forked from drone/command-center-dashboard

罗广辉
2025-04-21 2800fa4f32f3900509cb4d6eefaf2bfaf54efdd7
src/hooks/useMapAggregation/useMapAggregation.js
@@ -1,60 +1,69 @@
import * as Cesium from 'cesium'
import aggregationImg from '@/assets/images/home/useUavHome/aggregation.png'
import eventAggregationImg from '@/assets/images/home/useUavHome/eventAggregationImg.png'
import uavImg from '@/assets/images/home/useUavHome/uavImg.png'
import eventSingle from '@/assets/images/home/useEventOperate/eventSingle.png'
import _ from 'lodash'
import { getEventImage } from '@/utils/stateToImageMap/event'
import { getDroneStatusImage } from '@/utils/stateToImageMap/drone'
import DevicePopUpBox from '@/hooks/useMapAggregation/DevicePopUpBox.vue'
import EventPopUpBox from '@/hooks/useMapAggregation/EventPopUpBox.vue'
import { render } from 'vue'
import { useStore } from 'vuex'
import { getCenterPoint } from '@/utils/cesium/mapUtil'
import cesiumOperation from '@/utils/cesium-tsa'
import { getDeviceRegion, getDeviceRegionCount, getEventDetails, getMapEvents } from '@/api/home/aggregation'
import { PolyGradientMaterial } from '@/utils/cesium/Material'
import { start } from 'nprogress'
// hook
import { useMapHandlerClick } from '@/hooks/components/useMapHandlerClick'
import { MAP_LEVEL } from '@/const/drc'
/**
 * 机巢聚合功能
 */
let arrColor = ["rgb(15,176,255)", "rgb(18,76,154)", "#40C4E4", "#42B2BE", "rgb(51,176,204)", "#8CB7E5", "rgb(0,244,188)", "#139FF0"]
let arrColor = [
  'rgb(15,176,255)',
  'rgb(18,76,154)',
  '#40C4E4',
  '#42B2BE',
  'rgb(51,176,204)',
  '#8CB7E5',
  'rgb(0,244,188)',
  '#139FF0',
]
let index = 0
function getColor () {
  return arrColor[++index % arrColor.length]
}
export const useMapAggregation = type => {
export const useMapAggregation = (type, status) => {
  const { flyTo } = cesiumOperation()
  const singleImg = type === 'device' ? uavImg : eventSingle
  const mergeImg = type === 'device' ? aggregationImg : eventAggregationImg
  const MapPopUpBox = type === 'device' ? DevicePopUpBox : EventPopUpBox
  const styleTransform = type === 'device' ? 'translateY(-50%)' : 'translate(-50%,-110%)'
  const eventType = type === 'device' ? ['deviceAggregation', 'device'] : 'event'
  let scalingJudgment = [
    { name: '县', splashedList: [], gJson: null, show: false, outline: {}, value: [0, 48651], height: 31753 },
    { name: '市', splashedList: [], gJson: null, show: false, outline: {}, value: [48651, 314863], height: 257731 },
    {
      name: '省',
      splashedList: [],
      gJson: null,
      show: false,
      outline: {},
      value: [314863, 3796280000],
      height: 1987280,
    },
  ]
  const {
    handlerInit: mapHandlerInit,
    removeAll: removeMapHandlerAll,
    removeLabel: removeMapLabel
  } = useMapHandlerClick({
    popupType: `${type}-popup`,
    eventType: eventType,
    styleTransform,
    getViewer () {
      return viewer
    }
  })
  let scalingJudgment = _.cloneDeep(MAP_LEVEL).map(i => ({...i,gJson: null,splashedList:[], show: false, outline: {}}))
  let viewer = null
  let active = null
  let handler = null
  let currentEntity = null
  const store = useStore()
  const userAreaCode = computed(() => store.state.user.userInfo.detail.areaCode)
  const selectedAreaCode = computed(() => store.state.user.selectedAreaCode)
  const eventTimeType = computed(() => store.state.home.eventTimeType)
  const eventTimeRang = computed(() => store.state.home.eventTimeRang)
@@ -72,7 +81,6 @@
  let saveParams = { area_code: '', date_enum: 'CURRENT_WEEK' }
  // 确定缩放比例
  const determineScaling = () => {
    // console.log('确定缩放比例');
@@ -81,11 +89,11 @@
    // 根据高度展示对应的 gJson
    for (let [index, item] of scalingJudgment.entries()) {
      if (!item.show) return
      if (height > item.value[0] && height <= item.value[1]) {
      if (height > item.heightRange[0] && height <= item.heightRange[1]) {
        if (active === item.name) return
        active = item.name
        removeEntities()
        removeLabel()
        removeMapLabel()
        renderOutline(item)
        if (!item.gJson && !item.splashedList?.length) return
        item.gJson ? aggregation(item) : splashed(item)
@@ -110,20 +118,22 @@
  // 获取设备聚合
  function getDeviceCount (areaCode) {
    return getDeviceRegionCount({ areaCode }).then(res => {
      return (res?.data?.data || [])
      return res?.data?.data || []
    })
  }
  // 获取设备散点
  function getDeviceList (areaCode) {
    return getDeviceRegion({ areaCode }).then(res => {
      return (res?.data?.data || []).map(i => ({ ...i, type }))
    })
  }
  // 事件散点
  let eventList = []
  function processChildren (childrens) {
    // console.log(childrens, '事件点')
    return (childrens || []).map(item => {
      const arr = processChildren(item.childrens)
      if (item.data) {
@@ -137,14 +147,12 @@
      if (arr.length !== 0) {
        returnObj.childrens = arr
      }
      console.log(returnObj, '111111')
      return returnObj
    })
  }
  // 获取事件聚合
  function getMapEventCount (params) {
    console.log(5555555)
    return getMapEvents(params).then(res => {
      const resData = res?.data?.data
      if (resData?.data) {
@@ -165,9 +173,7 @@
  }
  const getOutLine = async (jsonPathPre, hierarchy) => {
    const parentGJson = await getFiler(`${defaultDir}${jsonPathPre}/index.json`)
    let features = parentGJson.features.find(
      item => item.properties.adcode === Number(hierarchy[hierarchy.length - 1])
    )
    let features = parentGJson.features.find(item => item.properties.adcode === Number(hierarchy[hierarchy.length - 1]))
    return { type: 'FeatureCollection', features: [features] }
  }
@@ -185,11 +191,18 @@
    eventList = []
    if (!areaCode) return
    saveParams.area_code = areaCode
    console.log(type, '444')
    const list = type === 'device' ? await getDeviceCount(areaCode) : await getMapEventCount(saveParams)
    const splashedList = type === 'device'
      ? await getDeviceList(areaCode)
      : eventList.map(i => ({ eventId: i.id, latitude: Number(i.latitude), longitude: Number(i.longitude), type: 'event' }))
    const splashedList =
      type === 'device'
        ? await getDeviceList(areaCode)
        : eventList.map(i => ({
          eventId: i.id,
          latitude: Number(i.latitude),
          longitude: Number(i.longitude),
          type: 'event',
          status: i.status
        }))
    const hierarchy = convertToHierarchy(areaCode.slice(0, 6))
    const jsonPath = hierarchy.join('/')
    const jsonPathPre = hierarchy.slice(0, hierarchy.length - 1).join('/')
@@ -228,50 +241,58 @@
    const outlineGJson = await getOutLine(jsonPathPre, hierarchy)
    scalingJudgment.forEach(item => item.show && (item.outline = outlineGJson))
    const [longitude, latitude] = outlineGJson.features[0].properties.centroid
    const height = scalingJudgment[(hierarchy.length - 3) * (-1)].height
    const height = scalingJudgment[(hierarchy.length - 3) * -1].height
    setCenterPosition({ longitude, latitude, height })
    flyTo({ longitude, latitude }, 0, height)
  }
  const userAreaPosition = computed(() => store.state.home.userAreaPosition)
  const setCenterPosition = (position) => {
  const setCenterPosition = position => {
    store.commit('setCurrentAreaPosition', position)
    if (!userAreaPosition.value.longitude) {
      store.commit('setUserAreaPosition', position)
    }
  }
  watch(combinedValues, async (newValue, oldValue) => {
    if (newValue.singleUavHome?.device_sn) {
      clearMapEntity()
      return
    }
  watch(
    combinedValues,
    async (newValue, oldValue) => {
      if (newValue.singleUavHome?.device_sn) {
        clearMapEntity()
        return
      }
    handlerInit()
      if (newValue.eventTimeType) {
        saveParams = { area_code: newValue.selectedAreaCode, date_enum: store.state.home.eventTimeParams }
      }
    if (newValue.eventTimeType) {
      saveParams = { area_code: newValue.selectedAreaCode, date_enum: store.state.home.eventTimeParams }
    }
      if (newValue.eventTimeRang) {
        saveParams = {
          area_code: newValue.selectedAreaCode,
          start_date: newValue.eventTimeRang[0],
          end_date: newValue.eventTimeRang[1],
        }
      }
    if (newValue.eventTimeRang) {
      saveParams = { area_code: newValue.selectedAreaCode, start_date: newValue.eventTimeRang[0], end_date: newValue.eventTimeRang[1] }
    }
      needFly = true
      if (!viewer) return
      mapHandlerInit()
    needFly = true
    if (!viewer) return
    viewer.scene.postRender.removeEventListener(determineScaling)
      viewer.scene.postRender.removeEventListener(determineScaling)
    initMapData(newValue.selectedAreaCode).then(() => {
      viewer.scene.postRender.addEventListener(determineScaling)
    })
  },
      initMapData(newValue.selectedAreaCode).then(() => {
        viewer.scene.postRender.addEventListener(determineScaling)
      })
    },
    { deep: true }
  )
  //散点机巢
  function splashed (row) {
    row.splashedList.forEach((item, index) => {
      const image = type === 'device' ? getDroneStatusImage(item.status) : getEventImage(item.status)
      viewer.entities.add({
        id: `aggregation-splashed-${index}`,
        position: Cesium.Cartesian3.fromDegrees(item.longitude, item.latitude),
@@ -286,7 +307,8 @@
          pixelOffset: new Cesium.Cartesian2(0, -9),
        },
        billboard: {
          image: new Cesium.ConstantProperty(singleImg),
          // singleImg
          image: new Cesium.ConstantProperty(image),
          width: 24,
          height: 24,
        },
@@ -315,7 +337,7 @@
            let material = new PolyGradientMaterial({
              color: Cesium.Color.fromCssColorString(arrColor[randomInt]),
              opacity: 0.7,
              alphaPower: 1.3
              alphaPower: 1.3,
            })
            entity.polygon.extrudedHeight = (entity.properties.childrenNum._value || 1) * 500
@@ -337,14 +359,14 @@
              }),
            },
            polygon
            polygon,
          })
        })
      })
  }
  // 聚合机巢
  const aggregation = (item) => {
  const aggregation = item => {
    if (!item.gJson) return
    const featuresList = item.gJson.features.map(item1 => {
      // const {lng,lat} = getCenterPoint(item1.geometry.coordinates[0][0])
@@ -409,7 +431,7 @@
        let material = new PolyGradientMaterial({
          color: Cesium.Color.fromCssColorString(getColor()),
          opacity: 0.7,
          alphaPower: 1.3
          alphaPower: 1.3,
        })
        const randomInt = Math.floor(Math.random() * 8) + 1
@@ -420,41 +442,15 @@
        entity.polygon.outline = false // 显示边框
      })
      needFly && viewer.flyTo(dataSource, {
        offset: new Cesium.HeadingPitchRange(0, Cesium.Math.toRadians(-60), 0),
        duration: 0.5,
      })
      needFly &&
        viewer.flyTo(dataSource, {
          offset: new Cesium.HeadingPitchRange(0, Cesium.Math.toRadians(-60), 0),
          duration: 0.5,
        })
      needFly = false
    })
  }
  // 获取弹框box
  const getLabelDom = data => {
    const vNode = h(MapPopUpBox, { data, removeLabel })
    const tooltipContainer = document.createElement('div')
    tooltipContainer.id = 'mapPopUpBox'
    tooltipContainer.style.position = 'absolute'
    tooltipContainer.style.transform = styleTransform
    tooltipContainer.style.pointerEvents = 'none'
    document.querySelector('.page-index').append(tooltipContainer)
    render(vNode, tooltipContainer)
    return tooltipContainer
  }
  // 弹框位置刷新
  const labelBoxRender = () => {
    if (!currentEntity) return
    let dom = document.querySelector('#mapPopUpBox')
    if (!dom) {
      dom = getLabelDom(currentEntity.properties.customData._value.data)
    }
    const screenPosition = viewer.scene.cartesianToCanvasCoordinates(currentEntity?.position?._value)
    if (screenPosition) {
      dom.style.left = `${screenPosition.x}px`
      dom.style.top = `${screenPosition.y}px`
      dom.style.display = 'block'
    }
  }
  /**
   * 根据条件获取项
@@ -464,40 +460,6 @@
   */
  const findTypeItem = (arr, condition) => {
    return arr.find(item => condition(item))
  }
  // 左键单机事件
  const singleMachineEvent = async click => {
    let clickTargets = viewer.scene.drillPick(click.position).map(item => item.id)
    if (!clickTargets.length) return
    console.log(clickTargets, 11111)
    let deviceAggregationFind = findTypeItem(clickTargets, (item) => item?.properties?.customData?._value?.data?.type === 'deviceAggregation')
    let deviceFind = findTypeItem(clickTargets, (item) => item?.properties?.customData?._value?.data?.type === 'device')
    // "event"
    let eventFind = findTypeItem(clickTargets, (item) => item?.properties?.customData?._value?.data?.type === 'event')
    // let eventFind = findTypeItem(clickTargets, (item) => item?.properties?.customData?._value?.data?.type === 'eventAggregation')
    currentEntity = deviceAggregationFind || deviceFind || eventFind
    if (!currentEntity) return
    if (!currentEntity?.position?._value) return
    // 一定要移除
    removeLabel()
    if (deviceAggregationFind || eventFind) {
      viewer.scene.postRender.addEventListener(labelBoxRender)
    }
    if (deviceFind) {
      const device = deviceFind.properties.customData._value.data
      store.commit('setSingleUavHome', device)
    }
  }
  const removeDom = () => {
    const dom = document.querySelector('#mapPopUpBox')
    if (dom && dom.parentNode) {
      dom.parentNode.removeChild(dom)
    }
  }
  // 移除 点 和 gjson 实体
@@ -513,11 +475,7 @@
      item.includes('aggregation-') && viewer.entities.removeById(item)
    })
  }
  // 移除弹框标签
  const removeLabel = () => {
    viewer?.scene.postRender.removeEventListener(labelBoxRender)
    removeDom()
  }
  // 移除所有监听事件,变量置空
  const removeAll = () => {
@@ -528,14 +486,12 @@
  const clearMapEntity = () => {
    if (!viewer) return
    removeEntities()
    removeLabel()
    removeMapHandlerAll()
    // viewer.camera.moveEnd.removeEventListener(determineScaling);
    viewer.scene.postRender.removeEventListener(determineScaling)
    handler?.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK)
    handler?.destroy()
    active = null
    handler = null
    currentEntity = null
  }
  const init = () => {
@@ -545,14 +501,7 @@
      viewer.scene.postRender.addEventListener(determineScaling)
    })
    handlerInit()
  }
  const handlerInit = () => {
    if (handler) return
    handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
    handler.setInputAction(singleMachineEvent, Cesium.ScreenSpaceEventType.LEFT_CLICK)
    mapHandlerInit()
  }
  onBeforeUnmount(() => { })