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