From 08ab4ebee26bb6c275b68c350bfa93ae770d6fee Mon Sep 17 00:00:00 2001
From: 罗广辉 <guanghui.luo@foxmail.com>
Date: Fri, 30 Jan 2026 16:26:27 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/master'

---
 applications/drone-command/src/views/areaManage/sceneManage/FormDiaLog.vue |  208 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 207 insertions(+), 1 deletions(-)

diff --git a/applications/drone-command/src/views/areaManage/sceneManage/FormDiaLog.vue b/applications/drone-command/src/views/areaManage/sceneManage/FormDiaLog.vue
index eba09ef..e3818e6 100644
--- a/applications/drone-command/src/views/areaManage/sceneManage/FormDiaLog.vue
+++ b/applications/drone-command/src/views/areaManage/sceneManage/FormDiaLog.vue
@@ -146,6 +146,9 @@
 import commandPost from '@/assets/images/dataCockpit/legend/command-post.png'
 import { saveOperationLog } from '@ztzf/apis'
 import { useRoute } from 'vue-router'
+import { fwAreaDivideDetailApi, fwAreaDivideListApi } from '../partition/partitionApi'
+import { buildEllipsePositions } from '@/utils/cesium/shapeTools'
+import { AREA_TYPE_STYLE_MAP, BUFFER_LEVEL_STYLES, DEFAULT_AREA_STYLE } from '@ztzf/constants'
 
 // 初始化表单数据
 const initForm = () => ({
@@ -169,10 +172,12 @@
 const titleEnum = ref({ edit: '编辑', view: '查看', add: '新增' })
 const effectiveDateRange = ref([]) // 有效时间范围
 const sceneConfigList = ref([]) // 场景配置列表
+const areaList = ref([]) // ????
 const mapRef = ref(null)
 const route = useRoute()
 let viewer
 let redPointEntity
+let areaDisplaySource
 let leftClickBound = false
 
 // 表单验证规则
@@ -229,6 +234,189 @@
 }
 
 // 获取场景配置列表
+// ?????
+function ensureAreaDisplaySource() {
+	if (!viewer) return null
+	if (!areaDisplaySource) {
+		areaDisplaySource = new Cesium.CustomDataSource('scene-manage-area-display')
+		viewer.dataSources.add(areaDisplaySource)
+	}
+	return areaDisplaySource
+}
+
+function clearAreaDisplay() {
+	if (!areaDisplaySource) return
+	areaDisplaySource.entities.removeAll()
+}
+
+function normalizeShapePoint(point) {
+	if (!point) return null
+	const lng = point?.lng ?? point?.longitude
+	const lat = point?.lat ?? point?.latitude
+	const height = Number.isFinite(Number(point?.height)) ? Number(point.height) : 0
+	if (!Number.isFinite(Number(lng)) || !Number.isFinite(Number(lat))) return null
+	return { lng: Number(lng), lat: Number(lat), height }
+}
+
+function buildShapePositions(points = []) {
+	const normalized = points.map(normalizeShapePoint).filter(Boolean)
+	return normalized.map(point => Cesium.Cartesian3.fromDegrees(point.lng, point.lat, point.height))
+}
+
+function getShapeDisplayPoints(shape) {
+	if (Array.isArray(shape?.displayPoints) && shape.displayPoints.length) {
+		return shape.displayPoints
+	}
+	return shape?.points || []
+}
+
+function getAreaTypeStyle(areaType) {
+	return AREA_TYPE_STYLE_MAP?.[String(areaType)] || DEFAULT_AREA_STYLE
+}
+
+function parseGeomJson(geomJson) {
+	if (!geomJson) return null
+	if (typeof geomJson === 'object') return geomJson
+	if (typeof geomJson !== 'string') return null
+	const trimmed = geomJson.trim()
+	if (!trimmed) return null
+	try {
+		return JSON.parse(trimmed)
+	} catch (error) {
+		return null
+	}
+}
+
+function resolveAreaShapes(area) {
+	const extList = Array.isArray(area?.fwAreaDivideExtList) ? area.fwAreaDivideExtList : []
+	if (!extList.length) return []
+	return extList
+		.map((item, index) => {
+			const isShapePayload = item?.drawType || item?.points
+			if (isShapePayload) {
+				return {
+					id: item?.id || `shape_${Date.now()}_${index}_${Math.random().toString(16).slice(2, 6)}`,
+					drawType: item?.drawType ?? 'polygon',
+					areaType: item?.areaType ?? item?.areaTypeKey ?? '',
+					points: Array.isArray(item?.points) ? item.points : [],
+					displayPoints: Array.isArray(item?.displayPoints) ? item.displayPoints : null,
+					meta: item?.meta ?? null,
+				}
+			}
+			const parsed = parseGeomJson(item?.geomJson)
+			if (!parsed) return null
+			return {
+				id: parsed?.id || `shape_${Date.now()}_${index}_${Math.random().toString(16).slice(2, 6)}`,
+				drawType: parsed?.drawType ?? 'polygon',
+				areaType: item?.areaTypeKey ?? parsed?.areaType ?? '',
+				points: Array.isArray(parsed?.points) ? parsed.points : [],
+				displayPoints: Array.isArray(parsed?.displayPoints) ? parsed.displayPoints : null,
+				meta: parsed?.meta ?? null,
+			}
+		})
+		.filter(Boolean)
+}
+
+function renderSceneAreas() {
+	if (!visible.value) {
+		clearAreaDisplay()
+		return
+	}
+	if (!viewer) initMap()
+	const dataSource = ensureAreaDisplaySource()
+	if (!dataSource) return
+	dataSource.entities.removeAll()
+	areaList.value.forEach(area => {
+		const shapes = resolveAreaShapes(area)
+		shapes.forEach(shape => {
+			if (shape.drawType === 'buffer' && shape.meta?.bufferRadii?.length && shape.meta?.center) {
+				const center = shape.meta.center
+				const centerCartesian = Cesium.Cartesian3.fromDegrees(center.lng, center.lat, center.height || 0)
+				const radii = shape.meta.bufferRadii
+					.map(radius => Number(radius))
+					.filter(radius => Number.isFinite(radius) && radius > 0)
+				radii.forEach((radius, index) => {
+					const style = BUFFER_LEVEL_STYLES[index] || BUFFER_LEVEL_STYLES[BUFFER_LEVEL_STYLES.length - 1]
+					dataSource.entities.add({
+						name: 'scene-manage-area-display',
+						customData: { drawType: shape.drawType, level: index + 1 },
+						position: centerCartesian,
+						ellipse: {
+							semiMajorAxis: radius,
+							semiMinorAxis: radius,
+							material: style.fill,
+							outline: false,
+							heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
+						},
+					})
+					const positions = buildEllipsePositions(centerCartesian, radius, radius)
+					dataSource.entities.add({
+						name: 'scene-manage-area-display',
+						customData: { drawType: shape.drawType, level: index + 1, outline: true },
+						polyline: {
+							positions: positions.length ? [...positions, positions[0]] : positions,
+							clampToGround: true,
+							width: 2,
+							material: style.outline,
+						},
+					})
+				})
+				return
+			}
+			const positions = buildShapePositions(getShapeDisplayPoints(shape))
+			if (positions.length < 3) return
+			const style = getAreaTypeStyle(shape.areaType)
+			dataSource.entities.add({
+				name: 'scene-manage-area-display',
+				customData: { drawType: shape.drawType },
+				polygon: {
+					hierarchy: new Cesium.PolygonHierarchy(positions),
+					material: style.fill,
+					outline: false,
+					heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
+				},
+				polyline: {
+					positions: positions.length ? [...positions, positions[0]] : positions,
+					clampToGround: true,
+					width: 2,
+					material: style.outline,
+				},
+			})
+		})
+	})
+}
+
+async function ensureAreaExtList(rows) {
+	const missingRows = rows.filter(row => row?.id && !Array.isArray(row?.fwAreaDivideExtList))
+	if (!missingRows.length) return rows
+	const detailList = await Promise.all(
+		missingRows.map(row =>
+			fwAreaDivideDetailApi({ id: row.id })
+				.then(res => res?.data?.data)
+				.catch(() => null)
+		)
+	)
+	const detailMap = new Map(detailList.filter(Boolean).map(item => [String(item.id), item]))
+	if (!detailMap.size) return rows
+	return rows.map(item => {
+		const detail = detailMap.get(String(item.id))
+		return detail ? { ...item, ...detail } : item
+	})
+}
+
+// ??????????
+async function loadAreaList(sceneId) {
+	if (!sceneId) {
+		areaList.value = []
+		clearAreaDisplay()
+		return
+	}
+	const res = await fwAreaDivideListApi({ sceneId })
+	const list = res?.data?.data ?? []
+	areaList.value = await ensureAreaExtList(list)
+	renderSceneAreas()
+}
+
 async function getSceneConfigList() {
 	if (sceneConfigList.value.length) return
 	const res = await fwDefenseSceneListApi({unbound: 1})
@@ -267,7 +455,7 @@
 }
 
 // 地图左键点击事件
-function LeftClickEvent(click) {
+async function LeftClickEvent(click) {
 	const pos = click.position
 	// 优先使用 pickPosition 获取贴地坐标(包含地形高度)
 	let cartesian3 = viewer.scene.pickPosition(pos)
@@ -282,6 +470,7 @@
 	formData.value.longitude = _.round(longitude, 6)
 	formData.value.latitude = _.round(latitude, 6)
 	setMapPoint(formData.value.longitude, formData.value.latitude)
+	await loadAreaList(formData.value.defenseSceneId)
 }
 
 // 设置地图点位
@@ -333,12 +522,29 @@
 	}
 	await nextTick()
 	setMapPoint(formData.value.longitude, formData.value.latitude)
+	await loadAreaList(formData.value.defenseSceneId)
 }
 
 onMounted(() => {
 	getSceneConfigList()
 })
 
+watch(
+	() => formData.value.defenseSceneId,
+	sceneId => {
+		if (!visible.value) return
+		loadAreaList(sceneId)
+	}
+)
+
+watch(
+	() => visible.value,
+	val => {
+		if (!val) clearAreaDisplay()
+	}
+)
+
+
 defineExpose({
 	open,
 })

--
Gitblit v1.9.3