diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/controller/ChannelController.java b/src/main/java/com/genersoft/iot/vmp/gb28181/controller/ChannelController.java index ccfb4b011..04f4d84d3 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/controller/ChannelController.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/controller/ChannelController.java @@ -5,10 +5,7 @@ import com.genersoft.iot.vmp.conf.UserSetting; import com.genersoft.iot.vmp.conf.exception.ControllerException; import com.genersoft.iot.vmp.conf.security.JwtUtils; import com.genersoft.iot.vmp.gb28181.bean.*; -import com.genersoft.iot.vmp.gb28181.controller.bean.ChannelToGroupByGbDeviceParam; -import com.genersoft.iot.vmp.gb28181.controller.bean.ChannelToGroupParam; -import com.genersoft.iot.vmp.gb28181.controller.bean.ChannelToRegionByGbDeviceParam; -import com.genersoft.iot.vmp.gb28181.controller.bean.ChannelToRegionParam; +import com.genersoft.iot.vmp.gb28181.controller.bean.*; import com.genersoft.iot.vmp.gb28181.service.IGbChannelPlayService; import com.genersoft.iot.vmp.gb28181.service.IGbChannelService; import com.genersoft.iot.vmp.service.bean.ErrorCallback; @@ -478,4 +475,10 @@ public class ChannelController { } return channelService.queryListForMap(query, online, hasRecordPlan, channelType); } + + @Operation(summary = "为地图保存抽稀结果", security = @SecurityRequirement(name = JwtUtils.HEADER)) + @PostMapping("/map/save-level") + public void saveLevel(@RequestBody List channels){ + channelService.saveLevel(channels); + } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/controller/bean/ChannelForThin.java b/src/main/java/com/genersoft/iot/vmp/gb28181/controller/bean/ChannelForThin.java new file mode 100644 index 000000000..02323b31e --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/controller/bean/ChannelForThin.java @@ -0,0 +1,9 @@ +package com.genersoft.iot.vmp.gb28181.controller.bean; + +import lombok.Data; + +@Data +public class ChannelForThin { + private Integer gbId; + private Integer mapLevel; +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/dao/CommonGBChannelMapper.java b/src/main/java/com/genersoft/iot/vmp/gb28181/dao/CommonGBChannelMapper.java index b087ee9ff..d6651003e 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/dao/CommonGBChannelMapper.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/dao/CommonGBChannelMapper.java @@ -1,6 +1,7 @@ package com.genersoft.iot.vmp.gb28181.dao; import com.genersoft.iot.vmp.gb28181.bean.*; +import com.genersoft.iot.vmp.gb28181.controller.bean.ChannelForThin; import com.genersoft.iot.vmp.gb28181.dao.provider.ChannelProvider; import com.genersoft.iot.vmp.service.bean.GPSMsgInfo; import com.genersoft.iot.vmp.streamPush.bean.StreamPush; @@ -644,4 +645,12 @@ public interface CommonGBChannelMapper { @SelectProvider(type = ChannelProvider.class, method = "queryListForSyMobile") List queryListForSyMobile(@Param("business") String business); + + @Update("") + void saveLevel(List channels); } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/dao/provider/ChannelProvider.java b/src/main/java/com/genersoft/iot/vmp/gb28181/dao/provider/ChannelProvider.java index d59a88cdb..7e1e65107 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/dao/provider/ChannelProvider.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/dao/provider/ChannelProvider.java @@ -21,6 +21,7 @@ public class ChannelProvider { " stream_id,\n" + " record_plan_id,\n" + " enable_broadcast,\n" + + " map_level,\n" + " coalesce(gb_device_id, device_id) as gb_device_id,\n" + " coalesce(gb_name, name) as gb_name,\n" + " coalesce(gb_manufacturer, manufacturer) as gb_manufacturer,\n" + diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/IGbChannelService.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/IGbChannelService.java index b5c2f97a9..b7ae39fe0 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/service/IGbChannelService.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/IGbChannelService.java @@ -1,6 +1,7 @@ package com.genersoft.iot.vmp.gb28181.service; import com.genersoft.iot.vmp.gb28181.bean.*; +import com.genersoft.iot.vmp.gb28181.controller.bean.ChannelForThin; import com.genersoft.iot.vmp.service.bean.GPSMsgInfo; import com.genersoft.iot.vmp.streamPush.bean.StreamPush; import com.github.pagehelper.PageInfo; @@ -99,4 +100,6 @@ public interface IGbChannelService { void updateGPS(List channelList); List queryListForMap(String query, Boolean online, Boolean hasRecordPlan, Integer channelType); + + void saveLevel(List channels); } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/GbChannelServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/GbChannelServiceImpl.java index 41c0570de..d6547f4ae 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/GbChannelServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/GbChannelServiceImpl.java @@ -3,6 +3,7 @@ package com.genersoft.iot.vmp.gb28181.service.impl; import com.genersoft.iot.vmp.common.enums.ChannelDataType; import com.genersoft.iot.vmp.conf.exception.ControllerException; import com.genersoft.iot.vmp.gb28181.bean.*; +import com.genersoft.iot.vmp.gb28181.controller.bean.ChannelForThin; import com.genersoft.iot.vmp.gb28181.dao.CommonGBChannelMapper; import com.genersoft.iot.vmp.gb28181.dao.GroupMapper; import com.genersoft.iot.vmp.gb28181.dao.PlatformChannelMapper; @@ -791,4 +792,21 @@ public class GbChannelServiceImpl implements IGbChannelService { public List queryListForMap(String query, Boolean online, Boolean hasRecordPlan, Integer channelType) { return commonGBChannelMapper.queryList(query, online, hasRecordPlan, channelType); } + + @Override + @Transactional + public void saveLevel(List channels) { + int limitCount = 1000; + if (channels.size() > limitCount) { + for (int i = 0; i < channels.size(); i += limitCount) { + int toIndex = i + limitCount; + if (i + limitCount > channels.size()) { + toIndex = channels.size(); + } + commonGBChannelMapper.saveLevel(channels.subList(i, toIndex)); + } + } else { + commonGBChannelMapper.saveLevel(channels); + } + } } diff --git a/web/src/api/commonChannel.js b/web/src/api/commonChannel.js index 9c08b71c8..47c1f6efc 100644 --- a/web/src/api/commonChannel.js +++ b/web/src/api/commonChannel.js @@ -598,6 +598,13 @@ export function getAllForMap({ query, online, hasRecordPlan, channelType }) { } }) } +export function saveLevel(data) { + return request({ + method: 'post', + url: '/api/common/channel/map/save-level', + data: data + }) +} export function test() { return request({ method: 'get', diff --git a/web/src/store/modules/commonChanel.js b/web/src/store/modules/commonChanel.js index ed696d6a5..335f66762 100644 --- a/web/src/store/modules/commonChanel.js +++ b/web/src/store/modules/commonChanel.js @@ -48,7 +48,7 @@ import { stopPlayback, pausePlayback, resumePlayback, - seekPlayback, speedPlayback, getAllForMap, test + seekPlayback, speedPlayback, getAllForMap, test, saveLevel } from '@/api/commonChannel' const actions = { @@ -572,6 +572,16 @@ const actions = { }) }) }, + saveLevel({ commit }, data) { + return new Promise((resolve, reject) => { + saveLevel(data).then(response => { + const { data } = response + resolve(data) + }).catch(error => { + reject(error) + }) + }) + }, test({ commit }) { return new Promise((resolve, reject) => { test().then(response => { diff --git a/web/src/views/common/CommonChannelEdit.vue b/web/src/views/common/CommonChannelEdit.vue index 8c9fd1c8b..d2e1a9687 100644 --- a/web/src/views/common/CommonChannelEdit.vue +++ b/web/src/views/common/CommonChannelEdit.vue @@ -55,7 +55,7 @@ - + @@ -64,6 +64,7 @@ + @@ -175,6 +176,14 @@ + + + + + + + + diff --git a/web/src/views/common/MapComponent.vue b/web/src/views/common/MapComponent.vue index e1a0fecef..73fe7ca39 100755 --- a/web/src/views/common/MapComponent.vue +++ b/web/src/views/common/MapComponent.vue @@ -153,11 +153,25 @@ export default { getZoom() { return olMap.getView().getZoom() }, - zoomIn(zoom) { - + zoomIn() { + let zoom = olMap.getView().getZoom() + if (zoom >= olMap.getView().getMaxZoom()) { + return + } + olMap.getView().animate({ + zoom: Math.trunc(zoom) + 1, + duration: 600 + }) }, - zoomOut(zoom) { - + zoomOut() { + let zoom = olMap.getView().getZoom() + if (zoom <= olMap.getView().getMinZoom()) { + return + } + olMap.getView().animate({ + zoom: Math.trunc(zoom) - 1, + duration: 400 + }) }, centerAndZoom(point, zoom, callback) { var zoom_ = olMap.getView().getZoom() @@ -177,6 +191,9 @@ export default { var coordinate = fromLonLat(point) if (containsCoordinate(olMap.getView().calculateExtent(), coordinate)) { olMap.getView().setCenter(coordinate) + if (zoom !== olMap.getView().getZoom()) { + olMap.getView().setZoom(zoom) + } if (endCallback) { endCallback() } @@ -189,7 +206,7 @@ export default { duration: duration }) olMap.getView().animate({ - zoom: 12, + zoom: zoom -2, duration: duration / 2 }, { zoom: zoom || olMap.getView().getZoom(), @@ -549,6 +566,8 @@ export default { callback([min[0], min[1], max[0], max[1]]) draw.abortDrawing() olMap.removeInteraction(draw) + source.clear(true) + olMap.removeLayer(vectorLayer) }) } } diff --git a/web/src/views/map/index.vue b/web/src/views/map/index.vue index 050254585..bf23914de 100755 --- a/web/src/views/map/index.vue +++ b/web/src/views/map/index.vue @@ -47,10 +47,10 @@
-
+
-
+
@@ -65,12 +65,12 @@
- 密度: - + 间隔: +
- 快速抽稀 - 局部抽稀 - 保存 + 快速抽稀 + 局部抽稀 + 保存 取消
@@ -160,7 +160,11 @@ export default { diffPixels: 60, zoomValue: 10, showDrawThin: false, - layerStyle: 1 + quicklyDrawThinLoading: false, + saveDrawThinLoading: false, + layerStyle: 1, + drawThinLayer: null, + layerGroupSource: null } }, created() { @@ -177,15 +181,18 @@ export default { if (!data.gbLongitude || data.gbLongitude < 0) { return } - if (this.$refs.mapComponent.coordinateInView([data.gbLongitude, data.gbLatitude])) { + let zoomExtent = this.$refs.mapComponent.getZoomExtent() + this.$refs.mapComponent.panTo([data.gbLongitude, data.gbLatitude], zoomExtent[1], () => { this.showChannelInfo(data) - }else { - this.$refs.mapComponent.panTo([data.gbLongitude, data.gbLatitude], 16, () => { - this.showChannelInfo(data) - }) - } + }) }) }, + zoomIn: function() { + this.$refs.mapComponent.zoomIn() + }, + zoomOut: function() { + this.$refs.mapComponent.zoomOut() + }, getContextmenu: function (event) { return [ { @@ -287,9 +294,19 @@ export default { }) }, 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(this.channelLayer) this.channelLayer = null @@ -502,117 +519,201 @@ export default { showDrawThinBox: function(show){ this.showDrawThin = show if (!show) { + // 关闭抽稀预览 + if (this.drawThinLayer !== null) { + this.$refs.mapComponent.removeLayer(this.drawThinLayer) + this.drawThinLayer = null + } + // 清空预览数据 + this.layerGroupSource = null this.updateChannelLayer() }else { - + // } }, quicklyDrawThin: function (){ - this.drawThin(cameraLayerExtent) - }, - boxDrawThin: function (){ - this.$refs.mapComponent.startDrawBox((extent) => { - this.drawThin(extent) + if (this.channelLayer) { + this.$refs.mapComponent.removeLayer(this.channelLayer) + } + if (this.drawThinLayer !== null) { + this.$refs.mapComponent.removeLayer(this.drawThinLayer) + this.drawThinLayer = null + } + // 获取待抽稀数据 + let cameraList = cameraListForSource.slice() + + this.quicklyDrawThinLoading = true + 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: '抽稀完成,请预览无误后保存抽稀结果' + }) }) }, - drawThin: function (extent){ - let layerGroupSource = new Map() + boxDrawThin: function (){ + // 绘制框 + this.$refs.mapComponent.startDrawBox((extent) => { - this.$refs.mapComponent.removeLayer(this.channelLayer) - let cameraListInExtent = [] - let cameraListOutExtent = [] - if (!extent) { - cameraListInExtent = cameraListForSource.slice() - }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) - } - } - } - - // 获取全部层级 - 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) + // 清理默认的摄像头图层 + if (this.channelLayer) { + this.$refs.mapComponent.removeLayer(this.channelLayer) } - for (let i = 0; i < cameraListInExtent.length; i++) { - let value = cameraListInExtent[i] - if (useCameraMap.has(value.gbId) || !value.gbLongitude || !value.gbLatitude) { - continue + 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 } - 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) + 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) } - }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 + // 如果已经在预览,清理预览图层 + if (this.drawThinLayer !== null) { + this.$refs.mapComponent.removeLayer(this.drawThinLayer) + this.drawThinLayer = null } - cameraArray.push(value) - } - let layerSource = this.createZoomLayerSource(cameraArray) - layerGroupSource.set(zoomExtent[1] - 1, layerSource) - if (cameraListOutExtent.length > 0) { - let layerSourceForOutExtent = this.createZoomLayerSource(cameraListOutExtent, zoomExtent[0]) - layerGroupSource.set(zoomExtent[0] - 1, layerSourceForOutExtent) - } - this.$refs.mapComponent.addPointLayerGroup(layerGroupSource, data => { - this.closeInfoBox() - this.$nextTick(() => { - if (data[0].edit) { - this.showEditInfo(data[0]) - }else { - this.showChannelInfo(data[0]) + 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]) + } + }) + }) }) }) }, + 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 = [] @@ -632,6 +733,39 @@ export default { 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: '保存成功' + }) + }) + .finally(() => { + this.saveDrawThinLoading = false + }) } }