From 6539b3c20d9eba747bdd429f532469ccd4491a26 Mon Sep 17 00:00:00 2001
From: shuishen <1109946754@qq.com>
Date: Sat, 17 Jan 2026 13:52:51 +0800
Subject: [PATCH] feat:数据驾驶舱相关显示处理
---
applications/drone-command/src/components/map-container/device-map-container.vue | 243 ++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 234 insertions(+), 9 deletions(-)
diff --git a/applications/drone-command/src/components/map-container/device-map-container.vue b/applications/drone-command/src/components/map-container/device-map-container.vue
index 44cf467..704eaf9 100644
--- a/applications/drone-command/src/components/map-container/device-map-container.vue
+++ b/applications/drone-command/src/components/map-container/device-map-container.vue
@@ -26,6 +26,10 @@
<script setup>
import * as Cesium from 'cesium'
import { PublicCesium } from '@/utils/cesium/publicCesium'
+import { geomAnalysis } from '@ztzf/utils'
+import { fwDefenseZonePageApi } from '@/views/areaManage/defenseZone/defenseZoneApi'
+import { fwAreaDividePageApi } from '@/views/areaManage/partition/partitionApi'
+import jaGeojsonRaw from '@/assets/geojson/ja.geojson?raw'
import layerControlIcon from '@/assets/images/dataCockpit/layerControl.png'
import equipmentIcon from '@/assets/images/dataCockpit/map/equipment.png'
@@ -48,9 +52,17 @@
},
})
+const DEFAULT_ZONE_PAGE_SIZE = 999
+
let viewInstance = null
let viewer = null
const deviceEntityIds = new Set()
+let defenseZoneSource = null
+let partitionSource = null
+let adminBoundarySource = null
+let adminBoundaryLabelSource = null
+let adminBoundaryLineSource = null
+let adminBoundaryFlyDone = false
const showLayerPanel = ref(false)
const layerWrapRef = ref(null)
const layerTreeProps = {
@@ -105,10 +117,33 @@
deviceEntityIds.clear()
}
+const clearDefenseZoneEntities = () => {
+ if (!defenseZoneSource) return
+ defenseZoneSource.entities.removeAll()
+}
+
+const clearPartitionEntities = () => {
+ if (!partitionSource) return
+ partitionSource.entities.removeAll()
+}
+
+const clearAdminBoundaryEntities = () => {
+ if (!adminBoundarySource) return
+ adminBoundarySource.entities.removeAll()
+}
+
+const clearAdminBoundaryLabels = () => {
+ if (!adminBoundaryLabelSource) return
+ adminBoundaryLabelSource.entities.removeAll()
+}
+
+const clearAdminBoundaryLines = () => {
+ if (!adminBoundaryLineSource) return
+ adminBoundaryLineSource.entities.removeAll()
+}
+
const RING_STYLES = [
- { inner: 0, outer: 5000, gradient: ['#FF361C', '#360B00'] },
- { inner: 5000, outer: 8000, gradient: ['#FFC609', '#583300'] },
- { inner: 8000, outer: 10000, gradient: ['#2AEDBF', '#012B11'] },
+ { inner: 0, outer: 2000, gradient: ['#FF361C', '#360B00'] }
]
const MATERIAL_TYPE = 'RadialGradientMaterial'
@@ -235,6 +270,180 @@
})
}
+const getDefenseZonePositions = geom => {
+ const points = geomAnalysis(geom)
+ if (points.length < 3) return []
+ const first = points[0]
+ const last = points[points.length - 1]
+ const list =
+ first && last && first.longitude === last.longitude && first.latitude === last.latitude
+ ? points.slice(0, -1)
+ : points
+ return list.map(item => Cesium.Cartesian3.fromDegrees(item.longitude, item.latitude))
+}
+
+const renderZonePolygons = ({ zones, source, idPrefix, lineColor, fillGradient }) => {
+ if (!viewer || !source) return
+ registerRadialGradientMaterial()
+ const borderColor = Cesium.Color.fromCssColorString(lineColor)
+ const fillColorStart = Cesium.Color.fromCssColorString(fillGradient[0]).withAlpha(0.34)
+ const fillColorEnd = Cesium.Color.fromCssColorString(fillGradient[1]).withAlpha(0.34)
+ const fillMaterial = new RadialGradientMaterialProperty(fillColorStart, fillColorEnd)
+ zones.forEach((zone, index) => {
+ if (!zone?.geom) return
+ const positions = getDefenseZonePositions(zone.geom)
+ if (!positions.length) return
+ const entityId = `${idPrefix}-${zone.id ?? index}`
+ const linePositions = positions.length > 1 ? [...positions, positions[0]] : positions
+ source.entities.add({
+ id: entityId,
+ polygon: {
+ hierarchy: new Cesium.PolygonHierarchy(positions),
+ material: fillMaterial,
+ outline: true,
+ outlineColor: borderColor,
+ heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
+ },
+ polyline: {
+ positions: linePositions,
+ clampToGround: true,
+ width: 2,
+ material: borderColor,
+ },
+ })
+ })
+}
+
+const renderDefenseZones = zones => {
+ if (!viewer) return
+ if (!defenseZoneSource) {
+ defenseZoneSource = new Cesium.CustomDataSource('defenseZoneSource')
+ viewer.dataSources.add(defenseZoneSource)
+ }
+ clearDefenseZoneEntities()
+ renderZonePolygons({
+ zones,
+ source: defenseZoneSource,
+ idPrefix: 'defense-zone',
+ lineColor: '#19D266',
+ fillGradient: ['#2AEDBF', '#012B11'],
+ })
+}
+
+const renderPartitions = zones => {
+ if (!viewer) return
+ if (!partitionSource) {
+ partitionSource = new Cesium.CustomDataSource('partitionSource')
+ viewer.dataSources.add(partitionSource)
+ }
+ clearPartitionEntities()
+ renderZonePolygons({
+ zones,
+ source: partitionSource,
+ idPrefix: 'partition-zone',
+ lineColor: '#FFCD2A',
+ fillGradient: ['#FFC609', '#583300'],
+ })
+}
+
+const loadDefenseZones = async () => {
+ if (!viewer) return
+ try {
+ const res = await fwDefenseZonePageApi({ current: 1, size: DEFAULT_ZONE_PAGE_SIZE })
+ renderDefenseZones(res?.data?.data?.records ?? [])
+ } catch (error) {
+ renderDefenseZones([])
+ }
+}
+
+const loadPartitions = async () => {
+ if (!viewer) return
+ try {
+ const res = await fwAreaDividePageApi({ current: 1, size: DEFAULT_ZONE_PAGE_SIZE })
+ renderPartitions(res?.data?.data?.records ?? [])
+ } catch (error) {
+ renderPartitions([])
+ }
+}
+
+const loadAdminBoundary = async () => {
+ if (!viewer) return
+ try {
+ if (adminBoundarySource) {
+ viewer.dataSources.remove(adminBoundarySource)
+ adminBoundarySource = null
+ }
+ if (adminBoundaryLabelSource) {
+ viewer.dataSources.remove(adminBoundaryLabelSource)
+ adminBoundaryLabelSource = null
+ }
+ if (adminBoundaryLineSource) {
+ viewer.dataSources.remove(adminBoundaryLineSource)
+ adminBoundaryLineSource = null
+ }
+ const geojson = JSON.parse(jaGeojsonRaw)
+ adminBoundarySource = await Cesium.GeoJsonDataSource.load(geojson, {
+ stroke: Cesium.Color.fromCssColorString('#FFFFFF'),
+ strokeWidth: 2,
+ fill: Cesium.Color.fromCssColorString('#FFFFFF').withAlpha(0.05),
+ clampToGround: true,
+ })
+ viewer.dataSources.add(adminBoundarySource)
+ if (!adminBoundaryFlyDone) {
+ adminBoundaryFlyDone = true
+ viewer.flyTo(adminBoundarySource, {
+ duration: 0,
+ offset: new Cesium.HeadingPitchRange(0, Cesium.Math.toRadians(-75), 0),
+ })
+ }
+
+ adminBoundaryLineSource = new Cesium.CustomDataSource('adminBoundaryLineSource')
+ adminBoundarySource.entities.values.forEach(entity => {
+ const polygon = entity.polygon
+ if (!polygon) return
+ const hierarchy = polygon.hierarchy?.getValue?.(viewer.clock.currentTime)
+ const positions = hierarchy?.positions
+ if (!positions?.length) return
+ adminBoundaryLineSource.entities.add({
+ polyline: {
+ positions,
+ clampToGround: true,
+ width: 2,
+ material: Cesium.Color.WHITE,
+ },
+ })
+ })
+ viewer.dataSources.add(adminBoundaryLineSource)
+
+ adminBoundaryLabelSource = new Cesium.CustomDataSource('adminBoundaryLabelSource')
+ geojson.features?.forEach(feature => {
+ const name = feature?.properties?.name
+ const point = feature?.properties?.centroid || feature?.properties?.center
+ if (!name || !Array.isArray(point) || point.length < 2) return
+ adminBoundaryLabelSource.entities.add({
+ position: Cesium.Cartesian3.fromDegrees(point[0], point[1]),
+ label: {
+ text: name,
+ font: '14px Source Han Sans CN',
+ fillColor: Cesium.Color.WHITE,
+ outlineColor: Cesium.Color.BLACK.withAlpha(0.6),
+ outlineWidth: 2,
+ style: Cesium.LabelStyle.FILL_AND_OUTLINE,
+ heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
+ verticalOrigin: Cesium.VerticalOrigin.CENTER,
+ horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
+ disableDepthTestDistance: Number.POSITIVE_INFINITY,
+ },
+ })
+ })
+ viewer.dataSources.add(adminBoundaryLabelSource)
+ } catch (error) {
+ clearAdminBoundaryEntities()
+ clearAdminBoundaryLabels()
+ clearAdminBoundaryLines()
+ }
+}
+
watch(
() => props.onlineDevices,
devices => {
@@ -274,11 +483,19 @@
viewer = viewInstance.getViewer()
renderDeviceEntities(props.onlineDevices)
+ loadDefenseZones()
+ loadPartitions()
+ loadAdminBoundary()
})
onBeforeUnmount(() => {
document.removeEventListener('click', handleClickOutside)
clearDeviceEntities()
+ clearDefenseZoneEntities()
+ clearPartitionEntities()
+ clearAdminBoundaryEntities()
+ clearAdminBoundaryLabels()
+ clearAdminBoundaryLines()
if (viewInstance) {
viewInstance?.viewerDestroy()
viewInstance = null
@@ -299,14 +516,14 @@
.layer-control-root {
position: absolute;
- left: 411px;
+ left: 337px;
bottom: 22px;
z-index: 9;
transition: transform 0.3s ease-in-out;
pointer-events: none;
&.collapsed {
- transform: translateX(-401px);
+ transform: translateX(-317px);
}
}
@@ -318,8 +535,8 @@
}
.layer-control {
- width: 34px;
- height: 34px;
+ width: 46px;
+ height: 46px;
cursor: pointer;
img {
@@ -333,7 +550,7 @@
display: flex;
flex-direction: column;
position: absolute;
- left: 46px;
+ left: 66px;
bottom: 0;
width: 160px;
max-height: 442px;
@@ -370,6 +587,7 @@
line-height: 30px !important;
.el-tree-node__content {
+ padding-left: 0 !important;
display: flex;
align-items: center;
height: 40px !important;
@@ -381,6 +599,12 @@
.el-tree-node__children {
.el-tree-node__content {
border: none;
+ }
+ }
+
+ &:focus {
+ .el-tree-node__content {
+ background: transparent !important;
}
}
}
@@ -412,7 +636,8 @@
display: none;
}
-.layer-panel :deep(.el-tree-node__content:hover) {
+.layer-panel :deep(.el-tree-node__content:hover),
+.layer-panel :deep(.el-tree-node__content:focus) {
background: transparent !important;
}
--
Gitblit v1.9.3