From 942e784e3127a2234a3a66c761d9876a01dd7dcc Mon Sep 17 00:00:00 2001
From: 罗广辉 <guanghui.luo@foxmail.com>
Date: Wed, 16 Apr 2025 20:23:10 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/master'

---
 src/hooks/useSingleDroneMap/useSingleDroneMap.js |  236 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 236 insertions(+), 0 deletions(-)

diff --git a/src/hooks/useSingleDroneMap/useSingleDroneMap.js b/src/hooks/useSingleDroneMap/useSingleDroneMap.js
new file mode 100644
index 0000000..86c46b0
--- /dev/null
+++ b/src/hooks/useSingleDroneMap/useSingleDroneMap.js
@@ -0,0 +1,236 @@
+/*
+ * @Author: shuishen 1109946754@qq.com
+ * @Date: 2025-04-15 22:41:40
+ * @LastEditors: shuishen 1109946754@qq.com
+ * @LastEditTime: 2025-04-16 18:38:00
+ * @FilePath: \command-center-dashboard\src\hooks\useSingleDroneMap\useSingleDroneMap.js
+ * @Description: 
+ * 
+ * Copyright (c) 2025 by shuishen, All Rights Reserved. 
+ */
+import * as Cesium from 'cesium'
+import endingImg from '@/assets/images/aiNowFly/ending.png'
+import endingHighImg from '@/assets/images/aiNowFly/ending-high.png'
+
+/**
+ * 
+ * @param {Object} options - 配置选项
+ */
+export function useSingleDroneMap (options = {
+  eventPositions: [],
+  eventApi: null,
+  eventApiParams: {}
+}) {
+  const { eventPositions, eventApi, eventApiParams } = options
+
+  let viewer = null
+  let handler = null
+  let currentEntity = null
+
+  // 初始化机场位置
+  const initDroneEntity = (dronePosition) => {
+    const { lng, lat, status } = dronePosition
+
+    if (!lng || !lat) return
+
+    const markerImg = status ? endingHighImg : endingImg
+    const position = Cesium.Cartesian3.fromDegrees(+lng, +lat, 0)
+
+    const droneEntity = viewer?.entities.add({
+      id: `single-drone-position`,
+      position: position,
+
+      billboard: {
+        image: new Cesium.ConstantProperty(markerImg),
+        width: 35,
+        height: 35,
+      },
+
+      ellipse: {
+        semiMinorAxis: 5000,
+        semiMajorAxis: 5000,
+        outline: true,
+        material: Cesium.Color.CORNFLOWERBLUE.withAlpha(0.3),
+      },
+
+      properties: {
+        customData: {
+          data: {
+            type: 'single-drone-event'
+          }
+        }
+      }
+    })
+
+    viewer?.flyTo(droneEntity, {
+      offset: new Cesium.HeadingPitchRange(0, Cesium.Math.toRadians(-60), 0),
+      duration: 0.5,
+    })
+  }
+
+  // 机巢事件地图撒点
+  const initDroneEventEntity = (eventPositions = eventPositions) => {
+    // 遍历特征并添加实体
+    eventPositions.length && eventPositions.forEach((item, index) => {
+      const { longitude, latitude, status, id } = item
+
+      const position = Cesium.Cartesian3.fromDegrees(+longitude, +latitude, 0)
+
+      viewer?.entities.add({
+        id: `single-drone-event-${index}`,
+        position: position,
+        billboard: {
+          image: new Cesium.ConstantProperty(endingHighImg),
+          width: 35,
+          height: 35,
+        },
+        properties: {
+          customData: {
+            data: {
+              type: 'single-drone-sign'
+            }
+          }
+        },
+      })
+    })
+  }
+
+  // 调用传入api
+  const initEventApiEntity = () => {
+    removeEventLayer()
+
+    eventApi(
+      {
+        ...eventApiParams,
+      }
+    ).then(res => {
+      const result = res.data.data.records
+
+      initDroneEventEntity(result)
+    })
+  }
+
+  // 事件地图撒点加载方式
+  const initEventLayer = () => {
+    eventApi ? initEventApiEntity() : initDroneEventEntity()
+  }
+
+  const removeEventLayer = () => {
+    // entities移除
+    const entitiesIDs = viewer?.entities.values.map(i => i.id)
+    entitiesIDs && entitiesIDs.forEach(item => {
+      item.includes('single-drone-event') && viewer?.entities.removeById(item)
+    })
+  }
+
+  // 移除当前地图所有entity
+  const removeLayer = () => {
+    // entities移除
+    const entitiesIDs = viewer?.entities.values.map(i => i.id)
+    entitiesIDs.forEach(item => {
+      item.includes('single-drone-') && viewer?.entities.removeById(item)
+    })
+  }
+
+  // 查找特定类型的实体
+  const findEntityByType = (entities, type) => {
+    return entities.find(entity =>
+      entity?.properties?.customData?._value?.data?.type === type
+    )
+  }
+
+  // 左键单机事件
+  const singleMachineEvent = async click => {
+    let clickedEntities = viewer?.scene.drillPick(click.position).map(item => item.id)
+    if (!clickedEntities.length) return
+
+    const currentEntity = findEntityByType(clickedEntities, 'single-drone-event')
+
+    removeLabel()
+
+    if (currentEntity) {
+      viewer?.scene.postRender.addEventListener(labelBoxRender)
+    }
+  }
+
+  // 事件初始化
+  const handlerInit = () => {
+    if (handler) return
+
+    handler = new Cesium.ScreenSpaceEventHandler(viewer?.scene.canvas)
+    handler.setInputAction(singleMachineEvent, Cesium.ScreenSpaceEventType.LEFT_CLICK)
+  }
+
+  // 事件移除
+  const removeHandler = () => {
+    handler?.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK)
+    handler?.destroy()
+    handler = null
+  }
+
+  // 获取弹框box
+  const getLabelDom = data => {
+    const vNode = h(EventPopUpBox, { 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'
+    }
+  }
+
+  const removeDom = () => {
+    const dom = document.querySelector('#mapPopUpBox')
+    if (dom && dom.parentNode) {
+      dom.parentNode.removeChild(dom)
+    }
+  }
+
+  // 移除弹框标签
+  const removeLabel = () => {
+    viewer?.scene.postRender.removeEventListener(labelBoxRender)
+    removeDom()
+  }
+
+
+  const init = () => {
+    viewer = window.$viewer
+
+    handlerInit()
+  }
+
+  const removeAll = () => {
+    removeLayer()
+    removeHandler()
+    removeLabel()
+  }
+
+  // 自动清理
+  onUnmounted(() => {
+    removeAll()
+  })
+
+  return {
+    init,
+    removeAll,
+    initEventLayer,
+    initDroneEntity,
+  }
+}
\ No newline at end of file

--
Gitblit v1.9.3