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