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