海康web插件技术文档
前情提要:本技术文档基于我司石衡项目视频监控页面的应用进行总结。
石衡项目是基于vue2,使用Element-ui + 海康web插件 + Echarts + GIS的集成项目。
视频监控实现的主要功能:
- 路段中所有摄像头树状显示和关键字检索
- 双击摄像头进行画面预览查看
- 预览模式和回放模式的切换
- 其他操作功能由海康web插件包含(例:抓图、录制、声音、全屏…)
使用的海康web插件介绍:由海康官网下载的视频WEB插件V1.5.2版本,解压完毕后目录如下
第一步:安装插件
安装插件包中的
bin
文件夹下的
VideoWebPlugin.exe
文件。
第二步:在项目中引入必要的JS文件
在项目目录中的
public
下创建
haikang
文件夹。把插件包中的
demo
文件夹中的
jquery-1.12.4.min.js
、
jsencrypt.min.js
、
jsWebControl-1.0.0.min.js
三个JS文件复制到
haikang
文件夹中,并在
index.html
中引入三个JS文件。
<-- public/index.html -->
<scriptsrc="./haikang/jquery-1.12.4.min.js"></script><scriptsrc="./haikang/jsencrypt.min.js"></script><scriptsrc="./haikang/jsWebControl-1.0.0.min.js"></script>
<-- public/index.html 打包时换成下面的格式 -->
<scriptsrc="<%= BASE_URL %>static/haikang/jquery-1.12.4.min.js"></script><scriptsrc="<%= BASE_URL %>static/haikang/jsencrypt.min.js"></script><scriptsrc="<%= BASE_URL %>static/haikang/jsWebControl-1.0.0.min.js"></script>
第三步:创建视频组件
在需要的项目目录中创建
haikang.vue
,该页面分为两部分。
左侧部分:可以切换预览模式与回放模式的基于element-ui按钮和基于element-ui生成的摄像机树形控件。
<-- haikang.vue -->
<div class="cebian">
<div class="top_box">
<el-button type="primary" class="aabox" @click="aaa()" size="mini">
视频监控
</el-button>
<el-button type="primary" class="aabox" @click="bbb()" size="mini">
视频回放
</el-button>
</div>
<!-- 树形控件 -->
<div class="dd_box">
<el-input
class="guolv"
size="mini"
placeholder="输入关键字进行过滤"
v-model="filterText"
>
</el-input>
<el-tree
class="filter_tree"
:data="data"
:props="defaultProps"
default-expand-all
:filter-node-method="filterNode"
ref="tree"
@node-click="nodeClick"
>
</el-tree>
</div>
</div>
左侧部分主要介绍:树形控件的双击方法和视频监控的预览与回放的方法。树形控件其他方法。
<-- haikang.vue -->
<script>
//data中声明
data{
treeClickCnt: 0,
treeClickTimeout: null,
treeClickId: "",
}
// 树形菜单点击事件
nodeClick(data) {
// 如果点击的id不相同,则重置点击次数
if (data.id != this.treeClickId) {
this.treeClickCnt = 0;
}
this.treeClickId = data.id;
this.treeClickCnt++;
// 注册清空点击次数计时器任务
window.clearTimeout(this.treeClickTimeout);
this.treeClickTimeout = window.setTimeout(() => {
this.treeClickCnt = 0;
}, 300);
// 连续点击多次则不做任何事情
if (this.treeClickCnt > 2) return;
// 点击一次时单击事件
if (this.treeClickCnt == 1) {
// 单击事件
console.log("单击");
}
// 点击两次时双击事件
if (this.treeClickCnt == 2) {
// 双击事件 双击预览
console.log("双击");
}
},
</script>
视频监控的预览和回放切换:主要通过插件包中
doc/视频WEB插件V1.5.2开发指南.pdf
开发文档进行实现。
思路:点击按钮销毁当前海康实例,再一次进行初始化中更换playMode 属性(0-预览、1-回放)。
右侧部分:基于海康WEB插件生成的视频控件。
<-- haikang.vue -->
<div class="zhuyao">
<div class="right" ref="playWndBox">
<!-- 视频数据站位 -->
<div
id="playWnd"
class="playWnd"
:style="{
height: playWndHeight + 'px',
width: playWndWidth + 'px',
}"
></div>
</div>
</div>
初始化实例
<-- haikang.vue -->
<script>
//声明全局变量
let oWebControl = null;
var initCount = 0;
var pubKey = "";
//钩子函数
mounted() {
this.playWndHeight = this.$refs.playWndBox.clientHeight; // 首次加载时的到父容器的高度
this.playWndWidth = this.$refs.playWndBox.clientWidth; // 首次加载时的到父容器的宽度
// 初始化摄像头
this.$nextTick(() => {
this.initPlugin(); //开发文档中有关于初始化的全程介绍
});
// 监听resize事件,使插件窗口尺寸跟随DIV窗口变化
window.addEventListener("resize", () => {
if (oWebControl != null) {
if (this.$refs.playWndBox)
oWebControl.JS_Resize(
this.$refs.playWndBox.clientWidth,
this.$refs.playWndBox.clientHeight
);
}
});
},
难题1.切换视频预览和视频回放模式时,显示当前模式的布局
思路:第一次初始化页面时,给定2*2的四分屏模式,接下来去
cbIntegrationCallBack
回调函数,每次切换布局则会返回
type=6
的返回对象,在
data
中保存其值,在下一次初始化实例时,可以进行应用。
// 回调的消息cbIntegrationCallBack(oData){let{responseMsg: type,responseMsg: msg }= oData;if(type.type ===1){this.boindex = type.msg.wndId;}elseif(type.type ===6){this.layout = type.msg.layout;//插件当前的布局。例:2✖2this.wndnum = type.msg.wndNum;//插件当前几分屏。例:4}},
难题2.切换视频预览和视频回放模式时,显示当前模式的摄像头画面
思路1(作废思路):
初始化实例后,不管几分屏,点击某屏后都有一个
type=1
的返回对象,在
data
中保存其值。并在双击时,获取到双击摄像头的编号值,组成一个对象,传入一个自建数组中。在进行模式切换时,初始化结束调用批量预览或批量回放方法,实现摄像头画面的继承。
// 回调的消息cbIntegrationCallBack(oData){let{responseMsg: type,responseMsg: msg }= oData;if(type.type ===1){this.boindex = type.msg.wndId;//当前点击的屏幕编号,例:四分屏 1-4}elseif(type.type ===6){this.layout = type.msg.layout;//插件当前的布局。例:2✖2this.wndnum = type.msg.wndNum;//插件当前几分屏。例:4}},
详细:初始化实例后,屏幕默认选中
wndId=1
的屏幕,可以在data中声明
boindex=1
,再次点击其他屏幕时,返回的
wndId
再给到
boindex
。选中某屏后,双击左侧树形控件进行预览,如下
var cameraIndexCode = data.index_code;//获取输入的监控点编号值,必填var streamMode =0;//主子码流标识:0-主码流,1-子码流var transMode =1;//传输协议:0-UDP,1-TCPvar gpuMode =0;//是否启用GPU硬解,0-不启用,1-启用var wndId =0;//播放窗口序号(在2x2以上布局下可指定播放窗口)
oWebControl.JS_RequestInterface({funcName:"startPreview",argument:JSON.stringify({cameraIndexCode: cameraIndexCode,//监控点编号streamMode: streamMode,//主子码流标识transMode: transMode,//传输协议gpuMode: gpuMode,//是否开启GPU硬解wndId: wndId,//可指定播放窗口}),});for(let i =0; i <this.bofang.length; i++){if(this.bofang[i].wndId ===this.boindex){this.bofang.splice(i,1);}}this.bofang.push({wndId:this.boindex,cameraIndexCode: cameraIndexCode,startTimeStamp:this.timestamp,});
需要传的参数中,
wndId
和
cameraIndexCode
两个参数为最重要参数。
wndId=-1
时,会自动选中下一个屏幕,
wndId=0
时,不会自动选中下一个屏幕。
思路2(正确思路):
经过真实项目调试后,发现打开视频画面后有一个
type=2
的返回值。
msg.result =768
可以返回已经打开的视频画面的
wndId
和
cameraIndexCode
两个参数,可以直接存入
data
,并且关闭某视频画面时,也有返回值,也可从存入的
data
中的数据中删除。
// 回调的消息cbIntegrationCallBack(oData){let{responseMsg: type,responseMsg: msg }= oData;//为了调试而打印的数据if(type ==="error"){
console.log(
type,
msg,this.dateFormat(newDate(),"yyyy-MM-dd hh:mm:ss"));}else{
console.log(
type,
msg,this.dateFormat(newDate(),"yyyy-MM-dd hh:mm:ss"));}if(type.type ===6){this.layout = type.msg.layout;this.wndnum = type.msg.wndNum;}elseif(type.type ===2){//删除data中的数据if(type.msg.result ===816){for(let i =0; i <this.bofang.length; i++){if(this.bofang[i].wndId == type.msg.wndId ||this.bofang[i].cameraIndexCode == type.msg.cameraIndexCode
){this.bofang.splice(i,1);}}}elseif(type.msg.result ===768){//正常播放视频画面后,存入datafor(let i =0; i <this.bofang.length; i++){if(this.bofang[i].wndId === type.msg.wndId){this.bofang.splice(i,1);}}this.bofang.push({wndId: type.msg.wndId,cameraIndexCode: type.msg.cameraIndexCode,startTimeStamp:this.timestamp,});}}},
难题3:APPkey,APPsecret,IP和摄像头的编号值等必要参数。
APPkey、APPsecret、IP这三个参数需要联系海康的对接人员,他们会安装一整套的海康插件,但是基于实际情况会只安装其中某一两个。这个时候需要联系他们安装所需要的平台,并从平台中获取三个参数。参考链接
摄像头编号值也可以从上方链接参考,但实际情况需要根据所见平台来进行搜索和查找。差别:搜索字段不同,进行代码调试时,需要手动输入本项目的APPkey和APPsecret…
难题4:初步解决海康控件的覆盖问题(针对遗留问题1)
目前并不能从层级方面解决海康控件覆盖问题。遗留问题中的裁剪方法使用后效果并不理想,所以又重新基于海康文档中隐藏/显示方法来实现控件后方的弹框显示。
基于本项目,在nav中的可视化管控、事件录入和应急联系单位三处添加eventBus通信,鼠标移入或点击打开时,传入值让海康控件进行隐藏,如下拉框和弹框关闭后,给当前海康控件页面加鼠标移入事件。
详细代码
<-- header.vue -->
<script>
import Bus from "@/utils/eventBus";
//鼠标移入和移出事件
gohaikang(val) {
Bus.$emit("changeMenus", val); //传给海康一个值
},
</script>
<-- eventBus.js -->
import Vue from 'vue';
const EventBus = new Vue();
export default EventBus
<-- haikang.vue -->
<script>
<template>
<div class="big_box" @mouseover="ccc(2)">
......内容
</div>
</template>
import EventBus from "@/utils/eventBus";
mounted(){
EventBus.$on("changeMenus", (val) => {
this.ccc(val); //接收header传来的值
});
},
methods:{
ccc(val) {
if (val == 1) {
oWebControl.JS_HideWnd();
} else if (val == 2) {
oWebControl.JS_ShowWnd();
}
},
}
</script>
效果图:
遗留问题1:海康插件生成的控件是最顶格,会覆盖控件后面的所有元素(弹框、下拉框)。
思路:基于本项目,我可以给项目的
nav
中
可视化管控
添加鼠标移入和移出方法,通过
eventBus
传给海康组件一个值,在海康组件中接收判断。判断后根据海康文档中的
JS_CuttingPartWindow()
和
JS_RepairPartWindow()
方法抠出来一块空白和补上去一块空白。
只是初步思路,接下来就是我可以得到下拉框距离
左边的margin
,也传进去,这样抠出来的空白是永远自适应的。
详细代码:
<-- header.vue -->
<el-submenu index="" popper-class="popperClass" v-else>
<template slot="title">
<div style="display:inline-block" @mouseover="gohaikang(1)"@mouseout="gohaikang(2)">
{{ route.meta.title }}
</div>
</template>
<el-menu-item v-for="item in route.children" :key="item.path" :index="item.path">
{{ item.meta.title }}
</el-menu-item>
</el-submenu>
<script>
import Bus from "@/utils/eventBus";
//鼠标移入和移出事件
gohaikang(val) {
Bus.$emit("changeMenus", val); //传给海康一个值
},
</script>
<-- eventBus.js -->
import Vue from 'vue';
const EventBus = new Vue();
export default EventBus
<-- haikang.vue -->
<script>
import EventBus from "@/utils/eventBus";
mounted(){
EventBus.$on("changeMenus", (val) => {
this.ccc(val); //接收header传来的值
});
},
methods:{
ccc(val) {
if (val == 1) {
//抠出来一块空白
oWebControl.JS_CuttingPartWindow(140, 0, 210, 120);
} else if (val == 2) {
setTimeout(() => {
//补回去一块空白
oWebControl.JS_RepairPartWindow(140, 0, 210, 120);
}, 3000);
}
},
}
</script>
遗留问题2:目前本项目只测试到可以正常预览,其余功能并没有实际测试。
海康页面的所有代码(只做参考):
请详细了解海康官网插件包
doc/视频WEB插件V1.5.2开发指南.pdf
或者查询足够多的海康插件知识后,可以详细
阅读下方代码。联系邮箱
[email protected]
<template>
<div class="big_box">
<div class="cebian">
<!-- 左上方预览和回放的切换按钮 -->
<div class="top_box">
<el-button type="primary" class="aabox" @click="aaa()" size="mini">
视频监控
</el-button>
<el-button type="primary" class="aabox" @click="bbb()" size="mini">
视频回放
</el-button>
</div>
<!-- 树形控件 -->
<div class="dd_box">
<!-- 关键字检索 -->
<el-input
class="guolv"
size="mini"
placeholder="输入关键字进行过滤"
v-model="filterText"
>
</el-input>
<!-- 树 -->
<el-tree
class="filter_tree"
:data="data"
:props="defaultProps"
default-expand-all
:filter-node-method="filterNode"
ref="tree"
@node-click="nodeClick"
>
</el-tree>
</div>
</div>
<div class="zhuyao">
<div class="right" ref="playWndBox">
<!-- 视频数据站位 -->
<div
id="playWnd"
class="playWnd"
:style="{
height: playWndHeight + 'px',
width: playWndWidth + 'px',
}"
></div>
</div>
</div>
</div>
</template>
<script>
import { get_camera_list } from "@/api/index"; //树形控件的接口(返回全部摄像头的数据)
let oWebControl = null; // 全局变量
var initCount = 0; // 全局变量
var pubKey = ""; // 全局变量
export default {
name: "videoRuntime",
props: {
// 由父组件传来的 APPkey APPsecret IP
basedata: {
type: Object,
default: "",
},
},
data() {
return {
playMode: 0, // 预览和回放模式 0-预览、1-回放
playWndHeight: "", // 视频盒子的高度
playWndWidth: "", // 视频盒子的宽度
treeClickCnt: 0, // 双击事件的点击次数
treeClickTimeout: null, // 击次数计时器任务
treeClickId: "", // 点击的id
filterText: "", // 关键字检索的关键字
data: [], // 树形控件的摄像机数据
defaultProps: {
// 树形控件的展示数据
children: "children",
label: "text",
},
// oWebControl: null,
layout: "", // 海康布局2*2
bofang: [{ wndId: 1 }], // 当前模式播放中的摄像头数据
boindex: 1, // 当前选中的屏幕ID
wndnum: 0, // 海康布局中屏幕的数量
timestamp: String(Date.parse(new Date()) / 1000), // 回放开始时间
timestamp1: String(Date.parse(new Date()) / 1000 + 1000), // 回放结束时间
};
},
computed: {},
created() {
this.get_camera_list(); // 调摄像头数据的接口
},
mounted() {
this.playWndHeight = this.$refs.playWndBox.clientHeight; // 首次加载时的到父容器的高度
this.playWndWidth = this.$refs.playWndBox.clientWidth; // 首次加载时的到父容器的宽度
console.log(this.playWndHeight, "高度");
console.log(this.playWndWidth, "宽度");
// 初始化摄像头
this.$nextTick(() => {
this.initPlugin();
});
// 监听resize事件,使插件窗口尺寸跟随DIV窗口变化
window.addEventListener("resize", () => {
if (oWebControl != null) {
if (this.$refs.playWndBox)
oWebControl.JS_Resize(
this.$refs.playWndBox.clientWidth,
this.$refs.playWndBox.clientHeight
);
}
});
},
watch: {
// 筛选摄像头名称
filterText(val) {
this.$refs.tree.filter(val);
},
},
methods: {
// 摄像机树
get_camera_list() {
let params = {
mode: "get",
};
get_camera_list(params).then((res) => {
this.data = res.data;
});
},
// 视频监控
aaa() {
if (this.playMode == 1) {
if (oWebControl != null) {
oWebControl.JS_HideWnd(); // 先让窗口隐藏,规避插件窗口滞后于浏览器消失问题
oWebControl.JS_Disconnect().then(
function () {},
function () {}
);
}
} else {
if (oWebControl != null) {
oWebControl.JS_HideWnd(); // 先让窗口隐藏,规避可能的插件窗口滞后于浏览器消失问题
oWebControl.JS_RequestInterface({ funcName: "destroyWnd" }); // 销毁当前播放的视频
oWebControl.JS_Disconnect(); // 断开与插件服务连接
}
}
oWebControl = null;
initCount = 0;
pubKey = "";
this.playWndHeight = this.$refs.playWndBox.clientHeight; // 首次加载时的到父容器的高度
this.playWndWidth = this.$refs.playWndBox.clientWidth; // 首次加载时的到父容器的宽度
this.playMode = 0;
setTimeout(() => {
this.initPlugin(0);
}, 1);
},
// 批量预览
piyu() {
oWebControl.JS_RequestInterface({
funcName: "startMultiPreviewByCameraIndexCode", // 固定写法
argument: { list: this.bofang }, // 批量预览所需要的参数
});
},
// 视频回放
bbb() {
if (this.playMode == 1) {
oWebControl.JS_HideWnd(); // 先让窗口隐藏,规避插件窗口滞后于浏览器消失问题
oWebControl.JS_Disconnect().then(
function () {},
function () {}
);
} else {
oWebControl.JS_HideWnd(); // 先让窗口隐藏,规避可能的插件窗口滞后于浏览器消失问题
oWebControl.JS_RequestInterface({ funcName: "destroyWnd" }); // 销毁当前播放的视频
oWebControl.JS_Disconnect(); // 断开与插件服务连接
}
oWebControl = null;
initCount = 0;
pubKey = "";
this.playWndHeight = this.$refs.playWndBox.clientHeight; // 首次加载时的到父容器的高度
this.playWndWidth = this.$refs.playWndBox.clientWidth; // 首次加载时的到父容器的宽度
this.playMode = 1;
setTimeout(() => {
this.initPlugin(1);
}, 1);
},
// 批量回放
pihui() {
var timestamp1 = String(Date.parse(new Date()) / 1000 + 1000);
for (let i = 0; i < this.bofang.length; i++) {
this.bofang[i].endTimeStamp = timestamp1; // 加入回放结束时间
}
oWebControl.JS_RequestInterface({
funcName: "startMultiPlaybackByCameraIndexCode", // 固定写法
argument: { list: this.bofang }, // 批量回放所需要的参数
});
},
// 初始化,创建实例
initPlugin(val) {
let that = this;
oWebControl = new WebControl({
szPluginContainer: "playWnd", // 指定容器id
iServicePortStart: 15900, // 指定起止端口号,建议使用该值
iServicePortEnd: 15909,
szClassId: "23BF3B0A-2C56-4D97-9C03-0CB103AA8F11", // 用于IE10使用ActiveX的clsid
cbConnectSuccess: () => {
// 创建WebControl实例成功
oWebControl
.JS_StartService("window", {
// WebControl实例创建成功后需要启动服务
// dllPath: "./", // 值"./VideoPluginConnect.dll"写死
dllPath: "./VideoPluginConnect.dll", // 值"./VideoPluginConnect.dll"写死
})
.then(
function () {
// 启动插件服务成
oWebControl.JS_SetWindowControlCallback({
// 设置消息回调
cbIntegrationCallBack: that.cbIntegrationCallBack,
});
oWebControl
.JS_CreateWnd(
"playWnd",
that.playWndWidth,
that.playWndHeight
)
.then(function () {
//JS_CreateWnd创建视频播放窗口,宽高可设定 默认设置为0 消除初始化闪白问题
that.init(val); // 创建播放实例成功后初始化
});
},
function () {
// 启动插件服务失败
}
);
},
cbConnectError: function () {
// 创建WebControl实例失败
oWebControl = null;
that.$message.warning("插件未启动,正在尝试启动,请稍候...");
window.WebControl.JS_WakeUp("VideoWebPlugin://"); // 程序未启动时执行error函数,采用wakeup来启动程序
initCount++;
if (initCount < 3) {
setTimeout(function () {
that.initPlugin();
}, 3000);
} else {
that.$message.warning("插件启动失败,请检查插件是否安装!");
}
},
cbConnectClose: () => {
// 异常断开:bNormalClose = false
// JS_Disconnect正常断开:bNormalClose = true
console.log("cbConnectClose");
oWebControl = null;
},
});
},
// 初始化页面的展示
init(val) {
let that = this;
// 获取公钥
this.getPubKey(() => {
// 初始化
var appkey = this.basedata.appkey; //综合安防管理平台提供的appkey,必填
var secret = this.setEncrypt(this.basedata.secret); //综合安防管理平台提供的secret,必填
var ip = this.basedata.ip; //综合安防管理平台IP地址,必填
var enableHTTPS = 1; //是否启用HTTPS协议与综合安防管理平台交互,这里总是填1
var port = this.basedata.port; //综合安防管理平台端口,若启用HTTPS协议,默认443
port = parseInt(port);
var playMode = this.playMode; //初始播放模式:0-预览,1-回放
var encryptedFields = "secret"; //加密字段,默认加密领域为secret
var snapDir = "D:\\SnapDir"; //抓图存储路径
var videoDir = "D:\\VideoDir"; //紧急录像或录像剪辑存储路径
var layout = this.layout; //playMode指定模式的布局
var showToolbar = 1; //是否显示工具栏,0-不显示,非0-显示
var showSmart = 1; //是否显示智能信息(如配置移动侦测后画面上的线框),0-不显示,非0-显示
// var 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: buttonIDs, //自定义工具条按钮
}),
})
.then(function (oData) {
console.log(oData);
oWebControl.JS_Resize(that.playWndWidth, that.playWndHeight); // 初始化后resize一次,规避firefox下首次显示窗口后插件窗口未与DIV窗口重合问题
// 批量播放,预览和回放分开
setTimeout(() => {
if (val == 1) {
that.pihui();
} else {
that.piyu();
}
}, 1);
});
// 获取当前初始化的布局和屏幕数量
oWebControl
.JS_RequestInterface({
funcName: "getLayout",
})
.then((res) => {
let data99 = JSON.parse(res.responseMsg.data);
this.layout = data99.layout;
this.wndnum = data99.wndNum;
});
});
},
// 获取公钥
getPubKey(callback) {
oWebControl
.JS_RequestInterface({
funcName: "getRSAPubKey",
argument: JSON.stringify({
keyLength: 1024,
}),
})
.then(function (oData) {
if (oData.responseMsg.data) {
pubKey = oData.responseMsg.data;
callback();
}
});
},
// RSA 加密
setEncrypt(value) {
var encrypt = new window.JSEncrypt();
encrypt.setPublicKey(pubKey);
return encrypt.encrypt(value);
},
// 回调的消息
cbIntegrationCallBack(oData) {
let { responseMsg: type, responseMsg: msg } = oData;
if (type === "error") {
console.log(
type,
msg,
this.dateFormat(new Date(), "yyyy-MM-dd hh:mm:ss")
);
} else {
console.log(
type,
msg,
this.dateFormat(new Date(), "yyyy-MM-dd hh:mm:ss")
);
}
if (type.type === 1) {
this.boindex = type.msg.wndId;
} else if (type.type === 6) {
this.layout = type.msg.layout;
this.wndnum = type.msg.wndNum;
}
},
// 格式化时间
dateFormat(oDate, fmt) {
var o = {
"M+": oDate.getMonth() + 1, //月份
"d+": oDate.getDate(), //日
"h+": oDate.getHours(), //小时
"m+": oDate.getMinutes(), //分
"s+": oDate.getSeconds(), //秒
"q+": Math.floor((oDate.getMonth() + 3) / 3), //季度
S: oDate.getMilliseconds(), //毫秒
};
if (/(y+)/.test(fmt)) {
fmt = fmt.replace(
RegExp.$1,
(oDate.getFullYear() + "").substr(4 - RegExp.$1.length)
);
}
for (var k in o) {
if (new RegExp("(" + k + ")").test(fmt)) {
fmt = fmt.replace(
RegExp.$1,
RegExp.$1.length == 1
? o[k]
: ("00" + o[k]).substr(("" + o[k]).length)
);
}
}
return fmt;
},
// 筛选方法
filterNode(value, data) {
if (!value) return true;
return data.text.indexOf(value) !== -1;
},
// 树形菜单点击事件
nodeClick(data) {
console.log(data);
// 如果点击的id不相同,则重置点击次数
if (data.id != this.treeClickId) {
this.treeClickCnt = 0;
}
this.treeClickId = data.id;
this.treeClickCnt++;
// 注册清空点击次数计时器任务
window.clearTimeout(this.treeClickTimeout);
this.treeClickTimeout = window.setTimeout(() => {
this.treeClickCnt = 0;
}, 300);
// 连续点击多次则不做任何事情
if (this.treeClickCnt > 2) return;
// 点击一次时单击事件
if (this.treeClickCnt == 1) {
// 单击事件
console.log("单击");
}
// 点击两次时双击事件
if (this.treeClickCnt == 2) {
// this.startPreview(data.id.toString())
// 双击事件 双击预览
// this.startPreview(data.id.toString())
// 双击事件 双击预览
console.log("双击");
var cameraIndexCode = data.index_code.toString(); //获取输入的监控点编号值,必填
var streamMode = 0; //主子码流标识:0-主码流,1-子码流
var transMode = 1; //传输协议:0-UDP,1-TCP
var gpuMode = 0; //是否启用GPU硬解,0-不启用,1-启用
var wndId = 0; //播放窗口序号(在2x2以上布局下可指定播放窗口)
var timestamp = String(Date.parse(new Date()) / 1000); //回放模式的开始时间
var timestamp1 = String(Date.parse(new Date()) / 1000 + 1000); //回放模式的结束时间
cameraIndexCode = cameraIndexCode.replace(/(^\s*)/g, "");
cameraIndexCode = cameraIndexCode.replace(/(\s*$)/g, "");
if (this.playMode == 0) {
oWebControl.JS_RequestInterface({
funcName: "startPreview",
argument: JSON.stringify({
cameraIndexCode: cameraIndexCode, //监控点编号
streamMode: streamMode, //主子码流标识
transMode: transMode, //传输协议
gpuMode: gpuMode, //是否开启GPU硬解
wndId: wndId, //可指定播放窗口
}),
});
// 双击某摄像头时,遍历数组,相同的屏幕id,删掉前一项
for (let i = 0; i < this.bofang.length; i++) {
if (this.bofang[i].wndId === this.boindex) {
this.bofang.splice(i, 1);
}
}
// 把海康的屏幕id,摄像头编号值,回放模式开始时间放入数组
this.bofang.push({
wndId: this.boindex,
cameraIndexCode: cameraIndexCode,
startTimeStamp: this.timestamp,
});
} else {
oWebControl.JS_RequestInterface({
funcName: "startPlayback",
argument: JSON.stringify({
cameraIndexCode: cameraIndexCode, //监控点编号
startTimeStamp: timestamp, // 录像查询开始时间戳,单位:秒
// startTimeStamp: "10237898985", // 录像查询开始时间戳,单位:秒
endTimeStamp: timestamp1, // 录像查询结束时间戳,单位:秒
// endTimeStamp: "10237899985", // 录像查询结束时间戳,单位:秒
recordLocation: 0, // 录像存储类型 0-中心存储 1-设备存储
transMode: transMode, // 传输协议 ,0-UDP 1-TCP
gpuMode: gpuMode, // 是否开启 GPU 硬解,0-不开启 1-开
}),
});
// 双击某摄像头时,遍历数组,相同的屏幕id,删掉前一项
for (let i = 0; i < this.bofang.length; i++) {
if (this.bofang[i].wndId === this.boindex) {
this.bofang.splice(i, 1);
}
}
// 把海康的屏幕id,摄像头编号值,回放模式开始时间放入数组
this.bofang.push({
wndId: this.boindex,
cameraIndexCode: cameraIndexCode,
startTimeStamp: this.timestamp,
});
}
}
},
},
beforeDestroy() {
if (oWebControl != null) {
oWebControl.JS_HideWnd(); // 先让窗口隐藏,规避可能的插件窗口滞后于浏览器消失问题
oWebControl.JS_RequestInterface({ funcName: "destroyWnd" }); // 销毁当前播放的视频
oWebControl.JS_Disconnect(); // 断开与插件服务连接
}
},
};
</script>
<style scoped lang="scss">
.big_box {
display: flex;
.cebian {
width: 256px;
height: calc(100vh - 48px);
background: #000;
.top_box {
height: 40px;
background: #202121;
display: flex;
align-items: center;
justify-content: space-around;
border-bottom: 1px solid #ccc;
.aabox {
border: 0px;
}
}
.box-left {
width: 256px;
height: 100%;
background-color: #202121;
overflow-y: auto;
}
.box-left::-webkit-scrollbar {
/*滚动条整体样式*/
width: 4px; /*高宽分别对应横竖滚动条的尺寸*/
height: 0;
}
.box-left::-webkit-scrollbar-thumb {
/*滚动条里面小方块*/
border-radius: 4px;
background-color: rgba(30, 249, 253, 0);
background-image: -webkit-linear-gradient(
45deg,
rgba(255, 255, 255, 0) 25%,
transparent 25%,
transparent 50%,
rgba(255, 255, 255, 0) 50%,
rgba(255, 255, 255, 0) 75%,
transparent 75%,
transparent
);
}
.box-left::-webkit-scrollbar-track {
/*滚动条里面轨道*/
box-shadow: inset 0 0 5px rgba(0, 0, 0, 0);
background: rgba(255, 255, 255, 0);
border-radius: 4px;
}
}
.zhuyao {
width: calc(100vw - 256px);
height: calc(100vh - 48px);
.right {
height: calc(100vh - 48px);
}
}
}
</style>
<style lang="scss">
.box-left {
.el-submenu__title {
height: 32px;
line-height: 32px;
font-size: 12px;
width: 256px;
}
.el-submenu__title:hover {
background-color: #265457 !important;
}
.el-menu-vertical-demo {
margin-top: 16px;
}
.el-submenu {
.el-menu-item {
height: 32px;
line-height: 32px;
font-size: 12px;
width: 240px;
margin-left: 16px;
padding-left: 32px !important;
}
}
.el-menu--inline {
.el-menu-item:hover {
background-color: #265457 !important;
}
.is-active {
background-color: #265457 !important;
}
}
.el-submenu__icon-arrow,
.el-icon-arrow-down {
color: #fff !important;
}
.sidebar-container {
.el-menu-vertical-demo {
margin-top: 24px;
}
}
}
.dd_box {
padding: 6px;
.filter_tree {
height: calc(100vh - 128px);
margin-top: 6px;
overflow-y: scroll;
}
.filter_tree::-webkit-scrollbar {
/*滚动条整体样式*/
width: 4px; /*高宽分别对应横竖滚动条的尺寸*/
height: 0;
}
.filter_tree::-webkit-scrollbar-thumb {
/*滚动条里面小方块*/
border-radius: 4px;
background-color: rgba(30, 249, 253, 0);
background-image: -webkit-linear-gradient(
45deg,
rgba(255, 255, 255, 0) 25%,
transparent 25%,
transparent 50%,
rgba(255, 255, 255, 0) 50%,
rgba(255, 255, 255, 0) 75%,
transparent 75%,
transparent
);
}
.filter_tree::-webkit-scrollbar-track {
/*滚动条里面轨道*/
box-shadow: inset 0 0 5px rgba(0, 0, 0, 0);
background: rgba(255, 255, 255, 0);
border-radius: 4px;
}
}
.dd_box .el-tree {
background: rgb(255 255 255 / 0%) !important; //将默认背景色进行透明处理
color: #fff !important;
}
.dd_box .el-tree-node__label {
font-size: 14px !important; //覆盖原有的字体大小
}
.dd_box .el-tree-node__content:hover {
background-color: #194f56 !important; //当鼠标浮动时,进行颜色改变,默认的为白色
}
.dd_box .el-tree-node:focus > .el-tree-node__content {
background-color: #194f56 !important; //当选中树节点时的颜色改变,默认为白色
}
</style>
<style scoped>
::v-deep .guolv .el-input__inner {
background-color: #e8e8e8;
text-align: center;
border-color: #c0c4cc;
color: #000;
}
</style>
{
/滚动条里面小方块/
border-radius: 4px;
background-color: rgba(30, 249, 253, 0);
background-image: -webkit-linear-gradient(
45deg,
rgba(255, 255, 255, 0) 25%,
transparent 25%,
transparent 50%,
rgba(255, 255, 255, 0) 50%,
rgba(255, 255, 255, 0) 75%,
transparent 75%,
transparent
);
}
.filter_tree::-webkit-scrollbar-track {
/滚动条里面轨道/
box-shadow: inset 0 0 5px rgba(0, 0, 0, 0);
background: rgba(255, 255, 255, 0);
border-radius: 4px;
}
}
.dd_box .el-tree {
background: rgb(255 255 255 / 0%) !important; //将默认背景色进行透明处理
color: #fff !important;
}
.dd_box .el-tree-node__label {
font-size: 14px !important; //覆盖原有的字体大小
}
.dd_box .el-tree-node__content:hover {
background-color: #194f56 !important; //当鼠标浮动时,进行颜色改变,默认的为白色
}
.dd_box .el-tree-node:focus > .el-tree-node__content {
background-color: #194f56 !important; //当选中树节点时的颜色改变,默认为白色
}
版权归原作者 裴浑河 所有, 如有侵权,请联系我们删除。