支持服务端抽稀和服务发布

This commit is contained in:
lin
2025-11-02 23:50:07 +08:00
parent 2a5435c810
commit 311b59870c
29 changed files with 1930 additions and 367 deletions

View File

@@ -5,7 +5,7 @@
<el-page-header content="编辑通道" @back="close" />
</div>
</div>
<CommonChannelEdit :id="id" ref="commonChannelEdit" :save-success="close" :cancel="close" />
<CommonChannelEdit :id="id" ref="commonChannelEdit" :showCancel="true" @submitSuccess="close" @cancel="close" />
</div>
</template>

View File

@@ -1,5 +1,5 @@
<template>
<div id="CommonChannelEdit" v-loading="loading" style="width: 100%">
<div id="CommonChannelEdit" v-loading="loading" style="width: 100%; overflow: auto; height: calc(-148px + 100vh);">
<el-form ref="channelForm" :model="form" :rules="rules" status-icon label-width="160px" class="channel-form" size="medium">
<div class="form-box">
<el-form-item label="名称" prop="gbName">
@@ -13,7 +13,7 @@
</el-input>
</el-form-item>
<el-form-item label="设备厂商">
<el-input v-model="gbManufacturer" placeholder="请输入设备厂商" />
<el-input v-model="form.gbManufacturer" placeholder="请输入设备厂商" />
</el-form-item>
<el-form-item label="设备型号">
<el-autocomplete
@@ -252,7 +252,7 @@
</el-form-item>
<div style="text-align: right">
<el-button type="primary" @click="onSubmit" >保存</el-button>
<el-button v-if="cancel" @click="cancelSubmit" >取消</el-button>
<el-button v-if="showCancel" @click="cancelSubmit" >取消</el-button>
<el-button v-if="form.dataType === 1" @click="reset">重置</el-button>
</div>
</div>
@@ -276,7 +276,7 @@ export default {
ChooseGroup,
channelCode
},
props: ['id', 'dataForm', 'saveSuccess', 'cancel'],
props: ['id', 'dataForm', 'showCancel'],
data() {
return {
rules: {
@@ -303,7 +303,7 @@ export default {
created() {
// 获取完整信息
if (this.id) {
this.getCommonChannel()
this.getCommonChannel(this.id)
} else {
if (!this.dataForm.gbDeviceId) {
this.dataForm.gbDeviceId = ''
@@ -335,9 +335,7 @@ export default {
showClose: true,
message: '保存成功'
})
if (this.saveSuccess) {
this.saveSuccess()
}
this.$emit('submitSuccess')
}).finally(() => {
this.loading = false
})
@@ -378,7 +376,7 @@ export default {
showClose: true,
message: '重置成功 已保存'
})
this.getCommonChannel()
this.getCommonChannel(this.form.gbId)
}
}).catch((error) => {
console.error(error)
@@ -389,9 +387,9 @@ export default {
})
},
getCommonChannel: function() {
getCommonChannel: function(id) {
this.loading = true
this.$store.dispatch('commonChanel/queryOne', this.id)
this.$store.dispatch('commonChanel/queryOne', id)
.then(data => {
if (data.gbDownloadSpeed) {
data.gbDownloadSpeedArray = data.gbDownloadSpeed.split('/')
@@ -422,9 +420,7 @@ export default {
})
},
cancelSubmit: function() {
if (this.cancel) {
this.cancel()
}
this.$emit('cancel')
},
getPaths: function() {
this.parentPath = []

View File

@@ -31,7 +31,7 @@ import { fromLonLat, toLonLat } from './map/TransformLonLat'
import { v4 } from 'uuid'
import { getUid } from 'ol'
import {Fill} from "ol/style";
import { Fill } from 'ol/style'
let olMap, tileLayer = null
export default {
@@ -158,6 +158,9 @@ export default {
source: source,
style: function(feature) {
let status = feature.properties_.gbStatus
if (layer.get('hideFeatures').includes(feature.properties_.gbId)) {
return new Style()
}
if (status === 'ON') {
return new Style({
image: new Icon({
@@ -203,6 +206,7 @@ export default {
// // ]
// }
})
layer.set('hideFeatures', [])
olMap.addLayer(layer)
if (clickEvent) {
layer.on('click', (event) => {
@@ -363,8 +367,6 @@ export default {
return vectorLayer
},
createPointLayer(data, clickEvent, option){
console.log(444)
console.log(data)
const features = []
let maxZoom = (option && option.maxZoom) ? option.maxZoom : olMap.getView().getMaxZoom()
let minZoom = (option && option.minZoom) ? option.minZoom : olMap.getView().getMinZoom()
@@ -498,7 +500,7 @@ export default {
updatePointLayer(layer, data, postponement) {
console.log(data)
layer.getSource().clear(true)
if (!data || data.length == 0) {
if (!data || data.length === 0) {
return
}
const features = []
@@ -567,12 +569,15 @@ export default {
feature.setStyle(style)
olMap.render()
},
hideFeature(layer, featureId) {
layer.get('hideFeatures').add(featureId)
},
cancelHideFeature(layer, featureId) {
let index = layer.get('hideFeatures').indexOf(featureId)
layer.get('hideFeatures').splice(index, 1)
},
setFeaturePositionById(layer, featureId, data) {
if (layer instanceof LayerGroup) {
}else {
}
let featureOld = layer.getSource().getFeatureById(featureId)
if (featureOld) {
layer.getSource().removeFeature(featureOld)
@@ -743,6 +748,11 @@ export default {
},
getCoordSys(){
return this.mapTileList[this.mapTileIndex].coordinateSystem
},
refreshLayer(layer){
if (layer && layer.getSource()) {
layer.getSource().refresh()
}
}
}
}

View File

@@ -5,7 +5,7 @@
<el-page-header content="编辑通道" @back="close" />
</div>
</div>
<CommonChannelEdit :id="id" ref="commonChannelEdit" :save-success="close" :cancel="close" />
<CommonChannelEdit :id="id" ref="commonChannelEdit" :showCancel="true" @submitSuccess="close" @cancel="close" />
</div>
</template>

View File

@@ -0,0 +1,78 @@
<template>
<div id="commonChannelEditDialog">
<el-dialog
v-el-drag-dialog
title="通道编辑"
width="90%"
top="2rem"
:append-to-body="true"
:close-on-click-modal="false"
:visible.sync="showDialog"
:destroy-on-close="true"
@close="close()"
>
<CommonChannelEdit style="overflow: auto !important;" ref="commonChannelEdit" :showCancel="true" :id="channelId" @cancel="close" @submitSuccess="close"></CommonChannelEdit>
</el-dialog>
</div>
</template>
<script>
import elDragDialog from '@/directive/el-drag-dialog'
import CommonChannelEdit from '../common/CommonChannelEdit.vue'
export default {
name: 'CommonChannelEditDialog',
components: { CommonChannelEdit },
directives: { elDragDialog },
props: ['platformId', 'platformDeviceId'],
data() {
return {
submitCallback: null,
showDialog: false,
channelId: null
}
},
computed: {},
created() {},
methods: {
openDialog: function(id) {
console.log(id)
this.channelId = id
this.showDialog = true
this.$refs.commonChannelEdit.getCommonChannel(this.channelId)
},
onSubmit: function() {
this.$refs['form'].validate((valid) => {
if (valid) {
this.$axios({
method: 'post',
url: `/api/platform/catalog/${!this.isEdit ? 'add' : 'edit'}`,
data: this.form
}).then((res) => {
if (res.data.code === 0) {
if (this.submitCallback) this.submitCallback(this.form)
} else {
this.$message({
showClose: true,
message: res.data.msg,
type: 'error'
})
}
this.close()
})
.catch((error) => {
console.log(error)
})
} else {
return false
}
})
},
close: function() {
this.channelId = null
this.showDialog = false
}
}
}
</script>

View File

@@ -22,7 +22,7 @@
</el-tab-pane>
<el-tab-pane label="国标通道配置">
<CommonChannelEdit :id="jtChannel.gbId" ref="commonChannelEdit" :data-form="jtChannel" :cancel="close" />
<CommonChannelEdit :id="jtChannel.gbId" ref="commonChannelEdit" :data-form="jtChannel" @cancel="close" />
</el-tab-pane>
</el-tabs>
</div>

View File

@@ -0,0 +1,84 @@
<template>
<div id="drawThinProgress" v-loading="isLoging">
<el-dialog
v-el-drag-dialog
width="240px"
top="13%"
:append-to-body="true"
:close-on-click-modal="false"
:visible.sync="showDialog"
:destroy-on-close="true"
:show-close="true"
style="text-align: center"
@close="close()"
>
<el-progress type="circle" :percentage="percentage" />
<div style="text-align: center">
{{ msg }}
</div>
</el-dialog>
</div>
</template>
<script>
import elDragDialog from '@/directive/el-drag-dialog'
export default {
name: 'drawThinProgress',
directives: { elDragDialog },
props: ['platformId'],
data() {
return {
endCallBack: null,
syncStatus: null,
percentage: 0,
showDialog: false,
isLoging: false,
syncFlag: false,
drawThinId: null,
timer: null,
errorTimer: null,
msg: '正在同步'
}
},
computed: {},
created() {},
methods: {
openDialog: function(drawThinId, endCallBack) {
console.log('drawThinId: ' + drawThinId)
this.drawThinId = drawThinId
this.showDialog = true
this.msg = ''
this.percentage = 0
this.syncFlag = false
this.syncStatus = null
this.endCallBack = endCallBack
this.getProgress()
},
getProgress() {
this.$store.dispatch('commonChanel/thinProgress', this.drawThinId)
.then(({ data }) => {
this.syncFlag = true
this.percentage = data.process * 100
this.msg = data.msg
console.log('drawThinId: ' + data.drawThinId)
this.timer = setTimeout(this.getProgress, 300)
}).catch((error) => {
this.syncStatus = 'error'
this.msg = error
window.clearTimeout(this.errorTimer)
this.errorTimer = setTimeout(() => {
this.showDialog = false
}, 2000)
})
},
close: function() {
if (this.endCallBack) {
this.endCallBack()
}
window.clearTimeout(this.timer)
}
}
}
</script>

View File

@@ -11,31 +11,23 @@
</div>
</div>
<div class="map-tool-btn-group" v-if="mapTileList.length > 0">
<el-dropdown placement="top" @command="changeLayerStyle">
<el-dropdown placement="top" @command="changeLayerType">
<div class="el-dropdown-link map-tool-btn">
<i class="iconfont icon-mti-jutai"></i>
</div>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item :command="0" >
<span v-if="layerStyle !== 0">图层关闭</span>
<span v-if="layerStyle === 0" style="color: rgb(64, 158, 255);">图层关闭</span>
<span v-if="layerType !== 0">图层关闭</span>
<span v-if="layerType === 0" style="color: rgb(64, 158, 255);">图层关闭</span>
</el-dropdown-item>
<el-dropdown-item :command="1" >
<span v-if="layerStyle !== 1">直接展示</span>
<span v-if="layerStyle === 1" style="color: rgb(64, 158, 255);">直接展示</span>
<span v-if="layerType !== 1">直接展示</span>
<span v-if="layerType === 1" style="color: rgb(64, 158, 255);">直接展示</span>
</el-dropdown-item>
<el-dropdown-item :command="2">
<span v-if="layerStyle !== 2">碰撞检测</span>
<span v-if="layerStyle === 2" style="color: rgb(64, 158, 255);">碰撞检测</span>
<span v-if="layerType !== 2">抽稀图层</span>
<span v-if="layerType === 2" style="color: rgb(64, 158, 255);">抽稀图层</span>
</el-dropdown-item>
<el-dropdown-item :command="3">
<span v-if="layerStyle !== 3">抽稀图层</span>
<span v-if="layerStyle === 3" style="color: rgb(64, 158, 255);">抽稀图层</span>
</el-dropdown-item>
<!-- <el-dropdown-item :command="4">-->
<!-- <span v-if="layerStyle !== 4">聚合图层</span>-->
<!-- <span v-if="layerStyle === 4" style="color: rgb(64, 158, 255);">聚合图层</span>-->
<!-- </el-dropdown-item>-->
</el-dropdown-menu>
</el-dropdown>
</div>
@@ -77,7 +69,7 @@
<el-slider v-model="diffPixels" show-input :min="10" :max="200" input-size="mini" ></el-slider>
<div style="margin-left: 10px; line-height: 38px;">
<el-button :loading="quicklyDrawThinLoading" @click="quicklyDrawThin" size="mini">快速抽稀</el-button>
<el-button size="mini" @click="boxDrawThin" >局部抽稀</el-button>
<el-button :loading="boxDrawThinLoading" size="mini" @click="boxDrawThin" >局部抽稀</el-button>
<el-button size="mini" @click="resetDrawThinData()">数据还原</el-button>
<el-button :loading="saveDrawThinLoading" type="primary" :disabled="!layerGroupSource" size="mini" @click="saveDrawThin()">保存</el-button>
<el-button type="warning" size="mini" @click="showDrawThinBox(false)">取消</el-button>
@@ -107,7 +99,8 @@
</el-descriptions>
<div style="padding-top: 10px; margin: 0 auto; width: fit-content;">
<el-button v-bind:disabled="channel.gbStatus !== 'ON'" type="primary" size="small" title="播放" icon="el-icon-video-play" @click="play(channel)">播放</el-button>
<el-button type="primary" size="small" title="编辑位置" icon="el-icon-edit" @click="edit(channel)">编辑</el-button>
<el-button type="primary" size="small" title="编辑" icon="el-icon-edit" @click="edit(channel)">编辑</el-button>
<el-button type="primary" size="small" title="位置" icon="el-icon-coordinate" @click="editPosition(channel)">位置</el-button>
<!-- <el-button type="primary" size="small" title="轨迹查询" icon="el-icon-map-location" @click="getTrace(channel)">轨迹</el-button>-->
</div>
<span class="infobox-close el-icon-close" @click="closeInfoBox"></span>
@@ -119,7 +112,7 @@
<div ref="infoboxForEdit">
<transition name="el-zoom-in-center">
<div class="infobox-edit-content" v-if="dragChannel">
<div style="width: 100%; height: 2rem; line-height: 1.5rem; font-size: 14px">{{dragChannel.gbName}} ({{dragChannel.gbDeviceId}})</div>
<div style="width: 100%; line-height: 1.5rem; font-size: 14px">{{dragChannel.gbName}} ({{dragChannel.gbDeviceId}})</div>
<span style="font-size: 14px">经度:</span> <el-input v-model="dragChannel.gbLongitude" placeholder="请输入经度" style="width: 7rem; margin-right: 10px"></el-input>
<span style="font-size: 14px">纬度: </span> <el-input v-model="dragChannel.gbLatitude" placeholder="请输入纬度" style="width: 7rem; "></el-input>
<el-button icon="el-icon-close" size="medium" type="text" @click="cancelEdit(dragChannel)" style="margin-left: 1rem; font-size: 18px; color: #2b2f3a"></el-button>
@@ -129,6 +122,8 @@
</div>
<devicePlayer ref="devicePlayer" ></devicePlayer>
<queryTrace ref="queryTrace" ></queryTrace>
<CommonChannelEditDialog ref="commonChannelEditDialog" ></CommonChannelEditDialog>
<DrawThinProgress ref="drawThinProgress" ></DrawThinProgress>
</div>
</template>
@@ -137,15 +132,19 @@ import DeviceTree from '../common/DeviceTree.vue'
import queryTrace from './queryTrace.vue'
import MapComponent from '../common/MapComponent.vue'
import devicePlayer from '../common/channelPlayer/index.vue'
import CommonChannelEditDialog from '../dialog/commonChannelEditDialog.vue'
import DrawThinProgress from './dialog/drawThinProgress.vue'
let cameraListForSource = []
let cameraList = []
let cameraListForLevelMap = new Map()
let cameraLayerExtent = []
let channelLayer = null
let channelLayer, channelTileLayer = null
export default {
name: 'Map',
components: {
DrawThinProgress,
CommonChannelEditDialog,
DeviceTree,
devicePlayer,
queryTrace,
@@ -170,9 +169,11 @@ export default {
zoomValue: 10,
showDrawThin: false,
quicklyDrawThinLoading: false,
saveDrawThinLoading: false,
layerStyle: 0,
boxDrawThinLoading: false,
drawThinId: null,
drawThinLayer: null,
saveDrawThinLoading: false,
layerType: 0,
layerGroupSource: null
}
},
@@ -184,64 +185,32 @@ export default {
},
methods: {
initChannelLayer: function () {
this.mapTileList = this.$refs.mapComponent.mapTileList
// 获取所有有位置的通道
this.closeInfoBox()
this.$store.dispatch('commonChanel/getAllForMap', {}).then(data => {
cameraListForSource = data
console.log(data.length)
let minLng = data[0].gbLongitude
let maxLng = data[0].gbLongitude
let minLat = data[0].gbLatitude
let maxLat = data[0].gbLatitude
for (let i = 1; i < data.length; i++) {
let item = data[i]
if (item.gbLongitude < minLng) {
minLng = item.gbLongitude
let clientEvent = data => {
this.closeInfoBox()
this.$nextTick(() => {
if (data[0].edit) {
this.showEditInfo(data[0])
}else {
this.showChannelInfo(data[0])
}
if (item.gbLongitude > maxLng) {
maxLng = item.gbLongitude
}
if (item.gbLatitude < minLat) {
minLat = item.gbLatitude
}
if (item.gbLatitude > maxLat) {
maxLat = item.gbLatitude
}
if (item.gbLongitude && item.gbLatitude) {
let position = [item.gbLongitude, item.gbLatitude]
let cameraData = {
id: item.gbId,
position: position,
status: item.gbStatus,
data: item,
image: {
anchor: [0.5, 1],
src: this.getImageByChannel(item)
}
}
cameraList.push(cameraData)
if (item.mapLevel) {
if (cameraListForLevelMap.has(item.mapLevel)) {
let list = cameraListForLevelMap.get(item.mapLevel)
list.push(cameraData)
}else {
cameraListForLevelMap.set(item.mapLevel, [cameraData])
}
}else {
cameraListForLevelMap.set(0, [cameraData])
}
}
}
cameraLayerExtent = [minLng, minLat, maxLng, maxLat]
this.updateChannelLayer()
})
})
}
channelLayer = this.$refs.mapComponent.addPointLayer([], clientEvent, null)
},
refreshLayer(){
this.closeInfoBox()
this.$refs.mapComponent.clearLayer(channelLayer)
this.initChannelLayer()
// 刷新瓦片图层
if (channelLayer) {
this.$refs.mapComponent.refreshLayer(channelLayer)
}
if (channelTileLayer) {
this.$refs.mapComponent.refreshLayer(channelTileLayer)
}
},
treeChannelClickEvent: function (id) {
this.closeInfoBox()
@@ -281,7 +250,18 @@ export default {
}
},
{
label: '编辑位置',
label: '修改位置',
icon: 'el-icon-coordinate',
type: 1,
onClick: (event, data, node) => {
this.$store.dispatch('commonChanel/queryOne', data.id)
.then(data => {
this.editPosition(data)
})
}
},
{
label: '编辑通道',
icon: 'el-icon-edit',
type: 1,
onClick: (event, data, node) => {
@@ -291,15 +271,6 @@ export default {
})
}
}
// ,
// {
// label: '轨迹查询',
// icon: 'el-icon-map-location',
// type: 1,
// onClick: (event, data, node) => {
//
// }
// }
]
},
showChannelInfo: function(data) {
@@ -312,9 +283,8 @@ export default {
data: data,
status: data.gbStatus
}
if (!this.$refs.mapComponent.hasFeature(channelLayer, data.gbId)) {
this.$refs.mapComponent.addFeature(channelLayer, cameraData)
}
this.$refs.mapComponent.addFeature(channelLayer, cameraData)
this.infoBoxId = this.$refs.mapComponent.openInfoBox(position, this.$refs.infobox, [0, -50])
},
zoomChange: function(zoom) {},
@@ -329,74 +299,37 @@ export default {
}
this.$refs.mapComponent.changeMapTile(index)
},
changeLayerStyle: function (index) {
if (this.layerStyle === index) {
clientEvent(data){
this.closeInfoBox()
this.$nextTick(() => {
if (data[0].edit) {
this.showEditInfo(data[0])
}else {
this.showChannelInfo(data[0])
}
})
},
changeLayerType: function (index) {
if (this.layerType === index) {
return
}
this.layerStyle = index
this.$refs.mapComponent.removeLayer(channelLayer)
this.channelLayer = null
this.updateChannelLayer()
},
updateChannelLayer: function() {
let clientEvent = data => {
this.closeInfoBox()
this.$nextTick(() => {
if (data[0].edit) {
this.showEditInfo(data[0])
}else {
this.showChannelInfo(data[0])
}
})
this.layerType = index
if (index === 0) {
this.$refs.mapComponent.removeLayer(channelTileLayer)
}
switch (this.layerStyle) {
case 0:
channelLayer = this.$refs.mapComponent.addPointLayer([], clientEvent, null)
break
case 1:
console.log(22221112222)
console.log(channelLayer)
// 直接展示
if (channelLayer) {
channelLayer = this.$refs.mapComponent.updatePointLayer(channelLayer, cameraList, true)
}else {
console.log(cameraList.length)
setTimeout(() => {
channelLayer = this.$refs.mapComponent.addPointLayer(cameraList, clientEvent, null)
})
}
break
case 2:
// 碰撞检测
if (channelLayer) {
channelLayer = this.$refs.mapComponent.updatePointLayer(channelLayer, cameraList, true)
}else {
setTimeout(() => {
channelLayer = this.$refs.mapComponent.addPointLayer(cameraList, clientEvent, {
declutter: true
})
})
}
break
case 3:
// 抽稀图层
this.$refs.mapComponent.removeLayer(channelLayer)
channelLayer = this.$refs.mapComponent.addPointLayerGroup(cameraListForLevelMap, clientEvent)
break
// case 4:
// // 聚合图层
//
// break
}
},
getImageByChannel: function (channel) {
if (channel.gbStatus === 'ON') {
return 'static/images/gis/camera1.png'
} else {
return 'static/images/gis/camera1-offline.png'
let geoCoordSys = this.$refs.mapComponent.getCoordSys()
const baseUrl = window.baseUrl ? window.baseUrl : ''
let baseApi = ((process.env.NODE_ENV === 'development') ? process.env.VUE_APP_BASE_API : baseUrl)
let tileUrl = null
if (index === 1) {
tileUrl = baseApi + `/api/common/channel/map/tile/{z}/{x}/{y}?geoCoordSys=${geoCoordSys}&accessToken=${this.$store.getters.token}`
}else if (index === 2) {
tileUrl = baseApi + `/api/common/channel/map/thin/tile/{z}/{x}/{y}?geoCoordSys=${geoCoordSys}&accessToken=${this.$store.getters.token}`
}else {
return
}
channelTileLayer = this.$refs.mapComponent.addVectorTileLayer(tileUrl. this.clientEvent)
},
closeInfoBox: function () {
if (this.infoBoxId !== null) {
@@ -423,6 +356,9 @@ export default {
})
},
edit: function (channel) {
this.$refs.commonChannelEditDialog.openDialog(channel.gbId)
},
editPosition: function (channel) {
this.closeInfoBox()
// 开启图标可拖动
this.$refs.mapComponent.dragInteraction.addFeatureId(channel.gbId,
@@ -459,6 +395,7 @@ export default {
}else {
this.showEditInfo(channel)
}
// 标记可编辑图标为红色
this.$refs.mapComponent.setFeaturePositionById(channelLayer, channel.gbId, {
id: channel.gbId,
@@ -466,6 +403,10 @@ export default {
data: channel,
status: 'checked'
})
// 如果开启了瓦片图层此时应该让瓦片图层不再显示这个feature
if (channelTileLayer) {
this.$refs.mapComponent.hideFeature(channelTileLayer, channel.gbId)
}
},
showEditInfo: function(data) {
this.dragChannel = data
@@ -483,6 +424,9 @@ export default {
data: channel,
status: channel.gbStatus
})
if (channelTileLayer) {
this.$refs.mapComponent.cancelHideFeature(channelTileLayer, channel.gbId)
}
},
submitEdit: function(channel) {
let position = [channel.gbLongitude, channel.gbLatitude]
@@ -507,89 +451,65 @@ export default {
})
},
getTrace: function (data) {
this.clean()
this.$refs.queryTrace.openDialog(data, (channelPositions) => {
if (channelPositions.length === 0) {
this.$message.warning({
showClose: true,
message: '未查询到轨迹信息'
})
} else {
let positions = []
for (let i = 0; i < channelPositions.length; i++) {
if (channelPositions[i][this.longitudeStr] * channelPositions[i][this.latitudeStr] > 0) {
positions.push([channelPositions[i][this.longitudeStr], channelPositions[i][this.latitudeStr]])
}
}
if (positions.length === 0) {
this.$message.warning({
showClose: true,
message: '未查询到轨迹信息'
})
return
}
}
})
},
clean: function (){
if (this.infoBoxId !== null) {
this.$refs.mapComponent.closeInfoBox(this.infoBoxId)
}
},
testArray: function (){
this.$store.dispatch('commonChanel/test')
},
showDrawThinBox: function(show){
this.showDrawThin = show
setTimeout(() => {
if (!show) {
// 关闭抽稀预览
if (this.drawThinId !== null) {
// 发送消息 清空抽稀结果
this.$store.dispatch('commonChanel/clearThin', this.drawThinId)
this.drawThinId = null
}
if (this.drawThinLayer !== null) {
this.$refs.mapComponent.removeLayer(this.drawThinLayer)
this.drawThinLayer = null
}
// 清空预览数据
this.layerGroupSource = null
this.updateChannelLayer()
}else {
//
}
}, 1)
},
quicklyDrawThin: function (){
if (this.channelLayer) {
if (channelLayer) {
this.$refs.mapComponent.removeLayer(channelLayer)
}
if (channelTileLayer) {
this.$refs.mapComponent.removeLayer(channelTileLayer)
}
if (this.drawThinLayer !== null) {
this.$refs.mapComponent.removeLayer(this.drawThinLayer)
this.drawThinLayer = null
}
// 获取待抽稀数据
let cameraList = cameraListForSource.slice()
this.quicklyDrawThinLoading = true
setTimeout(() => {
this.drawThin(cameraList).then((layerGroupSource) => {
this.layerGroupSource = layerGroupSource
this.drawThinLayer = this.$refs.mapComponent.addPointLayerGroup(layerGroupSource, data => {
console.log(222)
console.log(this.getDrawThinParam())
// 获取每一个图层的抽稀参数
this.$store.dispatch('commonChanel/drawThin', {
zoomParam: this.getDrawThinParam()
})
.then(drawThinId => {
// 显示抽稀进度
this.drawThinId = drawThinId
this.$refs.drawThinProgress.openDialog(drawThinId, () => {
this.closeInfoBox()
// this.$nextTick(() => {
// if (data[0].edit) {
// this.showEditInfo(data[0])
// }else {
// this.showChannelInfo(data[0])
// }
// })
})
this.quicklyDrawThinLoading = false
this.$message.success({
showClose: true,
message: '抽稀完成,请预览无误后保存抽稀结果'
this.$message.success({
showClose: true,
message: '抽稀完成,请预览无误后保存抽稀结果'
})
// 展示抽稀结果
this.showDrawThinLayer(drawThinId)
})
})
})
.finally(() => {
this.quicklyDrawThinLoading = false
})
},
showDrawThinLayer(thinId) {
// 展示抽稀结果
let geoCoordSys = this.$refs.mapComponent.getCoordSys()
const baseUrl = window.baseUrl ? window.baseUrl : ''
let baseApi = ((process.env.NODE_ENV === 'development') ? process.env.VUE_APP_BASE_API : baseUrl)
let tileUrl = baseApi + `/api/common/channel/map/thin/tile/{z}/{x}/{y}?geoCoordSys=${geoCoordSys}&thinId=${thinId}&accessToken=${this.$store.getters.token}`
this.drawThinLayer = this.$refs.mapComponent.addVectorTileLayer(tileUrl, null)
},
boxDrawThin: function (){
this.$message.warning({
@@ -601,92 +521,54 @@ export default {
// 清理默认的摄像头图层
if (channelLayer) {
this.$refs.mapComponent.clearLayer(channelLayer)
this.$refs.mapComponent.removeLayer(channelLayer)
}
this.$message.warning({
showClose: true,
message: '正在抽稀,请稍等'
if (channelTileLayer) {
this.$refs.mapComponent.removeLayer(channelTileLayer)
}
if (this.drawThinLayer !== null) {
this.$refs.mapComponent.removeLayer(this.drawThinLayer)
this.drawThinLayer = null
}
this.boxDrawThinLoading = true
// 获取每一个图层的抽稀参数
this.$store.dispatch('commonChanel/drawThin', {
zoomParam: this.getDrawThinParam(),
extent: extent
})
setTimeout(() => {
let zoomExtent = this.$refs.mapComponent.getZoomExtent()
let cameraListInExtent = []
let cameraListOutExtent = []
if (this.layerGroupSource !== null) {
// 从当前预览的数据里,获取待抽稀的数据
let sourceCameraList = this.layerGroupSource.get(0)
console.log(sourceCameraList)
if (!sourceCameraList) {
this.$message.warning({
showClose: true,
message: '数据已经全部抽稀'
})
return
}
for (let i = 0; i < sourceCameraList.length; i++) {
let value = sourceCameraList[i]
if (!value.data.gbLongitude || !value.data.gbLatitude) {
continue
}
if (value.data.gbLongitude >= extent[0] && value.data.gbLongitude <= extent[2]
&& value.data.gbLatitude >= extent[1] && value.data.gbLatitude <= extent[3]) {
cameraListInExtent.push(value.data)
}else {
cameraListOutExtent.push(value.data)
}
}
}else {
for (let i = 0; i < cameraListForSource.length; i++) {
let value = cameraListForSource[i]
if (!value.gbLongitude || !value.gbLatitude) {
continue
}
if (value.gbLongitude >= extent[0] && value.gbLongitude <= extent[2]
&& value.gbLatitude >= extent[1] && value.gbLatitude <= extent[3]) {
cameraListInExtent.push(value)
}else {
cameraListOutExtent.push(value)
}
}
}
// 如果已经在预览,清理预览图层
if (this.drawThinLayer !== null) {
this.$refs.mapComponent.removeLayer(this.drawThinLayer)
this.drawThinLayer = null
}
this.drawThin(cameraListInExtent).then((layerGroupSource) => {
if (this.layerGroupSource !== null) {
let zoom = zoomExtent[0]
// 按照层级合并每次的抽稀结果
while (zoom < zoomExtent[1]) {
Array.prototype.push.apply(layerGroupSource.get(zoom), this.layerGroupSource.get(zoom))
zoom += 1
}
}
if (cameraListOutExtent.length > 0) {
let layerSourceForOutExtent = this.createZoomLayerSource(cameraListOutExtent, zoomExtent[0])
layerGroupSource.set(0, layerSourceForOutExtent)
}
this.layerGroupSource = layerGroupSource
this.drawThinLayer = this.$refs.mapComponent.addPointLayerGroup(layerGroupSource, data => {
.then(drawThinId => {
// 显示抽稀进度
this.drawThinId = drawThinId
this.$refs.drawThinProgress.openDialog(drawThinId, () => {
this.closeInfoBox()
// this.$nextTick(() => {
// if (data[0].edit) {
// this.showEditInfo(data[0])
// }else {
// this.showChannelInfo(data[0])
// }
// })
})
this.$message.success({
showClose: true,
message: '抽稀完成,请预览无误后保存抽稀结果,如需继续,请再次点击局部抽稀按钮'
this.$message.success({
showClose: true,
message: '抽稀完成,请预览无误后保存抽稀结果'
})
// 展示抽稀结果
this.showDrawThinLayer(drawThinId)
})
})
}, 100)
.finally(() => {
this.boxDrawThinLoading = false
})
})
},
getDrawThinParam() {
// 获取全部层级
let zoomExtent = this.$refs.mapComponent.getZoomExtent()
let zoomMap = {}
let zoom = zoomExtent[0]
while (zoom < zoomExtent[1]) {
// 计算经纬度差值
let diff = this.$refs.mapComponent.computeDiff(this.diffPixels, zoom)
if (diff && diff > 0) {
zoomMap[zoom] = diff
}
zoom += 1
}
return zoomMap
},
drawThin: function (cameraListInExtent){
return new Promise((resolve, reject) => {
try {
@@ -778,30 +660,10 @@ export default {
return dataArray
},
saveDrawThin: function(){
if (!this.layerGroupSource) {
if (!this.drawThinId) {
return
}
this.saveDrawThinLoading = true
let param = []
let keys = Array.from(this.layerGroupSource.keys())
for (let i = 0; i < keys.length; i++) {
let zoom = keys[i]
let values = this.layerGroupSource.get(zoom)
for (let j = 0; j < values.length; j++) {
let value = values[j]
if (zoom === 0) {
param.push({
gbId: value.id
})
}else {
param.push({
gbId: value.id,
mapLevel: zoom
})
}
}
}
this.$store.dispatch('commonChanel/saveLevel', param)
this.$store.dispatch('commonChanel/saveThin', this.drawThinId)
.then((data) => {
this.$message.success({
showClose: true,
@@ -812,7 +674,6 @@ export default {
.finally(() => {
this.saveDrawThinLoading = false
})
},
resetDrawThinData(){
this.$confirm('确定移除抽稀结果?', '操作提示', {

989
web/src/views/map/index2.vue Executable file
View File

@@ -0,0 +1,989 @@
<template>
<div id="devicePosition" style="height: calc(100vh - 84px);width: 100%;">
<div style="height: 100%; display: grid; grid-template-columns: 360px auto">
<DeviceTree ref="deviceTree" @clickEvent="treeChannelClickEvent" :showPosition="true" :contextmenu="getContextmenu()"/>
<MapComponent ref="mapComponent" @loaded="initChannelLayer" @coordinateSystemChange="initChannelLayer" @zoomChange="zoomChange"></MapComponent>
</div>
<div class="map-tool-box-bottom-right">
<div class="map-tool-btn-group">
<div class="el-dropdown-link map-tool-btn" @click="addVectorTileLayer">
<i class="iconfont icon-mti-jutai"></i>
</div>
</div>
<div class="map-tool-btn-group" v-if="mapTileList.length > 0">
<el-dropdown placement="top" @command="changeLayerStyle">
<div class="el-dropdown-link map-tool-btn">
<i class="iconfont icon-mti-jutai"></i>
</div>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item :command="0" >
<span v-if="layerStyle !== 0">图层关闭</span>
<span v-if="layerStyle === 0" style="color: rgb(64, 158, 255);">图层关闭</span>
</el-dropdown-item>
<el-dropdown-item :command="1" >
<span v-if="layerStyle !== 1">直接展示</span>
<span v-if="layerStyle === 1" style="color: rgb(64, 158, 255);">直接展示</span>
</el-dropdown-item>
<el-dropdown-item :command="2">
<span v-if="layerStyle !== 2">碰撞检测</span>
<span v-if="layerStyle === 2" style="color: rgb(64, 158, 255);">碰撞检测</span>
</el-dropdown-item>
<el-dropdown-item :command="3">
<span v-if="layerStyle !== 3">抽稀图层</span>
<span v-if="layerStyle === 3" style="color: rgb(64, 158, 255);">抽稀图层</span>
</el-dropdown-item>
<!-- <el-dropdown-item :command="4">-->
<!-- <span v-if="layerStyle !== 4">聚合图层</span>-->
<!-- <span v-if="layerStyle === 4" style="color: rgb(64, 158, 255);">聚合图层</span>-->
<!-- </el-dropdown-item>-->
</el-dropdown-menu>
</el-dropdown>
</div>
<div class="map-tool-btn-group" v-if="mapTileList && mapTileList.length > 1">
<el-dropdown placement="top" @command="changeMapTile">
<div class="el-dropdown-link map-tool-btn">
<i class="iconfont icon-tuceng"></i>
</div>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item v-for="(item,index) in mapTileList" :key="index" :command="index">{{item.name}}</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
<div class="map-tool-btn-group">
<div class="map-tool-btn" @click="refreshLayer">
<i class="iconfont icon-shuaxin3"></i>
</div>
</div>
<div class="map-tool-btn-group">
<div class="map-tool-btn" @click="zoomIn">
<i class="iconfont icon-plus1"></i>
</div>
<div class="map-tool-btn" @click="zoomOut">
<i class="iconfont icon-minus1"></i>
</div>
</div>
</div>
<div class="map-tool-box-top-left">
<div class="map-tool-btn-group">
<div class="map-tool-btn" title="图层抽稀" @click="showDrawThinBox(true)">
<i class="iconfont icon-mti-sandian"></i> <span>图层抽稀</span>
</div>
</div>
</div>
<transition name="el-zoom-in-top">
<div v-show="showDrawThin" class="map-tool-draw-thin">
<div class="map-tool-draw-thin-density">
<span style="line-height: 36px; font-size: 15px">间隔 </span>
<el-slider v-model="diffPixels" show-input :min="10" :max="200" input-size="mini" ></el-slider>
<div style="margin-left: 10px; line-height: 38px;">
<el-button :loading="quicklyDrawThinLoading" @click="quicklyDrawThin" size="mini">快速抽稀</el-button>
<el-button size="mini" @click="boxDrawThin" >局部抽稀</el-button>
<el-button size="mini" @click="resetDrawThinData()">数据还原</el-button>
<el-button :loading="saveDrawThinLoading" type="primary" :disabled="!layerGroupSource" size="mini" @click="saveDrawThin()">保存</el-button>
<el-button type="warning" size="mini" @click="showDrawThinBox(false)">取消</el-button>
</div>
</div>
</div>
</transition>
<!-- <div class="map-tool-box-top-right">-->
<!-- <div class="map-tool-btn-group">-->
<!-- <div class="map-tool-btn" title="抽稀">-->
<!-- <i class="iconfont icon-mti-sandian"></i>-->
<!-- </div>-->
<!-- <div class="map-tool-btn" title="聚合">-->
<!-- <i class="iconfont icon-mti-jutai"></i>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<div ref="infobox">
<transition name="el-zoom-in-center">
<div class="infobox-content" v-if="channel">
<el-descriptions class="margin-top" :title="channel.gbName" :column="1" :colon="true" size="mini" :labelStyle="labelStyle" >
<el-descriptions-item label="编号" >{{channel.gbDeviceId}}</el-descriptions-item>
<el-descriptions-item label="生产厂商">{{channel.gbManufacture}}</el-descriptions-item>
<el-descriptions-item label="安装地址" >{{channel.gbAddress == null?'未知': channel.gbAddress}}</el-descriptions-item>
</el-descriptions>
<div style="padding-top: 10px; margin: 0 auto; width: fit-content;">
<el-button v-bind:disabled="channel.gbStatus !== 'ON'" type="primary" size="small" title="播放" icon="el-icon-video-play" @click="play(channel)">播放</el-button>
<el-button type="primary" size="small" title="编辑" icon="el-icon-edit" @click="edit(channel)">编辑</el-button>
<el-button type="primary" size="small" title="位置" icon="el-icon-coordinate" @click="editPosition(channel)">位置</el-button>
<!-- <el-button type="primary" size="small" title="轨迹查询" icon="el-icon-map-location" @click="getTrace(channel)">轨迹</el-button>-->
</div>
<span class="infobox-close el-icon-close" @click="closeInfoBox"></span>
</div>
</transition>
</div>
<div ref="infoboxForEdit">
<transition name="el-zoom-in-center">
<div class="infobox-edit-content" v-if="dragChannel">
<div style="width: 100%; line-height: 1.5rem; font-size: 14px">{{dragChannel.gbName}} ({{dragChannel.gbDeviceId}})</div>
<span style="font-size: 14px">经度:</span> <el-input v-model="dragChannel.gbLongitude" placeholder="请输入经度" style="width: 7rem; margin-right: 10px"></el-input>
<span style="font-size: 14px">纬度: </span> <el-input v-model="dragChannel.gbLatitude" placeholder="请输入纬度" style="width: 7rem; "></el-input>
<el-button icon="el-icon-close" size="medium" type="text" @click="cancelEdit(dragChannel)" style="margin-left: 1rem; font-size: 18px; color: #2b2f3a"></el-button>
<el-button icon="el-icon-check" size="medium" type="text" @click="submitEdit(dragChannel)" style="font-size: 18px; color: #0842e2"></el-button>
</div>
</transition>
</div>
<devicePlayer ref="devicePlayer" ></devicePlayer>
<queryTrace ref="queryTrace" ></queryTrace>
<CommonChannelEditDialog ref="commonChannelEditDialog" ></CommonChannelEditDialog>
</div>
</template>
<script>
import DeviceTree from '../common/DeviceTree.vue'
import queryTrace from './queryTrace.vue'
import MapComponent from '../common/MapComponent.vue'
import devicePlayer from '../common/channelPlayer/index.vue'
import CommonChannelEditDialog from "@/views/dialog/commonChannelEditDialog.vue";
let cameraListForSource = []
let cameraList = []
let cameraListForLevelMap = new Map()
let cameraLayerExtent = []
let channelLayer = null
export default {
name: 'Map',
components: {
CommonChannelEditDialog,
DeviceTree,
devicePlayer,
queryTrace,
MapComponent
},
data() {
return {
layer: null,
channel: null,
dragChannel: {},
feature: null,
device: null,
infoBoxId: null,
labelStyle: {
width: '56px'
},
isLoging: false,
longitudeStr: 'longitude',
latitudeStr: 'latitude',
mapTileList: [],
diffPixels: 60,
zoomValue: 10,
showDrawThin: false,
quicklyDrawThinLoading: false,
saveDrawThinLoading: false,
layerStyle: 0,
drawThinLayer: null,
layerGroupSource: null
}
},
created() {
},
destroyed() {
},
methods: {
initChannelLayer: function () {
this.mapTileList = this.$refs.mapComponent.mapTileList
// 获取所有有位置的通道
this.closeInfoBox()
this.$store.dispatch('commonChanel/getAllForMap', {}).then(data => {
cameraListForSource = data
console.log(data.length)
let minLng = data[0].gbLongitude
let maxLng = data[0].gbLongitude
let minLat = data[0].gbLatitude
let maxLat = data[0].gbLatitude
for (let i = 1; i < data.length; i++) {
let item = data[i]
if (item.gbLongitude < minLng) {
minLng = item.gbLongitude
}
if (item.gbLongitude > maxLng) {
maxLng = item.gbLongitude
}
if (item.gbLatitude < minLat) {
minLat = item.gbLatitude
}
if (item.gbLatitude > maxLat) {
maxLat = item.gbLatitude
}
if (item.gbLongitude && item.gbLatitude) {
let position = [item.gbLongitude, item.gbLatitude]
let cameraData = {
id: item.gbId,
position: position,
status: item.gbStatus,
data: item,
image: {
anchor: [0.5, 1],
src: this.getImageByChannel(item)
}
}
cameraList.push(cameraData)
if (item.mapLevel) {
if (cameraListForLevelMap.has(item.mapLevel)) {
let list = cameraListForLevelMap.get(item.mapLevel)
list.push(cameraData)
}else {
cameraListForLevelMap.set(item.mapLevel, [cameraData])
}
}else {
cameraListForLevelMap.set(0, [cameraData])
}
}
}
cameraLayerExtent = [minLng, minLat, maxLng, maxLat]
this.updateChannelLayer()
})
},
refreshLayer(){
this.closeInfoBox()
this.$refs.mapComponent.clearLayer(channelLayer)
this.initChannelLayer()
},
treeChannelClickEvent: function (id) {
this.closeInfoBox()
this.$store.dispatch('commonChanel/queryOne', id)
.then(data => {
if (!data.gbLongitude || data.gbLongitude < 0 || !data.gbLatitude || data.gbLatitude < 0) {
this.$message.warning({
showClose: true,
message: '无位置信息'
})
return
}
let zoomExtent = this.$refs.mapComponent.getZoomExtent()
this.$refs.mapComponent.panTo([data.gbLongitude, data.gbLatitude], zoomExtent[1], () => {
this.showChannelInfo(data)
})
})
},
zoomIn: function() {
this.$refs.mapComponent.zoomIn()
},
zoomOut: function() {
this.$refs.mapComponent.zoomOut()
},
getContextmenu: function (event) {
return [
{
label: '播放通道',
icon: 'el-icon-video-play',
type: 1,
onClick: (event, data, node) => {
console.log(data)
this.$store.dispatch('commonChanel/queryOne', data.id)
.then(data => {
this.play(data)
})
}
},
{
label: '编辑位置',
icon: 'el-icon-edit',
type: 1,
onClick: (event, data, node) => {
this.$store.dispatch('commonChanel/queryOne', data.id)
.then(data => {
this.edit(data)
})
}
}
// ,
// {
// label: '轨迹查询',
// icon: 'el-icon-map-location',
// type: 1,
// onClick: (event, data, node) => {
//
// }
// }
]
},
showChannelInfo: function(data) {
this.channel = data
// 此时增加临时图标
let position = [data.gbLongitude, data.gbLatitude]
let cameraData = {
id: data.gbId,
position: position,
data: data,
status: data.gbStatus
}
if (!this.$refs.mapComponent.hasFeature(channelLayer, data.gbId)) {
this.$refs.mapComponent.addFeature(channelLayer, cameraData)
}
this.infoBoxId = this.$refs.mapComponent.openInfoBox(position, this.$refs.infobox, [0, -50])
},
zoomChange: function(zoom) {},
changeMapTile: function (index) {
if (this.showDrawThin) {
this.$message.warning({
showClose: true,
message: '抽稀操作进行中,禁止切换图层'
})
return
}
this.$refs.mapComponent.changeMapTile(index)
},
changeLayerStyle: function (index) {
if (this.layerStyle === index) {
return
}
this.layerStyle = index
this.$refs.mapComponent.removeLayer(channelLayer)
this.channelLayer = null
this.updateChannelLayer()
},
updateChannelLayer: function() {
let clientEvent = data => {
this.closeInfoBox()
this.$nextTick(() => {
if (data[0].edit) {
this.showEditInfo(data[0])
}else {
this.showChannelInfo(data[0])
}
})
}
switch (this.layerStyle) {
case 0:
channelLayer = this.$refs.mapComponent.addPointLayer([], clientEvent, null)
break
case 1:
console.log(22221112222)
console.log(channelLayer)
// 直接展示
if (channelLayer) {
channelLayer = this.$refs.mapComponent.updatePointLayer(channelLayer, cameraList, true)
}else {
console.log(cameraList.length)
setTimeout(() => {
channelLayer = this.$refs.mapComponent.addPointLayer(cameraList, clientEvent, null)
})
}
break
case 2:
// 碰撞检测
if (channelLayer) {
channelLayer = this.$refs.mapComponent.updatePointLayer(channelLayer, cameraList, true)
}else {
setTimeout(() => {
channelLayer = this.$refs.mapComponent.addPointLayer(cameraList, clientEvent, {
declutter: true
})
})
}
break
case 3:
// 抽稀图层
this.$refs.mapComponent.removeLayer(channelLayer)
channelLayer = this.$refs.mapComponent.addPointLayerGroup(cameraListForLevelMap, clientEvent)
break
// case 4:
// // 聚合图层
//
// break
}
},
getImageByChannel: function (channel) {
if (channel.gbStatus === 'ON') {
return 'static/images/gis/camera1.png'
} else {
return 'static/images/gis/camera1-offline.png'
}
},
closeInfoBox: function () {
if (this.infoBoxId !== null) {
this.$refs.mapComponent.closeInfoBox(this.infoBoxId)
}
this.channel = null
this.dragChannel = null
},
play: function (channel) {
const loading = this.$loading({
lock: true,
text: '正在请求视频',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
})
this.$store.dispatch('commonChanel/playChannel', channel.gbId)
.then((data) => {
this.$refs.devicePlayer.openDialog('media', channel.gbId, {
streamInfo: data,
hasAudio: channel.hasAudio
})
}).finally(() => {
loading.close()
})
},
edit: function (channel) {
this.$refs.commonChannelEditDialog.openDialog(channel.gbId)
},
editPosition: function (channel) {
this.closeInfoBox()
// 开启图标可拖动
this.$refs.mapComponent.dragInteraction.addFeatureId(channel.gbId,
{
startEvent: event => {
this.closeInfoBox()
},
endEvent: event => {
channel.gbLongitude = event.lonLat[0]
channel.gbLatitude = event.lonLat[1]
this.showEditInfo(channel)
}
}
)
let position = null
if (!!channel.gbLongitude && !!channel.gbLatitude && channel.gbLongitude > 0 && channel.gbLatitude > 0) {
position = [channel.gbLongitude, channel.gbLatitude]
channel['oldLongitude'] = channel.gbLongitude
channel['oldLatitude'] = channel.gbLatitude
}else {
position = this.$refs.mapComponent.getCenter()
channel['oldLongitude'] = channel.gbLongitude
channel['oldLatitude'] = channel.gbLatitude
channel.gbLongitude = position[0]
channel.gbLatitude = position[1]
}
channel['edit'] = true
if (!this.$refs.mapComponent.coordinateInView(position)) {
this.$refs.mapComponent.panTo(position, 16, () => {
this.showEditInfo(channel)
})
}else {
this.showEditInfo(channel)
}
// 标记可编辑图标为红色
this.$refs.mapComponent.setFeaturePositionById(channelLayer, channel.gbId, {
id: channel.gbId,
position: position,
data: channel,
status: 'checked'
})
},
showEditInfo: function(data) {
this.dragChannel = data
this.infoBoxId = this.$refs.mapComponent.openInfoBox([data.gbLongitude, data.gbLatitude], this.$refs.infoboxForEdit, [0, -50])
},
cancelEdit: function(channel) {
this.closeInfoBox()
this.$refs.mapComponent.dragInteraction.removeFeatureId(channel.gbId)
channel.gbLongitude = channel.oldLongitude
channel.gbLatitude = channel.oldLatitude
channel['edit'] = false
this.$refs.mapComponent.setFeaturePositionById(channelLayer, channel.gbId, {
id: channel.gbId,
position: [channel.gbLongitude, channel.gbLatitude],
data: channel,
status: channel.gbStatus
})
},
submitEdit: function(channel) {
let position = [channel.gbLongitude, channel.gbLatitude]
this.$store.dispatch('commonChanel/update', channel)
.then(data => {
this.$message.success({
showClose: true,
message: '保存成功'
})
this.closeInfoBox()
channel['edit'] = false
this.$refs.mapComponent.dragInteraction.removeFeatureId(channel.gbId)
this.$refs.mapComponent.setFeaturePositionById(channelLayer, channel.gbId, {
id: channel.gbId,
position: position,
data: channel,
status: channel.gbStatus
})
// 刷星树菜单
this.$refs.deviceTree.refresh('channel' + channel.gbId)
})
},
getTrace: function (data) {
this.clean()
this.$refs.queryTrace.openDialog(data, (channelPositions) => {
if (channelPositions.length === 0) {
this.$message.warning({
showClose: true,
message: '未查询到轨迹信息'
})
} else {
let positions = []
for (let i = 0; i < channelPositions.length; i++) {
if (channelPositions[i][this.longitudeStr] * channelPositions[i][this.latitudeStr] > 0) {
positions.push([channelPositions[i][this.longitudeStr], channelPositions[i][this.latitudeStr]])
}
}
if (positions.length === 0) {
this.$message.warning({
showClose: true,
message: '未查询到轨迹信息'
})
return
}
}
})
},
clean: function (){
if (this.infoBoxId !== null) {
this.$refs.mapComponent.closeInfoBox(this.infoBoxId)
}
},
testArray: function (){
this.$store.dispatch('commonChanel/test')
},
showDrawThinBox: function(show){
this.showDrawThin = show
setTimeout(() => {
if (!show) {
// 关闭抽稀预览
if (this.drawThinLayer !== null) {
this.$refs.mapComponent.removeLayer(this.drawThinLayer)
this.drawThinLayer = null
}
// 清空预览数据
this.layerGroupSource = null
this.updateChannelLayer()
}else {
//
}
}, 1)
},
quicklyDrawThin: function (){
if (this.channelLayer) {
this.$refs.mapComponent.removeLayer(channelLayer)
}
if (this.drawThinLayer !== null) {
this.$refs.mapComponent.removeLayer(this.drawThinLayer)
this.drawThinLayer = null
}
// 获取待抽稀数据
let cameraList = cameraListForSource.slice()
this.quicklyDrawThinLoading = true
setTimeout(() => {
this.drawThin(cameraList).then((layerGroupSource) => {
this.layerGroupSource = layerGroupSource
this.drawThinLayer = this.$refs.mapComponent.addPointLayerGroup(layerGroupSource, data => {
this.closeInfoBox()
// this.$nextTick(() => {
// if (data[0].edit) {
// this.showEditInfo(data[0])
// }else {
// this.showChannelInfo(data[0])
// }
// })
})
this.quicklyDrawThinLoading = false
this.$message.success({
showClose: true,
message: '抽稀完成,请预览无误后保存抽稀结果'
})
})
})
},
boxDrawThin: function (){
this.$message.warning({
showClose: true,
message: '点击地图进行框选'
})
// 绘制框
this.$refs.mapComponent.startDrawBox((extent) => {
// 清理默认的摄像头图层
if (channelLayer) {
this.$refs.mapComponent.clearLayer(channelLayer)
}
this.$message.warning({
showClose: true,
message: '正在抽稀,请稍等'
})
setTimeout(() => {
let zoomExtent = this.$refs.mapComponent.getZoomExtent()
let cameraListInExtent = []
let cameraListOutExtent = []
if (this.layerGroupSource !== null) {
// 从当前预览的数据里,获取待抽稀的数据
let sourceCameraList = this.layerGroupSource.get(0)
console.log(sourceCameraList)
if (!sourceCameraList) {
this.$message.warning({
showClose: true,
message: '数据已经全部抽稀'
})
return
}
for (let i = 0; i < sourceCameraList.length; i++) {
let value = sourceCameraList[i]
if (!value.data.gbLongitude || !value.data.gbLatitude) {
continue
}
if (value.data.gbLongitude >= extent[0] && value.data.gbLongitude <= extent[2]
&& value.data.gbLatitude >= extent[1] && value.data.gbLatitude <= extent[3]) {
cameraListInExtent.push(value.data)
}else {
cameraListOutExtent.push(value.data)
}
}
}else {
for (let i = 0; i < cameraListForSource.length; i++) {
let value = cameraListForSource[i]
if (!value.gbLongitude || !value.gbLatitude) {
continue
}
if (value.gbLongitude >= extent[0] && value.gbLongitude <= extent[2]
&& value.gbLatitude >= extent[1] && value.gbLatitude <= extent[3]) {
cameraListInExtent.push(value)
}else {
cameraListOutExtent.push(value)
}
}
}
// 如果已经在预览,清理预览图层
if (this.drawThinLayer !== null) {
this.$refs.mapComponent.removeLayer(this.drawThinLayer)
this.drawThinLayer = null
}
this.drawThin(cameraListInExtent).then((layerGroupSource) => {
if (this.layerGroupSource !== null) {
let zoom = zoomExtent[0]
// 按照层级合并每次的抽稀结果
while (zoom < zoomExtent[1]) {
Array.prototype.push.apply(layerGroupSource.get(zoom), this.layerGroupSource.get(zoom))
zoom += 1
}
}
if (cameraListOutExtent.length > 0) {
let layerSourceForOutExtent = this.createZoomLayerSource(cameraListOutExtent, zoomExtent[0])
layerGroupSource.set(0, layerSourceForOutExtent)
}
this.layerGroupSource = layerGroupSource
this.drawThinLayer = this.$refs.mapComponent.addPointLayerGroup(layerGroupSource, data => {
this.closeInfoBox()
// this.$nextTick(() => {
// if (data[0].edit) {
// this.showEditInfo(data[0])
// }else {
// this.showChannelInfo(data[0])
// }
// })
})
this.$message.success({
showClose: true,
message: '抽稀完成,请预览无误后保存抽稀结果,如需继续,请再次点击局部抽稀按钮'
})
})
}, 100)
})
},
drawThin: function (cameraListInExtent){
return new Promise((resolve, reject) => {
try {
let layerGroupSource = new Map()
// 获取全部层级
let zoomExtent = this.$refs.mapComponent.getZoomExtent()
let zoom = zoomExtent[0]
let zoomCameraMap = new Map()
let useCameraMap = new Map()
while (zoom < zoomExtent[1]) {
// 计算经纬度差值
let diff = this.$refs.mapComponent.computeDiff(this.diffPixels, zoom)
let cameraMapForZoom = new Map()
let useCameraMapForZoom = new Map()
let useCameraList = Array.from(useCameraMap.values())
for (let i = 0; i < useCameraList.length; i++) {
let value = useCameraList[i]
let lngGrid = Math.trunc(value.gbLongitude / diff)
let latGrid = Math.trunc(value.gbLatitude / diff)
let gridKey = latGrid + ':' + lngGrid
useCameraMapForZoom.set(gridKey, value)
}
for (let i = 0; i < cameraListInExtent.length; i++) {
let value = cameraListInExtent[i]
if (useCameraMap.has(value.gbId) || !value.gbLongitude || !value.gbLatitude) {
continue
}
let lngGrid = Math.trunc(value.gbLongitude / diff)
let latGrid = Math.trunc(value.gbLatitude / diff)
let gridKey = latGrid + ':' + lngGrid
if (useCameraMapForZoom.has(gridKey)) {
continue
}
if (cameraMapForZoom.has(gridKey)) {
let oldValue = cameraMapForZoom.get(gridKey)
if (value.gbLongitude % diff < oldValue.gbLongitude % diff) {
cameraMapForZoom.set(gridKey, value)
useCameraMap.set(value.gbId, value)
useCameraMap.delete(oldValue.gbId)
}
}else {
cameraMapForZoom.set(gridKey, value)
useCameraMap.set(value.gbId, value)
}
}
let cameraArray = Array.from(cameraMapForZoom.values())
zoomCameraMap.set(zoom, cameraArray)
let layerSource = this.createZoomLayerSource(cameraArray)
layerGroupSource.set(zoom - 1, layerSource)
zoom += 1
}
let cameraArray = []
for (let i = 0; i < cameraListInExtent.length; i++) {
let value = cameraListInExtent[i]
if (useCameraMap.has(value.gbId) || !value.gbLongitude || !value.gbLatitude) {
continue
}
cameraArray.push(value)
}
let layerSource = this.createZoomLayerSource(cameraArray)
layerGroupSource.set(zoomExtent[1] - 1, layerSource)
resolve(layerGroupSource)
}catch (error) {
reject(error)
}
})
},
createZoomLayerSource(cameraArray) {
let dataArray = []
for (let i = 0; i < cameraArray.length; i++) {
let item = cameraArray[i]
let position = [item.gbLongitude, item.gbLatitude]
dataArray.push({
id: item.gbId,
position: position,
data: item,
status: item.gbStatus,
image: {
anchor: [0.5, 1],
src: this.getImageByChannel(item)
}
})
}
return dataArray
},
saveDrawThin: function(){
if (!this.layerGroupSource) {
return
}
this.saveDrawThinLoading = true
let param = []
let keys = Array.from(this.layerGroupSource.keys())
for (let i = 0; i < keys.length; i++) {
let zoom = keys[i]
let values = this.layerGroupSource.get(zoom)
for (let j = 0; j < values.length; j++) {
let value = values[j]
if (zoom === 0) {
param.push({
gbId: value.id
})
}else {
param.push({
gbId: value.id,
mapLevel: zoom
})
}
}
}
this.$store.dispatch('commonChanel/saveLevel', param)
.then((data) => {
this.$message.success({
showClose: true,
message: '保存成功'
})
this.showDrawThin = false
})
.finally(() => {
this.saveDrawThinLoading = false
})
},
resetDrawThinData(){
this.$confirm('确定移除抽稀结果?', '操作提示', {
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.$store.dispatch('commonChanel/resetLevel')
.then(() => {
this.$message.success({
showClose: true,
message: '数据还原成功'
})
})
})
},
addVectorTileLayer() {
let geoCoordSys = this.$refs.mapComponent.getCoordSys()
const baseUrl = window.baseUrl ? window.baseUrl : ''
let tileUrl = ((process.env.NODE_ENV === 'development') ? process.env.VUE_APP_BASE_API : baseUrl)
+ `/api/common/channel/map/tile/{z}/{x}/{y}?geoCoordSys=${geoCoordSys}&accessToken=${this.$store.getters.token}`
let clientEvent = data => {
this.closeInfoBox()
this.$nextTick(() => {
this.showChannelInfo(data[0])
// if (data[0].edit) {
// this.showEditInfo(data[0])
// }else {
// this.showChannelInfo(data[0])
// }
})
}
let tileEvent = error => {
console.log(error)
}
let tileLayer = this.$refs.mapComponent.addVectorTileLayer(tileUrl, clientEvent, tileEvent)
}
}
}
</script>
<style>
.map-tool-box-bottom-right {
position: absolute;
right: 20px;
bottom: 20px;
}
.map-tool-box-top-right {
position: absolute;
right: 20px;
top: 20px;
}
.map-tool-box-top-left {
position: absolute;
left: 380px;
top: 20px;
}
.map-tool-btn-group {
background-color: #FFFFFF;
border-radius: 3px;
user-select: none;
box-shadow: 0 2px 2px rgba(0, 0, 0, .15);
margin-bottom: 10px;
}
.map-tool-box-top-left .map-tool-btn-group {
display: flex;
}
.map-tool-box-top-right .map-tool-btn-group {
display: flex;
}
.map-tool-box-top-left .map-tool-btn {
padding: 0 10px;
}
.map-tool-box-top-right .map-tool-btn {
padding: 0 10px;
}
.map-tool-btn {
border-bottom: 1px #dfdfdf solid;
border-right: 1px #dfdfdf solid;
width: fit-content;
min-width: 33px;
height: 36px;
cursor: pointer;
text-align: center;
line-height: 36px;
font-size: 14px;
}
.map-tool-btn i {
font-size: 14px;
}
.map-tool-btn-group:last-child {
border-bottom: none;
border-right: none;
}
.map-tool-draw-thin {
position: absolute;
top: 63px;
left: 380px;
border: 1px solid #dfdfdf;
background-color: #fff;
border-radius: 4px;
padding: 0 10px;
}
.map-tool-draw-thin-density {
display: grid;
grid-template-columns: 50px 400px auto;
padding: 0;
margin: 0;
}
.infobox-content{
width: 270px;
background-color: #FFFFFF;
padding: 10px;
border-radius: 10px;
border: 1px solid #868686;
}
.infobox-content::after {
position: absolute;
bottom: -11px;
left: calc(50% - 8px);
display: block;
content: "";
width: 16px;
height: 16px;
background: url('/static/images/arrow.png') no-repeat center;
}
.infobox-edit-content{
width: 400px;
background-color: #FFFFFF;
padding: 10px;
border-radius: 10px;
border: 1px solid #868686;
}
.infobox-edit-content::after {
position: absolute;
bottom: -11px;
left: calc(50% - 8px);
display: block;
content: "";
width: 16px;
height: 16px;
background: url('/static/images/arrow.png') no-repeat center;
}
.infobox-close {
position: absolute;
right: 1rem;
top: 1rem;
color: #000000;
cursor:pointer
}
.el-descriptions__title {
font-size: 1rem;
font-weight: 700;
padding: 20px 20px 0px 23px;
text-align: center;
width: 100%;
}
</style>

View File

@@ -98,7 +98,7 @@
</el-form>
</el-tab-pane>
<el-tab-pane v-if="streamProxy.id" label="国标通道配置">
<CommonChannelEdit ref="commonChannelEdit" :data-form="streamProxy" :cancel="close" />
<CommonChannelEdit ref="commonChannelEdit" :showCancel="true" :data-form="streamProxy" @cancel="close" />
</el-tab-pane>
</el-tabs>
</div>

View File

@@ -32,7 +32,7 @@
</el-tab-pane>
<el-tab-pane v-if="streamPush.id" label="国标通道配置">
<CommonChannelEdit ref="commonChannelEdit" :data-form="streamPush" :cancel="close" />
<CommonChannelEdit ref="commonChannelEdit" :showCancel="true" :data-form="streamPush" @cancel="close" />
</el-tab-pane>
</el-tabs>
</div>