吉安感知网项目-前端
shuishen
2026-01-29 cb43af5c2caf2184bbf1a8e417f44e9aeaa2fdd9
feat:增加设备特效椭球
1 files modified
139 ■■■■■ changed files
applications/drone-command/src/views/areaManage/partition/FormDiaLog.vue 139 ●●●●● patch | view | raw | blame | history
applications/drone-command/src/views/areaManage/partition/FormDiaLog.vue
@@ -116,7 +116,7 @@
                    <div class="command-table-container">
                        <div class="command-table-content">
                            <el-table class="command-table" ref="deviceTableRef" :data="deviceOptions"
                                row-key="id">
                                row-key="id" @row-click="handleDeviceRowClick">
                                <el-table-column prop="deviceName" label="设备名称" />
                                <el-table-column prop="deviceType" label="类型">
                                    <template v-slot="{ row }">
@@ -215,7 +215,8 @@
                        <el-form-item prop="deviceIds" label-width="0">
                            <el-table class="command-table" ref="deviceTableRef"
                                :data="deviceOptions.filter(item => item.deviceName.includes(searchName))" row-key="id"
                                @selection-change="handleDeviceSelectionChange">
                                @selection-change="handleDeviceSelectionChange"
                                @row-click="handleDeviceRowClick">
                                <el-table-column type="selection" width="55" :reserve-selection="true" />
                                <el-table-column prop="deviceName" label="设备名称" />
                                <el-table-column prop="deviceType" label="类型">
@@ -323,6 +324,8 @@
let pointList = []
let viewEntity
let shapeDisplaySource
const deviceRangePrimitiveMap = new Map()
let deviceRangeMaterialRegistered = false
const activeToolMode = ref('')
const rules = {
@@ -424,6 +427,7 @@
            clearActiveTool()
            hideTypePanel()
            clearShapeDisplay()
            clearDeviceRangePrimitives()
        }
    }
)
@@ -468,6 +472,124 @@
        viewer.dataSources.add(shapeDisplaySource)
    }
    return shapeDisplaySource
}
function registerDeviceRangeMaterial () {
    if (deviceRangeMaterialRegistered || !Cesium?.Material) return
    deviceRangeMaterialRegistered = true
    Cesium.Material._materialCache.addMaterial('DeviceRangeEllipsoid', {
        fabric: {
            type: 'DeviceRangeEllipsoid',
            uniforms: {
                color: new Cesium.Color(1.0, 0.0, 0.0, 0.7),
                speed: 3.0,
            },
            source: `
                uniform vec4 color;
                uniform float speed;
                czm_material czm_getMaterial(czm_materialInput materialInput){
                    czm_material material = czm_getDefaultMaterial(materialInput);
                    vec2 st = materialInput.st;
                    float time = fract(czm_frameNumber * speed / 1000.0);
                    float alpha = abs(smoothstep(0.5,1.,fract( -st.t - time)));
                    alpha += .1;
                    material.alpha = alpha;
                    material.diffuse = color.rgb;
                    return material;
                }
            `,
        },
        translucent: () => true,
    })
}
function createDeviceRangeMaterial () {
    registerDeviceRangeMaterial()
    return Cesium.Material.fromType('DeviceRangeEllipsoid', {
        color: Cesium.Color.fromBytes(0, 255, 255, 155),
    })
}
function clearDeviceRangePrimitives () {
    if (!viewer || !deviceRangePrimitiveMap.size) return
    for (const primitive of deviceRangePrimitiveMap.values()) {
        viewer.scene.primitives.remove(primitive)
    }
    deviceRangePrimitiveMap.clear()
}
function normalizeDeviceRange (value) {
    const range = Number(value)
    if (!Number.isFinite(range) || range <= 0) return 2000
    return range
}
function getDeviceLngLat (device) {
    const lngRaw = device?.longitude ?? device?.lng ?? device?.lon
    const latRaw = device?.latitude ?? device?.lat
    const lng = Number(lngRaw)
    const lat = Number(latRaw)
    if (!Number.isFinite(lng) || !Number.isFinite(lat)) return null
    return { lng, lat }
}
function createDeviceRangePrimitive (device) {
    if (!viewer) return null
    if (!device) return null
    const position = getDeviceLngLat(device)
    if (!position) return null
    const rangeMeters = normalizeDeviceRange(device.effectiveRangeKm)
    const center = Cesium.Cartesian3.fromDegrees(position.lng, position.lat, 0)
    const radii = new Cesium.Cartesian3(rangeMeters, rangeMeters, rangeMeters)
    const geometry = new Cesium.EllipsoidGeometry({
        radii,
        vertexFormat: Cesium.MaterialAppearance.MaterialSupport.TEXTURED?.vertexFormat
            || Cesium.VertexFormat.POSITION_AND_NORMAL,
    })
    const instance = new Cesium.GeometryInstance({
        geometry,
        modelMatrix: Cesium.Transforms.eastNorthUpToFixedFrame(center),
    })
    return new Cesium.Primitive({
        geometryInstances: instance,
        appearance: new Cesium.MaterialAppearance({
            material: createDeviceRangeMaterial(),
            closed: true,
            translucent: true,
            flat: true,
            faceForward: true,
        }),
        asynchronous: false,
    })
}
function renderDeviceRangeSingle (device) {
    if (!viewer) return
    clearDeviceRangePrimitives()
    const primitive = createDeviceRangePrimitive(device)
    if (!primitive) return
    deviceRangePrimitiveMap.set(String(device?.id ?? Date.now()), primitive)
    viewer.scene.primitives.add(primitive)
}
function renderDeviceRanges (rows) {
    if (!viewer) return
    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)
        }
    }
    selectedRows.forEach(row => {
        const id = String(row?.id)
        if (!id || deviceRangePrimitiveMap.has(id)) return
        const primitive = createDeviceRangePrimitive(row)
        if (!primitive) return
        deviceRangePrimitiveMap.set(id, primitive)
        viewer.scene.primitives.add(primitive)
    })
}
function clearShapeDisplay () {
@@ -922,6 +1044,15 @@
    selectedDeviceRows.value = rows
    const ids = rows.map(item => item.id)
    formData.value.deviceIds = ids.join(',')
    renderDeviceRanges(rows)
}
function handleDeviceRowClick (row) {
    if (readonly.value) {
        renderDeviceRangeSingle(row)
        return
    }
    renderDeviceRanges(selectedDeviceRows.value)
}
// 同步选择状态
@@ -949,6 +1080,7 @@
    await nextTick()
    initMap()
    clearShapeDisplay()
    clearDeviceRangePrimitives()
    viewEntity && viewer?.entities?.remove(viewEntity)
    viewEntity = null
    clearActiveTool()
@@ -976,6 +1108,9 @@
    }
    await nextTick()
    syncDeviceSelection()
    if (!readonly.value) {
        renderDeviceRanges(selectedDeviceRows.value)
    }
}
onMounted(() => {