2023-08-15 19:28:55 +08:00

714 lines
22 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="video-box">
<layoutTop></layoutTop>
<div class="plr-20" style="display: flex">
<el-tabs class="demo-tabs" v-model="active">
<el-tab-pane label="项目名称" name="first">
<!-- <div>11</div> -->
<TreeFilter
ref="proTree"
:checkStrictly="true"
label="title"
:requestApi="proApi"
@change="changeTreeFilter"
class="treefilter"
>
</TreeFilter>
</el-tab-pane>
<el-tab-pane label="工程名称" name="two">
<TreeFilter ref="engTree" label="title" :requestApi="engApi" @change="changeTreeFilter" class="treefilter">
</TreeFilter>
</el-tab-pane>
</el-tabs>
<div class="middle-video">
<div class="title-video flx-justify-between">
<h3>实时视频</h3>
<!-- <span>-</span>
<h3>{{ childTitle }}</h3> -->
<img @click="onPhoto" src="@/assets/images/AIwaring/抓拍.png" alt="" />
</div>
<!-- 视频数据站位 -->
<!-- <div id="playWnd" ref="playWndBox" class="box vedioShow"></div> -->
<div ref="playWndBox" class="main">
<div
id="playWnd"
class="playWnd"
:style="{
height: playWndHeight + 'px',
width: playWndWidth + 'px'
}"
></div>
</div>
</div>
<div class="right-form">
<div class="date-form">
<el-date-picker
v-model="dateForm.dateTime"
type="daterange"
range-separator=""
start-placeholder="开始日期"
end-placeholder="结束日期"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
@change="onDatePicker"
@focus="onTimeFocus"
@blur="onTimeBlur"
/>
<el-button class="searchBtn" @click="searchBtn" type="primary">查询</el-button>
</div>
<el-scrollbar height="720px">
<div class="right-header">
<div class="question-form" v-if="showInitiate">
<div class="title">{{ parentTitle }}</div>
<div class="desc">
<div class="question" v-show="!showPhotoForm">问题描述</div>
<el-form v-show="showPhotoForm" :rules="rules" :model="photoList" ref="ruleFormRef" label-width="96px">
<el-form-item label="问题描述:" prop="questionDesc">
<el-input v-model="photoList.questionDesc" :autosize="{ minRows: 2, maxRows: 4 }" type="textarea"></el-input>
</el-form-item>
<el-form-item label="图片显示:">
<el-image v-model="photoList.image" style="width: 95px; height: 53px" :src="photoList.url" fit="fill" />
</el-form-item>
<el-form-item label="下达人:">
<el-input v-model="photoList.createBy" placeholder="请输入" />
</el-form-item>
</el-form>
<div class="date">
<span>{{ format(new Date(), "yyyy-MM-dd") }}</span>
<el-button v-show="!showPhotoForm" @click="onInitiate" class="addButtonStyle" size="small">去发起</el-button>
<el-button v-show="showPhotoForm" @click="onSubmit(ruleFormRef)" class="addButtonStyle" size="small"
>提交</el-button
>
</div>
</div>
</div>
<div class="question-form" v-for="item in rightForm" :key="item.monitorId">
<!-- <div class="title">{{ active === "first" ? item.projectName : item.engineeringName }}</div> -->
<div class="title">{{ item.engineeringName === null ? item.projectName : item.engineeringName }}</div>
<div class="desc">
<div class="question" v-show="!item.showForm">问题描述{{ item.questionDesc }}</div>
<el-form disabled v-show="item.showForm" :model="formData" label-width="90px">
<el-form-item label="问题描述:">
<el-input v-model="formData.questionDesc" :autosize="{ minRows: 2, maxRows: 4 }" type="textarea"></el-input>
</el-form-item>
<el-form-item label="图片显示:">
<el-image style="width: 95px; height: 53px" :src="formData.image" fit="fill" />
</el-form-item>
<el-form-item label="下达人:">
<el-input v-model="formData.createBy" placeholder="请输入" />
</el-form-item>
<el-form-item label="下达时间:">
<el-date-picker
style="width: 100%"
v-model="formData.createTime"
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
type="datetime"
placeholder="请选择时间"
/>
</el-form-item>
<el-form-item label="整改情况:">
<el-input
:value="formData.state == 0 ? '待整改' : '已整改'"
:autosize="{ minRows: 2, maxRows: 4 }"
type="textarea"
></el-input>
<!-- <el-input v-model="formData.state" :autosize="{ minRows: 2, maxRows: 4 }" type="textarea"></el-input> -->
</el-form-item>
<el-form-item label="图片显示:">
<el-image style="width: 95px; height: 53px" :src="formData.solveImage" fit="fill" />
</el-form-item>
<el-form-item label="处理人:">
<el-input v-model="formData.solveBy" placeholder="请输入" />
</el-form-item>
<el-form-item label="处理时间:">
<el-date-picker
style="width: 100%"
v-model="formData.solveTime"
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
type="datetime"
placeholder="请选择时间"
/>
</el-form-item>
</el-form>
<div class="date">
<span>{{ item.createTime }}</span>
<el-button v-show="!item.showForm" @click="handleEditItem(item)" type="primary" size="small">查看</el-button>
<el-button v-show="item.showForm" @click="OnClose(item)" type="primary" size="small">收起</el-button>
</div>
</div>
</div>
</div>
</el-scrollbar>
<Pagination
:pageable="pageable"
:total="pageable.total"
:page-size="pageable.pageSize"
layout="prev, pager, next"
prev-text="上一页"
next-text="下一页"
:handleCurrentChange="handleCurrentChange"
class="pagination"
/>
</div>
</div>
</div>
</template>
<script setup lang="ts" name="governVideo">
import { ref, reactive, onMounted, onBeforeUnmount, getCurrentInstance, nextTick, watch, Ref } from "vue";
import { ElMessage, ElMessageBox, ElStep } from "element-plus";
import { getVideoQuestionPage, getvideoProTreeList, getvideoEngTreeList, addmonitorQuestion } from "@/api/modules/goverment";
import { getpreviewURL, getmanualCaptureL, getpreviewURLS, getConfigInfo } from "@/api/modules/common";
import TreeFilter from "@/components/TreeFilter/index.vue";
import { GlobalStore } from "@/stores";
import Pagination from "@/components/ProTable/components/Pagination.vue";
import type { UploadProps, FormInstance, FormRules } from "element-plus";
import { format } from "date-fns";
import layoutTop from "@/components/layoutTop/index.vue";
import { useRouter } from "vue-router";
const router = useRouter();
const store = GlobalStore();
interface rightFormList {
createTime: string;
projectName: string;
engineeringName: string;
monitorId: string;
questionDesc: string;
showForm: boolean;
}
const pageable = reactive({
pageNo: 1,
pageSize: 9,
total: 0
});
const active = ref("first");
const dateTime = ref<string>("");
const parentTitle = ref<string>("");
const childTitle = ref<string>("");
const rightForm = ref<rightFormList>({
createTime: "",
projectName: "",
engineeringName: "",
monitorId: "",
questionDesc: "",
showForm: false
});
const photoList = ref({
url: "",
questionDesc: "",
createBy: "",
image: ""
});
const visible = ref(false);
const showInitiate = ref(false);
const showPhotoForm = ref(false);
const proTree = ref();
const engTree = ref();
const ruleFormRef = ref<FormInstance>();
const playWndBox = ref(null);
let playWndHeight = ref("");
let playWndWidth = ref("");
let pubKey = ref("");
let initCount = ref(0);
let oWebControl = ref(null);
let cameraIndexCode = ref<Array<string>>([]);
let objData = ref({
appkey: "", //海康提供的appkey
ip: "", //海康提供的ip
secret: "", //海康提供的secret
port: 18443,
playMode: 0, // 0 预览 1回放
layout: "4x6" //页面展示的模块数【16】
});
const dateForm = ref({
dateTime: "",
startTime: "",
endTime: ""
});
//必填校验
const rules = reactive<FormRules>({
questionDesc: [
{
required: true,
message: "请输入",
trigger: "blur"
}
]
});
const formData = ref({
createBy: "",
createTime: "",
image: "",
questionDesc: "",
solveBy: "",
solveImage: "",
solveTime: "",
state: 0
});
const changeTreeFilter = async (item: {
data: { code: string | null; title: any; children: any[] };
parent: { data: { title: any } };
}) => {
console.log("我是你要的数据", item);
//给该方法传入监控编码
cameraIndexCode.value = [item.data.code];
parentTitle.value = item.parent.data.title || item.data.title;
if (item.data.code === null) {
cameraIndexCode.value = item.data.children.map(item => {
return item.code;
});
cameraIndexCode.value.forEach(element => {
previewVideo(element);
});
// 点击父节点判断是项目还是工程
if (active.value === "first") {
const { result } = await getVideoQuestionPage({
...pageable,
projectSn: item.data.sn
});
rightForm.value = result.records;
pageable.total = +result.total;
} else {
const { result } = await getVideoQuestionPage({
...pageable,
engineeringSn: item.data.sn
});
rightForm.value = result.records;
pageable.total = +result.total;
}
} else {
// childTitle.value = item.data.title;
getVideo();
previewVideo(item.data.code);
const { result } = await getVideoQuestionPage({
...pageable,
deviceCode: item.data.code
});
rightForm.value = result.records;
pageable.total = +result.total;
}
};
const proApi = async () => {
const { result } = await getvideoProTreeList({});
proTree.value.treeAllData = result;
return result;
// cameraIndexCode.value = proTree.value.treeAllData[5].children[0].code;
// console.log(cameraIndexCode.value);
};
const engApi = async () => {
const { result } = await getvideoEngTreeList({});
engTree.value.treeAllData = result;
return result;
};
const handleEditItem = (row: {
showForm: boolean;
createBy: string;
createTime: string;
image: string;
questionDesc: string;
solveBy: string;
solveImage: string;
solveTime: string;
state: number;
}) => {
row.showForm = true;
formData.value = { ...row };
// console.log(row);
// formData.value.state === 0 ? "待整改" : "已整改";
if (row.showForm === true) {
visible.value = true;
} else {
return;
}
// console.log(row);
};
// 时间检索
const searchBtn = async () => {
const { result } = await getVideoQuestionPage({
...pageable,
...dateForm.value
});
rightForm.value = result.records;
pageable.total = +result.total;
};
// 分页
const handleCurrentChange = async (page: number) => {
const { result } = await getVideoQuestionPage({
pageNo: page,
pageSize: pageable.value.pageSize
});
rightForm.value = result.records;
pageable.total = +result.total;
};
// 收起
const OnClose = (row: { showForm: boolean }) => {
row.showForm = false;
visible.value = false;
};
// 拍照的按钮
const onPhoto = async () => {
if (cameraIndexCode.value.length !== 1) {
ElMessage.error("请先选择要抓拍的监控");
} else {
console.log(cameraIndexCode.value.length);
const { result } = await getmanualCaptureL({ monitorCode: cameraIndexCode.value });
photoList.value.url = result.url;
photoList.value.image = photoList.value.url;
showInitiate.value = true;
}
};
const onInitiate = () => {
showPhotoForm.value = true;
};
// 拍照按钮提交
const onSubmit = async (formEl: FormInstance | undefined) => {
if (!formEl) return;
await formEl.validate(async (valid, fields) => {
if (valid) {
await addmonitorQuestion({ ...photoList.value, deviceCode: cameraIndexCode.value[0] });
showPhotoForm.value = false;
showInitiate.value = false;
ElMessage.success("提交成功");
photoList.value = reactive({ url: "", questionDesc: "", createBy: "", image: "" });
} else {
console.log("error submit!", fields);
ElMessage({
showClose: true,
message: "请完善表单信息!",
type: "error"
});
}
});
};
// 获取视频流
const getVideo = async () => {
// await sendRequest({ code: cameraIndexCode.value });
await getpreviewURL({ cameraIndexCode: cameraIndexCode.value });
};
// 获取视频配置信息
const getVideoConfig = async () => {
// await sendRequest({ code: cameraIndexCode.value });
const res = await getConfigInfo({});
objData.value = reactive({
appkey: res.result.appKey, //海康提供的appkey
ip: res.result.ip + ":" + res.result.port, //海康提供的ip
secret: res.result.appSecret, //海康提供的secret
port: 18443,
playMode: 0, // 0 预览 1回放
layout: "4x6" //页面展示的模块数【16】
});
console.log(objData.value);
};
// form日期选择后改变入参
const onDatePicker = () => {
dateForm.value.startTime = dateForm.value?.dateTime[0];
dateForm.value.endTime = dateForm.value?.dateTime[1];
onTimeBlur();
// onTimeFocus();
};
// 点击日期的时候隐藏部分视频
const onTimeFocus = () => {
if (oWebControl.value === undefined) {
// oWebControl.JS_CuttingPartWindow(938, 0, 362, 316);
oWebControl.JS_HideWnd();
}
};
const onTimeBlur = () => {
if (oWebControl.value === undefined) {
// oWebControl.JS_RepairPartWindow(938, 0, 362, 316);
oWebControl.JS_ShowWnd();
}
};
watch(
() => dateForm.value.dateTime,
() => {
if (dateForm.value.dateTime === null) {
dateForm.value.startTime = "";
dateForm.value.endTime = "";
}
}
);
// 监听修改密码的弹窗
watch(
() => store.editPassword,
val => {
val ? oWebControl.JS_HideWnd() : oWebControl.JS_ShowWnd();
}
// {
// immediate: true
// }
);
/** 设备列表的点击操作 */
// window.addEventListener("keyup", () => {
// oWebControl.JS_CuttingPartWindow(0, 0, 20, 20);
// });
onMounted(async () => {
// 获取视频插件配置信息
getVideoConfig();
// 获取页面的实例对象 ee
const pageInstance = getCurrentInstance();
// 获取dom节点对象
const tagDomObj = pageInstance?.refs.playWndBox;
playWndHeight.value = tagDomObj?.clientHeight;
playWndWidth.value = tagDomObj?.clientWidth;
// 监听scroll事件使插件窗口尺寸跟随DIV窗口变化
window.addEventListener("scroll", () => {
if (oWebControl.value == undefined) {
oWebControl.JS_Resize(tagDomObj?.clientWidth, tagDomObj?.clientHeight);
// setWndCover();
}
});
// 监听resize事件使插件窗口尺寸跟随DIV窗口变化
window.addEventListener("resize", e => {
if (oWebControl.value == undefined) {
// console.log("wwwww", e);
oWebControl.JS_Resize(tagDomObj?.clientWidth, tagDomObj?.clientHeight);
// oWebControl.JS_Resize(playWndHeight.value, playWndWidth.value);
// setWndCover();
}
});
// 初始化播放器插件
nextTick(() => {
initPlugin();
});
const { result } = await getVideoQuestionPage({
...pageable
});
rightForm.value = result.records;
pageable.total = +result.total;
rightForm.value.map((item: { showForm: boolean }) => {
let showForm = false;
item.showForm = showForm;
// console.log(item);
});
});
onBeforeUnmount(() => {
if (oWebControl.value === undefined) {
// 先让窗口隐藏,规避可能的插件窗口滞后于浏览器消失问题
oWebControl.JS_HideWnd();
// 销毁当前播放的视频
oWebControl.JS_RequestInterface({ funcName: "destroyWnd" });
// 断开与插件服务连接
oWebControl.JS_Disconnect();
}
});
const initPlugin = () => {
oWebControl = new WebControl({
szPluginContainer: "playWnd", // 指定容器id
iServicePortStart: 15900, // 指定起止端口号,建议使用该值
iServicePortEnd: 15900,
szClassId: "23BF3B0A-2C56-4D97-9C03-0CB103AA8F11", // 用于IE10使用ActiveX的clsid
cbConnectSuccess: () => {
// 创建WebControl实例成功
oWebControl
.JS_StartService("window", {
// WebControl实例创建成功后需要启动服务
// 值"./VideoPluginConnect.dll"写死
dllPath: "./VideoPluginConnect.dll"
})
.then(
function () {
// 设置消息回调
oWebControl.JS_SetWindowControlCallback({
// cbIntegrationCallBack: cbIntegrationCallBack,
});
//JS_CreateWnd创建视频播放窗口宽高可设定
oWebControl
.JS_CreateWnd("playWnd", 1000, 600, { bEmbed: true }) //这一部分很重要两个参数为你盒子的宽高这样是写死是防止组件加载之前出现白屏bEmbed: true 防止窗口闪烁
.then(function () {
// 创建播放实例成功后初始化
init();
});
},
function () {
// 启动插件服务失败
}
);
},
// 创建WebControl实例失败
cbConnectError: function () {
// 这里写创建WebControl实例失败时的处理步骤,下面的代码仅做参看,具体实现步骤根据个人需求进行编写!!!!!!!!
// console.log(0);
// oWebControl.value = null;
console.log(oWebControl.value);
// 程序未启动时执行error函数采用wakeup来启动程序
window.WebControl.JS_WakeUp("VideoWebPlugin://");
initCount.value++;
if (initCount.value < 3) {
setTimeout(function () {
initPlugin();
}, 3000);
} else {
setTimeout(function () {
setTimeout(function () {
router.push("/home");
}, 4000);
}, 4000);
}
if (initCount.value < 2) {
oWebControl.value = null;
ElMessage.warning("插件未启动,正在尝试启动,请稍候...");
// 程序未启动时执行error函数采用wakeup来启动程序
window.WebControl.JS_WakeUp("VideoWebPlugin://");
setTimeout(() => {
initPlugin();
}, 3000);
initCount.value++;
}
// else {
// window.location.href = this.videoWebPluginUrl;
// }
// console.log(oWebControl.value);
},
cbConnectClose: () => {
// 异常断开bNormalClose = false
// JS_Disconnect正常断开bNormalClose = true
// console.log("cbConnectClose");
oWebControl.value = null;
}
});
// oWebControl.JS_CuttingPartWindow(500, 500, 500, 500);
};
// 初始化
const init = (callback: (() => void) | undefined) => {
getPubKey(() => {
let appkey = objData.value.appkey; //综合安防管理平台提供的appkey必填
let secret = setEncrypt(objData.value.secret); //综合安防管理平台提供的secret必填
let ip = objData.value.ip; //综合安防管理平台IP地址必填
let playMode = objData.value.playMode; //初始播放模式0-预览1-回放
let port = objData.value.port; //综合安防管理平台端口若启用HTTPS协议默认443
let snapDir = "D:\\SnapDir"; //抓图存储路径
let videoDir = "D:\\VideoDir"; //紧急录像或录像剪辑存储路径
let layout = objData.value.layout; //playMode指定模式的布局
let enableHTTPS = 1; //是否启用HTTPS协议与综合安防管理平台交互这里总是填1
let encryptedFields = "secret"; //加密字段默认加密领域为secret
let showToolbar = 1; //是否显示工具栏0-不显示非0-显示
let showSmart = 0; //是否显示移动框线框0-不显示非0-显示
let buttonIDs = "0,16,256,257,258,259,260,512,513,514,515,516,517,768,769"; //自定义工具条按钮
// var toolBarButtonIDs = "2049,2304" // 工具栏上自定义按钮
oWebControl
?.JS_RequestInterface({
funcName: "init",
argument: JSON.stringify({
appkey: appkey, //API网关提供的appkey
secret: secret, //API网关提供的secret
ip: ip, //API网关IP地址
playMode: playMode, //播放模式(决定显示预览还是回放界面)
port: port, //端口
snapDir: snapDir, //抓图存储路径
videoDir: videoDir, //紧急录像或录像剪辑存储路径
layout: layout, //布局
enableHTTPS: enableHTTPS, //是否启用HTTPS协议
encryptedFields: encryptedFields, //加密字段
showToolbar: showToolbar, //是否显示工具栏
showSmart: showSmart, //是否显示智能信息
buttonIDs //自定义工具条按钮
})
})
.then(function (oData: any) {
oWebControl.JS_Resize(playWndWidth.value, playWndHeight.value); // 初始化后resize一次规避firefox下首次显示窗口后插件窗口未与DIV窗口重合问题
if (callback) {
callback();
}
// 隐藏
// oWebControl.JS_HideWnd()
});
});
};
// RSA 加密
let setEncrypt = (value: string) => {
let encrypt = new window.JSEncrypt();
encrypt.setPublicKey(pubKey);
return encrypt.encrypt(value);
};
// 获取公钥
const getPubKey = (callback: { (): void; (): void }) => {
oWebControl
.JS_RequestInterface({
funcName: "getRSAPubKey",
argument: JSON.stringify({
keyLength: 1024
})
})
.then(function (oData: { responseMsg: { data: Ref<string> } }) {
if (oData.responseMsg.data) {
pubKey = oData.responseMsg.data;
callback();
}
});
};
// 调用这个函数可进行视频播放
// 视频预览功能
const previewVideo = (data: string | null) => {
let cameraIndexCode = data; // 获取输入的监控点编号值,必填
let streamMode = 0; // 主子码流标识0-主码流1-子码流
let transMode = 1; // 传输协议0-UDP1-TCP
let gpuMode = 0; // 是否启用GPU硬解0-不启用1-启用
let wndId = -1; // 播放窗口序号在2x2以上布局下可指定播放窗口
oWebControl
.JS_RequestInterface({
funcName: "startPreview",
argument: JSON.stringify({
cameraIndexCode: cameraIndexCode, // 监控点编号
streamMode: streamMode, // 主子码流标识
transMode: transMode, // 传输协议
gpuMode: gpuMode, // 是否开启GPU硬解
wndId: wndId // 可指定播放窗口
})
})
.then(function () {
oWebControl.JS_SetWindowControlCallback({});
});
};
</script>
<style lang="scss" scoped>
@import "./index.scss";
:deep(.btn-prev) {
border: 1px solid #e5e5e5;
}
:deep(.btn-next) {
border: 1px solid #e5e5e5;
}
</style>