forked from drone/command-center-dashboard

罗广辉
2025-04-18 61e6956be147e1e84e7104f16dd47e9f87f20dfd
src/components/CurrentTaskDetails/ControlPanel/ControlPanel.vue
@@ -53,12 +53,12 @@
                  <el-icon class="btnIcon">
                     <Top />
                  </el-icon>
                  <div class="btn" @mousedown="onMouseDown(KeyCode.ARROW_UP)" @mouseup="onMouseUp">C</div>
                  <div class="btn" @mousedown="onMouseDown(KeyCode.KEY_C)" @mouseup="onMouseUp">C</div>
               </div>
            </div>
            <div class="btnGroupT">
               <div class="btnItem">
                  <div class="btn" @mousedown="onMouseDown(KeyCode.ARROW_DOWN)" @mouseup="onMouseUp">Z</div>
                  <div class="btn" @mousedown="onMouseDown(KeyCode.KEY_Z)" @mouseup="onMouseUp">Z</div>
                  <el-icon class="btnIcon">
                     <Bottom />
                  </el-icon>
@@ -66,7 +66,7 @@
            </div>
         </div>
      </div>
      <!--     指南针-->
      <div class="compass">
         <ControlComPass />
      </div>
@@ -83,7 +83,13 @@
         </div>
         <div class="ptzControlBtnBox">
            <div class="ptzControlBtn b-r">
               <div v-for="(item, index) in list5" :style="item.style" class="ptzControlItem"></div>
               <div
                  v-for="(item, index) in list5"
                  :style="item.style"
                  class="ptzControlItem"
                  @mousedown="onMouseDown(item.key)"
                  @mouseup="onMouseUp"
               ></div>
               <div
                  class="ptzControlItemIcon"
@@ -120,9 +126,9 @@
   </div>
</template>
<script setup>
import ControlComPass from '../ControlComPass/ControlComPass.vue'
import ControlComPass from '@/components/CurrentTaskDetails/ControlPanel/ControlComPass/ControlComPass.vue'
import { KeyCode, useManualControl } from '@/hooks/controlDrone/useManualControl'
import { droneController, exitController, postDrc, postDrcExit, returnHome, returnHomeCancel } from '@/api/drc'
import { droneController, exitController, postDrc, returnHome, returnHomeCancel } from '@/api/drc'
import { ElMessage } from 'element-plus'
import { useStore } from 'vuex'
import { UranusMqtt } from '@/mqtt'
@@ -133,23 +139,30 @@
   ArrowUp,
   Bottom,
   CaretRight,
   CaretTop,
   Minus,
   Plus,
   RefreshLeft,
   RefreshRight,
} from '@element-plus/icons-vue'
import controlCenterImg from '@/assets/images/taskManagement/taskIntermediateContent/controlCenter.png'
import _ from 'lodash'
import BaseControl from '@/components/CurrentTaskDetails/ControlPanel/BaseControl.vue'
import EventBus from '@/event-bus'
import dayjs from 'dayjs'
import { getPayloadControlApi, ptzControlApi } from '@/api/payload'
const deviceOsdInfo = inject('deviceOsdInfo')
const host = computed(() => deviceOsdInfo?.value?.data?.host || {})
const taskDetails = inject('taskDetails')
const dockSn = inject('dockSn')
const droneSn = inject('droneSn')
const store = useStore()
let mqttState = null
const client_id = ref('')
const valueTime = ref('00:00:00')
let timer = null
let totalSeconds = 0
const workspace_id = computed(() => taskDetails?.value?.workspace_id)
const dock_sn = computed(() => taskDetails.value.device_sns[0])
const list1 = [
   { key: KeyCode.KEY_Q, text: 'Q', icon: RefreshLeft },
   { key: KeyCode.KEY_W, text: 'W', icon: ArrowUp },
@@ -162,42 +175,123 @@
]
const speed = ref(5)
provide('speed', speed)
const list5 = [
   { name: '上', style: { top: '-70%' }, imgStyle: { top: '20%', left: '50%' } },
   { name: '右', style: { left: '70%' }, imgStyle: { right: '0', top: '50%' } },
   { name: '下', style: { top: '70%' }, imgStyle: { bottom: '0', left: '50%' } },
   { name: '左', style: { left: '-70%' }, imgStyle: { left: '20%', top: '50%' } },
   { 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 = [
   [
      { name: '焦距倍数', value: '0' },
      { name: '俯仰角度', value: '0.0°' },
      { name: '横向角度', value: '0.0°' },
   ],
   [
      { name: '储存', value: '64.5G' },
      { name: '方向', value: '正北' },
      { name: '方向', value: '正北' },
   ],
]
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 pitchAngle = computed(() => {
   const { longitude, latitude, height, payloads } = host?.value || {}
   const gimbal_pitch = payloads?.[0]?.gimbal_pitch || 0
   let direction = ''
   if (gimbal_pitch > -2 && gimbal_pitch < 2) {
      direction = '正前'
   } else if (gimbal_pitch >= 2 && gimbal_pitch < 90) {
      direction = '斜上'
   } else if (gimbal_pitch === 90) {
      direction = '正上'
   } else if (gimbal_pitch <= -2 && gimbal_pitch > -90) {
      direction = '斜下'
   } else if (gimbal_pitch === -90 || gimbal_pitch < -90) {
      direction = '正下'
   }
   return {
      angle: _.round(gimbal_pitch || 0, 1) + '°',
      direction,
   }
})
let mqttState = null
const client_id = ref('')
const valueTime = ref('00:00:00')
let timer = null
let totalSeconds = 0
const yawAngle = computed(() => {
   let { longitude, latitude, height, payloads, attitude_head } = host?.value || {}
   const gimbal_pitch = payloads?.[0]?.gimbal_pitch || 0
   const gimbal_yaw = payloads?.[0]?.gimbal_yaw || 0
   attitude_head = attitude_head || 0
   let yaw = ''
   if (gimbal_yaw > 180) {
      yaw = gimbal_yaw
   } else {
      yaw = gimbal_yaw - attitude_head
   }
   let result = 0
   if (yaw < 0) {
      result = yaw + 360
   }
   if (yaw > 0) {
      result = yaw
   }
   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 = '正北'
   }
   return {
      angle: _.round(result, 1) + '°',
      direction,
   }
})
const deviceTopicInfo = ref({
   sn: deviceOsdInfo.value?.data?.sn,
   pubTopic: '',
   subTopic: '',
})
const flightController = ref(false)
// 控制对象
let manualControl = {}
const sn = computed(() => deviceOsdInfo?.value?.data?.sn)
const isAutoControl = inject('isAutoControl')
const timeStart = () => {
@@ -222,7 +316,7 @@
// 按下操作
function onMouseDown(type) {
   manualControl?.handleKeyup(type, { sn: sn.value, speed: speed.value })
   manualControl?.handleKeyup(type)
}
// 弹起操作
@@ -232,7 +326,7 @@
// 取消手动控制
function cancelControl() {
   exitController({ client_id: client_id.value, dock_sn: dock_sn.value })
   exitController({ client_id: client_id.value, dock_sn: dockSn.value })
      .then(res => {
         flightController.value = false
         deviceTopicInfo.value.subTopic = ''
@@ -242,11 +336,18 @@
      .catch(e => {})
}
// 获得有效载荷控制
function getPayloadControl() {
   getPayloadControlApi({ sn: dockSn.value }).then(res => {
      ElMessage.success('成功获得有效载荷控制')
   })
}
// 手动控制
function control() {
   if (!client_id.value) return ElMessage.error('无人机不在空中,不能进入指挥飞行模式。')
   if (!dock_sn.value) return ElMessage.error('系统错误,未获取到dock_sn')
   droneController({ client_id: client_id.value, dock_sn: dock_sn.value }).then(res => {
   if (!dockSn.value) return ElMessage.error('系统错误,未获取到dock_sn')
   droneController({ client_id: client_id.value, dock_sn: dockSn.value }).then(res => {
      flightController.value = true
      const { data } = res.data
      if (data.sub && data.sub?.length > 0) {
@@ -256,20 +357,21 @@
         deviceTopicInfo.value.pubTopic = data.pub[0]
      }
      ElMessage.success('控制成功')
      getPayloadControl()
      isAutoControl.value = false
   })
}
// 返航
function onBackDock() {
   returnHome(dock_sn.value).then(res => {
   returnHome(dockSn?.value).then(res => {
      ElMessage.success('返航操作成功')
   })
}
// 取消返航
function cancelBackDock() {
   returnHomeCancel({ client_id: this.clientId, dock_sn: this.sn }).then(res => {
   returnHomeCancel(dockSn?.value).then(res => {
      ElMessage.success('取消返航成功')
   })
}
@@ -303,13 +405,20 @@
   }
}
// useManualControl里面用的参数
const paramsRef = computed(() => ({
   droneSn: droneSn.value,
   dockSn: dockSn.value,
   speed: speed.value,
}))
watch(
   () => workspace_id.value,
   async () => {
      if (workspace_id.value) {
         await createConnect()
         // 使用控制
         manualControl = useManualControl(mqttState, deviceTopicInfo.value, flightController)
         manualControl = useManualControl(mqttState, deviceTopicInfo.value, flightController, paramsRef)
      }
   }
)
@@ -321,6 +430,7 @@
   EventBus.on('controlPanel-onMouseDown', onMouseDown)
   EventBus.on('controlPanel-timeStart', timeStart)
   EventBus.on('controlPanel-timeStop', timeStop)
   EventBus.on('controlPanel-getPayloadControl', getPayloadControl)
})
onBeforeUnmount(() => {
@@ -330,6 +440,7 @@
   EventBus.off('controlPanel-onMouseDown', onMouseDown)
   EventBus.off('controlPanel-timeStart', timeStart)
   EventBus.off('controlPanel-timeStop', timeStop)
   EventBus.off('controlPanel-getPayloadControl', getPayloadControl)
   destroyConnect()
})
</script>
@@ -358,7 +469,7 @@
   position: absolute;
   bottom: 0;
   right: 0;
   width: 1540px;
   width: 1400px;
   height: 217px;
   background: linear-gradient(196deg, rgba(23, 23, 23, 0.11) 0%, rgba(6, 6, 6, 0.11) 100%);
   backdrop-filter: blur(5px);
@@ -371,7 +482,7 @@
   pointer-events: all;
   .direction {
      width: 476px;
      width: 400px;
      height: 188px;
      background: rgb(0, 0, 0, 0.4); /* 半透明背景 */
      border-radius: 40px 40px 40px 40px;
@@ -386,7 +497,7 @@
         .btnGroupT,
         .btnGroupB {
            width: 238px;
            width: 180px;
            height: 73px;
         }
      }
@@ -423,7 +534,7 @@
   }
   .ptzControlBox {
      width: 406px;
      width: 386px;
      height: 188px;
      background: rgb(0, 0, 0, 0.4); /* 半透明背景 */
      border-radius: 40px 40px 40px 40px;
@@ -536,7 +647,7 @@
         display: flex;
         flex-direction: column;
         gap: 7px 0;
         width: 70px;
         width: 60px;
         .infoName {
            height: 25px;
@@ -574,8 +685,7 @@
      display: flex;
      align-items: center;
      text-align: center;
      justify-content: center;
      gap: 0 45px;
      justify-content: space-evenly;
      .btnItem {
         .btnIcon {