Vue3 + Element Plus版本iot前端迁移到vben版本
This commit is contained in:
349
apps/web-antd/src/views/iot/ota/modules/task/OtaTaskDetail.vue
Normal file
349
apps/web-antd/src/views/iot/ota/modules/task/OtaTaskDetail.vue
Normal file
@@ -0,0 +1,349 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, reactive, ref } from 'vue';
|
||||
import { useVbenModal } from '@vben/common-ui';
|
||||
import { Card, Col, Descriptions, Modal, Row, Table, Tabs, Tag, message } from 'ant-design-vue';
|
||||
import type { TableColumnsType } from 'ant-design-vue';
|
||||
import type { OtaTask } from '#/api/iot/ota/task';
|
||||
import * as IoTOtaTaskApi from '#/api/iot/ota/task';
|
||||
import type { OtaTaskRecord } from '#/api/iot/ota/task/record';
|
||||
import * as IoTOtaTaskRecordApi from '#/api/iot/ota/task/record';
|
||||
import { IoTOtaTaskRecordStatusEnum } from '#/views/iot/utils/constants';
|
||||
import { formatDate } from '@vben/utils';
|
||||
|
||||
/** OTA 任务详情组件 */
|
||||
defineOptions({ name: 'OtaTaskDetail' });
|
||||
|
||||
const emit = defineEmits(['success']);
|
||||
|
||||
const taskId = ref<number>();
|
||||
const taskLoading = ref(false);
|
||||
const task = ref<OtaTask>({} as OtaTask);
|
||||
|
||||
const taskStatisticsLoading = ref(false);
|
||||
const taskStatistics = ref<Record<string, number>>({});
|
||||
|
||||
const recordLoading = ref(false);
|
||||
const recordList = ref<OtaTaskRecord[]>([]);
|
||||
const recordTotal = ref(0);
|
||||
const queryParams = reactive({
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
taskId: undefined as number | undefined,
|
||||
status: undefined as number | undefined,
|
||||
});
|
||||
const activeTab = ref('');
|
||||
|
||||
/** 状态标签配置 */
|
||||
const statusTabs = computed(() => {
|
||||
const tabs = [{ key: '', label: '全部设备' }];
|
||||
Object.values(IoTOtaTaskRecordStatusEnum).forEach((status) => {
|
||||
tabs.push({
|
||||
key: status.value.toString(),
|
||||
label: status.label,
|
||||
});
|
||||
});
|
||||
return tabs;
|
||||
});
|
||||
|
||||
/** 表格列配置 */
|
||||
const columns: TableColumnsType = [
|
||||
{
|
||||
title: '设备名称',
|
||||
dataIndex: 'deviceName',
|
||||
key: 'deviceName',
|
||||
align: 'center' as const,
|
||||
},
|
||||
{
|
||||
title: '当前版本',
|
||||
dataIndex: 'fromFirmwareVersion',
|
||||
key: 'fromFirmwareVersion',
|
||||
align: 'center' as const,
|
||||
},
|
||||
{
|
||||
title: '升级状态',
|
||||
dataIndex: 'status',
|
||||
key: 'status',
|
||||
align: 'center' as const,
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
title: '升级进度',
|
||||
dataIndex: 'progress',
|
||||
key: 'progress',
|
||||
align: 'center' as const,
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
title: '状态描述',
|
||||
dataIndex: 'description',
|
||||
key: 'description',
|
||||
align: 'center' as const,
|
||||
},
|
||||
{
|
||||
title: '更新时间',
|
||||
dataIndex: 'updateTime',
|
||||
key: 'updateTime',
|
||||
align: 'center' as const,
|
||||
width: 180,
|
||||
customRender: ({ text }: any) => formatDate(text, 'YYYY-MM-DD HH:mm:ss'),
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
align: 'center' as const,
|
||||
width: 80,
|
||||
},
|
||||
];
|
||||
|
||||
const [ModalComponent, modalApi] = useVbenModal();
|
||||
|
||||
/** 获取任务详情 */
|
||||
const getTaskInfo = async () => {
|
||||
if (!taskId.value) {
|
||||
return;
|
||||
}
|
||||
taskLoading.value = true;
|
||||
try {
|
||||
task.value = await IoTOtaTaskApi.getOtaTask(taskId.value);
|
||||
} finally {
|
||||
taskLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
/** 获取统计数据 */
|
||||
const getStatistics = async () => {
|
||||
if (!taskId.value) {
|
||||
return;
|
||||
}
|
||||
taskStatisticsLoading.value = true;
|
||||
try {
|
||||
taskStatistics.value = await IoTOtaTaskRecordApi.getOtaTaskRecordStatusStatistics(
|
||||
undefined,
|
||||
taskId.value,
|
||||
);
|
||||
} finally {
|
||||
taskStatisticsLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
/** 获取升级记录列表 */
|
||||
const getRecordList = async () => {
|
||||
if (!taskId.value) {
|
||||
return;
|
||||
}
|
||||
recordLoading.value = true;
|
||||
try {
|
||||
queryParams.taskId = taskId.value;
|
||||
const data = await IoTOtaTaskRecordApi.getOtaTaskRecordPage(queryParams);
|
||||
recordList.value = data.list || [];
|
||||
recordTotal.value = data.total || 0;
|
||||
} finally {
|
||||
recordLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
/** 切换标签 */
|
||||
const handleTabChange = (tabKey: string | number) => {
|
||||
activeTab.value = String(tabKey);
|
||||
queryParams.pageNo = 1;
|
||||
queryParams.status = activeTab.value === '' ? undefined : parseInt(String(tabKey));
|
||||
getRecordList();
|
||||
};
|
||||
|
||||
/** 分页变化 */
|
||||
const handleTableChange = (pagination: any) => {
|
||||
queryParams.pageNo = pagination.current;
|
||||
queryParams.pageSize = pagination.pageSize;
|
||||
getRecordList();
|
||||
};
|
||||
|
||||
/** 取消升级 */
|
||||
const handleCancelUpgrade = async (record: OtaTaskRecord) => {
|
||||
Modal.confirm({
|
||||
title: '确认取消',
|
||||
content: '确认要取消该设备的升级任务吗?',
|
||||
async onOk() {
|
||||
try {
|
||||
await IoTOtaTaskRecordApi.cancelOtaTaskRecord(record.id!);
|
||||
message.success('取消成功');
|
||||
await getRecordList();
|
||||
await getStatistics();
|
||||
await getTaskInfo();
|
||||
emit('success');
|
||||
} catch (error) {
|
||||
console.error('取消升级失败', error);
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
/** 打开弹窗 */
|
||||
const open = (id: number) => {
|
||||
modalApi.open();
|
||||
taskId.value = id;
|
||||
activeTab.value = '';
|
||||
queryParams.pageNo = 1;
|
||||
queryParams.status = undefined;
|
||||
|
||||
// 加载数据
|
||||
getTaskInfo();
|
||||
getStatistics();
|
||||
getRecordList();
|
||||
};
|
||||
|
||||
/** 暴露方法 */
|
||||
defineExpose({ open });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ModalComponent title="升级任务详情" class="w-5/6">
|
||||
<div class="p-4">
|
||||
<!-- 任务信息 -->
|
||||
<Card title="任务信息" class="mb-5" :loading="taskLoading">
|
||||
<Descriptions :column="3" bordered>
|
||||
<Descriptions.Item label="任务编号">{{ task.id }}</Descriptions.Item>
|
||||
<Descriptions.Item label="任务名称">{{ task.name }}</Descriptions.Item>
|
||||
<Descriptions.Item label="升级范围">
|
||||
<Tag v-if="task.deviceScope === 1" color="blue">全部设备</Tag>
|
||||
<Tag v-else-if="task.deviceScope === 2" color="green">指定设备</Tag>
|
||||
<Tag v-else>{{ task.deviceScope }}</Tag>
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="任务状态">
|
||||
<Tag v-if="task.status === 0" color="orange">待执行</Tag>
|
||||
<Tag v-else-if="task.status === 1" color="blue">执行中</Tag>
|
||||
<Tag v-else-if="task.status === 2" color="green">已完成</Tag>
|
||||
<Tag v-else-if="task.status === 3" color="red">已取消</Tag>
|
||||
<Tag v-else>{{ task.status }}</Tag>
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="创建时间">
|
||||
{{ task.createTime ? formatDate(task.createTime, 'YYYY-MM-DD HH:mm:ss') : '-' }}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="任务描述" :span="3">
|
||||
{{ task.description }}
|
||||
</Descriptions.Item>
|
||||
</Descriptions>
|
||||
</Card>
|
||||
|
||||
<!-- 任务升级设备统计 -->
|
||||
<Card title="升级设备统计" class="mb-5" :loading="taskStatisticsLoading">
|
||||
<Row :gutter="20" class="py-5">
|
||||
<Col :span="6">
|
||||
<div class="text-center p-5 border border-solid border-gray-200 rounded bg-gray-50">
|
||||
<div class="text-3xl font-bold mb-2 text-blue-500">
|
||||
{{
|
||||
Object.values(taskStatistics).reduce((sum, count) => sum + (count || 0), 0) || 0
|
||||
}}
|
||||
</div>
|
||||
<div class="text-sm text-gray-600">升级设备总数</div>
|
||||
</div>
|
||||
</Col>
|
||||
<Col :span="3">
|
||||
<div class="text-center p-5 border border-solid border-gray-200 rounded bg-gray-50">
|
||||
<div class="text-3xl font-bold mb-2 text-gray-400">
|
||||
{{ taskStatistics[IoTOtaTaskRecordStatusEnum.PENDING.value] || 0 }}
|
||||
</div>
|
||||
<div class="text-sm text-gray-600">待推送</div>
|
||||
</div>
|
||||
</Col>
|
||||
<Col :span="3">
|
||||
<div class="text-center p-5 border border-solid border-gray-200 rounded bg-gray-50">
|
||||
<div class="text-3xl font-bold mb-2 text-blue-400">
|
||||
{{ taskStatistics[IoTOtaTaskRecordStatusEnum.PUSHED.value] || 0 }}
|
||||
</div>
|
||||
<div class="text-sm text-gray-600">已推送</div>
|
||||
</div>
|
||||
</Col>
|
||||
<Col :span="3">
|
||||
<div class="text-center p-5 border border-solid border-gray-200 rounded bg-gray-50">
|
||||
<div class="text-3xl font-bold mb-2 text-yellow-500">
|
||||
{{ taskStatistics[IoTOtaTaskRecordStatusEnum.UPGRADING.value] || 0 }}
|
||||
</div>
|
||||
<div class="text-sm text-gray-600">正在升级</div>
|
||||
</div>
|
||||
</Col>
|
||||
<Col :span="3">
|
||||
<div class="text-center p-5 border border-solid border-gray-200 rounded bg-gray-50">
|
||||
<div class="text-3xl font-bold mb-2 text-green-500">
|
||||
{{ taskStatistics[IoTOtaTaskRecordStatusEnum.SUCCESS.value] || 0 }}
|
||||
</div>
|
||||
<div class="text-sm text-gray-600">升级成功</div>
|
||||
</div>
|
||||
</Col>
|
||||
<Col :span="3">
|
||||
<div class="text-center p-5 border border-solid border-gray-200 rounded bg-gray-50">
|
||||
<div class="text-3xl font-bold mb-2 text-red-500">
|
||||
{{ taskStatistics[IoTOtaTaskRecordStatusEnum.FAILURE.value] || 0 }}
|
||||
</div>
|
||||
<div class="text-sm text-gray-600">升级失败</div>
|
||||
</div>
|
||||
</Col>
|
||||
<Col :span="3">
|
||||
<div class="text-center p-5 border border-solid border-gray-200 rounded bg-gray-50">
|
||||
<div class="text-3xl font-bold mb-2 text-gray-400">
|
||||
{{ taskStatistics[IoTOtaTaskRecordStatusEnum.CANCELED.value] || 0 }}
|
||||
</div>
|
||||
<div class="text-sm text-gray-600">升级取消</div>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
</Card>
|
||||
|
||||
<!-- 设备管理 -->
|
||||
<Card title="升级设备记录">
|
||||
<Tabs v-model:activeKey="activeTab" @change="handleTabChange" class="mb-4">
|
||||
<Tabs.TabPane v-for="tab in statusTabs" :key="tab.key" :tab="tab.label" />
|
||||
</Tabs>
|
||||
|
||||
<Table
|
||||
:columns="columns"
|
||||
:data-source="recordList"
|
||||
:loading="recordLoading"
|
||||
:pagination="{
|
||||
current: queryParams.pageNo,
|
||||
pageSize: queryParams.pageSize,
|
||||
total: recordTotal,
|
||||
showSizeChanger: true,
|
||||
showQuickJumper: true,
|
||||
showTotal: (total: number) => `共 ${total} 条`,
|
||||
}"
|
||||
@change="handleTableChange"
|
||||
>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<!-- 升级状态 -->
|
||||
<template v-if="column.key === 'status'">
|
||||
<Tag v-if="record.status === 0" color="default">待推送</Tag>
|
||||
<Tag v-else-if="record.status === 1" color="blue">已推送</Tag>
|
||||
<Tag v-else-if="record.status === 2" color="processing">升级中</Tag>
|
||||
<Tag v-else-if="record.status === 3" color="success">成功</Tag>
|
||||
<Tag v-else-if="record.status === 4" color="error">失败</Tag>
|
||||
<Tag v-else-if="record.status === 5" color="warning">已取消</Tag>
|
||||
<Tag v-else>{{ record.status }}</Tag>
|
||||
</template>
|
||||
|
||||
<!-- 升级进度 -->
|
||||
<template v-else-if="column.key === 'progress'">
|
||||
{{ record.progress }}%
|
||||
</template>
|
||||
|
||||
<!-- 操作 -->
|
||||
<template v-else-if="column.key === 'action'">
|
||||
<a
|
||||
v-if="
|
||||
[
|
||||
IoTOtaTaskRecordStatusEnum.PENDING.value,
|
||||
IoTOtaTaskRecordStatusEnum.PUSHED.value,
|
||||
IoTOtaTaskRecordStatusEnum.UPGRADING.value,
|
||||
].includes(record.status)
|
||||
"
|
||||
class="text-red-500"
|
||||
@click="handleCancelUpgrade(record)"
|
||||
>
|
||||
取消
|
||||
</a>
|
||||
</template>
|
||||
</template>
|
||||
</Table>
|
||||
</Card>
|
||||
</div>
|
||||
</ModalComponent>
|
||||
</template>
|
||||
Reference in New Issue
Block a user