From c99cad106ef5be9f818e45d385dfdcec29ce19e5 Mon Sep 17 00:00:00 2001 From: hanbaoshan <hanbaoshan@aiotlink.com> Date: 星期四, 03 十二月 2020 16:52:24 +0800 Subject: [PATCH] 修复绘制多边形撤销错误的bug --- src/pages/labelMark/components/RightSide.vue | 628 +++++++++++++++++++++++++++++++++++++++++++++----------- 1 files changed, 504 insertions(+), 124 deletions(-) diff --git a/src/pages/labelMark/components/RightSide.vue b/src/pages/labelMark/components/RightSide.vue index 9bf6d66..e1f2177 100644 --- a/src/pages/labelMark/components/RightSide.vue +++ b/src/pages/labelMark/components/RightSide.vue @@ -1,65 +1,204 @@ <template> <div class="right-side"> - <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> - <div class="action-bar"> - <el-button class="drawboard-trigger" size="small" @click="isEdit=!isEdit" :icon="isEdit?'el-icon-lock':'el-icon-edit'">{{isEdit?'閿佸畾':'缂栬緫'}}</el-button> - </div> - <div class="drawboard"> - <div class="mask" :class="{'edit-status-mask':isEdit}" ref="editBoard" > - <div class="label" @click="editLabel(item)" v-for="(item,index) in labels" :key="index" :style="{left:`${item.x}px`, top:`${item.y}px`, backgroundColor: colorPick, width: `${dotSize}px`, height: `${dotSize}px` }"></div> - </div> - <img :src="baseUrl" alt /> - <div class="popBox" v-show="isShowPop" :style="`top:${curLabel.y + 22}px;left:${curLabel.x}px`"> - <div class="title">鏍囨敞淇℃伅</div> - <div class="details"> - <div class="detail-item"> - <div class="left"> - <label for="">骞抽潰鍧愭爣X:</label> - <span class="fix-width">{{curLabel.x}}</span> - <i>px</i> + <div class="figure s-system-manage"> + <el-tabs + id="e-basic-setting" + v-model="actPage" + v-loading="loading" + element-loading-text="鍔犺浇涓�" + type="border-card" + > + <el-tab-pane label="鎽勫儚鏈烘爣娉�" name="1"> + <div class> + <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> - <span class="devide"></span> - <div class="right"> - <label for="">瀹為檯鍧愭爣X:</label> - <el-input type="text" size="mini" style="width:90px" v-model="curLabel.posX"></el-input> + <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 class="detail-item"> - <div class="left"> - <label for="">骞抽潰鍧愭爣Y:</label> - <span class="fix-width">{{curLabel.y}}</span> - <i>px</i> + </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="userImg" + :src="userImg" + fit="contain" + @mousemove="showCurPos" + @mouseout="isShowCurPos=false" + ></el-image> + <div class="el-upload__text"> + 灏嗘枃浠舵嫋鍒版澶勶紝鎴� + <em>鐐瑰嚮涓婁紶</em> + </div> + </el-upload> </div> - <span class="devide"></span> - <div class="right"> - <label for="">瀹為檯鍧愭爣Y:</label> - <el-input type="text" size="mini" style="width:90px" v-model="curLabel.posY"></el-input> + <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> - <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="submitInfo">纭畾</el-button> + </el-tab-pane> + </el-tabs> + <!-- <el-collapse v-model="actPage" @change="chnageActPage"> + <el-collapse-item title="鎽勫儚鏈烘爣娉�" name="1"> + + </el-collapse-item> + <el-collapse-item title="杩借釜瀹炴櫙鍧愭爣" 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="userImg" + :src="userImg" + fit="contain" + @mousemove="showCurPos" + @mouseout="isShowCurPos=false" + ></el-image> + <div class="el-upload__text"> + 灏嗘枃浠舵嫋鍒版澶勶紝鎴� + <em>鐐瑰嚮涓婁紶</em> + </div> + </el-upload> + </div> + <div class="info" v-show="isShowCurPos">褰撳墠浣嶇疆:{{traceX}},{{traceY}}</div> </div> - </div> - </div> + </el-collapse-item> + </el-collapse>--> </div> - </div> </template> <script> +import { getCamerasByServer } from '@/api/pollConfig'; +import { getCameraMarks, updateCameraMarks } from '@/api/camera'; import TreeDataPool from "@/Pool/TreeData"; +import { isNonnegativeInteger } from '@/scripts/validate'; export default { data () { return { @@ -69,99 +208,234 @@ isEdit: false, isShowPop: false, isNewLabel: false, + // curLabel: { + // id: '', + // posX: '', + // posY: '', + // x: '', + // y: '' + // }, curLabel: { - id:'', - posX:'', - posY:'', - x:'', - y:'' + id: '', + x1: '', + y1: '', + x0: '', + y0: '' }, - baseUrl: '' + 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: [] + } } }, computed: { - + }, - mounted(){ - setTimeout(()=>{ - let mockData = [{id:'a1',x:15, y:33, posX:150, posY:330},{id:'b2',x:56, y:87, posX:560, posY:870}]; - this.labels = mockData; - },1000); + mounted () { + this.getAllCameraData(); + //mock鍥炴樉鏍囨敞 + setTimeout(() => { + let mockData = [{ id: 'a1', x0: 15, y0: 33, x1: 150, y1: 330 }, { id: 'b2', x0: 56, y0: 87, x1: 560, y1: 870 }]; + //this.curCameraData.coords = mockData; + }, 1000); }, - watch:{ - isEdit(n,o){ - if(n){ - this.$refs['editBoard'].addEventListener('click',this.bindListen); - }else{ - this.$refs['editBoard'].removeEventListener('click',this.bindListen); + 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: { - bindListen(e){ + sure () { + let _this = this; + this.$refs['labelForm'].validate(valid => { + console.log(valid) + if (valid) { + _this.isShowPop = false; + debugger + //缂栬緫纭畾 + 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); + } + }, + chnageActPage () { + + }, + showCurPos (e) { + console.log(e); + this.isShowCurPos = true; + this.traceX = e.offsetX; + this.traceY = e.offsetY; + }, + 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 + let fileReader = new FileReader() + fileReader.onload = () => { + this.userImg = fileReader.result + } + if (_file) { + fileReader.readAsDataURL(_file) + } + }, + getAllCameraData () { + getCamerasByServer().then(res => { + if (res.success) { + this.cameraData = res.data; + } + }).catch(e => { + console.log(e) + }) + }, + bindListen (e) { this.newLabel(e); }, - newLabel(e){ + newLabel (e) { console.log('鐐瑰嚮浜嗙敾鏉�') - if(this.isShowPop) return; + if (this.isShowPop) return; //鑾峰彇榧犳爣鐩稿浜庣敾鏉跨殑瀹氫綅 console.log('鑾峰彇褰撳墠瀹氫綅淇℃伅'); + this.$refs['labelForm'].resetFields(); let target = { - id:'', - x:e.offsetX, - y:e.offsetY, - posX:'', - posY:'' + id: '', + x0: e.offsetX, + y0: e.offsetY, + x1: '', + y1: '' }; - this.labels.push(target); + 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){ + editLabel (label) { debugger - if(!this.isEdit) return; + 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(){ + cancle () { this.isShowPop = false; //濡傛灉鏄湭淇濆瓨杩囩殑label鐩存帴鍒犻櫎(鏈繚瀛樼殑灏辨槸labels鏁扮粍涓渶鍚庝竴涓�) - if(!this.curLabel.id){ - this.labels.pop(); + if (!this.curLabel.id) { + //this.labels.pop(); + this.curCameraData.coords.pop(); } }, - deleteLabel(){ - if(this.curLabel.id){ - //璇锋眰鍚庡彴鍒犻櫎 - }else{ - this.labels.pop(); - this.isShowPop = false; - } - }, - submitInfo(){ + 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"> .right-side { - height: 100%; background: #d2dcea; + .figure { + .el-tabs__content { + background: #d2dcea; + height: calc(100vh - 85px); + } + } .tool-bar { - width: 100%; - height: 60px; - padding: 10px 20px; + //width: 40px; + height: 100%; + padding: 10px 0 10px 20px; box-sizing: border-box; - background: rgb(250, 250, 250); - margin-bottom: 40px; + //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: rgb(245, 245, 245); + //background: rgba(245, 245, 245, 0.3); padding: 0 5px; height: 40px; margin: 7px; @@ -170,95 +444,201 @@ label { margin-right: 10px; color: rgb(161, 161, 161); + color: #fff; } .el-slider { width: 110px; } } } - .action-bar{ + .shadow-box { + box-shadow: 3px 3px 3px 1px rgba(0, 0, 0, 0.1); + } + .action-bar { width: 960px; margin: auto; - margin-bottom: 20px; + margin-top: 30px; + //margin-bottom: 20px; text-align: right; - .drawboard-trigger{ + .drawboard-trigger { background: transparent; color: #fff; - border-color: rgba(255,255,255,.3); + border-color: rgba(255, 255, 255, 0.3); } } .drawboard { margin: auto; width: 960px; height: 540px; + margin-bottom: 130px; position: relative; - background: #fff; - box-shadow: 3px 3px 3px 1px rgba(0, 0, 0, 0.1); - .mask{ + //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{ + &.edit-status-mask { background: rgba(20, 181, 255, 0.1); } - .label{ + .label { position: absolute; z-index: 2; border-radius: 50%; } } - img{ + img { width: 960px; height: 540px; - background:#f0ffca; + background: #f0ffca; } - .popBox{ + .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(0,0,0,.7); - .title{ + 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{ + .details { + .detail-item { display: flex; - align-items: center; margin: 5px 0; - label{ - color: #ccc; - width:65px; + label { + color: #a9a9a9; + width: 65px; display: inline-block; } - .left{ + .left { width: 110px; text-align: left; line-height: 28px; - .fix-width{ + .fix-width { display: inline-block; width: 23px; } } - .right{ + .right { width: 160px; } - .devide{ + .devide { width: 10px; height: 1px; - background: #ccc; - margin: 0 3px; + background: #a9a9a9; + margin: 14px 3px; } } - .btns{ - margin-top: 10px; + .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 + } + } + .img-card { + } + .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; + } + .upload-demo .el-upload__text { + position: absolute; + top: -24px; + left: 50%; + margin-left: -91px; + } + .upload-demo .preview { + object-fit: contain; + //position: relative; + // width: 100%; + // height: 100%; + } + .upload-demo .preview img { + // position: absolute; + // top: 50%; + // left: 50%; + // transform: translate(-50%, -50%); + // width: 100%; + // height: 100%; + } + } +} +.el-input__inner:focus { + outline: none; + border-color: rgba(42, 56, 93, 71%) !important; +} +.el-upload-dragger:hover { + border-color: rgba(42, 56, 93, 71%) !important; } </style> \ No newline at end of file -- Gitblit v1.8.0