Forráskód Böngészése

Merge remote-tracking branch 'origin/master'

huangmp 4 éve
szülő
commit
8a41811a76

+ 113 - 119
public/index.html

@@ -1,134 +1,128 @@
 <!DOCTYPE html>
 <html>
 
-  <head>
-    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
-    <meta http-equiv="X-UA-Compatible" content="IE=edge">
-    <meta http-equiv="X-UA-Compatible" content="chrome=1" />
-    <meta name="renderer" content="webkit">
-    <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0">
-    <meta name="apple-mobile-web-app-capable" content="yes">
-    <meta name="apple-mobile-web-app-status-bar-style" content="black">
-    <meta name="format-detection" content="telephone=no">
-    <link rel="stylesheet" href="<%= BASE_URL %>cdn/element-ui/2.15.1/theme-chalk/index.css">
-    <link rel="stylesheet" href="<%= BASE_URL %>cdn/animate/3.5.2/animate.css">
-    <link rel="stylesheet" href="<%= BASE_URL %>cdn/iconfont/index.css">
-    <link rel="stylesheet" href="<%= BASE_URL %>cdn/iconfont/avue/iconfont.css">
-    <link rel="stylesheet" href="<%= BASE_URL %>cdn/iconfont/saber/iconfont.css">
-    <link rel="stylesheet" href="<%= BASE_URL %>cdn/avue/2.8.12/index.css">
-    <script src="<%= BASE_URL %>cdn/xlsx/FileSaver.min.js"></script>
-    <script src="<%= BASE_URL %>cdn/xlsx/xlsx.full.min.js"></script>
-    <link rel="icon" href="<%= BASE_URL %>favicon.png">
-    <script src="<%= BASE_URL %>cdn/xlsx/FileSaver.min.js"></script>
-    <script src="<%= BASE_URL %>cdn/xlsx/xlsx.full.min.js"></script>
-    <script src="<%= BASE_URL %>cdn/elevator/zlplayer.min.js"></script>
-    <script src="http://libs.baidu.com/jquery/2.1.4/jquery.min.js"></script>
-    <script src="https://cdn.staticfile.org/echarts/4.3.0/echarts.min.js"></script>
-    <script src="js/china.js"></script>
-    <script type="text/javascript"
-      src="https://webapi.amap.com/maps?v=2.0&key=cbb265e2a60bbbc04a52eec4eecdeb12&plugin=AMap.PolygonEditor,AMap.Driving">
-    </script>
-    <script src="https://webapi.amap.com/ui/1.1/main.js?v=1.0.11"></script>
-    <script src="https://a.amap.com/jsapi_demos/static/demo-center/js/demoutils.js"></script>
-    <script type="text/javascript" src="./js/EasyWasmPlayer.js"></script>
-    <script type="text/javascript" src="./js/jessibuca/index.js"></script>
-    <script type="text/javascript" src="./js/ZLMRTCClient.js"></script>
-    <script type="text/javascript" src="//api.map.baidu.com/api?v=2.0&ak=rk73w8dv1rkE4UdZsataG68VarhYQzrx&s=1"></script>
-    <script charset="utf-8"
-      src="https:/
-      /map.qq.com/api/gljs?v=1.exp&key=UF2BZ-SAMWW-REORU-RLLLT-BPLGQ-DJBLD&libraries=geometry">
-    </script>
-    
-    <title>榕基智慧园区</title>
-    <style>
-      html,
-      body,
-      #app {
-        height: 100%;
-        margin: 0;
-        padding: 0;
-      }
+<head>
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+  <meta http-equiv="X-UA-Compatible" content="IE=edge">
+  <meta http-equiv="X-UA-Compatible" content="chrome=1"/>
+  <meta name="renderer" content="webkit">
+  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0">
+  <meta name="apple-mobile-web-app-capable" content="yes">
+  <meta name="apple-mobile-web-app-status-bar-style" content="black">
+  <meta name="format-detection" content="telephone=no">
+  <link rel="stylesheet" href="<%= BASE_URL %>cdn/element-ui/2.15.1/theme-chalk/index.css">
+  <link rel="stylesheet" href="<%= BASE_URL %>cdn/animate/3.5.2/animate.css">
+  <link rel="stylesheet" href="<%= BASE_URL %>cdn/iconfont/index.css">
+  <link rel="stylesheet" href="<%= BASE_URL %>cdn/iconfont/avue/iconfont.css">
+  <link rel="stylesheet" href="<%= BASE_URL %>cdn/iconfont/saber/iconfont.css">
+  <link rel="stylesheet" href="<%= BASE_URL %>cdn/avue/2.8.12/index.css">
+  <script src="<%= BASE_URL %>cdn/xlsx/FileSaver.min.js"></script>
+  <script src="<%= BASE_URL %>cdn/xlsx/xlsx.full.min.js"></script>
+  <link rel="icon" href="<%= BASE_URL %>favicon.png">
+  <script src="<%= BASE_URL %>cdn/xlsx/FileSaver.min.js"></script>
+  <script src="<%= BASE_URL %>cdn/xlsx/xlsx.full.min.js"></script>
+  <script src="<%= BASE_URL %>cdn/elevator/zlplayer.min.js"></script>
+  <script src="http://libs.baidu.com/jquery/2.1.4/jquery.min.js"></script>
+  <script src="https://cdn.staticfile.org/echarts/4.3.0/echarts.min.js"></script>
+  <script src="js/china.js"></script>
+  <script type="text/javascript" src="https://webapi.amap.com/maps?v=2.0&key=cbb265e2a60bbbc04a52eec4eecdeb12&plugin=AMap.PolygonEditor,AMap.Driving"></script>
+  <script src="https://webapi.amap.com/ui/1.1/main.js?v=1.0.11"></script>
+  <script src="https://a.amap.com/jsapi_demos/static/demo-center/js/demoutils.js"></script>
+  <script type="text/javascript" src="./js/EasyWasmPlayer.js"></script>
+  <script type="text/javascript" src="./js/jessibuca/index.js"></script>
+  <script type="text/javascript" src="./js/ZLMRTCClient.js"></script>
+  <script type="text/javascript" src="//api.map.baidu.com/api?v=2.0&ak=rk73w8dv1rkE4UdZsataG68VarhYQzrx&s=1"></script>
+  <script src="https://cdn.staticfile.org/flv.js/1.5.0/flv.js"></script>
+  <title>常运智慧园区</title>
+  <style>
+    html,
+    body,
+    #app {
+      height: 100%;
+      margin: 0;
+      padding: 0;
+    }
 
-      .avue-home {
-        background-color: #303133;
-        height: 100%;
-        display: flex;
-        flex-direction: column;
-      }
+    .avue-home {
+      background-color: #303133;
+      height: 100%;
+      display: flex;
+      flex-direction: column;
+    }
 
-      .avue-home__main {
-        user-select: none;
-        width: 100%;
-        flex-grow: 1;
-        display: flex;
-        justify-content: center;
-        align-items: center;
-        flex-direction: column;
-      }
+    .avue-home__main {
+      user-select: none;
+      width: 100%;
+      flex-grow: 1;
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      flex-direction: column;
+    }
 
-      .avue-home__footer {
-        width: 100%;
-        flex-grow: 0;
-        text-align: center;
-        padding: 1em 0;
-      }
+    .avue-home__footer {
+      width: 100%;
+      flex-grow: 0;
+      text-align: center;
+      padding: 1em 0;
+    }
 
-      .avue-home__footer>a {
-        font-size: 12px;
-        color: #ABABAB;
-        text-decoration: none;
-      }
+    .avue-home__footer > a {
+      font-size: 12px;
+      color: #ABABAB;
+      text-decoration: none;
+    }
 
-      .avue-home__loading {
-        height: 32px;
-        width: 32px;
-        margin-bottom: 20px;
-      }
+    .avue-home__loading {
+      height: 32px;
+      width: 32px;
+      margin-bottom: 20px;
+    }
 
-      .avue-home__title {
-        color: #FFF;
-        font-size: 14px;
-        margin-bottom: 10px;
-      }
+    .avue-home__title {
+      color: #FFF;
+      font-size: 14px;
+      margin-bottom: 10px;
+    }
 
-      .avue-home__sub-title {
-        color: #ABABAB;
-        font-size: 12px;
-      }
-    </style>
-  </head>
+    .avue-home__sub-title {
+      color: #ABABAB;
+      font-size: 12px;
+    }
+  </style>
+</head>
 
-  <body>
-    <noscript>
-      <strong>
-        很抱歉,如果没有 JavaScript 支持,Saber 将不能正常工作。请启用浏览器的 JavaScript 然后继续。
-      </strong>
-    </noscript>
-    <div id="app">
-      <div class="avue-home">
-        <div class="avue-home__main">
-          <img class="avue-home__loading" src="<%= BASE_URL %>svg/loading-spin.svg" alt="loading">
-          <div class="avue-home__title">
-            正在加载资源
-          </div>
-          <div class="avue-home__sub-title d">
-            初次加载资源可能需要较多时间 请耐心等待
-          </div>
-        </div>
-        <div class="avue-home__footer">
-          <a href="https://bladex.vip" target="_blank">
-            https://bladex.vip </a>
-        </div>
+<body>
+<noscript>
+  <strong>
+    很抱歉,如果没有 JavaScript 支持,Saber 将不能正常工作。请启用浏览器的 JavaScript 然后继续。
+  </strong>
+</noscript>
+<div id="app">
+  <div class="avue-home">
+    <div class="avue-home__main">
+      <img class="avue-home__loading" src="<%= BASE_URL %>svg/loading-spin.svg" alt="loading">
+      <div class="avue-home__title">
+        正在加载资源
       </div>
+      <div class="avue-home__sub-title d">
+        初次加载资源可能需要较多时间 请耐心等待
+      </div>
+    </div>
+    <div class="avue-home__footer">
+      <a href="https://bladex.vip" target="_blank">
+        https://bladex.vip </a>
     </div>
-    <!-- built files will be auto injected -->
-    <script src="<%= BASE_URL %>util/aes.js" charset="utf-8"></script>
-    <script src="<%= BASE_URL %>cdn/vue/2.6.10/vue.min.js" charset="utf-8"></script>
-    <script src="<%= BASE_URL %>cdn/vuex/3.1.1/vuex.min.js" charset="utf-8"></script>
-    <script src="<%= BASE_URL %>cdn/vue-router/3.0.1/vue-router.min.js" charset="utf-8"></script>
-    <script src="<%= BASE_URL %>cdn/axios/1.0.0/axios.min.js" charset="utf-8"></script>
-    <script src="<%= BASE_URL %>cdn/element-ui/2.15.1/index.js" charset="utf-8"></script>
-    <script src="<%= BASE_URL %>cdn/avue/2.8.12/avue.min.js" charset="utf-8"></script>
-  </body>
+  </div>
+</div>
+<!-- built files will be auto injected -->
+<script src="<%= BASE_URL %>util/aes.js" charset="utf-8"></script>
+<script src="<%= BASE_URL %>cdn/vue/2.6.10/vue.min.js" charset="utf-8"></script>
+<script src="<%= BASE_URL %>cdn/vuex/3.1.1/vuex.min.js" charset="utf-8"></script>
+<script src="<%= BASE_URL %>cdn/vue-router/3.0.1/vue-router.min.js" charset="utf-8"></script>
+<script src="<%= BASE_URL %>cdn/axios/1.0.0/axios.min.js" charset="utf-8"></script>
+<script src="<%= BASE_URL %>cdn/element-ui/2.15.1/index.js" charset="utf-8"></script>
+<script src="<%= BASE_URL %>cdn/avue/2.8.12/avue.min.js" charset="utf-8"></script>
+</body>
 
 </html>

+ 25 - 0
src/api/device/gb/gbdevicechannel.js

@@ -72,3 +72,28 @@ export const stopPlay = (deviceId, channelId) => {
   })
 }
 
+export const getGbChannelLazyTree = (parentColumn, parentId) => {
+  return request({
+    url: '/api/cyzh-smart-device/gbdevicechannel/lazy-tree',
+    method: 'get',
+    params: {
+      parentColumn,
+      parentId
+    }
+  })
+}
+
+export const channelBindLocal = (deviceId, channelId, residentialId, buildingId, floorId, installAddress) => {
+  return request({
+    url: '/api/cyzh-smart-device/gbdevicechannel/bind',
+    method: 'post',
+    params: {
+      deviceId,
+      channelId,
+      residentialId,
+      buildingId,
+      floorId,
+      installAddress
+    }
+  })
+}

+ 2 - 3
src/api/device/wvpvideodevice.js

@@ -1,14 +1,13 @@
 import request from '@/router/axios';
 
 //绑定设备
-export const bind = (deviceId, agencyId, residentialId) => {
+export const bind = (deviceId, agencyId) => {
   return request({
     url: '/api/cyzh-third/wvp/device/bind',
     method: 'post',
     params: {
       deviceId,
-      agencyId,
-      residentialId,
+      agencyId
     }
   })
 }

+ 0 - 2
src/components/scene/wvp/jessibuca.vue

@@ -11,8 +11,6 @@
         </div>
         <div class="buttons-box-right">
           <span class="jessibuca-btn">{{kBps}} kb/s</span>
-<!--          <i class="iconfont icon-file-record1 jessibuca-btn"></i>-->
-<!--          <i class="iconfont icon-xiangqing2 jessibuca-btn" ></i>-->
           <i class="icon-jietu jessibuca-btn" @click="jessibuca.screenshot('截图','png',0.5)" style="font-size: 0.2rem !important"></i>
           <i class="icon-shuaxin jessibuca-btn" @click="playBtnClick"></i>
           <i v-if="!fullscreen" class="iconfont icon-quanping  jessibuca-btn" @click="fullscreenSwich"></i>

+ 1 - 1
src/config/website.js

@@ -2,7 +2,7 @@
  * 全局配置文件
  */
 export default {
-  title: "榕基-SMART   智慧园区大数据平台",
+  title: "常运-SMART   智慧园区大数据平台",
   logo: "CY",
   key: 'saber',//配置主键,目前用于存储
   indexTitle: '智慧园区大数据平台',

+ 1 - 1
src/lang/zh.js

@@ -1,6 +1,6 @@
 export default {
   tip: '提示',
-  title: '榕基智慧园区',
+  title: '常运智慧园区',
   logoutTip: '退出系统, 是否继续?',
   submitText: '确定',
   cancelText: '取消',

+ 2 - 1
src/page/login/userlogin.vue

@@ -153,7 +153,8 @@
                 var _this = this;
                 getTenantTypeByTenantId(this.loginForm.tenantId).then((r) => {
                   console.log(r.data.data.tenantType == 1)
-                  localStorage.setItem("tenantType", r.data.data.tenantType)
+                  localStorage.setItem("tenantType", r.data.data.tenantType);
+                  localStorage.setItem("tenantId", r.data.data.tenantId);
 
                   if (r.data.data.tenantType == 1) {
                     let routeUrl = this.$router.resolve({

+ 54 - 26
src/views/accesscontrolmng/doordevice.vue

@@ -51,6 +51,11 @@
         <el-tag v-if="row.deviceStatus === 1" type="success">在线</el-tag>
         <el-tag v-if="row.deviceStatus === 2" type="danger">异常</el-tag>
       </template>
+      <template slot="localType" slot-scope="{row}">
+        <el-tag v-if="row.localType === 1" type="primary">普通点位</el-tag>
+        <el-tag v-if="row.localType === 2" type="danger">特殊点位</el-tag>
+
+      </template>
     </avue-crud>
   </basic-container>
 </template>
@@ -114,6 +119,54 @@ export default {
               trigger: "blur"
             }]
           },
+          {
+            label: "点位类型",
+            prop: "localType",
+            type: "select",
+            search: true,
+            searchSpan: 4,
+            width: 100,
+            align: "center",
+            slot: true,
+            dicData:[
+              {
+                label: "普通点位",
+                value: 1
+              },
+              {
+                label: "特殊点位",
+                value: 2
+              }
+            ],
+            rules: [{
+              required: true,
+              message: "请选择点位类型",
+              trigger: "blur"
+            }]
+          },
+          {
+            label: "进出方向",
+            prop: "isOut",
+            type: "select",
+            width: 80,
+            hide: true,
+            align: "center",
+            dicData:[
+              {
+                label: "进",
+                value: 1,
+              },
+              {
+                label: "出",
+                value: 2
+              }
+            ],
+            rules: [{
+              required: true,
+              message: "请输入进出方向",
+              trigger: "blur"
+            }]
+          },
           {
             label: "所属园区",
             prop: "agencyName",
@@ -231,7 +284,6 @@ export default {
             label: "所属单元",
             prop: "unitId",
             type: "select",
-            search: true,
             searchSpan: 4,
             searchFilterable: true,
             hide: true,
@@ -254,7 +306,6 @@ export default {
             label: "所属楼层",
             prop: "floorId",
             type: "select",
-            search: true,
             searchFilterable: true,
             hide: true,
             searchSpan: 4,
@@ -295,30 +346,7 @@ export default {
             }],
           },
           {
-            label: "进出方向",
-            prop: "isOut",
-            type: "select",
-            width: 80,
-            hide: true,
-            align: "center",
-            dicData:[
-              {
-                label: "进",
-                value: 1,
-              },
-              {
-                label: "出",
-                value: 2
-              }
-            ],
-            rules: [{
-              required: true,
-              message: "请输入进出方向",
-              trigger: "blur"
-            }]
-          },
-          {
-            label: "安装地址",
+            label: "安装位置",
             prop: "address",
             hide: true,
             overHidden: true,

+ 1 - 1
src/views/community/residential.vue

@@ -93,7 +93,7 @@
     add,
     update,
     remove,
-    updateResidential,
+    // updateResidential,
     syncHouseInfoAndUser,
     syncBuilding,
     syncUnit,

+ 22 - 42
src/views/device/videodevice/wvp/wvpvideodevice.vue

@@ -26,7 +26,7 @@
           <el-button-group>
             <el-button size="mini" :disabled="row.online != 1" type="primary" icon="el-icon-video-camera-solid" @click="handleChannel(row.deviceId)">通 道</el-button>
             <el-button size="mini" icon="el-icon-delete" type="danger" v-if="row.online != 1"  @click="deleteDevice(row.deviceId)">删除</el-button>
-            <el-button size="mini" type="success" @click="bindDevice(row)">绑 定</el-button>
+            <el-button size="mini" type="success" @click="showBindDialog(row)">绑 定</el-button>
           </el-button-group>
         </template>
       </avue-crud>
@@ -73,8 +73,8 @@
       </avue-crud>
     </basic-container>
     <devicePlayer ref="devicePlayer"></devicePlayer>
-    <el-dialog :modal-append-tobody="false" append-to-body :visible.sync="bindVisible" title="设备绑定" width="60%">
-      <select-dialog-residential :id="form.residentialId" :name="form.residentialName" :callback="selectCallback" v-if="bindVisible"></select-dialog-residential>
+    <el-dialog :modal-append-tobody="false" append-to-body :visible.sync="bindVisible" title="设备绑定" width="20%">
+      <avue-form :option="bindOption" v-model="bindForm" @submit="bindSubmit"></avue-form>
     </el-dialog>
 
   </basic-container>
@@ -114,7 +114,6 @@ export default {
       curDeviceId: null,
       showDeviceChannelCrud: false,
       bindBatchForm:{},
-      bindForm: {},
       videoVisible: false,
       video: {},
       editVisiable: false,
@@ -126,7 +125,6 @@ export default {
       form: {},
       query: {},
       loading: true,
-      bindVisible: false,
       bindBatchVisible: false,
       residentialList: [],
       page: {
@@ -135,7 +133,6 @@ export default {
         total: 0
       },
       selectionList: [],
-
       deviceOption: {
         menu: true,
         menuWidth:300,
@@ -153,7 +150,8 @@ export default {
         selection: true,
         dialogClickModal: false,
         addBtn:false,
-        column: [{
+        column: [
+          {
             label: "设备编号",
             prop: "deviceId",
             span: 12,
@@ -325,45 +323,28 @@ export default {
           },
         ]
       },
+      bindForm:{},
       bindOption: {
         column: [
           {
-            label: "所属区",
-            prop: "residentialId",
+            label: "所属区",
+            prop: "agencyId",
             type: "select",
-            search: true,
+            remote: true,
+            props: {
+              label: 'name',
+              value: 'id'
+            },
             span:24,
-            cascaderItem: ['buildingId'],
-            dicUrl: "/api/cyzh-community/residential/list?size=9999",
+            dicUrl: "/api/cyzh-community/agency/list?size=100&name={{key}}",
             dicFormatter:(res)=>{
               return res.data.records;//返回字典的层级结构
             },
-            props: {
-              label: "name",
-              value: "id"
-            },
             rules: [{
               required: true,
-              message: "请选择所属区",
+              message: "请选择所属园区",
               trigger: "blur"
             }]
-          },
-          {
-            label: "所属楼栋",
-            prop: "buildingId",
-            search: true,
-            type: "select",
-            span:24,
-            cascaderIndex: 0,
-            dicUrl: "/api/cyzh-community/building/list?residentialId={{key}}",
-            dicFormatter:(res) => {
-              return res.data.records;//返回字典层级结构
-            },
-            filterable: true,
-            props: {
-              label: "name",
-              value: "id"
-            },
           }]
       },
       data: []
@@ -392,19 +373,18 @@ export default {
     }
   },
   methods: {
-    bindDevice(row){
+    showBindDialog(row){
       this.bindVisible = true;
       this.deviceId = row.deviceId;
     },
-    selectCallback(row){
-      this.form.residentialId = row.id;
-      this.form.agencyId = row.agencyId;
-      this.form.deviceId = this.deviceId;
-      bind(this.deviceId, row.agencyId, row.id).then(() =>{
-
+    bindSubmit(form){
+      bind(this.deviceId, form.agencyId).then(() =>{
+        this.$message({
+          type: "success",
+          message: "绑定成功!"
+        });
       });
       this.bindVisible = false;
-      return;
     },
     dateFormat(fmt, date) {
       let ret;

+ 116 - 69
src/views/videoapply/comp/jessibuca.vue

@@ -1,31 +1,26 @@
 <template>
-  <div id="jessibuca" style="width: auto; height: auto">
-    <div id="container" ref="container" style="width: 100%; height: 10rem; background-color: #000" @dblclick="fullscreenSwich">
-      <div class="buttons-box" id="buttonsBox">
-        <div class="buttons-box-left">
-          <i v-if="!playing" class="iconfont icon-bofang jessibuca-btn" @click="playBtnClick"></i>
-          <i v-if="playing" class="iconfont icon-zanting jessibuca-btn" @click="pause"></i>
-          <i class="icon-stop jessibuca-btn" @click="destroy"></i>
-          <i v-if="isNotMute" class="iconfont icon-hanhan-01-01 jessibuca-btn" @click="jessibuca.mute()"></i>
-          <i v-if="!isNotMute" class="iconfont icon-jingyin  jessibuca-btn" @click="jessibuca.cancelMute()"></i>
-        </div>
-        <div class="buttons-box-right">
-          <span class="jessibuca-btn">{{kBps}} kb/s</span>
-<!--          <i class="iconfont icon-file-record1 jessibuca-btn"></i>-->
-<!--          <i class="iconfont icon-xiangqing2 jessibuca-btn" ></i>-->
-          <i class="icon-jietu jessibuca-btn" @click="jessibuca.screenshot('截图','png',0.5)" style="font-size: 0.2rem !important"></i>
-          <i class="icon-shuaxin jessibuca-btn" @click="playBtnClick"></i>
-          <i v-if="!fullscreen" class="iconfont icon-quanping  jessibuca-btn" @click="fullscreenSwich"></i>
-          <i v-if="fullscreen" class="iconfont icon-tuichuquanping  jessibuca-btn" @click="fullscreenSwich"></i>
-        </div>
+    <div>
+      <div :id="container" :ref="container" class="container-shell"></div>
+<!--      <div class="buttons-box" id="buttonsBox">-->
+<!--        <div class="buttons-box-left">-->
+<!--          <i v-if="!playing" class="iconfont icon-bofang jessibuca-btn" @click="playBtnClick"></i>-->
+<!--          <i v-if="playing" class="iconfont icon-zanting jessibuca-btn" @click="pause"></i>-->
+<!--          <i class="icon-stop jessibuca-btn" @click="destroy"></i>-->
+<!--          <i v-if="isNotMute" class="iconfont icon-hanhan-01-01 jessibuca-btn" @click="jessibuca.mute()"></i>-->
+<!--          <i v-if="!isNotMute" class="iconfont icon-jingyin  jessibuca-btn" @click="jessibuca.cancelMute()"></i>-->
+<!--        </div>-->
+<!--        <div class="buttons-box-right">-->
+<!--          <span class="jessibuca-btn">{{kBps}} kb/s</span>-->
+<!--          <i class="icon-jietu jessibuca-btn" @click="jessibuca.screenshot('截图','png',0.5)" style="font-size: 0.2rem !important"></i>-->
+<!--          <i class="icon-shuaxin jessibuca-btn" @click="playBtnClick"></i>-->
+<!--          <i v-if="!fullscreen" class="iconfont icon-quanping  jessibuca-btn" @click="fullscreenSwich"></i>-->
+<!--          <i v-if="fullscreen" class="iconfont icon-tuichuquanping  jessibuca-btn" @click="fullscreenSwich"></i>-->
+<!--        </div>-->
+<!--      </div>-->
     </div>
-
-    </div>
-  </div>
 </template>
 
 <script scope>
-  // import "@/styles/wvp/css/iconfont.css"
   export default {
     name: 'jessibuca',
     data() {
@@ -47,52 +42,43 @@
           forceNoOffscreen: false,
         };
     },
-    props: ['videoUrl', 'error', 'hasAudio', 'height'],
+    props: ['videoUrl', 'error', 'hasAudio', 'height', 'jessibucaId', 'container', 'buttonsBoxId'],
     mounted () {
       window.onerror = (msg) => {
-        // console.error(msg)
+
       };
       let paramUrl = decodeURIComponent(this.$route.params.url)
        this.$nextTick(() =>{
-         let dom = document.getElementById("container");
-         dom.style.height = (9/16 ) * dom.clientWidth + "px"
+         console.log('container=====' + this.container)
+         let dom = document.getElementById(this.container);
           if (typeof (this.videoUrl) == "undefined") {
             this.videoUrl = paramUrl;
           }
-         this.btnDom = document.getElementById("buttonsBox");
+         this.btnDom = document.getElementById(this.buttonsBoxId);
           console.log("初始化时的地址为: " + this.videoUrl)
-         this.play(this.videoUrl)
         })
     },
-    watch:{
-        videoUrl(newData, oldData){
-            this.play(newData)
-        },
-        immediate:true
-    },
     methods: {
-        create(){
+      create(){
           let options =  {};
-          console.log(this.$refs.container)
-          console.log("hasAudio  " + this.hasAudio)
-
+          console.log(this.$refs['container' + this.container.charAt(this.container.length-1)]);
           this.jessibuca = new window.Jessibuca(Object.assign(
             {
-              container: this.$refs.container,
+              container: document.getElementById(this.container),
               videoBuffer: 0.5, // 最大缓冲时长,单位秒
               isResize: true,
+              isFullResize: true,
               decoder: "./js/jessibuca/index.js",
-              // text: "WVP-PRO",
-              // background: "bg.jpg",
+              background: "bg.jpg",
               loadingText: "加载中",
               hasAudio: typeof (this.hasAudio) =="undefined"? true: this.hasAudio,
               debug: false,
               supportDblclickFullscreen: false, // 是否支持屏幕的双击事件,触发全屏,取消全屏事件。
               operateBtns: {
-                fullscreen: false,
-                screenshot: false,
-                play: false,
-                audio: false,
+                fullscreen: true,
+                screenshot: true,
+                play: true,
+                audio: true,
               },
               record: "record",
               vod: this.vod,
@@ -101,7 +87,6 @@
             },
             options
           ));
-
           let _this = this;
           this.jessibuca.on("load", function () {
             console.log("on load init");
@@ -195,10 +180,10 @@
 
           });
         },
-        playBtnClick: function (event){
+      playBtnClick: function (event){
           this.play(this.videoUrl)
         },
-        play: function (url) {
+      play: function (url) {
           console.log(url)
             if (this.jessibuca) {
               this.destroy();
@@ -218,7 +203,7 @@
               });
             }
         },
-        pause: function () {
+      pause: function () {
           if (this.jessibuca) {
             this.jessibuca.pause();
           }
@@ -226,35 +211,39 @@
           this.err = "";
           this.performance = "";
         },
-        destroy: function () {
-          if (this.jessibuca) {
-            this.jessibuca.destroy();
-          }
-          if (document.getElementById("buttonsBox") == null) {
-            document.getElementById("container").appendChild(this.btnDom)
-          }
-          this.jessibuca = null;
-          this.playing = false;
-          this.err = "";
-          this.performance = "";
+      destroy: function () {
+        if (this.jessibuca) {
+          this.jessibuca.destroy();
+        }
+        // if (document.getElementById(this.buttonsBoxId) == null) {
+        //   document.getElementById(this.container).appendChild(this.btnDom)
+        // }
+        this.create();
+        this.jessibuca = null;
+        this.playing = false;
+        this.err = "";
+        this.performance = "";
 
         },
-        eventcallbacK: function(type, message) {
+      eventcallbacK: function(type, message) {
             // console.log("player 事件回调")
             // console.log(type)
             // console.log(message)
         },
-        fullscreenSwich: function (){
-            let isFull = this.isFullscreen()
-            this.jessibuca.setFullscreen(!isFull)
-            this.fullscreen = !isFull;
+      fullscreenSwitch: function (){
+          let isFull = this.isFullscreen()
+          this.jessibuca.setFullscreen(!isFull)
+          this.fullscreen = !isFull;
         },
-        isFullscreen: function (){
+      isFullscreen: function (){
           return document.fullscreenElement ||
             document.msFullscreenElement  ||
             document.mozFullScreenElement ||
             document.webkitFullscreenElement || false;
-        }
+        },
+      resize(){
+        this.jessibuca.resize();
+      }
     },
     destroyed() {
       if (this.jessibuca) {
@@ -271,7 +260,7 @@
   .buttons-box{
     width: 100%;
     height: 28px;
-    background-color: rgba(43, 51, 63, 0.7);
+    background-color: #000000;
     position: absolute;
     display: -webkit-box;
     display: -ms-flexbox;
@@ -295,4 +284,62 @@
     position: absolute;
     right: 0;
   }
+  .containerClass{
+    background-color: #000;
+  }
+  .container-shell {
+    backdrop-filter: blur(5px);
+    background: #000000;
+    width: auto;
+    position: relative;
+    border-radius: 5px;
+    box-shadow: 0 5px 5px;
+  }
+  .container-shell:before {
+    position: absolute;
+    color: darkgray;
+    top: 4px;
+    left: 10px;
+    text-shadow: 1px 1px black;
+  }
+  .input {
+    display: flex;
+    margin-top: 10px;
+    color: white;
+    place-content: stretch;
+  }
+  .input2 {
+    bottom: 0px;
+  }
+  .input input {
+    flex: auto;
+  }
+  .err {
+    position: absolute;
+    top: 40px;
+    left: 10px;
+    color: red;
+  }
+  .option {
+    position: absolute;
+    top: 4px;
+    right: 10px;
+    display: flex;
+    place-content: center;
+    font-size: 12px;
+  }
+  .option span {
+    color: white;
+  }
+  .page {
+    background: url(/bg.jpg);
+    background-repeat: no-repeat;
+    background-position: top;
+  }
+  @media (max-width: 720px) {
+    #container {
+      width: 90vw;
+      height: 52.7vw;
+    }
+  }
 </style>

+ 659 - 0
src/views/videoapply/comp/videomanage.vue

@@ -0,0 +1,659 @@
+<template>
+  <basic-container>
+    <avue-crud v-if="!showDeviceChannelCrud"
+               :option="deviceOption"
+               :table-loading="loading"
+               :data="data"
+               :page.sync="page"
+               :permission="permissionList"
+               :before-open="beforeOpen"
+               v-model="form"
+               ref="crud"
+               @row-update="rowUpdate"
+               @row-save="rowSave"
+               @row-del="rowDel"
+               @search-change="searchChange"
+               @search-reset="searchReset"
+               @selection-change="selectionChange"
+               @current-change="currentChange"
+               @size-change="sizeChange"
+               @refresh-change="refreshChange"
+               @on-load="onLoad">
+      <template slot="menuLeft">
+        <el-button type="danger"
+                   size="small"
+                   icon="el-icon-delete"
+                   plain
+                   v-if="permission.gbdevice_delete"
+                   @click="handleDelete">删 除
+        </el-button>
+      </template>
+      <template slot="online" slot-scope="{row}">
+        <el-tag v-if="row.online === 1" type="success">在线</el-tag>
+        <el-tag v-if="row.online === 0" type="info">离线</el-tag>
+      </template>
+      <template slot="hostAddress" slot-scope="{row}">
+        <el-tag type="primary">{{row.hostAddress}}</el-tag>
+      </template>
+      <template slot="menu" slot-scope="{row}">
+        <el-button type="text" size="mini" icon="el-icon-setting">
+          <el-dropdown>
+                <span class="el-dropdown-link">
+                  操作<i class="el-icon-arrow-down el-icon--right"></i>
+                </span>
+            <el-dropdown-menu slot="dropdown">
+              <el-dropdown-item style="color: limegreen" @click.native="handleSync(row, row.$index)" icon="el-icon-refresh">刷新</el-dropdown-item>
+              <el-dropdown-item style="color: #0087ff" @click.native="handleChannel(row.deviceId)" icon="el-icon-video-camera-solid">通道</el-dropdown-item>
+            </el-dropdown-menu>
+          </el-dropdown>
+        </el-button>
+      </template>
+    </avue-crud>
+    <avue-crud v-if="showDeviceChannelCrud" :option="deviceChannelOption" :table-loading="loading" :data="data" :page="page" :permission="permissionList"
+               :before-open="beforeOpen" v-model="form" ref="crud" @row-update="rowUpdate" @row-save="rowSave" @row-del="rowDel"
+               @search-change="channelSearchChange" @search-reset="searchReset" @selection-change="selectionChange" @current-change="currentChange"
+               @size-change="sizeChange" @refresh-change="refreshChannelChange" @on-load="onLoadChannel">
+      <template slot-scope="{row}" slot="channelTypeSearch">
+        <el-select size="mini" style="margin-right: 1rem;" v-model="row.channelType" placeholder="请选择" default-first-option>
+          <el-option label="全部" value=""></el-option>
+          <el-option label="设备" value="false"></el-option>
+          <el-option label="子目录" value="true"></el-option>
+        </el-select>
+      </template>
+      <template slot-scope="{row}" slot="online">
+        <el-select size="mini" style="margin-right: 1rem;" v-model="row.online" placeholder="请选择" default-first-option>
+          <el-option label="全部" value=""></el-option>
+          <el-option label="在线" value="true"></el-option>
+          <el-option label="离线" value="false"></el-option>
+        </el-select>
+      </template>
+      <template slot="menuLeft">
+        <el-button type="primary" size="mini" icon="el-icon-arrow-left" @click="backToDeviceList">返 回</el-button>
+      </template>
+      <template slot="hasAudio" slot-scope="{row}">
+        <el-switch @change="updateChannel(scope.row)" v-model="row.hasAudio" active-color="#409EFF">
+        </el-switch>
+      </template>
+      <template slot="status" slot-scope="{row}">
+        <el-tag size="medium" v-if="row.status == 1">开启</el-tag>
+        <el-tag size="medium" v-else="row.status == 0">关闭</el-tag>
+      </template>
+      <template slot="menu" slot-scope="{row}">
+        <el-button size="mini" type="warning" @click="showBindDialog(row)">点位绑定</el-button>
+        <el-button size="mini" icon="el-icon-video-play" v-if="permission.gbdevicechannel_play" @click="devicePlay(row)">播放</el-button>
+        <el-button size="mini" icon="el-icon-switch-button" type="danger" :loading="stopBtnLoading" v-if="permission.gbdevicechannel_stop && !!row.streamId" @click="deviceStopPlay(row)">停止</el-button>
+        <!--          <el-button size="mini" type="primary" icon="el-icon-video-camera" v-if="permission.wvpvideodevice_record" @click="deviceRecord(row)">设备录像</el-button>-->
+      </template>
+    </avue-crud>
+    <devicePlayer ref="devicePlayer"></devicePlayer>
+    <el-dialog :modal-append-tobody="false" append-to-body :visible.sync="bindVisible" title="点位绑定" width="20%">
+      <avue-form :option="bindOption" v-model="bindForm" @submit="bindSubmit"></avue-form>
+    </el-dialog>
+  </basic-container>
+</template>
+
+<script>
+    import {getList, getDetail, add, update, remove, bind, sync} from "@/api/device/gb/gbdevice";
+    import {getList as getChannelList, startPlay, stopPlay, channelBindLocal} from "@/api/device/gb/gbdevicechannel";
+    import devicePlayer from "./devicePlayer";
+    import {mapGetters} from "vuex";
+    import videowall from "./videowall";
+    export default {
+      name: "videomanage",
+      components: {devicePlayer},
+      data(){
+        return{
+          form: {},
+          query: {},
+          loading: true,
+          bindVisible: false,
+          showDeviceChannelCrud: false,
+          deviceId: null,
+          channelId: null,
+          stopBtnLoading: false,
+          selectionList: [],
+          bindForm:{},
+          bindOption: {
+            column: [
+              {
+                label: "所属区域",
+                prop: "residentialId",
+                type: "select",
+                remote: true,
+                filterable: true,
+                cascaderItem: ['buildingId'],
+                props: {
+                  label: 'name',
+                  value: 'id'
+                },
+                span:24,
+                dicUrl: "/api/cyzh-community/residential/list?size=10&name={{key}}",
+                dicFormatter:(res)=>{
+                  return res.data.records;//返回字典的层级结构
+                },
+                rules: [{
+                  required: true,
+                  message: "请选择所属区域",
+                  trigger: "blur"
+                }]
+              },
+              {
+                label: "所属楼栋",
+                prop: "buildingId",
+                type: "select",
+                search: true,
+                cascaderItem: ['floorId'],
+                dicUrl: "/api/cyzh-community/building/list?residentialId={{key}}",
+                dicFormatter:(res)=>{
+                  return res.data.records;//返回字典的层级结构
+                },
+                span:24,
+                filterable: true,
+                props: {
+                  label: "name",
+                  value: "id"
+                },
+                rules: [{
+                  required: false,
+                  message: "请选择所属楼栋",
+                  trigger: "blur"
+                }]
+              },
+              {
+                label: "所属楼层",
+                prop: "floorId",
+                type: "select",
+                search: true,
+                span:24,
+                dicUrl: "/api/cyzh-community/floor/list?buildingId={{key}}",
+                dicFormatter:(res)=>{
+                  return res.data.records;//返回字典的层级结构
+                },
+                filterable: true,
+                props: {
+                  label: "name",
+                  value: "id"
+                },
+                rules: [{
+                  required: false,
+                  message: "请选择所属楼层",
+                  trigger: "blur"
+                }]
+              },
+              {
+                label: '安装位置',
+                prop: 'installAddress',
+                span:24,
+                placeholder: "机房,厨房,墙角",
+                rules: [{
+                  required: false,
+                  message: "请输入安装位置",
+                  trigger: "blur"
+                }]
+              }]
+          },
+          deviceOption: {
+            height:'auto',
+            calcHeight: 30,
+            tip: false,
+            searchShow: true,
+            searchMenuSpan: 6,
+            border: true,
+            index: true,
+            viewBtn: true,
+            selection: true,
+            dialogClickModal: false,
+            column: [
+              {
+                label: "设备编号",
+                prop: "deviceId",
+              },
+              {
+                label: "设备名称",
+                prop: "name",
+              },
+              {
+                label: "厂商名称",
+                prop: "manufacturer",
+              },
+              {
+                label: "型号",
+                prop: "model",
+                hide:true,
+                disabled: true
+              },
+              {
+                label: "传输协议",
+                prop: "transport",
+                hide:true,
+                disabled: true
+              },
+              {
+                label: "流传输模式",
+                prop: "streamMode",
+                hide:true,
+                disabled: true,
+                type: "select",
+                dicData:[
+                  {
+                    label: "udp传输",
+                    value: "UDP"
+                  },
+                  {
+                    label: "tcp主动模式",
+                    value: "TCP-ACTIVE"
+                  },
+                  {
+                    label: "tcp被动模式",
+                    value: "TCP-PASSIVE"
+                  },
+                ]
+              },
+              {
+                label: "在线状态",
+                prop: "online",
+                slot:true,
+                search: true,
+                type: "select",
+                width: 100,
+                align: "center",
+                dicData:[
+                  {
+                    label: "在线",
+                    value: 1
+                  },
+                  {
+                    label: "离线",
+                    value: 0
+                  }
+                ]
+              },
+              {
+                label: "注册时间",
+                prop: "registerTime",
+              },
+              {
+                label: "心跳时间",
+                prop: "keepaliveTime",
+              },
+              {
+                label: "wan地址",
+                prop: "hostAddress",
+                slot: true
+              },
+              {
+                label: "所属园区",
+                prop: "agencyName",
+              },
+              {
+                label: "所属园区",
+                prop: "agencyId",
+                hide: true,
+                search: true,
+                filterable: true,
+                cascaderItem: ['residentialId'],
+                type: "select",
+                remote: true,
+                dicUrl: "/api/cyzh-community/agency/list?size=10&name={{key}}",
+                dicFormatter:(res)=>{
+                  return res.data.records;//返回字典的层级结构
+                },
+                props: {
+                  label: "name",
+                  value: "id"
+                },
+              },
+              /*{
+                label: "所属区域",
+                prop: "residentialId",
+                hide: true,
+                slot: true,
+                type: "select",
+                search: true,
+                dicUrl: "/api/cyzh-community/residential/list?agencyId={{key}}",
+                dicFormatter:(res)=>{
+                  return res.data.records;//返回字典的层级结构
+                },
+                filterable: true,
+                props: {
+                  label: "name",
+                  value: "id"
+                },
+              },*/
+            ]
+          },
+          deviceChannelOption: {
+            menu: true,
+            menuWidth: 300,
+            height: 'auto',
+            calcHeight: 30,
+            tip: false,
+            searchShow: true,
+            searchMenuSpan: 6,
+            labelWidth: 150,
+            border: true,
+            index: true,
+            viewBtn: false,
+            editBtn: true,
+            delBtn: false,
+            selection: true,
+            dialogClickModal: false,
+            addBtn:false,
+            column: [
+              {
+                label: "通道编号",
+                prop: "channelId",
+                span: 12,
+              },
+              {
+                label: "设备编号",
+                prop: "deviceId",
+                span: 12,
+              },
+              {
+                label: "通道名称",
+                prop: "name",
+                span: 12,
+                width: 100,
+                search: true
+              },
+              {
+                label: "安装点位",
+                prop: "installLocal",
+              },
+              {
+                label: "开启音频",
+                prop: "hasAudio",
+                span: 12,
+                width: 80,
+                slot: true
+              },
+              {
+                label: "状态",
+                prop: "status",
+                span: 12,
+                width:80,
+                slot: true
+              },
+              {
+                label: "云台类型",
+                prop: "ptzType",
+                span: 12,
+                type: "select",
+                dicData:[
+                  {
+                    label: "未知",
+                    value: 0
+                  },
+                  {
+                    label: "球机",
+                    value: 1
+                  },
+                  {
+                    label: "半球",
+                    value: 2
+                  },
+                  {
+                    label: "固定枪机",
+                    value: 3
+                  },
+                  {
+                    label: "遥控枪机",
+                    value: 4
+                  }
+                ]
+              }
+            ]
+          },
+          page: {
+            pageSize: 10,
+            currentPage: 1,
+            total: 0
+          },
+          data:[]
+        };
+      },
+      computed: {
+        ...mapGetters(["permission"]),
+        permissionList() {
+          return {
+            addBtn: this.vaildData(this.permission.gbdevice_add, false),
+            viewBtn: this.vaildData(this.permission.gbdevice_view, false),
+            delBtn: this.vaildData(this.permission.gbdevice_delete, false),
+            editBtn: this.vaildData(this.permission.gbdevice_edit, false)
+          };
+        },
+        ids() {
+          let ids = [];
+          this.selectionList.forEach(ele => {
+            ids.push(ele.id);
+          });
+          return ids.join(",");
+        }
+      },
+      methods: {
+        showBindDialog(row){
+          this.bindVisible = true;
+          this.deviceId = row.deviceId;
+          this.channelId = row.channelId;
+        },
+        bindSubmit(form,done){
+          channelBindLocal(this.deviceId, this.channelId, form.residentialId, form.buildingId, form.floorId, form.installAddress).then(() =>{
+            this.onLoadChannel(this.page);
+            this.$message({
+              type: "success",
+              message: "绑定成功!"
+            });
+            done();
+          });
+          this.deviceId = null;
+          this.channelId = null;
+          this.bindVisible = false;
+        },
+        devicePlay(row){
+          let deviceId = row.deviceId;
+          let channelId = row.channelId;
+          let that = this;
+          startPlay(deviceId, channelId).then(res => {
+            if (res.data.code == 200) {
+              that.$refs.devicePlayer.openDialog("media", deviceId, channelId, {
+                streamInfo: res.data.data,
+                hasAudio: row.hasAudio
+              });
+              that.onLoadChannel(that.page);
+            }else {
+              that.$message.error(res.data.msg);
+            }
+          });
+        },
+        deviceStopPlay(row) {
+          let that = this;
+          let deviceId = row.deviceId;
+          let channelId = row.channelId;
+          this.stopBtnLoading = true;
+          stopPlay(deviceId, channelId).then(res => {
+            console.log(JSON.stringify(res));
+            that.onLoadChannel(that.page);
+            this.stopBtnLoading = false;
+          }).catch(err => {
+            if (err.response.status === 402) { // 已经停止过
+              that.onLoadChannel(that.page);
+            }else {
+              console.log(err)
+            }
+          });
+        },
+        channelSearchChange(params, done){
+          this.query = params;
+          this.page.currentPage = 1;
+          params.deviceId = this.deviceId;
+          this.onLoadChannel(this.page, params);
+          done();
+        },
+        handleSync(row, index){
+          sync(row).then(res => {
+            let result = res.data.data;
+            this.$set(this.data, index, result)
+            this.$message({
+              type: "success",
+              message: "操作成功!"
+            });
+          });
+        },
+        onLoadChannel(page, params = {}) {
+          this.loading = true;
+          getChannelList(page.currentPage, page.pageSize, Object.assign(params, this.query)).then(res => {
+            const data = res.data.data;
+            this.page.total = data.total;
+            this.data = data.records;
+            this.loading = false;
+            this.selectionClear();
+          });
+        },
+        backToDeviceList(){
+          this.showDeviceChannelCrud = false;
+          this.deviceId = null;
+          this.onLoad(this.page);
+        },
+        handleChannel(deviceId){
+          this.showDeviceChannelCrud = true;
+          this.deviceId = deviceId;
+          this.page.currentPage = 1;
+          this.onLoadChannel(this.page, {"deviceId": deviceId});
+        },
+        bindDevice(row){
+          this.bindVisible = true;
+          this.deviceId = row.deviceId;
+        },
+        refreshChannelChange() {
+          this.onLoadChannel(this.page, this.query);
+        },
+        selectCallback(row){
+          this.form.residentialId = row.id;
+          this.form.agencyId = row.agencyId;
+          this.form.deviceId = this.deviceId;
+          bind(this.form).then(() =>{
+            this.onLoad(this.page);
+            this.$message({
+              type: "success",
+              message: "操作成功!"
+            });
+          });
+          this.bindVisible = false;
+        },
+        rowSave(row, done, loading) {
+          add(row).then(() => {
+            this.onLoad(this.page);
+            this.$message({
+              type: "success",
+              message: "操作成功!"
+            });
+            done();
+          }, error => {
+            loading();
+            window.console.log(error);
+          });
+        },
+        rowUpdate(row, index, done, loading) {
+          update(row).then(() => {
+            this.onLoad(this.page);
+            this.$message({
+              type: "success",
+              message: "操作成功!"
+            });
+            done();
+          }, error => {
+            loading();
+            console.log(error);
+          });
+        },
+        rowDel(row) {
+          this.$confirm("确定将选择数据删除?", {
+            confirmButtonText: "确定",
+            cancelButtonText: "取消",
+            type: "warning"
+          })
+            .then(() => {
+              return remove(row.id);
+            })
+            .then(() => {
+              this.onLoad(this.page);
+              this.$message({
+                type: "success",
+                message: "操作成功!"
+              });
+            });
+        },
+        handleDelete() {
+          if (this.selectionList.length === 0) {
+            this.$message.warning("请选择至少一条数据");
+            return;
+          }
+          this.$confirm("确定将选择数据删除?", {
+            confirmButtonText: "确定",
+            cancelButtonText: "取消",
+            type: "warning"
+          })
+            .then(() => {
+              return remove(this.ids);
+            })
+            .then(() => {
+              this.onLoad(this.page);
+              this.$message({
+                type: "success",
+                message: "操作成功!"
+              });
+              this.$refs.crud.toggleSelection();
+            });
+        },
+        beforeOpen(done, type) {
+          if (["edit", "view"].includes(type)) {
+            getDetail(this.form.id).then(res => {
+              this.form = res.data.data;
+            });
+          }
+          done();
+        },
+        searchReset() {
+          this.query = {};
+          this.onLoad(this.page);
+        },
+        searchChange(params, done) {
+          this.query = params;
+          this.page.currentPage = 1;
+          this.onLoad(this.page, params);
+          done();
+        },
+        selectionChange(list) {
+          this.selectionList = list;
+        },
+        selectionClear() {
+          this.selectionList = [];
+          this.$refs.crud.toggleSelection();
+        },
+        currentChange(currentPage){
+          this.page.currentPage = currentPage;
+        },
+        sizeChange(pageSize){
+          this.page.pageSize = pageSize;
+        },
+        refreshChange() {
+          this.onLoad(this.page, this.query);
+        },
+        onLoad(page, params = {}) {
+          this.loading = true;
+          getList(page.currentPage, page.pageSize, Object.assign(params, this.query)).then(res => {
+            const data = res.data.data;
+            this.page.total = data.total;
+            this.data = data.records;
+            this.loading = false;
+            this.selectionClear();
+          });
+        }
+      }
+    }
+</script>
+
+<style scoped>
+
+</style>

+ 319 - 0
src/views/videoapply/comp/videowall.vue

@@ -0,0 +1,319 @@
+<template>
+    <el-row>
+      <el-col :span="4">
+        <div class="box">
+          <el-scrollbar>
+            <basic-container>
+              <el-input
+                placeholder="输入关键字进行过滤"
+                v-model="filterText">
+              </el-input>
+              <el-tree ref="tree" class="filter-tree" :props="treeProps" :data="treeData" @node-click="handleNodeClick"
+                       lazy :load="treeLoad":filter-node-method="filterNode">
+                <span class="custom-tree-node" slot-scope="{ node, data }">
+                  <span>{{ node.label }}</span>
+                  <span v-if="node.isLeaf">
+                    <el-button
+                      type="text"
+                      size="mini"
+                      @click="() => clickPlay(data)">
+                      播放
+                    </el-button>
+                    <el-button
+                      style="color:red"
+                      type="text"
+                      size="mini"
+                      @click="() => clickStop(node, data)">
+                      停止
+                    </el-button>
+                  </span>
+                </span>
+              </el-tree>
+            </basic-container>
+          </el-scrollbar>
+        </div>
+      </el-col>
+      <el-col :span="20">
+        <basic-container>
+          <div style="margin-bottom: 20px">
+            <el-radio-group v-model="screen" size="mini" @change="screenChange">
+              <el-radio-button :label="4">四屏</el-radio-button>
+              <el-radio-button :label="6">六分屏</el-radio-button>
+              <el-radio-button :label="9">九分屏</el-radio-button>
+              <el-radio-button :label="16">十六分屏</el-radio-button>
+            </el-radio-group>
+          </div>
+          <el-row :gutter="4">
+            <el-col :span="screenSpan" v-for="(item,index) in screenData" :key="index">
+              <player class="itemClass" :jessibucaId="'jessibucaId' + index" :container="'container' + index" :buttonsBoxId="'buttonsBoxId' + index" :ref="'videoPlayer' + index" :hasaudio="hasaudio" fluent autoplay live ></player>
+            </el-col>
+          </el-row>
+        </basic-container>
+      </el-col>
+    </el-row>
+</template>
+
+<script>
+    import {getGbChannelLazyTree, startPlay, stopPlay} from "@/api/device/gb/gbdevicechannel";
+    import player from './jessibuca.vue'
+    export default {
+      name: "videowall",
+      components: {player},
+      data () {
+        return {
+          screenSpan: 12,
+          screen: 4,
+          screenData:[],
+          playerRef: "4videoPlayer",
+          filterText: '',
+          treeData : [],
+          treeProps:{
+            labelText: '标题',
+            label: 'label',
+            parentLabel: 'parentLabelName',
+            children: 'children',
+            isLeaf: "leaf"
+          },
+          form:{},
+          data4:[],
+          data6:[],
+          data9:[],
+          data16:[],
+          loading:true,
+          data:[],
+        }
+      },
+      watch: {
+        filterText(val) {
+          this.$refs.tree.filter(val);
+        }
+      },
+      created(){
+        this.initData();
+      },
+      computed: {
+        classItem: function () {
+          if(this.screen == 4){
+            return {
+              item4 : true
+            }
+          }else if(this.screen == 6){
+            return {
+              item6 : true
+            }
+          }else if(this.screen == 9){
+            return {
+              item9 : true
+            }
+          }else if(this.screen == 16){
+            return {
+              item16 : true
+            }
+          }
+        }
+      },
+      methods:{
+        initData(){
+          for(let i = 0; i < 16; i++){
+            let item = {name:"", isPlay:false, index:i, channelId:null, display:true};
+            if(i <= 3){
+              this.data4.push(item);
+              this.data6.push(item);
+              this.data9.push(item);
+              this.data16.push(item);
+            }else if(i > 3 && i <= 5){
+              this.data6.push(item);
+              this.data9.push(item);
+              this.data16.push(item);
+            }else if(i > 5 && i <= 8){
+              this.data9.push(item);
+              this.data16.push(item);
+            }else if(i > 8 && i <= 15){
+              this.data16.push(item);
+            }
+          }
+          this.screenData = this.data4;
+          this.$nextTick(() =>{
+            for(let i = 0; i < this.screenData.length; i++){
+              let containerDom = document.getElementById("container" + i);
+              containerDom.style.height = (9/16) * containerDom.clientWidth + "px";
+              console.log(containerDom.style.height)
+            }
+          });
+        },
+        screenChange(value){
+          if(value === 4){
+            this.screenSpan = 12;
+            this.screenData = this.data4;
+          }else if(value === 6){
+            this.screenSpan = 8;
+            this.screenData = this.data6;
+          }else if(value === 9){
+            this.screenSpan = 8;
+            this.screenData = this.data9;
+          }else if(value === 16){
+            this.screenSpan = 6;
+            this.screenData = this.data16;
+          }
+          this.$nextTick(() =>{
+            for(let i = 0; i < this.screenData.length; i++){
+              let containerDom = document.getElementById("container" + i);
+              containerDom.style.height = (9/16) * containerDom.clientWidth + "px";
+              if(this.screenData[i].isPlay){
+                this.$refs['videoPlayer' + i][0].resize();
+              }
+            }
+          });
+        },
+        treeLoad(node, resolve){
+          const parentId = (node.level === 0) ? null : node.data.id;
+          let parentColumn = null;
+          const tenantId = localStorage.getItem("tenantId");
+          if(tenantId === "000000"){
+            if(node.level === 0){
+              parentColumn = "0";
+            }else if(node.level === 1){
+              parentColumn = "agency";
+            }else if(node.level === 2){
+              parentColumn = "residential";
+            }else if(node.level === 3){
+              parentColumn = "building";
+            }else if(node.level === 4){
+              parentColumn = "floor";
+            }else{
+              parentColumn = null;
+            }
+          }else{
+            if(node.level === 0){
+              parentColumn = "0";
+            }else if(node.level === 1){
+              parentColumn = "residential";
+            }else if(node.level === 2){
+              parentColumn = "building";
+            }else if(node.level === 3){
+              parentColumn = "floor";
+            }else{
+              parentColumn = null;
+            }
+          }
+          getGbChannelLazyTree(parentColumn, parentId).then(res => {
+            resolve(res.data.data.map(item => {
+              return {
+                ...item,
+                leaf: !item.hasChildren
+              }
+            }))
+          });
+        },
+        filterNode(value, data) {
+          if (!value) return true;
+          return data.label.indexOf(value) !== -1;
+        },
+        handleNodeClick(node, resolve){},
+        clickPlay(data){
+          this.$message.success("开始调取视频");
+          //找到第一个没有播放的屏幕
+          let emptyIndex = this.screenData.findIndex((item) => item.isPlay == false);
+          if(emptyIndex >= 0){ //表示找到
+            this.playVideo(data, emptyIndex).then(res => {
+              this.screenData[emptyIndex].isPlay = true;
+              this.screenData[emptyIndex].channelId = data.channelId;
+            });
+            return false;
+          }else{
+            this.playVideo(data, 0).then(res => {
+              this.screenData[0].isPlay = true;
+              this.screenData[0].channelId = data.channelId;
+            });
+          }
+        },
+        playVideo(treeItem, index){
+          let deviceId = treeItem.deviceId;
+          let channelId = treeItem.channelId;
+          startPlay(deviceId, channelId).then(res => {
+            if (res.data.data) {
+              let streamInfo = res.data.data;
+              this.$refs['videoPlayer' + index][0].play(streamInfo.ws_flv);
+            }
+          });
+        },
+        clickStop(node, treeItem){
+          this.$message.warning("正在停止");
+          let deviceId = treeItem.deviceId;
+          let channelId = treeItem.channelId;
+          let channelVideoIndex = this.screenData.findIndex((item,index) => {return item.channelId == treeItem.channelId});
+          stopPlay(deviceId, channelId).then(res => {
+            this.$message.success("停止成功");
+            this.$refs['videoPlayer' + channelVideoIndex][0].destroy();
+            this.screenData[channelVideoIndex].isPlay = false;
+            this.screenData[channelVideoIndex].channelId = null;
+          });
+        }
+      },
+    }
+</script>
+
+<style lang="less">
+  .box {
+    height: 800px;
+  }
+
+  .el-scrollbar {
+    height: 100%;
+  }
+
+  .box .el-scrollbar__wrap {
+    overflow: scroll;
+  }
+  #videoSurveillance {
+    width: 100%;
+    height: 100%;
+    display: flex;
+    flex-wrap: wrap;
+    box-sizing: border-box;
+
+    .item4 {
+      width: calc(~"49%");
+      overflow: hidden;
+      border-radius: 5px;
+      margin: 5px;
+      position: sticky;
+    }
+
+    .item6 {
+      width: calc(~"32%");
+      overflow: hidden;
+      border-radius: 5px;
+      margin: 5px;
+      position: sticky;
+    }
+
+    .item9 {
+      width: calc(~"32%");
+      overflow: hidden;
+      border-radius: 5px;
+      margin: 5px;
+      position: sticky;
+    }
+
+    .item16 {
+      width: calc(~"24%");
+      overflow: hidden;
+      border-radius: 5px;
+      margin: 5px;
+      position: sticky;
+    }
+  }
+  .itemClass {
+    position: sticky;
+  }
+  //}
+  .custom-tree-node {
+    flex: 1;
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    font-size: 14px;
+    padding-right: 8px;
+  }
+</style>

+ 333 - 0
src/views/videoapply/comp/videowallbak2.vue

@@ -0,0 +1,333 @@
+<template>
+    <el-row>
+      <el-col :span="4">
+        <div class="box">
+          <el-scrollbar>
+            <basic-container>
+              <el-input
+                placeholder="输入关键字进行过滤"
+                v-model="filterText">
+              </el-input>
+              <el-tree ref="tree" class="filter-tree" :props="treeProps" :data="treeData" @node-click="handleNodeClick"
+                       lazy :load="treeLoad":filter-node-method="filterNode">
+                <span class="custom-tree-node" slot-scope="{ node, data }">
+                  <span>{{ node.label }}</span>
+                  <span v-if="node.isLeaf">
+                    <el-button
+                      type="text"
+                      size="mini"
+                      @click="() => clickPlay(data)">
+                      播放
+                    </el-button>
+                    <el-button
+                      style="color:red"
+                      type="text"
+                      size="mini"
+                      @click="() => clickStop(node, data)">
+                      停止
+                    </el-button>
+                  </span>
+                </span>
+              </el-tree>
+            </basic-container>
+          </el-scrollbar>
+        </div>
+      </el-col>
+      <el-col :span="20">
+        <basic-container>
+          <div style="margin-bottom: 20px">
+            <el-radio-group v-model="screen" size="mini" @change="screenChange">
+              <el-radio-button :label="4">四屏</el-radio-button>
+              <el-radio-button :label="6">六分屏</el-radio-button>
+              <el-radio-button :label="9">九分屏</el-radio-button>
+              <el-radio-button :label="16">十六分屏</el-radio-button>
+            </el-radio-group>
+          </div>
+            <el-row :gutter="4">
+              <div class="item4" v-for="(item,index) in data4" :key="index" v-if="screen == 4">
+                <div align="center">{{item.name}}</div>
+                <video :id="'videoId' + index" controls="true" width="100%" height="100%">
+                </video>
+              </div>
+              <el-col :span="screenSpan" v-for="(item,index) in screenData" :key="screen + index" v-if="item.display">
+                <player style="position:sticky;overflow: hidden;" :jessibucaId="'jessibucaId' + index" :container="'container' + index" :buttonsBoxId="'buttonsBoxId' + index" :ref="'videoPlayer' + index" :hasaudio="hasaudio" fluent autoplay live ></player>
+              </el-col>
+            </el-row>
+          </div>
+        </basic-container>
+      </el-col>
+    </el-row>
+</template>
+
+<script>
+    import {getGbChannelLazyTree, startPlay, stopPlay} from "@/api/device/gb/gbdevicechannel";
+    import player from './jessibuca.vue'
+    export default {
+      name: "videowall",
+      components: {player},
+      data () {
+        return {
+          // itemClass: {
+          //   width: '500px',
+          //   overflow: 'hidden',
+          //   borderRadius: '5px',
+          //   margin: '5px',
+          //   position: 'sticky'
+          // },
+          screenSpan: 4,
+          screen: 4,
+          screenData:[],
+          playerRef: "4videoPlayer",
+          filterText: '',
+          treeData : [],
+          treeProps:{
+            labelText: '标题',
+            label: 'label',
+            parentLabel: 'parentLabelName',
+            children: 'children',
+            isLeaf: "leaf"
+          },
+          form:{},
+          data4:[],
+          data6:[],
+          data9:[],
+          data16:[],
+          loading:true,
+          data:[],
+        }
+      },
+      watch: {
+        filterText(val) {
+          this.$refs.tree.filter(val);
+        }
+      },
+      created(){
+        this.initData();
+      },
+      methods:{
+        initData(){
+          for(let i = 0; i < 16; i++){
+            let item = null;
+            if(i <= 3){
+              item = {name:"", isPlay:false, index:i, channelId:null, display:true};
+            }else{
+              item = {name:"", isPlay:false, index:i, channelId:null, display:false};
+            }
+            this.screenData.push(item);
+
+            // if(i <= 3){
+            //   this.data4.push(item);
+            //   this.data6.push(item);
+            //   this.data9.push(item);
+            //   this.data16.push(item);
+            // }else if(i > 3 && i <= 5){
+            //   this.data6.push(item);
+            //   this.data9.push(item);
+            //   this.data16.push(item);
+            // }else if(i > 5 && i <= 8){
+            //   this.data9.push(item);
+            //   this.data16.push(item);
+            // }else if(i > 8 && i <= 15){
+            //   this.data16.push(item);
+            // }
+          }
+        },
+        screenChange(value){
+          if(value === 4){
+            this.screenSpan = 12;
+            for(let i=0; i<16; i++){
+              if(i < 4){
+                this.screenData[i].display = true;
+              }else{
+                this.screenData[i].display = false;
+              }
+            }
+          }else if(value === 6){
+            this.screenSpan = 8;
+            for(let i=4; i<16; i++){
+              if(i < 6){
+                this.screenData[i].display = true;
+              }else{
+                this.screenData[i].display = false;
+              }
+            }
+          }else if(value === 9){
+            this.screenSpan = 8;
+            for(let i=6; i<9; i++){
+              if(i < 9){
+                this.screenData[i].display = true;
+              }else{
+                this.screenData[i].display = false;
+              }
+              this.screenData[i].display = true;
+            }
+          }else if(value === 16){
+            this.screenSpan = 6;
+            for(let i=4; i<16; i++){
+              this.screenData[i].display = true;
+            }
+          }
+        },
+        treeLoad(node, resolve){
+          const parentId = (node.level === 0) ? null : node.data.id;
+          let parentColumn = null;
+          const tenantId = localStorage.getItem("tenantId");
+          if(tenantId === "000000"){
+            if(node.level === 0){
+              parentColumn = "0";
+            }else if(node.level === 1){
+              parentColumn = "agency";
+            }else if(node.level === 2){
+              parentColumn = "residential";
+            }else if(node.level === 3){
+              parentColumn = "building";
+            }else if(node.level === 4){
+              parentColumn = "floor";
+            }else{
+              parentColumn = null;
+            }
+          }else{
+            if(node.level === 0){
+              parentColumn = "0";
+            }else if(node.level === 1){
+              parentColumn = "residential";
+            }else if(node.level === 2){
+              parentColumn = "building";
+            }else if(node.level === 3){
+              parentColumn = "floor";
+            }else{
+              parentColumn = null;
+            }
+          }
+          getGbChannelLazyTree(parentColumn, parentId).then(res => {
+            resolve(res.data.data.map(item => {
+              return {
+                ...item,
+                leaf: !item.hasChildren
+              }
+            }))
+          });
+        },
+        filterNode(value, data) {
+          if (!value) return true;
+          return data.label.indexOf(value) !== -1;
+        },
+        handleNodeClick(node, resolve){},
+        clickPlay(data){
+          this.$message.success("开始调取视频");
+          //找到第一个没有播放的屏幕
+          let emptyIndex = this.screenData.findIndex((item) => item.isPlay == false);
+          if(emptyIndex >= 0){ //表示找到
+            this.playVideo(data, emptyIndex);
+            this.screenData[emptyIndex].isPlay = true;
+            this.screenData[emptyIndex].channelId = data.channelId;
+            return false;
+          }else{
+            this.playVideo(data, 0);
+            this.screenData[0].isPlay = true;
+            this.screenData[0].channelId = data.channelId;
+          }
+        },
+        playVideo(treeItem, index){
+          let deviceId = treeItem.deviceId;
+          let channelId = treeItem.channelId;
+          console.log(this.$refs[this.playerRef + index]);
+          startPlay(deviceId, channelId).then(res => {
+            if (res.data.data) {
+              let streamInfo = res.data.data;
+              this.$refs[this.playerRef + index][0].play(streamInfo.ws_flv);
+              // try {
+              //   let videoElement = document.getElementById("videoId" + index);
+              //   let flvPlayer = flvjs.createPlayer({
+              //     type: 'flv',
+              //     url: streamInfo.ws_flv
+              //   });
+              //   flvPlayer.on(flvjs.Events.ERROR, (errType, errDetail) => {});
+              //   flvPlayer.on(flvjs.Events.MEDIA_SOURCE_CLOSE || flvjs.Events.MEDIA_SOURCE_ENDED, () => {});
+              //   flvPlayer.attachMediaElement(videoElement);
+              //   flvPlayer.load();
+              //   flvPlayer.play();
+              //   treeItem.isPlay = true;
+              // } catch (e) {
+              //   console.log(e);
+              // }
+            }
+          });
+        },
+        clickStop(node, treeItem){
+          this.$message.warning("正在停止");
+          let screenData = null;
+          let deviceId = treeItem.deviceId;
+          let channelId = treeItem.channelId;
+          let channelVideoIndex = this.screenData.findIndex((item,index) => {return item.channelId == treeItem.channelId});
+          this.$refs[this.playerRef + channelVideoIndex][0].pause();
+          // stopPlay(deviceId, channelId).then(res => {
+          //   this.$message.success("停止成功");
+          //   this.screenData[channelVideoIndex].isPlay = false;
+          //   this.screenData[channelVideoIndex].channelId = null;
+          // });
+        }
+      },
+    }
+</script>
+
+<style lang="less">
+  .box {
+    height: 800px;
+  }
+
+  .el-scrollbar {
+    height: 100%;
+  }
+
+  .box .el-scrollbar__wrap {
+    overflow: scroll;
+  }
+  #videoSurveillance {
+    width: 100%;
+    height: 100%;
+    display: flex;
+    flex-wrap: wrap;
+    box-sizing: border-box;
+
+    .item4 {
+      width: calc(~"49%");
+      overflow: hidden;
+      border-radius: 5px;
+      margin: 5px;
+      position: sticky;
+    }
+
+    .item6 {
+      width: calc(~"32%");
+      overflow: hidden;
+      border-radius: 5px;
+      margin: 5px;
+      position: sticky;
+    }
+
+    .item9 {
+      width: calc(~"32%");
+      overflow: hidden;
+      border-radius: 5px;
+      margin: 5px;
+      position: sticky;
+    }
+
+    .item16 {
+      width: calc(~"24%");
+      overflow: hidden;
+      border-radius: 5px;
+      margin: 5px;
+      position: sticky;
+    }
+  }
+  .custom-tree-node {
+    flex: 1;
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    font-size: 14px;
+    padding-right: 8px;
+  }
+</style>

+ 17 - 338
src/views/videoapply/videofusion.vue

@@ -1,356 +1,35 @@
 <template>
   <basic-container>
-    <avue-crud v-if="!showDeviceChannelCrud"
-               :option="deviceOption"
-               :table-loading="loading"
-               :data="data"
-               :page.sync="page"
-               :permission="permissionList"
-               :before-open="beforeOpen"
-               v-model="form"
-               ref="crud"
-               @row-update="rowUpdate"
-               @row-save="rowSave"
-               @row-del="rowDel"
-               @search-change="searchChange"
-               @search-reset="searchReset"
-               @selection-change="selectionChange"
-               @current-change="currentChange"
-               @size-change="sizeChange"
-               @refresh-change="refreshChange"
-               @on-load="onLoad">
-      <template slot="menuLeft">
-        <el-button type="danger"
-                   size="small"
-                   icon="el-icon-delete"
-                   plain
-                   v-if="permission.gbdevice_delete"
-                   @click="handleDelete">删 除
-        </el-button>
-      </template>
-      <template slot="online" slot-scope="{row}">
-        <el-tag v-if="row.online === 1" type="success">在线</el-tag>
-        <el-tag v-if="row.online === 0" type="info">离线</el-tag>
-      </template>
-      <template slot="hostAddress" slot-scope="{row}">
-        <el-tag type="primary">{{row.hostAddress}}</el-tag>
-      </template>
-      <template slot="menu" slot-scope="{row}">
-        <el-button type="text" size="mini" icon="el-icon-setting">
-          <el-dropdown>
-            <span class="el-dropdown-link">
-              操作<i class="el-icon-arrow-down el-icon--right"></i>
-            </span>
-            <el-dropdown-menu slot="dropdown">
-              <el-dropdown-item style="color: orange" v-if="permission.gbdevice_bind" @click.native="bindDevice(row)" icon="el-icon-paperclip">绑定</el-dropdown-item>
-              <el-dropdown-item style="color: limegreen" @click.native="handleSync(row, row.$index)" icon="el-icon-refresh">刷新</el-dropdown-item>
-              <el-dropdown-item style="color: #0087ff" @click.native="handleChannel(row.deviceId)" icon="el-icon-video-camera-solid">通道</el-dropdown-item>
-            </el-dropdown-menu>
-          </el-dropdown>
-        </el-button>
-      </template>
-    </avue-crud>
-    <avue-crud v-if="showDeviceChannelCrud" :option="deviceChannelOption" :table-loading="loading" :data="data" :page="page" :permission="permissionList"
-                 :before-open="beforeOpen" v-model="form" ref="crud" @row-update="rowUpdate" @row-save="rowSave" @row-del="rowDel"
-                 @search-change="channelSearchChange" @search-reset="searchReset" @selection-change="selectionChange" @current-change="currentChange"
-                 @size-change="sizeChange" @refresh-change="refreshChannelChange" @on-load="onLoadChannel">
-        <template slot-scope="{row}" slot="channelTypeSearch">
-          <el-select size="mini" style="margin-right: 1rem;" v-model="row.channelType" placeholder="请选择" default-first-option>
-            <el-option label="全部" value=""></el-option>
-            <el-option label="设备" value="false"></el-option>
-            <el-option label="子目录" value="true"></el-option>
-          </el-select>
-        </template>
-        <template slot-scope="{row}" slot="online">
-          <el-select size="mini" style="margin-right: 1rem;" v-model="row.online" placeholder="请选择" default-first-option>
-            <el-option label="全部" value=""></el-option>
-            <el-option label="在线" value="true"></el-option>
-            <el-option label="离线" value="false"></el-option>
-          </el-select>
-        </template>
-        <template slot="menuLeft">
-          <el-button type="primary" size="mini" icon="el-icon-arrow-left" @click="backToDeviceList">返 回</el-button>
-        </template>
-        <template slot="hasAudio" slot-scope="{row}">
-          <el-switch @change="updateChannel(scope.row)" v-model="row.hasAudio" active-color="#409EFF">
-          </el-switch>
-        </template>
-        <template slot="status" slot-scope="{row}">
-          <el-tag size="medium" v-if="row.status == 1">开启</el-tag>
-          <el-tag size="medium" v-else="row.status == 0">关闭</el-tag>
-        </template>
-        <template slot="menu" slot-scope="{row}">
-          <el-button size="mini" icon="el-icon-video-play" v-if="permission.gbdevicechannel_play" @click="devicePlay(row)">播放</el-button>
-          <el-button size="mini" icon="el-icon-switch-button" type="danger" :loading="stopBtnLoading" v-if="permission.gbdevicechannel_stop && !!row.streamId" @click="deviceStopPlay(row)">停止</el-button>
-<!--          <el-button size="mini" type="primary" icon="el-icon-video-camera" v-if="permission.wvpvideodevice_record" @click="deviceRecord(row)">设备录像</el-button>-->
-        </template>
-      </avue-crud>
-    <devicePlayer ref="devicePlayer"></devicePlayer>
-    <el-dialog :modal-append-tobody="false" append-to-body :visible.sync="bindVisible" title="设备绑定" width="60%">
-      <select-dialog-residential :id="form.residentialId" :name="form.residentialName" :callback="selectCallback" v-if="bindVisible"></select-dialog-residential>
-    </el-dialog>
+    <el-tabs type="card" v-model="activeName" @change="tabChange">
+      <el-tab-pane label="实时监控" name="videoWall">
+        <videowall></videowall>
+      </el-tab-pane>
+      <el-tab-pane label="视频管理" name="videoManage">
+        <videomanage></videomanage>
+      </el-tab-pane>
+    </el-tabs>
   </basic-container>
 </template>
 
 <script>
-  import {getList, getDetail, add, update, remove, bind, sync} from "@/api/device/gb/gbdevice";
-  import {getList as getChannelList, startPlay, stopPlay} from "@/api/device/gb/gbdevicechannel";
-  import {mapGetters} from "vuex";
-  import SelectDialogResidential from "../../components/select-dialog/select-dialog-residential";
   import devicePlayer from "./comp/devicePlayer";
+  import videowall from "./comp/videowall";
+  import videomanage from "./comp/videomanage";
 
   export default {
-    components: {devicePlayer, SelectDialogResidential},
+    components: {devicePlayer, videowall, videomanage},
     data() {
       return {
-        form: {},
-        query: {},
-        loading: true,
-        page: {
-          pageSize: 10,
-          currentPage: 1,
-          total: 0
-        },
-        bindVisible: false,
-        showDeviceChannelCrud: false,
-        deviceId: null,
-        stopBtnLoading: false,
-        selectionList: [],
-        deviceOption: {
-          height:'auto',
-          calcHeight: 30,
-          tip: false,
-          searchShow: true,
-          searchMenuSpan: 6,
-          border: true,
-          index: true,
-          viewBtn: true,
-          selection: true,
-          dialogClickModal: false,
-          column: [
-            {
-              label: "设备编号",
-              prop: "deviceId",
-            },
-            {
-              label: "设备名称",
-              prop: "name",
-            },
-            {
-              label: "厂商名称",
-              prop: "manufacturer",
-            },
-            {
-              label: "型号",
-              prop: "model",
-              hide:true,
-              disabled: true
-            },
-            {
-              label: "传输协议",
-              prop: "transport",
-              hide:true,
-              disabled: true
-            },
-            {
-              label: "流传输模式",
-              prop: "streamMode",
-              hide:true,
-              disabled: true,
-              type: "select",
-              dicData:[
-                {
-                  label: "udp传输",
-                  value: "UDP"
-                },
-                {
-                  label: "tcp主动模式",
-                  value: "TCP-ACTIVE"
-                },
-                {
-                  label: "tcp被动模式",
-                  value: "TCP-PASSIVE"
-                },
-              ]
-            },
-            {
-              label: "在线状态",
-              prop: "online",
-              slot:true,
-              search: true,
-              type: "select",
-              width: 100,
-              align: "center",
-              dicData:[
-                {
-                  label: "在线",
-                  value: 1
-                },
-                {
-                  label: "离线",
-                  value: 0
-                }
-              ]
-            },
-            {
-              label: "注册时间",
-              prop: "registerTime",
-            },
-            {
-              label: "心跳时间",
-              prop: "keepaliveTime",
-            },
-            {
-              label: "wan地址",
-              prop: "hostAddress",
-              slot: true
-            },
-            {
-              label: "所属园区",
-              prop: "agencyName",
-            },
-            {
-              label: "所属区域",
-              prop: "residentialName",
-            },
-            {
-              label: "所属园区",
-              prop: "agencyId",
-              hide: true,
-              search: true,
-              filterable: true,
-              cascaderItem: ['residentialId'],
-              type: "select",
-              remote: true,
-              dicUrl: "/api/cyzh-community/agency/list?size=10&name={{key}}",
-              dicFormatter:(res)=>{
-                return res.data.records;//返回字典的层级结构
-              },
-              props: {
-                label: "name",
-                value: "id"
-              },
-            },
-            {
-              label: "所属区域",
-              prop: "residentialId",
-              hide: true,
-              slot: true,
-              type: "select",
-              search: true,
-              dicUrl: "/api/cyzh-community/residential/list?agencyId={{key}}",
-              dicFormatter:(res)=>{
-                return res.data.records;//返回字典的层级结构
-              },
-              filterable: true,
-              props: {
-                label: "name",
-                value: "id"
-              },
-            },
-          ]
-        },
-        deviceChannelOption: {
-          menu: true,
-          menuWidth: 300,
-          height: 'auto',
-          calcHeight: 30,
-          tip: false,
-          searchShow: true,
-          searchMenuSpan: 6,
-          labelWidth: 150,
-          border: true,
-          index: true,
-          viewBtn: false,
-          editBtn: false,
-          delBtn: false,
-          selection: true,
-          dialogClickModal: false,
-          addBtn:false,
-          column: [
-            {
-              label: "通道编号",
-              prop: "channelId",
-              span: 12,
-            },
-            {
-              label: "设备编号",
-              prop: "deviceId",
-              span: 12,
-            },
-            {
-              label: "通道名称",
-              prop: "name",
-              span: 12,
-              width: 100,
-              search: true
-            },
-            {
-              label: "开启音频",
-              prop: "hasAudio",
-              span: 12,
-              width: 80,
-              slot: true
-            },
-            {
-              label: "状态",
-              prop: "status",
-              span: 12,
-              width:80,
-              slot: true
-            },
-            {
-              label: "云台类型",
-              prop: "ptzType",
-              span: 12,
-              type: "select",
-              dicData:[
-                {
-                  label: "未知",
-                  value: 0
-                },
-                {
-                  label: "球机",
-                  value: 1
-                },
-                {
-                  label: "半球",
-                  value: 2
-                },
-                {
-                  label: "固定枪机",
-                  value: 3
-                },
-                {
-                  label: "遥控枪机",
-                  value: 4
-                }
-              ]
-            },
-          ]
-        },
-        data: []
+        activeName: "videoWall",
       };
     },
-    computed: {
-      ...mapGetters(["permission"]),
-      permissionList() {
-        return {
-          addBtn: this.vaildData(this.permission.gbdevice_add, false),
-          viewBtn: this.vaildData(this.permission.gbdevice_view, false),
-          delBtn: this.vaildData(this.permission.gbdevice_delete, false),
-          editBtn: this.vaildData(this.permission.gbdevice_edit, false)
-        };
-      },
-      ids() {
-        let ids = [];
-        this.selectionList.forEach(ele => {
-          ids.push(ele.id);
-        });
-        return ids.join(",");
-      }
+    created(){
+      this.tab = this.tabsOption.column[0];
     },
     methods: {
+      tabChange(column) {
+        this.tab = column;
+      },
       devicePlay(row){
         let deviceId = row.deviceId;
         let channelId = row.channelId;