diff --git a/docs/superpowers/specs/2026-08-28-command-progress-float-design.md b/docs/superpowers/specs/2026-08-28-command-progress-float-design.md new file mode 100644 index 0000000..853e27e --- /dev/null +++ b/docs/superpowers/specs/2026-08-28-command-progress-float-design.md @@ -0,0 +1,116 @@ +# 监控页指令进度浮窗 + +## 背景 + +监控页快捷控制按钮旁写死「状态:待执行」。下发后只 toast「指令已下发」,领导反馈「指令没有状态」。 + +设备详情 / 操作记录已接入 `/v1/commands`,状态机为: + +`sent → acked | timeout | terminal` + +后端项目:`/Users/qingyuan/CodeProject/laic-backend` + +已核实: + +- `POST /v1/docks/:id/command` 返回完整 `DeviceCommandLog`(含 `id`、`status`) +- `GET /v1/commands/:id` 可查单条 +- `GET /v1/commands` 可查历史 +- 状态枚举:`sent` / `acked` / `timeout` / `terminal` +- 指令单**无**子步骤字段;工作流逐步事件走 MQTT `state/workflow`,本轮不接入 + +本轮不新增后端协议字段。 + +## 目标 + +1. 监控页下发指令后弹出**当前指令进度浮窗**,逐步展示状态。 +2. 与详情页操作记录同一套状态语义。 +3. 同步更新对应控制按钮旁 `small` 文案。 +4. 不打断地图与侧栏主流程。 + +## 非目标 + +- 工作流 PLC 子步骤时间线(开门/归中等)——需另开需求。 +- 批量多选指令。 +- ControlView / 设备详情操作记录大改。 +- 用 WebSocket 替换轮询(可后续增强)。 + +## 方案 + +### 1. 触发与数据流 + +1. 用户确认后调用现有 `devices.sendCommand(rec, title)`。 +2. 取返回体 `cmd.id` / `cmd.status`(axios 已解包 `data`)。 +3. 打开浮窗,初始化步骤: + - 步骤 1:确认下发(本地立即完成) + - 步骤 2:已下发(`sent`) + - 步骤 3:终态(`acked` / `timeout` / `terminal`) +4. 以 `1.5s` 间隔轮询 `GET /v1/commands/:id`,直到终态或超时上限。 +5. 轮询上限:`max(ttlMs, 30000) + 5000`;超时仍未终态则展示「等待超时,请稍后在操作记录查看」。 + +若下发失败(HTTP/业务错误):不进入轮询,仅 toast(与现网一致)。 + +### 2. 浮窗 UI + +- 位置:监控页右下角(避开比例尺),非模态,不挡主操作。 +- 标题:指令中文名(如「一键起飞」)+ 目标设备名。 +- 主体:垂直步骤列表,当前步高亮;完成步打勾;失败/超时用警示色。 +- 副文案: + - `sent`:等待应答 + - `acked`:`ackResultCode` 或「执行成功」 + - `timeout`:已超时 + - `terminal`:`ackResultCode` 或「执行失败」 +- 操作:手动关闭;终态后 **5s** 自动关闭。 +- Escape:关闭浮窗(不取消已下发指令)。 + +同设备再次下发新指令:替换当前浮窗内容与轮询目标(只跟踪最新一条)。 + +### 3. 按钮旁状态 + +监控页已有 `状态:待执行` 的 `small`: + +| 阶段 | 文案 | +|------|------| +| 默认 | 状态:待执行 | +| 下发中 / sent | 状态:已下发 | +| acked | 状态:已确认 | +| timeout | 状态:已超时 | +| terminal | 状态:执行失败 | + +仅更新**本次点击的那颗按钮**(或同 `title` 的按钮);其他按钮保持原状。离开监控页或卸载时清理定时器与浮窗状态。 + +### 4. 实现落点 + +- 主改:`src/views/MonitorView/MonitorView.vue` + - `runCommand` 接收 `sendCommand` 返回值 + - 本地 `commandProgress` 状态 + 轮询 + - 浮窗模板与样式(复用现有视觉 token) +- `src/config/urls.js` 增加 `COMMAND = (id) => `/v1/commands/${id}`` +- `devicesStore.sendCommand` 保持返回后端 `cmd` 对象(已返回,勿吞掉) + +状态映射复用详情页: + +```js +sent → 已下发 / 等待应答 +acked → 已确认 / 执行成功 +timeout → 已超时 +terminal → 执行失败 +``` + +### 5. 权限与错误 + +- `GET /v1/commands/:id` 若 403:停止轮询,浮窗提示无权限查看进度,保留「已下发」。 +- 404:停止轮询并提示。 +- 网络抖动:单次失败不关浮窗,连续失败 3 次再提示。 + +## 验收 + +1. 在线机巢点「打开舱门」:确认后出现浮窗;步骤从确认下发推进到已下发,再至已确认/失败/超时。 +2. 按钮 `small` 同步变化;终态约 5s 后浮窗自动消失,可提前手动关。 +3. 连续点两条指令:浮窗跟踪最新一条。 +4. 设备离线:仍只 toast,不出现成功态浮窗。 +5. 详情页「操作记录」能查到对应指令,状态与浮窗终态一致。 + +## 风险 + +- 后端 ACK 慢或 mock 不回 ACK:浮窗会停在「已下发」直到 timeout —— 符合真实状态机。 +- 工作流多步(起飞准备等)目前只有指令级状态;若领导后续要「开门/归中」子步骤,需后端补步骤事件或前端用 realtime 推断(另开需求)。