海康web插件技术文档

前情提要:本技术文档基于我司石衡项目视频监控页面的应用进行总结。

在这里插入图片描述

石衡项目是基于vue2,使用Element-ui + 海康web插件 + Echarts + GIS的集成项目。

视频监控实现的主要功能:

  1. 路段中所有摄像头树状显示和关键字检索
  2. 双击摄像头进行画面预览查看
  3. 预览模式和回放模式的切换
  4. 其他操作功能由海康web插件包含(例:抓图、录制、声音、全屏…)

使用的海康web插件介绍:由海康官网下载的视频WEB插件V1.5.2版本,解压完毕后目录如下

在这里插入图片描述

第一步:安装插件

安装插件包中的bin文件夹下的VideoWebPlugin.exe文件。

第二步:在项目中引入必要的JS文件

在项目目录中的public下创建haikang文件夹。把插件包中的demo文件夹中的jquery-1.12.4.min.jsjsencrypt.min.jsjsWebControl-1.0.0.min.js三个JS文件复制到haikang文件夹中,并在index.html中引入三个JS文件。

  <-- public/index.html -->
      
  <script src="./haikang/jquery-1.12.4.min.js"></script>
  <script src="./haikang/jsencrypt.min.js"></script>
  <script src="./haikang/jsWebControl-1.0.0.min.js"></script>
      
  <-- public/index.html 打包时换成下面的格式 -->
  <script src="<%= BASE_URL %>static/haikang/jquery-1.12.4.min.js"></script>
  <script src="<%= BASE_URL %>static/haikang/jsencrypt.min.js"></script>
  <script src="<%= 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;
      } else if (type.type === 6) {
        this.layout = type.msg.layout;  //插件当前的布局。例:2✖2
        this.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
      } else if (type.type === 6) {
        this.layout = type.msg.layout;  //插件当前的布局。例:2✖2
        this.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-TCP
        var 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,
          });

需要传的参数中,wndIdcameraIndexCode两个参数为最重要参数。wndId=-1时,会自动选中下一个屏幕,wndId=0时,不会自动选中下一个屏幕。

思路2(正确思路):

经过真实项目调试后,发现打开视频画面后有一个type=2的返回值。msg.result =768可以返回已经打开的视频画面的wndIdcameraIndexCode两个参数,可以直接存入data,并且关闭某视频画面时,也有返回值,也可从存入的data中的数据中删除。

    // 回调的消息
    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 === 6) {
        this.layout = type.msg.layout;
        this.wndnum = type.msg.wndNum;
      } else if (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);
            }
          }
        } else if (type.msg.result === 768) {
          //正常播放视频画面后,存入data
          for (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或者查询足够多的海康插件知识后,可以详细

阅读下方代码。联系邮箱zhuoren1204099@163.com

<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; //当选中树节点时的颜色改变,默认为白色
}


Logo

前往低代码交流专区

更多推荐