ota管理界面

This commit is contained in:
mmc
2026-09-22 19:37:13 +08:00
parent 300e2c221d
commit 8a7e239bd6
13 changed files with 2325 additions and 0 deletions

View File

@@ -0,0 +1,166 @@
# OTA 管理界面 — 实施方案
## Context
系统设置模块目前缺少固件/版本管理入口。运维人员需要在一个统一界面里:
- 查看所有机器的当前固件版本
- 上传新的固件包(.bin/.zip)
- 对单台或批量选中机器下发升级
- 每台机器记住上一次的版本号,支持按机器批量回退
后端 OTA 接口尚未实现。本方案先以 Mock 数据把页面与交互跑通,API 函数集中在 `src/api/ota.ts`,后续后端接口就绪时只需把 mock 实现替换为真实 `request` 调用即可,页面无需改动。
## 关键参考文件
- [routes.tsx](file:///d:/code/机器人智慧服务系统/src/router/routes.tsx) — 路由 + 懒加载注册位置(L35-L42 导入区,L160-L177 systemSetting.children)
- [SystemSetting.tsx](file:///d:/code/机器人智慧服务系统/src/pages/SystemSetting.tsx) — 系统设置页 Outlet 容器
- [AllDeviceManagement.tsx](file:///d:/code/机器人智慧服务系统/src/components/SystemSetting/AllDeviceManagement.tsx) — 表格 + 搜索 + 操作列模板
- [DeviceManagement.tsx](file:///d:/code/机器人智慧服务系统/src/components/SystemSetting/DeviceManagement.tsx) — Tabs 子页面模板
- [device.ts](file:///d:/code/机器人智慧服务系统/src/api/device.ts) — API 封装范例(`request`、`getAllDevice`、`importBindDevices` 上传 FormData 范例)
- [request.ts](file:///d:/code/机器人智慧服务系统/src/api/request.ts) — axios 实例 + token/FormData 拦截器
- [Layout.tsx](file:///d:/code/机器人智慧服务系统/src/components/Layout.tsx) — 侧边栏菜单构建(`buildMenuTree`、`renderMenuItems`),动态菜单来自 `getMenuList`
- [DeviceOverviewPage.tsx#L811-L814](file:///d:/code/机器人智慧服务系统/src/components/devices/DeviceOverviewPage.tsx) — 设备已有 `firmwareVersion` 字段
- [zh/index.ts](file:///d:/code/机器人智慧服务系统/src/locales/zh/index.ts) — 中文 i18n(`systemSetting` 节 L2433、`router` 节 L3562)
- [en/index.ts](file:///d:/code/机器人智慧服务系统/src/locales/en/index.ts) — 英文 i18n
## 实施步骤
### 1. 新建 Mock API 层 `src/api/ota.ts`
定义以下函数,内部用 `setTimeout` 模拟网络延迟,数据保存在模块级内存变量中(页面刷新即重置)。
```ts
// 数据结构
interface MachineVersion {
id: number; // 机器ID
code: string; // 编号
name: string; // 名称
type: string; // 类型 ROBOT/DRONE/CAMERA/...
online: 'ONLINE' | 'OFFLINE';
currentVersion: string; // 当前固件版本
previousVersion: string | null; // 上一版本(首次升级前为 null)
lastUpgradeTime: string | null;
status: 'IDLE' | 'UPGRADING' | 'FAILED' | 'SUCCESS';
}
interface FirmwarePackage {
id: number;
version: string; // 版本号,如 v1.2.3
fileName: string;
fileSize: number; // bytes
description?: string;
uploadTime: string;
}
```
导出函数:
- `getMachineVersionList()` → 返回 8~10 条 Mock 机器数据
- `getFirmwarePackageList()` → 返回已上传的固件包列表(初始内置 2 条历史版本)
- `uploadFirmwarePackage({ file, version, description })` → 把新固件加入列表并返回
- `upgradeMachines({ machineIds, targetVersion })` → 更新对应机器:`previousVersion = currentVersion`,`currentVersion = targetVersion`,`status` 流转,`lastUpgradeTime = now`
- `rollbackMachines({ machineIds })` → 对每台机器:若 `previousVersion` 存在则交换 current/previous;否则报错
### 2. 新建页面 `src/components/SystemSetting/OTAManagement.tsx`
单页三段式布局(参考 [AllDeviceManagement.tsx](file:///d:/code/机器人智慧服务系统/src/components/SystemSetting/AllDeviceManagement.tsx) 的表格范式):
**A. 顶部 — 固件包上传卡(Card)**
- `Upload` 组件(antd)`accept=".bin,.zip"` `beforeUpload` 返回 `false` 阻止自动上传
- `Input` 版本号(必填,校验 `v\d+\.\d+\.\d+` 格式)
- `Input.TextArea` 描述
- 「上传」按钮 → 调用 `uploadFirmwarePackage`,成功后刷新固件列表
**B. 中部 — 已上传固件包列表(Table)**
- 列:版本号 / 文件名 / 文件大小(格式化为 KB/MB)/ 描述 / 上传时间 / 操作(删除)
- `rowKey="id"`,分页 pageSize=10
**C. 底部 — 机器版本表(Table + rowSelection)**
- 列:机器编号 / 名称 / 类型 / 在线状态 / 当前版本 / 上一版本 / 最近升级时间 / 升级状态 / 操作(单台升级 / 单台回退)
- `rowSelection={{ type: 'checkbox' }}` 支持多选
- 表格上方工具栏:「批量升级」「批量回退」「刷新」按钮
- 「批量升级」弹出 `Modal.select` 让用户选择目标固件版本(从固件包列表)
- 「批量回退」对每台选中机器调用 `rollbackMachines`,对 `previousVersion` 为空的机器用 `message.warning` 跳过
- 操作期间 `loading` 状态,操作完成后 `message.success` 并刷新表格
整页使用 `useTranslation` + `App.useApp().modal/message` 保持与 [AllDeviceManagement.tsx](file:///d:/code/机器人智慧服务系统/src/components/SystemSetting/AllDeviceManagement.tsx) 一致的交互风格。
### 3. 注册路由 `src/router/routes.tsx`
- L35-L42 区添加:`const OTAManagementPage = lazy(() => import('../components/SystemSetting/OTAManagement'));`
- `systemSetting.children` 数组追加:`{ path: 'ota', element: withSuspense(OTAManagementPage) },`
### 4. 侧边栏入口 — `src/components/Layout.tsx` 加静态 fallback
`getMenu()` 拉到后端菜单后,遍历 `menuList` 找 `path === '/systemSetting'` 的节点,在其 `children` 末尾追加一项(若不存在):
```ts
{
key: '/systemSetting/ota',
label: t('router.otaManagement'),
icon: null, // 子项无图标,与现有子菜单保持一致
}
```
这样后端菜单数据未配置 OTA 时,前端也能立即在侧边栏看到入口;后端配置好之后该项会被原生菜单项覆盖或共存(key 相同不会重复渲染)。可通过 `t('router.otaManagement')` 做开关:前端 fallback 项的 label 与后端配置时使用同一个 i18n key。
### 5. i18n 文案
**`src/locales/zh/index.ts`**
`router` 节新增:
```ts
otaManagement: 'OTA 管理',
```
`systemSetting` 节新增:
```ts
ota: {
title: 'OTA 固件管理',
uploadCard: '上传固件包',
versionPlaceholder: '例如 v1.2.3',
description: '描述',
uploadBtn: '上传',
firmwareList: '已上传固件包',
machineVersionList: '机器版本列表',
currentVersion: '当前版本',
previousVersion: '上一版本',
lastUpgradeTime: '最近升级时间',
upgradeStatus: '升级状态',
batchUpgrade: '批量升级',
batchRollback: '批量回退',
selectTargetVersion: '选择目标固件版本',
confirmUpgrade: '确认对选中的 {count} 台机器升级到 {version}?',
confirmRollback: '确认对选中的 {count} 台机器回退到上一版本?',
noPreviousVersion: '机器 {name} 没有上一版本,无法回退',
uploadSuccess: '固件包上传成功',
upgradeSuccess: '升级指令已下发',
rollbackSuccess: '回退指令已下发',
deleteConfirm: '确认删除固件包 {version}?',
statusIdle: '空闲',
statusUpgrading: '升级中',
statusFailed: '失败',
statusSuccess: '成功',
},
```
**`src/locales/en/index.ts`** 同步补全英文翻译。
## 验证步骤
1. `npm run dev` 启动开发服务器
2. 登录后从侧边栏「系统设置 → OTA 管理」进入,或直接访问 `/systemSetting/ota`
3. 验证流程:
- 顶部上传一个 `.zip` 测试文件 + 填版本号 `v1.0.0` → 中部固件列表出现新条目
- 底部机器表勾选 2-3 台机器 → 点「批量升级」→ 弹窗选 `v1.0.0` → 确认 → 选中机器 `currentVersion` 变为 `v1.0.0`、`previousVersion` 记录原版本、`lastUpgradeTime` 刷新
- 再次勾选同样机器 → 点「批量回退」→ 确认 → `currentVersion` 与 `previousVersion` 互换
- 单台机器「操作」列的「升级」/「回退」按钮单独验证
- 取消勾选时「批量升级/回退」按钮置灰
- 切换语言到 English,所有文案正常
4. 浏览器 Network 面板无需真实请求(Mock 在前端完成);控制台无报错
5. `npm run build` 通过,无 TS 报错
## 范围边界
- 仅做前端 + Mock 数据,不修改后端代码
- 不改 `getMenuList` 接口契约,仅前端 Layout 加 fallback
- 不引入新依赖,全部使用项目已有的 antd 组件
- Mock 数据保存在模块内存,刷新即重置;后续接后端时仅替换 `src/api/ota.ts` 内部实现