吉安感知网项目-前端
张含笑
2026-01-14 46f71f1985eabbf84926d6416659370f1e8c8c3e
applications/drone-command/src/components/map-container/device-map-container.vue
File was renamed from applications/drone-command/src/views/dataCockpit/components/MapContainer.vue
@@ -1,16 +1,22 @@
<template>
   <div class="ztzf-cesium map-container" id="cesium"></div>
   <div class="layer-control-root" :class="{ collapsed: props.leftCollapsed }">
   <div class="ztzf-cesium map-container" :id="props.containerId"></div>
   <div v-if="props.showLayerControl" class="layer-control-root" :class="{ collapsed: props.leftCollapsed }">
      <div class="layer-control-wrap" ref="layerWrapRef">
         <div class="layer-control" @click="toggleLayerPanel">
            <img :src="layerControlIcon" alt="图层控制">
            <img :src="layerControlIcon" alt="图层控制" />
         </div>
         <div v-if="showLayerPanel" class="layer-panel">
            <div class="panel-title">图层管理</div>
            <div class="panel-content">
               <el-tree :data="layerTree" show-checkbox default-expand-all node-key="key" :props="layerTreeProps"
                  :default-checked-keys="defaultCheckedKeys" />
               <el-tree
                  :data="layerTree"
                  show-checkbox
                  default-expand-all
                  node-key="key"
                  :props="layerTreeProps"
                  :default-checked-keys="defaultCheckedKeys"
               />
            </div>
         </div>
      </div>
@@ -26,12 +32,20 @@
const props = defineProps({
   onlineDevices: {
      type: Array,
      default: () => []
      default: () => [],
   },
   leftCollapsed: {
      type: Boolean,
      default: false
   }
      default: false,
   },
   containerId: {
      type: String,
      default: 'device-map-container',
   },
   showLayerControl: {
      type: Boolean,
      default: true,
   },
})
let viewInstance = null
@@ -41,7 +55,7 @@
const layerWrapRef = ref(null)
const layerTreeProps = {
   label: 'label',
   children: 'children'
   children: 'children',
}
const defaultCheckedKeys = ['global', 'city-base']
const layerTree = ref([
@@ -50,8 +64,8 @@
      label: '地理信息图层',
      children: [
         { key: 'global', label: '全球地形' },
         { key: 'admin', label: '行政区划' }
      ]
         { key: 'admin', label: '行政区划' },
      ],
   },
   {
      key: 'city',
@@ -60,20 +74,20 @@
         { key: 'city-base', label: '皖山白模' },
         { key: 'city-grid', label: '皖山白模光栅网格' },
         { key: 'city-tilt', label: '皖山倾斜摄影' },
         { key: 'city-tilt-grid', label: '皖山倾斜摄影网格' }
      ]
         { key: 'city-tilt-grid', label: '皖山倾斜摄影网格' },
      ],
   },
   {
      key: 'sky',
      label: '空域要素图层',
      children: [
         { key: 'airspace', label: '空域边界' },
         { key: 'route', label: '飞行航路' }
      ]
   }
         { key: 'route', label: '飞行航路' },
      ],
   },
])
const getDevicePosition = (item) => {
const getDevicePosition = item => {
   const longitudeRaw = item.longitude ?? item.lng ?? item.lon
   const latitudeRaw = item.latitude ?? item.lat
   if (longitudeRaw == null || latitudeRaw == null) return null
@@ -85,7 +99,7 @@
const clearDeviceEntities = () => {
   if (!viewer) return
   deviceEntityIds.forEach((id) => {
   deviceEntityIds.forEach(id => {
      viewer.entities.removeById(id)
   })
   deviceEntityIds.clear()
@@ -94,7 +108,7 @@
const RING_STYLES = [
   { inner: 0, outer: 5000, gradient: ['#FF361C', '#360B00'] },
   { inner: 5000, outer: 8000, gradient: ['#FFC609', '#583300'] },
   { inner: 8000, outer: 10000, gradient: ['#2AEDBF', '#012B11'] }
   { inner: 8000, outer: 10000, gradient: ['#2AEDBF', '#012B11'] },
]
const MATERIAL_TYPE = 'RadialGradientMaterial'
@@ -108,7 +122,7 @@
         type: MATERIAL_TYPE,
         uniforms: {
            color1: new Cesium.Color(1.0, 1.0, 1.0, 1.0),
            color2: new Cesium.Color(0.0, 0.0, 0.0, 1.0)
            color2: new Cesium.Color(0.0, 0.0, 0.0, 1.0),
         },
         source: `
            czm_material czm_getMaterial(czm_materialInput materialInput) {
@@ -120,45 +134,10 @@
               material.alpha = color.a;
               return material;
            }
         `
         `,
      },
      translucent: () => true
      translucent: () => true,
   })
}
class RadialGradientMaterialProperty {
   constructor(color1, color2) {
      this._definitionChanged = new Cesium.Event()
      this.color1 = color1
      this.color2 = color2
   }
   get isConstant () {
      return true
   }
   get definitionChanged () {
      return this._definitionChanged
   }
   getType () {
      return MATERIAL_TYPE
   }
   getValue (time, result) {
      const target = result || {}
      target.color1 = this.color1
      target.color2 = this.color2
      return target
   }
   equals (other) {
      return (
         other instanceof RadialGradientMaterialProperty &&
         Cesium.Color.equals(this.color1, other.color1) &&
         Cesium.Color.equals(this.color2, other.color2)
      )
   }
}
const buildCirclePositions = (center, radiusMeters, steps = 64) => {
@@ -194,17 +173,49 @@
         id: entityId,
         polygon: {
            hierarchy: new Cesium.PolygonHierarchy(outerPositions, holes),
            material
         }
            material,
         },
      })
   })
}
const renderDeviceEntities = (devices) => {
   console.log(devices, 'devices')
class RadialGradientMaterialProperty {
   constructor(color1, color2) {
      this._definitionChanged = new Cesium.Event()
      this.color1 = color1
      this.color2 = color2
   }
   get isConstant() {
      return true
   }
   get definitionChanged() {
      return this._definitionChanged
   }
   getType() {
      return MATERIAL_TYPE
   }
   getValue(time, result) {
      const target = result || {}
      target.color1 = this.color1
      target.color2 = this.color2
      return target
   }
   equals(other) {
      return (
         other instanceof RadialGradientMaterialProperty &&
         Cesium.Color.equals(this.color1, other.color1) &&
         Cesium.Color.equals(this.color2, other.color2)
      )
   }
}
const renderDeviceEntities = devices => {
   if (!viewer) return
   clearDeviceEntities()
   devices.forEach((item, index) => {
      const position = getDevicePosition(item)
@@ -218,15 +229,15 @@
         billboard: {
            image: equipmentIcon,
            width: 40.34,
            height: 40.34
         }
            height: 40.34,
         },
      })
   })
}
watch(
   () => props.onlineDevices,
   (devices) => {
   devices => {
      renderDeviceEntities(devices || [])
   },
   { deep: true }
@@ -234,16 +245,17 @@
watch(
   () => props.leftCollapsed,
   (isCollapsed) => {
   isCollapsed => {
      if (isCollapsed) showLayerPanel.value = false
   }
)
const toggleLayerPanel = () => {
   if (!props.showLayerControl) return
   showLayerPanel.value = !showLayerPanel.value
}
const handleClickOutside = (event) => {
const handleClickOutside = event => {
   if (!showLayerPanel.value) return
   const target = event.target
   if (layerWrapRef.value?.contains(target)) return
@@ -253,11 +265,11 @@
onMounted(() => {
   document.addEventListener('click', handleClickOutside)
   viewInstance = new PublicCesium({
      dom: 'cesium',
      dom: props.containerId,
      flatMode: false,
      terrain: false,
      layerMode: 4,
      contour: false
      contour: false,
   })
   viewer = viewInstance.getViewer()
@@ -331,17 +343,14 @@
   .panel-title {
      padding: 0 16px;
      line-height: 42px;
      font-family: Open Sans, Open Sans;
      font-family: 'Open Sans', Open Sans;
      font-weight: 400;
      font-size: 12px;
      color: #FFFFFF;
      color: #ffffff;
      text-align: left;
      font-style: normal;
      text-transform: none;
      border-bottom: 1px solid rgba(70,70,100,0.5);
      border-bottom: 1px solid rgba(70, 70, 100, 0.5);
      box-sizing: border-box;
   }
@@ -354,7 +363,7 @@
   ::v-deep(.el-tree) {
      background: transparent;
      color: #C3C3DD;
      color: #c3c3dd;
      font-size: 12px;
      .el-tree-node {
@@ -365,7 +374,7 @@
            align-items: center;
            height: 40px !important;
            line-height: 40px !important;
            border-bottom: 1px solid rgba(70,70,100,0.5);
            border-bottom: 1px solid rgba(70, 70, 100, 0.5);
            box-sizing: border-box;
         }
@@ -375,14 +384,11 @@
            }
         }
      }
   }
}
.layer-panel :deep(.el-tree-node__label) {
   color: #C3C3DD;
   color: #c3c3dd;
}
.layer-panel :deep(.el-tree-node__expand-icon) {
@@ -412,20 +418,20 @@
.layer-panel :deep(.el-tree-node.is-current > .el-tree-node__content) {
   background: transparent !important;
   color: #FFFFFF;
   color: #ffffff;
}
.layer-panel :deep(.el-tree-node.is-current > .el-tree-node__content .el-tree-node__label) {
   color: #FFFFFF;
   color: #ffffff;
}
.layer-panel :deep(.el-checkbox__input.is-checked .el-checkbox__inner) {
   background-color: #023AFF;
   border-color: #023AFF;
   background-color: #023aff;
   border-color: #023aff;
}
.layer-panel :deep(.el-checkbox__inner) {
   background-color: transparent;
   border-color: #A1A3D4;
   border-color: #a1a3d4;
}
</style>