heyujie
2021-08-20 3b9477e4179ac9fca90a1abeb2cf544155d832bc
长春跟踪app
32个文件已修改
7个文件已添加
3380 ■■■■■ 已修改文件
public/apps.json 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/app.ts 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/camera.ts 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/system.ts 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/trackCamera.ts 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/giantTree/zTree/ztree.vue 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/player/index.vue 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/player/wfs/controller/buffer-controller.js 50 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/player/wfs/loader/websocket-loader.js 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/ai/index/App.vue 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/cameraAccess/components/CameraInfo.vue 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/cameraAccess/components/SceneRule.vue 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/cameraPlayer/components/player/wfs/controller/buffer-controller.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/cameraPlayer/components/player/wfs/loader/websocket-loader.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/cameraVideo/index/Video.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/changchunTrack/components/LeftNav.vue 904 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/changchunTrack/components/VideoItem.vue 342 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/changchunTrack/index/App.vue 124 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/changchunTrack/index/Video.vue 803 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/changchunTrack/index/main.ts 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/changchunTrack/index/mixins.ts 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/desktop/index/App.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/desktop/index/components/DFrame.vue 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/desktop/index/components/Desktop.vue 292 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/desktop/index/components/Tools.vue 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/desktop/index/components/ToolsEntry.vue 169 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/gb28181/index/api.ts 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/index/App.vue 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/panoramicView/index/App.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/panoramicView/index/main.ts 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/panoramicView/index/mixins.ts 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/settings/views/generalSettings.vue 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/syslog/views/eventPushLog.vue 92 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/syslog/views/operationLog.vue 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/vindicate/index/App.vue 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/vindicate/views/sysInfo.vue 341 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/vindicate/views/updateSettings.vue 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/visual/components/player/wfs/controller/buffer-controller.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/visual/components/player/wfs/loader/websocket-loader.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
public/apps.json
@@ -25,6 +25,29 @@
      "progressMsg": ""
    },
    {
      "id": "a9c4a1ad-0137-4137-acf3-fc293d6c295e",
      "name": "长春",
      "package": "changchunTrack",
      "type": "2",
      "url": "/view/changchunTrack/",
      "title": "长春",
      "width": 1328,
      "height": 690,
      "iconBlob": "",
      "icon": "../../images/app-mid/monitor.png",
      "version": "1.0.0",
      "create_time": "2020-10-09 14:00:01",
      "create_by": "",
      "update_time": "",
      "update_by": "",
      "isDelete": 0,
      "isDefault": true,
      "remoteVersion": "",
      "installed": true,
      "isUpgrade": false,
      "progressMsg": ""
    },
    {
      "id": "7dea48a4-8294-4914-85d8-c2bbd4caf553",
      "name": "应用中心",
      "package": "algorithmManage",
src/api/app.ts
@@ -25,10 +25,10 @@
}
//获取商城所有应用(已激活)
export const findAllApp = () => request({
  url: '/data/api-v/app/findAllApp',
  method: 'get'
});
// export const findAllApp = () => request({
//   url: '/data/api-v/app/findAllApp',
//   method: 'get'
// });
export const getAppDetail = (query:any) => request({
  url: '/data/api-v/app/detail',
src/api/camera.ts
@@ -1,13 +1,6 @@
import request from "@/scripts/httpRequest";
import qs from "qs";
export const checkCameraConnet = (query: any) => {
  return request({
    url: "/data/api-v/area/localmenu",
    method: "get",
    params: query
  });
};
export const createCamera = (camera: any) => {
  return request({
src/api/system.ts
@@ -362,3 +362,42 @@
  })
}
export const getActiveQrCode = (query: any) => {
  return request({
    url: "/version/offline/qrcode",
    method: "get",
    params: query
  })
}
export const getSN = (query: any) => {
  return request({
    url: "/version/sn",
    method: "get",
    params: query
  })
}
export const cancelAuthorization = (query: any) => {
  return request({
    url: "/version/cancelAuthorization",
    method: "post",
    data: qs.stringify(query),
    responseType: "blob"
  })
}
export const activateVersion = (query: any) => {
  return request({
    url: "/version/authorization",
    method: "post",
    data: qs.stringify(query)
  })
}
export const uploadKey = (data: any) => {
  return request({
    url: "/version/authorization/upload",
    method: "post",
    data
  })
}
src/api/trackCamera.ts
@@ -5,4 +5,12 @@
    url: "/playState",
    method: "get"
  });
};
};
export const showAllCameras = () => {
  return request({
    url: "/data/api-v/cameraCompose/showAll",
    method: "get"
  });
};
src/components/giantTree/zTree/ztree.vue
@@ -192,7 +192,6 @@
        item.appendChild(btn);
      }
      // 添加摄像机按钮
      if (item && !item.querySelector('.iconshishishipin') && treeNode.isParent && !this.readonly && !this.gb28181) {
        const btn = document.createElement('i');
src/components/player/index.vue
@@ -80,6 +80,7 @@
  },
  watch: {
    rtspUrl: function (newVal, oldVal) {
      console.log("new rstp:::", newVal);
      if (newVal !== oldVal) {
        if (this.wfs.config) {
          this.wfs.destroy();
src/components/player/wfs/controller/buffer-controller.js
@@ -74,7 +74,7 @@
  }
  onMediaSourceClose() {
    console.log('media source closed');
    // console.log('media source closed');
  }
  onMediaSourceEnded() {
@@ -152,9 +152,9 @@
    if (Object.keys(sourceBuffer).length) {
      if (this.media.error) {
        this.segments = [];
        console.log(
          'trying to append although a media error occured, flush segment and abort'
        );
        // console.log(
        //   'trying to append although a media error occured, flush segment and abort'
        // );
        return;
      }
      if (this.appending) {
@@ -175,27 +175,27 @@
        } catch (err) {
          // in case any error occured while appending, put back segment in segments table
          segments.unshift(segment);
          var event = { type: ErrorTypes.MEDIA_ERROR };
          if (err.code !== 22) {
            if (this.appendError) {
              this.appendError++;
            } else {
              this.appendError = 1;
            }
            event.details = ErrorDetails.BUFFER_APPEND_ERROR;
            event.frag = this.fragCurrent;
            if (this.appendError > wfs.config.appendErrorMaxRetry) {
              segments = [];
              event.fatal = true;
              return;
            } else {
              event.fatal = false;
            }
          } else {
            this.segments = [];
            event.details = ErrorDetails.BUFFER_FULL_ERROR;
            return;
          }
          // var event = { type: ErrorTypes.MEDIA_ERROR };
          // if (err.code !== 22) {
          //   if (this.appendError) {
          //     this.appendError++;
          //   } else {
          //     this.appendError = 1;
          //   }
          //   event.details = ErrorDetails.BUFFER_APPEND_ERROR;
          //   event.frag = this.fragCurrent;
          //   if (this.appendError > wfs.config.appendErrorMaxRetry) {
          //     segments = [];
          //     event.fatal = true;
          //     return;
          //   } else {
          //     event.fatal = false;
          //   }
          // } else {
          //   this.segments = [];
          //   event.details = ErrorDetails.BUFFER_FULL_ERROR;
          //   return;
          // }
        }
      }
    }
src/components/player/wfs/loader/websocket-loader.js
@@ -35,7 +35,7 @@
      this.client = data.websocket
      this.client.onopen = this.initSocketClient.bind(this)
      this.client.onclose = function (e) {
        console.log('Websocket Disconnected!')
        // console.log('Websocket Disconnected!')
        this.disconnected = true;
        // console.log(this)
        // this.close = true;
@@ -55,7 +55,7 @@
    })
    this.client.disconnected = false
    // console.log(this)
    console.log('Websocket Open!')
    // console.log('Websocket Open!')
  }
  receiveSocketMessage(event) {
src/pages/ai/index/App.vue
@@ -1343,7 +1343,6 @@
            });
            setTimeout(() => {
              this.getAllSdk();
              debugger
              window.parent.postMessage(
                {
                  msg: "AppUpdate",
@@ -1385,8 +1384,6 @@
                app.installLoading = false;
              }
              // _this.getAllApps();
              debugger
              window.parent.postMessage(
                {
                  msg: "AppUpdate",
@@ -1432,14 +1429,14 @@
            this.appUpgreading = true;
          }
          if (obj.upgradeDone) {
              this.$notify({
            this.$notify({
              type: "success",
              message:1 ? "算法安装成功" : "算法升级成功",
              message: 1 ? "算法安装成功" : "算法升级成功",
            });
          }
          item.installed ? iArry.push(obj) : sArry.push(obj);
          item.isUpgrade && nArry.push(obj);
        });
@@ -1460,8 +1457,6 @@
              if (res && res.success) {
                app.unloadLoading = false;
                _this.getAllApps();
              debugger
                window.parent.postMessage(
                  {
                    msg: "AppUpdate",
@@ -1685,8 +1680,6 @@
                  type: "success",
                });
                _this.getAllSdk();
              debugger
                window.parent.postMessage(
                  {
                    msg: "AppUpdate",
@@ -1789,16 +1782,12 @@
          //   type: "success",
          //   message: typ == 1 ? "算法安装成功" : "算法升级成功",
          // });
          // window.parent.postMessage(
          //     { msg: `refreshDesk?` },
          //     "*"
          //   );
          window.parent.postMessage(
                  {
                    msg: "AppUpdate",
                  },
                  "*"
                );
            {
              msg: "AppUpdate",
            },
            "*"
          );
        })
        .catch((err) => {
          this.$notify({
src/pages/cameraAccess/components/CameraInfo.vue
@@ -422,6 +422,11 @@
                  message: "摄像机添加失败!"
                });
              }
            }).catch((err) => {
              this.$notify({
                type: "error",
                message: err.msg
              });
            });
          }
        }
src/pages/cameraAccess/components/SceneRule.vue
@@ -156,7 +156,6 @@
<script>
import {
  saveCameraScene,
  getCameraSceneRule,
  deleteCameraScene
} from '@/api/scene'
import RuleEditor from "@/components/subComponents/RuleEditor";
src/pages/cameraPlayer/components/player/wfs/controller/buffer-controller.js
@@ -74,7 +74,7 @@
  }
  onMediaSourceClose() {
    console.log('media source closed');
    // console.log('media source closed');
  }
  onMediaSourceEnded() {
src/pages/cameraPlayer/components/player/wfs/loader/websocket-loader.js
@@ -35,7 +35,7 @@
      this.client = data.websocket
      this.client.onopen = this.initSocketClient.bind(this)
      this.client.onclose = function (e) {
        console.log('Websocket Disconnected!')
        // console.log('Websocket Disconnected!')
        this.disconnected = true;
        // console.log(this)
        // this.close = true;
src/pages/cameraVideo/index/Video.vue
@@ -41,7 +41,7 @@
              :class="guid === 1 ? 'video-main-box' : 'video-main-box-side'"
              v-if="visibilityState"
            >
              <video-item
              <VideoItem
                v-for="(item, index) in TreeDataPool.videoArr"
                :key="index"
                :videoGuid="guid"
@@ -53,12 +53,12 @@
                  guid === 1 ? 'onlyActiveItem' : ''
                ]"
                @click="videoItemClick(index)"
              ></video-item>
              ></VideoItem>
            </div>
          </div>
        </div>
        <div class="monitoring-task" ref="monitorTask">
          <video-task ref="taskview" @addToBase="toAdd"></video-task>
          <VideoTask ref="taskview" @addToBase="toAdd"></VideoTask>
        </div>
      </div>
      <div class="monitoring-photo">
src/pages/changchunTrack/components/LeftNav.vue
New file
@@ -0,0 +1,904 @@
<template>
  <transition name="slideLeft">
    <div
      class="left-tree-box"
      :style="`height:${height}px;animation-duration: 0.7s`"
      v-show="TreeDataPool.showTreeBox"
      v-loading="menuLoading"
    >
      <el-tabs v-model="TreeDataPool.treeActiveName" type="border-card" @tab-click="handleClick">
        <el-tab-pane label="摄像机" name="camera" :style="`height:${height - 56}px;`" v-if="showCam">
          <el-menu
            :default-openeds="openeds"
            background-color="#fff"
            text-color="#303133"
            active-text-color="#409EFF"
            style="height: 100%;"
            class="el-menu-vertical-demo"
            unique-opened
            @open="menuOpen"
            @close="menuClose"
          >
            <li class="navTopSelect">
              <el-select
                v-model="TreeDataPool.searchCamType"
                placeholder="请选择"
                @change="searchAreaData"
              >
                <el-option
                  v-for="item in searchTypeOptions"
                  :key="item.value"
                  :label="item.label"
                  :value="item.value"
                ></el-option>
              </el-select>
              <span style="display: inline-block;padding: 0px 3px;"></span>
              <el-input
                v-model="TreeDataPool.searchInput"
                placeholder="搜索"
                clearable
                @input="querySearchAsync('camera')"
              >
                <i
                  class="el-icon-search el-input__icon"
                  style="color:#DCDFE6"
                  slot="prefix"
                  @click="searchAreaData"
                ></i>
              </el-input>
              <!-- <div class="tree-close">
                <el-tooltip content="收起目录树" placement="bottom" popper-class="atooltip">
                  <i
                    class="el-icon-s-fold"
                    style="color: #3D68E1;line-height: 22px;font-size: 27px;"
                    @click="closeTree"
                  ></i>
                </el-tooltip>
              </div>-->
            </li>
            <div class="tree-edit area-add" v-show="!TreeDataPool.readonly">
              <el-tooltip content="添加区域" placement="bottom" popper-class="atooltip">
                <button @click="addNode($event)">
                  <i class="iconfont iconhebingxingzhuang"></i>
                </button>
              </el-tooltip>
            </div>
            <!-- 添加设备图标 -->
            <div class="tree-edit camera-add" v-show="!TreeDataPool.readonly">
              <el-tooltip content="添加设备" placement="bottom" popper-class="atooltip">
                <button @click="addCamera('0')">
                  <!-- <i class="el-icon-video-camera"></i> -->
                  <span class="iconfont iconshishishipin" style="font-size:14px;"></span>
                </button>
              </el-tooltip>
            </div>
            <!-- 导入设备 -->
            <div class="tree-edit import-btn" v-show="!TreeDataPool.readonly">
              <el-tooltip content="导入设备" placement="bottom" popper-class="atooltip">
                <button @click="importCameras('0')">
                  <!-- <i class="el-icon-video-camera"></i> -->
                  <span class="iconfont icondaoru" style="font-size:16px;"></span>
                </button>
              </el-tooltip>
            </div>
            <!-- 树操作锁 -->
            <div class="tree-edit tree-lock" v-show="showLock">
              <button @click="lockSwitch">
                <i v-if="TreeDataPool.readonly" class="el-icon-lock"></i>
                <i v-else class="el-icon-unlock"></i>
              </button>
            </div>
            <!-- 主菜单 -->
            <el-submenu index="0">
              <template slot="title">
                <!-- <i class="iconfont iconjiankongshexiangji"></i> -->
                <span
                  class="iconfont iconjiankongshexiangji"
                  style="padding-right:10px;font-size:13px;"
                ></span>
                <b class="tree-font">摄像机</b>
              </template>
              <el-menu-item-group class="item-group">
                <tree-menu
                  ref="tree"
                  :app="appName"
                  :treeName="'localTree'"
                  :node="TreeDataPool.treeData"
                  :height="height"
                  @addDevice="addCamera"
                  @import="importCameras"
                />
              </el-menu-item-group>
            </el-submenu>
          </el-menu>
        </el-tab-pane>
        <el-tab-pane
          label="集群"
          name="cluster"
          :style="`height:${height - 56}px;`"
          v-if="showCluster"
        >
          <div class="local-vedio-area">
            <!-- 搜索 -->
            <div class="navTopSelect">
              <div class="search-input flex-box">
                <el-select
                  v-model="TreeDataPool.searchCamType"
                  placeholder="请选择"
                  @change="searchClusterData"
                >
                  <el-option
                    v-for="item in searchTypeOptions"
                    :key="item.value"
                    :label="item.label"
                    :value="item.value"
                  ></el-option>
                </el-select>
                <span style="display: inline-block;padding: 0px 3px;"></span>
                <el-input
                  v-model="TreeDataPool.searchInput"
                  placeholder="搜索"
                  clearable
                  @input="querySearchAsync('cluster')"
                >
                  <i
                    class="el-icon-search el-input__icon"
                    style="color:#DCDFE6"
                    slot="prefix"
                    @click="searchClusterData"
                  ></i>
                </el-input>
              </div>
            </div>
            <div class="top-menu" style="margin:0 0 10px;text-align:left;">
              <span class="iconfont iconjiqun" style="font-size:20px;"></span>
              <span style="font-size:14px; margin-left: 5px;font-weight: 600;">{{clusterName}}</span>
            </div>
            <div class="cluster-list">
              <tree-menu
                ref="tree"
                :app="appName"
                :treeName="'localTree'"
                :node="TreeDataPool.clusterData"
                :height="height"
                @addDevice="addCamera"
                @import="importCameras"
              />
            </div>
          </div>
        </el-tab-pane>
        <el-tab-pane label="数据栈" name="dataStack" v-if="showDataStack">
          <div class="local-vedio-area">
            <!-- 搜索 -->
            <div class="search-input">
              <!-- <span style="display: inline-block;padding: 0px 3px;"></span> -->
              <el-select
                v-model="DataStackPool.searchType"
                placeholder="请选择"
                size="small"
                style="width: 134px;height: 34px;margin-left: 10px;"
                @change="searchDataStack"
              >
                <el-option
                  v-for="item in DataStackPool.searchOptions"
                  :key="item.value"
                  :label="item.label"
                  :value="item.value"
                ></el-option>
              </el-select>
              <span style="display: inline-block;padding: 0px 3px;"></span>
              <el-input
                v-model="DataStackPool.searchInput"
                placeholder="请输入"
                size="small"
                clearable
                @input="querySearchAsync('dir')"
                :style="'width:148px;'"
              >
                <i
                  class="el-icon-search el-input__icon"
                  style="color:black"
                  slot="prefix"
                  @click="searchDataStack"
                ></i>
              </el-input>
              <!-- 隐藏树按钮 -->
              <!-- <div class="dev-tree-close">
                <i
                  class="el-icon-s-fold"
                  style="color: #3D68E1;line-height: 22px;font-size: 27px;"
                  @click="closeTree"
                ></i>
              </div>-->
            </div>
            <!-- 本地视频源列表 -->
            <div class="dev-vedio-list">
              <!-- 添加文件夹图标 -->
              <div class="tree-edit area-add" v-show="!DataStackPool.readonly">
                <el-tooltip content="添加文件夹" placement="bottom" popper-class="atooltip">
                  <button @click="addDir($event)">
                    <i class="iconfont iconhebingxingzhuang"></i>
                  </button>
                </el-tooltip>
              </div>
              <!-- 文件夹操作锁 -->
              <div class="tree-edit tree-lock" v-show="showLock">
                <button @click="dataStackLockSwitch">
                  <i v-if="DataStackPool.readonly" class="el-icon-lock"></i>
                  <i v-else class="el-icon-unlock"></i>
                </button>
              </div>
              <LocalVedioList :dataList="TreeDataPool.localVedioList"></LocalVedioList>
            </div>
          </div>
          <file-upload v-show="fileUploadBox" @close="fileUploadBox= false" />
        </el-tab-pane>
      </el-tabs>
      <!-- 导入设备组件 事件触发 -->
      <el-upload
        class="upload-btn"
        action="https://jsonplaceholder.typicode.com/posts/"
        accept=".xlsx"
        :on-exceed="exceed"
        :limit="10"
        :on-remove="remove"
        :http-request="uploadFile"
        :show-file-list="false"
      >
        <button ref="import-btn" v-show="false"></button>
      </el-upload>
    </div>
  </transition>
</template>
<script>
import {
  show,
  changeEnable,
  deleteLocalFile,
  updateStatus
} from "@/api/localVedio";
import {
  createCamera,
} from "@/api/camera";
import bus from "@/plugin/bus"
// import TreeMenu from "@/components/treeMenu/index";
import TreeMenu from "@/components/giantTree/index";
import LocalVedioList from '@/components/subComponents/LocalVedioList';
import FileUpload from '@/components/subComponents/FileUpload/index';
import XLSX from 'xlsx'
import { findCluster } from "@/api/clusterManage";
export default {
  components: {
    TreeMenu,
    LocalVedioList,
    FileUpload
  },
  props: {
    appName: {
      type: String,
      default: "Video"
    },
    edit: {
      type: Boolean,
      default: false
    },
    height: {
      type: Number,
      default: 0
    }
  },
  computed: {
    showTab() {
      return true;
    },
    showCam() {
      return this.appName === "Camera" || this.appName === 'Cluster' || (this.appName === "Search" && (this.buttonAuthority.indexOf("search:camera") >= 0 || this.isAdmin));
    },
    showCluster() {
      return this.appName === "Cluster";
    },
    // 数据栈配置必须显示。 检索通过权限控制显示, 未安装数据栈也不显示
    showDataStack() {
      if (this.appName === "DataStack") {
        return true;
      }
      if (this.appName === "Search") {
        // 未安装数据栈配置
        if (this.installedApps.indexOf("dataStack") >= 0) {
          if (this.isAdmin) {
            return true;
          }
          if (this.buttonAuthority.indexOf("search:stack") >= 0) {
            return true;
          }
        }
      }
      return false;
    },
    showLock() {
      return this.edit;
    },
    openeds() {
      let arry = [];
      for (let i = 0; i < this.TreeDataPool.openeds.length; i++) {
        if (this.TreeDataPool.openeds[i]) {
          arry.push(i + "");
          // 默认展开一颗有数据的树
          break;
        }
      }
      return arry;
    },
    isAdmin() {
      if (
        sessionStorage.getItem("userInfo") &&
        sessionStorage.getItem("userInfo") !== ""
      ) {
        let loginName = JSON.parse(sessionStorage.getItem("userInfo")).username;
        return loginName === "superadmin" || loginName === "basic";
      }
      return false;
    }
  },
  data() {
    return {
      dataStack: "videoMonitor:dataStack",
      buttonAuthority: sessionStorage.getItem("buttonAuthoritys") || [],
      installedApps: sessionStorage.getItem("apps") || [],
      loginName: JSON.parse(sessionStorage.getItem("userInfo")).username || "用户名",
      searchTypeOptions: [
        {
          value: 0,
          label: "全部摄像机"
        },
        {
          value: 1,
          label: "分析摄像机"
        },
        {
          value: 2,
          label: "监控摄像机"
        },
        {
          value: 3,
          label: "联动摄像机"
        }
      ],
      timeout: null,
      fileUploadBox: false,
      loadingGBTree: false,
      importAreaId: "",
      menuLoading: false,
      clusterName: ''
    };
  },
  created() {
    if (this.showCam) {
      this.TreeDataPool.treeActiveName = "camera"
      this.TreeDataPool.fetchTreeData();
    } else {
      this.TreeDataPool.treeActiveName = "dataStack"
      this.DataStackPool.fetchFiles();
    }
    if (this.showCluster) {
      this.TreeDataPool.treeActiveName = "cluster"
      this.TreeDataPool.fetchClusterTree();
      findCluster().then(res => {
        if (res.success) {
          this.clusterName = res.data.clusterName;
        }
      })
    }
  },
  methods: {
    searchAreaData() {
      this.TreeDataPool.fetchTreeData();
    },
    searchDataStack() {
      this.DataStackPool.fetchFiles();
    },
    searchClusterData() {
      this.TreeDataPool.fetchClusterTree();
    },
    lockSwitch() {
      this.TreeDataPool.readonly = !this.TreeDataPool.readonly;
    },
    gbLockSwitch() {
      this.TreeDataPool.gbReadonly = !this.TreeDataPool.gbReadonly;
    },
    dataStackLockSwitch() {
      this.DataStackPool.readonly = !this.DataStackPool.readonly;
    },
    closeTree() {
      this.TreeDataPool.showTreeBox = false;
      bus.$emit('refreshCompareImg')
    },
    addNode(event) {
      this.$refs.tree.addNode(event, { id: 0 });
    },
    addCamera(node) {
      bus.$emit("addCameraOnTree", node);
    },
    addDir(node) {
      bus.$emit("addDirOnTree", node);
    },
    menuOpen(index) {
      this.TreeDataPool.openeds[index] = true;
    },
    menuClose(index) {
      this.TreeDataPool.openeds[index] = false;
    },
    refreshGB() {
      // 防止重复刷新
      if (this.loadingGBTree) {
        return;
      }
      // 国标摄像机数据是国标服务分批推送的,请求刷新列表后,需要等待约1分钟的时间后端才能同步完数据。
      this.TreeDataPool.refreshGB28181();
      this.loadingGBTree = true;
      setTimeout(() => {
        this.TreeDataPool.fetchGbTree();
        this.loadingGBTree = false;
      }, 1000 * 60);
    },
    querySearchAsync(type) {
      clearTimeout(this.timeout);
      this.timeout = setTimeout(() => {
        if (type === "camera") {
          this.TreeDataPool.fetchTreeData();
        }
        if (type === "cluster") {
          this.TreeDataPool.fetchClusterTree();
        }
        if (type === "dir") {
          this.DataStackPool.fetchFiles();
        }
      }, 500);
    },
    handleClick(event) {
      if (event.name == 'dataStack') {
        this.DataStackPool.fetchFiles();
        this.DataStackPool.clean();
        this.TreeDataPool.clean();
      }
      this.TreeDataPool.treeActiveName = event.name
      console.log("当前激活name:", this.TreeDataPool.treeActiveName)
    },
    async changeEnable() {
      if (this.PollData.localVideo === 0) {
        this.$notify({
          title: "失败",
          type: "warning",
          message: "开启本地数据视频分析处理,需先为本地数据手动设置算力资源!"
        })
        return false;
      }
      let res = await changeEnable({
        enable: this.TreeDataPool.vedioAnaliyseSwitch
      })
      if (res && res.success) {
        console.log(res, '切换本地文件分析开关')
      }
    },
    getCheckedFiles() {
      let list1 = this.TreeDataPool.localVedioList.filter(i => {
        return i.checkStatus
      })
      return list1
    },
    async stopVedio(status) {
      // let list1 = this.getCheckedFiles();
      if (this.TreeDataPool.checkedLocalVedio.length == 0) {
        this.$notify({
          type: "warning",
          message: "请先选择需要停止的视频!"
        });
        // this.$notify({
        //   type:"info",
        //   message:"请先选择需要停止的视频!"
        // })
        return false;
      }
      let res = await updateStatus({
        ids: this.TreeDataPool.checkedLocalVedio.map(i => {
          return i.id
        }),
        status: status
      })
      if (res && res.success) {
        console.log(res, '开启暂停参数')
      }
    },
    async deleteLocalFiles() {
      let list1 = this.getCheckedFiles();
      console.log(list1, '已勾选的视频')
      if (list1.length == 0) {
        return false
      }
      let res = await deleteLocalFile({
        ids: list1.map(i => { return i.id })
      })
      if (res && res.success) {
        this.$notify({
          type: 'success',
          message: '删除成功!!'
        })
      } else {
        this.$notify({
          type: "error",
          message: "删除失败!"
        })
      }
    },
    refrash(current, pageSize) {
      this.TreeDataPool.localCurrentPage = current;
    },
    importCameras(area) {
      this.importAreaId = area
      this.$refs["import-btn"].click()
    },
    async uploadFile(params) {
      const _file = params.file;
      const fileReader = new FileReader();
      fileReader.onload = (ev) => {
        this.menuLoading = true;
        try {
          const data = ev.target.result;
          const workbook = XLSX.read(data, {
            type: 'binary'
          });
          for (let sheet in workbook.Sheets) {
            //循环读取每个文件
            const sheetArray = XLSX.utils.sheet_to_json(workbook.Sheets[sheet]);
            //若当前sheet没有数据,则continue
            if (sheetArray.length == 0) {
              continue;
            }
            let succeed = 0;
            let failed = 0;
            let promiseArr = [];
            for (let item in sheetArray) {
              let camera = this.newCamera();
              camera.areaid = this.importAreaId;
              camera.name = String(sheetArray[item].name);
              camera.rtsp = String(sheetArray[item].rtsp);
              camera.addr = String(sheetArray[item].addr);
              promiseArr.push(createCamera(camera));
            }
            let _this = this;
            Promise.allSettled(promiseArr).then(res => {
              res.forEach(item => {
                if (item.status === 'fulfilled') {
                  succeed++;
                } else {
                  failed++;
                }
              });
              _this.menuLoading = false;
              _this.$message({
                type: "success",
                message: "操作完成, 导入成功:" + succeed + "个 失败:" + failed + "个"
              })
              _this.TreeDataPool.fetchTreeData();
            }).catch(e => {
              console.log(e)
            });
          }
        } catch (e) {
          this.menuLoading = false
          this.$message.warning('文件类型不正确!');
        }
      };
      fileReader.readAsBinaryString(_file);
    },
    exceed() {
      this.$message.error("最多只能上传1个xls文件");
    },
    //删除文件
    remove() {
    },
    newCamera() {
      return {
        latitude: 0,
        rtsp: "",
        longitude: 0,
        name: "",
        addr: "",
        areaid: "",
        reserved: "",
        run_type: -1,
        username: "",
        password: "",
        sensors: []
      }
    }
  }
};
</script>
<style lang="scss">
.left-tree-box {
  float: left;
  width: 100%;
  .el-tabs__nav-prev,
  .el-tabs__nav-next {
    display: none;
  }
  .el-tabs--border-card {
    border: none;
    box-shadow: none;
    .el-tabs__header {
      display: none;
      border-bottom: none;
      //margin: 0 0 15px;
    }
    .el-tabs__content {
      padding: 0;
      width: 100%;
    }
  }
  ul {
    li {
      .el-menu-item-group__title {
        padding: none;
      }
    }
    .el-submenu__title,
    .el-menu-item {
      padding-left: 10px !important;
      color: #222222 !important;
      font-size: 17px !important;
      height: 35px;
      line-height: 35px;
      .el-submenu__icon-arrow {
        font-size: 12px !important;
        padding-right: 2px !important;
        right: 0;
        //right: unset;
      }
      i {
        padding-right: 10px !important;
        font-size: 24px !important;
        color: #666666 !important;
      }
    }
  }
  .navTopSelect {
    display: flex;
    text-align: left;
    .el-input__icon {
      line-height: 34px;
    }
    // padding: 24px 0px;
    // padding-top: 24px;
    padding-bottom: 12px;
    input:nth-child(1) {
      height: 34px;
      box-shadow: 0 2px 11px -6px rgba(95, 95, 95, 0.5);
    }
    input:nth-child(2) {
      height: 34px;
      width: 103px;
      box-shadow: 0 2px 11px -6px rgba(95, 95, 95, 0.5);
    }
  }
  .isCollapse {
    font-size: 20px;
    padding: 0px 5px;
  }
  // .el-input__inner:focus {
  //     outline: none;
  //     border-color: #3D68E1;
  // }
  .el-menu {
    border-right: none;
  }
  .el-menu-vertical-demo:not(.el-menu--collapse) {
    .fontFamily,
    .el-submenu__title .fontFamily,
    .el-submenu__title .fontFamily {
      padding-right: 20px;
      font-size: 22px;
    }
    .el-menu {
      // border-right: solid 1px #e6e6e6;
      border-right: none;
    }
  }
  .el-menu-vertical-demo:hover {
    overflow-y: hidden;
    overflow-x: hidden;
  }
  .tree-anchor .fontFamily {
    font-size: 16px !important;
    color: #2074ef;
    padding-right: 0px !important;
  }
  .el-submenu__title,
  .el-menu-item {
    text-align: left;
  }
  .item-group {
    margin-left: 33px;
    margin-top: -12px;
  }
  .el-tabs__item {
    padding: 0 10px;
    height: 40px;
    -webkit-box-sizing: border-box;
    box-sizing: border-box;
    line-height: 40px;
    display: inline-block;
    list-style: none;
    font-size: 13px;
    font-weight: 500;
    color: #303133;
    position: relative;
  }
  .local-vedio-area {
    float: left;
    width: 300px;
    .tree-edit-btn {
      width: 100%;
      height: 40px;
      text-align: left;
      margin-top: -8px;
      i {
        font-size: 20px;
        margin: 0px 17px;
      }
      .el-button {
        margin-left: 0px;
      }
    }
    .search-input {
      padding-top: 8px;
      padding-bottom: 12px;
      text-align: left;
      .dev-tree-close {
        width: 10%;
        margin-left: 10px;
        font-size: 20px;
        display: inline-block;
        color: #9ea0a0;
        vertical-align: middle;
        cursor: pointer;
      }
      .dev-switch-close {
        text-align: left;
        margin-left: 15px;
        margin-top: 10px;
        span {
          font-size: 15px;
        }
      }
    }
    .dev-vedio-list {
      padding: 0 15px;
      box-sizing: border-box;
      // height: calc(100vh - 80px);
      //max-height: 740px;
      // overflow-x: hidden;
      overflow: auto;
    }
    .dev-vedio-list::-webkit-scrollbar {
      /*滚动条整体样式*/
      width: 4px; /*高宽分别对应横竖滚动条的尺寸*/
      height: 4px;
    }
  }
}
.tree-close {
  width: 10%;
  margin-left: 10px;
  font-size: 20px;
  display: inline-block;
  color: #9ea0a0;
  vertical-align: middle;
  cursor: pointer;
}
.tree-edit {
  z-index: 2;
  font-size: 16px;
  position: absolute;
  top: 56px;
  cursor: pointer;
  button {
    border: 0px;
    color: #3d68e1;
    background-color: transparent;
    cursor: pointer;
    outline: none;
  }
  button:hover {
    color: #2249b4;
  }
}
.tree-lock {
  left: 235px;
  button {
    color: #000;
  }
}
.gb-lock {
  left: 231px;
  top: -27px;
  button {
    color: #000;
  }
}
.area-add {
  left: 100px;
}
.camera-add {
  left: 128px;
}
.import-btn {
  left: 156px;
}
.tree-font {
  font-family: PingFangSC-Medium;
  font-size: 14px;
  color: #222222;
}
.gb-refresh {
  top: -27px;
  left: 113px;
}
.paginationClass {
  width: 100%;
  height: 60px;
  .el-pagination {
    max-width: 300px;
    white-space: nowrap;
    padding: 0;
    color: #303133;
    font-weight: bold;
  }
  .el-pagination__jump {
    margin-left: 0px;
    font-weight: normal;
    color: #606266;
  }
}
.flex-box {
  display: flex;
}
</style>
src/pages/changchunTrack/components/VideoItem.vue
New file
@@ -0,0 +1,342 @@
<template>
  <div
    :style="'width:' + vWidth + ';height:' + vHeight"
    class="video-box"
    @click.stop.prevent="_click"
    @mouseenter.stop.prevent="videoMouseEnter($event)"
    @mouseleave="videoMouseLeave($event)"
  >
    <div
      class="video-box-top"
      v-if="videoItem !== '' && videoItem !== undefined && videoItem !== null"
    >
      <b>{{ videoItem.name }}</b>
      <span @click="deleteVideo(videoIndex)">×</span>
    </div>
    <div style="position:relative;width:100%;height: 100%;background:#272727;">
      <div class="circle">
        <p class="p1" @mousedown="ptCtrl('up')" @mouseup="ptStop"></p>
        <p class="p2" @mousedown="ptCtrl('right')" @mouseup="ptStop"></p>
        <div class="mid" @mouseup="ptStop">
          <span class="mid_1" @mousedown="ptCtrl('zoomin')">
            <i class="el-icon-plus"></i>
          </span>
          <span class="mid_2" @mousedown="ptCtrl('zoomout')" @mouseup="ptStop">
            <i class="el-icon-minus"></i>
          </span>
        </div>
        <p class="p3" @mousedown="ptCtrl('down')" @mouseup="ptStop"></p>
        <p class="p4" @mousedown="ptCtrl('left')" @mouseup="ptStop"></p>
      </div>
      <camera-player
        :cameraName="videoItem.name"
        :cameraID="videoItem.id"
        :rtspUrl="videoItem.rtsp"
        :isRunning="videoItem.isRunning"
        :isGb="videoItem.cameraType === 1"
        :showArea="showArea"
        v-if="videoItem !== '' && videoItem !== undefined && videoItem !== null && TreeDataPool.treeActiveName==='camera'"
      ></camera-player>
      <video
        v-if="videoItem !== '' && videoItem !== undefined && videoItem !== null && TreeDataPool.treeActiveName==='dataStack'"
        :src="videoItem.rtsp"
        autoplay="autoplay"
        poster="/images/cameraVideo/video-poster.png"
        controls
      >您的浏览器不支持 video 标签。</video>
    </div>
  </div>
</template>
<script>
import { ptzControl } from "@/api/camera"
import CameraPlayer from "@/components/player";
export default {
  components: {
    CameraPlayer
  },
  props: {
    videoGuid: {
      type: Number,
      default: 1
    },
    videoIndex: null,
    starW: {
      type: String,
      default: ''
    },
    starH:{
      type: String,
      default: ''
    },
    videoItem: {
      type: [Object, String],
      default: null
    },
    showArea: Boolean,
  },
  data() {
    return {
      timer: '',
      mouseDown: false,
      videoDataItem: null
    }
  },
  computed: {
    vWidth() {
      if (this.starW!=0) {
        return this.starW
      }
      let per = (1 / this.videoGuid) * 100 + "%";
      return `calc(${per} - 4px)`;
    },
    vHeight() {
      if (this.starH!=0) {
        return this.starH
      }
      let per = (1 / this.videoGuid) * 100 + "%";
      return `calc(${per} - 4px)`;
    }
  },
  methods: {
    _click() {
      this.$emit("click");
    },
    ptCtrl(type) {
      // 当前只支持国标摄像机
      // console.log(type, 'ptCtrl')
      if (this.videoItem.cameraType != 1) {
        return
      }
      this.mouseDown = true;
      let params = {
        cameraId: this.videoItem.id,
        cameraType: this.videoItem.cameraType,
        PTZType: type
      }
      ptzControl(params).then(rsp => {
        // console.log(rsp)
      })
      let that = this
      this.timer = setTimeout(() => {
        that.ptStop()
      }, 5000)
    },
    ptStop() {
      // 当前只支持国标摄像机
      if (this.videoItem.cameraType != 1) {
        return
      }
      let params = {
        cameraId: this.videoItem.id,
        cameraType: this.videoItem.cameraType,
        PTZType: "stop"
      }
      if (this.mouseDown) {
        this.mouseDown = false
        ptzControl(params).then(rsp => {
          // console.log(rsp)
        })
      }
    },
    deleteVideo(index) {
      let video = this.TreeDataPool.videoArr;
      video[index].isPlaying = false;
      this.TreeDataPool.setVideoArr(index, undefined, this);
    },
    videoMouseEnter(e) {
      let target = e.target;
      if (target.children.length > 1) {
        target.children[0].style.display = "block";
        target.children[1].children[0].style.display = "block";
      }
    },
    videoMouseLeave(e) {
      let videoBoxTop = document.getElementsByClassName("video-box-top");
      let circle = document.getElementsByClassName("circle");
      for (let i = 0; i < videoBoxTop.length; i++) {
        videoBoxTop[i].style.display = "none";
      }
      for (let i = 0; i < circle.length; i++) {
        circle[i].style.display = "none";
      }
    }
  }
};
</script>
<style lang="scss">
.side-border {
  border-right: 1px solid #cacaca;
  border-bottom: 1px solid #cacaca;
}
.video-box {
  float: left;
  box-sizing: border-box;
  padding-left: 1px;
  padding-bottom: 1px;
  position: relative;
  margin: 0px 4px 4px 0px;
  background-color: #cacaca;
  .video-box-top {
    color: white;
    display: none;
    width: 100%;
    height: 32px;
    line-height: 32px;
    padding: 0px 20px;
    box-sizing: border-box;
    background: #27293190;
    position: absolute;
    top: 0px;
    z-index: 2;
    b {
      float: left;
    }
    span {
      float: right;
      font-size: 22px;
      font-weight: 900;
      cursor: pointer;
    }
  }
  .circle {
    height: 60px;
    width: 60px;
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.29);
    position: absolute;
    z-index: 1;
    top: 40px;
    right: 10px;
    display: none;
    p {
      position: relative;
      cursor: pointer;
    }
    .p1 {
      width: 0px;
      height: 0px;
      border: 8px solid;
      border-bottom-color: rgba(0, 0, 0, 0.6);
      border-left-color: transparent;
      border-top-color: transparent;
      border-right-color: transparent;
      left: 22px;
      top: -2px;
    }
    .p2 {
      width: 0px;
      height: 0px;
      border: 8px solid;
      border-bottom-color: transparent;
      border-left-color: rgba(0, 0, 0, 0.6);
      border-top-color: transparent;
      border-right-color: transparent;
      left: 46px;
      top: 7px;
    }
    .p3 {
      width: 0px;
      height: 0px;
      border: 8px solid;
      border-bottom-color: transparent;
      border-left-color: transparent;
      border-top-color: rgba(0, 0, 0, 0.6);
      border-right-color: transparent;
      left: 23px;
      top: -8px;
    }
    .p4 {
      width: 0px;
      height: 0px;
      border: 8px solid;
      border-bottom-color: transparent;
      border-left-color: transparent;
      border-top-color: transparent;
      border-right-color: rgba(0, 0, 0, 0.6);
      left: -2px;
      top: -49px;
    }
    .mid {
      width: 24px;
      height: 24px;
      border-radius: 50%;
      position: relative;
      font-size: 5px;
      top: -13px;
      left: 18px;
      background: rgba(0, 0, 0, 0.6);
      span {
        height: 24px;
        float: left;
        line-height: 24px;
        text-align: center;
        box-sizing: border-box;
        cursor: pointer;
        font-weight: 900;
        color: rgba($color: rgb(97, 97, 97), $alpha: 0.4);
      }
      span:hover {
        color: #fff;
        // background-color: #409eff;
      }
      .mid_1 {
        width: 50%;
        height: 24px;
        border-top-left-radius: 50%;
        border-bottom-left-radius: 50%;
      }
      .mid_1:hover {
        background: #fff;
        color: #222222;
      }
      .mid_2 {
        border-top-right-radius: 50%;
        border-bottom-right-radius: 50%;
        width: 50%;
        height: 24px;
      }
      .mid_2:hover {
        background: #fff;
        color: #222222;
      }
    }
    .mid2 {
      width: 18px;
      height: 18px;
    }
    .p1:hover {
      border-bottom-color: #fff;
    }
    .p2:hover {
      border-left-color: #fff;
    }
    .p3:hover {
      border-top-color: #fff;
    }
    .p4:hover {
      border-right-color: #fff;
    }
  }
  .video-js,
  .vjs-custom-skin {
    width: 100%;
    height: 100%;
  }
  .video-play {
    position: absolute;
    top: 0px;
    left: 0px;
    bottom: 0px;
    right: 0px;
    margin: auto;
  }
}
</style>
src/pages/changchunTrack/index/App.vue
New file
@@ -0,0 +1,124 @@
<template>
  <div class="column">
    <div class="column-left" >
      <div class="resize-bar"></div>
      <div class="resize-line"></div>
      <div class="resize-save">
        <left-nav :appName="'Camera'" :height="screenHeight - 40"></left-nav>
      </div>
    </div>
    <div class="column-right" >
      <right-side />
    </div>
    <card-window></card-window>
  </div>
</template>
<script>
// import LeftNav from "@/components/LeftNav";
import LeftNav from "../components/LeftNav";
import RightSide from "./Video";
import CardWindow from "@/components/cardWindow";
export default {
  name: "CameraVideo",
  components: {
    LeftNav,
    RightSide,
    CardWindow
  },
  data() {
    return {
      screenHeight: 0,
    }
  },
  mounted() {
    this.screenHeight = document.documentElement.clientHeight - 20;
    window.onresize = () => {
      return (() => {
        this.screenHeight = document.documentElement.clientHeight - 20;
      })();
    };
  },
};
</script>
<style lang="scss" scoped>
.column {
  overflow: hidden;
  // min-width: 1399px;
  // height: 100%;
}
.column-left {
  background-color: #fff;
  position: relative;
  float: left;
  height: 100vh;
  //height: inherit;
}
.column-right {
  height: 100vh;
  background-color: #eee;
  box-sizing: border-box;
  //overflow: hidden;
  overflow-x: auto;
  overflow-y: auto;
}
.resize-save {
  position: absolute;
  top: 0;
  right: 5px;
  bottom: 0;
  left: 0;
  padding: 14px;
  overflow-x: hidden;
}
.resize-bar {
  width: 310px;
  height: inherit;
  resize: horizontal;
  cursor: ew-resize;
  opacity: 0;
  overflow: scroll;
  max-width: 500px; //设定最大拉伸长度
  min-width: 33px; //设定最小宽度
}
/* 拖拽线 */
.resize-line {
  position: absolute;
  right: 0;
  top: 0;
  bottom: 0;
  border-right: 2px solid #efefef;
  border-left: 1px solid #e0e0e0;
  pointer-events: none;
}
.resize-bar:hover ~ .resize-line,
.resize-bar:active ~ .resize-line {
  border-left: 1px dashed skyblue;
}
.resize-bar::-webkit-scrollbar {
  width: 200px;
  height: inherit;
}
/* Firefox只有下面一小块区域可以拉伸 */
@supports (-moz-user-select: none) {
  .resize-bar:hover ~ .resize-line,
  .resize-bar:active ~ .resize-line {
    border-left: 1px solid #bbb;
  }
  .resize-bar:hover ~ .resize-line::after,
  .resize-bar:active ~ .resize-line::after {
    content: "";
    position: absolute;
    width: 16px;
    height: 16px;
    bottom: 0;
    right: -8px;
    // background: url(./resize.svg);
    background-size: 100% 100%;
  }
}
</style>
src/pages/changchunTrack/index/Video.vue
New file
@@ -0,0 +1,803 @@
<template>
  <div style="width: 100%; height: 100%">
    <div class="monitoring-right" ref="videoRight">
      <div class="main-top">
        <div class="monitoring-video" ref="monitorVideo">
          <!-- <div class="monitoring-video-guid">
            <span
              :class="guid === 1 ? 'iconfont icongongge1 activegongge':'iconfont icongongge1'"
              @click="setGuid(1)"
            ></span>
            <span
              :class="guid === 2 ? 'iconfont icongongge activegongge':'iconfont icongongge'"
              @click="setGuid(2)"
            ></span>
            <span
              :class="guid === 3 ? 'iconfont icongongge2 activegongge':'iconfont icongongge2'"
              @click="setGuid(3)"
            ></span>
            <el-tooltip v-if="TreeDataPool.selectedNode.id" :content="`${showArea?'隐藏区域':'查看区域'}`" placement="bottom" popper-class="atooltip">
              <span :class="showArea?'activegongge':''" class="iconfont iconquyu" @click="toggleShowArea"></span>
            </el-tooltip>
          </div> -->
          <div class="fixedRatioBox">
            <!-- :class="guid==1?'video-main-box':'video-main-box-side'" -->
            <div
              class="video-main-box-side"
              v-if="visibilityState && allVideoNum == 5"
            >
              <!-- :videoIndex="index" -->
              <VideoItem
                :videoGuid="guid"
                :starW="`calc(66.66% - 4px)`"
                :starH="`calc(66.66% - 4px)`"
                :videoItem="centerVideo"
                :showArea="showArea"
                class="activeItem"
              ></VideoItem>
              <!-- <VideoItem
                :videoGuid="guid"
                :starW="`calc(66.66% - 4px)`"
                :starH="`calc(66.66% - 4px)`"
                :videoItem="nextVideo"
                :showArea="showArea"
                class="activeItem"
              ></VideoItem> -->
              <VideoItem
                v-for="(item, index) in TreeDataPool.videoArr"
                :key="index"
                :videoGuid="guid"
                :videoIndex="index"
                :videoItem="item"
                :showArea="showArea"
                :class="[
                  TreeDataPool.activeVideoIndex === index + 1
                    ? 'activeItem'
                    : '',
                  guid === 1 ? 'onlyActiveItem' : '',
                ]"
                @click="videoItemClick(index)"
              ></VideoItem>
            </div>
            <div
              class="video-main-box-side"
              v-if="visibilityState && allVideoNum == 7"
            >
              <VideoItem
                :videoGuid="guid"
                :starW="`calc(74.99% - 4px)`"
                :starH="`calc(74.99% - 4px)`"
                :videoItem="centerVideo"
                :showArea="showArea"
                class="activeItem"
              ></VideoItem>
              <VideoItem
                v-for="(item, index) in TreeDataPool.videoArr"
                :key="index"
                :videoGuid="guid"
                :videoIndex="index"
                :videoItem="item"
                :showArea="showArea"
                :class="[
                  TreeDataPool.activeVideoIndex === index + 1
                    ? 'activeItem'
                    : '',
                  guid === 1 ? 'onlyActiveItem' : '',
                ]"
                @click="videoItemClick(index)"
              ></VideoItem>
            </div>
            <div
              class="video-main-box-side"
              v-if="visibilityState && allVideoNum == 12"
            >
              <div style="width: 100%; height: 25%">
                <VideoItem
                  v-for="(item, index) in TreeDataPool.videoArr.slice(0, 4)"
                  :key="index"
                  :videoGuid="guid"
                  :videoIndex="index"
                  :starW="`calc(24.99% - 4px)`"
                  :starH="`calc(100% - 4px)`"
                  :videoItem="item"
                  :showArea="showArea"
                  :class="[
                    TreeDataPool.activeVideoIndex === index + 1
                      ? 'activeItem'
                      : '',
                    guid === 1 ? 'onlyActiveItem' : '',
                  ]"
                  @click="videoItemClick(index)"
                ></VideoItem>
              </div>
              <div style="width: 25%; height: 50%; float: left">
                <VideoItem
                  v-for="(item, index) in TreeDataPool.videoArr.slice(4, 6)"
                  :key="index"
                  :videoGuid="guid"
                  :videoIndex="index"
                  :starW="`calc(100% - 4px)`"
                  :starH="`calc(50% - 4px)`"
                  :videoItem="item"
                  :showArea="showArea"
                  :class="[
                    TreeDataPool.activeVideoIndex === index + 1
                      ? 'activeItem'
                      : '',
                    guid === 1 ? 'onlyActiveItem' : '',
                  ]"
                  @click="videoItemClick(index)"
                ></VideoItem>
              </div>
              <VideoItem
                :videoGuid="guid"
                :starW="`calc(50% - 4px)`"
                :starH="`calc(50% - 4px)`"
                :videoItem="centerVideo"
                :showArea="showArea"
                class="activeItem"
              ></VideoItem>
              <div style="width: 25%; height: 50%; float: left">
                <VideoItem
                  v-for="(item, index) in TreeDataPool.videoArr.slice(6, 8)"
                  :key="index"
                  :videoGuid="guid"
                  :videoIndex="index"
                  :starW="`calc(100% - 4px)`"
                  :starH="`calc(50% - 4px)`"
                  :videoItem="item"
                  :showArea="showArea"
                  :class="[
                    TreeDataPool.activeVideoIndex === index + 1
                      ? 'activeItem'
                      : '',
                    guid === 1 ? 'onlyActiveItem' : '',
                  ]"
                  @click="videoItemClick(index)"
                ></VideoItem>
              </div>
              <div style="width: 100%; height: 25%">
                <VideoItem
                  v-for="(item, index) in TreeDataPool.videoArr.slice(8)"
                  :key="index"
                  :videoGuid="guid"
                  :videoIndex="index"
                  :starW="`calc(24.99% - 4px)`"
                  :starH="`calc(100% - 4px)`"
                  :videoItem="item"
                  :showArea="showArea"
                  :class="[
                    TreeDataPool.activeVideoIndex === index + 1
                      ? 'activeItem'
                      : '',
                    guid === 1 ? 'onlyActiveItem' : '',
                  ]"
                  @click="videoItemClick(index)"
                ></VideoItem>
              </div>
            </div>
            <div
              class="video-main-box-side"
              v-if="visibilityState && allVideoNum == 16"
            >
              <div style="width: 100%; height: 20%">
                <VideoItem
                  v-for="(item, index) in TreeDataPool.videoArr.slice(0, 5)"
                  :key="index"
                  :videoGuid="guid"
                  :videoIndex="index"
                  :starW="`calc(19.99% - 4px)`"
                  :starH="`calc(100% - 4px)`"
                  :videoItem="item"
                  :showArea="showArea"
                  :class="[
                    TreeDataPool.activeVideoIndex === index + 1
                      ? 'activeItem'
                      : '',
                    guid === 1 ? 'onlyActiveItem' : '',
                  ]"
                  @click="videoItemClick(index)"
                ></VideoItem>
              </div>
              <div style="width: 20%; height: 60%; float: left">
                <VideoItem
                  v-for="(item, index) in TreeDataPool.videoArr.slice(5, 8)"
                  :key="index"
                  :videoGuid="guid"
                  :videoIndex="index"
                  :starW="`calc(100% - 4px)`"
                  :starH="`calc(33.33% - 4px)`"
                  :videoItem="item"
                  :showArea="showArea"
                  :class="[
                    TreeDataPool.activeVideoIndex === index + 1
                      ? 'activeItem'
                      : '',
                    guid === 1 ? 'onlyActiveItem' : '',
                  ]"
                  @click="videoItemClick(index)"
                ></VideoItem>
              </div>
              <VideoItem
                :videoGuid="guid"
                :starW="`calc(60% - 4px)`"
                :starH="`calc(60% - 4px)`"
                :videoItem="centerVideo"
                :showArea="showArea"
                class="activeItem"
              ></VideoItem>
              <div style="width: 20%; height: 60%; float: left">
                <VideoItem
                  v-for="(item, index) in TreeDataPool.videoArr.slice(8, 11)"
                  :key="index"
                  :videoGuid="guid"
                  :videoIndex="index"
                  :starW="`calc(100% - 4px)`"
                  :starH="`calc(33.33% - 4px)`"
                  :videoItem="item"
                  :showArea="showArea"
                  :class="[
                    TreeDataPool.activeVideoIndex === index + 1
                      ? 'activeItem'
                      : '',
                    guid === 1 ? 'onlyActiveItem' : '',
                  ]"
                  @click="videoItemClick(index)"
                ></VideoItem>
              </div>
              <div style="width: 100%; height: 20%; float: left">
                <VideoItem
                  v-for="(item, index) in TreeDataPool.videoArr.slice(11)"
                  :key="index"
                  :videoGuid="guid"
                  :videoIndex="index"
                  :starW="`calc(19.99% - 4px)`"
                  :starH="`calc(100% - 4px)`"
                  :videoItem="item"
                  :showArea="showArea"
                  :class="[
                    TreeDataPool.activeVideoIndex === index + 1
                      ? 'activeItem'
                      : '',
                    guid === 1 ? 'onlyActiveItem' : '',
                  ]"
                  @click="videoItemClick(index)"
                ></VideoItem>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
import VideoItem from "../components/VideoItem";
import { getCameraPlayList, showAllCameras } from "@/api/trackCamera";
export default {
  name: "Video",
  components: {
    VideoItem,
  },
  data() {
    return {
      guid: 3,
      center: "",
      defaultHeight: 432,
      defaultWidth: 600,
      track: false,
      traceCache: {},
      traceTimer: null,
      tracePubUrl: `${location.protocol === "https" ? "wss" : "ws"}://${
        location.host
      }/track`,
      websocket: null,
      visibilityState: true,
      showArea: false,
      videoNum2Play: 0,
      centerVideo: null,
      nextVideo: null,
      list2TakeTurn: [],
      timer: null,
      centerIndex: 0,
    };
  },
  created() {
    this.TreeDataPool.activeVideoIndex = sessionStorage.activeIndex
      ? Number(sessionStorage.activeIndex)
      : this.TreeDataPool.activeVideoIndex;
    this.getActiveIndex();
    this.TreeDataPool.readonly = true;
    this.TreeDataPool.gbReadonly = true;
    this.TreeDataPool.multiple = false;
  },
  mounted() {
    document.addEventListener("visibilitychange", this.visibilitychange, false);
    this.$nextTick(() => {
      window.addEventListener("resize", this.resizeMonitorTask);
      //this.getRightWidth();
      this.resizeMonitorTask();
    });
    this.getCenter();
    this.blackAngWhite();
    this.VideoPhotoData.queryTagList();
    showAllCameras().then((res) => {
      this.videoNum2Play = res.data.length;
      res.data.forEach((info, i) => {
        let camera = this.TreeDataPool.getCameraInfoById(info.cameraId);
        this.TreeDataPool.setVideoArr(i, camera, this);
        if (info.status == 1) {
          this.list2TakeTurn.push(info);
        }
      });
      if (this.list2TakeTurn.length == 0 && res.data.length) {
        this.list2TakeTurn.push(res.data[0]);
      }
      this.handleSwitch();
      this.list2TakeTurn.forEach((item) => {});
    });
  },
  beforeDestroy() {
    window.removeEventListener("resize", this.getRightWidth);
    this.CardList.details = [];
    window.clearInterval(this.trackTimer);
    if (this.websocket) {
      this.websocket.close();
    }
  },
  watch: {
    "TreeDataPool.videoArr": function (newArry) {
      console.log("newArry", newArry);
      const cameras = this.filterNodes(newArry);
      this.getActiveIndex();
      // this.$refs.taskview.showTasks(cameras);
      // this.$refs.photoview.showCapture(cameras);
    },
    "VideoPhotoData.selectBlacks": function (value) {
      this.blackAngWhite();
    },
    "VideoPhotoData.selectWhites": function (value) {
      this.blackAngWhite();
    },
    "TreeDataPool.showTreeBox"(value) {
      this.getRightWidth();
    },
  },
  methods: {
    handleSwitch() {
      if (this.list2TakeTurn.length == 1) {
        this.centerVideo = this.list2TakeTurn[0];
        return;
      }
      let that = this;
      that.centerVideo = that.list2TakeTurn[that.centerIndex];
      that.nextVideo=that.list2TakeTurn[that.nextIndex]
      that.centerIndex++;
      if (that.centerIndex == that.list2TakeTurn.length) {
        that.centerIndex = 0;
      }
      this.timer = setInterval(() => {
        that.centerVideo = that.list2TakeTurn[that.centerIndex];
        that.nextVideo=that.list2TakeTurn[that.nextIndex]
        that.centerIndex++;
        if (that.centerIndex == that.list2TakeTurn.length) {
          that.centerIndex = 0;
        }
      }, 12000);
    },
    initTrackWebsocket() {
      if (typeof WebSocket === "undefined") {
        alert("您的浏览器不支持socket");
      } else {
        // 实例化socket
        this.websocket = new WebSocket(this.tracePubUrl);
        // 监听socket消息
        this.websocket.onopen = this.websocketonopen;
        this.websocket.onmessage = this.recvieTrackMessage;
      }
    },
    websocketonopen() {
      //连接建立之后执行send方法发送数据
      this.websocket.send("sub");
    },
    tracking() {
      getCameraPlayList().then((data) => {
        if (data && data.length) {
          data.forEach((ins) => {
            let newCamera = this.TreeDataPool.getCameraInfoById(
              ins.NewCameraId
            );
            if (!newCamera) {
              console.log("未查找到摄像机:", ins.NewCameraId);
              return;
            }
            if (ins.IsNew) {
              this.newPlayerInViewBox(newCamera);
            } else {
              this.replacePlayer(newCamera, ins.OldCameraId);
            }
          });
        }
      });
    },
    recvieTrackMessage(e) {
      let dataJson = JSON.parse(e.data);
      let cache = this.traceCache;
      let camera = dataJson.camera;
      let person = dataJson.person;
      let create = false;
      // 如果是已经在播放的摄像机, 直接返回
      if (cache[camera]) {
        cache[camera][person] = 10;
        return;
      }
      cache[camera] = {};
      cache[camera][person] = 10;
      // 查询播放该人的上一个摄像机
      for (var cam in cache) {
        if (cam === camera) {
          continue;
        }
        if (cache[cam][person]) {
          // 找到上一个摄像机, 判断摄像机里是否还有其他人, 有:新开播放器 没有:切换
          console.log("last camera:", cam, Object.keys(cache[cam]).length);
          if (Object.keys(cache[cam]).length > 2) {
            delete cache[cam][person];
            this.newPlayerInViewBox(camera);
            return;
          } else {
            this.replacePlayer(camera, cam);
            delete cache[cam];
            return;
          }
        }
      }
      // 未发现播放记录
      this.newPlayerInViewBox(camera);
    },
    newPlayerInViewBox(id) {
      // 新增播放窗口
      let camera = this.TreeDataPool.getCameraInfoById(id);
      let emptyIndex = -1;
      let exist = false;
      for (let i = 0; i < this.TreeDataPool.videoArr.length; i++) {
        // eslint-disable-next-line
        if (
          this.TreeDataPool.videoArr[i] === "" ||
          this.TreeDataPool.videoArr[i] === undefined
        ) {
          if (emptyIndex === -1) {
            emptyIndex = i;
          }
        } else {
          if (this.TreeDataPool.videoArr[i].id === camera.id) {
            exist = true;
          }
        }
      }
      if (!exist && emptyIndex !== -1) {
        this.TreeDataPool.setVideoArr(emptyIndex, camera, this);
      }
    },
    replacePlayer(id, oldCameraId) {
      let camera = this.TreeDataPool.getCameraInfoById(id);
      // 替换播放器
      for (let i = 0; i < this.TreeDataPool.videoArr.length; i++) {
        // eslint-disable-next-line
        if (
          this.TreeDataPool.videoArr[i] &&
          this.TreeDataPool.videoArr[i] !== undefined &&
          this.TreeDataPool.videoArr[i] !== ""
        ) {
          if (this.TreeDataPool.videoArr[i].id === oldCameraId) {
            this.TreeDataPool.setVideoArr(i, camera, this);
            return true;
          }
        }
      }
      return false;
    },
    closePlayer(id) {
      for (let i = 0; i < this.TreeDataPool.videoArr.length; i++) {
        // eslint-disable-next-line
        if (
          this.TreeDataPool.videoArr[i] &&
          this.TreeDataPool.videoArr[i] !== undefined &&
          this.TreeDataPool.videoArr[i] !== ""
        ) {
          if (this.TreeDataPool.videoArr[i].id === id) {
            this.TreeDataPool.setVideoArr(i, undefined, this);
            return true;
          }
        }
      }
    },
    visibilitychange() {
      switch (document.visibilityState) {
        case "hidden":
          this.visibilityState = false;
          break;
        case "visible":
          this.visibilityState = true;
          break;
      }
    },
    blackAngWhite() {
      if (this.VideoPhotoData.selectBlacks.length > 0) {
        for (let i = 0; i < this.VideoPhotoData.whiteList.length; i++) {
          this.$set(this.VideoPhotoData.whiteList[i], "disabled", true);
        }
      }
      if (this.VideoPhotoData.selectBlacks.length == 0) {
        for (let i = 0; i < this.VideoPhotoData.whiteList.length; i++) {
          this.$set(this.VideoPhotoData.whiteList[i], "disabled", false);
        }
      }
      if (this.VideoPhotoData.selectWhites.length > 0) {
        for (let i = 0; i < this.VideoPhotoData.blackList.length; i++) {
          this.$set(this.VideoPhotoData.blackList[i], "disabled", true);
        }
      }
      if (this.VideoPhotoData.selectWhites.length == 0) {
        for (let i = 0; i < this.VideoPhotoData.blackList.length; i++) {
          this.$set(this.VideoPhotoData.blackList[i], "disabled", false);
        }
      }
    },
    closeWindow(index) {
      this.CardList.addBaseList.splice(index, 1);
    },
    getVideoHeight() {
      let h = this.$refs.monitorVideo.offsetHeight;
      // this.$refs.monitorTask.style.height = h + "px";
    },
    resizeMonitorTask() {
      this.getRightWidth();
      this.getVideoHeight();
    },
    getRightWidth() {
      let w = this.$refs.videoRight.offsetWidth;
      // this.$refs.monitorTask.style.width =w - this.$refs.monitorVideo.offsetWidth - 40 + "px";
    },
    filterNodes(selectArry) {
      let nodes = [];
      selectArry.forEach((i) => {
        if (i && nodes.indexOf(i.id) < 0) {
          nodes.push(i.id);
        }
      });
      return nodes;
    },
    videoItemClick(index) {
      this.TreeDataPool.activeVideoIndex = index;
      this.TreeDataPool.activeForceChoose = true;
    },
    toAdd(item) {
      this.CardList.addBaseList.push(item);
    },
    getCenter() {
      this.center = {
        x: document.documentElement.clientWidth / 2 - 250,
        y: document.documentElement.clientHeight / 2 - 200,
      };
    },
    resizeWidth(w) {
      this.defaultWidth = w;
    },
    resizeHeight(h) {
      this.defaultHeight = h;
    },
    saveAddBase(item, index) {
      if (
        this.VideoPhotoData.selectBlacks.length === 0 &&
        this.VideoPhotoData.selectWhites.length === 0
      ) {
        this.$notify({
          title: "注意",
          message: "请选择要添加的底库",
          type: "warning",
        });
        return;
      }
      let res = this.VideoPhotoData.addBase(item);
      res.then((data) => {
        console.log("then", data);
        if (data.success) {
          this.$notify({
            title: "成功",
            message: data.data,
            type: "success",
          });
        } else {
          this.$notify({
            title: "失败",
            message: data.data,
            type: "error",
          });
        }
        this.CardList.addBaseList.splice(index, 1);
        this.VideoPhotoData.selectBlacks = [];
        this.VideoPhotoData.selectWhites = [];
      });
    },
    getActiveIndex() {
      this.TreeDataPool.videoArr.length = this.allVideoNum;
      let nullVideoIndex = "";
      for (let i = 0; i < this.TreeDataPool.videoArr.length; i++) {
        // eslint-disable-next-line
        if (
          this.TreeDataPool.videoArr[i] === "" ||
          this.TreeDataPool.videoArr[i] === undefined
        ) {
          nullVideoIndex = i;
        } else {
          nullVideoIndex = "";
        }
      }
      if (
        this.TreeDataPool.activeVideoIndex !== "" &&
        this.TreeDataPool.activeVideoIndex <
          this.TreeDataPool.videoArr.length - 1
      ) {
        return this.TreeDataPool.activeVideoIndex;
      } else {
        if (nullVideoIndex === "") {
          this.TreeDataPool.activeVideoIndex =
            this.TreeDataPool.videoArr.length - 1;
        } else {
          this.TreeDataPool.activeVideoIndex = nullVideoIndex;
        }
      }
    },
    setGuid(value) {
      clearTimeout(this.trackTimer);
      if (value < this.guid && this.TreeDataPool.activeVideoIndex > value) {
        // eslint-disable-next-line
        for (
          let i = this.TreeDataPool.activeVideoIndex - 1;
          i < this.TreeDataPool.videoArr.length;
          i++
        ) {
          // eslint-disable-next-line
          if (
            this.TreeDataPool.videoArr[i] &&
            this.TreeDataPool.videoArr[i]["isPlaying"]
          ) {
            this.TreeDataPool.videoArr[i]["isPlaying"] = false;
          }
        }
      }
      this.guid = value;
      sessionStorage.guid = this.guid;
      sessionStorage.activeIndex = this.TreeDataPool.activeVideoIndex;
      this.getActiveIndex();
    },
    toggleShowArea() {
      this.showArea = !this.showArea;
    },
  },
  destroyed() {
    window.removeEventListener("resize", this.getRightWidth);
    // this.CardList.details = [];
    this.CardList.addBaseList = [];
    this.VideoPhotoData.selectBlacks = [];
    this.VideoPhotoData.selectWhites = [];
  },
  computed: {
    allVideoNum() {
      if (this.videoNum2Play <= 5) {
        this.guid = 3;
        return 5;
      } else if (this.videoNum2Play <= 7) {
        this.guid = 4;
        return 7;
      } else if (this.videoNum2Play <= 12) {
        this.guid = 4;
        return 12;
      } else if (this.videoNum2Play <= 16) {
        this.guid = 5;
        return 16;
      }
    },
     nextIndex(){
       if (this.centerIndex==this.list2TakeTurn.length-1) {
         return 0
       }
       return this.centerIndex+1
     }
  },
};
</script>
<style lang="scss">
.monitoring-right {
  width: 100%;
  height: 100%;
  // min-width: 981px;
  //float: right;
  box-sizing: border-box;
  padding: 10px;
  background-color: #e9ebf2;
  .main-top {
    margin-bottom: 14px;
    display: flex;
    justify-content: space-between;
  }
  .monitoring-video {
    width: 100%;
    // min-width: 740px;
    // max-width: 1208px;
    // height: 98%;
    //float: left;
    box-sizing: border-box;
    // box-shadow: #e4e7ed 0px 0px 9px inset;
    border-radius: 5px;
    .activeItem {
      border: 3px solid #ff7733;
      position: relative;
      top: -1px;
      left: -1px;
      // width: calc(100% + 2px) !important;
      // height: calc(100% + 2px) !important;
    }
    .onlyActiveItem {
      width: calc(100% + 2px) !important;
      height: calc(100% + 2px) !important;
    }
    .video-main-box {
      background-color: #fff;
      box-sizing: border-box;
      border: 1px solid #cacaca;
    }
    .video-main-box-side {
      border-top: 1px solid #cacaca;
      border-left: 1px solid #cacaca;
      box-sizing: border-box;
      background-color: #fff;
    }
    .monitoring-video-guid {
      text-align: right;
      padding-bottom: 10px;
      .activegongge {
        color: #3d68e1;
      }
      span {
        font-size: 20px;
        color: #cacaca;
        padding-left: 12px;
        cursor: pointer;
      }
      .area-trigger {
        font-size: 16px;
      }
    }
    .fixedRatioBox {
      padding-top: 55.3%;
      box-sizing: border-box;
      position: relative;
      > div {
        width: 100%;
        height: 100%;
        position: absolute;
        top: 0;
      }
    }
  }
}
</style>
src/pages/changchunTrack/index/main.ts
New file
@@ -0,0 +1,28 @@
import Vue from 'vue';
import App from './App.vue';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
// import "@/assets/css/element-variables.scss";
import VueAwesomeSwiper from "vue-awesome-swiper";
import "swiper/dist/css/swiper.css";
import * as VueWindow from "@hscmap/vue-window";
import Mixin from "./mixins";
import preview from 'vue-photo-preview'
import 'vue-photo-preview/dist/skin.css'
Vue.use(preview)
Vue.use(ElementUI)
Vue.use(VueAwesomeSwiper as any);
Vue.use(VueWindow);
Vue.mixin(Mixin);
new Vue({
  el: '#app',
  render: h => h(App)
})
src/pages/changchunTrack/index/mixins.ts
New file
@@ -0,0 +1,29 @@
import TreeDataPool from "@/Pool/TreeData";
import DataStackPool from "@/Pool/dataStack"
import CardList from "@/Pool/CardList";
import VideoPhotoData from "@/Pool/VideoPhotoData";
import VideoTaskData from "@/Pool/VideoTaskData";
import VideoCaptrue from "@/Pool/VideoCapture";
/* eslint-disable */
const onlyTreeDataPool = new TreeDataPool
const onlyDataStack = new DataStackPool
const onlyCardList = new CardList
const onlyVideoPhotoData = new VideoPhotoData
const onlyVideoTaskData = new VideoTaskData
const onlyVideoCaptrue = new VideoCaptrue
const mixin = {
  data() {
    return {
      TreeDataPool: onlyTreeDataPool,
      DataStackPool: onlyDataStack,
      CardList: onlyCardList,
      VideoPhotoData: onlyVideoPhotoData,
      VideoTaskData: onlyVideoTaskData,
      VideoCaptrue: onlyVideoCaptrue,
    };
  },
};
export default mixin;
src/pages/desktop/index/App.vue
@@ -76,12 +76,8 @@
    }, 1000);
    window.addEventListener('message', (e) => {
      if (e.data.msg == 'AppUpdate') {
        debugger
        this.showApps();
      }
      //  if (e.data.msg && e.data.msg.indexOf("refreshDesk")>-1) {
      //     this.showApps();
      //   }
    });
  },
  methods: {
src/pages/desktop/index/components/DFrame.vue
@@ -85,7 +85,6 @@
    }
  },
  mounted() {
    console.log(document.querySelectorAll('iframe'))
    window.addEventListener('message', (d) => {
      let { source, trigger, menuT, menuL } = d.data;
      if (trigger == 'contextmenu') {
src/pages/desktop/index/components/Desktop.vue
@@ -1,25 +1,299 @@
<template>
  <div class="desktop">
    <d-frame v-for="item in this.$store.state.desktop.frames" :data="item" :key="item.id"></d-frame>
    <safari :data="$store.state.desktop.safari" v-if="$store.state.desktop.safari.active"></safari>
    <d-frame
      v-for="item in this.$store.state.desktop.frames"
      :data="item"
      :key="item.id"
    ></d-frame>
    <safari
      :data="$store.state.desktop.safari"
      v-if="$store.state.desktop.safari.active"
    ></safari>
    <div class="warn-tag" v-if="showFreeVersion">
      <span class="text"
        >试用版尚未激活,仅支持部分功能使用,如需使用全部功能,请尽快激活系统。</span
      >
      <span class="go-to" @click="gotoActive">前往激活</span>
      <span class="icon iconfont" @click="showFreeVersion = false"
        >&#xe61b;</span
      >
    </div>
    <el-dialog title="激活SmartAI" :visible.sync="dialogVisible" width="40%">
      <div class="ver"><span class="ver-text">版本:</span>{{ version }}</div>
      <div class="ver">
        <span class="ver-text">状态:</span>{{ versionState }}
      </div>
      <el-divider></el-divider>
      <div class="info">
        如果还没有产品密钥,你可以使用手机扫码或前往此链接
        <a href="http://os.smartai.com:7004" target="_blank"
          >http://os.smartai.com:7004</a
        >
        购买。
      </div>
      <!-- <img class="qr-code-img" src="/images/desktop/weather.png" /> -->
      <!-- <img class="qr-code-img" src="http://192.168.8.10:7009/version/offline/qrcode" /> -->
      <img
        class="qr-code-img"
        src="http://192.168.20.189:7009/version/offline/qrcode"
      />
      <el-divider></el-divider>
      <div class="ask">
        如果你具有SmartAI提供的产品密钥,请在此处输入激活SmartAI。
      </div>
      <div class="validate">
        <form id="myForm">
          <!-- <el-input
            class="single-input"
            size="small"
            ref="secrectKey"
            :maxlength="4"
            v-model="secrectKey"
            placeholder=""
            @input="onInput(1)"
          ></el-input
          >-
          <el-input
            class="single-input"
            size="small"
            ref="input2"
            :maxlength="4"
            v-model="input2"
            placeholder=""
            @input="onInput(2)"
          ></el-input
          >-
          <el-input
            class="single-input"
            size="small"
            ref="input3"
            :maxlength="4"
            v-model="input3"
            placeholder=""
            @input="onInput(3)"
          ></el-input>
          -
          <el-input
            class="single-input"
            size="small"
            ref="input4"
            :maxlength="4"
            v-model="input4"
            placeholder=""
            @input="onInput(4)"
          ></el-input
          >-
          <el-input
            class="single-input"
            size="small"
            ref="input5"
            :maxlength="4"
            v-model="input5"
            placeholder=""
            @input="onInput(5)"
          ></el-input> -->
          <el-input
            type="textarea"
            autosize
            style="width: 480px"
            placeholder="将产品密钥粘贴在此处"
            v-model="secrectKey"
          >
          </el-input>
        </form>
        <el-upload
          class="upload-demo"
          action
          :http-request="uploadKey"
          :limit="1"
          :show-file-list="false"
        >
          <el-button size="small" type="primary">导入产品密钥文件</el-button>
          <!-- <div class="el-upload__tip" slot="tip"></div> -->
        </el-upload>
      </div>
      <span slot="footer" class="dialog-footer">
        <el-button @click="dialogVisible = false">继续试用</el-button>
        <el-button type="primary" @click="activateVersion">激活</el-button>
      </span>
    </el-dialog>
  </div>
</template>
<script>
import DFrame from './DFrame';
import Safari from './Safari';
import DFrame from "./DFrame";
import Safari from "./Safari";
import {
  getActiveQrCode,
  getSN,
  activateVersion,
  uploadKey,
} from "@/api/system";
export default {
  name: "Desktop",
  components: {
    DFrame, Safari
  }
}
    DFrame,
    Safari,
  },
  data() {
    return {
      showFreeVersion: true,
      dialogVisible: false,
      version: "SmartAI试用版",
      versionState: "尚未激活",
      secrectKey: "",
      input2: "",
      input4: "",
      input3: "",
      input5: "",
    };
  },
  mounted() {
    getSN().then((res) => {
      this.showFreeVersion = res.data.sn == "";
    });
  },
  methods: {
    activateVersion() {
      if (this.secrectKey.trim()=="") {
        this.$message.warning("请先填写产品密钥")
        return
      }
      activateVersion({code:this.secrectKey.trim()}).then((res) => {
        debugger
        if (res.code==200) {
          this.$notify.success("激活成功")
          this.goToSysInfo()
          this.dialogVisible = false;
        }else{
          this.$notify.error(res.msg)
        }
      }).catch((err) => {
          this.$notify.error(err.msg)
      })
    },
    goToSysInfo() {
      window.parent.postMessage({ msg: `toVindicate?menu=系统信息` }, "*");
    },
    gotoActive() {
      this.showFreeVersion = false;
      this.dialogVisible = true;
    },
    uploadKey(params) {
      let param = new FormData();
      param.append("code", params.file);
      uploadKey(param).then(
        (res) => {
          this.$message.success("导入成功");
          this.secrectKey = res.data;
        },
        (err) => {
          this.$message.error("导入失败");
        }
      );
    },
    onInput(val) {
      if (this[`input${val}`].length == 4 && val < 5) {
        this.$refs[`input${val + 1}`].focus();
      }
      if (this[`input${val}`].length == 0 && val > 0) {
        this.$refs[`input${val - 1}`].focus();
      }
    },
  },
};
</script>
<style scoped>
<style lang="scss" >
.desktop {
  width: 100%;
  height: 100%;
  .el-dialog__header {
    padding: 15px 20px 10px;
    text-align: left;
    font-weight: 600;
  }
  .el-dialog__body {
    text-align: left;
    padding: 30px 50px;
    padding-top: 20px;
  }
  .el-divider--horizontal {
    margin: 20px 0;
  }
  .validate {
    display: flex;
    align-items: baseline;
    margin-top: 15px;
  }
  #myForm {
    display: flex;
    align-items: center;
    margin-right: 10px;
    .single-input {
      margin: 0 8px;
      width: 60px;
    }
  }
  .ver {
    margin-bottom: 10px;
    font-size: 16px;
    .ver-text {
      font-weight: 600;
    }
  }
  .info {
    font-size: 15px;
    margin-bottom: 10px;
  }
  .qr-code-img {
    // width: 120px;
    // height: 120px;
  }
  .ask {
    margin-top: 20px;
    font-size: 15px;
  }
}
.warn-tag {
  width: 35%;
  text-align: left;
  box-sizing: border-box;
  padding: 0 25px;
  height: 45px;
  background-color: rgba(255, 238, 230, 1);
  z-index: 99999;
  position: absolute;
  display: flex;
  justify-content: space-between;
  top: 55px;
  left: calc(50% - 17.5%);
  line-height: 45px;
  border-radius: 5px;
  .go-to {
    color: rgba(71, 153, 247, 1);
    cursor: pointer;
    text-decoration: underline;
    font-weight: 600;
    font-size: 13px;
  }
  .text {
    font-size: 13px;
  }
  .icon {
    font-size: 14px;
    cursor: pointer;
  }
}
</style>
src/pages/desktop/index/components/Tools.vue
@@ -350,6 +350,8 @@
    });
    this.askSysUpdate();
    this.askAppUpdate();
  },
  methods: {
    askAppUpdate() {
src/pages/desktop/index/components/ToolsEntry.vue
@@ -2,12 +2,12 @@
  <div class="tools-entry">
    <div class="entry-wrap">
      <el-carousel
        :height="rowSize==3?'600px':'770px'"
        :height="rowSize == 3 ? '600px' : '770px'"
        :autoplay="false"
        arrow="never"
        :indicator-position="carousels.length==1?'none':''"
        :indicator-position="carousels.length == 1 ? 'none' : ''"
      >
        <el-carousel-item v-for="(carousel,index) in carousels" :key="index">
        <el-carousel-item v-for="(carousel, index) in carousels" :key="index">
          <div class="app-list clearFix sdk-list">
            <!-- <draggable v-model="carousel" @start="drag=true" @end="drag=false"> -->
            <div v-for="item in carousel" :key="item.id">
@@ -16,21 +16,27 @@
                  <div class="app-icon">
                    <div
                      class="badge"
                      v-if="item.name=='algorithmManage' && badgeNum > 0"
                    >{{badgeNum}}</div>
                      v-if="item.name == 'algorithmManage' && badgeNum > 0"
                    >
                      {{ badgeNum }}
                    </div>
                    <img :src="item.src" :alt="item.alt" />
                  </div>
                  <div class="app-name">{{item.title}}</div>
                  <div class="app-name">{{ item.title }}</div>
                </div>
              </div>
              <div class="app sdk" v-if="item.sdk_name">
                <div class="wrap">
                  <div class="app-icon">
                    <img
                      :src="item.iconBlob.indexOf(',')>0? item.iconBlob:`data:image/png;base64,${item.iconBlob}`"
                      :src="
                        item.iconBlob.indexOf(',') > 0
                          ? item.iconBlob
                          : `data:image/png;base64,${item.iconBlob}`
                      "
                    />
                  </div>
                  <div class="app-name">{{item.sdk_name}}</div>
                  <div class="app-name">{{ item.sdk_name }}</div>
                </div>
              </div>
            </div>
@@ -46,11 +52,11 @@
</template>
<script>
import draggable from "vuedraggable"
import { findAllSdk } from '@/api/taskMange';
import bus from '@/plugin/bus'
import draggable from "vuedraggable";
import { findAllSdk } from "@/api/taskMange";
import bus from "@/plugin/bus";
export default {
  name: 'toolsEntry',
  name: "toolsEntry",
  data() {
    return {
      publicPath: process.env.BASE_URL,
@@ -68,16 +74,16 @@
      // ],
      //rowSize: 3,
      // badgeNum: 0,
    }
    };
  },
  computed: {
    stateDocks() {
      return this.$store.state.desktop.docks
      return this.$store.state.desktop.docks;
    },
    carousels() {
      let pages = 0;
      let tempArr = this.stateDocks.concat(this.installedSdk);
      let upgradeArr = tempArr.filter(item => item.isUpgrade);
      let upgradeArr = tempArr.filter((item) => item.isUpgrade);
      let arr = null;
      //根据屏幕高度来判断是展示3排还是4排 阈值:970
      if (window.innerHeight >= 930) {
@@ -87,11 +93,11 @@
        //this.rowSize = 3;
        arr = this.chunk(tempArr, 18);
      }
      return arr
      return arr;
    },
    badgeNum() {
      let tempArr = this.stateDocks.concat(this.installedSdk);
      return tempArr.filter(item => item.isUpgrade).length;
      return tempArr.filter((item) => item.isUpgrade).length;
    },
    rowSize() {
      if (window.innerHeight >= 930) {
@@ -99,12 +105,12 @@
      } else {
        return 3;
      }
    }
    },
  },
  mounted() {
    this.getAllSdk();
    let _this= this
    window.addEventListener('message', e => {
    let _this = this;
    window.addEventListener("message", (e) => {
      if (e.data && e.data.msg) {
        let msg = e.data.msg;
        if (msg === "logout") {
@@ -113,39 +119,35 @@
        }
        if (msg.indexOf("toSearch") >= 0) {
          let params = msg.substring(7);
          this.addFrameByName("search", params)
          this.addFrameByName("search", params);
        }
        if (msg.indexOf("toCluster") >= 0) {
          let params = msg.substring(8);
          this.addFrameByName("searchForCluster", params)
          this.addFrameByName("searchForCluster", params);
        }
        if (msg.indexOf("toSetting")>-1) {
          const str = msg.split("?")[1]
          this.addFrameByName("settings", str)
        if (msg.indexOf("toSetting") > -1) {
          const str = msg.split("?")[1];
          this.addFrameByName("settings", str);
        }
        if (msg.indexOf("toVindicate")>-1) {
          const str = msg.split("?")[1]
          this.addFrameByName("vindicate", str)
        if (msg.indexOf("toVindicate") > -1) {
          const str = msg.split("?")[1];
          this.addFrameByName("vindicate", str);
        }
         if (msg.indexOf("toAI")>-1) {
          const str = msg.split("?")[1]
          this.addFrameByName("algorithmManage", str)
        if (msg.indexOf("toAI") > -1) {
          const str = msg.split("?")[1];
          this.addFrameByName("algorithmManage", str);
        }
        if (msg.indexOf("toOpenApp") >= 0) {
          let id = msg.substring(10);
          this.addFrameByID(id)
          this.addFrameByID(id);
        }
        if (msg.indexOf("changeBackground")>-1) {
        const name = e.data.msg.split("?")[1]
        _this.$emit("changeBackground", `/images/desktop/${name}.png`)
      }
        // if (msg.indexOf("refreshDesk")>-1) {
        //   this.getAllSdk();
        // }
          debugger
        if (msg == 'AppUpdate') {
        if (msg.indexOf("changeBackground") > -1) {
          const name = e.data.msg.split("?")[1];
          _this.$emit("changeBackground", `/images/desktop/${name}.png`);
        }
        if (msg == "AppUpdate") {
          this.getAllSdk();
      }
        }
      }
    });
  },
@@ -154,115 +156,116 @@
      size = Math.max(size, 0);
      const len = arr == null ? 0 : arr.length;
      if (!len || size < 1) {
        return []
        return [];
      }
      let index = 0;
      let resIndex = 0;
      const result = new Array(Math.ceil(len / size))
      const result = new Array(Math.ceil(len / size));
      while (index < len) {
        result[resIndex++] = arr.slice(index, index += size)
        result[resIndex++] = arr.slice(index, (index += size));
      }
      return result
      return result;
    },
    onJumpToDock(name){
      let togo
      this.carousels.forEach(arr => {
        arr.forEach(x => {
          if (x.title==name) {
            togo= x
    onJumpToDock(name) {
      let togo;
      this.carousels.forEach((arr) => {
        arr.forEach((x) => {
          if (x.title == name) {
            togo = x;
          }
        });
      });
      this.dockClick(togo)
      this.dockClick(togo);
    },
    getAllSdk() {
      findAllSdk().then(res => {
        this.installedSdk = res.data.filter(item => item.installed)
      }).catch(e => {
        console.log(e)
      })
      findAllSdk()
        .then((res) => {
          this.installedSdk = res.data.filter((item) => item.installed);
        })
        .catch((e) => {
          console.log(e);
        });
    },
    dockClick(dock) {
      if (dock.type === '1') {
      if (dock.type === "1") {
        window.open(dock.url);
      } else if (dock.type === '2' && !dock.isOpen) {
        this.$store.dispatch('desktop/addFrame', {
      } else if (dock.type === "2" && !dock.isOpen) {
        this.$store.dispatch("desktop/addFrame", {
          id: dock.id,
          icon: dock.src,
          title: dock.title,
          url: dock.url
          url: dock.url,
        });
        this.$store.commit('desktop/addMinDock', {
        this.$store.commit("desktop/addMinDock", {
          id: dock.id,
          src: dock.src,
          alt: dock.title,
          type: "3",
          highlight: true,
          url: dock.url,
          screenshot: ''
          screenshot: "",
        });
        //打开应用后异步抓拍,之后的抓拍采用这张固定的
        //if(dock.name=='cameraVideo'||dock.name=='search'||dock.name=='library'||dock.name=='cameraAccess'||dock.name=='dataStack'){
        setTimeout(() => {
          this.$parent.screenShot(dock);
        }, 1500)
        }, 1500);
        //}
      } else if (dock.type === '2' && dock.isOpen) {
        this.$store.commit('desktop/resetMinFrame', dock.id);
      } else if (dock.type === "2" && dock.isOpen) {
        this.$store.commit("desktop/resetMinFrame", dock.id);
      }
    },
    resetDockItem() {
      const dockItems = document.getElementsByClassName('dock-item');
      const dockMask = document.getElementsByClassName('dock-mask')[0];
      const dockItems = document.getElementsByClassName("dock-item");
      const dockMask = document.getElementsByClassName("dock-mask")[0];
      for (let i = 0; i < dockItems.length; i++) {
        dockItems[i].width = 60;
        if (dockItems[i].parentNode.nextElementSibling) {
          dockItems[i].parentNode.nextElementSibling.style.marginLeft = "-35px";
        }
      }
      dockMask.style.width = dockItems.length * 60 + 40 + 'px';
      dockMask.style.width = dockItems.length * 60 + 40 + "px";
    },
    addFrameByName(name, params) {
      let dock = null;
      this.$store.state.desktop.docks.forEach(app => {
      this.$store.state.desktop.docks.forEach((app) => {
        if (app.name === name) {
          dock = app;
        }
      });
      if (dock.isOpen) {
        this.$store.dispatch('desktop/closeFrame', dock);
        this.$store.dispatch("desktop/closeFrame", dock);
      }
      this.$store.dispatch('desktop/addFrame', {
      this.$store.dispatch("desktop/addFrame", {
        id: dock.id,
        icon: dock.src,
        title: dock.title,
        url: dock.url + "?" + params
        url: dock.url + "?" + params,
      });
      this.$store.commit('desktop/addMinDock', {
      this.$store.commit("desktop/addMinDock", {
        id: dock.id,
        src: dock.src,
        alt: dock.title,
        type: "3",
        highlight: true,
        url: dock.url,
        screenshot: ''
        screenshot: "",
      });
    },
    addFrameByID(id, params) {
      let dock = null;
      let toClose = null
      this.$store.state.desktop.docks.forEach(app => {
      let toClose = null;
      this.$store.state.desktop.docks.forEach((app) => {
        if (app.id == id) {
          dock = app;
        }
        if (app.name == "algorithmManage") {
          toClose = app
          toClose = app;
        }
      });
      this.dockClick(dock)
    }
  }
      this.dockClick(dock);
    },
  },
};
</script>
src/pages/gb28181/index/api.ts
@@ -40,14 +40,6 @@
  });
};
export const getLocalCameraTree = (query: any) => {
  return request({
    url: "/data/api-v/area/localmenu",
    method: "get",
    params: query
  });
};
export const getGB28181CameraTree = (query: any) => {
  return request({
    url: "/data/api-v/area/gb28181Tree",
src/pages/index/App.vue
@@ -147,6 +147,7 @@
      })
    },
    async testLogin() {
      // location.assign("/view/desktop/")
      tologin({ username: this.user.loginName, password: this.user.password })
        .then(json => {
          const loginedInfo = {
src/pages/panoramicView/index/App.vue
@@ -15,6 +15,7 @@
        <el-menu-item index="1">位置标定</el-menu-item>
        <el-menu-item index="2" v-show="false">轨迹图</el-menu-item>
        <el-menu-item index="3">关联摄像机</el-menu-item>
        <el-menu-item index="4">视频分析</el-menu-item>
      </el-menu>
    </div>
    <div class="act-view">
@@ -30,6 +31,9 @@
      <template v-if="actMenuIndex=='3'">
        <relate-camera></relate-camera>
      </template>
      <template v-if="actMenuIndex=='4'">
        <relate-camera></relate-camera>
      </template>
    </div>
  </div>
</template>
src/pages/panoramicView/index/main.ts
@@ -4,7 +4,7 @@
import moment from "moment";
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import "@/assets/css/element-variables.scss";
// import "@/assets/css/element-variables.scss";
import VueAwesomeSwiper from "vue-awesome-swiper";
import "swiper/dist/css/swiper.css";
import Mixin from "./mixins";
src/pages/panoramicView/index/mixins.ts
@@ -7,7 +7,6 @@
  data() {
    return {
      TreeDataPool: onlyTreeDataPool
    };
  },
};
src/pages/settings/views/generalSettings.vue
@@ -400,6 +400,7 @@
      return day + "天 " + hour + "小时 " + minute + "分 " + second + "秒";
    },
    uploadSound(params) {
      debugger
      let param = new FormData();
      param.append("file", params.file);
      uploadSound(param).then(
src/pages/syslog/views/eventPushLog.vue
@@ -57,18 +57,20 @@
    <div class="table">
      <el-table
        class="tableBox"
        @cell-click="clickFaults"
        ref="multipleTable"
        :cell-style="styleFunc"
        highlight-current-row
        :data="tableData"
        :header-cell-style="{ background: '#f8f8f8', color: '#222222' }"
        style="width: 100%"
        v-if="!showSubTable"
      >
        <el-table-column :align="'center'" label="序号" type="index" width="50">
        </el-table-column>
        <el-table-column
          :align="'center'"
          sortable
          prop="add_time"
          label="状态"
        ></el-table-column>
@@ -101,6 +103,53 @@
          min-width="100px"
          label="失败总量"
        ></el-table-column>
      </el-table>
      <div class="back" v-if="showSubTable" @click="showSubTable=false">
        <span class="icon iconfont">&#xe680;</span>
        <span class="title">事件推送日志</span>
      </div>
       <el-table
        class="tableBox"
        ref="multipleTable"
        :cell-style="styleFunc"
        highlight-current-row
        :data="subTableData"
        :header-cell-style="{ background: '#f8f8f8', color: '#222222' }"
        style="width: 100%"
        v-if="showSubTable"
      >
        <el-table-column :align="'center'" label="序号" type="index" width="50">
        </el-table-column>
        <el-table-column
          :align="'center'"
          sortable
          prop="add_time"
          label="推送时间"
        ></el-table-column>
        <el-table-column
          sortable
          :align="'center'"
          prop="userName"
          label="推送状态"
        ></el-table-column>
        <el-table-column
          :align="'center'"
          sortable
          prop="module"
          label="详细信息"
        ></el-table-column>
        <el-table-column
          :align="'center'"
          prop="procName"
          label="再次推送时间"
        ></el-table-column>
        <el-table-column
          :align="'center'"
          sortable
          prop="result"
          label="再次推送状态"
        ></el-table-column>
        
      </el-table>
    </div>
@@ -121,15 +170,21 @@
<script>
import { deleteDate } from "@/api/system";
import { pad0 } from "@/api/utils";
import {  } from "@/api/log";
import {} from "@/api/log";
export default {
  data() {
    return {
      loading: false,
      loadingText: "",
      input3: "",
      tableData: [],
      loadingText: "",showSubTable: false,
      tableData: [
        { msg: 2, userName: "车辆识别" },
        { userName: "人脸识别", msg: 4 },
      ],
      subTableData:[
      ],
      dateArr: ["今日", "近三天", "近七天", "近一个月", "近六个月"],
      levelOptions: [],
      hostNameOptions: [],
@@ -166,6 +221,12 @@
    this.getOptions();
  },
  methods: {
    styleFunc({ row, column, rowIndex, columnIndex }) {
      if (columnIndex == 6) {
        return { cursor: "pointer" };
      }
      return {};
    },
    handleSizeChange(val) {
      this.pageSize = val;
      // this.getOperationLog();
@@ -187,6 +248,11 @@
      getModules().then((res) => {
        this.levelOptions = res.data;
      });
    },
    clickFaults(row, column, cell, event) {
      this.showSubTable=true
    },
    choseRange(item, i) {
      switch (item) {
@@ -212,8 +278,8 @@
      this.activeDateChoise = i;
    },
    getOperationLog(typ) {
      if (typ==1) {
        this.page=1
      if (typ == 1) {
        this.page = 1;
      }
      // queryOperationLog({
      //   timeStart: this.timeStart,
@@ -306,6 +372,7 @@
      display: flex;
      margin: 10px 0;
      padding: 0 20px;
      .bar {
        display: flex;
        align-items: baseline;
@@ -325,6 +392,17 @@
    border-radius: 5px;
    padding: 12px;
    background-color: white;
     .back{
            display: flex;
        align-items: center;
        .icon{
          cursor: pointer;  margin:0 5px;font-size: 18px;
        }
        .title{
          cursor: pointer;    line-height: 30px;font-size: 14px;
        }
      }
    .tableBox {
      th {
        padding: 0 !important;
src/pages/syslog/views/operationLog.vue
@@ -202,7 +202,7 @@
    };
  },
  mounted() {
    this.getTimeRange(24 * 60 * 60 * 1000);
    this.getTimeRange();
    this.getOperationLog();
    this.getOptions();
  },
@@ -232,7 +232,7 @@
    choseRange(item, i) {
      switch (item) {
        case "今日":
          this.getTimeRange(24 * 60 * 60 * 1000);
          this.getTimeRange();
          break;
        case "近三天":
          this.getTimeRange(24 * 60 * 60 * 1000 * 3);
@@ -253,8 +253,8 @@
      this.activeDateChoise = i;
    },
    getOperationLog(typ) {
      if (typ==1) {
        this.page=1
      if (typ == 1) {
        this.page = 1;
      }
      queryOperationLog({
        timeStart: this.timeStart,
@@ -279,10 +279,11 @@
      return `${date.getFullYear()}-${month}-${day} ${hour}:${minute}:${second}`;
    },
    getTimeRange(gap) {
      var date = new Date(); //当前时间
      var preDay = new Date(new Date().getTime() - gap);
      var preDay;
      preDay = gap
        ? new Date(new Date().getTime() - gap)
        : new Date(new Date().setHours(0, 0, 0, 0));
      this.timeStart = this.getTimeStr(preDay);
      this.timeEnd = this.getTimeStr(date);
    },
  },
};
src/pages/vindicate/index/App.vue
@@ -14,28 +14,29 @@
    </div>
    <systemClean v-if="activePage == 1" style="width: 100%" :free="free" :full="full" @refreshPercent="getLeftPer"></systemClean>
    <updateSettings v-if="activePage == 0" style="width: 100%"></updateSettings>
    <back-up v-if="activePage == 3" style="width: 100%"></back-up>
    <!-- <back-up v-if="activePage == 3" style="width: 100%"></back-up> -->
    <restartSettings v-if="activePage == 2" style="width: 100%"></restartSettings>
    <sysInfo v-if="activePage == 3" style="width: 100%"></sysInfo>
  </div>
</template>
<script>
import {
  getClockInfo,
  saveClockInfo,
  testNTPserver,freedisk
  freedisk
} from "@/api/system";
import { getUrlKey } from "@/api/utils";
import systemClean from "../views/systemClean";
import updateSettings from "../views/updateSettings";
import BackUp from "../views/backUp";
import restartSettings from "../views/restartSettings";
import sysInfo from "../views/sysInfo";
export default {
  name: "settings",
  components: {
    systemClean,
    updateSettings,
    BackUp,
    restartSettings,
    restartSettings,sysInfo
  },
  data() {
    return {
@@ -44,6 +45,7 @@
        // { name: "备份还原",icon:""  },
        { name: "系统清理" ,icon:"\uea3b" },
        { name: "重启设置" ,icon:"\ue709" },
        { name: "系统信息" ,icon:"\ue709" },
      ],
      activePage: 0,
      free: 0,
@@ -51,7 +53,13 @@
    };
  },
  mounted() {
    const menu = getUrlKey("menu");
    if (menu) {
      this.activePage = this.menuArr.findIndex((x) => x.name == menu);
      // this.$nextTick(() => {
      //   this.$refs.netSettings.openRight(2);
      // });
    }
     this.getLeftPer()
  },
  methods: {
src/pages/vindicate/views/sysInfo.vue
New file
@@ -0,0 +1,341 @@
<template>
  <div class="v-sys-info">
    <div class="sys-content">
      <div class="sys-right">
        <div class="auto">
          <div class="title-bg">
            <div class="title">SmartAIOS</div>
            <div class="desc">Copyright © 贝思科技术有限公司</div>
          </div>
          <div class="bar">
            <div class="name">版本:</div>
            <div class="desc">{{ verText }}</div>
          </div>
          <div class="bar">
            <div class="name">激活:</div>
            <div class="right-zone">
              <el-button type="primary" size="small" @click="confirmAgain"
                >导出产品密钥</el-button
              >
              <div class="desc" style="color: rgba(71, 153, 247, 1)">
                {{ sn == "" ? "未激活" : "已激活" }}
              </div>
            </div>
          </div>
          <div class="bar">
            <div class="name">请求码:</div>
            <div class="desc" style="font-size: 12px">{{ q }}</div>
          </div>
          <div class="bar">
            <div class="name">产品密钥:</div>
            <div class="desc" style="font-size: 12px">{{ authorization }}</div>
          </div>
          <div class="bar">
            <div class="name">到期时间:</div>
            <div class="desc">{{ expireTime }}</div>
          </div>
        </div>
      </div>
    </div>
    <el-dialog title="再次确认" :visible.sync="dialogVisible">
      <div class="ver">
        <span class="icon iconfont" style="color: orangered">&#xe6e6;</span>
        产品密钥导出后,系统大部分功能将无法使用,请确认是否继续?
      </div>
      <div class="info">
        如需继续,请输入管理员密码,并导入你想要激活的设备请求码,然后点击“确认”。
        <span style="color: #8f949a; font-size: 14px"
          >设备请求码获取方式:如系统已激活,在激活页面导出即可;如设备未激活,在SmartAI激活页面扫码获取。</span
        >
      </div>
      <!--  -->
      <div class="pw">
        <el-input
          size="small"
          placeholder="请输入管理员密码"
          v-model="password"
          style="padding-left: 50px; width: 360px"
        ></el-input>
      </div>
      <div class="validate">
        <form id="myForm">
          <el-input
            type="textarea"
            autosize
            style="width: 360px"
            placeholder="将产品密钥粘贴在此处"
            v-model="secrectKey"
          >
          </el-input>
        </form>
        <!-- <el-upload
          class="upload-demo"
          action
          :http-request="uploadKey"
          :limit="1"
          :show-file-list="false"
        >
        </el-upload> -->
          <el-button size="small" @click="txtbtn" type="primary">导入文件</el-button>
        <input type="file" @change="loadTextFromFile" id="txt" style="display:none"/>
      </div>
      <span slot="footer" class="dialog-footer">
        <el-button @click="dialogVisible = false">取消</el-button>
        <el-button type="primary" @click="confirmCancel">确定</el-button>
      </span>
    </el-dialog>
  </div>
</template>
<script>
import { getSN, cancelAuthorization } from "@/api/system";
export default {
  mounted() {
    getSN().then((res) => {
      if (res.code == 200) {
        this.authorization = res.data.authorization;
        this.expireTime = res.data.expireTime;
        this.sn = res.data.sn;
        this.q = res.data.q;
      }
    });
  },
  data() {
    return {
      authorization: "",
      expireTime: "",
      sn: "",
      secrectKey: "",
      q: "",
      verText: "SmartAIOS正式版",
      activeState: "已激活",
      password: "",
      dialogVisible: false,
    };
  },
  methods: {
    confirmAgain() {
      // this.$confirm("您是否确认立即备份所有应用的配置数据?", "立即备份", {
      //   confirmButtonText: "确定",
      //   cancelButtonText: "取消",
      // }).then(() => {
      //   this.$message({
      //     type: "success",
      //     message: "备份成功",
      //   });
      // });
      this.dialogVisible = true;
    },
     txtbtn() {
      document.getElementById("txt").click();
    },
    loadTextFromFile(e) {
      const file = e.target.files[0];
      var reader = new FileReader(); //new一个FileReader实例
      let that = this
      reader.onload = function () {
        debugger
        that.secrectKey = this.result.trim()
        console.log(this.result);
      };
      reader.readAsText(file);
    },
    confirmCancel() {
      this.secrectKey = this.secrectKey.trim();
      this.password = this.password.trim();
      if (this.secrectKey == "" || this.password == "") {
        this.$message.warning("请先填写密码和请求码");
        return;
      }
      cancelAuthorization({
        q: this.secrectKey,
        passwd: this.password,
        down: 1,
      }).then((res) => {
        debugger;
        let url = window.URL.createObjectURL(
          new Blob([res], {
            type: "text/plain",
          })
        );
        let a = document.createElement("a");
        a.href = url;
        a.download = "key.txt";
        a.click();
        window.URL.revokeObjectURL(url);
      });
    },
  },
};
</script>
<style lang="scss">
.v-sys-info {
  width: 100%;
  .el-dialog__header {
    padding: 15px 20px 10px;
    text-align: left;
    font-weight: 600;
  }
  .el-dialog__body {
    text-align: left;
    padding: 0;
    padding-bottom: 10px;
  }
  .el-divider--horizontal {
    margin: 20px 0;
  }
  .validate {
    padding: 0 50px;
    display: flex;
    align-items: baseline;
    margin-top: 15px;
  }
  #myForm {
    display: flex;
    align-items: center;
    margin-right: 10px;
    .single-input {
      margin: 0 8px;
      width: 60px;
    }
  }
  .ver {
    margin-bottom: 10px;
    background-color: rgba(242, 242, 242, 1);
    font-size: 16px;
    height: 60px;
    padding-left: 50px;
    line-height: 60px;
    .ver-text {
      font-weight: 600;
    }
  }
  .info {
    padding: 0 50px;
    font-size: 15px;
    line-height: 25px;
    margin: 15px 0;
  }
  .qr-code-img {
    width: 100px;
    height: 100px;
  }
  .ask {
    margin-top: 20px;
    font-size: 15px;
  }
}
.sys-content {
  height: 100%;
  display: flex;
  flex-direction: row;
  flex: 1;
  flex-basis: auto;
  box-sizing: border-box;
  .sys-right {
    flex: 1;
    flex-basis: auto;
    overflow: auto;
    box-sizing: border-box;
    position: relative;
    padding: 20px 40px;
    .el-form-item.is-required:not(.is-no-asterisk)
      > .el-form-item__label:before,
    .el-form-item.is-required:not(.is-no-asterisk)
      .el-form-item__label-wrap
      > .el-form-item__label:before {
      display: none;
    }
    .el-select {
      width: 100%;
    }
    .el-form-item {
      margin-bottom: 10px;
      height: 50px;
      background: #f8f8f8;
      padding: 4px 20px;
      -webkit-box-sizing: border-box;
      box-sizing: border-box;
      border-radius: 10px;
      .el-form-item__label {
        text-align: left;
        line-height: 42px;
      }
    }
    .el-form-item__content {
      line-height: 40px;
      position: relative;
      font-size: 14px;
    }
    .ip-input-container {
      max-width: none !important;
    }
    .auto {
      .title-bg {
        background-color: #f8f8f8;
        height: 150px;
        border-radius: 12px;
        margin-bottom: 20px;
        display: flex;
        flex-direction: column;
        justify-content: center;
        .title {
          font-size: 34px;
          font-weight: 600;
          line-height: 50px;
        }
        .desc {
          font-size: 16px;
          line-height: 30px;
        }
      }
      .bar {
        display: flex;
        align-items: center;
        padding: 12px 25px;
        background-color: #f8f8f8;
        justify-content: space-between;
        border-radius: 12px;
        margin-bottom: 10px;
        .right-zone {
          display: flex;
          align-items: center;
        }
        .name {
          font-size: 15px;
          text-align: left;
          min-width: 180px;
        }
        .desc {
          font-size: 15px;
          margin-left: 20px;
          max-width: 600px;
          /* overflow: hidden; */
          /* text-overflow: ellipsis; */
          /* white-space: nowrap; */
          line-height: normal;
          word-wrap: break-word;
          text-align: left;
        }
        .el-input {
          width: 100%;
          .el-input {
            height: auto;
          }
          .el-input__inner {
            border: none;
            border-radius: 8px;
            background-color: rgba(240, 240, 240, 1);
            text-align: left;
          }
        }
      }
    }
  }
}
</style>
src/pages/vindicate/views/updateSettings.vue
@@ -192,11 +192,6 @@
    if (isAutoUpdate==1) {
      this.checking = false
      this.upgradeNewVersion()
      // this.showWelcome = false;
      // this.activeIndex = this.menuArr.findIndex((x) => x.name == menu);
      // this.$nextTick(() => {
      //   this.$refs.netSettings.openRight(2);
      // });
    }else{
      this.fetchUpgradInfo();
    }
src/pages/visual/components/player/wfs/controller/buffer-controller.js
@@ -74,7 +74,7 @@
  }
  onMediaSourceClose() {
    console.log('media source closed');
    // console.log('media source closed');
  }
  onMediaSourceEnded() {
src/pages/visual/components/player/wfs/loader/websocket-loader.js
@@ -35,7 +35,7 @@
      this.client = data.websocket
      this.client.onopen = this.initSocketClient.bind(this)
      this.client.onclose = function (e) {
        console.log('Websocket Disconnected!')
        // console.log('Websocket Disconnected!')
      }
    }
  }