src/Pool/TreeData.ts | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/components/LeftNav.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/components/giantTree/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/components/giantTree/zTree/ztree.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/pages/gb28181/index/App.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/pages/gb28181/index/api.ts | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/pages/gb28181/index/main.ts | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
src/Pool/TreeData.ts
@@ -8,10 +8,11 @@ refreshGB28181Tree, updateCameraArea } from '@/api/area' import { findAllFile, show, changeEnable } from '@/api/localVedio' export default class TreeDataPool { public openeds: Array<boolean> public activeTreeData: Array<object> public treeData: Array<object> public clusterData: Array<object> public gb28181Data: Array<object> @@ -37,20 +38,6 @@ public foldNodeList: object //记录左侧tab:activeName public treeActiveName: string //本地视频:视频分析处理 public vedioAnaliyseSwitch: boolean //本地视频列表 public localVedioList: Array<any> //本地视频当前页 public localCurrentPage: number //本地视频每页查询20条 public localPageSize: number //本地视频总条数 public localTotal: number //勾选的本地视频 public checkedLocalVedio: Array<any> //当前选中的本地视频 public clickLocalVideo: object //控制开始、暂停按钮显示状态 public btnStaus: string //本地视频类型 @@ -60,10 +47,19 @@ //记录复制的摄像机name public ctrlCameraName: string // 是否使用ztree public zTree: boolean public checkedTreeNode: Array<object> // 选中的摄像机个数 public gb28181CheckedCount: number // 总摄像机个数 public gb28181ChildNodeCount: number constructor() { this.openeds = [true, true, false] this.activeTreeData = [] this.treeData = [] this.gb28181Data = [] this.clusterData = [] @@ -84,20 +80,17 @@ this.selectedNode = {} this.treeType = '' this.foldNodeList = {} this.vedioAnaliyseSwitch = false this.treeActiveName = 'camera' this.searchLocalType = 0 this.localVedioList = [] this.checkedLocalVedio = [] this.clickLocalVideo = {} //1:暂停状态;2:等待状态;3:置灰 this.btnStaus = '3' this.localCurrentPage = 1 this.localPageSize = 20 this.localTotal = 0 this.ctrlCameraId = '' this.ctrlCameraName = '' this.zTree = false this.checkedTreeNode = [] this.gb28181CheckedCount = 0 this.gb28181ChildNodeCount = 0 } setVideoArr(index: number, value: object, vue: any): void { @@ -261,8 +254,6 @@ this.isFold(this.gb28181Data) this.selectedNodes = [] this.selectedNode = {} this.cleanLocalVedio() } cleanTree(tree) { @@ -397,8 +388,6 @@ if (this.openeds[1]) { this.fetchGbTree() } this.findAllFile({}) } async add(name: string, parent: string) { @@ -434,109 +423,84 @@ // this.fetchGbTree() } async findAllFile(params: any) { ; (params.fileName = this.searchInput), (params.type = this.searchLocalType) params.page = this.localCurrentPage params.size = this.localPageSize let res: any = await findAllFile(params) if (res && res.success) { let list = res.data.dataList.map(i => { let obj: any = {} Object.assign(obj, i) if (i.ruleType == 0) { obj.iconStatus2 = '0' } else { obj.iconStatus2 = '1' } if (!i.snapshot_url) { // obj.snapshot_url = require('@/assets/nobody.png') obj.snapshot_url = '' } else { obj.snapshot_url = '/httpImage/' + obj.snapshot_url } if (i.is_running) { obj.iconStatus1 = '1' } else if (i.progress == 100) { obj.iconStatus1 = '2' } else if (i.status == 1 && i.progress == 0 && i.hasRule) { obj.iconStatus1 = '3' } else if (!i.hasRule && i.progress == 0) { obj.iconStatus1 = '4' } obj.checkStatus = false obj.clickStatus = false obj.showCheckBox = false return obj }) this.localVedioList = list this.localTotal = res.data.total // console.log(this.localVedioList,this.searchInput,'本地视频列表') } } async show() { let res: any = await show() if (res && res.success) { this.vedioAnaliyseSwitch = res.data.videoEnable } } async changeEnable() { let res: any = await changeEnable({ enable: this.vedioAnaliyseSwitch }) } getCheckedFiles() { this.checkedLocalVedio = this.localVedioList.filter(i => { return i.checkStatus }) this.clickLocalVideo = this.localVedioList.filter(i => { return i.clickStatus })[0] if (this.checkedLocalVedio.length === 0) { this.btnStaus = '3' return false } this.checkedLocalVedio.every((i, index) => { let t = '' if (i.status == 0 && i.hasRule) { t = '1' } else if (i.status == 1 && i.hasRule && !i.is_running) { t = '2' } else { t = '3' } if (index == 0) { this.btnStaus = t } else { if (this.btnStaus !== t) { this.btnStaus = '3' return false } } }) } filterLocalVideoWell() { if (this.localVedioList.length !== 0) { this.localVedioList = this.localVedioList.filter(i => { return i.progress == 100 }) } } cleanLocalVedio() { this.localVedioList.map(i => { i.checkStatus = false i.clickStatus = false }) this.checkedLocalVedio = [] this.btnStaus = '3' } async dropNode(cameraId, areaId) { async dropNode(cameraId: string, areaId: string) { await updateCameraArea({ cameraId: cameraId, areaId: areaId }) } getAllChildrenNodes(treeNode, arr) { for (var i = 0; i < treeNode.length; i++) { var sonList = treeNode[i].children; if (!sonList) { if (treeNode[i].type == "camera") { arr.push(treeNode[i]); if (treeNode[i].checked) { this.gb28181CheckedCount += 1; } } } else { this.getAllChildrenNodes(sonList, arr); } } return arr; } countChildrenNodes(treeNode) { let arry = [] this.getAllChildrenNodes(treeNode, arry) return arry.length } async fetchVideosvrCameras() { const rsp: any = await refreshGB28181Tree() if (rsp && rsp.success) { this.selectedNode = {} this.treeData = rsp.data ? rsp.data : [] if (this.treeData && this.treeData.length > 0) { this.sortTreeData(this.treeData) } // 设置禁止拖拽摄像机到摄像机节点 this.setDropDisable(this.treeData) this.isFold(this.treeData) this.activeTreeData = this.treeData this.gb28181CheckedCount = 0; this.gb28181ChildNodeCount = this.countChildrenNodes(this.treeData) } } removeNoCheckedNode(nodes: Array<any>) { for (let i = 0; i < nodes.length;) { if (!nodes[i].checked) { nodes.splice(i, 1) continue } if (nodes[i].children && nodes[i].children.length) { this.removeNoCheckedNode(nodes[i].children) } i++ } } countCheckedNodes(nodes: Array<any>) { let count = 0 nodes.forEach(n => { if (n.type == "camera") { count++ } }) this.gb28181CheckedCount = count } newTreeByChecked(nodes: Array<object>) { let newTree = JSON.parse(JSON.stringify(nodes)) this.removeNoCheckedNode(newTree) return newTree } } src/components/LeftNav.vue
@@ -123,14 +123,14 @@ </template> <!-- 国标刷新图标 --> <div class="tree-edit gb-refresh" v-show="!TreeDataPool.gbReadonly"> <!-- <div class="tree-edit gb-refresh" v-show="!TreeDataPool.gbReadonly"> <el-tooltip content="刷新" placement="top" popper-class="atooltip"> <button @click="refreshGB"> <i v-if="loadingGBTree" class="el-icon-loading" style="font-size:16px"></i> <i v-else class="el-icon-refresh" style="font-size:16px"></i> </button> </el-tooltip> </div> </div>--> <div class="tree-edit gb-lock" v-show="showLock"> <button @click="gbLockSwitch"> <i v-if="TreeDataPool.gbReadonly" class="el-icon-lock" style="font-size:16px"></i> src/components/giantTree/index.vue
@@ -5,6 +5,7 @@ :show-checkbox="TreeDataPool.multiple" :readonly="TreeDataPool.readonly" :gb28181="gb28181" :setting="setting" @onCreated="handleCreated" @onClick="itemClick" @onCheck="itemCheck" @@ -66,7 +67,14 @@ height: { type: Number, default: 0 } }, setting: { type: Object, require: false, default: function () { return {}; }, }, }, data() { return { @@ -117,13 +125,10 @@ //摄像机信息更新信息后,如果节点位置有变tId就不准了,this.TreeDataPool.selectedNode此时还是旧的信息 let ztreeNodes = ztreeObj.getNodes(); //var curNodeTid = ''; console.log(ztreeNodes) _this.findTidByIdFromArr(ztreeNodes); console.log('curNodeTid', _this.curNodeTid) this.TreeDataPool.selectedNode.tId = _this.curNodeTid; let node = this.ztreeObj.getNodeByTId(this.TreeDataPool.selectedNode.tId) console.log('selecBode', this.TreeDataPool.selectedNode) console.log('selectedNode.tId', this.TreeDataPool.selectedNode.tId) // 多选时, 选中单选单击的节点 if (this.TreeDataPool.multiple) { this.ztreeObj.checkAllNodes(false); @@ -266,7 +271,6 @@ this.showDialog = true; }, itemClick(evt, treeId, treeNode) { console.log(evt, treeId) this.TreeDataPool.selectedNode = treeNode; this.TreeDataPool.treeType = this.treeName; @@ -301,6 +305,12 @@ // this.ztreeObj.checkNode(treeNode, true, false, false); let checkedNodes = this.ztreeObj.getCheckedNodes(true); this.TreeDataPool.updateZTreeCheckNodes(checkedNodes); // 实时统计选中个数 this.TreeDataPool.countCheckedNodes(checkedNodes); // 保存一份数据 this.TreeDataPool.activeTreeData = this.ztreeObj.getNodes() }, //展开 itemExpand(e, id, node) { src/components/giantTree/zTree/ztree.vue
@@ -112,7 +112,6 @@ Object.assign({}, this.ztreeSetting, this.setting), this.list ); console.log('onCreated,ztr') this.$emit("onCreated", this.ztreeObj); }); }, src/pages/gb28181/index/App.vue
@@ -1,20 +1,15 @@ <template> <div class="s-basic-setting" @contextmenu.prevent="toOpenMenuList"> <el-menu :default-openeds="openeds" background-color="#fff" text-color="#303133" active-text-color="#409EFF" style="height: 100%;" class="menu-css" @open="menuOpen" @close="menuClose" <div class="s-system-manage"> <div class="s-basic-setting"> <el-tabs id="e-basic-setting" v-model="activeName" v-loading="loading" :element-loading-text="loadingText" type="border-card" @tab-click="hanleTabClick" > <el-submenu index="0"> <template slot="title"> <b class="tree-font">国际ID</b> </template> <el-menu-item-group class="item-group"> <el-tab-pane label="国标ID" name="gb28181"> <!-- GB28181设置 --> <el-form :model="gb28181" @@ -115,16 +110,11 @@ <el-button type="primary" @click="submitGB28281" size="small">保存</el-button> </el-form-item> </el-form> </el-menu-item-group> </el-submenu> <el-submenu index="1"> <template slot="title"> <b class="tree-font">接入平台列表</b> </template> <el-menu-item-group class="item-group"> <div> </el-tab-pane> <el-tab-pane label="接入平台列表" name="subordinates"> <el-table :data="tableList" :data="subDevTable" border fit highlight-current-row @@ -133,27 +123,47 @@ > <el-table-column type="index" label="序号" align="center" width="50"></el-table-column> <el-table-column prop="name" label="名称" align="center"></el-table-column> <el-table-column prop="id" label="ID" align="center"></el-table-column> <el-table-column prop="publicid" label="ID" align="center"></el-table-column> <el-table-column prop="ip" label="IP" align="center"></el-table-column> <el-table-column prop="status" label="状态" align="center"></el-table-column> <el-table-column prop="status" label="状态" align="center"> <template slot-scope="scope"> <span :style="scope.row.active ? `color:#047d19` : 'color:#f11a1a;' " >{{scope.row.active ? "在线": "离线"}}</span> </template> </el-table-column> <el-table-column prop="mark" label="备注" align="center"></el-table-column> </el-table> </el-tab-pane> <el-tab-pane label="国标摄像机" name="cameras"> <div style="text-align:left"> <el-button type="primary" size="small" @click="getCamerasFromVideosvr">刷新</el-button> </div> </el-menu-item-group> </el-submenu> <el-submenu index="2"> <template slot="title"> <b class="tree-font">国际摄像机</b> </template> <el-menu-item-group class="item-group"> <div> <div> <el-button type="primary" size="small">刷新</el-button> <div class="camera-title"> <b>国标摄像机配置</b> <span>(最多勾选500路摄像机)</span> </div> <tree-menu ref="tree" app="gb28181" treeName="localTree" :node="TreeDataPool.treeData" :height="treeHeight" :setting="treeSettings" /> <el-divider></el-divider> <span class="camera-seleted-text"> 已选择 ( <b>{{TreeDataPool.gb28181CheckedCount}}</b> / {{TreeDataPool.gb28181ChildNodeCount}} ) 路 </span> <el-button type="primary" size="small" @click="saveChecked">保存</el-button> </el-tab-pane> </el-tabs> </div> </el-menu-item-group> </el-submenu> </el-menu> </div> </template> @@ -162,13 +172,20 @@ getGB28181Config, saveGB28181Config, getGb28181AreaList, newGb28181ID newGb28181ID, getLocalCameraTree, getAllSubServer, saveGb28181CamTree } from './api' import TreeMenu from "@/components/giantTree/index"; import { isPort, isIPv4 } from '@/scripts/validate' import bus from '@/plugin/bus' export default { name: 'Gb28181Setting', components: { TreeMenu }, directives: { focus: { inserted: function (el) { @@ -179,10 +196,19 @@ data() { return { activeName: "gb28181", treeHeight: 750, loading: false, loadingText: "", openeds: ['0'], gb28181: {}, tableList: [], subDevTable: [], idType: 1, treeSettings: { check: { enable: true } }, rules: { ip: [ { @@ -228,12 +254,59 @@ } }, mounted() { this.TreeDataPool.multiple = true; //this.$nextTick(()=>{ this.initGB28181Conf() //}) this.initGB28181Conf(); }, methods: { hanleTabClick(tab, event) { if (this.activeName == "subordinates") { getAllSubServer().then(rsp => { if (rsp && rsp.success) { this.subDevTable = rsp.data; } }) } else if (this.activeName == "cameras") { this.getCamerasFromVideosvr(); } }, async getCamerasFromVideosvr() { this.loading = true; await this.TreeDataPool.fetchVideosvrCameras(); this.loading = false; }, saveChecked() { if (this.TreeDataPool.gb28181CheckedCount > 500) { this.$message({ type: "warning", message: "最多仅支持选择500路摄像机. 请重新选择" }) return; } this.loading = true; let treeData = this.TreeDataPool.newTreeByChecked(this.TreeDataPool.activeTreeData) saveGb28181CamTree({ checkedMenus: treeData }).then(rsp => { if (rsp && rsp.success) { this.$message({ type: "success", message: "保存成功" }) } this.loading = false; }).catch(err => { this.$message({ type: "error", message: "保存失败" }) this.loading = false; }) }, initGB28181Conf() { getGB28181Config().then(rsp => { if (rsp && rsp.success) { @@ -311,236 +384,119 @@ } </script> <style lang="scss"> .s-basic-setting { .s-system-manage { width: 100% !important; min-width: 1067px; height: 100%; padding: 20px; box-sizing: border-box; .item-group { padding: 0 15px; margin-bottom: 15px; } .el-form { .el-form-item { text-align: left; margin-bottom: 16px; &:last-of-type { width: 490px; } .el-button { float: right; } .el-select { margin-right: 10px; } .el-form-item__content { text-align: left; input { max-width: 360px; } .el-date-editor.el-input, .el-date-editor.el-input__inner { width: 216px; } .el-checkbox__label { padding-left: 5px; } padding: 10px; background-color: #f8f9fb; .s-system-manage-breadcrumb { height: 5%; box-sizing: border-box; border: 1px solid #e4e7ed; box-shadow: #e4e7ed 0px 0px 9px inset; box-shadow: #e4e7ed 0px 0px 9px inset; border-radius: 5px; } .el-form-item__label { text-align: left; } &.el-form-item.is-required:not(.is-no-asterisk) > .el-form-item__label:before { margin-left: -9px; } } } .alarmSetting { .el-input { width: 100%; // padding-right: 10px; } .el-select { max-width: 113px; } .el-slider { width: calc(100% - 120px); display: inline-block; padding-right: 30px; box-sizing: border-box; vertical-align: middle; } .el-input-number { width: 100px; display: inline-block; .el-input { width: 100%; } } } .time-type { height: 25px; width: 413px; line-height: 28px; padding: 3px 23px; font-size: 14px; font-weight: 600; background-color: #e4e6ed; } #e-basic-setting { .el-tabs--border-card { border: 0px solid #dcdfe6; -webkit-box-shadow: none; box-shadow: none; .el-tabs__header { border: 0px solid #dcdfe6; .el-tabs__item { padding: 5px 50px; height: 50px; font-family: PingFangSC-Regular; font-size: 14px; font-size: 15px; color: #222222; text-align: center; border: 0px solid transparent; } .el-tabs__item:nth-child(2) { padding-left: 50px; padding-left: 50px !important; } .el-tabs__item:last-child { padding-right: 50px; padding-right: 50px !important; } .el-tabs__item.is-active { color: #ff7733; font-weight: bold; color: #3d68e1; // border-right-color: #fff; // border-left-color: #fff; } .el-tabs__item:not(.is-disabled):hover { color: #ff7733; color: #3d68e1; } } .el-tabs__active-bar { background-color: #ff7733; } .xiangqin-label { text-align: left; width: 85px; font-size: 14px; line-height: 30px; .el-tabs__header { margin-bottom: 0; } .xiangqing-info { text-align: left; font-size: 14px; line-height: 30px; } } #cut_min_duration { .el-slider__bar { background-color: #3d68e1; } .el-slider__button { width: 10px; height: 10px; border: 4px solid #3d68e1; } } #cut_max_duration { .el-slider__bar { background-color: #ff9e6e; } .el-slider__button { width: 10px; height: 10px; border: 4px solid #ff9e6e; } } .menu-css, .el-menu { border-right: none; list-style: none; position: relative; margin: 0; padding-left: 0; background-color: #ffffff; .el-submenu__title { height: 35px; line-height: 35px; font-size: 14px; color: #303133; padding: 0 20px; list-style: none; cursor: pointer; position: relative; -webkit-transition: border-color 0.3s, background-color 0.3s, color 0.3s; transition: border-color 0.3s, background-color 0.3s, color 0.3s; -webkit-box-sizing: border-box; .el-tabs__content { height: calc(100% - 64px); box-sizing: border-box; white-space: nowrap; } .tree-font { font-family: PingFangSC-Medium; font-size: 14px; color: #222222; overflow-y: auto; padding: 20px 40px !important; background: #fff; .el-tab-pane { width: 100%; .s-title { text-align: left; } li { text-align: left; .el-submenu__title { // border-bottom: solid 1px #e6e6e6; padding-left: 10px !important; background-color: #e4e6ed !important; border-radius: 2px; .el-submenu__icon-arrow { position: absolute; top: 50%; right: auto; left: 135px; margin-top: -7px; -webkit-transition: -webkit-transform 0.3s; transition: -webkit-transform 0.3s; transition: transform 0.3s; transition: transform 0.3s, -webkit-transform 0.3s; font-size: 12px; padding: 15px 0px; font-size: 16px; } } } } .save-btn { text-align: right; position: relative; right: 40px; } } </style> <style lang="scss" scoped> .menu-css, .el-menu { border-right: none; list-style: none; position: relative; margin: 0; padding-left: 0; background-color: #ffffff; .tree-font { font-family: PingFangSC-Medium; font-size: 14px; color: #222222; text-align: left; .s-table { border: 1px solid #e8e8e9; margin-top: 40px; } li { .ui-top-title { padding-bottom: 10px; /* border-bottom: 1px solid #ebebeb; */ position: relative; text-align: left; .el-submenu__title { .el-submenu__icon-arrow { padding-left: 15px; font-size: 16px; font-weight: bold; } .ui-top-title:before { content: " "; border-left: 4px solid #f53d3d; display: inline-block; height: 16px; position: absolute; top: 50%; right: 0; margin-top: -7px; -webkit-transition: -webkit-transform 0.3s; transition: -webkit-transform 0.3s; transition: transform 0.3s; transition: transform 0.3s, -webkit-transform 0.3s; font-size: 12px; left: 0; margin-top: -13px; } .el-button--text { color: #3d68e1; text-decoration: underline; } .camera-title { text-align: left; padding: 0px 10px; margin: 5px 0px; height: 33px; background-color: #e4e2e2; line-height: 33px; font-size: 14px; } .camera-seleted-text { margin-right: 20px; .b { color: #3d68e1; } } } src/pages/gb28181/index/api.ts
@@ -24,6 +24,14 @@ }); }; export const getAllSubServer = (query: any) => { return request({ url: "/data/api-v/gb28181/getAllSubServer", method: "get", params: query }); }; export const newGb28181ID = (query: any) => { return request({ url: "/data/api-v/gb28181/newGbId", @@ -31,3 +39,34 @@ params: query }); }; 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", method: "get", params: query }); }; export const refreshGB28181Tree = () => { return request({ url: "/data/api-v/area/gb28181RefreshTree", method: "post", }); }; export const saveGb28181CamTree = (query: any) => { return request({ url: "/data/api-v/gb28181/saveGb28181CamTree", method: "post", data: query }); }; src/pages/gb28181/index/main.ts
@@ -1,11 +1,25 @@ import Vue from 'vue'; import App from './App.vue'; import TreeDataPool from "@/Pool/TreeData"; import ElementUI from 'element-ui'; import 'element-ui/lib/theme-chalk/index.css'; import "@/assets/css/element-variables.scss"; Vue.use(ElementUI) const onlyTreeDataPool = new TreeDataPool const mixin = { data() { return { TreeDataPool: onlyTreeDataPool }; }, }; Vue.mixin(mixin); new Vue({ el: '#app', render: h => h(App)