石超 2025-06-23 09:17:26 +08:00
commit ab25eb26b3
3 changed files with 135 additions and 14 deletions

View File

@ -0,0 +1,87 @@
<template>
<div style="margin-bottom: 10px;">
<div style="display: flex;align-items: center;">
<span style="margin-right: 10px;">远程调试</span>
<a-switch :checked="props.deviceInfoList[props.controlSN].mode_code == 2" @change="openDebug"/>
</div>
</div>
<div style="margin-bottom: 10px;">机场控制</div>
<div style="margin-bottom: 20px;">
<div style="width: 252px;height: 58px;background-color: #f7f9fa;padding-left: 8px;padding-right: 8px;display: flex;justify-content: space-between;">
<div style="display: flex;align-items: center;">
<div style="width: 21px;height: 21px;background-color: red;margin-right: 8px;"></div>
<div>
<div style="line-height: 22px;">{{getCoverState(props.deviceInfoList[props.controlSN].cover_state)}}</div>
<div style="line-height: 22px;">舱盖</div>
</div>
</div>
<div style="display: flex;align-items: center;">
<a-button style="width: 70px;height: 30px;" @click="openCoverState" :disabled="props.deviceInfoList[props.controlSN].mode_code != 2">{{props.deviceInfoList[props.controlSN].cover_state == 0? '打开': '关闭'}}</a-button>
</div>
</div>
</div>
<div style="margin-bottom: 10px;">飞行器控制</div>
<div>
<div style="width: 252px;height: 58px;background-color: #f7f9fa;padding-left: 8px;padding-right: 8px;display: flex;justify-content: space-between;">
<div style="display: flex;align-items: center;">
<div style="width: 21px;height: 21px;background-color: red;margin-right: 8px;"></div>
<div>
<div style="line-height: 22px;">{{props.deviceInfoList[props.controlSN].sub_device.device_online_status == 0? "关机": "开机"}}</div>
<div style="line-height: 22px;">飞行器电源</div>
</div>
</div>
<div style="display: flex;align-items: center;">
<a-button style="width: 70px;height: 30px;" @click="openDeviceOnline" :disabled="props.deviceInfoList[props.controlSN].mode_code != 2">{{props.deviceInfoList[props.controlSN].sub_device.device_online_status == 0? '开机': '关机'}}</a-button>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { defineProps } from "vue"
import { clientPublish } from '@/utils/mqtt'
import { buildGUID } from '@/utils/uuid';
const props = defineProps(['deviceInfoList', 'controlSN'])
const openDebug = () => {
let publishUrl = `thing/product/${props.controlSN}/services`
let params = {
method: props.deviceInfoList[props.controlSN].mode_code == 2? 'debug_mode_close': 'debug_mode_open',
data: null,
};
clientPublish(publishUrl,params)
}
const getCoverState = (value) => {
const options = {
0: '关闭',
1: '打开',
2: '半开',
3: '舱盖状态异常'
}
return options[value]
}
const openCoverState = () => {
let publishUrl = `thing/product/${props.controlSN}/services`
let params = {
method: props.deviceInfoList[props.controlSN].cover_state == 0? 'cover_open': 'cover_close',
bid: buildGUID(),
tid: buildGUID(),
timestamp: new Date().getTime(),
data: null,
};
clientPublish(publishUrl,params)
}
const openDeviceOnline = () => {
let publishUrl = `thing/product/${props.controlSN}/services`
let params = {
method: props.deviceInfoList[props.controlSN].sub_device.device_online_status == 0? 'drone_open': 'drone_close',
bid: buildGUID(),
tid: buildGUID(),
timestamp: new Date().getTime(),
data: null,
};
clientPublish(publishUrl,params)
}
</script>
<style lang="scss" scoped></style>

View File

@ -29,6 +29,7 @@
{
icon: 'carbon:calendar-tools',
onClick: () => {
openDeviceControl(record)
},
},
]"
@ -39,8 +40,8 @@
<a-drawer class="feedback-drawer" v-model:open="feedbackDrawer" width="80%" :closable="false">
<FeedbackDrawer />
</a-drawer>
<a-drawer class="feedback-drawer" v-model:open="feedbackDrawer" width="45%" :closable="false">
<FeedbackDrawer />
<a-drawer class="feedback-drawer" title="设备运维" v-model:open="deviceControl" width="45%" :closable="false">
<DeviceControl :deviceInfoList="deviceInfoList" :controlSN="controlSN"/>
</a-drawer>
<a-modal v-model:open="deviceBindingModal" title="设备绑定码" @ok="handleOk">
<DeviceBindModal />
@ -50,12 +51,14 @@
<script setup lang="ts">
import { ref, defineProps, onMounted, watch, nextTick } from "vue"
import { BasicTable, useTable, TableAction } from '@/components/Table';
import { columns, searchFormSchema } from './utils'
import { columns, searchFormSchema, servicesReplyMessage } from './utils'
import FeedbackDrawer from './FeedbackDrawer/index.vue'
import DeviceBindModal from './DeviceBindModal/index.vue'
import DeviceControl from './DeviceControl/index.vue'
import { GetDataList } from '@/api/demo/device'
import { getClient, clientSubscribe } from '@/utils/mqtt'
import dayjs from "dayjs";
import { message } from "ant-design-vue";
const props = defineProps(['projectList','connected'])
watch(() => props.projectList, () => {
@ -68,18 +71,31 @@ watch(() => props.projectList, () => {
}
})
watch(() => props.connected, () => {
getClient().on('message', (topic, message) => {
const rs = JSON.parse(message)
console.log('rs',rs)
console.log('getDataSource',getDataSource())
let list = getDataSource()
let sn = rs.gateway
for(let i = 0; i < list.length; i++){
if(list[i].sn == sn){
list[i] = {...list[i],...rs.data}
getClient().on('message', (topic, msg) => {
console.log('topic',topic)
if (topic.endsWith("osd")) {
const rs = JSON.parse(msg)
let list = getDataSource()
let sn = rs.gateway
for(let i = 0; i < list.length; i++){
if(list[i].sn == sn){
list[i] = {...list[i],...rs.data}
}
}
setTableData(list)
const origin = deviceInfoList.value[sn] || {}
const patch = rs.data || {}
for (const key in patch) {
origin[key] = patch[key]
}
deviceInfoList.value[sn] = origin
}else if(topic.endsWith("services_reply")){
const rs = JSON.parse(msg)
console.log('services_reply','rs',rs)
if(rs.data?.output?.status){
message.info(servicesReplyMessage[rs.data.output.status])
}
}
setTableData(list)
});
})
@ -87,6 +103,8 @@ const feedbackDrawer = ref(false)
const deviceBindingModal = ref(false)
const afterFetch = ref(false)
const deviceControl = ref(false)
const deviceInfoList = ref({})
const controlSN = ref()
watch(() => [afterFetch.value, props.connected], ([newAfterFetch, newConnected], [oldAfterFetch, oldConnected]) => {
console.log(newAfterFetch,newConnected)
console.log(getDataSource())
@ -95,7 +113,9 @@ watch(() => [afterFetch.value, props.connected], ([newAfterFetch, newConnected],
console.log(getDataSource())
getDataSource().forEach(item => {
let topicUrl = `thing/product/${item.sn}/osd`;
let servicesReplyUrl = `thing/product/${item.sn}/services_reply`
clientSubscribe(topicUrl);
clientSubscribe(servicesReplyUrl);
})
})
}
@ -165,6 +185,10 @@ const workStatus = (record) => {
return ''
}
}
const openDeviceControl = (record) => {
controlSN.value = record.sn
deviceControl.value = true
}
</script>
<style lang="scss" scoped>

View File

@ -100,4 +100,14 @@ export const searchFormSchema: FormSchema[] = [
component: 'Input',
colProps: { span: 6 },
},
];
];
export const servicesReplyMessage = {
'canceled': '取消或终止',
'failed': '失败',
'in_progress': '执行中',
'ok': '执行成功',
'paused': '暂停',
'rejected': '拒绝',
'sent': '已下发',
'timeout': '超时',
}