From d60b1396df45de76c6bae6aa75c15602dd4c2570 Mon Sep 17 00:00:00 2001
From: chenyao <1219716595@qq.com>
Date: Sat, 31 Jan 2026 14:22:27 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/master'

---
 applications/drone-command/src/views/areaManage/partition/FormDiaLog.vue |   89 ++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 85 insertions(+), 4 deletions(-)

diff --git a/applications/drone-command/src/views/areaManage/partition/FormDiaLog.vue b/applications/drone-command/src/views/areaManage/partition/FormDiaLog.vue
index 92c6ef8..9f490c4 100644
--- a/applications/drone-command/src/views/areaManage/partition/FormDiaLog.vue
+++ b/applications/drone-command/src/views/areaManage/partition/FormDiaLog.vue
@@ -266,7 +266,7 @@
 const formRef = ref(null) // 表单实例
 const formData = ref(initForm()) // 表单数据
 const visible = defineModel() // 弹框显隐
-const dialogMode = ref('add') // 弹框模式
+const dialogMode = ref() // 弹框模式
 const submitting = ref(false) // 提交中
 const readonly = computed(() => dialogMode.value === 'view')
 const route = useRoute()
@@ -301,6 +301,9 @@
 let shapeDisplaySource
 const deviceRangePrimitiveMap = new Map()
 const activeToolMode = ref('')
+const suppressDeviceFly = ref(false)
+let lastSelectedDeviceIds = []
+let deviceRangeRenderToken = 0
 
 const rules = {
 	areaName: fieldRules(true, 50),
@@ -482,6 +485,8 @@
 
 async function renderDeviceRanges (rows) {
 	if (!viewer) return
+	deviceRangeRenderToken += 1
+	const renderToken = deviceRangeRenderToken
 	const selectedRows = Array.isArray(rows) ? rows : []
 	const nextIds = new Set(selectedRows.map(row => String(row?.id)))
 	for (const [id, primitive] of deviceRangePrimitiveMap.entries()) {
@@ -504,9 +509,11 @@
 			return { row, primitive }
 		})
 	)
+	if (renderToken !== deviceRangeRenderToken) return
 	primitives.forEach(({ row, primitive }) => {
 		if (!primitive) return
 		const id = String(row?.id)
+		if (!nextIds.has(id)) return
 		deviceRangePrimitiveMap.set(id, primitive)
 		viewer.scene.primitives.add(primitive)
 	})
@@ -668,6 +675,69 @@
 				material: style.outline,
 			},
 		})
+	})
+}
+
+function pushRadiusBoundingPoints (positions, center, radius) {
+	if (!center || !Number.isFinite(Number(radius)) || radius <= 0) return
+	const resolved = resolveLngLatPoint(center) || {}
+	const lng = Number(resolved.lng ?? resolved.longitude)
+	const lat = Number(resolved.lat ?? resolved.latitude)
+	if (!Number.isFinite(lng) || !Number.isFinite(lat)) return
+	const baseLat = Cesium.Math.toRadians(lat)
+	const earthRadius = Cesium.Ellipsoid.WGS84.maximumRadius
+	const deltaLat = radius / earthRadius
+	const deltaLng = radius / (earthRadius * Math.max(Math.cos(baseLat), 0.000001))
+	const points = [
+		{ lng: Cesium.Math.toDegrees(Cesium.Math.toRadians(lng) + deltaLng), lat },
+		{ lng: Cesium.Math.toDegrees(Cesium.Math.toRadians(lng) - deltaLng), lat },
+		{ lng, lat: Cesium.Math.toDegrees(baseLat + deltaLat) },
+		{ lng, lat: Cesium.Math.toDegrees(baseLat - deltaLat) },
+	]
+	points.forEach(point => {
+		positions.push(Cesium.Cartesian3.fromDegrees(point.lng, point.lat, resolved.height || 0))
+	})
+}
+
+function collectShapeBoundingPositions () {
+	const positions = []
+	if (!viewer || !shapeList.value.length) return positions
+	shapeList.value.forEach(shape => {
+		let points = getShapeDisplayPoints(shape)
+		if (!Array.isArray(points) || !points.length) {
+			points = resolveControlPoints(shape?.meta, shape?.drawType)
+		}
+		if (Array.isArray(points) && points.length) {
+			points.forEach(point => {
+				const resolved = resolveLngLatPoint(point)
+				const normalized = normalizeShapePoint(resolved)
+				if (!normalized) return
+				positions.push(Cesium.Cartesian3.fromDegrees(normalized.lng, normalized.lat, normalized.height))
+			})
+		}
+		if (shape?.drawType === 'buffer' && shape?.meta?.center && Array.isArray(shape?.meta?.bufferRadii)) {
+			const maxRadius = Math.max(...shape.meta.bufferRadii.filter(item => Number.isFinite(item)))
+			pushRadiusBoundingPoints(positions, shape.meta.center, maxRadius)
+		}
+		if (shape?.drawType === 'ellipse' && shape?.meta?.center) {
+			const major = Number(shape?.meta?.semiMajor)
+			const minor = Number(shape?.meta?.semiMinor)
+			const radius = Number.isFinite(major) && Number.isFinite(minor) ? Math.max(major, minor) : null
+			pushRadiusBoundingPoints(positions, shape.meta.center, radius)
+		}
+	})
+	return positions
+}
+
+function fitViewToShapeList () {
+	if (!viewer || !shapeList.value.length) return
+	const positions = collectShapeBoundingPositions()
+	if (positions.length < 2) return
+	const boundingSphere = Cesium.BoundingSphere.fromPoints(positions)
+	const range = Math.max(boundingSphere.radius * 2.4, 200)
+	viewer.camera.flyToBoundingSphere(boundingSphere, {
+		duration: 0,
+		offset: new Cesium.HeadingPitchRange(viewer.camera.heading, Cesium.Math.toRadians(-90), range),
 	})
 }
 
@@ -970,6 +1040,7 @@
 	if (!viewer) return
 	if (shapeList.value.length) {
 		renderShapeList()
+		fitViewToShapeList()
 		return
 	}
 	if (!formData.value?.geom) return
@@ -1010,9 +1081,15 @@
 	const ids = rows.map(item => item.id)
 	formData.value.deviceIds = ids.join(',')
 	renderDeviceRanges(rows)
-	const target = rows[rows.length - 1]
-	if (target) {
-		void flyToDevice(target)
+	if (suppressDeviceFly.value) {
+		lastSelectedDeviceIds = [...ids]
+		return
+	}
+	const prevSet = new Set(lastSelectedDeviceIds)
+	const addedRow = rows.find(row => !prevSet.has(row.id))
+	lastSelectedDeviceIds = [...ids]
+	if (addedRow) {
+		void flyToDevice(addedRow)
 	}
 }
 
@@ -1074,7 +1151,11 @@
 		viewPolygon()
 	}
 	await nextTick()
+	suppressDeviceFly.value = true
 	syncDeviceSelection()
+	lastSelectedDeviceIds = selectedDeviceRows.value.map(row => row.id)
+	await nextTick()
+	suppressDeviceFly.value = false
 	if (!readonly.value) {
 		renderDeviceRanges(selectedDeviceRows.value)
 	}

--
Gitblit v1.9.3