# 调压任务模块说明（`src/tasks`）

## 1. 目标

- 管理调压主任务 `Task` 与明细 `TaskItem`。
- 支持状态机流转与事件触发，保证设备压力同步更新。

## 2. 状态机

- 当前发布流程：`PENDING -> ACCEPTED -> COMPLETED`
- 当前工程师撤回流程：`ACCEPTED -> PENDING`
- 当前取消流程：`PENDING/ACCEPTED -> CANCELLED`
- `PENDING` 表示任务已发布，等待本院工程师接收

非法流转会返回 `409` 冲突错误（中文消息）。

## 3. 角色权限

- 系统管理员/医院管理员/医生/主任/组长：发布任务时不再指定工程师，只能取消自己创建的任务
- 工程师：可接收本院 `PENDING` 任务；接收后只能由接收工程师自己完成，或取消接收并退回 `PENDING`
- 其他角色：默认拒绝

补充：

- `GET /b/tasks/engineers`：返回当前角色可见的医院工程师列表，系统管理员可按医院筛选。
- `GET /b/tasks`：返回当前角色可见的调压记录列表，系统管理员可按医院筛选。
- `POST /b/tasks/cancel` 现支持可选 `reason` 字段，便于前端保留取消原因输入。
- 当前取消原因仅透传到事件层，数据库暂未持久化该字段。
- 如果当前设备已经存在 `PENDING / ACCEPTED` 调压任务，则禁止再次发布；同一患者的其他设备不受影响。

## 4. 记录列表

- 后台任务页不再承担手工发布入口，只展示调压记录。
- 记录维度按 `TaskItem` 展开，每条记录会携带：
  - 任务状态
  - 患者信息
  - 手术名称
  - 设备信息
  - 旧压力 / 目标压力 / 当前压力（均为字符串挡位标签）
  - 完成凭证（图片/视频）
  - 创建人 / 接收人 / 发布时间

## 5. 事件触发

状态变化后会发出事件：

- `task.published`
- `task.accepted`
- `task.completed`
- `task.cancelled`

用于后续接入微信通知或消息中心。

## 6. 完成任务时的设备同步

`completeTask` 在单事务中执行：

1. 更新任务状态为 `COMPLETED`
2. 校验至少上传 1 条图片或视频凭证
3. 读取 `TaskItem.targetPressure`
4. 批量更新关联 `Device.currentPressure`

确保任务状态与设备压力一致性。

补充：

- `publishTask` 只负责生成任务和目标挡位，不会立刻修改设备当前压力。
- 只有工程师完成任务后，目标挡位才会回写到设备实例。
- 完成任务时必须上传至少一张图片或一个视频，凭证会保存到 `Task.completionMaterials`。
