From e044cb7dedd0c171e6a38bed486bf46c8f8c58bb Mon Sep 17 00:00:00 2001 From: hanbaoshan <hanbaoshan@aiotlink.com> Date: 星期三, 23 十二月 2020 15:20:36 +0800 Subject: [PATCH] 长春全景追踪应用更新(添加轨迹图查询,布局结构更新),场景轮播图算法图标不显示问题修复 --- src/pages/panoramicView/components/LabelMark.vue | 665 ++++++++++++++++++++ src/pages/labelMark/components/RightSide.vue | 122 +-- src/pages/panoramicView/index/App.vue | 95 ++ src/pages/labelMark/components/SlideCanvas.vue | 9 src/pages/panoramicView/components/RelateCamera.vue | 542 ++++++++++++++++ src/pages/panoramicView/components/SlideCanvas.vue | 231 +++++++ src/pages/panoramicView/index/main.ts | 19 public/apps.json | 23 src/api/panorama.ts | 12 src/pages/cameraAccess/components/scene/SlideScene.vue | 6 src/pages/panoramicView/index/mixins.ts | 14 src/pages/panoramicView/components/TracePlot.vue | 153 ++++ 12 files changed, 1,805 insertions(+), 86 deletions(-) diff --git a/public/apps.json b/public/apps.json index 7e5d3b6..3467881 100644 --- a/public/apps.json +++ b/public/apps.json @@ -391,6 +391,29 @@ "installed": true, "isUpgrade": false, "progressMsg": "" + }, + { + "id": "fa5674ee-70cf-4e22-8a06-c17429fbb70b", + "name": "鍏ㄦ櫙杩借釜", + "package": "panoramicView", + "type": "1", + "url": "/view/panoramicView/", + "title": "鍏ㄦ櫙杩借釜", + "width": 1500, + "height": 750, + "iconBlob": "", + "icon": "../../images/app-mid/360.png", + "version": "1.0.0", + "create_time": "2020-10-09 14:00:08", + "create_by": "", + "update_time": "", + "update_by": "", + "isDelete": 0, + "isDefault": false, + "remoteVersion": "", + "installed": true, + "isUpgrade": false, + "progressMsg": "" } ], "msg": "璇锋眰澶勭悊鎴愬姛", diff --git a/src/api/panorama.ts b/src/api/panorama.ts new file mode 100644 index 0000000..e8a897e --- /dev/null +++ b/src/api/panorama.ts @@ -0,0 +1,12 @@ +import request from '@/scripts/httpRequest'; +import qs from 'qs' +export const getPanoramaPic = ()=>request({ + url: '/data/api-v/panorama/show', + method: 'get' +}); + +export const putPanoramaPic = (data:any)=>request({ + url:'/data/api-v/panorama/upload', + method:'post', + data +}) \ No newline at end of file diff --git a/src/pages/cameraAccess/components/scene/SlideScene.vue b/src/pages/cameraAccess/components/scene/SlideScene.vue index ee755f0..969aae5 100644 --- a/src/pages/cameraAccess/components/scene/SlideScene.vue +++ b/src/pages/cameraAccess/components/scene/SlideScene.vue @@ -30,7 +30,7 @@ </svg>--> <img class="baseImg" - :src="item.rules[0].icon_blob &&item.rules[0].icon_blob.indexOf(',')>0?item.rules[0].icon_blob:`data:image/png;base64,${rule.icon_blob}`" + :src="item.rules[index].icon_blob &&item.rules[index].icon_blob.indexOf(',')>0?item.rules[index].icon_blob:`data:image/png;base64,${rule.icon_blob}`" alt /> </div> @@ -42,7 +42,7 @@ </svg>--> <img class="baseImg" - :src="item.rules[0].icon_blob &&item.rules[0].icon_blob.indexOf(',')>0?item.rules[0].icon_blob:`data:image/png;base64,${rule.icon_blob}`" + :src="item.rules[index].icon_blob &&item.rules[index].icon_blob.indexOf(',')>0?item.rules[index].icon_blob:`data:image/png;base64,${rule.icon_blob}`" alt /> </div> @@ -54,7 +54,7 @@ </svg>--> <img class="baseImg" - :src="item.rules[0].icon_blob && item.rules[0].icon_blob.indexOf(',')>0?item.rules[0].icon_blob:`data:image/png;base64,${rule.icon_blob}`" + :src="item.rules[index].icon_blob && item.rules[index].icon_blob.indexOf(',')>0?item.rules[index].icon_blob:`data:image/png;base64,${rule.icon_blob}`" alt /> </div> diff --git a/src/pages/labelMark/components/RightSide.vue b/src/pages/labelMark/components/RightSide.vue index 44808a9..d8a4478 100644 --- a/src/pages/labelMark/components/RightSide.vue +++ b/src/pages/labelMark/components/RightSide.vue @@ -9,7 +9,7 @@ element-loading-text="鍔犺浇涓�" type="border-card" > - <el-tab-pane label="浣嶇疆鏍囨敞" name="1"> + <el-tab-pane label="浣嶇疆鏍囧畾" name="1"> <el-tabs type="border-card"> <el-tab-pane label="鎽勫儚鏈烘爣娉�" name="11"> <div class> @@ -312,7 +312,7 @@ </div> </el-tab-pane> </el-tabs> - <el-dialog class="dialog-group" title="鏂板缓鍒嗙粍" :visible.sync="groupModelVisible"> + <el-dialog class="dialog-group" :title="groupForm.id?'缂栬緫鍒嗙粍':'鏂板缓鍒嗙粍'" :visible.sync="groupModelVisible"> <el-form :model="groupForm" ref="groupForm"> <el-form-item> <label>鍒嗙粍鍚嶇О</label> @@ -347,7 +347,7 @@ import { getCamerasByServer } from '@/api/pollConfig'; import { getCameraMarks, updateCameraMarks, findCameraGroups, saveCameraGroupInfo, delCameraGroup } from '@/api/camera'; import { getSearchList } from '@/api/search'; -import TreeDataPool from "@/Pool/TreeData"; + import { isNonnegativeInteger } from '@/scripts/validate'; import { getAllPolygon, saveRelationPolygon, findByCamGroup, findByGroup, delRelation } from '@/api/polygon'; import SlideCanvas from './SlideCanvas'; @@ -356,50 +356,42 @@ components: { SlideCanvas }, data () { return { - labels: [], - colorPick: '#79f2fb', - dotSize: 3, - isEdit: false, - isShowPop: false, - isNewLabel: false, + // labels: [], + // colorPick: '#79f2fb', + // dotSize: 3, + // isEdit: false, + // isShowPop: false, + // isNewLabel: false, // curLabel: { // id: '', - // posX: '', - // posY: '', - // x: '', - // y: '' + // x1: '', + // y1: '', + // x0: '', + // y0: '' // }, - curLabel: { - id: '', - x1: '', - y1: '', - x0: '', - y0: '' - }, - rules: { - x1: [ - { validator: isNonnegativeInteger, trigger: 'change' } - ], - y1: [ - { validator: isNonnegativeInteger, trigger: 'change' } - ] - }, - baseUrl: '', - snapshot_url: '', - userImg: '', - cameraData: [], - traceX: 0, - traceY: 0, - isShowCurPos: false, - actPage: '1', - loading: false, - spaceWidth: '', - spaceHeight: '', - curCameraData: { - cameraId: '', - coords: [] - }, - relativeCameras: [], + // rules: { + // x1: [ + // { validator: isNonnegativeInteger, trigger: 'change' } + // ], + // y1: [ + // { validator: isNonnegativeInteger, trigger: 'change' } + // ] + // }, + // baseUrl: '', + // snapshot_url: '', + // userImg: '', + // cameraData: [], + // traceX: 0, + // traceY: 0, + // isShowCurPos: false, + // actPage: '1', + // loading: false, + // spaceWidth: '', + // spaceHeight: '', + // curCameraData: { + // cameraId: '', + // coords: [] + // }, relativeList: [], cameraAreas: [], groupModelVisible: false, @@ -437,12 +429,7 @@ }, deep: true }, - // 'TreeDataPool.selectedNodes': { - // handler (n, o) { - // }, - // deep: true - // }, isEdit (n, o) { if (n) { this.$refs['editBoard'].addEventListener('click', this.bindListen); @@ -453,7 +440,6 @@ }, methods: { polygonUpdate(){ - debugger this.getAllGroups(); }, delRelation (item) { @@ -506,13 +492,7 @@ } }) }, - saveRelativeList () { - let params = { - groupId: this.curGroup.id, - } - //saveRelationPolygon().then() - }, async findPolygonByIds (cameras) { for (var i = 0; i < cameras.length; i++) { let res = await getAllPolygon({ cameraId: cameras[i].id }); @@ -678,13 +658,8 @@ cameras: [] } }, - changeTab () { - if (this.actPage == '1') { - this.$parent.$children[0].$el.parentNode.parentElement.style.display = 'block'; - } else { - this.$parent.$children[0].$el.parentNode.parentElement.style.display = 'none'; - } - }, + +//labelMark start sure () { let _this = this; this.$refs['labelForm'].validate(valid => { @@ -742,9 +717,6 @@ onChange (file, fileList) { fileList = [file] this.isShowCurPos = false; - // this.traceX = e.offsetX; - // this.traceY = e.offsetY; - //fileList.push(file) }, definedUpload (params) { let _file = params.file @@ -767,18 +739,6 @@ console.log(e) }) }, - // async getAllCameraData () { - // let res = await getCamerasByServer(); - // this.cameraData = res.data; - // let tempArr = []; - // this.cameraData.forEach(camera=>{ - // getAllPolygon({ cameraId: camera.id }).then(res=>{ - // tempArr.push(res.data); - // }) - // }); - // this.cameraAndPolygonData = tempArr; - // console.log(this.cameraAndPolygonData) - // }, bindListen (e) { this.newLabel(e); }, @@ -803,13 +763,11 @@ this.isNewLabel = true; }, editLabel (label) { - debugger if (!this.isEdit) return; this.isShowPop = true; this.$refs['labelForm'].clearValidate(); this.curLabel = JSON.parse(JSON.stringify(label)); - console.log(this.curLabel) - //this.curLabel = label; + }, cancle () { this.isShowPop = false; @@ -1011,8 +969,6 @@ } //color: #4966b7 } - } - .img-card { } .upload-demo, .el-upload { diff --git a/src/pages/labelMark/components/SlideCanvas.vue b/src/pages/labelMark/components/SlideCanvas.vue index ba82824..14362f4 100644 --- a/src/pages/labelMark/components/SlideCanvas.vue +++ b/src/pages/labelMark/components/SlideCanvas.vue @@ -22,11 +22,13 @@ <polygon-canvas class="polygon-canvas" :ref="`polygonCanvas_${camera.id}`" + :currentCameraId="camera.id" :snapshot_url="camera.canvasData.snapshot_url" :canvasDataShow="camera.canvasData" :canvasWidth="576" :canvasHeight="324" @fromCanvas="getCanvasData" + @refresh="refresh" ></polygon-canvas> </swiper-slide> </swiper> @@ -79,6 +81,13 @@ console.log(this.swiper) }, methods: { + refresh(url,cameraId) { + this.$emit('polygonDataUpdate') + + //let camera = this.cameras.find(one => one.id == cameraId); + //camera.canvasData.snapshot_url = url; + + }, getCanvasData(data) { let _this = this; savePolygon(data).then(rsp => { diff --git a/src/pages/panoramicView/components/LabelMark.vue b/src/pages/panoramicView/components/LabelMark.vue new file mode 100644 index 0000000..aaca3cc --- /dev/null +++ b/src/pages/panoramicView/components/LabelMark.vue @@ -0,0 +1,665 @@ +<template> + <div class="label-mark"> + <el-tabs type="border-card" v-model="actPage"> + <el-tab-pane label="鎽勫儚鏈烘爣娉�" name="1"> + <div class="mark-interface"> + <div class="left-tree"> + <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="tree-right"> + <div class="action-bar"> + <div class="tool-bar"> + <div> + <!-- <input type="color" ref="colorPicker" v-model="color"> --> + <label for>鎷捐壊鍣�:</label> + <el-color-picker v-model="colorPick" show-alpha size="mini"></el-color-picker> + </div> + <div style="width:250px;"> + <label for>绗旇Е:</label> + <el-slider v-model="dotSize" :min="1" :max="20"></el-slider> + </div> + <div> + <el-button + v-if="!isEdit" + class="drawboard-trigger" + size="small" + @click="editCameraData" + icon="el-icon-edit" + >缂栬緫</el-button> + + <el-button + v-if="isEdit" + class="drawboard-trigger save" + size="small" + @click="submitInfo" + icon="el-icon-lock" + >淇濆瓨</el-button> + </div> + </div> + </div> + <div class="drawboard shadow-box"> + <div class="mask" :class="{'edit-status-mask':isEdit}" ref="editBoard"> + <div + class="label" + @click="editLabel(item)" + v-for="(item,index) in curCameraData.coords" + :key="index" + :style="{left:`${item.x0}px`, top:`${item.y0}px`, backgroundColor: colorPick, width: `${dotSize}px`, height: `${dotSize}px` }" + ></div> + </div> + <img v-show="snapshot_url" :src="`/httpImage/${snapshot_url}`" alt /> + <div + class="popBox" + v-show="isShowPop" + :style="`top:${curLabel.y0 + 22}px;left:${curLabel.x0}px`" + > + <div class="title">鏍囨敞淇℃伅</div> + <div class="details"> + <el-form :model="curLabel" :rules="rules" ref="labelForm"> + <div class="detail-item"> + <div class="left"> + <el-form-item prop="x0"> + <label for>骞抽潰鍧愭爣X:</label> + <span class="fix-width">{{curLabel.x0}}</span> + <i>px</i> + </el-form-item> + </div> + <span class="devide"></span> + <div class="right"> + <el-form-item prop="x1"> + <label for>瀹為檯鍧愭爣X:</label> + <el-input + type="text" + size="mini" + style="width:90px" + v-model.number="curLabel.x1" + ></el-input> + </el-form-item> + </div> + </div> + <div class="detail-item"> + <div class="left"> + <el-form-item prop="y0"> + <label for>骞抽潰鍧愭爣Y:</label> + <span class="fix-width">{{curLabel.y0}}</span> + <i>px</i> + </el-form-item> + </div> + <span class="devide"></span> + <div class="right"> + <el-form-item prop="y1"> + <label for>瀹為檯鍧愭爣Y:</label> + <el-input + type="text" + size="mini" + style="width:90px" + v-model.number="curLabel.y1" + ></el-input> + </el-form-item> + </div> + </div> + <div class="btns"> + <el-button size="mini" type="danger" @click="deleteLabel">鍒犻櫎</el-button> + <el-button size="mini" type="primary" @click="cancle">鍙栨秷</el-button> + <el-button size="mini" type="success" @click="sure">纭畾</el-button> + </div> + </el-form> + </div> + </div> + </div> + </div> + </div> + </el-tab-pane> + <el-tab-pane label="瀹炴櫙鍧愭爣" name="2"> + <div class="user-upload"> + <div class="img-card"> + <el-upload + class="upload-demo" + drag + action="https://jsonplaceholder.typicode.com/posts/" + :http-request="definedUpload" + :on-change="onChange" + :show-file-list="false" + > + <el-image + class="preview" + v-if="panoramaPath" + :src="panoramaPath" + fit="contain" + @mousemove="showCurPos" + @mouseout="isShowCurPos=false" + ></el-image> + <div class="el-upload__text"> + 灏嗘枃浠舵嫋鍒版澶勶紝鎴� + <em>鐐瑰嚮涓婁紶</em> + </div> + </el-upload> + </div> + <div class="info"> + <div class="input-area"> + <!-- <div> + <label for>绌洪棿瀹�:</label> + <el-input v-model="spaceWidth" placeholder="璇疯緭鍏ュ疄闄呯┖闂村" size="small"></el-input> + </div> + <div> + <label for>绌洪棿楂�:</label> + <el-input v-model="spaceHeight" placeholder="璇疯緭鍏ュ疄闄呯┖闂撮珮" size="small"></el-input> + </div> --> + </div> + <div class="pos" v-show="isShowCurPos"> + 褰撳墠浣嶇疆: + <b>{{traceX}}</b>, + <b>{{traceY}}</b> + </div> + </div> + </div> + </el-tab-pane> + </el-tabs> + </div> +</template> + +<script> +import { getCamerasByServer } from '@/api/pollConfig'; +import { getCameraMarks, updateCameraMarks } from '@/api/camera'; +import { getPanoramaPic, putPanoramaPic } from '@/api/panorama'; +import { isNonnegativeInteger } from '@/scripts/validate'; +import LeftNav from "@/components/LeftNav"; +export default { + components: { LeftNav }, + data () { + return { + screenHeight: 0, + actPage: 1, + labels: [], + colorPick: '#79f2fb', + dotSize: 3, + isEdit: false, + isShowPop: false, + isNewLabel: false, + curLabel: { + id: '', + x1: '', + y1: '', + x0: '', + y0: '' + }, + rules: { + x1: [ + { validator: isNonnegativeInteger, trigger: 'change' } + ], + y1: [ + { validator: isNonnegativeInteger, trigger: 'change' } + ] + }, + baseUrl: '', + snapshot_url: '', + panoramaPath: '', + cameraData: [], + traceX: 0, + traceY: 0, + isShowCurPos: false, + actPage: '1', + loading: false, + spaceWidth: '', + spaceHeight: '', + curCameraData: { + cameraId: '', + coords: [] + }, + } + }, + mounted () { + this.getAllCameraData(); + this.getPanorama(); + this.screenHeight = document.documentElement.clientHeight - 20; + window.onresize = () => { + return (() => { + this.screenHeight = document.documentElement.clientHeight - 20; + })(); + }; + }, + + watch: { + 'TreeDataPool.selectedNode': { + handler (n, o) { + let curCamera = this.cameraData.find(item => item.id == n.id); + //璁剧疆鎽勫儚鏈哄簳鍥� + this.snapshot_url = curCamera.snapshot_url; + this.findCameraMarks(n.id); + }, + deep: true + }, + isEdit (n, o) { + if (n) { + this.$refs['editBoard'].addEventListener('click', this.bindListen); + } else { + this.$refs['editBoard'].removeEventListener('click', this.bindListen); + } + } + }, + methods: { + getAllCameraData () { + let _this = this; + getCamerasByServer().then(res => { + if (res.success) { + _this.cameraData = res.data; + //_this.getAllGroups(); + } + }).catch(e => { + console.log(e) + }) + }, + sure () { + let _this = this; + this.$refs['labelForm'].validate(valid => { + console.log(valid) + if (valid) { + _this.isShowPop = false; + //缂栬緫纭畾 + if (_this.curLabel.id) { + let editedIndex = _this.curCameraData.coords.findIndex(one => one.id == _this.curLabel.id); + _this.curCameraData.coords[editedIndex] = JSON.parse(JSON.stringify(_this.curLabel)); + + } + console.log(_this.curCameraData.coords) + this.$refs['labelForm'].clearValidate(); + } + }); + }, + //鑾峰彇鎽勫儚鏈烘爣娉� + findCameraMarks (id) { + getCameraMarks({ cameraId: id }).then(res => { + if (res.success) { + this.curCameraData.cameraId = id; + this.curCameraData.coords = res.data.map((item, index) => ({ id: 'm' + index, x0: item.x0, y0: item.y0, x1: item.x1, y1: item.y1 })); + } + }).catch(e => { + console.log(e) + }); + }, + editCameraData () { + if (!this.TreeDataPool.selectedNode.id) { + this.$notify({ + message: '璇峰厛閫夋嫨鎽勫儚鏈�', + type: 'warning' + }); + return; + } + this.isEdit = !this.isEdit; + }, + async submitInfo () { + this.isEdit = false; + let res = await updateCameraMarks(this.curCameraData); + if (res.success) { + this.findCameraMarks(this.curCameraData.cameraId); + } + }, + getPanorama(){ + let _this = this; + getPanoramaPic().then(res=>{ + _this.panoramaPath = res.data.panoramaPath + }) + }, + showCurPos (e) { + console.log(e); + this.isShowCurPos = true; + this.traceX = e.offsetX; + this.traceY = e.offsetY; + }, + onChange (file, fileList) { + fileList = [file] + this.isShowCurPos = false; + }, + definedUpload (params) { + let _this = this; + let _file = params.file; + let param = new FormData(); + param.append('file', params.file) + putPanoramaPic(param).then(res=>{ + _this.panoramaPath = res.data.panoramaPath+'?'+Math.random() + console.log(_this.panoramaPath) + }) + // let fileReader = new FileReader() + // fileReader.onload = () => { + // _this.file = fileReader.result; + // } + // if (_file) { + // fileReader.readAsDataURL(_file) + // } + }, + + bindListen (e) { + this.newLabel(e); + }, + newLabel (e) { + console.log('鐐瑰嚮浜嗙敾鏉�') + if (this.isShowPop) return; + //鑾峰彇榧犳爣鐩稿浜庣敾鏉跨殑瀹氫綅 + console.log('鑾峰彇褰撳墠瀹氫綅淇℃伅'); + this.$refs['labelForm'].resetFields(); + let target = { + id: '', + x0: e.offsetX, + y0: e.offsetY, + x1: '', + y1: '' + }; + target.id = 'n' + (this.curCameraData.coords.length - 1); + //this.labels.push(target); + this.curCameraData.coords.push(target); + this.curLabel = target; + this.isShowPop = true; + this.isNewLabel = true; + }, + editLabel (label) { + if (!this.isEdit) return; + this.isShowPop = true; + this.$refs['labelForm'].clearValidate(); + this.curLabel = JSON.parse(JSON.stringify(label)); + + }, + cancle () { + this.isShowPop = false; + //濡傛灉鏄湭淇濆瓨杩囩殑label鐩存帴鍒犻櫎(鏈繚瀛樼殑灏辨槸labels鏁扮粍涓渶鍚庝竴涓�) + if (this.curLabel.id.startsWith('n')) { + //this.labels.pop(); + this.curCameraData.coords.pop(); + } + }, + deleteLabel () { + if (this.curLabel.id) { + let index = this.curCameraData.coords.findIndex(item => item.id == this.curLabel.id); + this.curCameraData.coords.splice(index, 1); + + } else { + //this.labels.pop(); + this.curCameraData.coords.pop(); + } + this.isShowPop = false; + }, + } +} +</script> + +<style lang="scss"> +.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%; + } +} +.label-mark { + background: #d2dcea; + height: calc(100vh - 61px); + &>.el-tabs--border-card > .el-tabs__content { + background: #d2dcea; + padding: 0; + height: calc(100vh - 100px); + overflow: auto; + .mark-interface { + .left-tree { + position: relative; + float: left; + height: calc(100vh - 20px); + background: #fff; + } + .tree-right { + overflow: auto; + } + } + } + .tool-bar { + //width: 40px; + height: 100%; + padding: 10px 0 10px 20px; + box-sizing: border-box; + //background: rgb(250, 250, 250); + background: rgba(26, 45, 74, 0.6); + //margin-bottom: 40px; + display: flex; + align-items: center; + justify-content: flex-end; + > div { + cursor: pointer; + //background: rgba(245, 245, 245, 0.3); + padding: 0 5px; + height: 40px; + margin: 7px; + display: flex; + align-items: center; + label { + margin-right: 10px; + color: rgb(161, 161, 161); + color: #fff; + } + .el-slider { + width: 110px; + } + } + } + .shadow-box { + box-shadow: 3px 3px 3px 1px rgba(0, 0, 0, 0.1); + } + .action-bar { + width: 960px; + margin: auto; + margin-top: 30px; + //margin-bottom: 20px; + text-align: right; + .drawboard-trigger { + background: transparent; + color: #fff; + border-color: rgba(255, 255, 255, 0.3); + } + } + .drawboard { + margin: auto; + width: 960px; + height: 540px; + margin-bottom: 130px; + position: relative; + //background: #fff; + background: #f0ffca; + //box-shadow: 3px 3px 3px 1px rgba(0, 0, 0, 0.1); + .mask { + position: absolute; + background: transparent; + width: 100%; + height: 100%; + overflow: hidden; + &.edit-status-mask { + background: rgba(20, 181, 255, 0.1); + } + .label { + position: absolute; + z-index: 2; + border-radius: 50%; + } + } + img { + width: 960px; + height: 540px; + background: #f0ffca; + } + .right-panel { + width: 150px; + height: 100%; + background: rgba(26, 45, 74, 0.7); + } + .popBox { + position: absolute; + z-index: 99; + padding: 14px; + border-radius: 3px; + color: #fff; + background: rgba(26, 45, 74, 0.7); + .title { + font-weight: bold; + text-align: left; + font-size: 15px; + margin-bottom: 14px; + letter-spacing: 2px; + } + .details { + .detail-item { + display: flex; + margin: 5px 0; + label { + color: #a9a9a9; + width: 65px; + display: inline-block; + } + .left { + width: 110px; + text-align: left; + line-height: 28px; + .fix-width { + display: inline-block; + width: 23px; + } + } + .right { + width: 160px; + } + .devide { + width: 10px; + height: 1px; + background: #a9a9a9; + margin: 14px 3px; + } + } + .btns { + margin-top: 10px; + } + .el-form-item { + margin-bottom: 12px; + } + .el-form-item__content { + font-size: 12px; + line-height: 30px; + } + .el-form-item__error { + left: 70px; + top: 94%; + } + } + } + } + .user-upload { + margin: auto; + padding: 50px; + display: flex; + .info { + margin-left: 20px; + margin-top: 20px; + text-align: left; + font-size: 15px; + .input-area { + width: 300px; + label { + width: 80px; + color: rgba(39, 68, 111, 0.67); + } + > div { + display: flex; + align-items: center; + height: 40px; + } + } + .pos { + margin-top: 10px; + text-align: left; + color: rgba(39, 68, 111, 0.67); + b { + font-style: italic; + } + //color: #4966b7 + } + } + .upload-demo, + .el-upload { + height: 100%; + width: 100%; + margin: 0 auto; + } + .upload-demo .el-upload__input { + visibility: hidden; + } + .upload-demo .el-upload-dragger { + width: 100%; + height: 90%; + width: 962px; + height: 542px; + margin: 20px 0 0; + background: transparent; + /* border: none; */ + //position: relative; + overflow: visible; + border: none; + } + .upload-demo .el-upload__text { + position: absolute; + top: -24px; + left: 50%; + margin-left: -91px; + } + .upload-demo .preview { + object-fit: contain; + } + } +} +</style> \ No newline at end of file diff --git a/src/pages/panoramicView/components/RelateCamera.vue b/src/pages/panoramicView/components/RelateCamera.vue new file mode 100644 index 0000000..f196ec6 --- /dev/null +++ b/src/pages/panoramicView/components/RelateCamera.vue @@ -0,0 +1,542 @@ +<template> + <div class="relate-camera"> + <div class="part"> + <div class="title"> + <span>鍏宠仈璁惧鍒嗙粍</span> + <el-button @click="newGroup" icon="el-icon-plus" size="mini" type="primary">鏂板缓鍒嗙粍</el-button> + </div> + <el-alert type="info" title="鎻愮ず:璇风偣鍑讳笂鏂�'鏂板缓鍒嗙粍'鎸夐挳寤虹珛鍒嗙粍" show-icon v-if="groupList.length==0"></el-alert> + <div class="flex-box" v-if="groupList.length!==0"> + <div + class="group-card" + :class="{'checked':group.checked}" + v-for="(group,index) in groupList" + :key="index" + @click="checkCurrentGroup(group)" + > + <div class="top"> + <div class="left"> + <span class="icon el-icon-video-camera"></span> + </div> + <div class="right"> + <div class="name">{{group.groupName}}</div> + <div class="details"> + <label>鎽勫儚鏈�:</label> + <span + class="sub" + v-for="(camera,index) in group.cameras" + :key="camera.id" + >{{camera.name}} {{index!==group.cameras.length-1?'/':''}}</span> + </div> + </div> + </div> + <div class="bottom"> + <span @click.stop="editGroup(group)">缂栬緫鍒嗙粍</span> + <el-popconfirm title="纭畾鍒犻櫎璇ュ垎缁勫悧?" @onConfirm="removeGroup(group)"> + <el-button slot="reference" type="text">鍒犻櫎鍒嗙粍</el-button> + </el-popconfirm> + </div> + </div> + </div> + </div> + <!-- <div class="part" v-if="groupList.length"> --> + <div class="part" v-if="groupList.length!==0 && Object.keys(curGroup)"> + <div class="title">缁樺埗鍖哄煙(鐢ㄤ簬绠楁硶鍒嗘瀽)</div> + <div class="relative-partment" v-if="curGroup.cameras&&curGroup.cameras.length"> + <div class="area-wrap" v-for="i in 2" :key="'sc'+i"> + <slide-canvas :cameras="curGroup.cameras" @polygonDataUpdate="polygonUpdate"></slide-canvas> + </div> + </div> + </div> + <div class="part relative-config" v-if="Object.keys(curGroup)"> + <div class="title"> + <div class="left"> + <span>鍏宠仈鍖哄煙閰嶇疆</span> + </div> + <div class="right" v-if="curGroup.id"> + <el-button icon="el-icon-plus" size="mini" type="primary" @click="addRelation">娣诲姞鍏宠仈</el-button> + </div> + </div> + <div class="relative-list"> + <div class="relative-item" v-for="item in relativeList" :key="item.id"> + <div class="left"> + <el-select v-model="item.sourceObj" value-key="polygonId" size="small"> + <el-option + v-for="area in cameraAreas" + :key="area.polygonId" + :label="area.name" + :value="area" + ></el-option> + </el-select> + <i class="el-icon-connection"></i> + <el-select v-model="item.targetObj" value-key="polygonId" size="small"> + <el-option + v-for="area in cameraAreas" + :key="area.polygonId" + :label="area.name" + :value="area" + ></el-option> + </el-select> + </div> + <div class="right"> + <el-button type="text" @click="saveRelativePolygon(item)">淇濆瓨</el-button> + <div class="btn-del" @click="delRelation(item)"> + <i class="el-icon-delete"></i> + </div> + </div> + </div> + </div> + <!-- <div class="btns"> + <el-button size="small" >鍙栨秷</el-button> + <el-button size="small" type="primary" @click="saveRelativeList">淇濆瓨</el-button> + </div>--> + <el-dialog + class="dialog-group" + :title="groupForm.id?'缂栬緫鍒嗙粍':'鏂板缓鍒嗙粍'" + :visible.sync="groupModelVisible" + > + <el-form :model="groupForm" ref="groupForm"> + <el-form-item> + <label>鍒嗙粍鍚嶇О</label> + <div> + <el-input v-model="groupForm.groupName"></el-input> + </div> + </el-form-item> + <el-form-item> + <label>閫夋嫨鎽勫儚鏈�</label> + <div> + <el-select v-model="groupForm.cameras" value-key="id" multiple> + <el-option + :label="camera.name" + :value="camera" + v-for="camera in cameraData" + :key="camera.id" + ></el-option> + </el-select> + </div> + </el-form-item> + <div class="btns"> + <el-button @click="groupModelVisible=false;">鍙栨秷</el-button> + <el-button type="primary" @click="confirmGroupDialog">纭畾</el-button> + </div> + </el-form> + </el-dialog> + </div> + </div> +</template> + +<script> +import { getCamerasByServer } from '@/api/pollConfig'; +import { findCameraGroups, saveCameraGroupInfo, delCameraGroup } from '@/api/camera'; +import { getAllPolygon, saveRelationPolygon, findByCamGroup, findByGroup, delRelation } from '@/api/polygon'; +import SlideCanvas from './SlideCanvas'; + +export default { + components: { SlideCanvas }, + data () { + return { + cameraData: [], + relativeList: [], + cameraAreas: [], + groupModelVisible: false, + groupList: [], + curGroup: {}, + groupForm: { + groupName: '', + cameras: [] + }, + groupCameras: [], + groupCamera: { + + }, + cameraAndPolygonData: [] + } + }, + mounted () { + this.getAllCameraData(); + }, + methods: { + getAllCameraData () { + let _this = this; + getCamerasByServer().then(res => { + if (res.success) { + _this.cameraData = res.data; + _this.getAllGroups(); + } + }).catch(e => { + console.log(e) + }) + }, + polygonUpdate () { + this.getAllGroups(); + }, + delRelation (item) { + let _this = this; + delRelation(item.id).then(res => { + if (res.success) { + this.$notify({ + type: 'success', + message: res.data + }); + _this.findRelationByGroup(); + } + }) + }, + findRelationByGroup () { + let _this = this; + findByGroup({ groupId: this.curGroup.id }).then(res => { + + _this.relativeList = res.data.map(relation => { + let obj = { sourceObj: {}, targetObj: {} }; + obj.sourceObj.cameraId = relation.source_camera_id; + obj.sourceObj.polygonId = relation.source_polygon_id; + obj.targetObj.cameraId = relation.target_camera_id; + obj.targetObj.polygonId = relation.target_polygon_id; + obj.sourceObj.name = relation.source_polygon.name; + obj.targetObj.name = relation.target_polygon.name; + obj.id = relation.id; + return obj; + }) + }) + }, + saveRelativePolygon (item) { + debugger + let _this = this; + let params = { + groupId: this.curGroup.id, + source_camera_id: item.sourceObj.cameraId, + target_camera_id: item.targetObj.cameraId, + source_polygon_id: item.sourceObj.polygonId, + target_polygon_id: item.targetObj.polygonId, + id: item.id || '' + } + + saveRelationPolygon(params).then(res => { + if (res.success) { + this.$notify({ + type: 'success', + message: '淇濆瓨鎴愬姛', + }); + _this.findRelationByGroup() + } + }) + }, + + async findPolygonByIds (cameras) { + for (var i = 0; i < cameras.length; i++) { + let res = await getAllPolygon({ cameraId: cameras[i].id }); + cameras[i].canvasData = res.data; + } + return cameras + }, + + async getAllGroupInfo () { + let _this = this; + let res = await findCameraGroups(); + let groupArr = res.data.map(item => { + let obj = {}; //group + obj.groupName = item.groupName; + obj.id = item.id; + let cameras = []; //cameras + item.cameraIds.forEach(id => { + let camera = {}; + _this.cameraData.find(one => { + if (one.id == id) { + camera.name = one.name; + camera.id = id; + } + }); + cameras.push(camera) + }); + //cameras [{id,name}] + obj.cameras = cameras; + return obj; + + }); + return groupArr; + }, + // async getAllGroups () { + // let _this = this; + // let groups = await this.getAllGroupInfo(); + // let promiseArr = []; + // for (var i = 0; i < groups.length; i++) { + // let pro = new Promise(resolve => { + // resolve(_this.findPolygonByIds(groups[i].cameras)) + // }); + // promiseArr.push(pro) + // } + // Promise.allSettled(promiseArr).then(camerasArr => { + + // for (var i = 0; i < camerasArr.length; i++) { + // groups[i].cameras = camerasArr[i].value + // } + // _this.groupList = groups; + // //閫変腑绗竴涓� + // _this.checkCurrentGroup(_this.groupList[0]); + // }) + // }, + async getAllGroups () { + let _this = this; + let groups = await this.getAllGroupInfo(); + for (var i = 0; i < groups.length; i++) { + groups[i].cameras = await _this.findPolygonByIds(groups[i].cameras) + } + this.groupList = groups; + //閫変腑绗竴涓� + this.groupList.length && this.checkCurrentGroup(_this.groupList[0]); + + }, + + addRelation () { + let obj = { cameraArea1: '', cameraArea2: '' }; + this.relativeList.push(obj) + }, + + editGroup (group) { + this.groupModelVisible = true; + //this.$refs['groupForm'].resetFields(); + this.groupForm = group; + }, + removeGroup (group) { + let _this = this; + delCameraGroup(group.id).then(res => { + _this.getAllGroups() + }) + }, + checkCurrentGroup (group) { + this.groupList.forEach(group => { + group.checked = false; + }) + this.curGroup = group; + this.curGroup.checked = true; + this.findRelationByGroup(); + //鏌ヨ绗竴涓垎缁勪笅鎽勫儚鏈哄尯鍩� + findByCamGroup({ groupId: group.id }).then(res => { + let tempArr = []; + res.data.forEach(camera => { + let cameraArea = []; + camera.polygon.forEach(item => { + let area = {}; + area.name = camera.camera_name + '' + item.name; + area.cameraId = camera.camera_id; + area.polygonId = item.id; + cameraArea.push(area); + }); + camera.rect.forEach(item => { + let area = {}; + area.name = camera.camera_name + '' + item.name; + area.cameraId = camera.camera_id; + area.polygonId = item.id; + cameraArea.push(area); + }); + tempArr = tempArr.concat(cameraArea) + }); + this.cameraAreas = tempArr; + console.log(this.cameraAreas) + }) + }, + confirmGroupDialog () { + //璇锋眰淇濆瓨鏂板缓鎴栫紪杈戝垎缁� + let _this = this; + let params = { + cameraIds: [], + groupName: '', + id: '' + }; + if (!this.groupForm.groupName.trim()) { + this.$notify({ + type: 'warning', + message: '璇疯緭鍏ュ垎缁勫悕绉�' + }); + return + } + if (this.groupForm.cameras.length < 2) { + this.$notify({ + type: 'warning', + message: '璇烽�夋嫨鑷冲皯涓や釜鎽勫儚鏈�' + }); + return + } + params.groupName = this.groupForm.groupName; + params.id = this.groupForm.id || ''; + this.groupForm.cameras.forEach(camera => { + params.cameraIds.push(camera.id); + //鏍规嵁鍒嗙粍鍐呮憚鍍忔満id鏌ュ悇鑷尯鍩� + getAllPolygon({ cameraId: camera.id }).then(res => { + _this.groupCameras.push(res.data); + }).catch(e => { + console.log(e) + }); + }) + //this.groupList.push(this.groupForm); + saveCameraGroupInfo(params).then(res => { + _this.getAllGroups(); + }) + this.groupModelVisible = false; + + }, + newGroup () { + this.groupModelVisible = true; + this.$nextTick(() => { + this.$refs['groupForm'].resetFields(); + }) + this.groupForm = { + groupName: '', + cameras: [] + } + } + } +} +</script> + +<style lang="scss"> +.relate-camera { + padding: 20px 30px; + .el-alert--info { + background: rgba(230, 247, 255, 1); + border-color: rgba(145, 213, 255, 1); + color: #666; + .el-alert__icon.el-icon-info { + color: #1890ff; + } + } + .title { + text-align: left; + font-size: 15px; + line-height: 40px; + .el-button { + margin-left: 14px; + } + } + .group-card { + cursor: pointer; + background: #fff; + width: 293px; + height: 153px; + margin-right: 10px; + box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1); + border: 1px solid transparent; + &.checked { + border-color: #1890ff; + } + .top { + height: 104px; + display: flex; + padding: 20px 20px 0; + box-sizing: border-box; + //align-items: center; + .right { + text-align: left; + padding-left: 14px; + } + .icon { + font-size: 40px; + } + .name { + font-size: 16px; + margin-bottom: 10px; + font-weight: bold; + } + .details { + display: -webkit-box; + overflow: hidden; + text-overflow:ellipsis; + word-break:break-all; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; + //flex-wrap: wrap; + label { + width: 46px; + } + .sub { + } + } + } + .bottom { + border-top: 1px solid #e9e9e9; + height: 48px; + line-height: 48px; + background: #f7f9fa; + position: relative; + display: flex; + &:after { + content: ''; + position: absolute; + font-size: 0; + width: 1px; + height: 14px; + background: #0000006d; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + } + span { + cursor: pointer; + width: 50%; + font-size: 14px; + color: #0000006d; + } + } + } + .part { + margin-bottom: 20px; + .relative-partment { + width: 1200px; + margin: 0 auto; + display: flex; + justify-content: space-between; + .area-wrap { + width: 576px; + } + } + } + .relative-config { + width: 700px; + .title { + display: flex; + justify-content: space-between; + } + .relative-list { + .relative-item { + width: 680px; + height: 48px; + padding-left: 20px; + background: #ecf2f5; + margin-bottom: 6px; + display: flex; + align-items: center; + .left { + width: 650px; + text-align: left; + } + .right { + display: flex; + align-items: center; + } + i { + font-size: 20px; + padding: 0 10px; + cursor: pointer; + } + } + } + } + .dialog-group { + .el-form { + .el-form-item__content { + display: flex; + label { + width: 80px; + text-align: left; + } + & > div { + flex: 1; + .el-select { + width: 100%; + } + } + } + } + } +} +</style> \ No newline at end of file diff --git a/src/pages/panoramicView/components/SlideCanvas.vue b/src/pages/panoramicView/components/SlideCanvas.vue new file mode 100644 index 0000000..14362f4 --- /dev/null +++ b/src/pages/panoramicView/components/SlideCanvas.vue @@ -0,0 +1,231 @@ +<template> + <div class="swiper-box"> + <p class="task-tip" v-if="cameras.length == 0 "></p> + <swiper + ref="cameraSwiper" + v-if="cameras.length>=1" + :options="swiperOption" + class="swiper-box-container" + > + <swiper-slide v-for="camera in cameras" :key="camera.id+'c'"> + <div class="swiper-draw-box-title"> + <b>{{camera.name}}</b> + <b style="margin-left:14px;">缁樺埗鍖哄煙</b> + <span + class="el-dropdown-link" + @click="drawBaseImg(camera.id)" + style="position: relative;top: 5px; cursor:pointer" + > + <i class="iconfont iconbianji1" style="font-size: 28px; "></i> + </span> + </div> + <polygon-canvas + class="polygon-canvas" + :ref="`polygonCanvas_${camera.id}`" + :currentCameraId="camera.id" + :snapshot_url="camera.canvasData.snapshot_url" + :canvasDataShow="camera.canvasData" + :canvasWidth="576" + :canvasHeight="324" + @fromCanvas="getCanvasData" + @refresh="refresh" + ></polygon-canvas> + </swiper-slide> + </swiper> + <div class="swiper-pre-border" slot="button-prev" @click="pre" > + <div class="icon-btn" > + <i class="iconfont iconzuo"></i> + </div> + </div> + <div class="swiper-next-border" slot="button-next" @click="next"> + <div class="icon-btn" > + <i class="iconfont iconyou1"></i> + </div> + </div> + + </div> +</template> + +<script> +import { chunkArr } from '@/scripts/util'; +import PolygonCanvas from '@/components/canvas'; +import { savePolygon } from "@/api/polygon"; +export default { + //cameras: [{ id: '',snapshot_url:'', canvasData: {} }] + props: [ + 'cameras', + //'swiperOption' + ], + watch:{ + cameras:{ + handler(n,o){ + console.log('slidecanvas cameras',n) + }, + deep: true + } + }, + components: { PolygonCanvas }, + data () { + return { + swiperOption: this.newOption(), + //mySwiper: {} + } + }, + computed: { + swiper () { + return this.$refs['cameraSwiper'].swiper + } + }, + mounted () { + //this.mySwiper = this.$refs.sceneSwiper.swiper; + console.log(this.swiper) + }, + methods: { + refresh(url,cameraId) { + this.$emit('polygonDataUpdate') + + //let camera = this.cameras.find(one => one.id == cameraId); + //camera.canvasData.snapshot_url = url; + + }, + getCanvasData(data) { + let _this = this; + savePolygon(data).then(rsp => { + _this.$emit('polygonDataUpdate') + }); + }, + newOption () { + return { + slidesPerView: 1, + spaceBetween: 0, + pagination: { + el: ".swiper-pagination", + clickable: true + }, + observer: true,//淇敼swiper鑷繁鎴栧瓙鍏冪礌鏃讹紝鑷姩鍒濆鍖杝wiper + observeParents: true,//淇敼swiper鐨勭埗鍏冪礌鏃讹紝鑷姩鍒濆鍖杝wiper + } + }, + + pre () { + this.swiper.activeIndex-- + this.swiper.slideTo(this.swiper.activeIndex); + }, + next () { + this.swiper.activeIndex++ + this.swiper.slideTo(this.swiper.activeIndex); + }, + drawBaseImg (id) { + this.$refs[`polygonCanvas_${id}`][0].showModal(); + } + } +}; +</script> + +<style lang="scss"> +.icon { + width: 1em; + height: 1em; + vertical-align: -0.15em; + fill: currentColor; + overflow: hidden; +} +.task-tip { + font-family: PingFangSC-Regular; + font-size: 12px; + color: #cccccc; + margin-top: 10%; +} +.swiper-box { + position: relative; +} +.swiper-pre-border, +.swiper-next-border { + width: 40px; + height: 40px; + position: absolute; + background: #8888; + top: 50%; + margin-top: -20px; + z-index: 99; + border-radius: 4em; + outline: none; + .icon-btn { + color: rgb(255, 255, 255); + text-align: center; + line-height: 38px; + cursor: pointer; + } +} +.swiper-pre-border { + left: 10px; +} +.swiper-pre-border:hover { + background: #666; +} +.swiper-next-border { + right: 10px; +} +.swiper-next-border:hover { + background: #666; +} +.swiper-draw-box-title { + display: flex; + justify-content: center; + align-items: center; + height: 24px; + b { + font-size: 14px; + } +} +.wrap-box { + width: 100%; + display: inline-block; + .inner { + width: 90%; + box-sizing: border-box; + position: relative; + font-size: 14px; + padding: 7px 0 48px; + transition: all 1s; + background: #ffffff; + border: 1px solid #e2e2e2; + box-shadow: 0 5px 12px 0 rgba(0, 0, 0, 0.07); + border-radius: 4px; + margin: auto; + &:hover { + .mask { + display: block; + } + } + .mask { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.65); + backdrop-filter: blur(1px) brightness(100%); + text-align: center; + z-index: 1; + border-radius: 3px; + display: none; + .tool { + position: absolute; + top: 49%; + left: 50%; + transform: translate(-50%, -50%); + i { + font-size: 50px; + } + i:nth-of-type(1) { + margin-right: 30px; + } + i:nth-of-type(2) { + color: red; + } + } + } + } +} +</style> \ No newline at end of file diff --git a/src/pages/panoramicView/components/TracePlot.vue b/src/pages/panoramicView/components/TracePlot.vue new file mode 100644 index 0000000..f12095d --- /dev/null +++ b/src/pages/panoramicView/components/TracePlot.vue @@ -0,0 +1,153 @@ +<template> + <div class="trace-plot"> + <div class="filter-bar"> + <el-date-picker + size="small" + v-model="searchTime" + @change="searchData" + type="datetimerange" + start-placeholder="寮�濮嬫棩鏈�" + end-placeholder="缁撴潫鏃ユ湡" + value-format="yyyy-MM-dd HH:mm:ss" + :default-time="['00:00:00','23:59:59']" + + ></el-date-picker> + <el-button @click="searchData" size="small" type="primary" class="btn-search">鏌� 璇�</el-button> + </div> + <!-- <p class="p-date" style="width:19%;vertical-align: top;"> + <el-date-picker + size="mini" + v-model="searchTime" + @change="searchData" + type="datetimerange" + start-placeholder="寮�濮嬫棩鏈�" + end-placeholder="缁撴潫鏃ユ湡" + value-format="yyyy-MM-dd HH:mm:ss" + :default-time="['00:00:00','23:59:59']" + style="width:99%;min-width:200px" + ></el-date-picker> + </p> --> + <canvas ref="trackArea" width="960" height="540" :style="{backgroundImage:`url(${panoramaPath})`}"></canvas> + </div> +</template> + +<script> +import { getSearchList } from '@/api/search'; +import { getPanoramaPic } from "@/api/panorama"; +export default { + data () { + return { + panoramaPath:'', + trackData: [], + activeObjHashMap: {}, + actObj: {}, + searchTime: [ + this.$moment().format("YYYY-MM-DD 00:00:00"), + this.$moment().format("YYYY-MM-DD 23:59:59") + //this.$moment().format("YYYY-MM-DD HH:mm:ss") + ], + timer: null, + } + }, + mounted () { + this.searchData(); + this.getPanoramaPic(); + this.timer = setInterval(()=>{ + this.searchData(); + },7000); + }, + beforeDestroy(){ + console.log('beforeDestroy') + clearInterval(this.timer); + }, + methods: { + getPanoramaPic () { + let _this = this; + getPanoramaPic().then(res=>{ + _this.panoramaPath = res.data.panoramaPath + }) + }, + drawTracePath () { + //let canvas = document.querySelector('#trackArea'); + let canvas = this.$refs['trackArea']; + let ctx = canvas.getContext('2d'); + ctx.clearRect(0,0,canvas.width,canvas.height); + ctx.strokeStyle = 'yellow'; + ctx.fillStyle = 'aqua'; + //ctx.globalAlpha=0.5; + ctx.lineWidth = 2; + //ctx.lineJoin='round'; + ctx.lineCap = 'round'; + for (var target in this.actObj) { + ctx.beginPath(); + ctx.fillStyle = `rgb(${Math.floor(Math.random() * 20 + 220)},${Math.floor(Math.random() * 35 + 200)},${Math.floor(Math.random() * 55 + 200)})`; + ctx.strokeStyle = `rgb(${Math.floor(Math.random() * 20 + 220)},${Math.floor(Math.random() * 20 + 210)},${Math.floor(Math.random() * 55 + 200)})`; + ctx.fillRect(this.actObj[target][0].globalCoordX, this.actObj[target][0].globalCoordY, 9, 9); + ctx.moveTo(this.actObj[target][0].globalCoordX, this.actObj[target][0].globalCoordY); + for (var i = 1; i < this.actObj[target].length; i++) { + ctx.lineTo(this.actObj[target][i].globalCoordX, this.actObj[target][i].globalCoordY); + ctx.fillRect(this.actObj[target][i].globalCoordX, this.actObj[target][i].globalCoordY, 9, 9); + } + ctx.stroke(); + } + }, + searchData () { + let _this = this; + var param = { + page: 1, + size: 70, + searchTime: this.searchTime, + alarmlevel: [], + inputValue: '', + tabs: [], + tasks: [], + treeNodes: [], + isAll: true + }; + getSearchList(param).then(res => { + let filterArr = []; + res.data.datalist&&res.data.datalist.forEach(obj => { + if (_this.activeObjHashMap[obj.activeObject.id] !== 1) { + _this.activeObjHashMap[obj.activeObject.id] = 1 + filterArr.push(obj) + } + }); + filterArr.forEach(item => { + item.activeObject.targetInfo.forEach(target => { + if (target.targetType == 'UniquelID') { + let attribute = JSON.parse(target.attribute) + if (_this.actObj[target.targetId]) { + _this.actObj[target.targetId].push({ globalCoordX: attribute.globalCoordX, globalCoordY: attribute.globalCoordY }); + } else { + _this.actObj[target.targetId] = [{ globalCoordX: attribute.globalCoordX, globalCoordY: attribute.globalCoordY }]; + } + } + }) + }); + console.log(_this.actObj) + _this.drawTracePath() + }) + } + } +} +</script> + +<style lang="scss"> +.trace-plot { + .filter-bar{ + width: 960px; + margin: 20px auto; + display: flex; + align-items: center; + flex-direction: end; + .btn-search{ + margin-left:20px; + } + } + canvas { + background: lightsteelblue; + background-repeat: no-repeat; + + } +} +</style> \ No newline at end of file diff --git a/src/pages/panoramicView/index/App.vue b/src/pages/panoramicView/index/App.vue new file mode 100644 index 0000000..90550f6 --- /dev/null +++ b/src/pages/panoramicView/index/App.vue @@ -0,0 +1,95 @@ +<template> + <div class="panoramic-view"> + <div class="top-nav"> + <div class="logo"> + <div class="icon"></div> + <a class="title">闀挎槬鍏ㄦ櫙杩借釜</a> + </div> + <el-menu + :default-active="actMenuIndex" + class="el-menu-demo" + mode="horizontal" + @select="checkMenu" + > + <el-menu-item index="1">浣嶇疆鏍囧畾</el-menu-item> + <el-menu-item index="2">杞ㄨ抗鍥�</el-menu-item> + <el-menu-item index="3">鍏宠仈鎽勫儚鏈�</el-menu-item> + </el-menu> + </div> + <div class="act-view"> + <template v-if="actMenuIndex=='1'"> + <label-mark></label-mark> + </template> + <template v-if="actMenuIndex=='2'"> + <trace-plot></trace-plot> + </template> + <template v-if="actMenuIndex=='3'"> + <relate-camera></relate-camera> + </template> + </div> + </div> +</template> + +<script> +import LabelMark from '../components/LabelMark'; +import TracePlot from '../components/TracePlot'; +import RelateCamera from '../components/RelateCamera'; +export default { + components: { LabelMark, TracePlot, RelateCamera }, + data () { + return { + actMenuIndex: '1', + } + }, + methods: { + checkMenu (key, keyPath) { + this.actMenuIndex = key; + } + } +} +</script> + +<style lang="scss"> +.panoramic-view { + min-width: 1399px; + overflow: hidden; + height: 100%; + .top-nav { + display: flex; + background: rgba(28, 26, 96, 1); + .logo { + width: 310px; + display: flex; + align-items: center; + .icon{ + width: 100px; + + } + .title{ + text-decoration: none; + margin-left: 10px; + font-size: 18px; + color: #fff; + letter-spacing: 2px; + } + } + .el-menu--horizontal { + border-bottom: 0; + background: rgba(28, 26, 96, 1); + } + .el-menu--horizontal > .el-menu-item { + border-bottom: 0; + color: #fff; + &:hover{ + color: #fff; + background: rgb(24, 35, 182); + } + } + .el-menu--horizontal > .el-menu-item.is-active { + //border-bottom: 0; + background-color: rgba(61, 73, 225, 1); + color: #fff; + } + } +} +</style> \ No newline at end of file diff --git a/src/pages/panoramicView/index/main.ts b/src/pages/panoramicView/index/main.ts new file mode 100644 index 0000000..bffdf32 --- /dev/null +++ b/src/pages/panoramicView/index/main.ts @@ -0,0 +1,19 @@ +import Vue from 'vue'; +import App from './App.vue'; + +import moment from "moment"; +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 Mixin from "./mixins"; + +Vue.use(ElementUI); +Vue.use(VueAwesomeSwiper as any); +Vue.mixin(Mixin); +Vue.prototype.$moment = moment; +new Vue({ + el: '#app', + render: h => h(App) +}); \ No newline at end of file diff --git a/src/pages/panoramicView/index/mixins.ts b/src/pages/panoramicView/index/mixins.ts new file mode 100644 index 0000000..feda309 --- /dev/null +++ b/src/pages/panoramicView/index/mixins.ts @@ -0,0 +1,14 @@ +import TreeDataPool from "@/Pool/TreeData"; + +/* eslint-disable */ +const onlyTreeDataPool = new TreeDataPool + +const mixin = { + data() { + return { + TreeDataPool: onlyTreeDataPool + + }; + }, +}; +export default mixin; \ No newline at end of file -- Gitblit v1.8.0