forked from drone/command-center-dashboard

罗广辉
2025-04-21 2800fa4f32f3900509cb4d6eefaf2bfaf54efdd7
src/components/CurrentTaskDetails/ControlPanel/ControlPanel.vue
@@ -34,7 +34,7 @@
         </div>
         <div class="speed">
            <el-icon class="btnIcon" @click="speed = speed + 1">
            <el-icon class="btnIcon" @click="speed = speed === 15 ? 15 : speed + 1">
               <Plus />
            </el-icon>
            <div>
@@ -42,7 +42,7 @@
               <br />
               m/s
            </div>
            <el-icon class="btnIcon" @click="speed = speed - 1">
            <el-icon class="btnIcon" @click="speed = speed === 0 ? 0 : speed - 1">
               <Minus />
            </el-icon>
         </div>
@@ -68,7 +68,7 @@
      </div>
      <!--     指南针-->
      <div class="compass">
         <ControlComPass />
         <ControlComPass :options="compassOptions" />
      </div>
      <div class="ptzControlBox">
@@ -84,7 +84,7 @@
         <div class="ptzControlBtnBox">
            <div class="ptzControlBtn b-r">
               <div
                  v-for="(item, index) in list5"
                  v-for="(item, index) in ptzBtns"
                  :style="item.style"
                  class="ptzControlItem"
                  @mousedown="onMouseDown(item.key)"
@@ -93,7 +93,7 @@
               <div
                  class="ptzControlItemIcon"
                  v-for="(item, index) in list5"
                  v-for="(item, index) in ptzBtns"
                  :style="{ transform: `rotate(${index * 90}deg)` }"
               >
                  <el-icon>
@@ -116,10 +116,10 @@
         </div>
         <div class="divider"></div>
         <div v-for="arr in list4" class="info">
         <div v-for="arr in baseInfoList" class="info">
            <div v-for="item in arr" class="infoItem">
               <div class="infoName">{{ item.name }}</div>
               <div class="infoValue">{{ item.value }}</div>
               <div class="infoValue">{{ item.value + (item.unit || '') }}</div>
            </div>
         </div>
      </div>
@@ -147,22 +147,42 @@
import _ from 'lodash'
import BaseControl from '@/components/CurrentTaskDetails/ControlPanel/BaseControl.vue'
import EventBus from '@/event-bus'
import { getPayloadControlApi, ptzControlApi } from '@/api/payload'
import { getPayloadControlApi } from '@/api/payload'
import { directionMap } from '@/const/drc'
const deviceOsdInfo = inject('deviceOsdInfo')
const host = computed(() => deviceOsdInfo?.value?.data?.host || {})
const wsInfo = inject('wsInfo')
const device_osd_host = computed(() => wsInfo?.value?.device_osd?.data?.host || {})
const dock_osd_host = computed(() => wsInfo?.value?.dock_osd?.data?.host || {})
const taskDetails = inject('taskDetails')
const dockSn = inject('dockSn')
const droneSn = inject('droneSn')
const trueAltitude = inject('trueAltitude')
const client_id = inject('client_id')
const isBackDock = inject('isBackDock')
const store = useStore()
const deviceTopicInfo = ref({
   pubTopic: '',
   subTopic: '',
})
const flightController = ref(false)
// 控制对象
let manualControl = {}
const isAutoControl = inject('isAutoControl')
const compassOptions = computed(() => {
   return {
      pitchAngle: pitchAngle.value.angle,
      trueAltitude: trueAltitude.value,
      yawAngle: yawAngle.value.angle,
   }
})
let mqttState = null
const client_id = ref('')
const valueTime = ref('00:00:00')
let timer = null
let totalSeconds = 0
const workspace_id = computed(() => taskDetails?.value?.workspace_id)
const workspace_id = inject('workspace_id')
const list1 = [
   { key: KeyCode.KEY_Q, text: 'Q', icon: RefreshLeft },
   { key: KeyCode.KEY_W, text: 'W', icon: ArrowUp },
@@ -177,31 +197,28 @@
const speed = ref(5)
provide('speed', speed)
const list5 = [
const ptzBtns = [
   { name: '上', key: KeyCode.ARROW_UP, operate: 'up', style: { top: '-70%' } },
   { name: '右', key: KeyCode.ARROW_RIGHT, operate: 'right', style: { left: '70%' } },
   { name: '下', key: KeyCode.ARROW_DOWN, operate: 'down', style: { top: '70%' } },
   { name: '左', key: KeyCode.ARROW_LEFT, operate: 'left', style: { left: '-70%' } },
]
const list4 = computed(() => {
   const { longitude, latitude, height, payloads } = host?.value || {}
   const { gimbal_pitch } = payloads?.[0] || {} //俯仰角度
   return [
      [
         { name: '焦距倍数', value: '0' },
         { name: '俯仰角度', value: pitchAngle.value.angle },
         { name: '横向角度', value: yawAngle.value.angle },
      ],
      [
         { name: '储存', value: '64.5G' },
         { name: '方向', value: pitchAngle.value.direction },
         { name: '方向', value: yawAngle.value.direction },
      ],
   ]
})
const baseInfoList = ref([
   [
      { name: '焦距倍数', value: 0 },
      { name: '俯仰角度', value: 0, unit: '°' },
      { name: '横向角度', value: 0, unit: '°' },
   ],
   [
      { name: '储存', value: 0, unit: 'G' },
      { name: '方向', value: 0 },
      { name: '方向', value: 0 },
   ],
])
const pitchAngle = computed(() => {
   const { longitude, latitude, height, payloads } = host?.value || {}
   const { payloads } = device_osd_host?.value || {}
   const gimbal_pitch = payloads?.[0]?.gimbal_pitch || 0
   let direction = ''
   if (gimbal_pitch > -2 && gimbal_pitch < 2) {
@@ -216,14 +233,12 @@
      direction = '正下'
   }
   return {
      angle: _.round(gimbal_pitch || 0, 1) + '°',
      angle: _.round(gimbal_pitch || 0, 1),
      direction,
   }
})
const yawAngle = computed(() => {
   let { longitude, latitude, height, payloads, attitude_head } = host?.value || {}
   const gimbal_pitch = payloads?.[0]?.gimbal_pitch || 0
   let { payloads, attitude_head } = device_osd_host?.value || {}
   const gimbal_yaw = payloads?.[0]?.gimbal_yaw || 0
   attitude_head = attitude_head || 0
   let yaw = ''
@@ -242,57 +257,39 @@
   if ((yaw > -2 && yaw < 2) || parseInt(attitude_head) === parseInt(gimbal_yaw)) {
      result = attitude_head < 0 ? 180 + (180 + attitude_head) : attitude_head
   }
   let direction = ''
   const roundResult = Math.round(result)
   if (roundResult === 0) {
      direction = '正北'
   } else if (roundResult > 0 && roundResult < 45) {
      direction = '北偏东'
   } else if (roundResult === 45) {
      direction = '东北'
   } else if (roundResult > 45 && roundResult < 90) {
      direction = '北偏东'
   } else if (roundResult === 90) {
      direction = '正东'
   } else if (roundResult > 90 && roundResult < 135) {
      direction = '东偏南'
   } else if (roundResult === 135) {
      direction = '东南'
   } else if (roundResult > 135 && roundResult < 180) {
      direction = '南偏东'
   } else if (roundResult === 180) {
      direction = '正南'
   } else if (roundResult > 180 && roundResult < 225) {
      direction = '南偏西'
   } else if (roundResult === 225) {
      direction = '西南'
   } else if (roundResult > 225 && roundResult < 270) {
      direction = '西偏南'
   } else if (roundResult === 270) {
      direction = '正西'
   } else if (roundResult > 270 && roundResult < 315) {
      direction = '西偏北'
   } else if (roundResult === 315) {
      direction = '西北'
   } else if (roundResult > 315 && roundResult < 360) {
      direction = '北偏西'
   } else if (roundResult === 360) {
      direction = '正北'
   let direction = ''
   for (const item of directionMap) {
      if (roundResult >= item.min && roundResult <= item.max) {
         direction = item.value
         break
      }
   }
   return {
      angle: _.round(result, 1) + '°',
      angle: _.round(result, 1),
      direction,
   }
})
const deviceTopicInfo = ref({
   pubTopic: '',
   subTopic: '',
})
const flightController = ref(false)
// 控制对象
let manualControl = {}
const isAutoControl = inject('isAutoControl')
const baseInfoChange = () => {
   const newUsedStorage = dock_osd_host.value?.storage?.used
   const zoom_factor = device_osd_host.value?.cameras?.[0]?.zoom_factor || 0
   const usedStorageGB = _.round(newUsedStorage / 1024 / 1024, 2)
   baseInfoList.value[0][0].value = _.round(zoom_factor, 0)
   baseInfoList.value[0][1].value = pitchAngle.value.angle
   baseInfoList.value[0][2].value = yawAngle.value.angle
   if (newUsedStorage !== undefined) baseInfoList.value[1][0].value = usedStorageGB
   baseInfoList.value[1][1].value = pitchAngle.value.direction
   baseInfoList.value[1][2].value = yawAngle.value.direction
}
watch(
   wsInfo,
   () => {
      baseInfoChange()
   },
   { immediate: true, deep: true }
)
const timeStart = () => {
   stop() // 避免重复启动
@@ -328,9 +325,10 @@
function cancelControl() {
   exitController({ client_id: client_id.value, dock_sn: dockSn.value })
      .then(res => {
         flightController.value = false
         deviceTopicInfo.value.subTopic = ''
         deviceTopicInfo.value.pubTopic = ''
         flightController.value = false
         isAutoControl.value = true
         ElMessage.success('退出飞行控制成功')
      })
      .catch(e => {})
@@ -362,18 +360,22 @@
   })
}
// 返航
function onBackDock() {
   returnHome(dockSn?.value).then(res => {
      ElMessage.success('返航操作成功')
   })
async function onBackDock() {
   await returnHome(dockSn?.value)
   ElMessage.success('返航操作成功')
   isBackDock.value = true
   isAutoControl.value = true
}
// 取消返航
function cancelBackDock() {
   returnHomeCancel(dockSn?.value).then(res => {
      ElMessage.success('取消返航成功')
   })
async function cancelBackDock() {
   await returnHomeCancel({ dock_sn: dockSn?.value, client_id: client_id.value })
   ElMessage.success('取消返航成功')
   isBackDock.value = false
   isAutoControl.value = false
}
// 创建mqtt连接
@@ -398,11 +400,7 @@
// 返航或取消返航
const returnOrCancelReturn = () => {
   if (deviceOsdInfo.value?.data?.host?.mode_code === 9) {
      cancelBackDock()
   } else {
      onBackDock()
   }
   isBackDock.value ? cancelBackDock() : onBackDock()
}
// useManualControl里面用的参数
@@ -412,10 +410,9 @@
   speed: speed.value,
}))
watch(
   () => workspace_id.value,
watch(workspace_id,
   async () => {
      if (workspace_id.value) {
      if (workspace_id.value && mqttState === null && client_id.value === '') {
         await createConnect()
         // 使用控制
         manualControl = useManualControl(mqttState, deviceTopicInfo.value, flightController, paramsRef)
@@ -471,7 +468,7 @@
   right: 0;
   width: 1400px;
   height: 217px;
   background: linear-gradient(196deg, rgba(23, 23, 23, 0.11) 0%, rgba(6, 6, 6, 0.11) 100%);
   background: rgba(31, 31, 31, 0.15);
   backdrop-filter: blur(5px);
   border-radius: 40px 0px 40px 40px;
   display: flex;
@@ -525,10 +522,11 @@
         box-shadow: 2px 4px 6px 0px rgba(0, 13, 26, 0.42);
         border-radius: 8px 8px 8px 8px;
         text-align: center;
         padding: 5px 0;
         padding: 10px 0;
         .btnIcon {
            font-size: 20px;
            cursor: pointer;
         }
      }
   }
@@ -637,7 +635,7 @@
      .divider {
         position: absolute;
         transform: translateX(90px);
         transform: translateX(95px);
         width: 0;
         height: 137px;
         border: 1px solid rgba(255, 255, 255, 0.07);