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
271 ■■■■■ 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 83 ●●●●● 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 />
            </template>
            <TaskDetailsLeft />
            </template>
            <!--    控制面板,里面有方法需要立即执行,不可用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,17 +20,27 @@
 * 机巢聚合功能
 */
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 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%)'
@@ -55,7 +67,6 @@
  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)
@@ -71,7 +82,6 @@
  }))
  let saveParams = { area_code: '', date_enum: 'CURRENT_WEEK' }
  // 确定缩放比例
  const determineScaling = () => {
@@ -110,13 +120,16 @@
  // 获取设备聚合
  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 }))
    })
  }
@@ -163,9 +176,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] }
  }
@@ -184,9 +195,15 @@
    if (!areaCode) return
    saveParams.area_code = areaCode
    const list = type === 'device' ? await getDeviceCount(areaCode) : await getMapEventCount(saveParams)
    const splashedList = type === 'device'
        const splashedList =
            type === 'device'
      ? await getDeviceList(areaCode)
      : eventList.map(i => ({ eventId: i.id, latitude: Number(i.latitude), longitude: Number(i.longitude), type: 'event' }))
                : 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('/')
@@ -225,21 +242,23 @@
    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) => {
    watch(
        combinedValues,
        async (newValue, oldValue) => {
    if (newValue.singleUavHome?.device_sn) {
      clearMapEntity()
      return
@@ -250,7 +269,11 @@
    }
    if (newValue.eventTimeRang) {
      saveParams = { area_code: newValue.selectedAreaCode, start_date: newValue.eventTimeRang[0], end_date: newValue.eventTimeRang[1] }
                saveParams = {
                    area_code: newValue.selectedAreaCode,
                    start_date: newValue.eventTimeRang[0],
                    end_date: newValue.eventTimeRang[1],
                }
    }
    needFly = true
@@ -269,6 +292,7 @@
  //散点机巢
  function splashed (row) {
    row.splashedList.forEach((item, index) => {
      viewer.entities.add({
        id: `aggregation-splashed-${index}`,
        position: Cesium.Cartesian3.fromDegrees(item.longitude, item.latitude),
@@ -283,7 +307,10 @@
          pixelOffset: new Cesium.Cartesian2(0, -9),
        },
        billboard: {
          image: new Cesium.ConstantProperty(singleImg),
          // singleImg
                    image: new Cesium.ConstantProperty(()=>{
            return item.status ==="OFFLINE" ? offlinesingleImg:singleImg
          }),
          width: 24,
          height: 24,
        },
@@ -312,7 +339,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
@@ -334,14 +361,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])
@@ -406,7 +433,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
@@ -417,7 +444,8 @@
        entity.polygon.outline = false // 显示边框
      })
      needFly && viewer.flyTo(dataSource, {
            needFly &&
                viewer.flyTo(dataSource, {
        offset: new Cesium.HeadingPitchRange(0, Cesium.Math.toRadians(-60), 0),
        duration: 0.5,
      })
@@ -468,12 +496,15 @@
    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')
        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 === 'event')
    // let eventFind = findTypeItem(clickTargets, (item) => item?.properties?.customData?._value?.data?.type === 'eventAggregation')
    currentEntity = deviceAggregationFind || deviceFind || eventFind
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
    }
}