From 2d40c08a9358a1fc1183a45fa806d5e433822e21 Mon Sep 17 00:00:00 2001
From: shuishen <1109946754@qq.com>
Date: Mon, 02 Feb 2026 11:41:16 +0800
Subject: [PATCH] feat:区域划分新增根据绘制区域筛选设备处理
---
applications/drone-command/src/views/areaManage/partition/FormDiaLog.vue | 166 ++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 157 insertions(+), 9 deletions(-)
diff --git a/applications/drone-command/src/views/areaManage/partition/FormDiaLog.vue b/applications/drone-command/src/views/areaManage/partition/FormDiaLog.vue
index 1af5da2..a2ee6e4 100644
--- a/applications/drone-command/src/views/areaManage/partition/FormDiaLog.vue
+++ b/applications/drone-command/src/views/areaManage/partition/FormDiaLog.vue
@@ -249,7 +249,7 @@
import * as Cesium from 'cesium'
import { AREA_TYPE_STYLE_MAP, BUFFER_LEVEL_STYLES, DEFAULT_AREA_STYLE } from '@ztzf/constants'
import { fwPoliceStationListApi } from '@/views/areaManage/precinctInfo/precinctInfoApi'
-import { fwDeviceListApi } from '@/views/basicManage/deviceStock/fwDevice'
+import { fwDeviceListByPolygonsApi } from '@/views/basicManage/deviceStock/fwDevice'
import polygonIcon from '@/assets/images/areaMap/polygon.png'
import rectIcon from '@/assets/images/areaMap/rect.png'
import ellipseIcon from '@/assets/images/areaMap/ellipse.png'
@@ -307,8 +307,11 @@
const deviceRangePrimitiveMap = new Map()
const activeToolMode = ref('')
const suppressDeviceFly = ref(false)
+const isDialogInitializing = ref(false)
let lastSelectedDeviceIds = []
let deviceRangeRenderToken = 0
+let deviceListTimer = null
+let deviceListRequestToken = 0
const rules = {
areaName: fieldRules(true, 50),
@@ -411,6 +414,10 @@
() => visible.value,
val => {
if (!val) {
+ if (deviceListTimer) {
+ clearTimeout(deviceListTimer)
+ deviceListTimer = null
+ }
viewEntity && viewer?.entities?.remove(viewEntity)
viewEntity = null
clearActiveTool()
@@ -425,6 +432,14 @@
val => {
updateActiveShapeAreaType(val)
}
+)
+watch(
+ () => shapeList.value,
+ () => {
+ if (isDialogInitializing.value) return
+ queueDeviceListRefresh()
+ },
+ { deep: true }
)
// 加载详情
@@ -474,6 +489,98 @@
viewer.scene.primitives.remove(primitive)
}
deviceRangePrimitiveMap.clear()
+}
+
+function clearDeviceListState () {
+ deviceOptions.value = []
+ selectedDeviceRows.value = []
+ formData.value.deviceIds = ''
+ if (deviceTableRef.value) {
+ deviceTableRef.value.clearSelection()
+ }
+}
+
+function formatWktNumber (value) {
+ if (!Number.isFinite(Number(value))) return null
+ return Number(value).toFixed(6)
+}
+
+function isSameWktPoint (left, right) {
+ if (!left || !right) return false
+ return Math.abs(left.lat - right.lat) < 0.000001 && Math.abs(left.lng - right.lng) < 0.000001
+}
+
+function buildPolygonWktFromPoints (points) {
+ if (!Array.isArray(points) || points.length < 3) return null
+ const ring = points
+ .map(resolveLngLatPoint)
+ .filter(Boolean)
+ .map(point => ({ lng: point.lng, lat: point.lat }))
+ if (ring.length < 3) return null
+ const first = ring[0]
+ const last = ring[ring.length - 1]
+ if (!isSameWktPoint(first, last)) {
+ ring.push({ ...first })
+ }
+ const coordText = ring
+ .map(point => {
+ const lng = formatWktNumber(point.lng)
+ const lat = formatWktNumber(point.lat)
+ if (lat === null || lng === null) return null
+ return `${lng} ${lat}`
+ })
+ .filter(Boolean)
+ .join(', ')
+ if (!coordText) return null
+ return `POLYGON((${coordText}))`
+}
+
+function buildEllipseWktFromMeta (center, semiMajor, semiMinor) {
+ if (!viewer) return null
+ const resolvedCenter = resolveLngLatPoint(center)
+ if (!resolvedCenter) return null
+ if (!Number.isFinite(Number(semiMajor)) || !Number.isFinite(Number(semiMinor))) return null
+ const centerCartesian = Cesium.Cartesian3.fromDegrees(
+ resolvedCenter.lng,
+ resolvedCenter.lat,
+ resolvedCenter.height || 0
+ )
+ const positions = buildEllipsePositions(centerCartesian, Number(semiMajor), Number(semiMinor))
+ if (!positions.length) return null
+ const points = positions
+ .map(item => {
+ const converted = cartesian3Convert(item, viewer)
+ return { lng: converted.longitude, lat: converted.latitude }
+ })
+ .filter(Boolean)
+ return buildPolygonWktFromPoints(points)
+}
+
+function resolveShapePolygonsWkt () {
+ const polygons = []
+ shapeList.value.forEach(shape => {
+ if (!shape) return
+ if (shape.drawType === 'buffer') {
+ const radii = Array.isArray(shape?.meta?.bufferRadii)
+ ? shape.meta.bufferRadii.filter(item => Number.isFinite(item) && item > 0)
+ : []
+ const maxRadius = radii.length ? Math.max(...radii) : null
+ const wkt = buildEllipseWktFromMeta(shape?.meta?.center, maxRadius, maxRadius)
+ if (wkt) polygons.push(wkt)
+ return
+ }
+ if (shape.drawType === 'ellipse') {
+ const wkt = buildEllipseWktFromMeta(shape?.meta?.center, shape?.meta?.semiMajor, shape?.meta?.semiMinor)
+ if (wkt) {
+ polygons.push(wkt)
+ return
+ }
+ }
+ const points = getShapeDisplayPoints(shape)
+ const wkt = buildPolygonWktFromPoints(points)
+ if (wkt) polygons.push(wkt)
+ })
+ return polygons
}
async function renderDeviceRangeSingle (device) {
@@ -1075,12 +1182,44 @@
}
// 获取设备列表
-async function getDeviceList () {
- if (deviceOptions.value.length) return
- const res = await fwDeviceListApi({ isAreaSelect: 1, areaId: formData.value.id, isTrack: 1 })
+function queueDeviceListRefresh () {
+ if (!visible.value) return
+ if (deviceListTimer) {
+ clearTimeout(deviceListTimer)
+ }
+ deviceListTimer = setTimeout(() => {
+ deviceListTimer = null
+ void getDeviceListByPolygons()
+ }, 200)
+}
+
+async function getDeviceListByPolygons () {
+ if (!visible.value) return
+ const polygons = resolveShapePolygonsWkt()
+ if (!polygons.length) {
+ clearDeviceListState()
+ return
+ }
+ deviceListRequestToken += 1
+ const requestToken = deviceListRequestToken
+ const res = await fwDeviceListByPolygonsApi({
+ isAreaSelect: 1,
+ isTrack: 1,
+ polygons,
+ })
+ if (requestToken !== deviceListRequestToken) return
deviceOptions.value = res?.data?.data ?? []
- if (dialogMode.value === 'view') {
- deviceOptions.value = deviceOptions.value.filter(item => formData.value.deviceIds.includes(item.id))
+ if (dialogMode.value === 'view' && formData.value.deviceIds) {
+ const targetIds = formData.value.deviceIds.split(',')
+ deviceOptions.value = deviceOptions.value.filter(item => targetIds.includes(String(item.id)))
+ }
+ await nextTick()
+ const prevSuppressDeviceFly = suppressDeviceFly.value
+ suppressDeviceFly.value = true
+ syncDeviceSelection()
+ suppressDeviceFly.value = prevSuppressDeviceFly
+ if (!readonly.value) {
+ renderDeviceRanges(selectedDeviceRows.value)
}
}
@@ -1114,14 +1253,16 @@
// 同步选择状态
function syncDeviceSelection () {
+ if (isDialogInitializing.value && !deviceOptions.value.length) return
const rows = []
- const arr = formData.value.deviceIds.split(',')
+ const arr = formData.value.deviceIds ? formData.value.deviceIds.split(',') : []
deviceOptions.value.forEach(row => {
- if (arr.includes(row.id)) {
+ if (arr.includes(String(row.id))) {
rows.push(row)
}
})
selectedDeviceRows.value = rows
+ formData.value.deviceIds = rows.map(item => item.id).join(',')
if (readonly.value) {
renderDeviceRanges(selectedDeviceRows.value)
return
@@ -1135,9 +1276,11 @@
// 打开弹框
async function open ({ mode, row } = {}) {
+ isDialogInitializing.value = true
dialogMode.value = mode || 'add'
formData.value = dialogMode.value === 'add' ? initForm() : row
selectedDeviceRows.value = []
+ deviceOptions.value = []
shapeList.value = []
activeShapeId.value = null
activeAreaType.value = ''
@@ -1149,7 +1292,6 @@
viewEntity && viewer?.entities?.remove(viewEntity)
viewEntity = null
clearActiveTool()
- await getDeviceList()
if (dialogMode.value === 'add') {
mapRef.value?.zoomToAdminBoundary?.()
// default no draw mode
@@ -1169,6 +1311,8 @@
if (!readonly.value) {
renderDeviceRanges(selectedDeviceRows.value)
}
+ isDialogInitializing.value = false
+ queueDeviceListRefresh()
}
onMounted(() => {
@@ -1176,6 +1320,10 @@
})
onBeforeUnmount(() => {
+ if (deviceListTimer) {
+ clearTimeout(deviceListTimer)
+ deviceListTimer = null
+ }
hideTypePanel()
})
--
Gitblit v1.9.3