# 机器人全生命周期管理 - UI 交互规范

> **module**: robot-manager
> **doc_type**: UISpec
> **status**: ⚠️ **v2 sections DEPRECATED · v3 UI 入口见 §0**
> **owner**: FFOA 开发团队
> **upstream_docs**: 01-prd.md, 04-state-machine.md, 07-api.md, business-analysis/*
> **last_verified**: 2026-05-18（v3 主路径 MCP 跑通）

---

## ⚠️ v2 → v3 UI 重构通告（2026-05）

**本文档大量内容描述 v2 6 状态机的 UI**（设备列表 Tab、6 状态下拉、`/admin/models` 等），跟当前 UI 不符。

当前 UI 已经是 **v3 28 stage 配套**，业务表入口（PO/SO/Delivery/Payment/Rental/ServiceTicket）独立。

v2 sections 仅作历史参考，新功能开发按 §0 走。

---

## §0 v3 UI 入口清单（2026-05-18 实测）

### 侧栏导航结构（robot-manager 模块）

```
Quick Actions          → /robot-manager/my-work       my-work 工作台（按 stage 分组卡片）
All Devices            → /robot-manager               设备列表（28 stage 通用）
Reports                → /robot-manager/reports       报表
─── BUSINESS（v3 L3 业务表）───
Purchase Orders        → /robot-manager/purchase-orders   PO 列表 + 新建 PO（自动生成占位 RobotUnit）
Sales Orders           → /robot-manager/sales-orders      SO 列表 + 新建 SO（绑定 RobotUnit）
Deliveries             → /robot-manager/deliveries        DR + DF 列表
Payments               → /robot-manager/payments          PaymentRecord 列表
Service Tickets        → /robot-manager/service-tickets   售后工单
Rentals                → /robot-manager/rentals           租赁合约
─── MASTER DATA（L2 模块主数据）───
Models                 → /robot-manager/admin/models      RobotModel 管理
SKUs                   → /robot-manager/admin/skus        RobotSku 管理
─── REFERENCE ───
Workflow               → /robot-manager/workflow          v3 28 stage 业务流程图
User Guide             → /robot-manager/help              用户指南
```

### 关键页面交互

#### 1. 创建 PO + 占位 SN（v3 流程入口）

**入口**：`/robot-manager/purchase-orders` 「新建 PO」按钮

**Dialog**：
- PO 编号（自动生成 / 手工指定）
- 采购日期（可选，默认今天）
- 供应商下拉（来自 platform_master.suppliers）
- 货币下拉（来自 platform_master.currencies）
- 采购行（≥1 行）：
  - SKU 下拉 / 数量 / 单价
  - 「添加行」按钮支持多行

**提交后**：按 lines × quantity 自动生成 N 个占位 RobotUnit，ffsn = `{poNo}-LINE-{NNN}` 全部 currentStage = SUPPLY_PO_CREATED。

#### 2. my-work 工作台（按 stage 分组卡片）

**入口**：`/robot-manager/my-work`

**布局**：
- 标题区：搜索 / 新建 PO / 新建机器人 / 扫码
- 按 stage 分组的卡片：每个 stage 一个 group，展示该 stage 下用户部门相关的所有 RobotUnit
- 卡片展开后列出 unit，每个 unit 旁标「待填 X 项」
- 点击 unit 弹出 detail drawer

#### 3. Detail Drawer（v3 推进入口）

**关键元素**（按业务流程顺序）：
- 头部：当前 stage 名 + 部门 + 「扫码激活 SN」按钮（占位 SN 阶段）
- 当前阶段需填字段（数量动态计算）
- 机器人详细信息（80+ 字段按 stage 分组展示，✎ 可编辑）
- 底部：「完成并推进 → {下个 stage 名}」按钮 / 「搁置」 / 「详情页」跳转

**推进 UX**：点「完成并推进」后 drawer 自动关闭返回列表（注意：批量推进时每次都要重新点开 drawer）。

#### 4. 详情页（设备 detail）

**入口**：`/robot-manager/[id]` 或 `/robot-manager/r/[ffsn]`（QR 扫码短链）

**布局**（三栏）：
- 左：事件流时间线（按时间倒序的 RobotLifecycleEvent）
- 中：当前操作（StageActionPanel）
- 右：身份 + 二维码

### 关键 UI 命名约定

- 「快捷处理」= my-work 工作台
- 「完成并推进」= 推进 stage button
- 「扫码激活 SN」= activate-sn 入口
- 「占位 SN」= placeholderSnOrig（区分于 ffsn 正式 SN）

### 已知 UI bug（待修，参考 testing/reports/robot-manager-2026-05-18-e2e-report.md）

- bug #1 i18n 部分硬编码：英文 locale 下页面 heading 仍显示中文（已修：5 个核心 heading；副标题/按钮文案待下次系统性 i18n PR）
- bug #3 snapshot.currentSalesOrderId 投影漏（**已修**：projector 推进 SALES_RESERVED 时同步刷）

---

## 历史参考（v2，不再使用）

⚠️ 以下 §概述 / §交互原则 / §页面级规范 等是 v2 6 状态机的 UI spec（admin/models 列表、6 状态下拉、Section 权限矩阵等），**与当前 UI 不符**。
仅在迁移/对比时参考；新功能按 §0 实测 + 配套截图（在 frontend 实现 + 这份 spec §0 持续更新）。

---

## 导航结构

模块采用二级侧边栏导航，分**用户菜单**和**管理菜单**（按权限过滤）。

### 用户菜单（所有角色可见）

| 菜单项 | 路由 | 图标 |
|--------|------|------|
| Dashboard | `/robot-manager/dashboard` | LayoutDashboard |
| 设备管理 | `/robot-manager` | Monitor |
| 报表 | `/robot-manager/reports` | BarChart3 |

### 管理菜单（权限过滤，3 个分组）

| 分组 | 菜单项 | 路由 | 所需权限 |
|------|--------|------|----------|
| 基础数据 (archive) | 型号管理 | `/robot-manager/admin/models` | `robot-manager:manage:models` |
| 基础数据 | SKU 管理 | `/robot-manager/admin/skus` | `robot-manager:manage:models` |
| 基础数据 | 供应商管理 | `/robot-manager/admin/suppliers` | `robot-manager:manage:suppliers` |
| 基础数据 | 客户管理 | `/robot-manager/admin/customers` | `robot-manager:manage:customers` |
| 基础数据 | 位置管理 | `/robot-manager/admin/locations` | `robot-manager:manage:locations` |
| 配置 (config) | 字段定义 | `/robot-manager/admin/fields` | `robot-manager:manage:fields` |
| 配置 | 系统配置 | `/robot-manager/admin/settings` | `robot-manager:manage:fields` |
| 工具 (tool) | 数据导入 | `/robot-manager/import` | `robot-manager:create` |

**Administrator 角色跳过所有权限检查**（在 PermissionsGuard 内实现），所有菜单可见；非 Admin 角色按 `requiredPermissions` 精确过滤。

### 全局快捷键

| 按键 | 动作 |
|------|------|
| `c` | 跳转 `/robot-manager/create` 新建设备 |
| `?` | 跳转 `/robot-manager/help` |

快捷键实现于 `useHotkeys` hook，输入框聚焦时不触发。

---

## 页面清单

| 页面 | 路由 | 说明 | 角色可见性 |
|------|------|------|-----------|
| Dashboard | `/robot-manager/dashboard` | 设备状态概览、关键数字 | 所有角色 |
| 设备列表 | `/robot-manager` | 分页列表 + 筛选抽屉 + FFSN 搜索 | 所有角色 |
| 新建设备 | `/robot-manager/create` | 仅需 modelId + skuId | `create` 权限 |
| 设备详情 | `/robot-manager/[id]` | 6 大数据 Tab + 状态流转 + 售后记录 + 附件 | 所有角色（Tab 可编辑性按 `write:*` 过滤） |
| 对比 | `/robot-manager/compare` | 多选设备对比 | 所有角色 |
| 报表 | `/robot-manager/reports` | 库存 / 销售 / 财务 三页签 | `read`（Finance 对外可见） |
| 数据导入 | `/robot-manager/import` | 4 tab wizard：模板下载 → 上传 → 校验 → 确认 | `create` |
| 帮助 | `/robot-manager/help` | 用户指南、角色矩阵、路线图 | 所有角色 |
| 型号管理 | `/robot-manager/admin/models` | CRUD | `manage:models` |
| SKU 管理 | `/robot-manager/admin/skus` | CRUD（需 modelId 过滤） | `manage:models` |
| 供应商管理 | `/robot-manager/admin/suppliers` | CRUD | `manage:suppliers` |
| 客户管理 | `/robot-manager/admin/customers` | CRUD | `manage:customers` |
| 位置管理 | `/robot-manager/admin/locations` | CRUD + typeCode 过滤 | `manage:locations` |
| 字段定义 | `/robot-manager/admin/fields` | 2 Tab（Custom/System）+ OptionsEditor | `manage:fields` |
| 系统配置 | `/robot-manager/admin/settings` | ffsn_rule / status_default_location 等 JSON 表单 | `manage:fields` |

---

## 页面详细规范

### 1. Dashboard（`/robot-manager/dashboard`）

**组件**: `RobotDashboard`

**布局**：
- 顶部 4 张数字卡片：总设备数 / 在库 / 在途 / 已交付
- 中部：状态分布饼图 + 最近 30 天趋势折线图
- 底部：最近变更的设备列表（10 条）

**交互**：
- 卡片可点击，跳转到设备列表并自动套用 status filter
- 空数据态：显示"尚无设备"提示，引导按钮跳转新建页

### 2. 设备列表（`/robot-manager`）

**组件**: 列表页 `page.tsx`、`ColumnConfig`、`FilterDrawer`、`GlobalSearch`

**列**：FFSN / 型号 / SKU / 状态 / 客户 / Sales Price / Cost / 更新时间 / 操作
- 列可见性由用户在 `ColumnConfig` 配置；持久化到 localStorage
- Sales/Cost 列按 `showInList=true` 的 FieldDef 自动生成（支持动态字段）

**筛选抽屉**（`FilterDrawer`）：
- status（多选）
- modelId / skuId（关联下拉，skuId 按 modelId 过滤）
- customerId / supplierId / locationId
- 日期范围（createdAt / deliveredAt）

**搜索**：
- 搜索栏仅匹配 FFSN（DB 索引字段）
- 输入 3 字符后自动查询，debounce 300ms

**分页**：默认每页 20，可选 10/20/50/100

**行操作**：
- 单击行 → 跳转详情
- 右键 / "…" 菜单：查看 / 编辑 / 变更状态 / 删除
- 删除需二次确认弹窗，显示 FFSN

**空状态**：显示"尚无数据"+ "新建"按钮（仅 `create` 权限可见）

### 3. 设备详情（`/robot-manager/[id]`）

**布局**：
- 顶部：FFSN + 状态徽标 + 版本号 + 返回按钮
- Tab 区：Identity / Supply Chain / Sales / Finance / After-Sales / Compliance 六个
- 右侧栏：状态变更日志（时间线）+ 附件面板（`AttachmentsPanel`）

**Tab 可编辑性矩阵**（来自 `write:*` 权限）：

| Tab | 所需权限 |
|-----|----------|
| Identity | `robot-manager:write:identity` |
| Supply Chain | `robot-manager:write:supply-chain` |
| Sales | `robot-manager:write:sales` |
| Finance | `robot-manager:write:finance` |
| After-Sales | `robot-manager:write:after-sales` |
| Compliance | `robot-manager:write:compliance` |

无权限时：Tab 仍可查看，"编辑"按钮隐藏；尝试通过 API 绕过时后端返回 403。

**字段来源**：
- 静态字段：controller DTO 字段（currentStatus / customerId / supplierId / locationId 等）
- 动态字段：`RobotFieldDef (scope=unit)` 按 `group` 分配到 Tab；字段渲染由 `DynamicField` 组件按 `type` 分支（text/textarea/date/money/select/url）

**金额字段**：
- 所有 `type=money` 字段使用 `formatMoney` 工具 + 顶层 `currency` 字段渲染
- 输入态显示原始数值；显示态格式为 `Intl.NumberFormat(locale, { style: 'currency', currency })`
- `currency` 字段在 Identity Tab 首位，变更后实时更新所有 money 字段的显示

**不可变字段**：`FFSN` / `poNumber`（首次写入后）/ `salesOrderId`（首次写入后）显示为锁定状态，鼠标悬停提示"已锁定"。

**状态变更**：
- 独立按钮 "变更状态" 弹窗
- 弹窗下拉仅显示当前状态的合法目标（按 `VALID_TRANSITIONS`）
- 目标为 CANCELLED 时强制要求 remark 文本框
- 推进到 REPAIR 时提示"将创建维修记录"
- 乐观锁冲突 (409) 显示 "数据已被他人修改，请刷新" 并提供刷新按钮

**状态变更日志**：时间线从新到旧，每条显示 `fromStatus → toStatus`、操作人、时间、remark。

### 4. 报表（`/robot-manager/reports`）

**三个子页签**：
- 库存：按 status 柱状图 + `physical / available / inTransit / total` 数字卡
- 销售：累计交付、累计收入、客户 Top 10 表格
- 财务：`revenue / cost / margin` 数字卡 + 月度趋势

**筛选**：时间范围（默认近 90 天）、部门（若启用组织过滤）

**导出**：每个子页签顶部有"导出 Excel"按钮，调用对应 `/excel/export` 端点

### 5. 数据导入（`/robot-manager/import`）— v3 重做

> **完整 UX 规格见 [14-import-export-tool-prd.md §4 / §8](14-import-export-tool-prd.md)**。本节摘要核心结构供 UI 实施快速参考。
> **M1 实施状态（2026-05-18）**：`purchase-order` tab 已上线；`robot-unit` / `master` / `service-ticket` tab 标 disabled + "即将上线" badge。

**入口**：`/robot-manager/import`（sidebar archive group "数据导入"，权限 `robot-manager:create`），含 4 top tab（PO / RobotUnit / MasterData / ServiceTicket）+ MasterData 内 5 sub-tab（M3a）；无权限 tab 显示 disabled + tooltip。

**Wizard 4-step**（每个 tab 复用同一组件，类型不同）：

```
URL: /robot-manager/import
URL: /robot-manager/import/batches/:batchId  ← URL 持久化，刷新可恢复

Step 1 Upload                       Step 2 Preview                  Step 3 Confirm         Step 4 Done
[ Download Template ]               [ Statistic Cards ]              [ Confirm Button ]      [ Success ]
[ Drag/Select File ]                [ Error Aggregation Cards ]      [ Progress Bar ]        [ View History ]
                                    [ Virtual Scrolling List ]
                                    [ Download Error Report ]
                                    [ Change File ← 回 step 1 ]

顶部 Stepper：◉ Upload ─ ○ Preview ─ ○ Confirm ─ ○ Done
```

**Step 2 错误展示规格**：
- 顶部 4 个 stat 卡片（绿 successRows / 红 errorRows / 黄 warningRows / 灰 total）
- ≥100 错误时按 error code 聚合卡片（"类型错误 ×237 / FK 不存在 ×88"），点卡片下钻
- 行列表虚拟滚动 + 默认 50/页；超过 100 自动折叠 + 引导下载错误报告 Excel
- 「全部错误修正后启用 Step 3 按钮」（errorRows = 0 才解锁）

**Step 3 confirm UX**：
- 进度 bar（解析 → 校验 → 写入三阶段 indicator）
- 网络断后 retry 入口
- 重跑校验失败时显示 IMPORT_REFS_CHANGED_RETRY → 引导用户重新 preview（生成新 batch）

**Step 4 完成**：跳「查看历史」入口（/robot-manager/import/history）

**Sheet 规格**（模板）：
- **Sheet1 数据**：表头颜色（黄背景=必填 / 红边框=FK / 普通=可选）；Excel data validation 给 enum 列做下拉；cell comment 标"填 code 例如 'SUP-001'"；日期格式锁 YYYY-MM-DD
- **Sheet2 字段说明**：必填 / 类型 / 枚举值 / FK 表+列 / 示例 / 失败 error code 列；顶部含 `templateSchemaHash` + 生成时间
- **Sheet3 示例数据**：合成假数据（`SUP-EXAMPLE-001`），**禁从真实表 sample**（安全约束）

**模板下载**：`GET /robot-manager/import/:type/template`（M1 PR-B 实施）；响应 header 含 `X-Template-Schema-Hash` + 文件名 `{type}-template-{hash[:8]}.xlsx`

**错误码 i18n**：21 个 `IMPORT_*` 错误码，前端按 `t.robotManager.errorCodes[code]` 渲染（不依赖 server 中文 message），见 [08-error-codes.md §「数据导入工具（v3）」](08-error-codes.md)

**首次访问 onboarding**：empty state + 「3 步完成你的第一次导入」引导卡 + demo 样本下载

**a11y**：WCAG 2.1 AA（键盘可达 + 焦点可见 + 错误 aria-live 播报）；桌面端 only（min-width 1024px），移动 viewport 显示降级提示

**i18n / 双语**：所有文案 zh-CN ↔ en-US，wizard 切换 locale 无中文残留；模板表头 + 错误消息均按 `Accept-Language` 双语

### 6. 字段定义（`/robot-manager/admin/fields`）

**组件**: `EntityAdminPage` + `OptionsEditor`

**布局**：
- 2 Tab：Custom Fields（scope=unit）/ System Dicts（scope=service_record + location）
- 每 Tab 内为实体列表 + 新建/编辑弹窗

**字段编辑表单**：

| 字段 | 控件 | 规则 |
|------|------|------|
| Scope | 只读（当前 Tab 决定） | Custom=unit；System 下拉 service_record/location |
| labelEn | 文本 | **必填**，以字母开头，含字母数字空格 |
| label | 文本 | 可选；若空则用 labelEn 作后备显示 |
| key | 只读（预览） | 由 labelEn 自动生成为 camelCase；写入前检查首字符是字母 |
| type | 下拉 | text / textarea / date / money / select / url |
| group | 下拉（仅 scope=unit） | identity / supply-chain / sales / finance / after-sales / compliance |
| sortOrder | 数字 | 同 group 内按此排序 |
| required / enabled / showInList / indexed | 开关 | |
| options | `OptionsEditor`（仅 type=select） | 表格编辑，必填≥1 行 |

**OptionsEditor 表格**：
- 列：`label`（必填）+ 操作
- `code` 列**不显示**，保存时按 label 自动生成（大写下划线）
- 可增删行；空行保存时抛 `ROBOT_FIELD_OPTION_REQUIRES_CODE_AND_LABEL`

**错误码提示**（按 `error.code` 翻译）：

| Code | 提示 |
|------|------|
| `ROBOT_FIELD_KEY_OR_LABEL_EN_REQUIRED` | "字段的 English Label 必填" |
| `ROBOT_FIELD_KEY_GENERATION_FAILED` | "无法从 Label 生成 key，请用字母英文或手动指定" |
| `ROBOT_FIELD_KEY_MUST_START_WITH_LETTER` | "key 必须以字母开头" |
| `ROBOT_FIELD_GROUP_REQUIRED_FOR_UNIT_SCOPE` | "unit 字段必须指定分组" |
| `ROBOT_FIELD_OPTIONS_REQUIRED_FOR_SELECT` | "select 字段必须提供选项" |
| `ROBOT_FIELD_OPTION_REQUIRES_CODE_AND_LABEL` | "每个选项必须同时有 code 和 label" |
| `ROBOT_FIELD_OPTIONS_ONLY_FOR_SELECT` | "只有 select 字段才能配置选项" |

### 7. 型号 / SKU / 供应商 / 客户 / 位置（`/robot-manager/admin/*`）

共用 `EntityAdminPage` 模板：
- 上方标题 + "新建"按钮
- 中部列表（简单 Table，无高级筛选）
- 点击行或"编辑"打开侧滑抽屉
- 删除二次确认

**SKU 特殊**：新建/编辑需先选 Model；列表可按 modelId 过滤（query string）。

**Location 特殊**：
- 列表显示 `typeCode` 字段
- `typeCode` 下拉来自 System FieldDef `locationType`（scope=location）

### 8. 设备创建（`/robot-manager/create`）

- 最小表单：modelId / skuId（联动）
- 提交后跳转详情页继续补充其余字段
- 创建成功 Toast："设备已创建，FFSN: FF-YYYYMM-XXXXX"

### 9. 帮助（`/robot-manager/help`）

静态 TSX 页面，9 个 Section：
- 角色矩阵
- 业务流（Setup / Lifecycle / Daily Ops）
- 权限矩阵（5 角色 × 18 权限 Table）
- 状态机图（合法转换表）
- 快捷键
- 错误码字典
- 路线图
- 常见问题
- 反馈入口

---

## 通用交互模式

### Loading

- 列表请求中：Skeleton 条（行级）
- 表单提交中：按钮禁用 + 旋转图标
- 全屏 Loading 仅用于首次进入详情页

### Error

- 网络错误：顶部 Banner（5 秒消失）
- 业务错误（400/403/409）：按 `error.code` 查 i18n 字典
- 查不到翻译：fallback 到 `error.message`（英文）
- 500：统一提示"系统错误，请联系管理员"

### Confirm

- 破坏性操作（删除、取消、报废）必须二次确认
- 弹窗文案包含具体对象（如 FFSN）

### Empty State

- 列表空：居中图示 + 指引性按钮（仅有权限时显示）
- 过滤后空：显示"当前条件下无数据，清除筛选"按钮

### Toast

- 成功：3 秒自动消失
- 失败：5 秒；含"详情"链接展开错误堆栈
- 位置：右上角

---

## i18n 规则

- 全部用户可见文案位于 `frontend/src/locales/robot-manager/zh.ts` + `en.ts`
- 错误码翻译归入 `errorCodes.ROBOT_XXX`
- 权限矩阵显示文案统一走 `permissionMatrix.labels`；权限的 ACCESS 数据分离到 `permissionMatrix.access`
- 术语"基础数据"（Master Data），**不使用**"档案"
- 货币符号统一走 `Intl.NumberFormat(locale, { style: 'currency', currency })`，前端不写死 $ / ¥ 符号

---

## 响应式

- 桌面（≥ 1280px）：侧边栏常驻 240px，详情页 Tab 水平排列
- 平板（768-1280px）：侧边栏可折叠，详情 Tab 保持
- 手机（< 768px）：不是主要场景。保证列表页可浏览，详情页降级为单栏 Accordion

---

## 设计系统对齐

- 组件库：`shadcn/ui` + 项目扩展 `ui/*`（与 Lark 风格对齐）
- 字体：系统默认
- 主色：`primary`（蓝色系）；危险：`destructive`（红）；成功：`success`（绿）；警告：`warning`（黄）
- 间距尺度：4px 基数
- 圆角：默认 `md`（6px）

---

## 验收关键点（配合 L3）

| 维度 | 检查项 |
|------|--------|
| 布局 | 与设计稿一致；响应式断点正确 |
| 空数据 | 所有列表/详情的空态文案和指引 |
| 多组织 | 切换组织后数据立刻刷新，无前一组织残留 |
| 角色可见性 | 对照 10-e2e-test-spec.md E2E-RM-014 的菜单矩阵逐项勾选 |
| 极端数据 | 超长文本（中英混合 200 字符）不破版；金额含多位小数/大数位 |
| 0 console error | 全流程开发者工具无 JS 报错 |
| i18n | 每个页面中/英文切换无漏译 |
