From 40c2702c3da24d9d9fda6bd63894c3206779f812 Mon Sep 17 00:00:00 2001
From: chenyao <1219716595@qq.com>
Date: Sat, 17 Jan 2026 16:46:53 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/master'
---
applications/drone-command/src/components/map-container/device-map-container.vue | 189 ++++++++++++++++++++++++++++++++++++++++-------
1 files changed, 160 insertions(+), 29 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 888edaf..938bdfe 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
@@ -1,5 +1,18 @@
<template>
- <div class="ztzf-cesium map-container" :id="props.containerId"></div>
+ <CommonCesiumMap
+ ref="mapRef"
+ class="command-cesium map-container"
+ :dom-id="props.containerId"
+ :active="true"
+ :flat-mode="false"
+ :terrain="false"
+ :layer-mode="4"
+ :contour="false"
+ :boundary="false"
+ :show-admin-boundary="true"
+ :zoom-to-boundary="true"
+ @ready="handleMapReady"
+ />
<div v-if="props.showLayerControl" class="layer-control-root" :class="{ collapsed: props.leftCollapsed }">
<div class="layer-control-wrap" ref="layerWrapRef">
<div class="layer-control" @click="toggleLayerPanel">
@@ -25,7 +38,10 @@
<script setup>
import * as Cesium from 'cesium'
-import { PublicCesium } from '@/utils/cesium/publicCesium'
+import CommonCesiumMap from '@/components/map-container/common-cesium-map.vue'
+import { geomAnalysis } from '@ztzf/utils'
+import { fwDefenseZonePageApi } from '@/views/areaManage/defenseZone/defenseZoneApi'
+import { fwAreaDividePageApi } from '@/views/areaManage/partition/partitionApi'
import layerControlIcon from '@/assets/images/dataCockpit/layerControl.png'
import equipmentIcon from '@/assets/images/dataCockpit/map/equipment.png'
@@ -48,9 +64,13 @@
},
})
-let viewInstance = null
+const DEFAULT_ZONE_PAGE_SIZE = 999
+
+const mapRef = ref(null)
let viewer = null
const deviceEntityIds = new Set()
+let defenseZoneSource = null
+let partitionSource = null
const showLayerPanel = ref(false)
const layerWrapRef = ref(null)
const layerTreeProps = {
@@ -105,10 +125,19 @@
deviceEntityIds.clear()
}
+const clearDefenseZoneEntities = () => {
+ if (!defenseZoneSource) return
+ defenseZoneSource.entities.removeAll()
+}
+
+const clearPartitionEntities = () => {
+ if (!partitionSource) return
+ partitionSource.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'
@@ -228,12 +257,110 @@
position: Cesium.Cartesian3.fromDegrees(position.longitude, position.latitude, 0),
billboard: {
image: equipmentIcon,
- width: 40.34,
- height: 40.34,
+ width: 40,
+ height: 56,
+ verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
},
})
})
}
+
+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([])
+ }
+}
+
watch(
() => props.onlineDevices,
@@ -255,6 +382,13 @@
showLayerPanel.value = !showLayerPanel.value
}
+const handleMapReady = ({ viewer: mapViewer }) => {
+ viewer = mapViewer
+ renderDeviceEntities(props.onlineDevices)
+ loadDefenseZones()
+ loadPartitions()
+}
+
const handleClickOutside = event => {
if (!showLayerPanel.value) return
const target = event.target
@@ -264,26 +398,15 @@
onMounted(() => {
document.addEventListener('click', handleClickOutside)
- viewInstance = new PublicCesium({
- dom: props.containerId,
- flatMode: false,
- terrain: false,
- layerMode: 4,
- contour: false,
- })
-
- viewer = viewInstance.getViewer()
- renderDeviceEntities(props.onlineDevices)
+ const map = mapRef.value?.getMap()
+ if (map?.viewer) handleMapReady(map)
})
onBeforeUnmount(() => {
document.removeEventListener('click', handleClickOutside)
clearDeviceEntities()
- if (viewInstance) {
- viewInstance?.viewerDestroy()
- viewInstance = null
- }
-
+ clearDefenseZoneEntities()
+ clearPartitionEntities()
viewer = null
})
</script>
@@ -299,14 +422,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 +441,8 @@
}
.layer-control {
- width: 34px;
- height: 34px;
+ width: 46px;
+ height: 46px;
cursor: pointer;
img {
@@ -333,7 +456,7 @@
display: flex;
flex-direction: column;
position: absolute;
- left: 46px;
+ left: 66px;
bottom: 0;
width: 160px;
max-height: 442px;
@@ -370,6 +493,7 @@
line-height: 30px !important;
.el-tree-node__content {
+ padding-left: 0 !important;
display: flex;
align-items: center;
height: 40px !important;
@@ -381,6 +505,12 @@
.el-tree-node__children {
.el-tree-node__content {
border: none;
+ }
+ }
+
+ &:focus {
+ .el-tree-node__content {
+ background: transparent !important;
}
}
}
@@ -412,7 +542,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