吉安感知网项目-前端
罗广辉
2026-02-04 34d14c12f48e4fab2f7eee330804646dd7bd8de4
Merge remote-tracking branch 'origin/master'
3 files modified
131 ■■■■■ changed files
applications/drone-command/src/views/areaManage/sceneConfig/FormDiaLog.vue 125 ●●●●● patch | view | raw | blame | history
applications/drone-command/src/views/areaManage/sceneConfig/index.vue 2 ●●● patch | view | raw | blame | history
applications/drone-command/src/views/detectionCountermeasure/countermeasureEvaluation/index.vue 4 ●●●● patch | view | raw | blame | history
applications/drone-command/src/views/areaManage/sceneConfig/FormDiaLog.vue
@@ -60,7 +60,11 @@
                                row-key="id"
                            >
                                <el-table-column prop="deviceName" show-overflow-tooltip label="设备名称" />
                                <el-table-column prop="deviceType" show-overflow-tooltip label="设备类型" />
                                <el-table-column prop="deviceType" show-overflow-tooltip label="设备类型">
                                    <template v-slot="{ row }">
                                        {{ getDictLabel(row.deviceType, dictObj.deviceType) }}
                                    </template>
                                </el-table-column>
                            </el-table>
                        </div>
                    </div>
@@ -153,7 +157,11 @@
                                row-key="id"
                            >
                                <el-table-column prop="deviceName" show-overflow-tooltip label="设备名称" />
                                <el-table-column prop="deviceType" show-overflow-tooltip label="设备类型" />
                                <el-table-column prop="deviceType" show-overflow-tooltip label="设备类型">
                                    <template v-slot="{ row }">
                                        {{ getDictLabel(row.deviceType, dictObj.deviceType) }}
                                    </template>
                                </el-table-column>
                            </el-table>
                        </div>
                    </div>
@@ -195,9 +203,15 @@
    buildEllipsePositions,
} from '@/utils/cesium/shapeTools'
import { cartesian3Convert } from '@/utils/cesium/mapUtil'
import {
    createDeviceRangePrimitive,
    getDeviceLngLat,
    normalizeDeviceRange,
} from '@/utils/cesium/deviceRange'
import { saveOperationLog } from '@ztzf/apis'
import { useRoute } from 'vue-router'
import { AREA_TYPE_STYLE_MAP, BUFFER_LEVEL_STYLES, DEFAULT_AREA_STYLE } from '@ztzf/constants'
import equipmentIcon from '@/assets/images/dataCockpit/map/equipment.png'
const initForm = () => ({
    sceneName: '', // 配置名称
@@ -219,6 +233,7 @@
const searchName = ref('')
const areaList = ref([]) // 关联区域列表
const selectedAreaRows = ref([]) //选中列表
let lastSelectedAreaIds = []
const deviceList = ref([]) // 设备列表
const deviceLoading = ref(false)
const dictObj = inject('dictObj')
@@ -226,6 +241,9 @@
const route = useRoute()
let viewer
let areaDisplaySource
const deviceRangePrimitiveMap = new Map()
const deviceIconEntityMap = new Map()
let deviceRangeRenderToken = 0
const rules = {
    sceneName: fieldRules(true, 50),
@@ -279,12 +297,16 @@
async function loadDeviceListByAreaIds(areaIdsKey) {
    if (!areaIdsKey) {
        deviceList.value = []
        clearDeviceRangePrimitives()
        clearDeviceIconEntities()
        return
    }
    deviceLoading.value = true
    try {
        const res = await fwDeviceListApi({ areaIds: areaIdsKey })
        deviceList.value = res?.data?.data ?? []
        await nextTick()
        renderDeviceRanges(deviceList.value)
    } finally {
        deviceLoading.value = false
    }
@@ -292,11 +314,17 @@
// 关联区域变更
async function handleAreaSelectionChange(rows) {
    const prevIds = new Set(lastSelectedAreaIds)
    const selectedRows = await ensureAreaExtList(rows)
    selectedAreaRows.value = selectedRows
    const ids = selectedRows.map(item => item.id)
    lastSelectedAreaIds = [...ids]
    formData.value.areaDivideIds = ids.join(',')
    formData.value.areaCount = ids.length
    if (ids.some(id => !prevIds.has(id))) {
        await nextTick()
        fitViewToSelectedAreas()
    }
}
// 渲染面
@@ -312,6 +340,22 @@
function clearAreaDisplay() {
    if (!areaDisplaySource) return
    areaDisplaySource.entities.removeAll()
}
function clearDeviceRangePrimitives() {
    if (!viewer || !deviceRangePrimitiveMap.size) return
    for (const primitive of deviceRangePrimitiveMap.values()) {
        viewer.scene.primitives.remove(primitive)
    }
    deviceRangePrimitiveMap.clear()
}
function clearDeviceIconEntities() {
    if (!viewer || !deviceIconEntityMap.size) return
    for (const entity of deviceIconEntityMap.values()) {
        viewer.entities.remove(entity)
    }
    deviceIconEntityMap.clear()
}
function normalizeShapePoint(point) {
@@ -559,6 +603,70 @@
    })
}
function addDeviceIconEntity(device, position) {
    if (!viewer || !position) return
    const id = String(device?.id ?? '')
    if (!id || deviceIconEntityMap.has(id)) return
    const entity = viewer.entities.add({
        position: Cesium.Cartesian3.fromDegrees(position.lng, position.lat, position.height || 0),
        billboard: {
            image: equipmentIcon,
            width: 28,
            height: 38,
            verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
            heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
        },
    })
    deviceIconEntityMap.set(id, entity)
}
async function renderDeviceRanges(rows) {
    if (!visible.value) return
    if (!viewer) initMap()
    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()) {
        if (!nextIds.has(id)) {
            viewer.scene.primitives.remove(primitive)
            deviceRangePrimitiveMap.delete(id)
        }
    }
    for (const [id, entity] of deviceIconEntityMap.entries()) {
        if (!nextIds.has(id)) {
            viewer.entities.remove(entity)
            deviceIconEntityMap.delete(id)
        }
    }
    const pendingRows = selectedRows.filter(row => {
        const id = String(row?.id)
        return id && !deviceRangePrimitiveMap.has(id)
    })
    if (!pendingRows.length) return
    const primitives = await Promise.all(
        pendingRows.map(async row => {
            const position = getDeviceLngLat(row)
            if (!position) return { row, primitive: null, position: null }
            const rangeMeters = normalizeDeviceRange(row.effectiveRangeKm)
            const primitive = await createDeviceRangePrimitive(viewer, position, rangeMeters)
            return { row, primitive, position }
        })
    )
    if (renderToken !== deviceRangeRenderToken) return
    primitives.forEach(({ row, primitive, position }) => {
        if (position) {
            addDeviceIconEntity(row, position)
        }
        if (!primitive) return
        const id = String(row?.id)
        if (!nextIds.has(id)) return
        deviceRangePrimitiveMap.set(id, primitive)
        viewer.scene.primitives.add(primitive)
    })
}
watch(() => selectedAreaRows.value, renderSelectedAreas)
const deviceAreaIdsKey = computed(() =>
    selectedAreaRows.value.map(item => item?.id).filter(Boolean).join(',')
@@ -570,9 +678,19 @@
    }
)
watch(
    () => deviceList.value,
    val => {
        renderDeviceRanges(val)
    }
)
watch(
    () => visible.value,
    val => {
        if (!val) clearAreaDisplay()
        if (!val) {
            clearAreaDisplay()
            clearDeviceRangePrimitives()
            clearDeviceIconEntities()
        }
    }
)
@@ -619,6 +737,7 @@
    selectedAreaRows.value = ensuredRows
    if (!ensuredRows.length) return
    formData.value.areaCount = ensuredRows.length
    lastSelectedAreaIds = ensuredRows.map(row => row.id)
}
// 初始化地图实例
applications/drone-command/src/views/areaManage/sceneConfig/index.vue
@@ -174,7 +174,7 @@
// 获取字典
function getDictList() {
    getDictionaryByCode('CommandSceneType,deviceMode,areaType').then(res => {
    getDictionaryByCode('CommandSceneType,deviceMode,areaType,deviceType').then(res => {
        dictObj.value = res.data.data
    })
}
applications/drone-command/src/views/detectionCountermeasure/countermeasureEvaluation/index.vue
@@ -74,8 +74,8 @@
                        </template>
                    </el-table-column>
                    <el-table-column prop="deviceSn" show-overflow-tooltip width="140" label="反制设备编码" />
                    <el-table-column prop="areaCode" show-overflow-tooltip width="120" label="场景" />
                    <el-table-column prop="areaCode" show-overflow-tooltip width="120" label="区域" />
                    <el-table-column prop="sceneName" show-overflow-tooltip width="120" label="场景" />
                    <el-table-column prop="areaName" show-overflow-tooltip width="120" label="区域" />
                    <el-table-column show-overflow-tooltip width="172" label="部署位置">
                        <template v-slot="{ row }">
                            {{ row.deployLongitude && row.deployLatitude ? `${row.deployLongitude}, ${row.deployLatitude}` : '' }}