Compare commits

...

6 Commits

Author SHA1 Message Date
阿斌
66dd869d1c
Pre Merge pull request !36 from 阿斌/N/A 2025-11-11 07:34:42 +00:00
lin
99b292b023 增加地址拼接接口 2025-11-11 15:34:22 +08:00
lin
512a57a7d1 修复抽稀图层预览关闭后打开的图层未恢复的BUG 2025-11-11 15:18:31 +08:00
lin
3e3a3c202f 完善树结构大数据量的展示 2025-11-11 14:23:45 +08:00
lin
01fa67fee6 补充缺少的文件 2025-11-10 16:02:27 +08:00
阿斌
da98101aac
update src/main/resources/civilCode.csv.
行政规划错误。江苏南通海门市,修改为海门区,浙江杭州删除下城区、江干区,新增钱塘区,临平区

Signed-off-by: 阿斌 <38912748@qq.com>
2024-12-15 08:58:42 +00:00
9 changed files with 143 additions and 1009 deletions

View File

@ -389,6 +389,32 @@ public class CameraChannelController {
return result;
}
@Operation(summary = "获取推流播放地址(不做检查)", security = @SecurityRequirement(name = JwtUtils.HEADER))
@Parameter(name = "app", description = "应用名", required = true)
@Parameter(name = "stream", description = "流id", required = true)
@Parameter(name = "callId", description = "推流时携带的自定义鉴权ID", required = true)
@GetMapping(value = "/push/play-without-check")
@ResponseBody
public StreamContent getStreamInfoByAppAndStreamWithoutCheck(HttpServletRequest request,
String app,
String stream,
String callId){
MediaServer mediaServer = mediaServerService.getDefaultMediaServer();
Assert.notNull(mediaServer, "流媒体服务器不存在");
StreamInfo streamInfo = mediaServerService.getStreamInfoByAppAndStream(mediaServer, app, stream, null, callId);
streamInfo=streamInfo.clone();//深拷贝
String host;
try {
URL url=new URL(request.getRequestURL().toString());
host=url.getHost();
} catch (MalformedURLException e) {
host=request.getLocalAddr();
}
streamInfo.changeStreamIp(host);
return new StreamContent(streamInfo);
}
@ResponseBody
@GetMapping("/record/collect/add")
@Operation(summary = "添加收藏")

View File

@ -122,3 +122,4 @@ public class CachedBodyHttpServletRequest extends HttpServletRequestWrapper {
}

View File

@ -861,7 +861,7 @@
320623,如东县,3206
320681,启东市,3206
320682,如皋市,3206
320684,海门,3206
320684,海门,3206
320685,海安市,3206
3207,连云港市,32
320703,连云区,3207
@ -918,8 +918,6 @@
33,浙江省,
3301,杭州市,33
330102,上城区,3301
330103,下城区,3301
330104,江干区,3301
330105,拱墅区,3301
330106,西湖区,3301
330108,滨江区,3301
@ -927,6 +925,8 @@
330110,余杭区,3301
330111,富阳区,3301
330112,临安区,3301
330113,临平区,3301
330114,钱塘区,3301
330122,桐庐县,3301
330127,淳安县,3301
330182,建德市,3301

1 编号 名称 上级
861 320623 如东县 3206
862 320681 启东市 3206
863 320682 如皋市 3206
864 320684 海门市 海门区 3206
865 320685 海安市 3206
866 3207 连云港市 32
867 320703 连云区 3207
918 33 浙江省
919 3301 杭州市 33
920 330102 上城区 3301
330103 下城区 3301
330104 江干区 3301
921 330105 拱墅区 3301
922 330106 西湖区 3301
923 330108 滨江区 3301
925 330110 余杭区 3301
926 330111 富阳区 3301
927 330112 临安区 3301
928 330113 临平区 3301
929 330114 钱塘区 3301
930 330122 桐庐县 3301
931 330127 淳安县 3301
932 330182 建德市 3301

Binary file not shown.

View File

@ -16,15 +16,16 @@ export function add(data) {
data: data
})
}
export function getTreeList(params) {
const { query, parent, hasChannel } = params
export function getTreeList({ query, parent, hasChannel, page, count }) {
return request({
method: 'get',
url: `/api/group/tree/list`,
params: {
query: query,
parent: parent,
hasChannel: hasChannel
hasChannel: hasChannel,
page: page,
count: count
}
})
}

View File

@ -141,6 +141,7 @@ export default {
},
showCode: false,
showAlert: true,
treeLimit: 50,
searchStr: '',
chooseId: '',
treeData: [],
@ -212,6 +213,7 @@ export default {
type: 0
}])
} else {
console.log(node.data)
if (node.data.leaf) {
resolve([])
return
@ -221,10 +223,26 @@ export default {
parent: node.data.id,
hasChannel: this.hasChannel
}).then(data => {
console.log(data)
if (data.length > 0) {
this.showAlert = false
}
resolve(data)
if (data.length > this.treeLimit) {
let subData = data.splice(0, this.treeLimit)
subData.push({
treeId: '---',
deviceId: '---',
name: '加载更多...',
isLeaf: true,
leaf: true,
type: 100,
nextData: data.splice(this.treeLimit, data.length)
})
resolve(subData)
}else {
resolve(data)
}
}).finally(() => {
this.locading = false
})
@ -447,8 +465,37 @@ export default {
}, id)
},
nodeClickHandler: function(data, node, tree) {
this.chooseId = data.deviceId
this.$emit('clickEvent', data)
console.log(data)
if (data && data.nextData && data.nextData.length > 0) {
const parentNode = node.parent
let nextData = data.nextData
if (nextData.length > this.treeLimit) {
let subData = nextData.splice(0, this.treeLimit)
subData.push({
treeId: '---',
deviceId: '---',
name: '加载更多...',
isLeaf: true,
leaf: true,
type: 100,
nextData: nextData.splice(this.treeLimit, nextData.length)
})
this.$refs.veTree.remove(data, parentNode)
for (let item of subData) {
this.$refs.veTree.append(item, parentNode)
}
} else {
this.$refs.veTree.remove(data, parentNode)
for (let item of subData) {
this.$refs.veTree.append(item, parentNode)
}
}
}else {
this.chooseId = data.deviceId
this.$emit('clickEvent', data)
}
},
listClickHandler: function(data) {
this.chooseId = data.deviceId

View File

@ -137,6 +137,7 @@ export default {
searchType: 0,
showCode: false,
showAlert: true,
treeLimit: 50,
searchStr: '',
chooseId: '',
treeData: [],
@ -220,7 +221,23 @@ export default {
if (data.length > 0) {
this.showAlert = false
}
resolve(data)
if (data.length > this.treeLimit) {
let subData = data.splice(0, this.treeLimit)
subData.push({
treeId: '---',
deviceId: '---',
name: '加载更多...',
isLeaf: true,
leaf: true,
type: 100,
children: [],
nextData: data.splice(this.treeLimit, data.length)
})
resolve(subData)
}else {
resolve(data)
}
}).finally(() => {
this.locading = false
})
@ -442,8 +459,37 @@ export default {
}, node.data)
},
nodeClickHandler: function(data, node, tree) {
this.chooseId = data.deviceId
this.$emit('clickEvent', data)
if (data && data.nextData && data.nextData.length > 0) {
const parentNode = node.parent
let nextData = data.nextData
if (nextData.length > this.treeLimit) {
let subData = nextData.splice(0, this.treeLimit)
subData.push({
treeId: '---',
deviceId: '---',
name: '加载更多...',
isLeaf: true,
leaf: true,
type: 100,
children: [],
nextData: nextData.splice(this.treeLimit, nextData.length)
})
this.$refs.veTree.remove(data, parentNode)
for (let item of subData) {
this.$refs.veTree.append(item, parentNode)
}
} else {
this.$refs.veTree.remove(data, parentNode)
for (let item of subData) {
this.$refs.veTree.append(item, parentNode)
}
}
}else {
this.chooseId = data.deviceId
this.$emit('clickEvent', data)
}
},
listClickHandler: function(data) {
this.chooseId = data.deviceId

View File

@ -168,7 +168,7 @@ export default {
drawThinId: null,
drawThinLayer: null,
saveDrawThinLoading: false,
layerType: 0,
layerType: 0
}
},
created() {
@ -304,9 +304,6 @@ export default {
})
},
changeLayerType: function (index) {
if (this.layerType === index) {
return
}
this.layerType = index
if (index === 0) {
this.$refs.mapComponent.removeLayer(channelTileLayer)
@ -446,8 +443,8 @@ export default {
},
showDrawThinBox: function(show){
this.showDrawThin = show
setTimeout(() => {
if (!show) {
if (!show) {
setTimeout(() => {
//
if (this.drawThinId !== null) {
//
@ -458,8 +455,13 @@ export default {
this.$refs.mapComponent.removeLayer(this.drawThinLayer)
this.drawThinLayer = null
}
}
}, 1)
//
if (this.layerType > 0) {
this.changeLayerType(this.layerType)
}
}, 1)
}
},
quicklyDrawThin: function (){
if (channelLayer) {

View File

@ -1,989 +0,0 @@
<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>