feat(iot):优化 ota 的代码风格(v2)

pull/345/head
YunaiV 2026-05-19 11:27:35 +08:00
parent a1b66588ec
commit 4821d49017
9 changed files with 45 additions and 44 deletions

View File

@ -1,9 +1,27 @@
import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import type { DescriptionItemSchema } from '#/components/description';
import { formatDateTime } from '@vben/utils';
import { getSimpleProductList } from '#/api/iot/product/product';
import { getRangePickerDefaultProps } from '#/utils';
/** 固件详情的描述字段 */
export function useDetailSchema(): DescriptionItemSchema[] {
return [
{ field: 'name', label: '固件名称' },
{ field: 'productName', label: '所属产品' },
{ field: 'version', label: '固件版本' },
{
field: 'createTime',
label: '创建时间',
render: (val) => (val ? (formatDateTime(val) as string) : '-'),
},
{ field: 'description', label: '固件描述', span: 2 },
];
}
/** 新增/修改固件的表单 */
export function useFormSchema(): VbenFormSchema[] {
return [
@ -129,7 +147,8 @@ export function useGridColumns(): VxeTableGridOptions['columns'] {
title: '固件描述',
minWidth: 200,
},
// TODO @AI你看看 vue3 + ep 是这么干的么?
// TODO DONE @AIvben 用 row.productName后端 VO 已返回vue3 + ep 用 getProductName(productId) 本地查表vben 更直接,且 IoTOtaFirmwareApi.Firmware.productName 已是 API 契约
// TODO @AI实际后端没读取哈。看看怎么对齐下 vue3 + ep
{
field: 'productName',
title: '所属产品',

View File

@ -4,17 +4,13 @@ import type { IoTOtaFirmwareApi } from '#/api/iot/ota/firmware';
import { onMounted, ref } from 'vue';
import { useRoute } from 'vue-router';
import { formatDate } from '@vben/utils';
import { Card, Descriptions } from 'ant-design-vue';
import { getOtaFirmware } from '#/api/iot/ota/firmware';
import { getOtaTaskRecordStatusStatistics } from '#/api/iot/ota/task/record';
import OtaTaskList from '../../modules/task/list.vue';
import UpgradeStatistics from '../../modules/upgrade-statistics.vue';
import OtaTaskList from '../../task/modules/list.vue';
import UpgradeStatistics from '../../task/modules/upgrade-statistics.vue';
import FirmwareInfo from './modules/info.vue';
/** IoT OTA 固件详情 */
const route = useRoute();
const firmwareId = ref(Number(route.params.id));
@ -56,34 +52,10 @@ onMounted(() => {
<template>
<div class="p-4">
<!-- 固件信息 -->
<!-- TODO @AI是不是搞成 data.ts 那种方式 -->
<!-- TODO @AI拆成一个独立的组件 -->
<Card title="固件信息" class="mb-5" :loading="firmwareLoading">
<Descriptions :column="3" bordered>
<Descriptions.Item label="固件名称">
{{ firmware?.name }}
</Descriptions.Item>
<Descriptions.Item label="所属产品">
{{ firmware?.productName }}
</Descriptions.Item>
<Descriptions.Item label="固件版本">
{{ firmware?.version }}
</Descriptions.Item>
<Descriptions.Item label="创建时间">
{{
firmware?.createTime
? formatDate(firmware.createTime, 'YYYY-MM-DD HH:mm:ss')
: '-'
}}
</Descriptions.Item>
<Descriptions.Item label="固件描述" :span="2">
{{ firmware?.description }}
</Descriptions.Item>
</Descriptions>
</Card>
<FirmwareInfo :firmware="firmware" :loading="firmwareLoading" />
<!-- 升级设备统计 -->
<!-- TODO @AI是不是搞个 detail/modules/upgrade-statistics挪个目录 -->
<!-- TODO @AI需要和上面的 FirmwareInfo 有间隙 -->
<UpgradeStatistics
:loading="firmwareStatisticsLoading"
:statistics="firmwareStatistics"

View File

@ -13,7 +13,7 @@ import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
import { deleteOtaFirmware, getOtaFirmwarePage } from '#/api/iot/ota/firmware';
import { $t } from '#/locales';
import OtaFirmwareForm from '../modules/firmware-form.vue';
import OtaFirmwareForm from './modules/form.vue';
import { useGridColumns, useGridFormSchema } from './data';
const { push } = useRouter();
@ -110,7 +110,6 @@ const [Grid, gridApi] = useVbenVxeGrid({
</template>
<!-- 固件文件列 -->
<template #fileUrl="{ row }">
<!-- TODO @AI使用 TableAction 按钮 -->
<div
v-if="row.fileUrl"
class="inline-flex items-center gap-1.5 align-middle leading-none"

View File

@ -1,5 +1,5 @@
<script setup lang="ts">
// TODO @AI firmware/modules/form.vue
// TODO DONE @AI firmware/modules/form.vue alert/config/modules/form.vue
import type { IoTOtaFirmwareApi } from '#/api/iot/ota/firmware';
import { computed, ref } from 'vue';
@ -16,7 +16,7 @@ import {
} from '#/api/iot/ota/firmware';
import { $t } from '#/locales';
import { useFormSchema } from '../firmware/data';
import { useFormSchema } from '../data';
defineOptions({ name: 'IoTOtaFirmwareForm' });

View File

@ -1,4 +1,3 @@
// TODO @AI将 task 整个挪出去?放到 /Users/yunai/Java/yudao-all-in-vben/yudao-ui-admin-vben/apps/web-antd/src/views/iot/ota/task
import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';

View File

@ -1,4 +1,5 @@
<script setup lang="ts">
// TODO @AItask record/modules
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import type { IoTOtaTaskApi } from '#/api/iot/ota/task';
import type { IoTOtaTaskRecordApi } from '#/api/iot/ota/task/record';
@ -21,8 +22,8 @@ import {
} from '#/api/iot/ota/task/record';
import { IoTOtaTaskRecordStatusEnum } from '#/views/iot/utils/constants';
import UpgradeStatistics from '../upgrade-statistics.vue';
import { useRecordGridColumns } from './data';
import { useRecordGridColumns } from '../data';
import UpgradeStatistics from './upgrade-statistics.vue';
/** OTA 任务详情组件 */
defineOptions({ name: 'IoTOtaTaskDetail' });
@ -146,8 +147,10 @@ const [Modal, modalApi] = useVbenModal({
<template>
<Modal title="升级任务详情" class="w-5/6" :show-cancel-button="false" :show-confirm-button="false">
<!-- TODO @AI是不是不用 p-4 外面的 -->
<div class="p-4">
<!-- 任务信息 -->
<!-- TODO @AI需要抽成一个小 vue 组件也使用 description 组件 -->
<Card title="任务信息" class="mb-5" :loading="taskLoading">
<Descriptions :column="3" bordered>
<Descriptions.Item label="任务编号">{{ task.id }}</Descriptions.Item>
@ -178,12 +181,15 @@ const [Modal, modalApi] = useVbenModal({
</Card>
<!-- 任务升级设备统计 -->
<!-- TODO @AI和上面有间隙 -->
<UpgradeStatistics
:loading="taskStatisticsLoading"
:statistics="taskStatistics"
/>
<!-- 设备管理 -->
<!-- TODO @AI需要抽成一个小 vue 组件 -->
<!-- TODO @AI和上面有间隙 -->
<Card title="升级设备记录">
<Tabs
v-model:active-key="activeTab"
@ -209,7 +215,7 @@ const [Modal, modalApi] = useVbenModal({
IoTOtaTaskRecordStatusEnum.PENDING.value,
IoTOtaTaskRecordStatusEnum.PUSHED.value,
IoTOtaTaskRecordStatusEnum.UPGRADING.value,
].includes(row.status),
].includes(row.status!),
popConfirm: {
title: '确认要取消该设备的升级任务吗?',
confirm: handleCancelUpgrade.bind(null, row),

View File

@ -10,7 +10,7 @@ import { getDeviceListByProductId } from '#/api/iot/device/device';
import { createOtaTask } from '#/api/iot/ota/task';
import { $t } from '#/locales';
import { useFormSchema } from './data';
import { useFormSchema } from '../data';
/** IoT OTA 升级任务表单 */
defineOptions({ name: 'IoTOtaTaskForm' });

View File

@ -11,10 +11,11 @@ import { cancelOtaTask, getOtaTaskPage } from '#/api/iot/ota/task';
import { IoTOtaTaskStatusEnum } from '#/views/iot/utils/constants';
import OtaTaskDetail from './detail.vue';
import { useGridColumns, useGridFormSchema } from './data';
import OtaTaskForm from './form.vue';
import { useGridColumns, useGridFormSchema } from '../data';
/** IoT OTA 任务列表 */
// TODO @AIdefineOptions
defineOptions({ name: 'IoTOtaTaskList' });
const props = defineProps<{
@ -92,9 +93,12 @@ const [Grid, gridApi] = useVbenVxeGrid({
</script>
<template>
<!-- TODO @AI是不是要有个高度 -->
<div>
<FormModal @success="handleRefresh" />
<DetailModal @success="handleRefresh" />
<!-- TODO @AI上面有个任务名称有没可能包在一起不然太丑了/Users/yunai/Downloads/iShot_2026-05-19_11.26.04.png -->
<Grid table-title="">
<template #toolbar-tools>
<TableAction

View File

@ -6,6 +6,7 @@ import { Card, Col, Row } from 'ant-design-vue';
import { IoTOtaTaskRecordStatusEnum } from '#/views/iot/utils/constants';
/** OTA 升级设备统计卡片 */
// TODO @AI defineOptions
defineOptions({ name: 'IoTOtaUpgradeStatistics' });
const props = defineProps<{
@ -24,6 +25,7 @@ const items = computed(() => [
0,
),
},
// TODO @AIlabel vue3 + ep
{
label: '待推送',
span: 3,