基于IoT平台完整5接口(create/confirm/submit/false-alarm/auto-complete), 采用方案A严格模式(IoT回调后再更新告警+卡片)。
198 lines
7.1 KiB
Markdown
198 lines
7.1 KiB
Markdown
# 工单引擎对接 + 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. 根据状态展示:
|
||
- 待处理/处理中:告警截图 + 处理表单(文字输入+拍照+提交)
|
||
- 已完成:告警截图 + 处理后照片 + 描述(只读)
|
||
- 误报:显示"已标记误报"
|
||
|
||
拍照使用 `<input type="file" accept="image/*" capture="environment">`。
|
||
|
||
---
|
||
|
||
### 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 控制,无硬编码密钥
|