| | |
| | | <div class="pointControl"> |
| | | <div class="direction"> |
| | | <div class="blackBg directionUp"> |
| | | <div v-for="item in upperRowButton" :key="item.text"> |
| | | <el-icon :class="item.icon"></el-icon> |
| | | <div |
| | | :class="{ hotkeyBtn: true, activeKey: currentKey === item.text }" |
| | | @click="() => mousedown(item.text)" |
| | | v-hold="() => mousedown(item.text)" |
| | | > |
| | | {{ item.text }} |
| | | </div> |
| | | </div> |
| | | <el-button type="primary" @click="control">控制</el-button> |
| | | <el-button type="primary" @click="cancelControl">取消控制</el-button> |
| | | <el-button type="primary" ghost @mousedown="onMouseDown(KeyCode.KEY_Q)" @mouseup="onMouseUp">q</el-button> |
| | | </div> |
| | | <div class="blackBg directionDown"> |
| | | <div v-for="item in lowerRowButton" :key="item.text"> |
| | | <el-icon :class="item.icon"></el-icon> |
| | | <div |
| | | :class="{ hotkeyBtn: true, activeKey: currentKey === item.text }" |
| | | @click="() => mousedown(item.text)" |
| | | v-hold="() => mousedown(item.text)" |
| | | > |
| | | {{ item.text }} |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="blackBg directionDown"></div> |
| | | </div> |
| | | |
| | | <ControlComPass /> |
| | | |
| | | <div class="height-direction"> |
| | | <div class="blackBg height-direction-btn"> |
| | | <el-icon class="el-icon-top" /> |
| | | <div :class="{ hotkeyBtn: true, activeKey: currentKey === 'C' }" v-hold="() => mousedown('C')">C</div> |
| | | </div> |
| | | <div class="blackBg height-direction-btn"> |
| | | <div :class="{ hotkeyBtn: true, activeKey: currentKey === 'Z' }" v-hold="() => mousedown('Z')">Z</div> |
| | | <el-icon class="el-icon-bottom" /> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | <script setup> |
| | | import vHold from '@/directive/hold' |
| | | import ControlComPass from './ControlComPass/ControlComPass.vue' |
| | | import { |
| | | KeyCode, |
| | | useManualControl, |
| | | } from '@/hooks/controlDrone/useManualControl' |
| | | import { useMqtt } from '@/hooks/controlDrone/useMqtt' |
| | | import { useConnectDrone } from '@/hooks/controlDrone/useConnectDrone' |
| | | import { droneController, exitController, postDrcExit } from '@/api/drc' |
| | | import { ElMessage } from 'element-plus' |
| | | import { useStore } from 'vuex' |
| | | |
| | | const lowerRowButton = [ |
| | | { icon: 'el-icon-arrow-left', text: 'A' }, |
| | | { icon: 'el-icon-arrow-down', text: 'S' }, |
| | | { icon: 'el-icon-arrow-right', text: 'D' }, |
| | | ] |
| | | const upperRowButton = [ |
| | | { icon: 'el-icon-refresh-left', text: 'Q' }, |
| | | { icon: 'el-icon-arrow-up', text: 'W' }, |
| | | { icon: 'el-icon-refresh-right', text: 'E' }, |
| | | ] |
| | | let currentKey = ref('') |
| | | let keyReset = null |
| | | let visible = false |
| | | const deviceOsdInfo = inject('deviceOsdInfo') |
| | | const taskDetails = inject('taskDetails') |
| | | |
| | | function mousedown(key) { |
| | | if (key === 'Q') { |
| | | console.log(6666666666) |
| | | } |
| | | } |
| | | |
| | | function handleKeydown(e) { |
| | | currentKey.value = e.key.toUpperCase() |
| | | mousedown(e.key.toUpperCase()) |
| | | } |
| | | |
| | | function handleKeyup() { |
| | | currentKey.value = null |
| | | } |
| | | |
| | | onMounted(() => { |
| | | window.addEventListener('keydown', handleKeydown) |
| | | window.addEventListener('keyup', handleKeyup) |
| | | const deviceTopicInfo = ref({ |
| | | sn: deviceOsdInfo.value?.data?.sn, |
| | | pubTopic: '', |
| | | subTopic: '', |
| | | }) |
| | | onBeforeUnmount(() => { |
| | | window.removeEventListener('keydown', handleKeydown) |
| | | window.removeEventListener('keyup', handleKeyup) |
| | | }) |
| | | const flightController = ref(false) |
| | | console.log('控制面板') |
| | | |
| | | // 连接无人机mqtt 成功获得有效控制 |
| | | useConnectDrone() |
| | | |
| | | // 订阅消息 |
| | | useMqtt(deviceTopicInfo.value) |
| | | |
| | | // 使用手动控制 |
| | | const { handleKeyup, handleEmergencyStop, resetControlState } = useManualControl( |
| | | deviceTopicInfo.value, |
| | | flightController |
| | | ) |
| | | |
| | | function onMouseDown(type) { |
| | | console.log('anxia') |
| | | handleKeyup(type) |
| | | } |
| | | |
| | | const store = useStore() |
| | | const clientId = computed(() => store.state.common.clientId) |
| | | const dock_sn = computed(() => taskDetails.value.device_sns[0]) |
| | | |
| | | function cancelControl() { |
| | | exitController({ client_id: clientId.value, dock_sn:dock_sn.value }) |
| | | .then(res => { |
| | | flightController.value = false |
| | | deviceTopicInfo.value.subTopic = '' |
| | | deviceTopicInfo.value.pubTopic = '' |
| | | ElMessage.success('退出飞行控制成功') |
| | | }) |
| | | .catch(e => {}) |
| | | } |
| | | |
| | | // 控制 |
| | | function control() { |
| | | if (!clientId.value) return ElMessage.error('无人机不在空中,不能进入指挥飞行模式。') |
| | | if (!dock_sn.value) return ElMessage.error('系统错误,未获取到dock_sn') |
| | | droneController({ client_id: clientId.value, dock_sn:dock_sn.value }).then(res => { |
| | | flightController.value = true |
| | | const { data } = res.data |
| | | if (data.sub && data.sub?.length > 0) { |
| | | deviceTopicInfo.value.subTopic = data.sub[0] |
| | | } |
| | | if (data.pub && data.pub?.length > 0) { |
| | | deviceTopicInfo.value.pubTopic = data.pub[0] |
| | | } |
| | | ElMessage.success('控制成功') |
| | | }) |
| | | } |
| | | |
| | | function onMouseUp() { |
| | | console.log('弹起') |
| | | resetControlState() |
| | | } |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | |
| | | align-items: center; |
| | | } |
| | | |
| | | //变量 |
| | | $FSColor: #00ee8b; |
| | | |
| | | .hotkeyBtn { |
| | | background: #3c3c3c; |
| | | border-radius: 2px; |
| | | width: 24px; |
| | | height: 24px; |
| | | font-size: 14px; |
| | | line-height: 24px; |
| | | text-align: center; |
| | | color: #fff; |
| | | cursor: pointer; |
| | | -webkit-user-select: none; |
| | | user-select: none; |
| | | |
| | | &:hover { |
| | | background: $FSColor; |
| | | } |
| | | } |
| | | |
| | | .pointControl { |
| | | position: absolute; |
| | | bottom: 0; |
| | | right: 0; |
| | | width: 1540px; |
| | | height: 217px; |
| | | background: rgba(255, 255, 255, 0.3); |
| | | border-radius: 40px 0px 40px 40px; |
| | | display: flex; |
| | | justify-content: center; |
| | | align-items: flex-end; |
| | | color: white; |
| | | gap: 0 10px; |
| | | pointer-events: all; |
| | | width: 100%; |
| | | height: 200px; |
| | | |
| | | .activeKey { |
| | | background: $FSColor; |
| | | } |
| | | |
| | | .blackBg { |
| | | background: rgba(0, 0, 0, 0.65); |
| | | padding: 5px 5px; |
| | | border-radius: 5px; |
| | | } |
| | | |
| | | .direction { |
| | | display: flex; |
| | | flex-direction: column; |
| | | width: 100px; |
| | | |
| | | .speedBox { |
| | | color: $FSColor; |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | margin: 5px 0; |
| | | gap: 0 5px; |
| | | } |
| | | |
| | | .editBox { |
| | | display: flex; |
| | | justify-content: end; |
| | | gap: 0 5px; |
| | | margin-bottom: 5px; |
| | | |
| | | .current-point { |
| | | font-size: 20px; |
| | | display: flex; |
| | | align-items: center; |
| | | color: $FSColor; |
| | | } |
| | | |
| | | .editPointBtn { |
| | | &:hover { |
| | | cursor: pointer; |
| | | background: $FSColor; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .directionUp, |
| | | .directionDown { |
| | | display: flex; |
| | | justify-content: space-around; |
| | | text-align: center; |
| | | height: 55px; |
| | | |
| | | > div { |
| | | display: flex; |
| | | flex-direction: column; |
| | | justify-content: space-between; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .height-direction { |
| | | width: 100px; |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: end; |
| | | gap: 5px 0; |
| | | |
| | | .height-direction-btn { |
| | | width: 35px; |
| | | height: 55px; |
| | | text-align: center; |
| | | display: flex; |
| | | flex-direction: column; |
| | | justify-content: space-between; |
| | | } |
| | | } |
| | | } |
| | | </style> |