chenyao
2025-03-13 bdc6d8733ae6eeb3a9762e77dbabe21441336474
更新分享
15 files modified
4 files added
4611 ■■■■ changed files
package-lock.json 6 ●●●●● patch | view | raw | blame | history
package.json 1 ●●●● patch | view | raw | blame | history
src/api/http/request.ts 9 ●●●●● patch | view | raw | blame | history
src/api/manage.ts 14 ●●●●● patch | view | raw | blame | history
src/router/index.ts 5 ●●●●● patch | view | raw | blame | history
src/store/index.ts 19 ●●●●● patch | view | raw | blame | history
src/types/drc.ts 4 ●●● patch | view | raw | blame | history
src/types/enums.ts 1 ●●●● patch | view | raw | blame | history
src/utils/mqtt/index.ts 13 ●●●●● patch | view | raw | blame | history
src/views/DronePilotDetails-copy0303.vue 685 ●●●●● patch | view | raw | blame | history
src/views/DronePilotDetails.vue 45 ●●●●● patch | view | raw | blame | history
src/views/DronePilotList.vue 2 ●●●●● patch | view | raw | blame | history
src/views/DronePilotShare.vue 638 ●●●●● patch | view | raw | blame | history
src/views/components/controlConsole-copy.vue 1138 ●●●●● patch | view | raw | blame | history
src/views/components/controlConsole-copy1.vue 1154 ●●●●● patch | view | raw | blame | history
src/views/components/controlConsole.vue 848 ●●●●● patch | view | raw | blame | history
src/views/hooks/droneFly.ts 23 ●●●● patch | view | raw | blame | history
tsconfig.json 2 ●●● patch | view | raw | blame | history
vite.config.ts 4 ●●●● patch | view | raw | blame | history
package-lock.json
@@ -12,6 +12,7 @@
        "@turf/turf": "^6.5.0",
        "axios": "^0.21.1",
        "cesium": "^1.95.0",
        "crypto-js": "^4.2.0",
        "element-plus": "^2.9.2",
        "eventemitter3": "^5.0.0",
        "flv.js": "^1.6.2",
@@ -4106,6 +4107,11 @@
        "node": ">= 8"
      }
    },
    "node_modules/crypto-js": {
      "version": "4.2.0",
      "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz",
      "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q=="
    },
    "node_modules/csstype": {
      "version": "3.1.3",
      "resolved": "https://registry.npmmirror.com/csstype/-/csstype-3.1.3.tgz",
package.json
@@ -14,6 +14,7 @@
    "@turf/turf": "^6.5.0",
    "axios": "^0.21.1",
    "cesium": "^1.95.0",
    "crypto-js": "^4.2.0",
    "element-plus": "^2.9.2",
    "eventemitter3": "^5.0.0",
    "flv.js": "^1.6.2",
src/api/http/request.ts
@@ -67,10 +67,8 @@
    url: string
    authorization: boolean
  }) => {
    if(config.url.includes('h5')) {
      config.url = '/drone-h5' + config.url
    } else if (!config.url.includes('/blade-') && !config.url.includes('https://') && !config.url.includes('http://')) {
      config.url = '/drone-yw' + config.url
    if (!config.url.includes('/blade-') && !config.url.includes('https://') && !config.url.includes('http://')) {
      config.url = '/drone-device-core' + config.url
    }
    const authorization = config.authorization === false
    if (!authorization) {
@@ -81,6 +79,9 @@
    const isToken = meta.isToken === false
    if (getToken() && !isToken) {
      config.headers[website.tokenHeader] = 'bearer ' + getToken()
    } else {
      // 为了兼容分享页面
      config.headers[website.tokenHeader] = 'bearer ' + getAuthToken()
    }
    if (meta.noCookie) {
      delete config.headers.cookie
src/api/manage.ts
@@ -125,6 +125,20 @@
  return result.data
}
// 分享功能先保存token
export const saveToken = async function (body:any): Promise<IWorkspaceResponse<any>> {
  const url = `${HTTP_PREFIX_H5}/saveToken`
  const result = await request.post(url,body)
  return result.data
}
// 分享功能先保存code
export const getTokenByCode = async function (code: string): Promise<IWorkspaceResponse<any>> {
  const url = `${HTTP_PREFIX_H5}/getTokenByCode?code=${code}`
  const result = await request.get(url)
  return result.data
}
// Get User Info
export const getUserInfo = async function (): Promise<IWorkspaceResponse<any>> {
  const url = `${HTTP_PREFIX}/users/current`
src/router/index.ts
@@ -44,6 +44,11 @@
    component: () => import('@/views/DronePilotDetails.vue')
  },
  {
    path: '/dronePilotShare',
    name: ERouterName.DRONEPILOTSHARE,
    component: () => import('@/views/DronePilotShare.vue')
  },
  {
    path: '/' + ERouterName.DRONE,
    name: ERouterName.DRONE,
    component: () => import('@/views/drone/index.vue')
src/store/index.ts
@@ -74,6 +74,20 @@
    psdk_widget_values: {},
    speakerAudioPlayStartProgress: {},
  },
  airPortInfo: {
    sn: '',
    workspaceId: '',
    subType: 0,
    name: '',
    longitude: 0,
    latitude: 0,
    isOnline: false,
    height: 0,
    domain: 0,
    dockSn: '',
    deviceType: 0,
    children: {}
  }, // 保存机场信息
  osdVisible: { // osd 显示设备相关信息
    sn: '',
    callsign: '',
@@ -185,6 +199,10 @@
    state.osdVisible = Object.assign({}, info)
    window.localStorage.setItem('bs_osd', JSON.stringify(info))
  },
  // 保存机场信息
  SET_AIRPORT_INFO (state, info) {
    state.airPortInfo = info
  },
  SET_SELECT_WAYLINE_INFO (state, info) {
    state.waylineInfo = info
  },
@@ -241,7 +259,6 @@
  },
  // 设置视角
  SET_CURRENTANGLE (state, currentAngle) {
    console.log('120')
    state.currentAngle = currentAngle
  }
}
src/types/drc.ts
@@ -1,6 +1,8 @@
import store from '@/store'
console.log('哒哒哒',store.state.airPortInfo)
export enum DRC_METHOD {
  HEART_BEAT = 'heart_beat',
  DRONE_CONTROL = 'drone_control', // 飞行控制-虚拟摇杆
  DRONE_CONTROL = (store.state.airPortInfo.deviceType == 1 && store.state.airPortInfo.subType == 0 && store.state.airPortInfo.domain == 3 )?'drone_control':'stick_control', // 飞行控制-摇杆
  DRONE_EMERGENCY_STOP = 'drone_emergency_stop', // 急停
  OSD_INFO_PUSH = 'osd_info_push', // 高频osd信息上报
  HSI_INFO_PUSH = 'hsi_info_push', // 避障信息上报
src/types/enums.ts
@@ -3,6 +3,7 @@
    LOGIN = 'login',
    DRONEPILOTLIST = 'dronePilotList',
    DRONEPILOTDETAILS = 'dronePilotDetails',
    DRONEPILOTSHARE = 'dronePilotShare',
    DRONE = 'drone',
    PROJECT = 'project',
    ADD_PROJECT = 'add_project',
src/utils/mqtt/index.ts
@@ -81,21 +81,18 @@
  // 心跳
  const heartBeatSeq = ref(0)
  const state = reactive({
    heartState: new Map<string, {
      pingInterval: any;
    }>(),
  })
  const state = reactive({heartState: new Map()})
  // 监听云控控制权
  watch(() => deviceTopicInfo, (val, oldVal) => {
    if (val.subTopic !== '') {
      // 1.订阅topic
      subscribeMqtt(deviceTopicInfo.subTopic)
      // 2.发心跳
      publishDrcPing(deviceTopicInfo.sn)
    } else {
      clearInterval(state.heartState.get(deviceTopicInfo.sn)?.pingInterval)
      const heartState = state.heartState.get(deviceTopicInfo.sn)
      if (heartState && heartState.pingInterval) {
        clearInterval(heartState.pingInterval)
      }
      state.heartState.delete(deviceTopicInfo.sn)
      heartBeatSeq.value = 0
    }
src/views/DronePilotDetails-copy0303.vue
New file
@@ -0,0 +1,685 @@
<template>
    <div class="drone-pilot-details" :style="{ width: screenWidth,height: screenHeight}">
      <van-nav-bar
        title="详情"
        left-arrow
        @click-left="onClickLogin"
      />
      <div id="landscapeBox" class="landscape-box" :style="{ width: boxWidth + 'px', height: boxHeight + 'px'}">
        <div id="videoModule" class="l-video" :style="{ width: screenWidthVideo + 'px', height: (screenHeightVideo) + 'px'}">
          <video v-show="videoUrl" ref="videoPlayerBig" :style="{ width: screenWidthVideo + 'px', height: screenHeightVideo + 'px'}" controls autoplay muted playsinline style="text-align: left; object-fit: fill">
            Your browser is too old which doesn't support HTML5 video.
          </video>
          <el-empty v-show="videoUrl == ''" description="当前设备已关机,无法进行直播" :image="imageUrl"></el-empty>
          <div v-if="videoUrl" class="center-point"></div>
          <div class="right-box">
            <ptzControl :sn="sn" :osdVisible="sbInfo"/>
            <controlConsole :sn="sn" :osdVisible="sbInfo" :cesiumViewe="globalViewer" />
          </div>
        </div>
        <div class="l-map" :style="{ width: screenWidthVideo + 'px', height: (screenHeightVideo) + 'px'}">
          <div id="cesiumContainerBigMap"></div>
          <div class="l-zp" id="lZp">
            <comPass :cesiumViewe="globalViewer"/>
          </div>
          <div class="l-zoom" id="lZoom">
            <div class="zoom">
              <img src="@/assets/images/me.png" @touchstart="clickPhoneLocation" />
            </div>
            <div class="zoom" @touchstart="onChangeD">
              <img v-if="is2d" src="@/assets/images/stand.png" />
              <img v-else src="@/assets/images/satellite.png" />
            </div>
            <div class="zoom">
              <img v-if="!isBigMap" src="@/assets/images/fang.png" @touchstart="changeModelMap" />
              <img v-else src="@/assets/images/suo.png" @touchstart="changeModelMap" />
            </div>
          </div>
        </div>
      </div>
    </div>
  </template>
  <script lang="ts" setup>
  import { ref, onMounted, onBeforeUnmount, nextTick, reactive, computed, watch } from 'vue';
  import { EDeviceTypeName, EHmsLevel } from '@/types/enums'
  import { getRoot } from '../../root'
  import { getWaylineFile, getLiveVideoUrl } from '@/api/manage'
  import { CURRENT_CONFIG as config } from '@/api/http/config';
  import { getLnglatDist, cartesian3Convert, getLnglatAltitude, createCircleBillboard } from '@/utils/cesium/mapUtil';
  import cesiumOperation from '@/utils/cesium-tsa.js';
  const { _init, viewerDestory } = cesiumOperation();
  import { useMyStore } from '@/store'
  import comPass from './components/comPass.vue'
  import ptzControl from './components/ptzControl.vue'
  import controlConsole from './components/controlConsole.vue'
  import { useConnectWebSocket } from '@/utils/websocket/connect-websocket'
  import { getWebsocketUrl } from '@/websocket/util/config'
  import { EBizCode, ELocalStorageKey, ERouterName } from '@/types'
  import VConsole from 'vconsole';
  import { analyzeKmzFile, XMLToJSON } from '@/utils/cesium/kmz.js'
  import { initPointWayLine } from './hooks/initPointWayline'
  import { initPlanarWayline } from './hooks/initPlanarWayline'
  import { droneFly } from './hooks/droneFly'
  const { pointWayline } = initPointWayLine()
  const { planarWayline } = initPlanarWayline()
  const { initDock, getPhoneLocation, clickPhoneLocation } = droneFly()
  const {
    removeAllPoint,
    removeAllDataSource,
    globalCesium,
    getEntityById,
    removeById,
    loadLAYER,
  } = cesiumOperation()
  const vConsole = new VConsole();
  let globalViewer = null
  // 使用 ref 来存储屏幕宽度和高度
  const screenWidth = ref(window.innerWidth);
  const screenHeight = ref(window.innerHeight);
  // 加了头部
  const boxWidth = ref(window.innerWidth);
  const boxHeight = ref(window.innerHeight - 46);
  // 地图切换
  const screenWidthMap = ref(boxWidth.value)// ref(((boxHeight.value)/2)*2)
  const screenHeightMap = ref(((boxHeight.value)/2));
  // 视频切换
  const screenWidthVideo = ref(boxWidth.value);
  const screenHeightVideo = ref(boxHeight.value/2);
  const isBigMap = ref(false)
  // 显示高德地图矢量还是影像(2D/3D)
  let is2d = ref(true)
  const onChangeD = () => {
    is2d.value = !is2d.value
    store.commit('SET_MAP_SETTING_MODE', is2d.value?2:3);
    loadLAYER();
  }
  const store = useMyStore()
  // 获取路由
  const root = getRoot()
  interface deviceInfo {
    dockSn: string;
    latitude?:number;// 机场经纬度
    longitude?:number;
    height?:number; // 机场高度
    isOnline: boolean;
    name: string; // 可选字段
    sn: string;
    workspaceId:string;
    children?: {  };
  }
  // 获取机场/遥控器sn
  let localData = ref<any>(window.localStorage.getItem('sbInfo'))
  const sbInfo: deviceInfo = JSON.parse(localData.value) as deviceInfo;
  // 无人机sn
  const sn = ref<String>(sbInfo.sn)
  // 机场sn
  const dockSn = ref<String>(sbInfo.dockSn)
  // 记录横竖屏模式
  const isLandscape = ref(false);
  // 记录视频地址
  const videoUrl = ref<String>('');
  // 设置图片地址
  const imageUrl = new URL('@/assets/images/norecord.png', import.meta.url).href
  const imageMapSrc = new URL('@/assets/images/mapdock.png', import.meta.url).href
  const jgbMapSrc = new URL('@/assets/images/jgb.png', import.meta.url).href
  const mapswitching = new URL('@/assets/images/mapswitching.png', import.meta.url).href
  const videoWH = ref<any>(null)
  // 视频宽高
  const drawCanvasWidth = ref<Number>(0)
  const drawCanvasHeight = ref<Number>(0)
  const videoPlayerBig = ref<any>(null); // 视频播放器实例
  let webrtcPlayerBig = null
  let player = null; // video.js 播放器
  // 无人机实时飞行链接
  let ssLinePath = ref<String>(null)
  // 实时定位
  let viewDroneInfo = {}
  // 机场高度
  let droneHeight = ref(0)
  // 监听
  let connectWs = ref<any>(null)
  let workspaceId = ref<String>(sbInfo.workspaceId)
  localStorage.setItem('bs_workspace_id', workspaceId.value)
  // RTCWEB 加载视频
  const playBig = () => {
    webrtcPlayerBig = new window.ZLMRTCClient.Endpoint({
      element: videoPlayerBig.value, // video 标签
      debug: true, // 是否打印日志
      zlmsdpUrl: videoUrl.value, //流地址
      simulecast: false,
      useCamera: false,
      audioEnable: true,
      videoEnable: true,
      recvOnly: true,
      usedatachannel: false,
    })
    webrtcPlayerBig.on(
      window.ZLMRTCClient.Events.WEBRTC_ICE_CANDIDATE_ERROR,
      (e) => {
        // ICE 协商出错
        console.error('ICE 协商出错')
        // this.eventcallbacK('ICE ERROR', 'ICE 协商出错')
      },
    )
    webrtcPlayerBig.on(
      window.ZLMRTCClient.Events.WEBRTC_ON_REMOTE_STREAMS,
      (e) => {
        //获取到了远端流,可以播放
        console.log('播放成功', e.streams)
        // this.eventcallbacK('playing', '播放成功')
      },
    )
    webrtcPlayerBig.on(
      window.ZLMRTCClient.Events.WEBRTC_OFFER_ANWSER_EXCHANGE_FAILED,
      (e) => {
        // offer anwser 交换失败
        console.error('offer anwser 交换失败', e)
        // this.eventcallbacK('OFFER ANSWER ERROR ', 'offer anwser 交换失败')
        if (e.code == -400 && e.msg == '流不存在') {
          console.log('流不存在')
          timerBig = setTimeout(() => {
            webrtcPlayerBig.close()
            playBig()
          }, 100)
        }
      },
    )
    webrtcPlayerBig.on(
      window.ZLMRTCClient.Events.WEBRTC_ON_LOCAL_STREAM,
      (s) => {
        // 获取到了本地流
        // document.getElementById('selfVideo').srcObject=s;
        // this.eventcallbacK('LOCAL STREAM', '获取到了本地流')
      },
    )
  }
  // 加载该设备的视频信息
  const loadVideo = async () => {
    await getLiveVideoUrl(sn.value).then((res) => {
      if (res.data.code != 0) return
      // 获取高度
      if (videoWH.value) {
        drawCanvasWidth.value = videoWH.value.offsetWidth;
        drawCanvasHeight.value = videoWH.value.offsetHeight;
      }
      videoUrl.value =  res.data.data.rtcs_url
      // 播放
      playBig()
    })
  }
  //===============================
  // 获取实时航线
  const getWrjSsLx = () => {
    if (window.cesiumViewer== null) return
    getWaylineFile(sbInfo.sn).then((res:any) => {
      if (res.code != 200) return
      ssLinePath.value = res.data
      // globalViewer = window.cesiumViewer
      // 先有航线,再飞行
      generateCourse()
    })
  }
  // 生成航线轨迹
  const generateCourse = async () => {
    if (!ssLinePath.value) return
    const { fileInfoObj } = await analyzeKmzFile(`${ssLinePath.value}?_t=${new Date().getTime()}`)
    const xmlStr = await fileInfoObj['wpmz/template.kml']
    const xmlJson = XMLToJSON(xmlStr)?.['Document']
    const placemark = xmlJson.Folder.Placemark
    if (placemark?.Polygon) {
      // return 'planar'
      planarWayline(ssLinePath.value, sbInfo.longitude, sbInfo.latitude)
    } else {
      // return 'point'
      pointWayline(ssLinePath.value, sbInfo.longitude, sbInfo.latitude)
    }
  }
  // 无人机相关信息
  // const droneInfo = ref({})
  // 监听ws
  const messageHandler = async (payload: any) => {
    // if (!payload) {
    //   return
    // }
    switch (payload.biz_code) {
      case EBizCode.GatewayOsd: { // 遥控器
        store.commit('SET_GATEWAY_INFO', payload.data)
        break
      }
      case EBizCode.DeviceOsd: { // 无人机的
        store.commit('SET_DEVICE_INFO', payload.data)
        store.commit('SET_WS_MESSAGE', payload)
        getviewDrone(payload)
        break
      }
      case EBizCode.DockOsd: { // 机场
        store.commit('SET_DOCK_INFO', payload.data)
        break
      }
      case EBizCode.DeviceOffline: {
        store.commit('SET_DEVICE_OFFLINE', payload.data)
        if (!payload.data.online_status) {
          videoUrl.value = ''
        }
        break
      }
      case EBizCode.FlightTaskProgress: { // 获取进度
        // 如果点击列表进入没有获取到航线文件,那么这里重新请求一次
        if (!ssLinePath || !ssLinePath.value) {
          getWrjSsLx()
        }
        break
      }
    }
  }
  const webSorketUrl = getWebsocketUrl() + '&workspace-id=' + workspaceId.value
  // 监听ws 消息
  useConnectWebSocket(messageHandler, webSorketUrl)
  // 定义方法直接监听机场消息
  const getviewDrone = (newValue) => {
    if (newValue.data.host) {
      viewDroneInfo.longitude = newValue.data.host?.longitude
      viewDroneInfo.latitude = newValue.data.host?.latitude
      viewDroneInfo.elevation = Number(newValue.data.host?.elevation.toFixed(2)) + droneHeight.value
    }
  }
  // let savedMapState = null; // 保存地图状态
  // // 销毁之前先保存状态
  // const destroyViewer = () => {
  //   if ( window.cesiumViewer) {
  //     // 保存当前地图状态(如相机位置)
  //     // savedMapState = window.cesiumViewer.camera.view;
  //     window.cesiumViewer.destroy();
  //     window.cesiumViewer = null;
  //   }
  // }
  // 视频全屏切换
  // const changeModelVideo = (value:Boolean) => {
  //   const videoModule = document.getElementById('videoModule');
  //   // 不管是否竖/横屏都一样
  //   if (value) { // 全屏
  //     videoModule.style.width = `${screenWidth.value}px`
  //     videoModule.style.height = `${screenHeight.value}px`
  //   } else {
  //     if (isLandscape.value) {
  //       videoModule.style.width = `${screenWidth.value/2}px`
  //       videoModule.style.height = `${screenHeight.value}px`
  //     } else {
  //       videoModule.style.height = `${screenHeight.value/2}px`
  //       videoModule.style.width = `${screenWidth.value}px`
  //     }
  //   }
  // }
  // 地图全屏切换
  const changeModelMap = () => {
    isBigMap.value = !isBigMap.value
    const cesiumContainer = document.getElementById('cesiumContainerBigMap');
    const lZp = document.getElementById('lZp');
    // const lZoom = document.getElementById('lZoom');
    if (isLandscape.value) { // 横屏
      if (isBigMap.value) { // 全屏
        cesiumContainer.style.position = 'fixed';
        cesiumContainer.style.top = '46px';
        cesiumContainer.style.left = '0';
        cesiumContainer.style.width = `${boxWidth.value}px`
        // cesiumContainer.style.height = `${screenHeightMap.value}px`
        lZp.style.right = '40%';
        // lZoom.style.left = '0';
      } else { // 缩放
        cesiumContainer.style.width = `${boxWidth.value/2}px`
        // cesiumContainer.style.height = `${screenHeightMap.value}px`
        cesiumContainer.style.position = 'static';
        lZp.style.right = '16%';
        // lZoom.style.left = '50%';
      }
    } else {
      if (isBigMap.value) { // 竖-全屏
        cesiumContainer.style.position = 'fixed';
        cesiumContainer.style.top = '46px';
        cesiumContainer.style.left = '0';
        // cesiumContainer.style.width = `${boxHeight.value}px`
        cesiumContainer.style.height = `${boxHeight.value}px`
        lZp.style.right = '30%';
        // lZoom.style.right = '0';
      } else { // 缩放
        cesiumContainer.style.width = `${boxHeight.value}px`
        cesiumContainer.style.height = `${boxHeight.value/2}px`
        cesiumContainer.style.position = 'static';
        lZp.style.right = '30%';
        // lZoom.style.right = '0';
      }
    }
  }
  // 更新屏幕尺寸的函数
  // const updateScreenSize = () => {
  //   const cesiumContainer = document.getElementById('cesiumContainerBigMap');
  //   screenWidth.value = window.innerWidth;
  //   screenHeight.value = window.innerHeight;
  //   console.log('屏幕自身宽度',window.innerWidth)
  //   console.log('屏幕自身高度',window.innerHeight)
  //   if (isLandscape.value) { //横屏
  //     screenWidthMap.value = window.innerWidth/2
  //     screenHeightMap.value = window.innerHeight
  //     screenWidthVideo.value = window.innerWidth/2
  //     screenHeightVideo.value = window.innerHeight
  //     cesiumContainer.style.width = `${screenWidthMap.value}px`
  //     cesiumContainer.style.height = `${screenHeightMap.value}px`
  //   } else {//竖屏
  //     screenWidthMap.value = window.innerHeight
  //     screenHeightMap.value = (window.innerHeight/2)
  //     screenWidthVideo.value = window.innerWidth
  //     screenHeightVideo.value = (window.innerHeight/2)
  //     // 重新给赋值宽高
  //     cesiumContainer.style.width = `${screenWidthMap.value}px`
  //     cesiumContainer.style.height = `${screenHeightMap.value}px`
  //     console.log('切换竖屏宽度',screenWidthMap.value)
  //     console.log('切换竖屏高度度',screenHeightMap.value)
  //   }
  // };
  const checkOrientation = async () => {
    boxWidth.value = window.innerWidth;
    boxHeight.value = window.innerHeight - 46;
    const landscapeBox = document.getElementById('landscapeBox');
    let cesiumContainer = document.getElementById('cesiumContainerBigMap');
    const lZp = document.getElementById('lZp');
    const lZoom = document.getElementById('lZoom');
    if (window.innerWidth > window.innerHeight) {//横屏
      screenWidthVideo.value = boxWidth.value/2
      screenHeightVideo.value = boxHeight.value
      isLandscape.value = true;
      // updateScreenSize()
      landscapeBox.style.display = 'flex';
      lZp.style.right = '16%';
      lZoom.style.position = 'fixed';
      cesiumContainer.style.width = `${boxWidth.value/2}px`
      cesiumContainer.style.height = `${boxHeight.value}px`
      cesiumContainer.style.position = 'static'
      cesiumContainer.style.right = '0'
      cesiumContainer.style.marginLeft = '0%'
    } else { //竖屏
      isLandscape.value = false;
      screenWidthVideo.value = boxWidth.value
      screenHeightVideo.value = boxHeight.value/2
      // updateScreenSize()
      landscapeBox.style.display = 'inherit';
      landscapeBox.style.overflow = 'hidden';
      lZp.style.right = '32%';
      cesiumContainer.style.width = `${boxHeight.value}px`
      cesiumContainer.style.height = `${boxHeight.value/2}px`
      // cesiumContainer.style.position = 'absolute'
      cesiumContainer.style.marginLeft = '-32%'
    }
  };
  // 切换航线轨迹
  const courseTrack = (data:any) => {
    if (window.cesiumViewer== null) return
    const currentSn = dockSn.value
    const longitude = data.dockInfo[currentSn]?.basic_osd?.longitude || null
    const latitude = data.dockInfo[currentSn]?.basic_osd?.latitude || null
    const height = data.dockInfo[currentSn]?.basic_osd?.height || null
    let getLongOk = ref(0)
    if (!getEntityById('drone_dock')) {
      getLnglatAltitude(longitude, latitude,  window.cesiumViewer).then(res => {
        removeById('drone_dock')
         window.cesiumViewer.entities.add({
          position: globalCesium.Cartesian3.fromDegrees(
            longitude,
            latitude,
            res.height,
          ),
          id: 'drone_dock',
          billboard: {
            image: imageMapSrc,
            outlineWidth: 0,
            width: 36,
            height: 36,
            scale: 1.0,
          }
        })
        window.cesiumViewer.scene.camera.setView({
          destination: globalCesium.Cartesian3.fromDegrees(
            Number(longitude),
            Number(latitude),
            10000.0,
          ),
        })
        droneHeight.value = res.height
      })
    } else {
      // 当机场坐标存在时,判断获取的位置与机场坐标位置是否一致,若不是,重新更新位置
      let dornePoint = cartesian3Convert(getEntityById('drone_dock')._position._value, window.cesiumViewer,)
      getLongOk = getLnglatDist(
        dornePoint.longitude,
        dornePoint.latitude,
        longitude,
        latitude,
      )
      if (getLongOk.value > 100) {
        removeById('drone_dock')
      }
    }
    if (getLongOk.value > 100) return
    initDock(data, sn.value, dockSn.value, workspaceId.value, ssLinePath.value, viewDroneInfo)
  }
  // 监听
  watch(() => store.state.deviceState, (newValue, oldValue) => {
    if (newValue) {
      nextTick()
      courseTrack(newValue)
    }
  }, {deep: true})
  // watch(() => store.state.wsMessage, (newValue, oldValue) => {
  //   // 控制台报 Expected longitude to be typeof number, actual typeof was undefined 是因为这里没有及时拿到longitude数据
  //   if (newValue) {
  //     viewDroneInfo.longitude = newValue?.longitude
  //     viewDroneInfo.latitude = newValue?.latitude
  //     viewDroneInfo.elevation = Number(newValue?.elevation.toFixed(2)) + droneHeight.value
  //   }
  // }, {deep: true})
  let intervalId = null;
  const onClickLogin = () => {
    history.back();
  }
  // 为组件赋值
  const getGlobalViewer = () => {
    globalViewer = window.cesiumViewer;
  }
  onMounted(async () => {
    window.addEventListener('orientationchange', checkOrientation);
    window.addEventListener('resize', checkOrientation); // 兼容某些设备
    checkOrientation(); // 初始化时检查一次
    loadVideo()
    await nextTick();
    await _init('cesiumContainerBigMap');
    await getGlobalViewer()
    await getWrjSsLx();
    // 判断是遥控器还是机场
    let domain = sessionStorage.getItem('domain')
    if (domain !== '0') {
      await getPhoneLocation(workspaceId.value)
    // // // 设置定时器,每隔 5 秒刷新一次数据
      // intervalId = setInterval(()=> {
      //   getPhoneLocation(workspaceId.value)
      // }, 5000);
    }
  });
  onBeforeUnmount(() => {
    window.removeEventListener('orientationchange', checkOrientation);
    window.removeEventListener('resize', checkOrientation);
    // removeAllPoint()
    // removeAllDataSource()
    // 销毁地图实例
    if (window.cesiumViewer && !window.cesiumViewer.isDestroyed()) {
      window.cesiumViewer.destroy();
    }
    if (globalViewer && !globalViewer.isDestroyed()) {
      globalViewer.destroy();
    }
    if (player) {
      player.dispose();
    }
    // 组件卸载时清除定时器
    if (intervalId) {
      clearInterval(intervalId);
    }
  });
  </script>
  <style lang="scss" scoped>
  .drone-pilot-details {
    .landscape-box {
      overflow: hidden;
      // position: relative;
      // display: flex;
      .l-map {
        .l-zp {
          position: fixed;
          right: 16%;
          bottom: 0;
        }
        .l-zoom {
          position: fixed;
          bottom: 0;
          right: 0;
          .zoom {
            width: 2rem;
            height: 2rem;
            margin: 0.2rem 0.4rem;
            border-radius: 3px;
            background-color: rgba(0, 0, 0, 0.8);
            display: flex;
            align-items: center;
            justify-content: center;
            overflow: hidden;
            cursor: pointer;
            pointer-events: all;
            img {
              width: 1.6rem;
              height: 1.6rem;
            }
          }
        }
      }
    }
    .l-video {
      position: relative;
      .el-empty {
        width: 100%;
        height: 100%;
        padding: 0;
        ::v-deep(.el-empty__image) {
          width: 50%;
          height: 50%;
        }
        ::v-deep(.el-empty__description) {
          margin: 0;
        }
      }
      .center-point {
        position: absolute;
        top: 50%;
        left: 50%;
        width: 0.4rem;
        height: 0.4rem;
        opacity: 0.5;
        border-radius: 50%;
        background-color: yellow;
        transform: translate(-50%, -50%);
        justify-content: center;
      }
      .right-box {}
    }
    #cesiumContainerBigMap {
      width: 100%;
      height: 100%;
      margin: 0;
      padding: 0;
      overflow: hidden;
      :deep() {
        .cesium-viewer {
          width: 100%;
          height: 100%;
          .cesium-viewer-cesiumWidgetContainer {
            width: 100%;
            height: 100%;
            .cesium-widget {
              width: 100%;
              height: 100%;
              canvas {
                width: 100%;
                height: 100%;
              }
            }
          }
        }
      }
    }
  }
  </style>
src/views/DronePilotDetails.vue
@@ -2,8 +2,10 @@
  <div class="drone-pilot-details" :style="{ width: screenWidth,height: screenHeight}">
    <van-nav-bar
      title="详情"
      right-text="分享"
      left-arrow
      @click-left="onClickLogin"
      @click-right="onClickShare"
    />
    <div id="landscapeBox" class="landscape-box" :style="{ width: boxWidth + 'px', height: boxHeight + 'px'}">
      <div id="videoModule" class="l-video" :style="{ width: screenWidthVideo + 'px', height: (screenHeightVideo) + 'px'}">
@@ -37,14 +39,21 @@
        </div>
      </div>
    </div>
    <van-share-sheet
    v-model:show="showShare"
    title="立即分享"
    :options="shareOptions"
    @select="onSelectShare"
  />
  </div>
</template>
<script lang="ts" setup>
import { ref, onMounted, onBeforeUnmount, nextTick, reactive, computed, watch } from 'vue';
import { showNotify } from 'vant';
import { EDeviceTypeName, EHmsLevel } from '@/types/enums'
import { getRoot } from '../../root'
import { getWaylineFile, getLiveVideoUrl } from '@/api/manage'
import { getWaylineFile, getLiveVideoUrl, saveToken } from '@/api/manage'
import { CURRENT_CONFIG as config } from '@/api/http/config';
import { getLnglatDist, cartesian3Convert, getLnglatAltitude, createCircleBillboard } from '@/utils/cesium/mapUtil';
import cesiumOperation from '@/utils/cesium-tsa.js';
@@ -75,6 +84,10 @@
} = cesiumOperation()
const vConsole = new VConsole();
const showShare = ref(false)
const shareOptions = [ { name: '复制链接', icon: 'link' }]
let globalViewer = null
@@ -152,7 +165,7 @@
let player = null; // video.js 播放器
// 无人机实时飞行链接
let ssLinePath = ref(null)
let ssLinePath = ref<String>(null)
// 实时定位
let viewDroneInfo = {}
@@ -514,7 +527,6 @@
// 监听
watch(() => store.state.deviceState, (newValue, oldValue) => {
  // 试试
  if (newValue) {
    nextTick()
    courseTrack(newValue)
@@ -537,6 +549,27 @@
  history.back();
}
const onClickShare = () => {
  showShare.value = true
  // root.$router.push({
  //   path:ERouterName.DRONEPILOTSHARE,
  //   query: { workspaceId:workspaceId.value, token: localStorage.getItem(ELocalStorageKey.Token),sbInfo:window.localStorage.getItem('sbInfo') } });
}
// 复制链接
const onSelectShare = () => {
  saveToken({ token: localStorage.getItem(ELocalStorageKey.Token), sbInfo: window.localStorage.getItem('sbInfo') }).then((res) => {
    // if (res.code !==0) return
    const shareUrl = `https://wrj.shuixiongit.com/pilot-h5/#/dronePilotShare?code=${Number(res.data)}`
    navigator.clipboard.writeText(shareUrl).then(() => {
      showNotify({ type: 'success', message: '复制成功' })
    }).catch(() => {
      showNotify({ type: 'warning', message: '复制失败' })
    });
    showShare.value = false
  });
}
// 为组件赋值
const getGlobalViewer = () => {
  globalViewer = window.cesiumViewer;
@@ -554,7 +587,7 @@
  // 判断是遥控器还是机场
  let domain = sessionStorage.getItem('domain')
  if (domain !== '0') {
    await getPhoneLocation(workspaceId.value)
    // await getPhoneLocation(workspaceId.value)
  // // // 设置定时器,每隔 5 秒刷新一次数据
    // intervalId = setInterval(()=> {
    //   getPhoneLocation(workspaceId.value)
@@ -658,6 +691,10 @@
    margin: 0;
    padding: 0;
    overflow: hidden;
    transform-origin: top left;
    transition: none; // 防止切换时的动画效果
    backface-visibility: hidden; // 提高性能
    -webkit-backface-visibility: hidden; // 提高性能
    :deep() {
      .cesium-viewer {
src/views/DronePilotList.vue
@@ -84,6 +84,8 @@
    // 前端自己加的判断
    window.sessionStorage.setItem('domain', JSON.stringify(droneOrPilotTxt.value == 'drone'? 0 : 2));
    store.commit('SET_OSD_VISIBLE_INFO', osdVisible)
    // 存储机场信息
    store.commit('SET_AIRPORT_INFO', data)
    // 跳转操作屏幕
    root.$router.push({ path:ERouterName.DRONEPILOTDETAILS })
  }
src/views/DronePilotShare.vue
New file
@@ -0,0 +1,638 @@
<template>
    <div class="drone-pilot-details" :style="{ width: screenWidth,height: screenHeight}">
      <van-nav-bar
        title="详情"
        left-arrow
        @click-left="onClickLogin"
      />
      <div id="landscapeBox" class="landscape-box" :style="{ width: boxWidth + 'px', height: boxHeight + 'px'}">
        <div id="videoModule" class="l-video" :style="{ width: screenWidthVideo + 'px', height: (screenHeightVideo) + 'px'}">
          <video v-show="videoUrl" ref="videoPlayerBig" :style="{ width: screenWidthVideo + 'px', height: screenHeightVideo + 'px'}" controls autoplay muted playsinline style="text-align: left; object-fit: fill">
            Your browser is too old which doesn't support HTML5 video.
          </video>
          <el-empty v-show="videoUrl == ''" description="当前设备已关机,无法进行直播" :image="imageUrl"></el-empty>
          <div v-if="videoUrl" class="center-point"></div>
          <div class="right-box">
            <!-- <ptzControl :sn="sn" :osdVisible="sbInfo"/> -->
            <!-- <controlConsole :sn="sn" :osdVisible="sbInfo" :cesiumViewe="globalViewer" /> -->
          </div>
        </div>
        <div class="l-map" :style="{ width: screenWidthVideo + 'px', height: (screenHeightVideo) + 'px'}">
          <div id="cesiumContainerBigMap"></div>
          <div class="l-zp" id="lZp">
            <comPass :cesiumViewe="globalViewer"/>
          </div>
          <div class="l-zoom" id="lZoom">
            <div class="zoom">
              <img src="@/assets/images/me.png" @touchstart="clickPhoneLocation" />
            </div>
            <div class="zoom" @touchstart="onChangeD">
              <img v-if="is2d" src="@/assets/images/stand.png" />
              <img v-else src="@/assets/images/satellite.png" />
            </div>
            <div class="zoom">
              <img v-if="!isBigMap" src="@/assets/images/fang.png" @touchstart="changeModelMap" />
              <img v-else src="@/assets/images/suo.png" @touchstart="changeModelMap" />
            </div>
          </div>
        </div>
      </div>
    </div>
  </template>
  <script lang="ts" setup>
  import { ref, onMounted, onBeforeUnmount, nextTick, reactive, computed, watch } from 'vue';
  import { EDeviceTypeName, EHmsLevel } from '@/types/enums'
  import { getRoot } from '../../root'
  import { getWaylineFile, getLiveVideoUrl,getTokenByCode } from '@/api/manage'
  import { CURRENT_CONFIG as config } from '@/api/http/config';
  import { getLnglatDist, cartesian3Convert, getLnglatAltitude, createCircleBillboard } from '@/utils/cesium/mapUtil';
  import cesiumOperation from '@/utils/cesium-tsa.js';
  const { _init, viewerDestory } = cesiumOperation();
  import { useMyStore } from '@/store'
  import comPass from './components/comPass.vue'
  import ptzControl from './components/ptzControl.vue'
  import controlConsole from './components/controlConsole.vue'
  import { useConnectWebSocket } from '@/utils/websocket/connect-websocket'
  import { getWebsocketUrl } from '@/websocket/util/config'
  import { EBizCode, ELocalStorageKey, ERouterName } from '@/types'
  import VConsole from 'vconsole';
  import { analyzeKmzFile, XMLToJSON } from '@/utils/cesium/kmz.js'
  import { initPointWayLine } from './hooks/initPointWayline'
  import { initPlanarWayline } from './hooks/initPlanarWayline'
  import { droneFly } from './hooks/droneFly'
  const { pointWayline } = initPointWayLine()
  const { planarWayline } = initPlanarWayline()
  const { initDock, getPhoneLocation, clickPhoneLocation } = droneFly()
  const {
    removeAllPoint,
    removeAllDataSource,
    globalCesium,
    getEntityById,
    removeById,
    loadLAYER,
  } = cesiumOperation()
  const vConsole = new VConsole();
  let globalViewer = null
  // 使用 ref 来存储屏幕宽度和高度
  const screenWidth = ref(window.innerWidth);
  const screenHeight = ref(window.innerHeight);
  // 加了头部
  const boxWidth = ref(window.innerWidth);
  const boxHeight = ref(window.innerHeight - 46);
  // 地图切换
  const screenWidthMap = ref(boxWidth.value)// ref(((boxHeight.value)/2)*2)
  const screenHeightMap = ref(((boxHeight.value)/2));
  // 视频切换
  const screenWidthVideo = ref(boxWidth.value);
  const screenHeightVideo = ref(boxHeight.value/2);
  const isBigMap = ref(false)
  // 显示高德地图矢量还是影像(2D/3D)
  let is2d = ref(true)
  const onChangeD = () => {
    is2d.value = !is2d.value
    store.commit('SET_MAP_SETTING_MODE', is2d.value?2:3);
    loadLAYER();
  }
  const store = useMyStore()
  // 获取路由
  const root = getRoot()
  interface deviceInfo {
    dockSn: string;
    latitude?:number;// 机场经纬度
    longitude?:number;
    height?:number; // 机场高度
    isOnline: boolean;
    name: string; // 可选字段
    sn: string;
    workspaceId:string;
    children?: {  };
  }
    // 取值
    let sbInfo: deviceInfo = {} as deviceInfo;
    // 无人机sn
    let sn = ref<String>('')
    // 机场sn
    let dockSn = ref<String>('')
    // workspaceId
    let workspaceId = ref<String>('')
    // 获取实时航线
    const getWrjSsLx = async () => {
      if (window.cesiumViewer== null) return
      console.log('哒哒哒1111',sbInfo)
      await getWaylineFile(sbInfo.sn).then((res:any) => {
        if (res.code != 200) return
        ssLinePath.value = res.data
        // globalViewer = window.cesiumViewer
        // 先有航线,再飞行
        generateCourse()
      })
    }
    const getTokenAndTbInfo = () => {
      getTokenByCode(root.$route.query.code).then((res:any) => {
        let tokenAndInfo = JSON.parse(res.data);
        sbInfo = JSON.parse(tokenAndInfo.sbInfo);
        store.commit('SET_TOKEN', tokenAndInfo.token);
        sn.value = sbInfo.sn;
        dockSn.value = sbInfo.dockSn;
        workspaceId.value = sbInfo.workspaceId
        // 监听ws
        const messageHandler = async (payload: any) => {
          if (!payload) return
          switch (payload.biz_code) {
            case EBizCode.GatewayOsd: { // 遥控器
              store.commit('SET_GATEWAY_INFO', payload.data)
              break
            }
            case EBizCode.DeviceOsd: { // 无人机的
              store.commit('SET_DEVICE_INFO', payload.data)
              store.commit('SET_WS_MESSAGE', payload)
              getviewDrone(payload)
              break
            }
            case EBizCode.DockOsd: { // 机场
              store.commit('SET_DOCK_INFO', payload.data)
              break
            }
            case EBizCode.DeviceOffline: {
              store.commit('SET_DEVICE_OFFLINE', payload.data)
              if (!payload.data.online_status) {
                videoUrl.value = ''
              }
              break
            }
            case EBizCode.FlightTaskProgress: { // 获取进度
              // 如果点击列表进入没有获取到航线文件,那么这里重新请求一次
              if (!ssLinePath || !ssLinePath.value) {
                getWrjSsLx()
              }
              break
            }
          }
        }
        const webSorketUrl = getWebsocketUrl() + '&workspace-id=' + workspaceId.value
        // 监听ws 消息
        useConnectWebSocket(messageHandler, webSorketUrl)
        // 获取视频信息
        loadVideo();
        // 获取航线信息
        getWrjSsLx();
      })
    }
    getTokenAndTbInfo()
    console.log('哒哒哒',sbInfo)
  // 记录横竖屏模式
  const isLandscape = ref(false);
  // 记录视频地址
  const videoUrl = ref<String>('');
  // 设置图片地址
  const imageUrl = new URL('@/assets/images/norecord.png', import.meta.url).href
  const imageMapSrc = new URL('@/assets/images/mapdock.png', import.meta.url).href
  const jgbMapSrc = new URL('@/assets/images/jgb.png', import.meta.url).href
  const mapswitching = new URL('@/assets/images/mapswitching.png', import.meta.url).href
  const videoWH = ref<any>(null)
  // 视频宽高
  const drawCanvasWidth = ref<Number>(0)
  const drawCanvasHeight = ref<Number>(0)
  const videoPlayerBig = ref<any>(null); // 视频播放器实例
  let webrtcPlayerBig = null
  let player = null; // video.js 播放器
  // 无人机实时飞行链接
  let ssLinePath = ref<String>(null)
  // 实时定位
  let viewDroneInfo = {}
  // 机场高度
  let droneHeight = ref(0)
  // 监听
  let connectWs = ref<any>(null)
  // RTCWEB 加载视频
  const playBig = () => {
    webrtcPlayerBig = new window.ZLMRTCClient.Endpoint({
      element: videoPlayerBig.value, // video 标签
      debug: true, // 是否打印日志
      zlmsdpUrl: videoUrl.value, //流地址
      simulecast: false,
      useCamera: false,
      audioEnable: true,
      videoEnable: true,
      recvOnly: true,
      usedatachannel: false,
    })
    webrtcPlayerBig.on(
      window.ZLMRTCClient.Events.WEBRTC_ICE_CANDIDATE_ERROR,
      (e) => {
        // ICE 协商出错
        console.error('ICE 协商出错')
        // this.eventcallbacK('ICE ERROR', 'ICE 协商出错')
      },
    )
    webrtcPlayerBig.on(
      window.ZLMRTCClient.Events.WEBRTC_ON_REMOTE_STREAMS,
      (e) => {
        //获取到了远端流,可以播放
        console.log('播放成功', e.streams)
        // this.eventcallbacK('playing', '播放成功')
      },
    )
    webrtcPlayerBig.on(
      window.ZLMRTCClient.Events.WEBRTC_OFFER_ANWSER_EXCHANGE_FAILED,
      (e) => {
        // offer anwser 交换失败
        console.error('offer anwser 交换失败', e)
        // this.eventcallbacK('OFFER ANSWER ERROR ', 'offer anwser 交换失败')
        if (e.code == -400 && e.msg == '流不存在') {
          console.log('流不存在')
          timerBig = setTimeout(() => {
            webrtcPlayerBig.close()
            playBig()
          }, 100)
        }
      },
    )
    webrtcPlayerBig.on(
      window.ZLMRTCClient.Events.WEBRTC_ON_LOCAL_STREAM,
      (s) => {
        // 获取到了本地流
        // document.getElementById('selfVideo').srcObject=s;
        // this.eventcallbacK('LOCAL STREAM', '获取到了本地流')
      },
    )
  }
  // 加载该设备的视频信息
  const loadVideo = async () => {
    await getLiveVideoUrl(sn.value).then((res) => {
      if (res.data.code != 0) return
      // 获取高度
      if (videoWH.value) {
        drawCanvasWidth.value = videoWH.value.offsetWidth;
        drawCanvasHeight.value = videoWH.value.offsetHeight;
      }
      videoUrl.value =  res.data.data.rtcs_url
      // 播放
      playBig()
    })
  }
  // 生成航线轨迹
  const generateCourse = async () => {
    if (!ssLinePath.value) return
    const { fileInfoObj } = await analyzeKmzFile(`${ssLinePath.value}?_t=${new Date().getTime()}`)
    const xmlStr = await fileInfoObj['wpmz/template.kml']
    const xmlJson = XMLToJSON(xmlStr)?.['Document']
    const placemark = xmlJson.Folder.Placemark
    if (placemark?.Polygon) {
      // return 'planar'
      planarWayline(ssLinePath.value, sbInfo.longitude, sbInfo.latitude)
    } else {
      // return 'point'
      pointWayline(ssLinePath.value, sbInfo.longitude, sbInfo.latitude)
    }
  }
  // 定义方法直接监听机场消息
  const getviewDrone = (newValue:any) => {
    if (newValue.data.host) {
      viewDroneInfo.longitude = newValue.data.host?.longitude
      viewDroneInfo.latitude = newValue.data.host?.latitude
      viewDroneInfo.elevation = Number(newValue.data.host?.elevation.toFixed(2)) + droneHeight.value
    }
  }
  // 地图全屏切换
  const changeModelMap = () => {
    isBigMap.value = !isBigMap.value
    const cesiumContainer = document.getElementById('cesiumContainerBigMap');
    const lZp = document.getElementById('lZp');
    // const lZoom = document.getElementById('lZoom');
    if (isLandscape.value) { // 横屏
      if (isBigMap.value) { // 全屏
        cesiumContainer.style.position = 'fixed';
        cesiumContainer.style.top = '46px';
        cesiumContainer.style.left = '0';
        cesiumContainer.style.width = `${boxWidth.value}px`
        // cesiumContainer.style.height = `${screenHeightMap.value}px`
        lZp.style.right = '40%';
        // lZoom.style.left = '0';
      } else { // 缩放
        cesiumContainer.style.width = `${boxWidth.value/2}px`
        // cesiumContainer.style.height = `${screenHeightMap.value}px`
        cesiumContainer.style.position = 'static';
        lZp.style.right = '16%';
        // lZoom.style.left = '50%';
      }
    } else {
      if (isBigMap.value) { // 竖-全屏
        cesiumContainer.style.position = 'fixed';
        cesiumContainer.style.top = '46px';
        cesiumContainer.style.left = '0';
        // cesiumContainer.style.width = `${boxHeight.value}px`
        cesiumContainer.style.height = `${boxHeight.value}px`
        lZp.style.right = '30%';
        // lZoom.style.right = '0';
      } else { // 缩放
        cesiumContainer.style.width = `${boxHeight.value}px`
        cesiumContainer.style.height = `${boxHeight.value/2}px`
        cesiumContainer.style.position = 'static';
        lZp.style.right = '30%';
        // lZoom.style.right = '0';
      }
    }
  }
  const checkOrientation = async () => {
      boxWidth.value = window.innerWidth;
      boxHeight.value = window.innerHeight - 46;
      const landscapeBox = document.getElementById('landscapeBox');
      let cesiumContainer = document.getElementById('cesiumContainerBigMap');
      const lZp = document.getElementById('lZp');
      const lZoom = document.getElementById('lZoom');
      if (window.innerWidth > window.innerHeight) {//横屏
        screenWidthVideo.value = boxWidth.value/2
        screenHeightVideo.value = boxHeight.value
        isLandscape.value = true;
        // updateScreenSize()
        landscapeBox.style.display = 'flex';
        lZp.style.right = '16%';
        lZoom.style.position = 'fixed';
        cesiumContainer.style.width = `${boxWidth.value/2}px`
        cesiumContainer.style.height = `${boxHeight.value}px`
        cesiumContainer.style.position = 'static'
        cesiumContainer.style.right = '0'
        cesiumContainer.style.marginLeft = '0%'
      } else { //竖屏
        isLandscape.value = false;
        screenWidthVideo.value = boxWidth.value
        screenHeightVideo.value = boxHeight.value/2
        // updateScreenSize()
        landscapeBox.style.display = 'inherit';
        landscapeBox.style.overflow = 'hidden';
        lZp.style.right = '32%';
        cesiumContainer.style.width = `${boxHeight.value}px`
        cesiumContainer.style.height = `${boxHeight.value/2}px`
        // cesiumContainer.style.position = 'absolute'
        cesiumContainer.style.marginLeft = '-32%'
      }
    };
  // 切换航线轨迹
  const courseTrack = (data:any) => {
    if (window.cesiumViewer== null) return
    const currentSn = dockSn.value
    const longitude = data.dockInfo[currentSn]?.basic_osd?.longitude || null
    const latitude = data.dockInfo[currentSn]?.basic_osd?.latitude || null
    const height = data.dockInfo[currentSn]?.basic_osd?.height || null
    let getLongOk = ref(0)
    if (!getEntityById('drone_dock')) {
      getLnglatAltitude(longitude, latitude,  window.cesiumViewer).then(res => {
        removeById('drone_dock')
         window.cesiumViewer.entities.add({
          position: globalCesium.Cartesian3.fromDegrees(
            longitude,
            latitude,
            res.height,
          ),
          id: 'drone_dock',
          billboard: {
            image: imageMapSrc,
            outlineWidth: 0,
            width: 36,
            height: 36,
            scale: 1.0,
          }
        })
        window.cesiumViewer.scene.camera.setView({
          destination: globalCesium.Cartesian3.fromDegrees(
            Number(longitude),
            Number(latitude),
            10000.0,
          ),
        })
        droneHeight.value = res.height
      })
    } else {
      // 当机场坐标存在时,判断获取的位置与机场坐标位置是否一致,若不是,重新更新位置
      let dornePoint = cartesian3Convert(getEntityById('drone_dock')._position._value, window.cesiumViewer,)
      getLongOk = getLnglatDist(
        dornePoint.longitude,
        dornePoint.latitude,
        longitude,
        latitude,
      )
      if (getLongOk.value > 100) {
        removeById('drone_dock')
      }
    }
    if (getLongOk.value > 100) return
    initDock(data, sn.value, dockSn.value, workspaceId.value, ssLinePath.value, viewDroneInfo)
  }
  // 监听
  watch(() => store.state.deviceState, (newValue, oldValue) => {
    if (newValue) {
      nextTick()
      courseTrack(newValue)
    }
  }, {deep: true})
  // watch(() => store.state.wsMessage, (newValue, oldValue) => {
  //   // 控制台报 Expected longitude to be typeof number, actual typeof was undefined 是因为这里没有及时拿到longitude数据
  //   if (newValue) {
  //     viewDroneInfo.longitude = newValue?.longitude
  //     viewDroneInfo.latitude = newValue?.latitude
  //     viewDroneInfo.elevation = Number(newValue?.elevation.toFixed(2)) + droneHeight.value
  //   }
  // }, {deep: true})
  let intervalId = null;
  const onClickLogin = () => {
    history.back();
  }
  // 为组件赋值
  const getGlobalViewer = () => {
    globalViewer = window.cesiumViewer;
  }
  onMounted(async () => {
    window.addEventListener('orientationchange', checkOrientation);
    window.addEventListener('resize', checkOrientation); // 兼容某些设备
    checkOrientation(); // 初始化时检查一次
    // loadVideo();
    await nextTick();
    await _init('cesiumContainerBigMap');
    await getGlobalViewer()
    // await getWrjSsLx();
    // 判断是遥控器还是机场
    let domain = sessionStorage.getItem('domain')
    if (domain !== '0') {
      await getPhoneLocation(workspaceId.value)
    // // // 设置定时器,每隔 5 秒刷新一次数据
      // intervalId = setInterval(()=> {
      //   getPhoneLocation(workspaceId.value)
      // }, 5000);
    }
  });
  onBeforeUnmount(() => {
    window.removeEventListener('orientationchange', checkOrientation);
    window.removeEventListener('resize', checkOrientation);
    // removeAllPoint()
    // removeAllDataSource()
    // 销毁地图实例
    if (window.cesiumViewer && !window.cesiumViewer.isDestroyed()) {
      window.cesiumViewer.destroy();
    }
    if (globalViewer && !globalViewer.isDestroyed()) {
      globalViewer.destroy();
    }
    if (player) {
      player.dispose();
    }
    // 组件卸载时清除定时器
    if (intervalId) {
      clearInterval(intervalId);
    }
  });
  </script>
  <style lang="scss" scoped>
  .drone-pilot-details {
    .landscape-box {
      overflow: hidden;
      // position: relative;
      // display: flex;
      .l-map {
        .l-zp {
          position: fixed;
          right: 16%;
          bottom: 0;
        }
        .l-zoom {
          position: fixed;
          bottom: 0;
          right: 0;
          .zoom {
            width: 2rem;
            height: 2rem;
            margin: 0.2rem 0.4rem;
            border-radius: 3px;
            background-color: rgba(0, 0, 0, 0.8);
            display: flex;
            align-items: center;
            justify-content: center;
            overflow: hidden;
            cursor: pointer;
            pointer-events: all;
            img {
              width: 1.6rem;
              height: 1.6rem;
            }
          }
        }
      }
    }
    .l-video {
      position: relative;
      .el-empty {
        width: 100%;
        height: 100%;
        padding: 0;
        ::v-deep(.el-empty__image) {
          width: 50%;
          height: 50%;
        }
        ::v-deep(.el-empty__description) {
          margin: 0;
        }
      }
      .center-point {
        position: absolute;
        top: 50%;
        left: 50%;
        width: 0.4rem;
        height: 0.4rem;
        opacity: 0.5;
        border-radius: 50%;
        background-color: yellow;
        transform: translate(-50%, -50%);
        justify-content: center;
      }
      .right-box {}
    }
    #cesiumContainerBigMap {
      width: 100%;
      height: 100%;
      margin: 0;
      padding: 0;
      overflow: hidden;
      transform-origin: top left;
      transition: none; // 防止切换时的动画效果
      backface-visibility: hidden; // 提高性能
      -webkit-backface-visibility: hidden; // 提高性能
      :deep() {
        .cesium-viewer {
          width: 100%;
          height: 100%;
          .cesium-viewer-cesiumWidgetContainer {
            width: 100%;
            height: 100%;
            .cesium-widget {
              width: 100%;
              height: 100%;
              canvas {
                width: 100%;
                height: 100%;
              }
            }
          }
        }
      }
    }
  }
  </style>
src/views/components/controlConsole-copy.vue
New file
@@ -0,0 +1,1138 @@
<template>
    <div class="control-console">
      <div class="control" :class="isShowKzBtn?'actived-blue':''" @click="authenticationPwd">
        <img src="@/assets/images/open-close.png" />
      </div>
      <div class="control-left" v-show="isShowKzBtn">
        <div class="top"  @touchstart="handlePublish({ x: SPEED })"><div class="xq">向前</div></div>
        <div class="left" @touchstart="handlePublish({ y: -SPEED })"><div class="xz">向左</div></div>
        <div class="bottom" @touchstart="handlePublish({ x: -SPEED })"><div class="xx">向下</div></div>
        <div class="right" @touchstart="handlePublish({ y: SPEED })"><div class="xy">向右</div></div>
      </div>
      <div class="control-right" v-show="isShowKzBtn">
        <div class="top"  @touchstart="handlePublish({ h: HEIGHT })"><div class="xq">上升</div></div>
        <div class="left" @touchstart="handlePublish({ w: -W_SPEED })"><div class="xz">左转</div></div>
        <div class="bottom" @touchstart="handlePublish({ h: -HEIGHT })"><div class="xx">下降</div></div>
        <div class="right" @touchstart="handlePublish({ w: W_SPEED })" ><div class="xy">右转</div></div>
      </div>
      <van-dialog v-model:show="dialogVisible" title="确认是否接管?" show-cancel-button @confirm="sureJg"></van-dialog>
    </div>
  </template>
  <script lang="ts" setup>
  import { showNotify } from 'vant';
  import { ref, onMounted, onBeforeUnmount, nextTick, reactive, computed, watch } from 'vue';
  import { useMyStore } from '@/store'
  import {exitController,droneController,returnHomeCancel,returnHome} from '@/api/drone/drc'
  import { useConnectMqtt } from '@/utils/mqtt/connect-mqtt';
  import { useMqtt, DeviceTopicInfo } from '@/utils/mqtt/index'
  import { DRC_METHOD } from '@/types/drc'
  const props = defineProps({
    sn: {
      type: String,
      required: true,
    },
    osdVisible: {
      type: Object,
      required: true,
    }
  });
  const store = useMyStore()
  // 显示控制和退出控制状态按钮
  let isShowKzBtn = ref(false);
  // 是否接管提示
  let dialogVisible = ref(false);
  // 面板提示
  let hasPermission = ref(false);
  // 是否返航状态
  let nowInReturnStatus = ref(false);
  // 返航状态点击
  let nowInReturnStatusClick = ref(false)
  // 控制状态
  let flightMode = ref('自动控制')
  // 控制无人机速度
  let droneSeepd = ref(5);
  const SPEED = ref(droneSeepd.value || 5) //  check
  const HEIGHT = ref(5) //  check
  const W_SPEED = ref(20) // 机头角速度
  // A S D....按键
  let deviceTopicInfo: DeviceTopicInfo = reactive({
    sn: props.sn || '',
    pubTopic: '',
    subTopic: ''
  })
  // 连接或断开drc
  useConnectMqtt()
  // const clientId = computed(() => {
  //   return localStorage.getItem('clientId') //store.state.clientId
  // });
  let clientId = ref(localStorage.getItem('client_id'))
  // {"0":"待机","1":"起飞准备","2":"起飞准备完毕","3":"手动飞行","4":"自动起飞","5":"航线飞行","6":"全景拍照","7":"智能跟随","8":"ADS-B 躲避","9":"自动返航","10":"自动降落","11":"强制降落","12":"三桨叶降落","13":"升级中","14":"未连接","15":"APAS","16":"虚拟摇杆状态","17":"指令飞行","18":"空中 RTK 收敛模式","19":"机场选址中"}
  watch(() => store.state.wsMessage, (newValue, oldValue) => {
    // console.log('监控值', newValue.mode_code)
    hasPermission.value = false
    if (newValue.mode_code == '5') {
      hasPermission.value = true
    }
    if (newValue.mode_code && (newValue.mode_code == 9 || newValue.mode_code == 10) && !nowInReturnStatusClick.value) {
      nowInReturnStatus.value = true
      flightMode.value = '自动控制'
    } else if (newValue.mode_code && (newValue.mode_code == 9 || newValue.mode_code == 10) && nowInReturnStatusClick.value) {
      // 没电、强制返航
      nowInReturnStatus.value = true
      nowInReturnStatusClick.value = false
    }
  }, {deep:true})
  // 进行控制
  const enterFlightControl = () => {
    droneController({ client_id: clientId.value, dock_sn: props.osdVisible.dockSn}).then((result:any) => {
      if (result.code != 0) { return }
      if (result.data.sub && result.data.sub?.length > 0) {
        deviceTopicInfo.subTopic = result.data.sub[0]
      }
      if (result.data.pub && result.data.pub?.length > 0) {
        deviceTopicInfo.pubTopic = result.data.pub[0]
      }
      // 接管成功之后再显示
      isShowKzBtn.value = true
      flightMode.value = '人工控制'
      // 控制成功之后:也可以操作了
      hasPermission.value = true
      nowInReturnStatus.value = true
    })
  }
  // 退出控制
  const exitFlightCOntrol = () => {
    exitController({ client_id: clientId.value, dock_sn: props.osdVisible.dockSn}).then((result:any) => {
      deviceTopicInfo.subTopic = ''
      deviceTopicInfo.pubTopic = ''
      flightMode.value = '自动控制'
    })
  }
  const sureJg = () => {
    dialogVisible.value = false
    enterFlightControl()
  }
  // 是否进行人工控制
  const authenticationPwd = (value:any, str:String) => {
    // 提示是否进行人工控制
    if (!isShowKzBtn.value) {
      if (!hasPermission.value) { return showNotify({ type: 'warning', message: '暂无无人机控制权限' })}
      dialogVisible.value = true
    } else {
      isShowKzBtn.value = false
      exitFlightCOntrol()
    }
  }
  // 返航
  const onBackDock = () => {
    returnHome(props.sn).then((res) => {
      if (res.code === 0) {
        nowInReturnStatus.value = true
        flightMode.value = '自动控制'
        nowInReturnStatusClick.value = false
      }
    })
  }
  // 取消返航
  const notonBackDock = () => {
    returnHomeCancel({ client_id: clientId.value, dock_sn: props.osdVisible.dockSn}).then((result:any) => {
    if (result.code !== 0) return
      nowInReturnStatus.value = false
      // 取消返航时,退出飞行控制,进入人工控制
      nowInReturnStatusClick.value = true
      flightMode.value = '人工控制'
    })
  }
  // 无人机速度控制
  const onControlsDroneSpeed = (value:Boolean) => {
    if (value) {
      if (droneSeepd.value >= 15) {
        return showNotify({ type: 'warning', message: '无人机速度范围应处于0~15m/s之间' })
      }
      droneSeepd.value += 1
    } else {
      if (droneSeepd.value <= 0) {
        return showNotify({ type: 'warning', message: '无人机速度范围应处于0~15m/s之间' })
      }
      droneSeepd.value -= 1
    }
  }
  const mqttHooks =  useMqtt(deviceTopicInfo)
  // 字母按键
  const handlePublish = (params:Object) => {
    if (!hasPermission.value) { return showNotify({ type: 'warning', message: '暂无无人机控制权限' });}
    const body = { method: DRC_METHOD.DRONE_CONTROL, data: params}
    mqttHooks?.publishMqtt(deviceTopicInfo.pubTopic, body, {qos: 0})
  }
  onMounted(async () => {
    await nextTick()
  })
  </script>
  <style lang="scss" scoped>
  .control-console {
    .control {
      position: absolute;
      bottom: 12.8rem;
      right: 0.2rem;
      width: 2rem;
      height: 2rem;
      border-radius: 3px;
      background-color: rgba(0, 0, 0, 0.5);
      display: flex;
      align-items: center;
      justify-content: center;
      overflow: hidden;
      cursor: pointer;
      pointer-events: all;
      img {
        width: 1.6rem;
        height: 1.6rem;
      }
    }
    .actived-blue {
      background-image: none;
      background-color: rgba(23, 124, 198, 0.7);
    }
    .control-left {
      left: 10%;
    }
    .control-right {
      right: 10%;
    }
    .control-left, .control-right{
      width: 100px;
      height: 100px;
      border-radius: 50%;
      overflow: hidden;
      // background-color: rgba(255, 255, 255, 0.5); /* 白色,50%透明度 */
      // box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.3); /* 阴影效果 */
      background-color: rgba(0, 0, 0, 0.5);
      padding: 20px; /* 内边距 */
      position: absolute;
      top: 30%;
      .top,
      .left,
      .bottom,
      .right {
        width: 10px;
        height: 10px;
        position: absolute;
        cursor: pointer;
        z-index: 2;
      }
      .top {
        top: -2px;
        left: 50%;
        transform: translateX(-50%);
        border-top: 10px solid transparent;
        border-right: 10px solid transparent;
        border-left: 10px solid transparent;
        border-bottom: 10px solid #fff;
        &:hover {
          &~.blue-bgc {
            border-top: 50px solid #fff;
          }
        }
        .xq {
          position: absolute;
          top: 10px;
          font-size: 10px;
          width: 30px;
          left: -9px;
          color: #fff;
        }
      }
      .left {
        top: 50%;
        left: -2px;
        transform: translateY(-50%);
        border-top: 10px solid transparent;
        border-right: 10px solid #fff;
        border-left: 10px solid transparent;
        border-bottom: 10px solid transparent;
        &:hover {
          &~.blue-bgc {
            border-left: 50px solid #fff;
          }
        }
        .xz {
          position: absolute;
          top: -7px;
          font-size: 10px;
          width: 30px;
          left: 11px;
          color: #fff;
        }
      }
      .bottom {
        bottom: -2px;
        left: 50%;
        transform: translateX(-50%);
        border-top: 10px solid #fff;
        border-right: 10px solid transparent;
        border-left: 10px solid transparent;
        border-bottom: 10px solid transparent;
        &:hover {
          &~.blue-bgc {
            border-bottom: 50px solid #fff;
          }
        }
        .xx {
          position: absolute;
          bottom: 8px;
          font-size: 10px;
          width: 30px;
          left: -9px;
          color: #fff;
        }
      }
      .right {
        top: 50%;
        right: -2px;
        transform: translateY(-50%);
        border-top: 10px solid transparent;
        border-right: 10px solid transparent;
        border-left: 10px solid #fff;
        border-bottom: 10px solid transparent;
        &:hover {
          &~.blue-bgc {
            border-right: 50px solid #fff;
          }
        }
        .xy {
          position: absolute;
          top: -8px;
          font-size: 10px;
          width: 30px;
          right : 2px;
          color: #fff;
        }
      }
    }
      // width: 100%;
      // height: 200px;
      // margin-top: 20px;
      // margin: 0 auto;
      // display: flex;
      // align-items: center;
      // justify-content: space-between;
      // overflow-x: auto;
      // overflow-y: hidden;
      // background-repeat: no-repeat;
      // background-size: 100% 100%;
      // color: #fff;
      // font-weight: bold;
    // .DroneOperation {
    //   display: flex;
    //   align-items: center;
    //   height: 245px;
    //   position: relative;
    // }
    // .center {
    //   display: flex;
    //   align-items: center;
    //   &_left,
    //   &_center,
    //   .speed {
    //     margin-right: 10px;
    //   }
    //   .center_left {
    //     .tubiaoshow {
    //       height: 50px;
    //       display: flex;
    //       justify-content: center;
    //       align-items: center;
    //       img {
    //         width: 40px;
    //         height: 50px;
    //         cursor: pointer;
    //       }
    //     }
    //     .Airplanemode {
    //       font-style: normal;
    //       margin: 5px 0px;
    //       text-align: center;
    //     }
    //     .operatingjixufanhang {
    //       display: flex;
    //       justify-content: center;
    //       .el-button {
    //         font-size: 16px;
    //         background-color: rgba(0, 0, 0, 0.5);
    //         color: white;
    //         border-width: 0;
    //         margin: 5px;
    //       }
    //     }
    //   }
    //   .center_center {
    //     width: 120px;
    //     padding: 0px 0px;
    //     .center {
    //       height: 45px;
    //       p {
    //         line-height: 50px;
    //         color: #00ee8b;
    //         font-size: 20px;
    //         margin: 0 auto;
    //       }
    //     }
    //     .top,
    //     .bottom {
    //       background: rgba(0, 0, 0, 0.5);
    //       border-radius: 5px;
    //       display: flex;
    //       height: 80px;
    //       width: 100%;
    //       .Q,
    //       .W,
    //       .E {
    //         flex: 1;
    //         display: flex;
    //         flex-direction: column;
    //         align-items: center;
    //         justify-content: center;
    //         gap: 10px;
    //         img {
    //           width: 20px;
    //           height: 20px;
    //           // margin-top: 5px;
    //           // margin-top: 5px;
    //         }
    //         .el-button {
    //           padding: 4px;
    //           font-size: 20px;
    //           height: 30px;
    //           background: #3c3c3c;
    //           color: white;
    //           -webkit-touch-callout: none;
    //           -webkit-user-select: none;
    //           -khtml-user-select: none;
    //           -moz-user-select: none;
    //           -ms-user-select: none;
    //           user-select: none;
    //         }
    //       }
    //       .A,
    //       .S,
    //       .D {
    //         flex: 1;
    //         display: flex;
    //         flex-direction: column;
    //         align-items: center;
    //         justify-content: center;
    //         img {
    //           width: 20px;
    //           height: 20px;
    //         }
    //         .el-button {
    //           padding: 4px;
    //           font-size: 20px;
    //           margin-bottom: 10px;
    //           height: 30px;
    //           background: #3c3c3c;
    //           color: white;
    //           -webkit-touch-callout: none;
    //           -webkit-user-select: none;
    //           -khtml-user-select: none;
    //           -moz-user-select: none;
    //           -ms-user-select: none;
    //           user-select: none;
    //         }
    //       }
    //     }
    //     .top {
    //       // padding: 5px 2px 5px;
    //       margin-bottom: 10px;
    //     }
    //     .bottom {
    //       padding: 5px 0px 0px 0px;
    //     }
    //   }
    //   .speed {
    //     width: 43px;
    //     height: 170px;
    //     border-radius: 5px;
    //     background-color: rgba(0, 0, 0, 0.5);
    //     &-content {
    //       height: 100%;
    //       display: flex;
    //       flex-direction: column;
    //       .add-speed--button,
    //       .sub-speed--button {
    //         flex: 1;
    //         display: flex;
    //         justify-content: center;
    //         align-items: center;
    //         cursor: pointer;
    //         i {
    //           font-size: 20px;
    //           font-weight: bolder;
    //         }
    //       }
    //       .speed-text {
    //         flex: 2;
    //         display: flex;
    //         flex-direction: column;
    //         justify-content: center;
    //         align-items: center;
    //         div:first-child {
    //           font-size: 20px;
    //           color: #00ee8b;
    //           font-weight: bolder;
    //         }
    //       }
    //     }
    //   }
    // }
    // .right {
    //   .rightbutton {
    //     // padding: 0px 0px;
    //     // // width: 150px;
    //     // margin-right: 0px;
    //     .center {
    //       height: 45px;
    //       margin: 5px 0px;
    //       display: flex;
    //       flex-direction: column;
    //       .top_in {
    //         display: flex;
    //         width: 100%;
    //         .top_in_left {
    //           min-width: 70px;
    //           text-align: right;
    //           font-size: 22px;
    //           color: #00ee8b;
    //           margin-right: 5px;
    //           margin-left: auto;
    //         }
    //         .top_in_right {
    //           p {
    //             font-size: 14px;
    //             line-height: 14px;
    //             text-align: right;
    //           }
    //         }
    //       }
    //       .top_in_ASL {
    //         font-size: 12px;
    //         line-height: 12px;
    //         text-align: right;
    //       }
    //     }
    //     .top {
    //       margin-left: auto;
    //       width: 43px;
    //       background: rgba(0, 0, 0, 0.5);
    //       display: flex;
    //       flex-direction: column;
    //       border-radius: 5px;
    //       height: 80px;
    //       margin-bottom: 10px;
    //       img {
    //         width: 25px;
    //         height: 25px;
    //         margin: 5px auto 0px;
    //       }
    //       .el-button {
    //         padding: 4px;
    //         font-size: 16px;
    //         background: #3c3c3c;
    //         color: white;
    //         width: 25px;
    //         height: 30px;
    //         margin: 10px auto 12px;
    //         -webkit-touch-callout: none;
    //         -webkit-user-select: none;
    //         -khtml-user-select: none;
    //         -moz-user-select: none;
    //         -ms-user-select: none;
    //         user-select: none;
    //       }
    //     }
    //     .bottom {
    //       margin-left: auto;
    //       width: 40px;
    //       background: rgba(0, 0, 0, 0.5);
    //       display: flex;
    //       flex-direction: column;
    //       border-radius: 5px;
    //       height: 80px;
    //       img {
    //         width: 25px;
    //         height: 25px;
    //         margin: 0px auto 5px;
    //       }
    //       .el-button {
    //         padding: 4px;
    //         font-size: 20px;
    //         background: #3c3c3c;
    //         color: white;
    //         width: 25px;
    //         margin: 10px auto 10px;
    //       }
    //     }
    //   }
    // }
    // .instrument-panel {
    //   position: relative;
    //   .title {
    //     position: absolute;
    //     font-size: 12px;
    //     font-weight: 400;
    //     top: -5px;
    //     left: 10px;
    //     color: #ffffff;
    //     z-index: 1;
    //   }
    // }
    // .camera-load {
    //   // background: rgba(6, 25, 39, 0.5);
    //   // height: 245px;
    //   // padding: 10px;
    //   // position: relative;
    //   // border: 1px solid red;
    //   .title {
    //     position: absolute;
    //     font-size: 12px;
    //     font-weight: 400;
    //     top: -5px;
    //     left: 10px;
    //     color: #ffffff;
    //     z-index: 1;
    //   }
    //   .camera-control {
    //     width: 100%;
    //     margin-bottom: 10px;
    //     display: flex;
    //     justify-content: center;
    //     .promptInformation {
    //       position: absolute;
    //       width: 30px;
    //       height: 30px;
    //       right: 10px;
    //       top: 10px;
    //     }
    //     .circle-box {
    //       width: 90px;
    //       height: 90px;
    //       border-radius: 50%;
    //       background-color: rgba(0, 0, 0, 0.5);
    //       -webkit-mask-image: radial-gradient(circle,
    //           transparent 35%,
    //           white 35%);
    //       mask-image: radial-gradient(circle, transparent 35%, white 35%);
    //       position: relative;
    //       .top,
    //       .left,
    //       .bottom,
    //       .right {
    //         width: 10px;
    //         height: 10px;
    //         position: absolute;
    //         cursor: pointer;
    //         z-index: 2;
    //       }
    //       .top {
    //         top: -2px;
    //         left: 50%;
    //         transform: translateX(-50%);
    //         border-top: 10px solid transparent;
    //         border-right: 10px solid transparent;
    //         border-left: 10px solid transparent;
    //         border-bottom: 10px solid #fff;
    //         &:hover {
    //           &~.blue-bgc {
    //             border-top: 45px solid #409eff;
    //           }
    //         }
    //       }
    //       .left {
    //         top: 50%;
    //         left: -2px;
    //         transform: translateY(-50%);
    //         border-top: 10px solid transparent;
    //         border-right: 10px solid #fff;
    //         border-left: 10px solid transparent;
    //         border-bottom: 10px solid transparent;
    //         &:hover {
    //           &~.blue-bgc {
    //             border-left: 45px solid #409eff;
    //           }
    //         }
    //       }
    //       .bottom {
    //         bottom: -2px;
    //         left: 50%;
    //         transform: translateX(-50%);
    //         border-top: 10px solid #fff;
    //         border-right: 10px solid transparent;
    //         border-left: 10px solid transparent;
    //         border-bottom: 10px solid transparent;
    //         &:hover {
    //           &~.blue-bgc {
    //             border-bottom: 45px solid #409eff;
    //           }
    //         }
    //       }
    //       .right {
    //         top: 50%;
    //         right: -2px;
    //         transform: translateY(-50%);
    //         border-top: 10px solid transparent;
    //         border-right: 10px solid transparent;
    //         border-left: 10px solid #fff;
    //         border-bottom: 10px solid transparent;
    //         &:hover {
    //           &~.blue-bgc {
    //             border-right: 45px solid #409eff;
    //           }
    //         }
    //       }
    //       .blue-bgc {
    //         width: 90px;
    //         height: 90px;
    //         position: absolute;
    //         top: 0;
    //         left: 0;
    //         z-index: 1;
    //         border-top: 45px solid transparent;
    //         border-right: 45px solid transparent;
    //         border-left: 45px solid transparent;
    //         border-bottom: 45px solid transparent;
    //       }
    //     }
    //   }
    //   .camera-select {
    //     display: flex;
    //     display: flex;
    //     justify-content: center;
    //     :deep() {
    //       .el-select {
    //         width: 250px;
    //         height: 40px;
    //         line-height: 40px;
    //         background-color: rgba(0, 0, 0, 0.5);
    //         border-radius: 5px;
    //         .el-input {
    //           width: auto;
    //           height: auto;
    //           .el-input__inner {
    //             background-color: transparent;
    //             box-shadow: none;
    //             border: 0;
    //             color: #fff;
    //           }
    //           .el-input__suffix {
    //             display: flex;
    //             align-items: center;
    //           }
    //         }
    //       }
    //     }
    //     .load-button {
    //       font-style: normal;
    //       background: rgba(21, 138, 255, 0.5);
    //       margin-left: 10px;
    //       padding: 0 5px;
    //       &:hover {
    //         color: #409eff;
    //       }
    //     }
    //   }
    //   .btn-group {
    //     display: flex;
    //     flex-wrap: wrap;
    //     margin-top: 10px;
    //     width: 300px;
    //     padding: 0px 20px;
    //     .btn-item {
    //       display: flex;
    //       // width: 140px;
    //       box-sizing: border-box;
    //       margin: 2px 10px;
    //       cursor: pointer;
    //       img {
    //         width: 30px;
    //         height: 30px;
    //         margin-right: 3px;
    //       }
    //       div {
    //         font-size: 18px;
    //         font-style: normal;
    //       }
    //     }
    //   }
    // }
    // .payload-control {
    //   height: 100%;
    //   display: flex;
    //   justify-content: center;
    //   flex-direction: column;
    //   gap: 15px;
    //   .left-box {
    //     display: flex;
    //     // flex-direction: column;
    //     align-items: center;
    //     justify-content: center;
    //     gap: 10px;
    //     .circle-box {
    //       width: 100px;
    //       height: 100px;
    //       border-radius: 50%;
    //       overflow: hidden;
    //       background-color: rgba(0, 0, 0, 0.5);
    //       // -webkit-mask-image: radial-gradient(
    //       //   circle,
    //       //   transparent 35%,
    //       //   white 35%
    //       // );
    //       // mask-image: radial-gradient(circle, transparent 35%, white 35%);
    //       position: relative;
    //       // border: 1px solid red;
    //       .top,
    //       .left,
    //       .bottom,
    //       .right {
    //         width: 10px;
    //         height: 10px;
    //         position: absolute;
    //         cursor: pointer;
    //         z-index: 2;
    //       }
    //       .top {
    //         top: -2px;
    //         left: 50%;
    //         transform: translateX(-50%);
    //         border-top: 10px solid transparent;
    //         border-right: 10px solid transparent;
    //         border-left: 10px solid transparent;
    //         border-bottom: 10px solid #fff;
    //         &:hover {
    //           &~.blue-bgc {
    //             border-top: 50px solid #409eff;
    //           }
    //         }
    //       }
    //       .left {
    //         top: 50%;
    //         left: -2px;
    //         transform: translateY(-50%);
    //         border-top: 10px solid transparent;
    //         border-right: 10px solid #fff;
    //         border-left: 10px solid transparent;
    //         border-bottom: 10px solid transparent;
    //         &:hover {
    //           &~.blue-bgc {
    //             border-left: 50px solid #409eff;
    //           }
    //         }
    //       }
    //       .bottom {
    //         bottom: -2px;
    //         left: 50%;
    //         transform: translateX(-50%);
    //         border-top: 10px solid #fff;
    //         border-right: 10px solid transparent;
    //         border-left: 10px solid transparent;
    //         border-bottom: 10px solid transparent;
    //         &:hover {
    //           &~.blue-bgc {
    //             border-bottom: 50px solid #409eff;
    //           }
    //         }
    //       }
    //       .right {
    //         top: 50%;
    //         right: -2px;
    //         transform: translateY(-50%);
    //         border-top: 10px solid transparent;
    //         border-right: 10px solid transparent;
    //         border-left: 10px solid #fff;
    //         border-bottom: 10px solid transparent;
    //         &:hover {
    //           &~.blue-bgc {
    //             border-right: 50px solid #409eff;
    //           }
    //         }
    //       }
    //       .reset-center {
    //         position: absolute;
    //         width: 40%;
    //         height: 40%;
    //         left: 50%;
    //         top: 50%;
    //         transform: translate(-50%, -50%);
    //         border-radius: 50%;
    //         background-color: rgb(63, 66, 68);
    //         z-index: 2;
    //         cursor: pointer;
    //         display: flex;
    //         justify-content: center;
    //         align-items: center;
    //         i {
    //           color: #fff;
    //           font-size: 20px;
    //           font-weight: bolder;
    //         }
    //         &:hover {
    //           background-color: #409eff;
    //         }
    //       }
    //       .blue-bgc {
    //         width: 100px;
    //         height: 100px;
    //         position: absolute;
    //         top: 0;
    //         left: 0;
    //         z-index: 1;
    //         border-top: 50px solid transparent;
    //         border-right: 50px solid transparent;
    //         border-left: 50px solid transparent;
    //         border-bottom: 50px solid transparent;
    //       }
    //     }
    //     .payload-info {
    //       font-size: 14px;
    //     }
    //     .btn-group {
    //       width: auto;
    //       display: flex;
    //       flex-wrap: wrap;
    //       width: 200px;
    //       // flex-direction: column;
    //       // justify-content: center;
    //       .btn-item {
    //         width: 100px;
    //         display: flex;
    //         box-sizing: border-box;
    //         cursor: pointer;
    //         img {
    //           width: 30px;
    //           height: 30px;
    //           margin-right: 3px;
    //         }
    //         div {
    //           height: 100%;
    //           font-size: 17px;
    //           line-height: 30px;
    //           font-style: normal;
    //         }
    //       }
    //     }
    //   }
    //   .right-box {
    //     position: relative;
    //     flex-shrink: 0;
    //     display: flex;
    //     // justify-content: center;
    //     .btn-group {
    //       width: auto;
    //       display: flex;
    //       flex-wrap: wrap;
    //       width: 290px;
    //       justify-content: center;
    //       .btn-item {
    //         width: 140px;
    //         display: flex;
    //         box-sizing: border-box;
    //         cursor: pointer;
    //         img {
    //           width: 30px;
    //           height: 30px;
    //           margin-right: 3px;
    //         }
    //         div {
    //           width: 100px;
    //           height: 100%;
    //           font-size: 17px;
    //           line-height: 30px;
    //           font-style: normal;
    //         }
    //       }
    //     }
    //     .payload-info {
    //       font-size: 14px;
    //       .info-item {
    //         display: flex;
    //         align-items: center;
    //         gap: 10px;
    //         height: 25px;
    //         div:first-child {
    //           width: 170px;
    //         }
    //         div:nth-child(2) {
    //           :deep() {
    //             .el-input-number {
    //               width: 70px;
    //               height: 20px;
    //               &__decrease,
    //               &__increase {
    //                 width: 18px;
    //                 height: 18px;
    //                 line-height: 18px;
    //                 background-color: transparent;
    //                 border-right: 0;
    //                 border-left: 0;
    //                 i {
    //                   color: #fff;
    //                   font-size: 17px;
    //                   font-weight: bold;
    //                 }
    //               }
    //               .el-input {
    //                 margin: 0;
    //                 padding: 0;
    //                 height: 18px;
    //                 display: flex;
    //                 justify-content: center;
    //                 &__inner {
    //                   padding: 0;
    //                 }
    //                 input {
    //                   width: 80px;
    //                   height: 18px;
    //                   overflow: hidden;
    //                   font-size: 14px;
    //                   font-weight: bold;
    //                 }
    //               }
    //             }
    //           }
    //         }
    //       }
    //     }
    //   }
    // }
  }
  </style>
src/views/components/controlConsole-copy1.vue
New file
@@ -0,0 +1,1154 @@
<template>
    <div class="control-console">
      <div class="control" :class="isShowKzBtn?'actived-blue':''" @click="authenticationPwd">
        <img src="@/assets/images/open-close.png" />
      </div>
      <div class="control-left">
        <div class="top"  @touchstart="handlePublish('xq')"><div class="xq">向前</div></div>
        <div class="left" @touchstart="handlePublish('xz')"><div class="xz">向左</div></div>
        <div class="bottom" @touchstart="handlePublish('xx')"><div class="xx">向下</div></div>
        <div class="right" @touchstart="handlePublish('xy')"><div class="xy">向右</div></div>
      </div>
      <div class="control-right">
        <div class="top"  @touchstart="handlePublish('ss')"><div class="xq">上升</div></div>
        <div class="left" @touchstart="handlePublish('xz')"><div class="xz">左转</div></div>
        <div class="bottom" @touchstart="handlePublish('xj')"><div class="xx">下降</div></div>
        <div class="right" @touchstart="handlePublish('yz')" ><div class="xy">右转</div></div>
      </div>
      <van-dialog v-model:show="dialogVisible" title="确认是否接管?" show-cancel-button @confirm="sureJg"></van-dialog>
    </div>
  </template>
  <script lang="ts" setup>
  import { showNotify } from 'vant';
  import { ref, onMounted, onBeforeUnmount, nextTick, reactive, computed, watch } from 'vue';
  import { useMyStore } from '@/store'
  import {exitController,droneController,returnHomeCancel,returnHome} from '@/api/drone/drc'
  import { useConnectMqtt } from '@/utils/mqtt/connect-mqtt';
  import { useMqtt, DeviceTopicInfo } from '@/utils/mqtt/index'
  import { DRC_METHOD } from '@/types/drc'
  const props = defineProps({
    sn: {
      type: String,
      required: true,
    },
    osdVisible: {
      type: Object,
      required: true,
    }
  });
  const store = useMyStore()
  // 显示控制和退出控制状态按钮
  let isShowKzBtn = ref(false);
  // 是否接管提示
  let dialogVisible = ref(false);
  // 面板提示
  let hasPermission = ref(false);
  // 是否返航状态
  let nowInReturnStatus = ref(false);
  // 返航状态点击
  let nowInReturnStatusClick = ref(false)
  // 控制状态
  let flightMode = ref('自动控制')
  // 判断机型是1代还是其他机型 适配替换的api
  let genPortOne = ref(false)
  // 判断机型是1代还是其他机型 适配替换的api
  if (store.state.airPortInfo.deviceType == 1 && store.state.airPortInfo.subType == 0 && store.state.airPortInfo.domain == 3) {
    genPortOne.value = true
  }
  // 控制无人机速度
  let droneSeepd = ref(5);
  const SPEED = genPortOne.value ? ref(droneSeepd.value || 5) : ref(500); //  check
  const HEIGHT = genPortOne.value ? ref(5) : ref(500); //  check
  const W_SPEED = genPortOne.value ? ref(20) : ref(500) // 机头角速度
  // A S D....按键
  let deviceTopicInfo: DeviceTopicInfo = reactive({
    sn: props.sn || '',
    pubTopic: '',
    subTopic: ''
  })
  // 连接或断开drc
  useConnectMqtt()
  // const clientId = computed(() => {
  //   return localStorage.getItem('clientId') //store.state.clientId
  // });
  let clientId = ref(localStorage.getItem('client_id'))
  // {"0":"待机","1":"起飞准备","2":"起飞准备完毕","3":"手动飞行","4":"自动起飞","5":"航线飞行","6":"全景拍照","7":"智能跟随","8":"ADS-B 躲避","9":"自动返航","10":"自动降落","11":"强制降落","12":"三桨叶降落","13":"升级中","14":"未连接","15":"APAS","16":"虚拟摇杆状态","17":"指令飞行","18":"空中 RTK 收敛模式","19":"机场选址中"}
  watch(() => store.state.wsMessage, (newValue, oldValue) => {
    // console.log('监控值', newValue.mode_code)
    hasPermission.value = false
    if (newValue.mode_code == '5' || newValue.mode_code == '17') {
      hasPermission.value = true
    }
    if (newValue.mode_code && (newValue.mode_code == 9 || newValue.mode_code == 10) && !nowInReturnStatusClick.value) {
      nowInReturnStatus.value = true
      flightMode.value = '自动控制'
    } else if (newValue.mode_code && (newValue.mode_code == 9 || newValue.mode_code == 10) && nowInReturnStatusClick.value) {
      // 没电、强制返航
      nowInReturnStatus.value = true
      nowInReturnStatusClick.value = false
    }
  }, {deep:true})
  // 进行控制
  const enterFlightControl = () => {
    droneController({ client_id: clientId.value, dock_sn: props.osdVisible.dockSn}).then((result:any) => {
      if (result.code != 0) { return }
      if (result.data.sub && result.data.sub?.length > 0) {
        deviceTopicInfo.subTopic = result.data.sub[0]
      }
      if (result.data.pub && result.data.pub?.length > 0) {
        deviceTopicInfo.pubTopic = result.data.pub[0]
      }
      // 接管成功之后再显示
      isShowKzBtn.value = true
      flightMode.value = '人工控制'
      // 控制成功之后:也可以操作了
      hasPermission.value = true
      nowInReturnStatus.value = true
    })
  }
  // 退出控制
  const exitFlightCOntrol = () => {
    exitController({ client_id: clientId.value, dock_sn: props.osdVisible.dockSn}).then((result:any) => {
      deviceTopicInfo.subTopic = ''
      deviceTopicInfo.pubTopic = ''
      flightMode.value = '自动控制'
    })
  }
  const sureJg = () => {
    dialogVisible.value = false
    enterFlightControl()
  }
  // 是否进行人工控制
  const authenticationPwd = (value:any, str:String) => {
    // 提示是否进行人工控制
    if (!isShowKzBtn.value) {
      if (!hasPermission.value) { return showNotify({ type: 'warning', message: '暂无无人机控制权限' })}
      dialogVisible.value = true
    } else {
      isShowKzBtn.value = false
      exitFlightCOntrol()
    }
  }
  // 返航
  const onBackDock = () => {
    returnHome(props.sn).then((res) => {
      if (res.code === 0) {
        nowInReturnStatus.value = true
        flightMode.value = '自动控制'
        nowInReturnStatusClick.value = false
      }
    })
  }
  // 取消返航
  const notonBackDock = () => {
    returnHomeCancel({ client_id: clientId.value, dock_sn: props.osdVisible.dockSn}).then((result:any) => {
    if (result.code !== 0) return
      nowInReturnStatus.value = false
      // 取消返航时,退出飞行控制,进入人工控制
      nowInReturnStatusClick.value = true
      flightMode.value = '人工控制'
    })
  }
  // 无人机速度控制
  const onControlsDroneSpeed = (value:Boolean) => {
    if (value) {
      if (droneSeepd.value >= 15) {
        return showNotify({ type: 'warning', message: '无人机速度范围应处于0~15m/s之间' })
      }
      droneSeepd.value += 1
    } else {
      if (droneSeepd.value <= 0) {
        return showNotify({ type: 'warning', message: '无人机速度范围应处于0~15m/s之间' })
      }
      droneSeepd.value -= 1
    }
  }
  const mqttHooks =  useMqtt(deviceTopicInfo)
  // 字母按键
  const handlePublish = (str:String) => {
    console.log('哒哒哒',DRC_METHOD.DRONE_CONTROL)
    // if (!hasPermission.value) { return showNotify({ type: 'warning', message: '暂无无人机控制权限' });}
    let params = ref({})
    if (str == 'xq') {params.value = genPortOne.value?{ x: SPEED.value}:{ pitch: 1024+SPEED.value}}
    else if (str == 'xz') {params.value = genPortOne.value?{ y: -SPEED.value}:{ roll: 1024-SPEED.value}}
    else if (str == 'xx') {params.value = genPortOne.value?{ x: -SPEED.value}:{ pitch: 1024-SPEED.value}}
    else if (str == 'xy') {params.value = genPortOne.value?{ y: SPEED.value}:{ roll: 1024+SPEED.value}}
    else if (str == 'ss') {params.value = genPortOne.value?{ h: HEIGHT.value}:{ throttle: 1024+HEIGHT.value}}
    else if (str == 'xj') {params.value = genPortOne.value?{ w: -W_SPEED.value}:{ yaw: 1024-W_SPEED.value}}
    else if (str == 'yz') {params.value = genPortOne.value?{ h: -HEIGHT.value}:{ throttle: 1024+HEIGHT.value}}
    else if (str == 'xz') {params.value = genPortOne.value?{ w: W_SPEED.value}:{ yaw: 1024+W_SPEED.value}}
    const body = { method: 'stick_control', data: params.value}
    mqttHooks?.publishMqtt(deviceTopicInfo.pubTopic, body, {qos: 0})
  }
  onMounted(() => {
  })
  </script>
  <style lang="scss" scoped>
  .control-console {
    .control {
      position: absolute;
      bottom: 12.8rem;
      right: 0.2rem;
      width: 2rem;
      height: 2rem;
      border-radius: 3px;
      background-color: rgba(0, 0, 0, 0.5);
      display: flex;
      align-items: center;
      justify-content: center;
      overflow: hidden;
      cursor: pointer;
      pointer-events: all;
      img {
        width: 1.6rem;
        height: 1.6rem;
      }
    }
    .actived-blue {
      background-image: none;
      background-color: rgba(23, 124, 198, 0.7);
    }
    .control-left {
      left: 10%;
    }
    .control-right {
      right: 10%;
    }
    .control-left, .control-right{
      width: 100px;
      height: 100px;
      border-radius: 50%;
      overflow: hidden;
      // background-color: rgba(255, 255, 255, 0.5); /* 白色,50%透明度 */
      // box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.3); /* 阴影效果 */
      background-color: rgba(0, 0, 0, 0.5);
      padding: 20px; /* 内边距 */
      position: absolute;
      top: 30%;
      .top,
      .left,
      .bottom,
      .right {
        width: 10px;
        height: 10px;
        position: absolute;
        cursor: pointer;
        z-index: 2;
      }
      .top {
        top: -2px;
        left: 50%;
        transform: translateX(-50%);
        border-top: 10px solid transparent;
        border-right: 10px solid transparent;
        border-left: 10px solid transparent;
        border-bottom: 10px solid #fff;
        &:hover {
          &~.blue-bgc {
            border-top: 50px solid #fff;
          }
        }
        .xq {
          position: absolute;
          top: 10px;
          font-size: 10px;
          width: 30px;
          left: -9px;
          color: #fff;
        }
      }
      .left {
        top: 50%;
        left: -2px;
        transform: translateY(-50%);
        border-top: 10px solid transparent;
        border-right: 10px solid #fff;
        border-left: 10px solid transparent;
        border-bottom: 10px solid transparent;
        &:hover {
          &~.blue-bgc {
            border-left: 50px solid #fff;
          }
        }
        .xz {
          position: absolute;
          top: -7px;
          font-size: 10px;
          width: 30px;
          left: 11px;
          color: #fff;
        }
      }
      .bottom {
        bottom: -2px;
        left: 50%;
        transform: translateX(-50%);
        border-top: 10px solid #fff;
        border-right: 10px solid transparent;
        border-left: 10px solid transparent;
        border-bottom: 10px solid transparent;
        &:hover {
          &~.blue-bgc {
            border-bottom: 50px solid #fff;
          }
        }
        .xx {
          position: absolute;
          bottom: 8px;
          font-size: 10px;
          width: 30px;
          left: -9px;
          color: #fff;
        }
      }
      .right {
        top: 50%;
        right: -2px;
        transform: translateY(-50%);
        border-top: 10px solid transparent;
        border-right: 10px solid transparent;
        border-left: 10px solid #fff;
        border-bottom: 10px solid transparent;
        &:hover {
          &~.blue-bgc {
            border-right: 50px solid #fff;
          }
        }
        .xy {
          position: absolute;
          top: -8px;
          font-size: 10px;
          width: 30px;
          right : 2px;
          color: #fff;
        }
      }
    }
      // width: 100%;
      // height: 200px;
      // margin-top: 20px;
      // margin: 0 auto;
      // display: flex;
      // align-items: center;
      // justify-content: space-between;
      // overflow-x: auto;
      // overflow-y: hidden;
      // background-repeat: no-repeat;
      // background-size: 100% 100%;
      // color: #fff;
      // font-weight: bold;
    // .DroneOperation {
    //   display: flex;
    //   align-items: center;
    //   height: 245px;
    //   position: relative;
    // }
    // .center {
    //   display: flex;
    //   align-items: center;
    //   &_left,
    //   &_center,
    //   .speed {
    //     margin-right: 10px;
    //   }
    //   .center_left {
    //     .tubiaoshow {
    //       height: 50px;
    //       display: flex;
    //       justify-content: center;
    //       align-items: center;
    //       img {
    //         width: 40px;
    //         height: 50px;
    //         cursor: pointer;
    //       }
    //     }
    //     .Airplanemode {
    //       font-style: normal;
    //       margin: 5px 0px;
    //       text-align: center;
    //     }
    //     .operatingjixufanhang {
    //       display: flex;
    //       justify-content: center;
    //       .el-button {
    //         font-size: 16px;
    //         background-color: rgba(0, 0, 0, 0.5);
    //         color: white;
    //         border-width: 0;
    //         margin: 5px;
    //       }
    //     }
    //   }
    //   .center_center {
    //     width: 120px;
    //     padding: 0px 0px;
    //     .center {
    //       height: 45px;
    //       p {
    //         line-height: 50px;
    //         color: #00ee8b;
    //         font-size: 20px;
    //         margin: 0 auto;
    //       }
    //     }
    //     .top,
    //     .bottom {
    //       background: rgba(0, 0, 0, 0.5);
    //       border-radius: 5px;
    //       display: flex;
    //       height: 80px;
    //       width: 100%;
    //       .Q,
    //       .W,
    //       .E {
    //         flex: 1;
    //         display: flex;
    //         flex-direction: column;
    //         align-items: center;
    //         justify-content: center;
    //         gap: 10px;
    //         img {
    //           width: 20px;
    //           height: 20px;
    //           // margin-top: 5px;
    //           // margin-top: 5px;
    //         }
    //         .el-button {
    //           padding: 4px;
    //           font-size: 20px;
    //           height: 30px;
    //           background: #3c3c3c;
    //           color: white;
    //           -webkit-touch-callout: none;
    //           -webkit-user-select: none;
    //           -khtml-user-select: none;
    //           -moz-user-select: none;
    //           -ms-user-select: none;
    //           user-select: none;
    //         }
    //       }
    //       .A,
    //       .S,
    //       .D {
    //         flex: 1;
    //         display: flex;
    //         flex-direction: column;
    //         align-items: center;
    //         justify-content: center;
    //         img {
    //           width: 20px;
    //           height: 20px;
    //         }
    //         .el-button {
    //           padding: 4px;
    //           font-size: 20px;
    //           margin-bottom: 10px;
    //           height: 30px;
    //           background: #3c3c3c;
    //           color: white;
    //           -webkit-touch-callout: none;
    //           -webkit-user-select: none;
    //           -khtml-user-select: none;
    //           -moz-user-select: none;
    //           -ms-user-select: none;
    //           user-select: none;
    //         }
    //       }
    //     }
    //     .top {
    //       // padding: 5px 2px 5px;
    //       margin-bottom: 10px;
    //     }
    //     .bottom {
    //       padding: 5px 0px 0px 0px;
    //     }
    //   }
    //   .speed {
    //     width: 43px;
    //     height: 170px;
    //     border-radius: 5px;
    //     background-color: rgba(0, 0, 0, 0.5);
    //     &-content {
    //       height: 100%;
    //       display: flex;
    //       flex-direction: column;
    //       .add-speed--button,
    //       .sub-speed--button {
    //         flex: 1;
    //         display: flex;
    //         justify-content: center;
    //         align-items: center;
    //         cursor: pointer;
    //         i {
    //           font-size: 20px;
    //           font-weight: bolder;
    //         }
    //       }
    //       .speed-text {
    //         flex: 2;
    //         display: flex;
    //         flex-direction: column;
    //         justify-content: center;
    //         align-items: center;
    //         div:first-child {
    //           font-size: 20px;
    //           color: #00ee8b;
    //           font-weight: bolder;
    //         }
    //       }
    //     }
    //   }
    // }
    // .right {
    //   .rightbutton {
    //     // padding: 0px 0px;
    //     // // width: 150px;
    //     // margin-right: 0px;
    //     .center {
    //       height: 45px;
    //       margin: 5px 0px;
    //       display: flex;
    //       flex-direction: column;
    //       .top_in {
    //         display: flex;
    //         width: 100%;
    //         .top_in_left {
    //           min-width: 70px;
    //           text-align: right;
    //           font-size: 22px;
    //           color: #00ee8b;
    //           margin-right: 5px;
    //           margin-left: auto;
    //         }
    //         .top_in_right {
    //           p {
    //             font-size: 14px;
    //             line-height: 14px;
    //             text-align: right;
    //           }
    //         }
    //       }
    //       .top_in_ASL {
    //         font-size: 12px;
    //         line-height: 12px;
    //         text-align: right;
    //       }
    //     }
    //     .top {
    //       margin-left: auto;
    //       width: 43px;
    //       background: rgba(0, 0, 0, 0.5);
    //       display: flex;
    //       flex-direction: column;
    //       border-radius: 5px;
    //       height: 80px;
    //       margin-bottom: 10px;
    //       img {
    //         width: 25px;
    //         height: 25px;
    //         margin: 5px auto 0px;
    //       }
    //       .el-button {
    //         padding: 4px;
    //         font-size: 16px;
    //         background: #3c3c3c;
    //         color: white;
    //         width: 25px;
    //         height: 30px;
    //         margin: 10px auto 12px;
    //         -webkit-touch-callout: none;
    //         -webkit-user-select: none;
    //         -khtml-user-select: none;
    //         -moz-user-select: none;
    //         -ms-user-select: none;
    //         user-select: none;
    //       }
    //     }
    //     .bottom {
    //       margin-left: auto;
    //       width: 40px;
    //       background: rgba(0, 0, 0, 0.5);
    //       display: flex;
    //       flex-direction: column;
    //       border-radius: 5px;
    //       height: 80px;
    //       img {
    //         width: 25px;
    //         height: 25px;
    //         margin: 0px auto 5px;
    //       }
    //       .el-button {
    //         padding: 4px;
    //         font-size: 20px;
    //         background: #3c3c3c;
    //         color: white;
    //         width: 25px;
    //         margin: 10px auto 10px;
    //       }
    //     }
    //   }
    // }
    // .instrument-panel {
    //   position: relative;
    //   .title {
    //     position: absolute;
    //     font-size: 12px;
    //     font-weight: 400;
    //     top: -5px;
    //     left: 10px;
    //     color: #ffffff;
    //     z-index: 1;
    //   }
    // }
    // .camera-load {
    //   // background: rgba(6, 25, 39, 0.5);
    //   // height: 245px;
    //   // padding: 10px;
    //   // position: relative;
    //   // border: 1px solid red;
    //   .title {
    //     position: absolute;
    //     font-size: 12px;
    //     font-weight: 400;
    //     top: -5px;
    //     left: 10px;
    //     color: #ffffff;
    //     z-index: 1;
    //   }
    //   .camera-control {
    //     width: 100%;
    //     margin-bottom: 10px;
    //     display: flex;
    //     justify-content: center;
    //     .promptInformation {
    //       position: absolute;
    //       width: 30px;
    //       height: 30px;
    //       right: 10px;
    //       top: 10px;
    //     }
    //     .circle-box {
    //       width: 90px;
    //       height: 90px;
    //       border-radius: 50%;
    //       background-color: rgba(0, 0, 0, 0.5);
    //       -webkit-mask-image: radial-gradient(circle,
    //           transparent 35%,
    //           white 35%);
    //       mask-image: radial-gradient(circle, transparent 35%, white 35%);
    //       position: relative;
    //       .top,
    //       .left,
    //       .bottom,
    //       .right {
    //         width: 10px;
    //         height: 10px;
    //         position: absolute;
    //         cursor: pointer;
    //         z-index: 2;
    //       }
    //       .top {
    //         top: -2px;
    //         left: 50%;
    //         transform: translateX(-50%);
    //         border-top: 10px solid transparent;
    //         border-right: 10px solid transparent;
    //         border-left: 10px solid transparent;
    //         border-bottom: 10px solid #fff;
    //         &:hover {
    //           &~.blue-bgc {
    //             border-top: 45px solid #409eff;
    //           }
    //         }
    //       }
    //       .left {
    //         top: 50%;
    //         left: -2px;
    //         transform: translateY(-50%);
    //         border-top: 10px solid transparent;
    //         border-right: 10px solid #fff;
    //         border-left: 10px solid transparent;
    //         border-bottom: 10px solid transparent;
    //         &:hover {
    //           &~.blue-bgc {
    //             border-left: 45px solid #409eff;
    //           }
    //         }
    //       }
    //       .bottom {
    //         bottom: -2px;
    //         left: 50%;
    //         transform: translateX(-50%);
    //         border-top: 10px solid #fff;
    //         border-right: 10px solid transparent;
    //         border-left: 10px solid transparent;
    //         border-bottom: 10px solid transparent;
    //         &:hover {
    //           &~.blue-bgc {
    //             border-bottom: 45px solid #409eff;
    //           }
    //         }
    //       }
    //       .right {
    //         top: 50%;
    //         right: -2px;
    //         transform: translateY(-50%);
    //         border-top: 10px solid transparent;
    //         border-right: 10px solid transparent;
    //         border-left: 10px solid #fff;
    //         border-bottom: 10px solid transparent;
    //         &:hover {
    //           &~.blue-bgc {
    //             border-right: 45px solid #409eff;
    //           }
    //         }
    //       }
    //       .blue-bgc {
    //         width: 90px;
    //         height: 90px;
    //         position: absolute;
    //         top: 0;
    //         left: 0;
    //         z-index: 1;
    //         border-top: 45px solid transparent;
    //         border-right: 45px solid transparent;
    //         border-left: 45px solid transparent;
    //         border-bottom: 45px solid transparent;
    //       }
    //     }
    //   }
    //   .camera-select {
    //     display: flex;
    //     display: flex;
    //     justify-content: center;
    //     :deep() {
    //       .el-select {
    //         width: 250px;
    //         height: 40px;
    //         line-height: 40px;
    //         background-color: rgba(0, 0, 0, 0.5);
    //         border-radius: 5px;
    //         .el-input {
    //           width: auto;
    //           height: auto;
    //           .el-input__inner {
    //             background-color: transparent;
    //             box-shadow: none;
    //             border: 0;
    //             color: #fff;
    //           }
    //           .el-input__suffix {
    //             display: flex;
    //             align-items: center;
    //           }
    //         }
    //       }
    //     }
    //     .load-button {
    //       font-style: normal;
    //       background: rgba(21, 138, 255, 0.5);
    //       margin-left: 10px;
    //       padding: 0 5px;
    //       &:hover {
    //         color: #409eff;
    //       }
    //     }
    //   }
    //   .btn-group {
    //     display: flex;
    //     flex-wrap: wrap;
    //     margin-top: 10px;
    //     width: 300px;
    //     padding: 0px 20px;
    //     .btn-item {
    //       display: flex;
    //       // width: 140px;
    //       box-sizing: border-box;
    //       margin: 2px 10px;
    //       cursor: pointer;
    //       img {
    //         width: 30px;
    //         height: 30px;
    //         margin-right: 3px;
    //       }
    //       div {
    //         font-size: 18px;
    //         font-style: normal;
    //       }
    //     }
    //   }
    // }
    // .payload-control {
    //   height: 100%;
    //   display: flex;
    //   justify-content: center;
    //   flex-direction: column;
    //   gap: 15px;
    //   .left-box {
    //     display: flex;
    //     // flex-direction: column;
    //     align-items: center;
    //     justify-content: center;
    //     gap: 10px;
    //     .circle-box {
    //       width: 100px;
    //       height: 100px;
    //       border-radius: 50%;
    //       overflow: hidden;
    //       background-color: rgba(0, 0, 0, 0.5);
    //       // -webkit-mask-image: radial-gradient(
    //       //   circle,
    //       //   transparent 35%,
    //       //   white 35%
    //       // );
    //       // mask-image: radial-gradient(circle, transparent 35%, white 35%);
    //       position: relative;
    //       // border: 1px solid red;
    //       .top,
    //       .left,
    //       .bottom,
    //       .right {
    //         width: 10px;
    //         height: 10px;
    //         position: absolute;
    //         cursor: pointer;
    //         z-index: 2;
    //       }
    //       .top {
    //         top: -2px;
    //         left: 50%;
    //         transform: translateX(-50%);
    //         border-top: 10px solid transparent;
    //         border-right: 10px solid transparent;
    //         border-left: 10px solid transparent;
    //         border-bottom: 10px solid #fff;
    //         &:hover {
    //           &~.blue-bgc {
    //             border-top: 50px solid #409eff;
    //           }
    //         }
    //       }
    //       .left {
    //         top: 50%;
    //         left: -2px;
    //         transform: translateY(-50%);
    //         border-top: 10px solid transparent;
    //         border-right: 10px solid #fff;
    //         border-left: 10px solid transparent;
    //         border-bottom: 10px solid transparent;
    //         &:hover {
    //           &~.blue-bgc {
    //             border-left: 50px solid #409eff;
    //           }
    //         }
    //       }
    //       .bottom {
    //         bottom: -2px;
    //         left: 50%;
    //         transform: translateX(-50%);
    //         border-top: 10px solid #fff;
    //         border-right: 10px solid transparent;
    //         border-left: 10px solid transparent;
    //         border-bottom: 10px solid transparent;
    //         &:hover {
    //           &~.blue-bgc {
    //             border-bottom: 50px solid #409eff;
    //           }
    //         }
    //       }
    //       .right {
    //         top: 50%;
    //         right: -2px;
    //         transform: translateY(-50%);
    //         border-top: 10px solid transparent;
    //         border-right: 10px solid transparent;
    //         border-left: 10px solid #fff;
    //         border-bottom: 10px solid transparent;
    //         &:hover {
    //           &~.blue-bgc {
    //             border-right: 50px solid #409eff;
    //           }
    //         }
    //       }
    //       .reset-center {
    //         position: absolute;
    //         width: 40%;
    //         height: 40%;
    //         left: 50%;
    //         top: 50%;
    //         transform: translate(-50%, -50%);
    //         border-radius: 50%;
    //         background-color: rgb(63, 66, 68);
    //         z-index: 2;
    //         cursor: pointer;
    //         display: flex;
    //         justify-content: center;
    //         align-items: center;
    //         i {
    //           color: #fff;
    //           font-size: 20px;
    //           font-weight: bolder;
    //         }
    //         &:hover {
    //           background-color: #409eff;
    //         }
    //       }
    //       .blue-bgc {
    //         width: 100px;
    //         height: 100px;
    //         position: absolute;
    //         top: 0;
    //         left: 0;
    //         z-index: 1;
    //         border-top: 50px solid transparent;
    //         border-right: 50px solid transparent;
    //         border-left: 50px solid transparent;
    //         border-bottom: 50px solid transparent;
    //       }
    //     }
    //     .payload-info {
    //       font-size: 14px;
    //     }
    //     .btn-group {
    //       width: auto;
    //       display: flex;
    //       flex-wrap: wrap;
    //       width: 200px;
    //       // flex-direction: column;
    //       // justify-content: center;
    //       .btn-item {
    //         width: 100px;
    //         display: flex;
    //         box-sizing: border-box;
    //         cursor: pointer;
    //         img {
    //           width: 30px;
    //           height: 30px;
    //           margin-right: 3px;
    //         }
    //         div {
    //           height: 100%;
    //           font-size: 17px;
    //           line-height: 30px;
    //           font-style: normal;
    //         }
    //       }
    //     }
    //   }
    //   .right-box {
    //     position: relative;
    //     flex-shrink: 0;
    //     display: flex;
    //     // justify-content: center;
    //     .btn-group {
    //       width: auto;
    //       display: flex;
    //       flex-wrap: wrap;
    //       width: 290px;
    //       justify-content: center;
    //       .btn-item {
    //         width: 140px;
    //         display: flex;
    //         box-sizing: border-box;
    //         cursor: pointer;
    //         img {
    //           width: 30px;
    //           height: 30px;
    //           margin-right: 3px;
    //         }
    //         div {
    //           width: 100px;
    //           height: 100%;
    //           font-size: 17px;
    //           line-height: 30px;
    //           font-style: normal;
    //         }
    //       }
    //     }
    //     .payload-info {
    //       font-size: 14px;
    //       .info-item {
    //         display: flex;
    //         align-items: center;
    //         gap: 10px;
    //         height: 25px;
    //         div:first-child {
    //           width: 170px;
    //         }
    //         div:nth-child(2) {
    //           :deep() {
    //             .el-input-number {
    //               width: 70px;
    //               height: 20px;
    //               &__decrease,
    //               &__increase {
    //                 width: 18px;
    //                 height: 18px;
    //                 line-height: 18px;
    //                 background-color: transparent;
    //                 border-right: 0;
    //                 border-left: 0;
    //                 i {
    //                   color: #fff;
    //                   font-size: 17px;
    //                   font-weight: bold;
    //                 }
    //               }
    //               .el-input {
    //                 margin: 0;
    //                 padding: 0;
    //                 height: 18px;
    //                 display: flex;
    //                 justify-content: center;
    //                 &__inner {
    //                   padding: 0;
    //                 }
    //                 input {
    //                   width: 80px;
    //                   height: 18px;
    //                   overflow: hidden;
    //                   font-size: 14px;
    //                   font-weight: bold;
    //                 }
    //               }
    //             }
    //           }
    //         }
    //       }
    //     }
    //   }
    // }
  }
  </style>
src/views/components/controlConsole.vue
@@ -4,16 +4,16 @@
      <img src="@/assets/images/open-close.png" />
    </div>
    <div class="control-left" v-show="isShowKzBtn">
      <div class="top"  @touchstart="handlePublish({ x: SPEED })"><div class="xq">向前</div></div>
      <div class="left" @touchstart="handlePublish({ y: -SPEED })"><div class="xz">向左</div></div>
      <div class="bottom" @touchstart="handlePublish({ x: -SPEED })"><div class="xx">向下</div></div>
      <div class="right" @touchstart="handlePublish({ y: SPEED })"><div class="xy">向右</div></div>
      <div class="top"  @touchstart="handlePublish('xq')"><div class="xq">向前</div></div>
      <div class="left" @touchstart="handlePublish('xz')"><div class="xz">向左</div></div>
      <div class="bottom" @touchstart="handlePublish('xx')"><div class="xx">向下</div></div>
      <div class="right" @touchstart="handlePublish('xy')"><div class="xy">向右</div></div>
    </div>
    <div class="control-right" v-show="isShowKzBtn">
      <div class="top"  @touchstart="handlePublish({ h: HEIGHT })"><div class="xq">上升</div></div>
      <div class="left" @touchstart="handlePublish({ w: -W_SPEED })"><div class="xz">左转</div></div>
      <div class="bottom" @touchstart="handlePublish({ h: -HEIGHT })"><div class="xx">下降</div></div>
      <div class="right" @touchstart="handlePublish({ w: W_SPEED })" ><div class="xy">右转</div></div>
      <div class="top"  @touchstart="handlePublish('ss')"><div class="xq">上升</div></div>
      <div class="left" @touchstart="handlePublish('zz')"><div class="xz">左转</div></div>
      <div class="bottom" @touchstart="handlePublish('xj')"><div class="xx">下降</div></div>
      <div class="right" @touchstart="handlePublish('yz')" ><div class="xy">右转</div></div>
    </div>
    <van-dialog v-model:show="dialogVisible" title="确认是否接管?" show-cancel-button @confirm="sureJg"></van-dialog>
  </div>
@@ -54,11 +54,16 @@
// 控制状态
let flightMode = ref('自动控制')
let genPortOne = ref(false)
if (store.state.airPortInfo.deviceType == 1 && store.state.airPortInfo.subType == 0 && store.state.airPortInfo.domain == 3) {
  genPortOne.value = true
}
// 控制无人机速度
let droneSeepd = ref(5);
const SPEED = ref(droneSeepd.value || 5) //  check
const HEIGHT = ref(5) //  check
const W_SPEED = ref(20) // 机头角速度
const SPEED = genPortOne.value ? ref(droneSeepd.value || 5) : ref(500); //  check
const HEIGHT = genPortOne.value ? ref(5) : ref(500); //  check
const W_SPEED = genPortOne.value ? ref(20) : ref(500); // 机头角速度
// A S D....按键
let deviceTopicInfo: DeviceTopicInfo = reactive({
@@ -175,10 +180,29 @@
}
const mqttHooks =  useMqtt(deviceTopicInfo)
let seq = ref(0)
// 字母按键
const handlePublish = (params:Object) => {
  if (!hasPermission.value) { return showNotify({ type: 'warning', message: '暂无无人机控制权限' });}
  const body = { method: DRC_METHOD.DRONE_CONTROL, data: params}
const handlePublish = (str:String) => {
  // if (!hasPermission.value) { return showNotify({ type: 'warning', message: '暂无无人机控制权限' });}
  let params = ref({})
  if (str === 'xq') {
    params.value = genPortOne.value ? { x: SPEED.value,seq: seq.value++ } : { x: (1024+SPEED.value),seq: seq.value++ }
  } else if(str === 'xz') {
    params.value = genPortOne.value ? { y: -SPEED.value,seq: seq.value++ } : { y: (1024-SPEED.value),seq: seq.value++ }
  } else if(str === 'xx') {
    params.value = genPortOne.value ? { x: -SPEED.value,seq: seq.value++ } : { x: (1024-SPEED.value),seq: seq.value++ }
  } else if(str === 'xy') {
    params.value = genPortOne.value ? { y: SPEED.value,seq: seq.value++ } :  { y: (1024+SPEED.value),seq: seq.value++ }
  } else if(str === 'ss') {
    params.value = genPortOne.value ? { h: HEIGHT.value,seq: seq.value++ } : { h: (1024+HEIGHT.value),seq: seq.value++ }
  } else if(str === 'zz') {
    params.value = genPortOne.value ? { w: -W_SPEED.value,seq: seq.value++ } : { w: (1024-W_SPEED.value),seq: seq.value++ }
  } else if(str === 'xj') {
    params.value = genPortOne.value ? { h: -HEIGHT.value,seq: seq.value++ } :  { h: (1024-HEIGHT.value),seq: seq.value++ }
  } else if(str === 'yz') {
    params.value = genPortOne.value ? { w: W_SPEED.value,seq: seq.value++ } :  { w: (1024+W_SPEED.value),seq: seq.value++ }
  }
  const body = { method: genPortOne.value?'drone_control':'stick_control', data: params.value}
  mqttHooks?.publishMqtt(deviceTopicInfo.pubTopic, body, {qos: 0})
}
@@ -338,801 +362,5 @@
      }
    }
  }
    // width: 100%;
    // height: 200px;
    // margin-top: 20px;
    // margin: 0 auto;
    // display: flex;
    // align-items: center;
    // justify-content: space-between;
    // overflow-x: auto;
    // overflow-y: hidden;
    // background-repeat: no-repeat;
    // background-size: 100% 100%;
    // color: #fff;
    // font-weight: bold;
  // .DroneOperation {
  //   display: flex;
  //   align-items: center;
  //   height: 245px;
  //   position: relative;
  // }
  // .center {
  //   display: flex;
  //   align-items: center;
  //   &_left,
  //   &_center,
  //   .speed {
  //     margin-right: 10px;
  //   }
  //   .center_left {
  //     .tubiaoshow {
  //       height: 50px;
  //       display: flex;
  //       justify-content: center;
  //       align-items: center;
  //       img {
  //         width: 40px;
  //         height: 50px;
  //         cursor: pointer;
  //       }
  //     }
  //     .Airplanemode {
  //       font-style: normal;
  //       margin: 5px 0px;
  //       text-align: center;
  //     }
  //     .operatingjixufanhang {
  //       display: flex;
  //       justify-content: center;
  //       .el-button {
  //         font-size: 16px;
  //         background-color: rgba(0, 0, 0, 0.5);
  //         color: white;
  //         border-width: 0;
  //         margin: 5px;
  //       }
  //     }
  //   }
  //   .center_center {
  //     width: 120px;
  //     padding: 0px 0px;
  //     .center {
  //       height: 45px;
  //       p {
  //         line-height: 50px;
  //         color: #00ee8b;
  //         font-size: 20px;
  //         margin: 0 auto;
  //       }
  //     }
  //     .top,
  //     .bottom {
  //       background: rgba(0, 0, 0, 0.5);
  //       border-radius: 5px;
  //       display: flex;
  //       height: 80px;
  //       width: 100%;
  //       .Q,
  //       .W,
  //       .E {
  //         flex: 1;
  //         display: flex;
  //         flex-direction: column;
  //         align-items: center;
  //         justify-content: center;
  //         gap: 10px;
  //         img {
  //           width: 20px;
  //           height: 20px;
  //           // margin-top: 5px;
  //           // margin-top: 5px;
  //         }
  //         .el-button {
  //           padding: 4px;
  //           font-size: 20px;
  //           height: 30px;
  //           background: #3c3c3c;
  //           color: white;
  //           -webkit-touch-callout: none;
  //           -webkit-user-select: none;
  //           -khtml-user-select: none;
  //           -moz-user-select: none;
  //           -ms-user-select: none;
  //           user-select: none;
  //         }
  //       }
  //       .A,
  //       .S,
  //       .D {
  //         flex: 1;
  //         display: flex;
  //         flex-direction: column;
  //         align-items: center;
  //         justify-content: center;
  //         img {
  //           width: 20px;
  //           height: 20px;
  //         }
  //         .el-button {
  //           padding: 4px;
  //           font-size: 20px;
  //           margin-bottom: 10px;
  //           height: 30px;
  //           background: #3c3c3c;
  //           color: white;
  //           -webkit-touch-callout: none;
  //           -webkit-user-select: none;
  //           -khtml-user-select: none;
  //           -moz-user-select: none;
  //           -ms-user-select: none;
  //           user-select: none;
  //         }
  //       }
  //     }
  //     .top {
  //       // padding: 5px 2px 5px;
  //       margin-bottom: 10px;
  //     }
  //     .bottom {
  //       padding: 5px 0px 0px 0px;
  //     }
  //   }
  //   .speed {
  //     width: 43px;
  //     height: 170px;
  //     border-radius: 5px;
  //     background-color: rgba(0, 0, 0, 0.5);
  //     &-content {
  //       height: 100%;
  //       display: flex;
  //       flex-direction: column;
  //       .add-speed--button,
  //       .sub-speed--button {
  //         flex: 1;
  //         display: flex;
  //         justify-content: center;
  //         align-items: center;
  //         cursor: pointer;
  //         i {
  //           font-size: 20px;
  //           font-weight: bolder;
  //         }
  //       }
  //       .speed-text {
  //         flex: 2;
  //         display: flex;
  //         flex-direction: column;
  //         justify-content: center;
  //         align-items: center;
  //         div:first-child {
  //           font-size: 20px;
  //           color: #00ee8b;
  //           font-weight: bolder;
  //         }
  //       }
  //     }
  //   }
  // }
  // .right {
  //   .rightbutton {
  //     // padding: 0px 0px;
  //     // // width: 150px;
  //     // margin-right: 0px;
  //     .center {
  //       height: 45px;
  //       margin: 5px 0px;
  //       display: flex;
  //       flex-direction: column;
  //       .top_in {
  //         display: flex;
  //         width: 100%;
  //         .top_in_left {
  //           min-width: 70px;
  //           text-align: right;
  //           font-size: 22px;
  //           color: #00ee8b;
  //           margin-right: 5px;
  //           margin-left: auto;
  //         }
  //         .top_in_right {
  //           p {
  //             font-size: 14px;
  //             line-height: 14px;
  //             text-align: right;
  //           }
  //         }
  //       }
  //       .top_in_ASL {
  //         font-size: 12px;
  //         line-height: 12px;
  //         text-align: right;
  //       }
  //     }
  //     .top {
  //       margin-left: auto;
  //       width: 43px;
  //       background: rgba(0, 0, 0, 0.5);
  //       display: flex;
  //       flex-direction: column;
  //       border-radius: 5px;
  //       height: 80px;
  //       margin-bottom: 10px;
  //       img {
  //         width: 25px;
  //         height: 25px;
  //         margin: 5px auto 0px;
  //       }
  //       .el-button {
  //         padding: 4px;
  //         font-size: 16px;
  //         background: #3c3c3c;
  //         color: white;
  //         width: 25px;
  //         height: 30px;
  //         margin: 10px auto 12px;
  //         -webkit-touch-callout: none;
  //         -webkit-user-select: none;
  //         -khtml-user-select: none;
  //         -moz-user-select: none;
  //         -ms-user-select: none;
  //         user-select: none;
  //       }
  //     }
  //     .bottom {
  //       margin-left: auto;
  //       width: 40px;
  //       background: rgba(0, 0, 0, 0.5);
  //       display: flex;
  //       flex-direction: column;
  //       border-radius: 5px;
  //       height: 80px;
  //       img {
  //         width: 25px;
  //         height: 25px;
  //         margin: 0px auto 5px;
  //       }
  //       .el-button {
  //         padding: 4px;
  //         font-size: 20px;
  //         background: #3c3c3c;
  //         color: white;
  //         width: 25px;
  //         margin: 10px auto 10px;
  //       }
  //     }
  //   }
  // }
  // .instrument-panel {
  //   position: relative;
  //   .title {
  //     position: absolute;
  //     font-size: 12px;
  //     font-weight: 400;
  //     top: -5px;
  //     left: 10px;
  //     color: #ffffff;
  //     z-index: 1;
  //   }
  // }
  // .camera-load {
  //   // background: rgba(6, 25, 39, 0.5);
  //   // height: 245px;
  //   // padding: 10px;
  //   // position: relative;
  //   // border: 1px solid red;
  //   .title {
  //     position: absolute;
  //     font-size: 12px;
  //     font-weight: 400;
  //     top: -5px;
  //     left: 10px;
  //     color: #ffffff;
  //     z-index: 1;
  //   }
  //   .camera-control {
  //     width: 100%;
  //     margin-bottom: 10px;
  //     display: flex;
  //     justify-content: center;
  //     .promptInformation {
  //       position: absolute;
  //       width: 30px;
  //       height: 30px;
  //       right: 10px;
  //       top: 10px;
  //     }
  //     .circle-box {
  //       width: 90px;
  //       height: 90px;
  //       border-radius: 50%;
  //       background-color: rgba(0, 0, 0, 0.5);
  //       -webkit-mask-image: radial-gradient(circle,
  //           transparent 35%,
  //           white 35%);
  //       mask-image: radial-gradient(circle, transparent 35%, white 35%);
  //       position: relative;
  //       .top,
  //       .left,
  //       .bottom,
  //       .right {
  //         width: 10px;
  //         height: 10px;
  //         position: absolute;
  //         cursor: pointer;
  //         z-index: 2;
  //       }
  //       .top {
  //         top: -2px;
  //         left: 50%;
  //         transform: translateX(-50%);
  //         border-top: 10px solid transparent;
  //         border-right: 10px solid transparent;
  //         border-left: 10px solid transparent;
  //         border-bottom: 10px solid #fff;
  //         &:hover {
  //           &~.blue-bgc {
  //             border-top: 45px solid #409eff;
  //           }
  //         }
  //       }
  //       .left {
  //         top: 50%;
  //         left: -2px;
  //         transform: translateY(-50%);
  //         border-top: 10px solid transparent;
  //         border-right: 10px solid #fff;
  //         border-left: 10px solid transparent;
  //         border-bottom: 10px solid transparent;
  //         &:hover {
  //           &~.blue-bgc {
  //             border-left: 45px solid #409eff;
  //           }
  //         }
  //       }
  //       .bottom {
  //         bottom: -2px;
  //         left: 50%;
  //         transform: translateX(-50%);
  //         border-top: 10px solid #fff;
  //         border-right: 10px solid transparent;
  //         border-left: 10px solid transparent;
  //         border-bottom: 10px solid transparent;
  //         &:hover {
  //           &~.blue-bgc {
  //             border-bottom: 45px solid #409eff;
  //           }
  //         }
  //       }
  //       .right {
  //         top: 50%;
  //         right: -2px;
  //         transform: translateY(-50%);
  //         border-top: 10px solid transparent;
  //         border-right: 10px solid transparent;
  //         border-left: 10px solid #fff;
  //         border-bottom: 10px solid transparent;
  //         &:hover {
  //           &~.blue-bgc {
  //             border-right: 45px solid #409eff;
  //           }
  //         }
  //       }
  //       .blue-bgc {
  //         width: 90px;
  //         height: 90px;
  //         position: absolute;
  //         top: 0;
  //         left: 0;
  //         z-index: 1;
  //         border-top: 45px solid transparent;
  //         border-right: 45px solid transparent;
  //         border-left: 45px solid transparent;
  //         border-bottom: 45px solid transparent;
  //       }
  //     }
  //   }
  //   .camera-select {
  //     display: flex;
  //     display: flex;
  //     justify-content: center;
  //     :deep() {
  //       .el-select {
  //         width: 250px;
  //         height: 40px;
  //         line-height: 40px;
  //         background-color: rgba(0, 0, 0, 0.5);
  //         border-radius: 5px;
  //         .el-input {
  //           width: auto;
  //           height: auto;
  //           .el-input__inner {
  //             background-color: transparent;
  //             box-shadow: none;
  //             border: 0;
  //             color: #fff;
  //           }
  //           .el-input__suffix {
  //             display: flex;
  //             align-items: center;
  //           }
  //         }
  //       }
  //     }
  //     .load-button {
  //       font-style: normal;
  //       background: rgba(21, 138, 255, 0.5);
  //       margin-left: 10px;
  //       padding: 0 5px;
  //       &:hover {
  //         color: #409eff;
  //       }
  //     }
  //   }
  //   .btn-group {
  //     display: flex;
  //     flex-wrap: wrap;
  //     margin-top: 10px;
  //     width: 300px;
  //     padding: 0px 20px;
  //     .btn-item {
  //       display: flex;
  //       // width: 140px;
  //       box-sizing: border-box;
  //       margin: 2px 10px;
  //       cursor: pointer;
  //       img {
  //         width: 30px;
  //         height: 30px;
  //         margin-right: 3px;
  //       }
  //       div {
  //         font-size: 18px;
  //         font-style: normal;
  //       }
  //     }
  //   }
  // }
  // .payload-control {
  //   height: 100%;
  //   display: flex;
  //   justify-content: center;
  //   flex-direction: column;
  //   gap: 15px;
  //   .left-box {
  //     display: flex;
  //     // flex-direction: column;
  //     align-items: center;
  //     justify-content: center;
  //     gap: 10px;
  //     .circle-box {
  //       width: 100px;
  //       height: 100px;
  //       border-radius: 50%;
  //       overflow: hidden;
  //       background-color: rgba(0, 0, 0, 0.5);
  //       // -webkit-mask-image: radial-gradient(
  //       //   circle,
  //       //   transparent 35%,
  //       //   white 35%
  //       // );
  //       // mask-image: radial-gradient(circle, transparent 35%, white 35%);
  //       position: relative;
  //       // border: 1px solid red;
  //       .top,
  //       .left,
  //       .bottom,
  //       .right {
  //         width: 10px;
  //         height: 10px;
  //         position: absolute;
  //         cursor: pointer;
  //         z-index: 2;
  //       }
  //       .top {
  //         top: -2px;
  //         left: 50%;
  //         transform: translateX(-50%);
  //         border-top: 10px solid transparent;
  //         border-right: 10px solid transparent;
  //         border-left: 10px solid transparent;
  //         border-bottom: 10px solid #fff;
  //         &:hover {
  //           &~.blue-bgc {
  //             border-top: 50px solid #409eff;
  //           }
  //         }
  //       }
  //       .left {
  //         top: 50%;
  //         left: -2px;
  //         transform: translateY(-50%);
  //         border-top: 10px solid transparent;
  //         border-right: 10px solid #fff;
  //         border-left: 10px solid transparent;
  //         border-bottom: 10px solid transparent;
  //         &:hover {
  //           &~.blue-bgc {
  //             border-left: 50px solid #409eff;
  //           }
  //         }
  //       }
  //       .bottom {
  //         bottom: -2px;
  //         left: 50%;
  //         transform: translateX(-50%);
  //         border-top: 10px solid #fff;
  //         border-right: 10px solid transparent;
  //         border-left: 10px solid transparent;
  //         border-bottom: 10px solid transparent;
  //         &:hover {
  //           &~.blue-bgc {
  //             border-bottom: 50px solid #409eff;
  //           }
  //         }
  //       }
  //       .right {
  //         top: 50%;
  //         right: -2px;
  //         transform: translateY(-50%);
  //         border-top: 10px solid transparent;
  //         border-right: 10px solid transparent;
  //         border-left: 10px solid #fff;
  //         border-bottom: 10px solid transparent;
  //         &:hover {
  //           &~.blue-bgc {
  //             border-right: 50px solid #409eff;
  //           }
  //         }
  //       }
  //       .reset-center {
  //         position: absolute;
  //         width: 40%;
  //         height: 40%;
  //         left: 50%;
  //         top: 50%;
  //         transform: translate(-50%, -50%);
  //         border-radius: 50%;
  //         background-color: rgb(63, 66, 68);
  //         z-index: 2;
  //         cursor: pointer;
  //         display: flex;
  //         justify-content: center;
  //         align-items: center;
  //         i {
  //           color: #fff;
  //           font-size: 20px;
  //           font-weight: bolder;
  //         }
  //         &:hover {
  //           background-color: #409eff;
  //         }
  //       }
  //       .blue-bgc {
  //         width: 100px;
  //         height: 100px;
  //         position: absolute;
  //         top: 0;
  //         left: 0;
  //         z-index: 1;
  //         border-top: 50px solid transparent;
  //         border-right: 50px solid transparent;
  //         border-left: 50px solid transparent;
  //         border-bottom: 50px solid transparent;
  //       }
  //     }
  //     .payload-info {
  //       font-size: 14px;
  //     }
  //     .btn-group {
  //       width: auto;
  //       display: flex;
  //       flex-wrap: wrap;
  //       width: 200px;
  //       // flex-direction: column;
  //       // justify-content: center;
  //       .btn-item {
  //         width: 100px;
  //         display: flex;
  //         box-sizing: border-box;
  //         cursor: pointer;
  //         img {
  //           width: 30px;
  //           height: 30px;
  //           margin-right: 3px;
  //         }
  //         div {
  //           height: 100%;
  //           font-size: 17px;
  //           line-height: 30px;
  //           font-style: normal;
  //         }
  //       }
  //     }
  //   }
  //   .right-box {
  //     position: relative;
  //     flex-shrink: 0;
  //     display: flex;
  //     // justify-content: center;
  //     .btn-group {
  //       width: auto;
  //       display: flex;
  //       flex-wrap: wrap;
  //       width: 290px;
  //       justify-content: center;
  //       .btn-item {
  //         width: 140px;
  //         display: flex;
  //         box-sizing: border-box;
  //         cursor: pointer;
  //         img {
  //           width: 30px;
  //           height: 30px;
  //           margin-right: 3px;
  //         }
  //         div {
  //           width: 100px;
  //           height: 100%;
  //           font-size: 17px;
  //           line-height: 30px;
  //           font-style: normal;
  //         }
  //       }
  //     }
  //     .payload-info {
  //       font-size: 14px;
  //       .info-item {
  //         display: flex;
  //         align-items: center;
  //         gap: 10px;
  //         height: 25px;
  //         div:first-child {
  //           width: 170px;
  //         }
  //         div:nth-child(2) {
  //           :deep() {
  //             .el-input-number {
  //               width: 70px;
  //               height: 20px;
  //               &__decrease,
  //               &__increase {
  //                 width: 18px;
  //                 height: 18px;
  //                 line-height: 18px;
  //                 background-color: transparent;
  //                 border-right: 0;
  //                 border-left: 0;
  //                 i {
  //                   color: #fff;
  //                   font-size: 17px;
  //                   font-weight: bold;
  //                 }
  //               }
  //               .el-input {
  //                 margin: 0;
  //                 padding: 0;
  //                 height: 18px;
  //                 display: flex;
  //                 justify-content: center;
  //                 &__inner {
  //                   padding: 0;
  //                 }
  //                 input {
  //                   width: 80px;
  //                   height: 18px;
  //                   overflow: hidden;
  //                   font-size: 14px;
  //                   font-weight: bold;
  //                 }
  //               }
  //             }
  //           }
  //         }
  //       }
  //     }
  //   }
  // }
}
</style>
src/views/hooks/droneFly.ts
@@ -80,11 +80,11 @@
            ssLinePath
          )
          let domain = sessionStorage.getItem('domain')
          if (domain !== '0') {
            addFlyLaser(
              deviceInfo.payloads[0]
            )
          }
          // if (domain !== '0') {
          //   addFlyLaser(
          //     deviceInfo.payloads[0]
          //   )
          // }
          setelCamera(
            viewDroneInfo.longitude,
            viewDroneInfo.latitude,
@@ -109,7 +109,6 @@
        }
      } else {
        if (deviceInfo.mode_code && [3, 4, 5, 9, 10, 17].includes(deviceInfo.mode_code)) {
          // 暂时把视锥代码注释掉
          initCreateFrustum(deviceInfo, viewDroneInfo)
          addFlyGltf(
            viewDroneInfo.longitude,
@@ -122,11 +121,11 @@
            ssLinePath
          )
          let domain = sessionStorage.getItem('domain')
          if (domain !== '0') {
            addFlyLaser(
              deviceInfo.payloads[0]
            )
          }
          // if (domain !== '0') {
          //   addFlyLaser(
          //     deviceInfo.payloads[0]
          //   )
          // }
        }
      }
      const imgRightBlue = new URL('@/assets/images/arrow-right-pink.png', import.meta.url).href
@@ -149,7 +148,7 @@
        })
      }
      
      if (data.deviceInfo[data.currentSn].mode_code && [3, 4, 5, 9, 10, 17].includes(deviceInfo.mode_code)) {
      if (data.deviceInfo[data.currentSn].mode_code && [3, 4, 5, 9, 10].includes(deviceInfo.mode_code)) {
        if (switchSaving) return (switchSaving = false)
        const newPositions = globalCesium.Cartesian3.fromDegrees(
          data.deviceInfo[data.currentSn].longitude,
tsconfig.json
@@ -17,7 +17,7 @@
      "dom",
    ],
    "paths": {
      "/@/*": [
      "@/*": [
        "src/*"
      ],
    }
vite.config.ts
@@ -20,8 +20,8 @@
  },
  server: {
    open: true,
    // host: '192.168.1.79',
    // port: 5173,
    host: '192.168.1.178',
    port: 5173,
    proxy: {
      '/index/api': {
        target: 'https://wrj.shuixiongit.com/index/api',