| src/hooks/components/useMapHandlerClick.js | ●●●●● patch | view | raw | blame | history | |
| src/hooks/useMapAggregation/useMapAggregation.js | ●●●●● patch | view | raw | blame | history | |
| src/hooks/useSingleDroneMap/useSingleDroneMap.js | ●●●●● patch | view | raw | blame | history |
src/hooks/components/useMapHandlerClick.js
@@ -2,33 +2,72 @@ * @Author: shuishen 1109946754@qq.com * @Date: 2025-04-15 22:41:40 * @LastEditors: shuishen 1109946754@qq.com * @LastEditTime: 2025-04-16 19:02:39 * @LastEditTime: 2025-04-17 19:43:36 * @FilePath: \command-center-dashboard\src\hooks\components\useMapHandlerClick.js * @Description: * * Copyright (c) 2025 by shuishen, All Rights Reserved. */ import * as Cesium from 'cesium' import { render } from 'vue' import { useStore } from 'vuex' import DevicePopUpBox from '@/hooks/components/DevicePopUpBox.vue' import EventPopUpBox from '@/hooks/components/EventPopUpBox.vue' /** * * @param {Object} options - 配置选项 */ export function useMapHandlerClick (viewer, options = { type: 'single-drone-event', customDom: EventPopUpBox }) { const { type } = options export function useMapHandlerClick (options = {}) { const { popupType = 'event-popup', eventType = 'single-drone-event', styleTransform = 'translate(-50%,-110%)', getViewer } = options const currentClickEntity = ref(null) const store = useStore() const popupData = { 'event-popup': EventPopUpBox, 'device-popup': DevicePopUpBox } const MapPopUpBox = popupData[popupType] let viewer = null let handler = null let currentClickEntity = null // 查找特定类型的实体 const findEntityByType = (entities, type) => { return entities.find(entity => entity?.properties?.customData?._value?.data?.type === type ) let types = [] Array.isArray(type) ? types = type : types = [type] return types.reduce((pre, curType) => { let entity = entities.find(entity => entity?.properties?.customData?._value?.data?.type === curType) return entity ? (pre.push({ type: curType, entity }), pre) : pre }, []) } const publicEvent = (entity) => { viewer.scene.postRender.addEventListener(labelBoxRender) } const typeEvent = { 'deviceAggregation': publicEvent, 'single-drone-event': publicEvent, 'event': publicEvent, 'device': (entity) => { const device = entity.properties.customData._value.data store.commit('setSingleUavHome', device) } } // 左键单机事件 @@ -36,17 +75,21 @@ let clickedEntities = viewer?.scene.drillPick(click.position).map(item => item.id) if (!clickedEntities.length) return currentClickEntity.value = findEntityByType(clickedEntities, type) let curClick = findEntityByType(clickedEntities, eventType) removeLabel() if (currentClickEntity.value) { viewer?.scene.postRender.addEventListener(labelBoxRender) if (curClick.length > 0 && typeEvent[curClick[0].type]) { currentClickEntity = curClick[0].entity typeEvent[curClick[0].type](currentClickEntity) } } // 事件初始化 const handlerInit = () => { !viewer && (viewer = getViewer()) if (handler) return handler = new Cesium.ScreenSpaceEventHandler(viewer?.scene.canvas) @@ -62,7 +105,7 @@ // 获取弹框box const getLabelDom = data => { const vNode = h(customDom, { data, removeLabel }) const vNode = h(MapPopUpBox, { data, removeLabel }) const tooltipContainer = document.createElement('div') tooltipContainer.id = 'mapPopUpBox' tooltipContainer.style.position = 'absolute' @@ -75,12 +118,12 @@ // 弹框位置刷新 const labelBoxRender = () => { if (!currentEntity) return if (!currentClickEntity) return let dom = document.querySelector('#mapPopUpBox') if (!dom) { dom = getLabelDom(currentEntity.properties.customData._value.data) dom = getLabelDom(currentClickEntity.properties.customData._value.data) } const screenPosition = viewer?.scene.cartesianToCanvasCoordinates(currentEntity?.position?._value) const screenPosition = viewer?.scene.cartesianToCanvasCoordinates(currentClickEntity?.position?._value) if (screenPosition) { dom.style.left = `${screenPosition.x}px` dom.style.top = `${screenPosition.y}px` @@ -101,15 +144,19 @@ removeDom() } // 自动清理 onUnmounted(() => { const removeAll = () => { removeHandler() removeLabel() } // 自动清理 onUnmounted(() => { removeAll() }) return { currentClickEntity, handlerInit, removeHandler removeAll, removeLabel } } src/hooks/useMapAggregation/useMapAggregation.js
@@ -3,30 +3,19 @@ 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 { getEventImage } from '@/utils/stateToImageMap/event' import { getDroneStatusImage } from '@/utils/stateToImageMap/drone' import eventPending from '@/assets/images/home/useEventOperate/eventPending.png' // 待处理 0 import eventWaitAudit from '@/assets/images/home/useEventOperate/eventWaitAudit.png' // 待审核 2 import eventProcessing from '@/assets/images/home/useEventOperate/eventProcessing.png' // 处理中 3 import eventCompleted from '@/assets/images/home/useEventOperate/eventCompleted.png' // 已完成 4 import eventClosed from '@/assets/images/home/useEventOperate/eventClosed.png' // 已完结 5 import DevicePopUpBox from '@/hooks/components/DevicePopUpBox.vue' import EventPopUpBox from '@/hooks/components/EventPopUpBox.vue' // 机巢图标 import endingImg from '@/assets/images/aiNowFly/ending.png' import endingHighImg from '@/assets/images/aiNowFly/ending-high.png' 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' /** * 机巢聚合功能 */ @@ -51,8 +40,21 @@ const { flyTo } = cesiumOperation() 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' const { handlerInit: mapHandlerInit, removeAll: removeMapHandlerAll, removeLabel: removeMapLabel } = useMapHandlerClick({ popupType: `${type}-popup`, eventType: eventType, styleTransform, getViewer () { return viewer } }) let scalingJudgment = [ { name: '县', splashedList: [], gJson: null, show: false, outline: {}, value: [0, 48651], height: 31753 }, @@ -69,8 +71,6 @@ ] let viewer = null let active = null let handler = null let currentEntity = null const store = useStore() const userAreaCode = computed(() => store.state.user.userInfo.detail.areaCode) @@ -104,7 +104,7 @@ 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) @@ -288,7 +288,7 @@ needFly = true if (!viewer) return handlerInit() mapHandlerInit() viewer.scene.postRender.removeEventListener(determineScaling) @@ -302,15 +302,7 @@ //散点机巢 function splashed (row) { row.splashedList.forEach((item, index) => { const eventImage = { 0: eventPending, 2: eventWaitAudit, 3: eventProcessing, 4: eventCompleted, 5: eventClosed } const image = type === 'device' ? (item.status === "OFFLINE" ? endingHighImg : endingImg) : eventImage[item.status] || eventSingle const image = type === 'device' ? getDroneStatusImage(item.status) : getEventImage(item.status) viewer.entities.add({ id: `aggregation-splashed-${index}`, @@ -470,33 +462,6 @@ }) } // 获取弹框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' } } /** * 根据条件获取项 @@ -506,41 +471,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 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 实体 @@ -556,11 +486,7 @@ item.includes('aggregation-') && viewer.entities.removeById(item) }) } // 移除弹框标签 const removeLabel = () => { viewer?.scene.postRender.removeEventListener(labelBoxRender) removeDom() } // 移除所有监听事件,变量置空 const removeAll = () => { @@ -571,14 +497,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 = () => { @@ -588,14 +512,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(() => { }) src/hooks/useSingleDroneMap/useSingleDroneMap.js
@@ -2,25 +2,18 @@ * @Author: shuishen 1109946754@qq.com * @Date: 2025-04-15 22:41:40 * @LastEditors: shuishen 1109946754@qq.com * @LastEditTime: 2025-04-17 15:05:32 * @LastEditTime: 2025-04-17 20:24:19 * @FilePath: \command-center-dashboard\src\hooks\useSingleDroneMap\useSingleDroneMap.js * @Description: * * Copyright (c) 2025 by shuishen, All Rights Reserved. */ import * as Cesium from 'cesium' import { render } from 'vue' import endingImg from '@/assets/images/aiNowFly/ending.png' import endingHighImg from '@/assets/images/aiNowFly/ending-high.png' import EventPopUpBox from '@/hooks/components/EventPopUpBox.vue' import eventSingle from '@/assets/images/home/useEventOperate/eventSingle.png' import { getEventImage } from '@/utils/stateToImageMap/event' import { getDroneFlagImage } from '@/utils/stateToImageMap/drone' import eventPending from '@/assets/images/home/useEventOperate/eventPending.png' // 待处理 0 import eventWaitAudit from '@/assets/images/home/useEventOperate/eventWaitAudit.png' // 待审核 2 import eventProcessing from '@/assets/images/home/useEventOperate/eventProcessing.png' // 处理中 3 import eventCompleted from '@/assets/images/home/useEventOperate/eventCompleted.png' // 已完成 4 import eventClosed from '@/assets/images/home/useEventOperate/eventClosed.png' // 已完结 5 import { useMapHandlerClick } from '@/hooks/components/useMapHandlerClick' /** * @@ -31,20 +24,18 @@ eventApi: null, eventApiParams: {} }) { const styleTransform = 'translate(-50%,-110%)' const { eventPositions, eventApi, eventApiParams } = options const eventImage = { 0: eventPending, 2: eventWaitAudit, 3: eventProcessing, 4: eventCompleted, 5: eventClosed } let viewer = null let handler = null let currentEntity = null const { handlerInit: mapHandlerInit, removeAll: removeMapHandlerAll } = useMapHandlerClick({ getViewer () { return viewer } }) // 初始化机场位置 const initDroneEntity = (dronePosition) => { @@ -52,7 +43,7 @@ if (!lng || !lat) return const markerImg = status ? endingHighImg : endingImg const markerImg = getDroneFlagImage(status) const position = Cesium.Cartesian3.fromDegrees(+lng, +lat, 0) const droneEntity = viewer?.entities.add({ @@ -93,7 +84,7 @@ eventData.length && eventData.forEach((item, index) => { const { longitude, latitude, status, id } = item const curImg = eventImage[status] || eventSingle const curImg = getEventImage(status) const position = Cesium.Cartesian3.fromDegrees(+longitude, +latitude, 0) @@ -109,7 +100,7 @@ customData: { data: { ...item, eventId: item.id, eventId: id, type: 'single-drone-event' } } @@ -155,104 +146,20 @@ }) } // 查找特定类型的实体 const findEntityByType = (entities, type) => { return entities.find(entity => entity?.properties?.customData?._value?.data?.type === type ) } // 左键单机事件 const singleMachineEvent = async click => { currentEntity = null let clickedEntities = viewer?.scene.drillPick(click.position).map(item => item.id) if (!clickedEntities?.length) return 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() mapHandlerInit() } const removeAll = () => { removeLayer() removeHandler() removeLabel() removeMapHandlerAll() } onMounted(() => { nextTick(() => { init() }) onMounted(async () => { await nextTick() init() }) // 自动清理