吉安感知网项目-前端
chenyao
2026-02-11 e4439e5d0a2cba9983f013bd044fe4e22c7b7077
applications/drone-command/src/components/map-container/device-map-container.vue
@@ -77,6 +77,7 @@
const DETAIL_HEIGHT = 10000
const POLYGON_HEIGHT_M = 0.2
const DRONE_TRACK_DURATION_S = 30 * 60
const FIXED_DRONE_TRACK_IDS = ['6000000000602', '6000000000601']
const props = defineProps({
   allDevices: {
@@ -131,8 +132,8 @@
let favoritePulseElapsed = 0
const favoritePulseEntities = []
const pulseBaseColor = Cesium.Color.fromCssColorString('#FF3B30')
const PULSE_MIN_RADIUS_M = 2
const PULSE_MAX_RADIUS_M = 30
const PULSE_MIN_RADIUS_M = 20
const PULSE_MAX_RADIUS_M = 80
const PULSE_DURATION_S = 1.4
const detailVisible = ref(true)
const clusterVisible = ref(false)
@@ -216,93 +217,17 @@
   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 = getPulseSphereMaterial()
   const pulse = {
      material,
      offset: Math.random() * PULSE_DURATION_S,
      entity: null,
   }
   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),
      ellipsoid: {
         radii: new Cesium.CallbackProperty(() => getPulseRadius3D(), false),
         material,
      point: {
         pixelSize: new Cesium.CallbackProperty(() => getPulseRadius(pulse), false),
         color: pulseBaseColor.withAlpha(0.4),
      },
   })
   favoritePulseEntities.push(pulse)
@@ -378,10 +303,10 @@
   if (deviceRingOutlinePrimitives.length) {
      deviceRingOutlinePrimitives.forEach(primitive => cockpitPrimitiveLayer.add(primitive))
   }
   if (commandPostBillboardCollection) cockpitPrimitiveLayer.add(commandPostBillboardCollection)
   if (deviceBillboardCollection) cockpitPrimitiveLayer.add(deviceBillboardCollection)
   if (droneTrackPolylineCollection) cockpitPrimitiveLayer.add(droneTrackPolylineCollection)
   if (droneTrackBillboardCollection) cockpitPrimitiveLayer.add(droneTrackBillboardCollection)
   if (deviceBillboardCollection) cockpitPrimitiveLayer.add(deviceBillboardCollection)
   if (commandPostBillboardCollection) cockpitPrimitiveLayer.add(commandPostBillboardCollection)
}
const clearDeviceEntities = () => {
@@ -525,38 +450,43 @@
   const basePoints = [
      [
         {
            longitude: 114.963191,
            latitude: 27.136716,
            height: 120
            longitude: 114.964975,
            latitude: 27.134855,
            height: 200
         },
         {
            longitude: 114.957308,
            latitude: 27.138452,
            height: 120
            longitude: 114.963966,
            latitude: 27.132836,
            height: 200
         },
         {
            longitude: 114.952,
            latitude: 27.136317,
            height: 120
            longitude: 114.963966,
            latitude: 27.132836,
            height: 320
         },
         {
            longitude: 114.949293,
            latitude: 27.133864,
            height: 120
            longitude: 114.963974,
            latitude: 27.132677,
            height: 320
         },
         {
            longitude: 114.944666,
            latitude: 27.130526,
            height: 120
            longitude: 114.963432,
            latitude: 27.131665,
            height: 320
         },
         {
            longitude: 114.945909,
            latitude: 27.127845,
            height: 120
            longitude: 114.962865,
            latitude: 27.130377,
            height: 320
         },
         {
            longitude: 114.962974,
            latitude: 27.136242,
            longitude: 114.965318,
            latitude: 27.129925,
            height: 320
         },
         {
            longitude: 114.960144,
            latitude: 27.134902,
            height: 120
         },
      ],
@@ -578,29 +508,34 @@
            height: 120
         },
         {
            longitude: 114.925836,
            longitude: 114.925958,
            latitude: 27.096963,
            height: 400
         },
         {
            longitude: 114.925836,
            latitude: 27.096102,
            height: 120
            height: 400
         },
         {
            longitude: 114.928384,
            longitude: 114.928384,
            latitude: 27.095866,
            height: 120
            height: 400
         },
         {
            longitude: 114.929874,
            longitude: 114.929874,
            latitude: 27.096095,
            height: 120
            height: 400
         },
         {
            longitude: 114.931048,
            longitude: 114.931048,
            latitude: 27.097666,
            height: 120
            height: 400
         },
      ]
      ],
   ]
   return basePoints[center.trackIndex]
   return basePoints[center.trackIndex] || basePoints[1]
}
@@ -667,7 +602,9 @@
const setupDroneTrackClock = () => {
   if (!viewer) return
   const startTime = Cesium.JulianDate.now()
   const now = new Date()
   const noon = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 12, 0, 0, 0)
   const startTime = Cesium.JulianDate.fromDate(noon)
   const stopTime = Cesium.JulianDate.addSeconds(startTime, DRONE_TRACK_DURATION_S, new Cesium.JulianDate())
   viewer.clock.startTime = startTime
   viewer.clock.stopTime = stopTime
@@ -692,11 +629,11 @@
      const pos = isEntityPosition
         ? getBillboardPosition(track.billboard)
         : Cesium.Cartesian3.lerp(
               track.positions[seg],
               track.positions[seg + 1],
               ratio,
               new Cesium.Cartesian3()
           )
            track.positions[seg],
            track.positions[seg + 1],
            ratio,
            new Cesium.Cartesian3()
         )
      if (!pos) return
      if (!isEntityPosition) {
         track.billboard.position = pos
@@ -782,7 +719,9 @@
   droneTrackPolylineCollection.show = detailVisible.value
   droneTrackRuntime = []
   const baseTrackColor = Cesium.Color.fromCssColorString('red')
      ; (list || []).forEach((item, trackIndex) => {
      ; (FIXED_DRONE_TRACK_IDS || []).forEach((trackId, trackIndex) => {
         const item = (list || []).find(entry => String(entry?.id) === String(trackId))
         if (!item) return
         const position = getDevicePosition(item)
         if (!position) return
         const points = buildSimulatedTrackPoints({ ...position, height: item.flightHeightM, trackIndex })
@@ -806,7 +745,7 @@
            width: 3,
            material: trackMaterial,
         })
         const droneId = `drone-alarm-${item?.alarmRecordId ?? item?.id ?? trackIndex}`
         const droneId = `drone-alarm-${trackId}`
         const startTime = viewer.clock.startTime
         const stopTime = viewer.clock.stopTime
         const positionProperty = new Cesium.SampledPositionProperty()
@@ -909,6 +848,7 @@
            width: 40,
            height: 56,
            verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
            disableDepthTestDistance: Number.POSITIVE_INFINITY,
         })
         billboard.id = entry.entityId
         devicePickMap.set(entry.entityId, { data: entry.data, billboard })
@@ -1037,7 +977,7 @@
   if (!trimmed) return null
   try {
      return JSON.parse(trimmed)
   } catch (error) {}
   } catch (error) { }
   return null
}
@@ -1090,7 +1030,7 @@
                  .filter(radius => Number.isFinite(radius) && radius > 0)
               radii.forEach((radius, levelIndex) => {
                  const positions = buildEllipsePositions(centerCartesian, radius, radius)
               const style = BUFFER_LEVEL_STYLES[levelIndex] || BUFFER_LEVEL_STYLES[BUFFER_LEVEL_STYLES.length - 1]
                  const style = BUFFER_LEVEL_STYLES[levelIndex] || BUFFER_LEVEL_STYLES[BUFFER_LEVEL_STYLES.length - 1]
                  if (positions.length >= 3) {
                     shapes.push({
                        positions,
@@ -1298,6 +1238,7 @@
            width: 40,
            height: 56,
            verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
            disableDepthTestDistance: Number.POSITIVE_INFINITY,
         })
      })
   }
@@ -1390,7 +1331,7 @@
   setDroneVisibility(!showCluster)
}
const handleMapReady = ({ viewer: mapViewer, publicCesium: mapPublic }) => {
const  handleMapReady = async ({ viewer: mapViewer, publicCesium: mapPublic }) => {
   if (mapReadyHandled) return
   mapReadyHandled = true
   viewer = mapViewer
@@ -1400,10 +1341,10 @@
   const height = viewer?.camera?.positionCartographic?.height
   const stage = getStageByHeight(height)
   updateStageDisplay(stage)
   await loadCommandPosts()
   renderDeviceEntities(props.allDevices)
   loadPartitions()
   loadAggregation()
   loadCommandPosts()
   renderSimulatedDroneTrack(props.alarmDrones)
   initDeviceClickHandler()
}
@@ -1441,6 +1382,20 @@
   viewer = null
   publicCesium = null
})
const getMap = () => {
   return mapRef.value?.getMap()
}
// 暴露给父组件调用
const flyTo = (options) => {
   mapRef.value?.flyToPoint(options)
}
defineExpose({
   getMap,
   flyTo
})
</script>
<style lang="scss" scoped>