<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('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('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>
|
</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 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 = 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') {
|
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)
|
let seq = ref(0)
|
// 字母按键
|
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})
|
}
|
|
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;
|
}
|
}
|
}
|
}
|
</style>
|