吉安感知网项目-前端
chenyao
2026-02-04 35f53b54046e95a39ee6ca77f513fe5ce2feb6d7
applications/drone-command/src/components/map-container/device-map-container.vue
@@ -49,11 +49,10 @@
import CommonCesiumMap from '@/components/map-container/common-cesium-map.vue'
import { buildEllipsePositions } from '@/utils/cesium/shapeTools'
import { AREA_TYPE_STYLE_MAP, BUFFER_LEVEL_STYLES, DEFAULT_AREA_STYLE } from '@ztzf/constants'
import { fwAreaDivideListApi } from '@/views/areaManage/partition/partitionApi'
import { fwDefenseSceneManageListApi } from '@/views/areaManage/sceneManage/sceneManageApi'
import { newAreaDivideList, newDefenseSceneManageList } from '@/api/dataCockpit/index'
import { cockpitAggregationApi } from '@/api/dataCockpit'
import { newCockpitAggregationApi } from '@/api/dataCockpit'
import layerControlIcon from '@/assets/images/dataCockpit/layerControl.png'
import equipmentIcon from '@/assets/images/dataCockpit/map/equipment.png'
import offlineEquipmentIcon from '@/assets/images/dataCockpit/map/offline-equipment.png'
@@ -132,9 +131,9 @@
let favoritePulseElapsed = 0
const favoritePulseEntities = []
const pulseBaseColor = Cesium.Color.fromCssColorString('#FF3B30')
const PULSE_MIN_RADIUS_M = 60
const PULSE_MAX_RADIUS_M = 180
const PULSE_DURATION_S = 1.6
const PULSE_MIN_RADIUS_M = 2
const PULSE_MAX_RADIUS_M = 30
const PULSE_DURATION_S = 1.4
const detailVisible = ref(true)
const clusterVisible = ref(false)
const countyCenterMap = new Map()
@@ -217,31 +216,93 @@
   return canvas
}
class PulseSphereMaterialProperty {
   constructor(color, speed = 1.2, bands = 3.0, softness = 0.18) {
      this._definitionChanged = new Cesium.Event()
      this.color = color
      this.speed = speed
      this.bands = bands
      this.softness = softness
   }
   get isConstant() {
      return true
   }
   get definitionChanged() {
      return this._definitionChanged
   }
   getType() {
      return 'PulseSphereMaterial'
   }
   getValue(_time, result = {}) {
      result.color = this.color
      result.time = (performance.now() / 1000) * this.speed
      result.bands = this.bands
      result.softness = this.softness
      return result
   }
   equals(other) {
      return (
         other instanceof PulseSphereMaterialProperty &&
         Cesium.Color.equals(this.color, other.color) &&
         this.speed === other.speed &&
         this.bands === other.bands &&
         this.softness === other.softness
      )
   }
}
let pulseSphereMaterial = null
const getPulseSphereMaterial = () => {
   if (pulseSphereMaterial) return pulseSphereMaterial
   Cesium.Material._materialCache.addMaterial('PulseSphereMaterial', {
      fabric: {
         type: 'PulseSphereMaterial',
         uniforms: {
            color: pulseBaseColor.withAlpha(0.45),
            time: 0,
            bands: 3.0,
            softness: 0.18,
         },
         source: `
            czm_material czm_getMaterial(czm_materialInput materialInput)
            {
               czm_material material = czm_getDefaultMaterial(materialInput);
               vec3 normalEC = normalize(materialInput.normalEC);
               vec3 viewEC = normalize(-materialInput.positionToEyeEC);
               float ndv = max(dot(normalEC, viewEC), 0.0);
               float fresnel = pow(1.0 - ndv, 1.6);
               float wave = sin((ndv * bands + time) * 6.2831853);
               float ring = smoothstep(-softness, softness, wave);
               float alpha = (ring * 0.6 + fresnel * 0.4) * color.a;
               material.diffuse = color.rgb;
               material.alpha = alpha;
               return material;
            }
         `,
      },
      translucent: () => true,
   })
   pulseSphereMaterial = new PulseSphereMaterialProperty(pulseBaseColor.withAlpha(0.45), 1.1, 3.2, 0.22)
   return pulseSphereMaterial
}
const createFavoritePulseEntity = (billboard) => {
   if (!viewer || !billboard) return
   const material = new Cesium.ImageMaterialProperty({
      image: getPulseCanvas(),
      transparent: true,
   })
   const material = getPulseSphereMaterial()
   const pulse = {
      material,
      offset: Math.random() * PULSE_DURATION_S,
      entity: null,
   }
   const getPulseHeight = () => {
      const pos = getBillboardPosition(billboard)
      if (!pos) return 0
      const carto = Cesium.Cartographic.fromCartesian(pos)
      return carto?.height ?? 0
   const getPulseRadius3D = () => {
      const radius = getPulseRadius(pulse)
      return new Cesium.Cartesian3(radius, radius, radius)
   }
   pulse.entity = viewer.entities.add({
      position: new Cesium.CallbackProperty(() => getBillboardPosition(billboard), false),
      ellipse: {
         semiMajorAxis: new Cesium.CallbackProperty(() => getPulseRadius(pulse), false),
         semiMinorAxis: new Cesium.CallbackProperty(() => getPulseRadius(pulse), false),
      ellipsoid: {
         radii: new Cesium.CallbackProperty(() => getPulseRadius3D(), false),
         material,
         height: new Cesium.CallbackProperty(() => getPulseHeight(), false),
         heightReference: Cesium.HeightReference.NONE,
      },
   })
   favoritePulseEntities.push(pulse)
@@ -831,32 +892,26 @@
      const entityId = `online-device-${item.id ?? index}-${index}`
      const rangeMeters = getDeviceRange(item)
      devicePositions.push({ lng: position.longitude, lat: position.latitude })
      const billboard = deviceBillboardCollection.add({
         position: Cesium.Cartesian3.fromDegrees(position.longitude, position.latitude, 0),
         image: isOnline ? equipmentIcon : offlineEquipmentIcon,
         width: 40,
         height: 56,
         verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
      })
      billboard.id = entityId
      devicePickMap.set(entityId, { data: item, billboard })
      deviceEntries.push({ position, rangeMeters, billboard, isOnline })
      deviceEntries.push({ position, rangeMeters, isOnline, entityId, data: item })
   })
   if (selectedTargetType.value === 'device' && selectedDeviceBillboard && !devicePickMap.has(selectedDeviceBillboard.id)) {
      closePopup()
   }
   if (deviceEntries.length) {
      const heights = await getPointPositionsHeight(devicePositions, viewer)
      deviceEntries.forEach((entry, index) => {
         const height = Number(heights?.[index]?.ASL)
         const centerHeight = Number.isFinite(height) ? height : 0
         if (entry.billboard) {
            entry.billboard.position = Cesium.Cartesian3.fromDegrees(
         const billboard = deviceBillboardCollection.add({
            position: Cesium.Cartesian3.fromDegrees(
               entry.position.longitude,
               entry.position.latitude,
               centerHeight
            )
         }
            ),
            image: entry.isOnline ? equipmentIcon : offlineEquipmentIcon,
            width: 40,
            height: 56,
            verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
         })
         billboard.id = entry.entityId
         devicePickMap.set(entry.entityId, { data: entry.data, billboard })
         if (!entry.isOnline) return
         if (!Number.isFinite(entry.rangeMeters) || entry.rangeMeters <= 0) return
         const primitive = createDeviceRangePrimitiveWithHeight(entry.position, entry.rangeMeters, centerHeight)
@@ -865,6 +920,9 @@
         addCockpitPrimitive(primitive)
         deviceRingFillPrimitives.push(primitive)
      })
   }
   if (selectedTargetType.value === 'device' && selectedDeviceBillboard && !devicePickMap.has(selectedDeviceBillboard.id)) {
      closePopup()
   }
   reorderCockpitPrimitives()
}
@@ -1080,7 +1138,7 @@
const loadPartitions = async () => {
   if (!viewer) return
   try {
      const res = await fwAreaDivideListApi({
      const res = await newAreaDivideList({
         isSetSceneManage: 1,
         flyTime: dayjs().format('YYYY-MM-DD HH:mm:ss'),
      })
@@ -1212,28 +1270,43 @@
const handleDroneSignal = () => emit('droneSignal', selectedDevice.value)
const handleDroneCounter = () => emit('droneCounter', selectedDevice.value)
const renderCommandPosts = list => {
const renderCommandPosts = async list => {
   if (!viewer) return
   ensureCommandPostCollection()
   commandPostBillboardCollection.removeAll()
   commandPostBillboardCollection.show = detailVisible.value
   const entries = []
   const positions = []
      ; (list || []).forEach((item, index) => {
         const position = getDevicePosition(item)
         if (!position) return
         entries.push({ position, index })
         positions.push({ lng: position.longitude, lat: position.latitude })
      })
   if (positions.length) {
      const heights = await getPointPositionsHeight(positions, viewer)
      entries.forEach((entry, idx) => {
         const height = Number(heights?.[idx]?.ASL)
         const centerHeight = Number.isFinite(height) ? height : 0
         commandPostBillboardCollection.add({
            position: Cesium.Cartesian3.fromDegrees(position.longitude, position.latitude, 0),
            position: Cesium.Cartesian3.fromDegrees(
               entry.position.longitude,
               entry.position.latitude,
               centerHeight
            ),
            image: commandPostIcon,
            width: 40,
            height: 56,
            verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
         })
      })
   }
   reorderCockpitPrimitives()
}
const loadAggregation = async () => {
   try {
      const res = await cockpitAggregationApi({
      const res = await newCockpitAggregationApi({
         effectiveRangeKmIsNotNull: 1
      })
      renderAggregation(res?.data?.data ?? [])
@@ -1244,12 +1317,12 @@
const loadCommandPosts = async () => {
   try {
      const res = await fwDefenseSceneManageListApi({
      const res = await newDefenseSceneManageList({
         time: dayjs().format('YYYY-MM-DD HH:mm:ss')
      })
      renderCommandPosts(res?.data?.data ?? [])
      await renderCommandPosts(res?.data?.data ?? [])
   } catch (error) {
      renderCommandPosts([])
      await renderCommandPosts([])
   }
}