You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
178 lines
5.3 KiB
178 lines
5.3 KiB
<template>
|
|
<section class="operation-page">
|
|
<header class="operation-page-header">
|
|
<div>
|
|
<h1>设备操作记录</h1>
|
|
<span>你对机巢和无人机下发的控制指令</span>
|
|
</div>
|
|
<t-button shape="square" variant="outline" title="刷新" @click="load"><svg><use href="#i-refresh" /></svg></t-button>
|
|
</header>
|
|
|
|
<div class="business-workspace">
|
|
<div class="asset-toolbar">
|
|
<div class="asset-search">
|
|
<t-input v-model="keyword" clearable placeholder="搜索机巢 / 指令 / 无人机" @keyup.enter="reload" @clear="reload">
|
|
<template #prefix-icon><t-icon name="search" /></template>
|
|
</t-input>
|
|
</div>
|
|
<div class="toolbar-group">
|
|
<t-select
|
|
v-model="statusFilter"
|
|
:options="statusFilterOptions"
|
|
placeholder="全部状态"
|
|
style="width: 140px"
|
|
@change="reload"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="asset-table-wrap">
|
|
<t-table
|
|
row-key="id"
|
|
:data="list"
|
|
:columns="columns"
|
|
empty="暂无设备操作记录"
|
|
>
|
|
<template #command="{ row }">
|
|
<strong>{{ row.commandName }}</strong><small>{{ row.commandType }}</small>
|
|
</template>
|
|
<template #status="{ row }">
|
|
<span class="table-status" :class="row.statusClass"><i></i>{{ row.statusName }}</span>
|
|
</template>
|
|
</t-table>
|
|
</div>
|
|
|
|
<div class="table-footer">
|
|
<t-pagination
|
|
v-model:current="pageNum"
|
|
:total="total"
|
|
:page-size="pageSize"
|
|
@current-change="load"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { onMounted, ref } from 'vue'
|
|
import { useUiStore } from '@/stores/modules/uiStore'
|
|
import request from '@/utils/http'
|
|
import * as urls from '@/config/urls'
|
|
|
|
const ui = useUiStore()
|
|
const list = ref([])
|
|
const total = ref(0)
|
|
const pageNum = ref(1)
|
|
const pageSize = ref(20)
|
|
const keyword = ref('')
|
|
const statusFilter = ref('')
|
|
|
|
const statusFilterOptions = [
|
|
{ label: '全部状态', value: '' },
|
|
{ label: '已下发', value: 'sent' },
|
|
{ label: '已确认', value: 'acked' },
|
|
{ label: '已超时', value: 'timeout' },
|
|
{ label: '执行失败', value: 'terminal' }
|
|
]
|
|
|
|
const columns = [
|
|
{ colKey: 'dockId', title: '目标机巢', width: '18%' },
|
|
{ colKey: 'command', title: '控制指令', width: '20%' },
|
|
{ colKey: 'droneSn', title: '目标飞机', width: '18%' },
|
|
{ colKey: 'status', title: '执行状态', width: '12%' },
|
|
{ colKey: 'result', title: '应答结果', width: '14%' },
|
|
{ colKey: 'createdAt', title: '下发时间', width: '18%' }
|
|
]
|
|
|
|
const COMMAND_NAMES = {
|
|
'dock.open': '打开舱门',
|
|
'dock.close': '关闭舱门',
|
|
'dock.reset': '整机复位',
|
|
'dock.prepare_takeoff': '起飞准备',
|
|
'dock.complete_takeoff': '起飞准备完成',
|
|
'dock.prepare_landing': '降落准备',
|
|
'dock.complete_landing': '降落准备完成',
|
|
'dock.charge_start': '开始充电',
|
|
'dock.drone_power_on': '无人机开机',
|
|
'dock.drone_power_off': '无人机关机',
|
|
'dock.reboot': '远程重启',
|
|
'dock.clear_alarm': '清除设备告警',
|
|
'dock.emergency_stop': '紧急停止',
|
|
'drone.takeoff': '无人机起飞',
|
|
'drone.land': '无人机降落',
|
|
'drone.return': '一键返航',
|
|
'drone.mission_upload': '上传任务',
|
|
'drone.mission_start': '开始任务',
|
|
'drone.mission_pause': '暂停任务',
|
|
'drone.mission_resume': '恢复任务',
|
|
'drone.mission_cancel': '取消任务',
|
|
'workflow.start_task': '执行任务',
|
|
'workflow.one_key_takeoff': '一键起飞',
|
|
'workflow.one_key_land': '一键降落',
|
|
'video.start_stream': '开始直播',
|
|
'video.stop_stream': '停止直播'
|
|
}
|
|
|
|
const STATUS_NAMES = {
|
|
sent: { name: '已下发', cls: 'processing' },
|
|
acked: { name: '已确认', cls: 'online' },
|
|
timeout: { name: '已超时', cls: 'offline' },
|
|
terminal: { name: '执行失败', cls: 'offline' }
|
|
}
|
|
|
|
function fmtTime(t) {
|
|
if (!t) return '--'
|
|
const d = new Date(t)
|
|
if (Number.isNaN(d.getTime())) return '--'
|
|
return d.toLocaleString('zh-CN', { hour12: false })
|
|
}
|
|
|
|
async function load() {
|
|
try {
|
|
const params = { pageNum: pageNum.value, pageSize: pageSize.value }
|
|
if (keyword.value) params.keyword = keyword.value
|
|
if (statusFilter.value) params.status = statusFilter.value
|
|
const page = await request.get(urls.COMMANDS, { params })
|
|
total.value = page?.total || 0
|
|
list.value = (page?.records || []).map((c) => {
|
|
const status = STATUS_NAMES[c.status] || { name: c.status || '--', cls: 'offline' }
|
|
return {
|
|
id: String(c.id),
|
|
dockId: c.dockId || '--',
|
|
commandType: c.commandType || '--',
|
|
commandName: COMMAND_NAMES[c.commandType] || c.commandType || '--',
|
|
droneSn: c.droneSn || '机巢本体',
|
|
statusName: status.name,
|
|
statusClass: status.cls,
|
|
result: c.ackResultCode || (c.status === 'sent' ? '等待应答' : '--'),
|
|
createdAt: fmtTime(c.createdAt)
|
|
}
|
|
})
|
|
} catch (e) {
|
|
ui.toast(e.message || '加载设备操作记录失败')
|
|
}
|
|
}
|
|
|
|
function reload() {
|
|
pageNum.value = 1
|
|
load()
|
|
}
|
|
|
|
|
|
onMounted(load)
|
|
</script>
|
|
|
|
<style scoped>
|
|
.asset-search :deep(.t-input) {
|
|
width: 100%;
|
|
}
|
|
.asset-search {
|
|
border: 0;
|
|
padding: 0;
|
|
height: auto;
|
|
}
|
|
.toolbar-group :deep(.t-select) {
|
|
flex-shrink: 0;
|
|
}
|
|
</style>
|
|
|