chenyao
2025-02-14 58aeb1b4b7fef38bfbba99231c46d1c6572e8712
修改一版
9 files modified
1 files added
714 ■■■■■ changed files
index.html 2 ●●● patch | view | raw | blame | history
src/api/manage.ts 7 ●●●●● patch | view | raw | blame | history
src/assets/images/me_zx.png patch | view | raw | blame | history
src/utils/cesium-tsa.js 2 ●●● patch | view | raw | blame | history
src/views/DronePilotDetails.vue 424 ●●●●● patch | view | raw | blame | history
src/views/DronePilotList.vue 5 ●●●● patch | view | raw | blame | history
src/views/components/controlConsole.vue 80 ●●●●● patch | view | raw | blame | history
src/views/components/ptzControl.vue 20 ●●●● patch | view | raw | blame | history
src/views/hooks/droneFly.ts 172 ●●●● patch | view | raw | blame | history
src/views/hooks/initPointWayline.ts 2 ●●● patch | view | raw | blame | history
index.html
@@ -5,7 +5,7 @@
    <link rel="icon" href="/favicon.ico">
    <!-- <meta name="viewport" content="width=device-width, initial-scale=1.0"> -->
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <title>低空无人机监测app</title>
    <title>低空无人机监测网移动应用</title>
  </head>
  <body>
    <div id="app"></div>
src/api/manage.ts
@@ -118,6 +118,13 @@
  return result.data
}
// 获取两点之间的高度和距离
export const getTwoPointInfo = async function (workspace_id: String,personLat:Number,personLng:Number,pointLat:Number,pointLng:Number): Promise<IWorkspaceResponse<any>> {
  const url = `${HTTP_PREFIX_H5}/getPointInfo/${workspace_id}/?personLat=${personLat}&personLng=${personLng}&pointLat=${pointLat}&pointLng=${pointLng}`
  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/assets/images/me_zx.png
src/utils/cesium-tsa.js
@@ -178,7 +178,7 @@
      navigationHelpButton: false, // 右上角的帮助按钮,
      selectionIndicator: false, // 是否显示选择指示器
      baseLayer: false,
      fullscreenButton: true,
      fullscreenButton: false,
    })
src/views/DronePilotDetails.vue
@@ -1,6 +1,5 @@
<template>
  <div class="drone-pilot-details" :style="{ width: screenWidth,height: screenHeight}">
    <!-- 横屏模式 -->
    <div id="landscapeBox" class="landscape-box" :style="{ width: screenWidth + 'px', height: (screenHeight) + '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">
@@ -8,12 +7,19 @@
        </video>
        <el-empty v-show="videoUrl == ''" description="当前设备已关机,无法进行直播" :image="imageUrl"></el-empty>
      </div>
      <div class="l-map" :style="{ width: screenWidthMap + 'px', height: (screenHeightMap) + 'px'}">
      <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="getPhoneLocation(true)" />
          </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" />
@@ -25,25 +31,6 @@
        <controlConsole :sn="sn" :osdVisible="sbInfo" :cesiumViewe="globalViewer" />
      </div>
    </div>
    <!-- 竖屏 -->
    <!-- <div class="portrait-screen" v-else>
      <div class="l-video" :style="{ width: screenWidth + 'px', height: (screenHeight/2)+40 + 'px'}">
        <video v-show="videoUrl" ref="videoPlayerBig" :style="{ width: screenWidth + 'px', height: (screenHeight/2)+40 + '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>
      <div class="l-map" :style="{ width: screenWidth + 'px', height: (screenHeight/2)-40 + 'px'}">
        <div id="cesiumContainerMap"></div>
        <div class="l-zp" id="lZp">
          <comPass :cesiumViewe="globalViewer"/>
        </div>
      </div>
      <div class="right-box">
        <ptzControl :sn="sn" :osdVisible="sbInfo" />
        <controlConsole :sn="sn" :osdVisible="sbInfo" />
      </div>
    </div> -->
  </div>
</template>
@@ -51,7 +38,7 @@
import { ref, onMounted, onBeforeUnmount, nextTick, reactive, computed, watch } from 'vue';
import { EDeviceTypeName, EHmsLevel } from '@/types/enums'
import { getRoot } from '../../root'
import { startLivestream, getLiveVideoUrl } from '@/api/manage'
import { getWaylineFile, getLiveVideoUrl } from '@/api/manage'
import { CURRENT_CONFIG as config } from '@/api/http/config'
// import videojs from 'video.js'
// import 'video.js/dist/video-js.css';
@@ -63,7 +50,6 @@
// import { cesiumOperation } from '@/hooks/use-cesium-tsa'
// const { _init } = cesiumOperation();
import { useMyStore } from '@/store'
import { getWaylineFile } from '@/api/manage'
import comPass from './components/comPass.vue'
import ptzControl from './components/ptzControl.vue'
import controlConsole from './components/controlConsole.vue'
@@ -79,7 +65,7 @@
import flvjs from 'flv.js';
const { pointWayline } = initPointWayLine()
const { planarWayline } = initPlanarWayline()
const { initDock } = droneFly()
const { initDock, getPhoneLocation } = droneFly()
const {
  removeAllPoint,
@@ -98,29 +84,21 @@
const screenWidth = ref(window.innerWidth);
const screenHeight = ref(window.innerHeight);
// 地图切换
const screenWidthMap = ref(window.innerWidth);
const screenHeightMap = ref((window.innerHeight/2)+40);
const screenWidthMap = ref((window.innerHeight/2)*2)// ref(window.innerWidth);
const screenHeightMap = ref((window.innerHeight/2));
// 视频切换
const screenWidthVideo = ref(window.innerWidth);
const screenHeightVideo = ref(window.innerHeight/2);
const isBigMap = ref(false)
// 更新屏幕尺寸的函数
const updateScreenSize = () => {
  screenWidth.value = window.innerWidth;
  screenHeight.value = window.innerHeight;
  if (isLandscape.value) { //横屏
    screenWidthMap.value = window.innerWidth/2
    screenHeightMap.value = window.innerHeight
    screenWidthVideo.value = window.innerWidth/2
    screenHeightVideo.value = window.innerHeight
  } else {//竖屏
    screenWidthMap.value = window.innerWidth
    screenHeightMap.value = (window.innerHeight/2)-40
    screenWidthVideo.value = window.innerWidth
    screenHeightVideo.value = (window.innerHeight/2)+40
  }
};
// 显示高德地图矢量还是影像(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()
// 获取路由
@@ -140,7 +118,7 @@
// 获取机场/遥控器sn
let localData = ref<any>(window.localStorage.getItem('sbInfo'))
const sbInfo: deviceInfo = JSON.parse(localData.value) as deviceInfo;
// console.log('哒哒哒', sbInfo)
// 无人机sn 
const sn = ref<String>(sbInfo.sn)
// 机场sn 
@@ -156,8 +134,6 @@
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 meMapSrc = new URL('@/assets/images/me.png', import.meta.url).href
const jgbMapSrc = new URL('@/assets/images/jgb.png', import.meta.url).href
@@ -195,6 +171,10 @@
let workspaceId = ref<String>(sbInfo.workspaceId)
localStorage.setItem('bs_workspace_id', workspaceId.value)
// store.commit('SET_SELECTED_WORKSPACE_ID', workspaceId.value);
// 自身定位
let me_latitude = 0;
let me_longitude = 0;
// RTCWEB 加载视频
const playBig = () => {
@@ -253,59 +233,8 @@
    },
  )
}
// const play = () => {
//   webrtcPlayer = new window.ZLMRTCClient.Endpoint({
//     element: videoPlayer.value, // video 标签
//     debug: true, // 是否打印日志
//     zlmsdpUrl: videoUrl.value, //Rtc地址
//     simulecast: false,
//     useCamera: false,
//     audioEnable: true,
//     videoEnable: true,
//     recvOnly: true,
//     usedatachannel: false,
//   })
//   webrtcPlayer.on(
//     window.ZLMRTCClient.Events.WEBRTC_ICE_CANDIDATE_ERROR,
//     (e) => {
//       // ICE 协商出错
//       console.error('ICE 协商出错')
//       // this.eventcallbacK('ICE ERROR', 'ICE 协商出错')
//     },
//   )
//   webrtcPlayer.on(
//     window.ZLMRTCClient.Events.WEBRTC_ON_REMOTE_STREAMS,
//     (e) => {
//       //获取到了远端流,可以播放
//       console.log('播放成功', e.streams)
//       // this.eventcallbacK('playing', '播放成功')
//     },
//   )
//   webrtcPlayer.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('流不存在')
//         timer = setTimeout(() => {
//           webrtcPlayer.close()
//           play()
//         }, 100)
//       }
//     },
//   )
//   webrtcPlayer.on(
//     window.ZLMRTCClient.Events.WEBRTC_ON_LOCAL_STREAM,
//     (s) => {
//     },
//   )
// }
const videoUrlFlv = ref<String>('')
// 加载该设备的视频信息
const loadVideo = async () => {
  await getLiveVideoUrl(sn.value).then((res) => {
@@ -316,34 +245,10 @@
      drawCanvasHeight.value = videoWH.value.offsetHeight;
    }
    videoUrl.value =  res.data.data.rtcs_url
    videoUrlFlv.value = res.data.data.url
    // 播放
    // play()
    playBig()
    // flv
    // initFlvPlayer()
  })
}
// flv
const videoPlayerFlv = ref(null); // 引用 video 元素
let flvPlayer = null; // 用于存储 flv.js 播放器实例
 // 初始化 flv.js 播放器
const initFlvPlayer = () => {
  if (flvjs.isSupported()) {
    const videoElement = videoPlayerFlv.value; // 获取 video 元素
    flvPlayer = flvjs.createPlayer({
      type: 'flv', // 视频格式
      url: videoUrlFlv.value, // FLV 视频地址
    });
    flvPlayer.attachMediaElement(videoElement); // 绑定 video 元素
    flvPlayer.load(); // 加载视频
    flvPlayer.play(); // 播放视频
  } else {
    console.error('Your browser does not support flv.js.');
  }
};
//===============================
@@ -391,69 +296,116 @@
  isBigMap.value = !isBigMap.value
  const cesiumContainer = document.getElementById('cesiumContainerBigMap');
  const lZp = document.getElementById('lZp');
  const lZoom = document.getElementById('lZoom');
  if (isBigMap.value) { // 全屏
    cesiumContainer.style.position = 'fixed';
    cesiumContainer.style.top = '0';
    cesiumContainer.style.left = '0';
    cesiumContainer.style.width = '100%';
    cesiumContainer.style.height = '100%';
    lZp.style.right = '40%';
    lZoom.style.left = '0';
  } else { // 缩放
    cesiumContainer.style.position = 'static';
    cesiumContainer.style.width = `${screenWidthMap.value}`
    cesiumContainer.style.height = `${screenHeight.value}`
    lZp.style.right = '16%';
    lZoom.style.left = 'auto';
  // const lZoom = document.getElementById('lZoom');
  if (isLandscape.value) { // 横屏
    if (isBigMap.value) { // 全屏
      cesiumContainer.style.position = 'fixed';
      cesiumContainer.style.top = '0';
      cesiumContainer.style.left = '0';
      cesiumContainer.style.width = `${screenWidthMap.value * 2}px`
      cesiumContainer.style.height = `${screenHeightMap.value}px`
      lZp.style.right = '40%';
      // lZoom.style.left = '0';
    } else { // 缩放
      cesiumContainer.style.width = `${screenWidthMap.value}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 = '0';
      cesiumContainer.style.left = '0';
      cesiumContainer.style.width = `${screenWidthMap.value}px`
      cesiumContainer.style.height = `${screenHeightMap.value * 2}px`
      lZp.style.right = '30%';
      // lZoom.style.right = '0';
    } else { // 缩放
    console.log('竖屏宽度',screenWidthMap.value)
    console.log('竖屏高度度',screenHeightMap.value)
      cesiumContainer.style.width = `${screenWidthMap.value}px`
      cesiumContainer.style.height = `${screenHeightMap.value}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 () => {
  screenWidth.value = window.innerWidth;
  screenHeight.value = window.innerHeight;
  console.log('屏幕宽度', screenWidth.value)
  console.log('屏幕高度', screenHeight.value)
  const landscapeBox = document.getElementById('landscapeBox');
  const cesiumContainer = document.getElementById('cesiumContainerBigMap');
  let cesiumContainer = document.getElementById('cesiumContainerBigMap');
  const videoModule = document.getElementById('videoModule');
  const lZp = document.getElementById('lZp');
  const lZoom = document.getElementById('lZoom');
  // 横屏再加载视频请求
  // destroyViewer()
  // loadVideo()
  if (window.innerWidth > window.innerHeight) {
  if (window.innerWidth > window.innerHeight) {//横屏
    screenWidthVideo.value = window.innerWidth/2
    screenHeightVideo.value = window.innerHeight
    isLandscape.value = true;
    updateScreenSize()
    // updateScreenSize()
    landscapeBox.style.display = 'flex';
    lZp.style.right = '16%';
    lZoom.style.display = 'block';
    lZoom.style.position = 'fixed';
    // await nextTick();
    // await _init('cesiumContainerBigMap');
    // await getWrjSsLx();
  } else {
    cesiumContainer.style.width = `${screenWidth.value/2}px`
    cesiumContainer.style.height = `${screenHeight.value}px`
  } else { //竖屏
    isLandscape.value = false;
    updateScreenSize()
    screenWidthVideo.value = window.innerWidth
    screenHeightVideo.value = (window.innerHeight/2)
    // updateScreenSize()
    landscapeBox.style.display = 'inherit';
    lZp.style.right = '28%';
    lZoom.style.display = 'none';
    // landscapeBox.style.width = `${screenWidth}`
    // landscapeBox.style.height = `${screenHeight}`
    // videoModule.style.width = `${screenWidth}`
    // videoModule.style.height = `${screenHeight}`
    // await nextTick();
    // await _init('cesiumContainerMap');
    // await getWrjSsLx();
    landscapeBox.style.overflow = 'hidden';
    lZp.style.right = '32%';
    cesiumContainer.style.width = `${screenHeight.value}px`
    cesiumContainer.style.height = `${screenHeight.value/2}px`
  }
};
// 获取实时航线
const getWrjSsLx = () => {
  if (window.cesiumViewer== null) return
  globalViewer = window.cesiumViewer;
  getWaylineFile(sbInfo.sn).then((res:any) => {
    if (res.code != 200) return
    console.log('草草草草', res.data)
    ssLinePath.value = res.data
    globalViewer = window.cesiumViewer
    // globalViewer = window.cesiumViewer
    // 先有航线,再飞行
    generateCourse()
  })
@@ -485,7 +437,7 @@
          scale: 1.0,
        }
      })
       window.cesiumViewer.scene.camera.setView({
      window.cesiumViewer.scene.camera.setView({
        destination: globalCesium.Cartesian3.fromDegrees(
          Number(longitude),
          Number(latitude),
@@ -522,21 +474,24 @@
watch(() => store.state.wsMessage, (newValue, oldValue) => {
  // 控制台报 Expected longitude to be typeof number, actual typeof was undefined 是因为这里没有及时拿到longitude数据
  viewDroneInfo.longitude = newValue?.longitude
  viewDroneInfo.latitude = newValue?.latitude
  viewDroneInfo.elevation = Number(newValue?.elevation.toFixed(2)) + droneHeight.value
  if (newValue) {
    viewDroneInfo.longitude = newValue?.longitude
    viewDroneInfo.latitude = newValue?.latitude
    viewDroneInfo.elevation = Number(newValue?.elevation.toFixed(2)) + droneHeight.value
  }
}, {deep: true})
// 生成航线轨迹
const generateCourse = async () => {
  // ssLinePath.value = 'https://wrj.shuixiongit.com/minio/cloud-bucket/wayline/20250211/wayline_1739254562374.kmz'
  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
  console.log('看看航线值', placemark.Polygon)
  console.log('看看航线值', sbInfo)
  if (placemark?.Polygon) {
    // return 'planar'
    planarWayline(ssLinePath.value, sbInfo.longitude, sbInfo.latitude)
@@ -546,57 +501,7 @@
  }
}
const me_latitude = ref(0);
const me_longitude = ref(0);
// const loading = ref(true);
// const error = ref(null);
// 获取自身定位
const getLocation = () => {
  if (window.cesiumViewer == null) return
  if (navigator.geolocation) {
    navigator.geolocation.getCurrentPosition(
      (position) => {
        console.log('333',position.coords.latitude)
        console.log('333',position.coords.longitude)
        me_latitude.value =  position.coords.latitude;
        me_longitude.value = position.coords.longitude;
        // loading.value = false;
        // 开始给自己定位
        getLnglatAltitude(me_longitude.value, me_latitude.value,  window.cesiumViewer).then(res => {
          removeById('me_coordinate')
          window.cesiumViewer.entities.add({
            position: globalCesium.Cartesian3.fromDegrees(
              me_longitude.value,
              me_latitude.value,
              res.height,
            ),
            id: 'me_coordinate',
            billboard: {
              image: meMapSrc,
              outlineWidth: 0,
              width: 36,
              height: 36,
              scale: 1.0,
            }
          })
          // window.cesiumViewer.scene.camera.setView({
          //   destination: globalCesium.Cartesian3.fromDegrees(
          //     Number(me_longitude),
          //     Number(me_latitude),
          //     10000.0,
          //   ),
          // })
          // droneHeight.value = res.height
        })
      },
      (err) => {
        console.log('定位有误')
      }
    );
  } else {
    console.log('您的浏览器不支持地理定位')
  }
};
let intervalId = null;
onMounted(async () => {
  window.addEventListener('orientationchange', checkOrientation);
@@ -606,9 +511,13 @@
  await nextTick();
  await _init('cesiumContainerBigMap');
  await getWrjSsLx();
  await getLocation()
  // 判断是遥控器还是机场
  let domain = sessionStorage.getItem('domain')
  if (domain !== '0') {
    await getPhoneLocation(false,workspaceId.value)
  // // // 设置定时器,每隔 5 秒刷新一次数据
    intervalId = setInterval(getPhoneLocation, 5000);
  }
});
onBeforeUnmount(() => {
@@ -617,12 +526,9 @@
  if (player) {
    player.dispose();
  }
  if (flvPlayer) {
    flvPlayer.pause(); // 暂停播放
    flvPlayer.unload(); // 卸载视频
    flvPlayer.detachMediaElement(); // 解绑 video 元素
    flvPlayer.destroy(); // 销毁播放器
    flvPlayer = null;
  // 组件卸载时清除定时器
  if (intervalId) {
    clearInterval(intervalId);
  }
});
@@ -633,8 +539,9 @@
<style lang="scss" scoped>
.drone-pilot-details {
  .landscape-box {
    position: relative;
    display: flex;
    overflow: hidden;
    // position: relative;
    // display: flex;
    .l-map {
      .l-zp {
        position: fixed;
@@ -644,9 +551,11 @@
      .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;
@@ -680,6 +589,8 @@
  #cesiumContainerBigMap {
    width: 100%;
    height: 100%;
    margin: 0;
    padding: 0;
    overflow: hidden;
    :deep() {
@@ -704,61 +615,6 @@
      }
    }
  }
  #cesiumContainerMap {
    width: 100%;
    height: 100%;
    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%;
            }
          }
        }
      }
    }
  }
  .portrait-screen {
    .l-map {
      .l-zp {
        position: fixed;
        right: 28%;
        bottom: 0;
      }
      .l-zoom {
        position: fixed;
        bottom: 0;
        .zoom {
          width: 2rem;
          height: 2rem;
          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;
          }
        }
      }
    }
  }
  .right-box {}
}
</style>
src/views/DronePilotList.vue
@@ -57,7 +57,7 @@
// 存储设备值
let osdVisible = reactive<any>({})
const vConsole = new VConsole();
// const vConsole = new VConsole();
// 点击信息详情
const infoClick = (data:any) => {
@@ -75,6 +75,9 @@
    osdVisible.device_domain = data.children.domain || 0
    osdVisible.device_sub_type = data.children.sub_type || 1
    osdVisible.device_type = data.children.type || 0
    // osdVisible.domain = data.children.domain || 0
    // 前端自己加的判断
    window.sessionStorage.setItem('domain', JSON.stringify(droneOrPilotTxt.value == 'drone'? 0 : 2));
    store.commit('SET_OSD_VISIBLE_INFO', osdVisible)
    // 跳转操作屏幕
    root.$router.push({ path:ERouterName.DRONEPILOTDETAILS })
src/views/components/controlConsole.vue
@@ -29,84 +29,6 @@
        </div>
      </template>
    </el-dialog>
    <!-- <div class="DroneOperation">
      <div class="center">
        <div class="center_left">
          <div class="tubiaoshow">
            <el-tooltip effect="dark" content="控制开关" placement="top">
              <img ref="controllerRef" v-show="!isShowKzBtn" src="@/assets/images/notTurnoffcontrol.png" @click="authenticationPwd(1, '开')" />
              <img ref="controllerRef" v-show="isShowKzBtn" src="@/assets/images/Turnoffcontrol.png" @click="authenticationPwd(1, '关')" />
            </el-tooltip>
          </div>
          <p class="Airplanemode">
            <span>飞行模式:</span>
            <span ref="flightModeRef">{{ flightMode }}</span>
          </p>
          <p class="operatingjixufanhang">
            <el-button size="mini" @click="!nowInReturnStatus ? onBackDock() : notonBackDock()">
              {{ !nowInReturnStatus ? '返航' : '取消返航' }}
            </el-button>
            <el-button size="mini" @click="authenticationPwd(2, '关')">继续任务</el-button>
          </p>
        </div>
        <div class="center_center">
          <div class="top">
            <div class="Q">
              <img src="/public/images/turnleft-drone.png" class="img" />
              <el-button type="info" size="mini" @click="handlePublish({ w: -W_SPEED })">Q</el-button>
            </div>
            <div class="W">
              <img src="/public/images/up-drone.png" class="img" />
              <el-button type="info" size="mini" @click="handlePublish({ x: SPEED })">W</el-button>
            </div>
            <div class="E">
              <img src="/public/images/turnright-drone.png" class="img"/>
              <el-button type="info" size="mini" @click="handlePublish({ w: W_SPEED })">E</el-button>
            </div>
          </div>
          <div class="bottom">
            <div class="A">
              <el-button type="info" size="mini"  @click="handlePublish({ y: -SPEED })">A</el-button>
              <img src="/public/images/left-drone.png"/>
            </div>
            <div class="S">
              <el-button type="info" size="mini"  @click="handlePublish({ x: -SPEED })">S</el-button>
              <img src="/public/images/down-drone.png"/>
            </div>
            <div class="D">
              <el-button type="info" size="mini"  @click="handlePublish({ y: SPEED })">D</el-button>
              <img src="/public/images/right-drone.png"/>
            </div>
          </div>
        </div>
        <div class="speed">
          <div class="speed-content">
            <div class="add-speed--button" @click="onControlsDroneSpeed(true)">
              <i class="el-icon-plus"></i>
            </div>
            <div class="speed-text">
              <div>{{ droneSeepd }}</div>
              <div>m/s</div>
            </div>
            <div class="sub-speed--button" @click="onControlsDroneSpeed(false)">
              <i class="el-icon-minus"></i>
            </div>
          </div>
        </div>
      </div>
      <div class="right">
        <div class="rightbutton">
          <div class="top">
            <img src="/public/images/zbottom-drone.png"/>
            <el-button size="mini" @click="handlePublish({ h: HEIGHT })">C</el-button>
          </div>
          <div class="bottom">
            <el-button size="mini"  @click="handlePublish({ h: -HEIGHT })">Z</el-button>
            <img src="/public/images/ctop-drone.png"/>
          </div>
        </div>
      </div>
    </div> -->
  </div>
</template>
@@ -285,7 +207,7 @@
  .control {
    position: fixed;
    top: 0.2rem;
    right: 0.2rem;
    left: 0.2rem;
    width: 2rem;
    height: 2rem;
    border-radius: 3px;
src/views/components/ptzControl.vue
@@ -19,10 +19,10 @@
      <div class="btn-item" @touchstart="onZoom(false)">
        <img src="@/assets/images/suoxiao.png" />
      </div>
      <div class="btn-item" @touchstart="onChangeD">
      <!-- <div class="btn-item" @touchstart="onChangeD">
        <img v-if="is2d" src="@/assets/images/stand.png" />
        <img v-else src="@/assets/images/satellite.png" />
      </div>
      </div> -->
    </div>
    <div class="circle-box" v-show="isPtz">
      <div class="top" @click="ytClick('up')" @mousedown="onMouseDown(KeyCode.ARROW_UP)" @mouseup="onMouseUp"
@@ -102,7 +102,7 @@
let isPtz = ref(false)
// 显示高德地图矢量还是影像(2D/3D)
let is2d = ref(true)
// let is2d = ref(true)
let yaw_speed = ref((payloadCameraMode.value == 'wide'? 1 : Math.ceil(zoom_factor.value))*10) // 云台横向角度
let pitch_speed = ref((payloadCameraMode.value == 'wide'? 1 : Math.ceil(zoom_factor.value))*10) // 云台纵向角度
@@ -346,11 +346,11 @@
  })
}
const onChangeD = () => {
  is2d.value = !is2d.value
  store.commit('SET_MAP_SETTING_MODE', is2d.value?2:3);
  loadLAYER();
}
// const onChangeD = () => {
//   is2d.value = !is2d.value
//   store.commit('SET_MAP_SETTING_MODE', is2d.value?2:3);
//   loadLAYER();
// }
// 重置云台角度
const onResetGimbal = async (resetMode:any) => {
@@ -401,7 +401,7 @@
  .ptz {
    position: fixed;
    top: 3rem;
    right: 0.2rem;
    left: 0.2rem;
    width: 2rem;
    height: 2rem;
    border-radius: 3px;
@@ -425,7 +425,7 @@
  .btn-group {
    position: fixed;
    top: 5.8rem;
    right: 4px;
    left: 0.2rem;
    // padding: 4px;
    .btn-item {
      width: 2rem;
src/views/hooks/droneFly.ts
@@ -5,6 +5,7 @@
import IndexedDBService from '@/utils/indexDB'
import CreateFrustum from '@/utils/cesium/frustum/CreateFrustum'
import { useMyStore } from '@/store'
import { getTwoPointInfo } from '@/api/manage'
const { getEntityById, removeById, globalCesium, addLeftClickEvent, removeLeftClickEvent, flyTo } = cesiumOperation()
// 无人机实体
@@ -12,6 +13,10 @@
// 激光实体
let laserEntity = null
// 两点之间线实体
let twoLineEntity = null
let myAppEntity = null;
export function droneFly () {
  const store = useMyStore()
  let deviceInfo = {} // 无人机信息
@@ -30,6 +35,16 @@
  let lastTime = null
  let viewInfoFrustum = null
  // 手机设备定位
  let me_latitude = 0;
  let me_longitude = 0;
  let me_altitude = 0;
  // 扫射定位
  let measure_target_longitude = 0;
  let measure_target_latitude = 0;
  let measure_target_altitude = 0;
  async function initDock(data:any, sn:any, dockSn:any, workspaceId:any, ssLinePath:any, viewDroneInfo:any) {
    // 获取workspaceId
    wId = workspaceId
@@ -38,7 +53,7 @@
    // 机场信息
    dockInfo = data.dockInfo[`${dockSn}`]
    viewDroneInfo = viewDroneInfo
    console.log('打印我想看的',viewDroneInfo.longitude)
    console.log('导致地图不显示原因1',viewDroneInfo.longitude)
    // 当前飞行任务创建时间
    if (data.currentType === EDeviceTypeName.Aircraft && deviceInfo) {
      const droneLngLat = {
@@ -64,16 +79,12 @@
            dockInfo,
            ssLinePath
          )
          addFlyLaser(
            viewDroneInfo.longitude,
            viewDroneInfo.latitude,
            deviceInfo.height,
            deviceInfo.payloads[0],
            deviceInfo.attitude_head,
            deviceInfo,
            dockInfo,
            ssLinePath
          )
          let domain = sessionStorage.getItem('domain')
          if (domain !== '0') {
            addFlyLaser(
              deviceInfo.payloads[0]
            )
          }
          setelCamera(
            viewDroneInfo.longitude,
            viewDroneInfo.latitude,
@@ -95,7 +106,6 @@
      } else {
        if (deviceInfo.mode_code && [3, 4, 5, 9, 10].includes(deviceInfo.mode_code)) {
          initCreateFrustum(deviceInfo, viewDroneInfo)
          console.log('4444', viewDroneInfo.longitude)
          addFlyGltf(
            viewDroneInfo.longitude,
            viewDroneInfo.latitude,
@@ -106,16 +116,12 @@
            dockInfo,
            ssLinePath
          )
          addFlyLaser(
            viewDroneInfo.longitude,
            viewDroneInfo.latitude,
            deviceInfo.height,
            deviceInfo.payloads[0],
            deviceInfo.attitude_head,
            deviceInfo,
            dockInfo,
            ssLinePath
          )
          let domain = sessionStorage.getItem('domain')
          if (domain !== '0') {
            addFlyLaser(
              deviceInfo.payloads[0]
            )
          }
        }
      }
      const imgRightBlue = new URL('@/assets/images/arrow-right-pink.png', import.meta.url).href
@@ -188,18 +194,24 @@
  const imgLaser = new URL('@/assets/images/laser.png', import.meta.url).href
  // 增加激光扫射点
  function addFlyLaser(lng:any, lat:any, alt:any, payloads:any, attitude_head:any, deviceInfo:any, dockInfo:any, ssLinePath:any) {
    console.log('哒哒哒', payloads)
  function addFlyLaser(payloads:any) {
    const startPosition = globalCesium.Cartesian3.fromDegrees(
      me_longitude, me_latitude, 0
    )
    const position = globalCesium.Cartesian3.fromDegrees(
      payloads.measure_target_longitude, payloads.measure_target_latitude, payloads.measure_target_altitude
    )
    measure_target_longitude = payloads.measure_target_longitude;
    measure_target_latitude = payloads.measure_target_latitude;
    measure_target_altitude = payloads.measure_target_altitude;
    if (laserEntity && laserEntity != null) {
      laserEntity.position = new globalCesium.CallbackProperty(function () {
        return position
      }, false)
      laserEntity.orientation = new globalCesium.CallbackProperty(function () {
        return orientation
      }, false)
      // laserEntity.orientation = new globalCesium.CallbackProperty(function () {
      //   return orientation
      // }, false)
  
      laserEntity.show = true
  
@@ -217,6 +229,20 @@
        }
      })
    }
    removeById('route_two_line')
    twoLineEntity = window.cesiumViewer.entities.add({
      id: 'route_two_line',
      polyline: {
        positions: new globalCesium.CallbackProperty(() => [startPosition, position], false),
        width: 5,
        material: new globalCesium.PolylineDashMaterialProperty({
            color: globalCesium.Color.YELLOW, // 虚线颜色
            dashLength: 6.0, // 虚线段的长度
        }),
        zIndex: 1,
        clampToGround: false,
      }
    })
    // 增加激光扫射信息
    laserEntity.label = new globalCesium.LabelGraphics({
      text: `目标海拔:${Math.ceil(payloads.measure_target_altitude)}m\n测距距离:${Math.round(
@@ -286,7 +312,6 @@
  async function createDroneEntityLabel (entity:any, deviceInfo:any, dockInfo:any, ssLinePath:any) {
    deviceInfo = deviceInfo
    if (currentTaskCreateTime === null) return
    console.log('77777', deviceInfo?.basic_osd?.longitude)
    if (!deviceInfo?.longitude && !deviceInfo?.latitude) return
    if (deviceInfo.mode_code !== 5) {
      currentTaskCreateTime = null
@@ -538,7 +563,96 @@
      heading: attitude_head,
    })
  }
  // 获取手机定位和激光发射定位的高度和距离
  function getTwoHeightWidth(workspaceId:String) {
    getTwoPointInfo(workspaceId,me_latitude,me_longitude,measure_target_latitude,measure_target_longitude).then((res:any) => {
      const heightDifference = res.data.heightDifference
      const distance = res.data.distance
      // 增加激光扫射信息
      myAppEntity.label = new globalCesium.LabelGraphics({
        text: `高度:${Math.ceil(heightDifference)}m\n距离:${Math.round(
          Math.ceil(distance),
        )}m`,
        font: '13px monospace',
        showBackground: true,
        horizontalOrigin: globalCesium.HorizontalOrigin.CENTER,
        verticalOrigin: globalCesium.VerticalOrigin.BOTTOM,
        disableDepthTestDistance: Number.POSITIVE_INFINITY,
        pixelOffset: new globalCesium.Cartesian2(0, -40),
        show: true,
      })
    })
  }
  const meMapSrc = new URL('@/assets/images/me.png', import.meta.url).href
  // 获取手机设备定位
  function getPhoneLocation(value:Boolean, workspaceId:String) {
    if (window.cesiumViewer == null) return
    // 创建一个箭头实体
    removeById('me_dw')
    myAppEntity = window.cesiumViewer.entities.add({
      id: 'me_dw',
      position: globalCesium.Cartesian3.fromDegrees(0, 0, 0), // 初始位置
      billboard: {
        image: meMapSrc, // 箭头图片路径
        width: 30,
        height: 30,
        alignedAxis: globalCesium.Cartesian3.UNIT_Z, // 对齐轴
      },
      // orientation: new globalCesium.CallbackProperty(() => {
      //   return globalCesium.Transforms.headingPitchRollQuaternion(
      //     myAppEntity.position.getValue(window.cesiumViewer.clock.currentTime),
      //     new globalCesium.HeadingPitchRoll(heading, 0, 0) // 设置朝向
      //   );
      // }, false),
    });
    let heading = 0; // 初始朝向
    // 获取设备朝向
    // if (window.DeviceOrientationEvent) {
    //   window.addEventListener('deviceorientation', (event) => {
    //     if (event.alpha !== null) {
    //       heading = globalCesium.Math.toRadians(event.alpha); // 将 alpha 转换为弧度
    //     }
    //   });
    // } else {
    //   console.log('手机不支持.');
    // }
    // 获取设备位置
    if (navigator.geolocation) {
      navigator.geolocation.watchPosition((position) => {
        me_longitude = position.coords.longitude;
        me_latitude = position.coords.latitude;
        me_altitude = position.coords.altitude || 0;
        // 更新箭头实体的位置
        myAppEntity.position = globalCesium.Cartesian3.fromDegrees(me_longitude, me_latitude, me_altitude);
        if (value) {
          // 将相机定位到设备位置 只有点击图标才可以执行这里
          window.cesiumViewer.camera.setView({
            destination: globalCesium.Cartesian3.fromDegrees(me_longitude, me_latitude, me_altitude + 1000), // 相机高度
            // orientation: {
            //   heading: heading, // 相机朝向
            //   pitch: globalCesium.Math.toRadians(-90), // 俯视角度
            //   roll: 0,
            // },
          });
        }
        // 查看两条线直接距离和高度
        // getTwoHeightWidth(workspaceId)
      }, (error) => {
        console.error('定位有误:', error);
      });
    } else {
      console.log('手机不支持.');
    }
  }
  return {
    initDock
    initDock,
    getPhoneLocation,
  }
}
src/views/hooks/initPointWayline.ts
@@ -58,6 +58,7 @@
  }
  // 绘制航线到地图上
  function drawWayline (xmlJson:any, route:any) {
    console.log('航线绘制到地图上',xmlJson)
    const points = xmlJson?.['Folder']?.['Placemark']
    //每个点数据
    let waylinePosition = reactive([])
@@ -102,7 +103,6 @@
            dornePoint.longitude,
            dornePoint.latitude,
          )
          console.log('看看值', waylinePosition[index])
          if (getLongOk < 20) {
            setting = {
              id: 'route_point_' + index,