forked from drone/command-center-dashboard

chenyao
2025-04-17 2ddedb48ebcb4952e57aefe2fa0b2ba8094ea4c0
Merge branch 'master' of http://139.196.74.78:10010/r/drone/command-center-dashboard
9 files modified
1 files added
1181 ■■■■ changed files
src/api/drc.js 4 ●●●● patch | view | raw | blame | history
src/api/payload.js 3 ●●●● patch | view | raw | blame | history
src/assets/images/taskManagement/taskIntermediateContent/amplifyImg.png patch | view | raw | blame | history
src/components/CurrentTaskDetails/ControlPanel/ControlPanel.vue 54 ●●●●● patch | view | raw | blame | history
src/components/CurrentTaskDetails/CurrentTaskDetails.vue 101 ●●●● patch | view | raw | blame | history
src/components/CurrentTaskDetails/TaskDetailsLeft.vue 1 ●●●● patch | view | raw | blame | history
src/const/drc.js 1 ●●●● patch | view | raw | blame | history
src/hooks/controlDrone/useManualControl.js 16 ●●●● patch | view | raw | blame | history
src/hooks/useMapAggregation/useMapAggregation.js 993 ●●●● patch | view | raw | blame | history
src/websocket/index.js 8 ●●●●● patch | view | raw | blame | history
src/api/drc.js
@@ -44,7 +44,7 @@
// 一键返航
export async function returnHome(sn) {
  return request({
    url: `/dp/home/${sn}/drc/returnHome`,
    url: `/drone-device-core/dp/home/${sn}/drc/returnHome`,
    method: 'post',
  })
}
@@ -52,7 +52,7 @@
// 取消返航
export async function returnHomeCancel(sn) {
  return request({
    url: `/dp/home/${sn}/drc/returnHomeCancel`,
    url: `/drone-device-core/dp/home/${sn}/drc/returnHomeCancel`,
    method: 'post',
  })
}
src/api/payload.js
@@ -23,10 +23,11 @@
    return await request.post(`${API_PREFIX}/devices/${sn}/payload/commands`, body, config)
}
// 拍照和录像
export async function callPhotoAndVideoCmd(sn, type) {
  return await request({
    url:`/droneAirport/liveStreamApi/${sn}/payload/photoAndVideoCmd/${type}`,
    url:`/drone-device-core/droneAirport/liveStreamApi/${sn}/payload/photoAndVideoCmd/${type}`,
    method:'get',
  })
}
src/assets/images/taskManagement/taskIntermediateContent/amplifyImg.png
src/components/CurrentTaskDetails/ControlPanel/ControlPanel.vue
@@ -147,9 +147,19 @@
const deviceOsdInfo = inject('deviceOsdInfo')
const taskDetails = inject('taskDetails')
const dockSn = inject('dockSn')
const droneSn = inject('droneSn')
const store = useStore()
let mqttState = null
const client_id = ref('')
const valueTime = ref('00:00:00')
let timer = null
let totalSeconds = 0
const workspace_id = computed(() => taskDetails?.value?.workspace_id)
const dock_sn = computed(() => taskDetails.value.device_sns[0])
const list1 = [
    { key: KeyCode.KEY_Q, text: 'Q', icon: RefreshLeft },
    { key: KeyCode.KEY_W, text: 'W', icon: ArrowUp },
@@ -162,6 +172,7 @@
]
const speed = ref(5)
provide('speed',speed)
const list5 = [
    { name: '上', style: { top: '-70%' }, imgStyle: { top: '20%', left: '50%' } },
@@ -183,21 +194,15 @@
    ],
]
let mqttState = null
const client_id = ref('')
const valueTime = ref('00:00:00')
let timer = null
let totalSeconds = 0
const deviceTopicInfo = ref({
    sn: deviceOsdInfo.value?.data?.sn,
    pubTopic: '',
    subTopic: '',
})
const flightController = ref(false)
// 控制对象
let manualControl = {}
const sn = computed(() => deviceOsdInfo?.value?.data?.sn)
const isAutoControl = inject('isAutoControl')
const timeStart = () => {
@@ -222,7 +227,7 @@
// 按下操作
function onMouseDown(type) {
    manualControl?.handleKeyup(type, { sn: sn.value, speed: speed.value })
    manualControl?.handleKeyup(type)
}
// 弹起操作
@@ -232,7 +237,7 @@
// 取消手动控制
function cancelControl() {
    exitController({ client_id: client_id.value, dock_sn: dock_sn.value })
    exitController({ client_id: client_id.value, dock_sn: dockSn.value })
        .then(res => {
            flightController.value = false
            deviceTopicInfo.value.subTopic = ''
@@ -245,8 +250,8 @@
// 手动控制
function control() {
    if (!client_id.value) return ElMessage.error('无人机不在空中,不能进入指挥飞行模式。')
    if (!dock_sn.value) return ElMessage.error('系统错误,未获取到dock_sn')
    droneController({ client_id: client_id.value, dock_sn: dock_sn.value }).then(res => {
    if (!dockSn.value) return ElMessage.error('系统错误,未获取到dock_sn')
    droneController({ client_id: client_id.value, dock_sn: dockSn.value }).then(res => {
        flightController.value = true
        const { data } = res.data
        if (data.sub && data.sub?.length > 0) {
@@ -262,14 +267,14 @@
// 返航
function onBackDock() {
    returnHome(dock_sn.value).then(res => {
    returnHome(dockSn?.value).then(res => {
        ElMessage.success('返航操作成功')
    })
}
// 取消返航
function cancelBackDock() {
    returnHomeCancel({ client_id: this.clientId, dock_sn: this.sn }).then(res => {
    returnHomeCancel(dockSn?.value).then(res => {
        ElMessage.success('取消返航成功')
    })
}
@@ -303,13 +308,19 @@
    }
}
// useManualControl里面用的参数
const paramsRef = computed(()=>({
    droneSn:droneSn.value,
    speed:speed.value,
}))
watch(
    () => workspace_id.value,
    async () => {
        if (workspace_id.value) {
            await createConnect()
            // 使用控制
            manualControl = useManualControl(mqttState, deviceTopicInfo.value, flightController)
            manualControl = useManualControl(mqttState, deviceTopicInfo.value, flightController,paramsRef)
        }
    }
)
@@ -358,7 +369,7 @@
    position: absolute;
    bottom: 0;
    right: 0;
    width: 1540px;
    width: 1400px;
    height: 217px;
    background: linear-gradient(196deg, rgba(23, 23, 23, 0.11) 0%, rgba(6, 6, 6, 0.11) 100%);
    backdrop-filter: blur(5px);
@@ -371,7 +382,7 @@
    pointer-events: all;
    .direction {
        width: 476px;
        width: 400px;
        height: 188px;
        background: rgb(0, 0, 0, 0.4); /* 半透明背景 */
        border-radius: 40px 40px 40px 40px;
@@ -386,7 +397,7 @@
            .btnGroupT,
            .btnGroupB {
                width: 238px;
                width: 180px;
                height: 73px;
            }
        }
@@ -423,7 +434,7 @@
    }
    .ptzControlBox {
        width: 406px;
        width: 386px;
        height: 188px;
        background: rgb(0, 0, 0, 0.4); /* 半透明背景 */
        border-radius: 40px 40px 40px 40px;
@@ -536,7 +547,7 @@
            display: flex;
            flex-direction: column;
            gap: 7px 0;
            width: 70px;
            width: 60px;
            .infoName {
                height: 25px;
@@ -574,8 +585,7 @@
        display: flex;
        align-items: center;
        text-align: center;
        justify-content: center;
        gap: 0 45px;
        justify-content: space-evenly;
        .btnItem {
            .btnIcon {
src/components/CurrentTaskDetails/CurrentTaskDetails.vue
@@ -10,20 +10,20 @@
    >
        <div class="content-container" v-if="isShow">
            <!-- 视频直播 -->
            <div class="video-container">
            <div :class="`${isMaxMap ? 'minBox' : 'maxBox'}`">
                <LiveVideo :videoUrl="currentLiveUrl" :controls="false" />
            </div>
            <!-- 展示地图 -->
            <RealTimeMap class="realTimeMap" />
            <RealTimeMap :class="`${isMaxMap ? 'maxBox' : 'minBox'}`" />
            <TaskDetailsRight v-if="isAutoControl" />
            <template v-else>
                <TaskDetailsHead />
                <TaskDetailsLeft />
            </template>
            <TaskDetailsLeft />
            <!--    控制面板,里面有方法需要立即执行,不可用v-if        -->
            <ControlPanel v-show="!isAutoControl" />
            <img alt="" :src="amplifyImg" class="amplify" @click="amplify" />
        </div>
    </el-dialog>
</template>
@@ -42,6 +42,7 @@
import TaskDetailsHead from '@/components/CurrentTaskDetails/TaskDetailsHead.vue'
import TaskDetailsLeft from '@/components/CurrentTaskDetails/TaskDetailsLeft.vue'
import TaskDetailsRight from '@/components/CurrentTaskDetails/TaskDetailsRight.vue'
import amplifyImg from '@/assets/images/taskManagement/taskIntermediateContent/amplifyImg.png'
import { ElMessage } from 'element-plus'
import EventBus from '@/event-bus'
@@ -53,49 +54,44 @@
const isShow = defineModel('show')
const props = defineProps(['id'])
const currentLiveUrl = ref('')
const machineNestUrl = ref('')
const droneLiveUrl = ref('')
let taskDetails = ref({})
const deviceOsdInfo = ref({})
provide('taskDetails', taskDetails)
provide('deviceOsdInfo', deviceOsdInfo)
provide('dockSn', taskDetails?.value?.device_sns?.[0])
provide('droneSn', deviceOsdInfo?.value?.data?.sn)
const dockSn = computed(() => taskDetails?.value?.device_sns?.[0])
const droneSn = computed(() => deviceOsdInfo?.value?.data?.sn)
provide('dockSn', dockSn)
provide('droneSn', droneSn)
const isMaxMap = ref(false)
const amplify = () => {
    isMaxMap.value = !isMaxMap.value
}
// 机巢直播
const getDeviceLiveUrl = async () => {
    if (machineNestUrl.value) return machineNestUrl.value
    const res = await liveStart(taskDetails.value.device_sns[0], 2)
    machineNestUrl.value = res.data.data.rtcs_url
    return machineNestUrl.value
}
// 无人机直播
const getDroneLiveUrl = async droneSn => {
    if (droneLiveUrl.value) return droneLiveUrl.value
    const res = await liveStart(droneSn, lineQuality.value)
    droneLiveUrl.value = res.data.data.rtcs_url
    return droneLiveUrl.value
    const res = await liveStart(dockSn.value, 2)
    currentLiveUrl.value = res.data.data.rtcs_url
}
// 无人机直播画质切换
const changeLineQuality = async () => {
    const res = await liveStart(droneSn, lineQuality.value)
    droneLiveUrl.value = res.data.data.rtcs_url
    return droneLiveUrl.value
    const res = await liveStart(droneSn.value, lineQuality.value)
    currentLiveUrl.value = res.data.data.rtcs_url
}
const isTakeOff = ref(false)
// 设置当前直播地址
const setCurrentLiveUrl = async () => {
    const data = deviceOsdInfo.value?.data
    const deviceInfo = data?.host
    const drone = data?.sn
    if ([14, 0].includes(deviceInfo.mode_code)) {
        currentLiveUrl.value = await getDeviceLiveUrl()
    } else {
        currentLiveUrl.value = await getDroneLiveUrl(drone)
    }
    const currentIsTakeOff = ![14, 0].includes(deviceInfo.mode_code)
    // 如果还是之前的状态,不切换
    if (isTakeOff.value === currentIsTakeOff) return
    isTakeOff.value = currentIsTakeOff
    isTakeOff.value ? await changeLineQuality() : await getDeviceLiveUrl()
}
// 获取任务详情获取航线文件
@@ -103,20 +99,20 @@
    if (!props.id) ElMessage.warning('请检查是否传入id')
    getJobDetails({ wayLineJobInfoId: props.id }).then(async res => {
        taskDetails.value = res.data.data
        currentLiveUrl.value = await getDeviceLiveUrl()
        await getDeviceLiveUrl()
        taskDetails.value.workspace_id = taskDetails.value.way_lines[0]?.workspace_id
        createWsConnect()
    })
}
// websocket 的消息
// websocket 的消息回调
const messageHandler = result => {
    let payload = JSON.parse(result) // 为了兼容聊天消息
    let payload = JSON.parse(result)
    switch (payload.biz_code) {
        case EBizCode.DeviceOsd: {
            deviceOsdInfo.value = payload
            // console.log(deviceOsdInfo.value,'osd信息')
            setCurrentLiveUrl()
            console.log(deviceOsdInfo.value, 'device_osd信息')
            break
        }
        default:
@@ -124,26 +120,14 @@
    }
}
let droneWebSocket
// 创建ws连接
let connectWs
const createWsConnect = () => {
    const workspaceId = taskDetails.value.workspace_id
    if (!workspaceId) return
    let webSocketUrl = getWebsocketUrl() + '&workspace-id=' + workspaceId
    // 监听ws 消息
    connectWs = useConnectWebSocket(messageHandler, webSocketUrl)
}
watch(
    () => taskDetails.value.workspace_id,
    () => {
        createWsConnect()
    }
)
const removeEvent = () => {
    connectWs?.close()
    deviceOsdInfo.value = {}
    droneWebSocket = useConnectWebSocket(messageHandler, webSocketUrl)
}
onMounted(() => {
@@ -152,8 +136,10 @@
})
onBeforeUnmount(() => {
    droneWebSocket?.close()
    deviceOsdInfo.value = {}
    droneWebSocket = null
    EventBus.off('CurrentTaskDetails-timeStop', changeLineQuality)
    removeEvent()
})
</script>
@@ -201,20 +187,27 @@
    border-radius: 4rem;
    overflow: hidden;
    .video-container {
    .maxBox {
        width: 100%;
        height: 100%;
    }
    .realTimeMap {
    .minBox {
        position: absolute;
        left: -1px;
        bottom: -1px;
        width: 218px;
        height: 217px;
        width: 376px;
        height: 212px;
        left: 0;
        bottom: 0;
        border-radius: 0px 20px 0px 40px;
        border: 1px solid #62a1ff;
        overflow: hidden;
    }
    .amplify {
        cursor: pointer;
        position: absolute;
        left: 340px;
        bottom: 183px;
    }
}
</style>
src/components/CurrentTaskDetails/TaskDetailsLeft.vue
@@ -59,6 +59,7 @@
    const type = isRecording.value ? 'video_stop' : 'video_start'
    const msg = isRecording.value ? '停止录像' : '开始录像'
    const emitType = isRecording.value ? 'controlPanel-timeStop' : 'controlPanel-timeStart'
    callPhotoAndVideoCmd(droneSn.value, type).then(res => {
        ElMessage.success(msg)
        EventBus.emit(emitType)
src/const/drc.js
@@ -1,6 +1,7 @@
export const DRC_METHOD = {
    HEART_BEAT: 'heart_beat',
    DRONE_CONTROL: 'drone_control', // 飞行控制-虚拟摇杆
    DRONE_CONTROL2: 'stick_control', // 2代及以上飞行控制-摇杆
    DRONE_EMERGENCY_STOP: 'drone_emergency_stop', // 急停
    OSD_INFO_PUSH: 'osd_info_push', // 高频osd信息上报
    HSI_INFO_PUSH: 'hsi_info_push', // 避障信息上报
src/hooks/controlDrone/useManualControl.js
@@ -34,15 +34,15 @@
        KEY_M: 'KeyM',
    }
export function useManualControl(mqttState,deviceTopicInfo, isCurrentFlightController) {
export function useManualControl(mqttState,deviceTopicInfo, isCurrentFlightController,paramsRef) {
    const activeCodeKey = ref(null)
    let genPortOne = true //是一代机场
    const mqttHooks = useMqtt(mqttState,deviceTopicInfo)
    let seq = 0
    function handlePublish(params) {
        const body = {
            method: DRC_METHOD.DRONE_CONTROL,
            method: genPortOne ? DRC_METHOD.DRONE_CONTROL : DRC_METHOD.DRONE_CONTROL2,
            data: params,
        }
        handleClearInterval()
@@ -54,18 +54,18 @@
        }, 50)
    }
    function handleKeyup(keyCode,params) {
        const {sn,speed} = params
        let genPortOne = false //是一代机场
    function handleKeyup(keyCode) {
        const  {droneSn,speed} =  paramsRef.value
        if (!deviceTopicInfo.pubTopic) {
            ElMessage.error('请确保已经建立DRC链路')
            return
        }
        if (sn === '4TADKCM0010016' || sn === 'BA0BA1C3D38157A49E1B16574FA474F7') {
        if (droneSn.value === '4TADKCM0010016' || droneSn.value === 'BA0BA1C3D38157A49E1B16574FA474F7') {
            genPortOne = true
        }
        const SPEED = genPortOne ? (speed || 5) : 500 //  check
        const SPEED = genPortOne ? (speed.value || 5) : 500 //  check
        const HEIGHT = genPortOne ? 5 : 500; //  check
        const W_SPEED = genPortOne ? 20 : 500 // 机头角速度
src/hooks/useMapAggregation/useMapAggregation.js
@@ -6,7 +6,9 @@
import DevicePopUpBox from '@/hooks/components/DevicePopUpBox.vue'
import EventPopUpBox from '@/hooks/components/EventPopUpBox.vue'
// 图标
import offlineImg from '@/assets/images/home/useEventOperate/offline.png'
import onlineImg from '@/assets/images/home/useEventOperate/eventSingle.png'
import { render } from 'vue'
import { useStore } from 'vuex'
import { getCenterPoint } from '@/utils/cesium/mapUtil'
@@ -18,548 +20,577 @@
 * 机巢聚合功能
 */
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]
function getColor() {
    return arrColor[++index % arrColor.length]
}
export const useMapAggregation = type => {
  const { flyTo } = cesiumOperation()
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 singleImg = type === 'device' ? onlineImg : eventSingle
  const offlinesingleImg = type === 'device' ? offlineImg : eventSingle
    const mergeImg = type === 'device' ? aggregationImg : eventAggregationImg
    const MapPopUpBox = type === 'device' ? DevicePopUpBox : EventPopUpBox
    const styleTransform = type === 'device' ? 'translateY(-50%)' : 'translate(-50%,-110%)'
  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,
    },
  ]
  let viewer = null
  let active = null
  let handler = null
  let currentEntity = null
    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,
        },
    ]
    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 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)
  const eventTimeType = computed(() => store.state.home.eventTimeType)
  const eventTimeRang = computed(() => store.state.home.eventTimeRang)
    const singleUavHome = computed(() => store.state.home.singleUavHome)
  const singleUavHome = computed(() => store.state.home.singleUavHome)
    let needFly = true
  let needFly = true
    const combinedValues = computed(() => ({
        selectedAreaCode: selectedAreaCode.value,
        eventTimeType: eventTimeType.value,
        eventTimeRang: eventTimeRang.value,
        singleUavHome: singleUavHome.value,
    }))
  const combinedValues = computed(() => ({
    selectedAreaCode: selectedAreaCode.value,
    eventTimeType: eventTimeType.value,
    eventTimeRang: eventTimeRang.value,
    singleUavHome: singleUavHome.value,
  }))
    let saveParams = { area_code: '', date_enum: 'CURRENT_WEEK' }
  let saveParams = { area_code: '', date_enum: 'CURRENT_WEEK' }
    // 确定缩放比例
    const determineScaling = () => {
        // console.log('确定缩放比例');
        if (!viewer) return
        let height = viewer.camera.positionCartographic.height
        // 根据高度展示对应的 gJson
        for (let [index, item] of scalingJudgment.entries()) {
            if (!item.show) return
            if (height > item.value[0] && height <= item.value[1]) {
                if (active === item.name) return
                active = item.name
                removeEntities()
                removeLabel()
                renderOutline(item)
                if (!item.gJson && !item.splashedList?.length) return
                item.gJson ? aggregation(item) : splashed(item)
                break
            }
        }
    }
    // 转换为目录结构, 返回数组,
    function convertToHierarchy(code) {
        const codeStr = code.toString()
        const provinceCode = codeStr.slice(0, 2) + '0000'
        const cityCode = codeStr.slice(0, 4) + '00'
        if (codeStr.slice(2, 4) === '00' && codeStr.slice(4, 6) === '00') {
            return [provinceCode]
        } else if (codeStr.slice(4, 6) === '00') {
            return [provinceCode, cityCode]
        }
        return [provinceCode, cityCode, code]
    }
  // 确定缩放比例
  const determineScaling = () => {
    // console.log('确定缩放比例');
    if (!viewer) return
    let height = viewer.camera.positionCartographic.height
    // 根据高度展示对应的 gJson
    for (let [index, item] of scalingJudgment.entries()) {
      if (!item.show) return
      if (height > item.value[0] && height <= item.value[1]) {
        if (active === item.name) return
        active = item.name
        removeEntities()
        removeLabel()
        renderOutline(item)
        if (!item.gJson && !item.splashedList?.length) return
        item.gJson ? aggregation(item) : splashed(item)
        break
      }
    }
  }
    // 获取设备聚合
    function getDeviceCount(areaCode) {
        return getDeviceRegionCount({ areaCode }).then(res => {
            return res?.data?.data || []
        })
    }
    // 获取设备散点
    function getDeviceList(areaCode) {
        return getDeviceRegion({ areaCode }).then(res => {
            return (res?.data?.data || []).map(i => ({ ...i, type }))
  // 转换为目录结构, 返回数组,
  function convertToHierarchy (code) {
    const codeStr = code.toString()
    const provinceCode = codeStr.slice(0, 2) + '0000'
    const cityCode = codeStr.slice(0, 4) + '00'
    if (codeStr.slice(2, 4) === '00' && codeStr.slice(4, 6) === '00') {
      return [provinceCode]
    } else if (codeStr.slice(4, 6) === '00') {
      return [provinceCode, cityCode]
    }
    return [provinceCode, cityCode, code]
  }
        })
    }
  // 获取设备聚合
  function getDeviceCount (areaCode) {
    return getDeviceRegionCount({ areaCode }).then(res => {
      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) {
                eventList = eventList.concat(item.data)
            }
            const returnObj = {
                total_device_count: item.number,
                region_code: item.id,
                region_name: item.name,
            }
            if (arr.length !== 0) {
                returnObj.childrens = arr
            }
            return returnObj
        })
    }
  // 事件散点
  let eventList = []
  function processChildren (childrens) {
    // console.log(childrens, '事件点')
    return (childrens || []).map(item => {
      const arr = processChildren(item.childrens)
      if (item.data) {
        eventList = eventList.concat(item.data)
      }
      const returnObj = {
        total_device_count: item.number,
        region_code: item.id,
        region_name: item.name,
      }
      if (arr.length !== 0) {
        returnObj.childrens = arr
      }
      return returnObj
    })
  }
    // 获取事件聚合
    function getMapEventCount(params) {
        return getMapEvents(params).then(res => {
            const resData = res?.data?.data
            if (resData?.data) {
                eventList = resData?.data
                return []
            }
            return processChildren(resData?.childrens)
        })
    }
  // 获取事件聚合
  function getMapEventCount (params) {
    return getMapEvents(params).then(res => {
      const resData = res?.data?.data
      if (resData?.data) {
        eventList = resData?.data
        return []
      }
      return processChildren(resData?.childrens)
    })
  }
    const findFun = (featItem, numItem) => Number(featItem.region_code.slice(0, 6)) === numItem.properties.adcode
    const { VITE_APP_BASE, VITE_APP_ENV } = import.meta.env
    const defaultDir = `${VITE_APP_BASE}${VITE_APP_ENV === 'development' ? 'public/' : ''}geoJson/100000/`
  const findFun = (featItem, numItem) => Number(featItem.region_code.slice(0, 6)) === numItem.properties.adcode
  const { VITE_APP_BASE, VITE_APP_ENV } = import.meta.env
  const defaultDir = `${VITE_APP_BASE}${VITE_APP_ENV === 'development' ? 'public/' : ''}geoJson/100000/`
    const getFiler = async url => {
        const res = await fetch(url)
        return await res.json()
    }
    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]))
        return { type: 'FeatureCollection', features: [features] }
    }
  const getFiler = async url => {
    const res = await fetch(url)
    return await res.json()
  }
  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])
    )
    return { type: 'FeatureCollection', features: [features] }
  }
    const injectData = (gJson, dataList) => {
        return {
            ...gJson,
            features: gJson.features.map(item => {
                const findData = dataList.find(item1 => findFun(item1, item))
                return { ...item, data: { ...findData, type: type + 'Aggregation' } }
            }),
        }
    }
  const injectData = (gJson, dataList) => {
    return {
      ...gJson,
      features: gJson.features.map(item => {
        const findData = dataList.find(item1 => findFun(item1, item))
        return { ...item, data: { ...findData, type: type + 'Aggregation' } }
      }),
    }
  }
    const initMapData = async areaCode => {
        eventList = []
        if (!areaCode) return
        saveParams.area_code = areaCode
        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 hierarchy = convertToHierarchy(areaCode.slice(0, 6))
        const jsonPath = hierarchy.join('/')
        const jsonPathPre = hierarchy.slice(0, hierarchy.length - 1).join('/')
        scalingJudgment = scalingJudgment.map(item => ({ ...item, show: true }))
        scalingJudgment[0].gJson = null
        scalingJudgment[0].splashedList = splashedList
        active = null
        // 省
        if (hierarchy.length === 1) {
            const gJson1 = await getFiler(`${defaultDir}${jsonPath}/indexDistrict.json`)
            const gJson2 = await getFiler(`${defaultDir}${jsonPath}/index.json`)
            scalingJudgment[1].gJson = {
                ...gJson1,
                features: gJson1.features.map(item => {
                    const findData = list.flatMap(item => item.childrens || []).find(item1 => findFun(item1, item))
                    return { ...item, data: { ...findData, type: type + 'Aggregation' } }
                }),
            }
            scalingJudgment[2].gJson = injectData(gJson2, list)
        }
        // 市
        if (hierarchy.length === 2) {
            scalingJudgment[2].gJson = null
            scalingJudgment[2].show = false
            const gJson1 = await getFiler(`${defaultDir}${jsonPath}/index.json`)
            scalingJudgment[1].gJson = injectData(gJson1, list)
        }
        // 区县
        if (hierarchy.length === 3) {
            scalingJudgment[1].gJson = null
            scalingJudgment[1].show = false
            scalingJudgment[2].gJson = null
            scalingJudgment[2].show = false
        }
        // 轮廓
        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
        setCenterPosition({ longitude, latitude, height })
        flyTo({ longitude, latitude }, 0, height)
    }
  const initMapData = async areaCode => {
    eventList = []
    if (!areaCode) return
    saveParams.area_code = areaCode
    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 hierarchy = convertToHierarchy(areaCode.slice(0, 6))
    const jsonPath = hierarchy.join('/')
    const jsonPathPre = hierarchy.slice(0, hierarchy.length - 1).join('/')
    scalingJudgment = scalingJudgment.map(item => ({ ...item, show: true }))
    scalingJudgment[0].gJson = null
    scalingJudgment[0].splashedList = splashedList
    active = null
    // 省
    if (hierarchy.length === 1) {
      const gJson1 = await getFiler(`${defaultDir}${jsonPath}/indexDistrict.json`)
      const gJson2 = await getFiler(`${defaultDir}${jsonPath}/index.json`)
      scalingJudgment[1].gJson = {
        ...gJson1,
        features: gJson1.features.map(item => {
          const findData = list.flatMap(item => item.childrens || []).find(item1 => findFun(item1, item))
          return { ...item, data: { ...findData, type: type + 'Aggregation' } }
        }),
      }
      scalingJudgment[2].gJson = injectData(gJson2, list)
    }
    // 市
    if (hierarchy.length === 2) {
      scalingJudgment[2].gJson = null
      scalingJudgment[2].show = false
      const gJson1 = await getFiler(`${defaultDir}${jsonPath}/index.json`)
      scalingJudgment[1].gJson = injectData(gJson1, list)
    }
    // 区县
    if (hierarchy.length === 3) {
      scalingJudgment[1].gJson = null
      scalingJudgment[1].show = false
      scalingJudgment[2].gJson = null
      scalingJudgment[2].show = false
    }
    // 轮廓
    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
    setCenterPosition({ longitude, latitude, height })
    flyTo({ longitude, latitude }, 0, height)
  }
    const userAreaPosition = computed(() => store.state.home.userAreaPosition)
  const userAreaPosition = computed(() => store.state.home.userAreaPosition)
    const setCenterPosition = position => {
        store.commit('setCurrentAreaPosition', position)
        if (!userAreaPosition.value.longitude) {
            store.commit('setUserAreaPosition', 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
    }
            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
            handlerInit()
    needFly = true
    if (!viewer) return
    handlerInit()
            viewer.scene.postRender.removeEventListener(determineScaling)
    viewer.scene.postRender.removeEventListener(determineScaling)
            initMapData(newValue.selectedAreaCode).then(() => {
                viewer.scene.postRender.addEventListener(determineScaling)
            })
        },
        { deep: true }
    )
    initMapData(newValue.selectedAreaCode).then(() => {
      viewer.scene.postRender.addEventListener(determineScaling)
    })
  },
    { deep: true }
  )
    //散点机巢
    function splashed(row) {
        row.splashedList.forEach((item, index) => {
  //散点机巢
  function splashed (row) {
    row.splashedList.forEach((item, index) => {
      viewer.entities.add({
        id: `aggregation-splashed-${index}`,
        position: Cesium.Cartesian3.fromDegrees(item.longitude, item.latitude),
        label: {
          text: item.nickname,
          font: '12pt Source Han Sans CN',
          fillColor: Cesium.Color.WHITE,
          outlineColor: Cesium.Color.BLACK,
          outlineWidth: 2,
          style: Cesium.LabelStyle.FILL_AND_OUTLINE,
          verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
          pixelOffset: new Cesium.Cartesian2(0, -9),
        },
        billboard: {
          image: new Cesium.ConstantProperty(singleImg),
          width: 24,
          height: 24,
        },
        properties: {
          customData: {
            data: item,
          },
        },
      })
    })
  }
            viewer.entities.add({
                id: `aggregation-splashed-${index}`,
                position: Cesium.Cartesian3.fromDegrees(item.longitude, item.latitude),
                label: {
                    text: item.nickname,
                    font: '12pt Source Han Sans CN',
                    fillColor: Cesium.Color.WHITE,
                    outlineColor: Cesium.Color.BLACK,
                    outlineWidth: 2,
                    style: Cesium.LabelStyle.FILL_AND_OUTLINE,
                    verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
                    pixelOffset: new Cesium.Cartesian2(0, -9),
                },
                billboard: {
          // singleImg
                    image: new Cesium.ConstantProperty(()=>{
            return item.status ==="OFFLINE" ? offlinesingleImg:singleImg
          }),
                    width: 24,
                    height: 24,
                },
                properties: {
                    customData: {
                        data: item,
                    },
                },
            })
        })
    }
  // 渲染轮廓
  const renderOutline = item => {
    item.outline &&
      Cesium.GeoJsonDataSource.load(item.outline).then(dataSource => {
        const entities = dataSource.entities.values
        entities.forEach((entity, index) => {
          // 创建独立折线作为轮廓
          const positions = entity.polygon.hierarchy.getValue().positions
          const randomInt = Math.floor(Math.random() * 5) + 1
    // 渲染轮廓
    const renderOutline = item => {
        item.outline &&
            Cesium.GeoJsonDataSource.load(item.outline).then(dataSource => {
                const entities = dataSource.entities.values
                entities.forEach((entity, index) => {
                    // 创建独立折线作为轮廓
                    const positions = entity.polygon.hierarchy.getValue().positions
                    const randomInt = Math.floor(Math.random() * 5) + 1
          let polygon = {}
                    let polygon = {}
          if (item.name === '县') {
            let material = new PolyGradientMaterial({
              color: Cesium.Color.fromCssColorString(arrColor[randomInt]),
              opacity: 0.7,
              alphaPower: 1.3
            })
                    if (item.name === '县') {
                        let material = new PolyGradientMaterial({
                            color: Cesium.Color.fromCssColorString(arrColor[randomInt]),
                            opacity: 0.7,
                            alphaPower: 1.3,
                        })
            entity.polygon.extrudedHeight = (entity.properties.childrenNum._value || 1) * 500
                        entity.polygon.extrudedHeight = (entity.properties.childrenNum._value || 1) * 500
            entity.polygon.material = material
                        entity.polygon.material = material
            polygon = entity.polygon
            entity.polygon.outline = false // 显示边框
          }
                        polygon = entity.polygon
                        entity.polygon.outline = false // 显示边框
                    }
          viewer.entities.add({
            id: `aggregation-outline-${index}`,
            polyline: {
              positions: positions,
              width: 5, // 直接设置宽度
              material: new Cesium.PolylineGlowMaterialProperty({
                glowPower: 0.5,
                color: Cesium.Color.AQUA,
              }),
            },
                    viewer.entities.add({
                        id: `aggregation-outline-${index}`,
                        polyline: {
                            positions: positions,
                            width: 5, // 直接设置宽度
                            material: new Cesium.PolylineGlowMaterialProperty({
                                glowPower: 0.5,
                                color: Cesium.Color.AQUA,
                            }),
                        },
            polygon
          })
        })
      })
  }
                        polygon,
                    })
                })
            })
    }
  // 聚合机巢
  const aggregation = (item) => {
    if (!item.gJson) return
    const featuresList = item.gJson.features.map(item1 => {
      // const {lng,lat} = getCenterPoint(item1.geometry.coordinates[0][0])
      return {
        name: item1.properties.name,
        position: item1.properties.centroid,
        data: item1.data,
        id: item1.region_code,
      }
    })
    // 遍历特征并添加实体
    featuresList.forEach((feature, index) => {
      if (!feature.position) return
      const position = Cesium.Cartesian3.fromDegrees(feature.position[0], feature.position[1], 0)
      viewer.entities.add({
        position: position,
        id: `aggregation-name-${index}`,
        label: {
          text: feature.name,
          font: '14pt Source Han Sans CN',
          fillColor: Cesium.Color.WHITE,
          outlineColor: Cesium.Color.BLACK,
          outlineWidth: 2,
          style: Cesium.LabelStyle.FILL_AND_OUTLINE,
          verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
          pixelOffset: new Cesium.Cartesian2(0, -9),
        },
      })
      viewer.entities.add({
        id: `aggregation-count-${index}`,
        position: position,
        label: {
          text: (feature.data.total_device_count || 0).toString(),
          font: '12pt Source Han Sans CN',
          fillColor: Cesium.Color.BLACK,
          outlineColor: Cesium.Color.BLACK,
          style: Cesium.LabelStyle.FILL_AND_OUTLINE,
          eyeOffset: new Cesium.Cartesian3(0, 0, -10), // 让label "浮" 在广告牌前面
        },
        billboard: {
          image: new Cesium.ConstantProperty(mergeImg),
          width: 35,
          height: 35,
        },
        properties: {
          id: feature.id,
          customData: {
            data: feature.data,
          },
        },
      })
    })
    // 聚合机巢
    const aggregation = item => {
        if (!item.gJson) return
        const featuresList = item.gJson.features.map(item1 => {
            // const {lng,lat} = getCenterPoint(item1.geometry.coordinates[0][0])
            return {
                name: item1.properties.name,
                position: item1.properties.centroid,
                data: item1.data,
                id: item1.region_code,
            }
        })
        // 遍历特征并添加实体
        featuresList.forEach((feature, index) => {
            if (!feature.position) return
            const position = Cesium.Cartesian3.fromDegrees(feature.position[0], feature.position[1], 0)
            viewer.entities.add({
                position: position,
                id: `aggregation-name-${index}`,
                label: {
                    text: feature.name,
                    font: '14pt Source Han Sans CN',
                    fillColor: Cesium.Color.WHITE,
                    outlineColor: Cesium.Color.BLACK,
                    outlineWidth: 2,
                    style: Cesium.LabelStyle.FILL_AND_OUTLINE,
                    verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
                    pixelOffset: new Cesium.Cartesian2(0, -9),
                },
            })
            viewer.entities.add({
                id: `aggregation-count-${index}`,
                position: position,
                label: {
                    text: (feature.data.total_device_count || 0).toString(),
                    font: '12pt Source Han Sans CN',
                    fillColor: Cesium.Color.BLACK,
                    outlineColor: Cesium.Color.BLACK,
                    style: Cesium.LabelStyle.FILL_AND_OUTLINE,
                    eyeOffset: new Cesium.Cartesian3(0, 0, -10), // 让label "浮" 在广告牌前面
                },
                billboard: {
                    image: new Cesium.ConstantProperty(mergeImg),
                    width: 35,
                    height: 35,
                },
                properties: {
                    id: feature.id,
                    customData: {
                        data: feature.data,
                    },
                },
            })
        })
    // 加载边界
    Cesium.GeoJsonDataSource.load(item.gJson).then(dataSource => {
      viewer.dataSources.add(dataSource)
      item.BJDataSource = dataSource // 保存数据源以便后续删除
      // 获取数据源中的实体
      const entities = dataSource.entities.values
        // 加载边界
        Cesium.GeoJsonDataSource.load(item.gJson).then(dataSource => {
            viewer.dataSources.add(dataSource)
            item.BJDataSource = dataSource // 保存数据源以便后续删除
            // 获取数据源中的实体
            const entities = dataSource.entities.values
      entities.forEach(entity => {
        let material = new PolyGradientMaterial({
          color: Cesium.Color.fromCssColorString(getColor()),
          opacity: 0.7,
          alphaPower: 1.3
        })
            entities.forEach(entity => {
                let material = new PolyGradientMaterial({
                    color: Cesium.Color.fromCssColorString(getColor()),
                    opacity: 0.7,
                    alphaPower: 1.3,
                })
        const randomInt = Math.floor(Math.random() * 8) + 1
                const randomInt = Math.floor(Math.random() * 8) + 1
        entity.polygon.extrudedHeight = (entity.properties.childrenNum._value || randomInt) * 500
                entity.polygon.extrudedHeight = (entity.properties.childrenNum._value || randomInt) * 500
        entity.polygon.material = material
        entity.polygon.outline = false // 显示边框
      })
                entity.polygon.material = material
                entity.polygon.outline = false // 显示边框
            })
      needFly && viewer.flyTo(dataSource, {
        offset: new Cesium.HeadingPitchRange(0, Cesium.Math.toRadians(-60), 0),
        duration: 0.5,
      })
      needFly = false
    })
  }
            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
  }
    // 获取弹框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'
    }
  }
    // 弹框位置刷新
    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'
        }
    }
  /**
   * 根据条件获取项
   * @param {Array} arr 数据源
   * @param {Function} condition 条件
   * @returns
   */
  const findTypeItem = (arr, condition) => {
    return arr.find(item => condition(item))
  }
    /**
     * 根据条件获取项
     * @param {Array} arr 数据源
     * @param {Function} condition 条件
     * @returns
     */
    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
    // 左键单机事件
    const singleMachineEvent = async click => {
        let clickTargets = viewer.scene.drillPick(click.position).map(item => item.id)
        if (!clickTargets.length) return
    console.log(clickTargets, 11111)
        // 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
        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)
    }
  }
        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)
    }
  }
    const removeDom = () => {
        const dom = document.querySelector('#mapPopUpBox')
        if (dom && dom.parentNode) {
            dom.parentNode.removeChild(dom)
        }
    }
  // 移除 点 和 gjson 实体
  const removeEntities = () => {
    // dataSources移除
    scalingJudgment.forEach(item => {
      item.BJDataSource && viewer.dataSources.remove(item.BJDataSource)
      item.BJDataSource = null
    })
    // entities移除
    const entitiesIDs = viewer.entities.values.map(i => i.id)
    entitiesIDs.forEach(item => {
      item.includes('aggregation-') && viewer.entities.removeById(item)
    })
  }
  // 移除弹框标签
  const removeLabel = () => {
    viewer?.scene.postRender.removeEventListener(labelBoxRender)
    removeDom()
  }
    // 移除 点 和 gjson 实体
    const removeEntities = () => {
        // dataSources移除
        scalingJudgment.forEach(item => {
            item.BJDataSource && viewer.dataSources.remove(item.BJDataSource)
            item.BJDataSource = null
        })
        // entities移除
        const entitiesIDs = viewer.entities.values.map(i => i.id)
        entitiesIDs.forEach(item => {
            item.includes('aggregation-') && viewer.entities.removeById(item)
        })
    }
    // 移除弹框标签
    const removeLabel = () => {
        viewer?.scene.postRender.removeEventListener(labelBoxRender)
        removeDom()
    }
  // 移除所有监听事件,变量置空
  const removeAll = () => {
    clearMapEntity()
    viewer = null
  }
    // 移除所有监听事件,变量置空
    const removeAll = () => {
        clearMapEntity()
        viewer = null
    }
  const clearMapEntity = () => {
    if (!viewer) return
    removeEntities()
    removeLabel()
    // 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 clearMapEntity = () => {
        if (!viewer) return
        removeEntities()
        removeLabel()
        // 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 = () => {
    viewer = window.$viewer
    viewer.scene.postRender.removeEventListener(determineScaling)
    initMapData(selectedAreaCode.value || userAreaCode.value).then(() => {
      viewer.scene.postRender.addEventListener(determineScaling)
    })
    const init = () => {
        viewer = window.$viewer
        viewer.scene.postRender.removeEventListener(determineScaling)
        initMapData(selectedAreaCode.value || userAreaCode.value).then(() => {
            viewer.scene.postRender.addEventListener(determineScaling)
        })
    handlerInit()
  }
        handlerInit()
    }
  const handlerInit = () => {
    if (handler) return
    const handlerInit = () => {
        if (handler) return
    handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
    handler.setInputAction(singleMachineEvent, Cesium.ScreenSpaceEventType.LEFT_CLICK)
  }
        handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
        handler.setInputAction(singleMachineEvent, Cesium.ScreenSpaceEventType.LEFT_CLICK)
    }
  onBeforeUnmount(() => { })
  // onMounted(() => {
  //   nextTick(() => {
  //     viewer = window.$viewer;
  //     handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
  //     handler.setInputAction(singleMachineEvent, Cesium.ScreenSpaceEventType.LEFT_CLICK);
  //   });
  // });
    onBeforeUnmount(() => {})
    // onMounted(() => {
    //   nextTick(() => {
    //     viewer = window.$viewer;
    //     handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
    //     handler.setInputAction(singleMachineEvent, Cesium.ScreenSpaceEventType.LEFT_CLICK);
    //   });
    // });
  return { init, removeAll }
    return { init, removeAll }
}
src/websocket/index.js
@@ -40,15 +40,15 @@
    }
    _onOpen() {
        console.log('连接成功')
        console.log('ws连接成功')
    }
    _onClose() {
        console.log('连接已断开')
        console.log('ws连接已断开')
    }
    _onError() {
        console.log('连接 error')
        console.log('ws连接 error')
    }
    registerMessageHandler(messageHandler) {
@@ -68,6 +68,8 @@
    close() {
        this._socket?.close()
        this._messageHandler = null
        this._socket = null
    }
}