diff --git a/docs/plans/2026-03-23-work-order-v2-design.md b/docs/plans/2026-03-23-work-order-v2-design.md new file mode 100644 index 0000000..0b3b72b --- /dev/null +++ b/docs/plans/2026-03-23-work-order-v2-design.md @@ -0,0 +1,197 @@ +# 工单引擎对接 + H5 工单详情页 实施计划(v2) + +> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. + +**Goal:** 打通 告警→IoT工单→企微卡片→保安处理→H5提交→IoT结单→告警状态同步 的完整闭环。 + +**Architecture:** vsp-service 作为企微通知网关,IoT 平台作为工单状态权威源。告警触发后 vsp-service 调 IoT 创建工单,IoT 派单后回调 vsp-service 发企微卡片。保安通过卡片按钮做简单操作(确认/误报),通过 H5 详情页做复杂操作(描述+图片)。所有状态变更走 IoT → 回调 vsp-service 同步告警+卡片。 + +**Tech Stack:** Python/FastAPI, Vue 3/Ant Design Vue, 企微 JS-SDK/OAuth2, work_order_client (SHA256签名) + +--- + +## IoT 平台开放接口(vsp-service 调用) + +| 接口 | 路径 | 必填参数 | 可选参数 | +|------|------|---------|---------| +| 创建工单 | `POST /open-api/.../create` | title, areaId | description, priority, alarmId, alarmType, cameraId, roiId, imageUrl, sourceType | +| 确认工单 | `POST /open-api/.../confirm` | orderId | | +| 工单提交 | `POST /open-api/.../submit` | orderId, result | resultImgUrls | +| 误报标记 | `POST /open-api/.../false-alarm` | orderId | | +| 自动完单 | `POST /open-api/.../auto-complete` | orderId | remark | + +## vsp-service 提供给 IoT 的接口 + +| 接口 | 入参 | 用途 | +|------|------|------| +| `POST /api/wechat/notify/send-card` | alarmId, orderId, userIds[], title, areaName, cameraName, eventTime, level, snapshotUrl | IoT 派单后调用,发企微工单卡片 | +| `POST /api/wechat/notify/sync-status` | alarmId, orderId, status(confirmed/completed/false_alarm/auto_resolved), operator, remark | IoT 状态变更后调用,同步告警+卡片 | + +## 完整流程 + +``` +边缘告警 → vsp-service VLM复核 → 调IoT /create(拿到orderId) + → IoT自动派单 → IoT调 vsp-service /send-card → 发企微卡片 + +卡片按钮:[确认处理] [误报忽略] | 点击卡片整体 → H5详情页 + +点[确认处理]: + → vsp-service 调 IoT /confirm + → IoT 回调 /sync-status(status=confirmed) + → 更新告警CONFIRMED + 卡片重绘"已接单,请点击卡片提交处理结果" + +点[误报忽略]: + → vsp-service 调 IoT /false-alarm + → IoT 回调 /sync-status(status=false_alarm) + → 更新告警FALSE + 卡片终态"已忽略" + +H5提交处理结果: + → 上传图片到COS → 调 vsp-service → vsp-service 调 IoT /submit + → IoT 回调 /sync-status(status=completed) + → 更新告警CLOSED + 卡片终态"已处理" + +边缘端告警自动解除: + → vsp-service 调 IoT /auto-complete + → IoT 回调 /sync-status(status=auto_resolved) + → 更新告警 + 卡片终态"系统自动结单" +``` + +--- + +### Task 1: work_order_client 补充 3 个新方法 + +**Files:** +- Modify: `iot-device-management-service/app/services/work_order_client.py` + +在现有 `create_order` 和 `auto_complete_order` 基础上,新增: +- `confirm_order(orderId)` → `POST /confirm` +- `submit_order(orderId, result, resultImgUrls=[])` → `POST /submit` +- `false_alarm(orderId)` → `POST /false-alarm` + +签名逻辑复用现有的 `_sign` 和 `_build_headers`。 + +--- + +### Task 2: work_order_client 初始化启用 + +**Files:** +- Modify: `iot-device-management-service/app/main.py` + +取消 `work_order_client` 初始化的注释,从 `.env` 读取配置。 + +--- + +### Task 3: notify_dispatch 启用工单创建 + +**Files:** +- Modify: `iot-device-management-service/app/services/notify_dispatch.py` + +VLM 复核通过后: +1. 调 `wo_client.create_order()` 创建工单 +2. 存 orderId 到 `alarm_event_ext`(ext_type=WORK_ORDER) +3. 企微通知正常发送(后续改为由 IoT 回调触发) + +--- + +### Task 4: 新增 IoT 回调接口(send-card + sync-status) + +**Files:** +- Create: `iot-device-management-service/app/routers/wechat_notify_api.py` +- Modify: `iot-device-management-service/app/main.py`(注册路由) + +``` +POST /api/wechat/notify/send-card + → 接收 IoT 派单通知 → 发企微工单卡片给指定 userIds + +POST /api/wechat/notify/sync-status + → 接收 IoT 状态变更 → 更新告警状态 + 更新企微卡片 + → status 映射: + confirmed → 告警CONFIRMED + 卡片重绘"已接单,请点击卡片提交处理结果" + completed → 告警CLOSED + 卡片终态"已处理" + false_alarm → 告警FALSE + 卡片终态"已忽略" + auto_resolved → 告警CLOSED + 卡片终态"系统自动结单" +``` + +--- + +### Task 5: 卡片按钮回调改造(调 IoT 而非直接更新) + +**Files:** +- Modify: `iot-device-management-service/app/routers/wechat_callback.py` + +方案A严格模式: +- 点[确认处理] → 调 IoT /confirm → 等 IoT 回调 sync-status 再更新 +- 点[误报忽略] → 调 IoT /false-alarm → 等 IoT 回调 sync-status 再更新 + +卡片按钮简化为一步(去掉 step2 的第二轮按钮)。 + +--- + +### Task 6: 卡片样式调整 + card_action.url + +**Files:** +- Modify: `iot-device-management-service/app/services/wechat_service.py` + +1. `_alarm_detail_url` 改为 H5 工单页:`/work-order?alarmId={alarm_id}` +2. 卡片按钮只保留 [确认处理] [误报忽略] +3. 确认后卡片重绘提示:"已接单,请点击卡片提交处理结果" +4. 去掉 `update_alarm_card_step2` 中的第二轮交互按钮 + +--- + +### Task 7: 后端 — H5 工单处理 API + +**Files:** +- Create: `iot-device-management-service/app/routers/work_order_api.py` +- Modify: `iot-device-management-service/app/main.py`(注册路由) + +``` +GET /api/work-order/detail?alarmId={alarmId} + → 返回告警信息 + orderId + 工单状态 + 截图URL + +POST /api/work-order/submit + Body: {alarmId, result, resultImgUrls?} + → 查 orderId → 调 IoT /submit → 等 IoT 回调同步状态 + +POST /api/work-order/upload-image + Body: multipart/form-data + → 上传到 COS → 返回永久 URL +``` + +--- + +### Task 8: 前端 — H5 工单详情页 + +**Files:** +- Create: `iot-device-management-frontend/apps/web-antd/src/views/work-order/index.vue` + +页面逻辑: +1. 从 URL 参数获取 alarmId +2. 调 `/api/work-order/detail` 获取信息 +3. 根据状态展示: + - 待处理/处理中:告警截图 + 处理表单(文字输入+拍照+提交) + - 已完成:告警截图 + 处理后照片 + 描述(只读) + - 误报:显示"已标记误报" + +拍照使用 ``。 + +--- + +### Task 9: 前端 — 路由配置 + +**Files:** +- 添加 `/work-order` 路由,使用空布局(无侧边栏无顶栏) +- 不需要登录(通过企微 OAuth2 或 alarmId 鉴权) + +--- + +## 验证清单 + +- [ ] 边缘告警 → VLM复核 → IoT工单创建成功 +- [ ] IoT 回调 send-card → 企微卡片正确发送 +- [ ] 点[确认处理] → 调IoT confirm → 回调更新告警+卡片 +- [ ] 点[误报忽略] → 调IoT false-alarm → 回调更新告警+卡片终态 +- [ ] H5 详情页展示告警信息和工单状态 +- [ ] H5 提交描述+图片 → 调IoT submit → 回调更新告警+卡片终态 +- [ ] 边缘端告警解除 → 调IoT auto-complete → 回调更新告警+卡片终态 +- [ ] 所有配置通过 .env 控制,无硬编码密钥