forked from erp-dev/erp
647 lines
18 KiB
Markdown
647 lines
18 KiB
Markdown
# API v2 Mission 任务模块接口文档
|
||
|
||
本文档面向前端,描述 `mission` 中立任务模块的 API。
|
||
|
||
## 基本约定
|
||
|
||
- Base URL: `/api/v2`
|
||
- 认证:所有接口都需要登录。
|
||
- 人员身份:后端使用 `request.user.employee` 作为当前员工身份。
|
||
- 多商户隔离:所有任务、任务分类、参与者、回应都只允许访问当前员工所属商户的数据。
|
||
- 删除能力:不提供任务删除接口;需要结束业务时使用 `cancel` 取消任务。
|
||
- 状态字段:普通创建/更新接口不允许修改状态字段,状态变化统一走独立接口。
|
||
|
||
普通 CRUD 禁止提交这些字段:
|
||
|
||
| 字段 | 说明 |
|
||
|------|------|
|
||
| `is_urgent` | 是否紧急,使用 `set-urgent` 接口修改 |
|
||
| `is_completed` | 是否完成,由结束回应或 reopen/reject 流程维护 |
|
||
| `is_cancelled` | 是否取消,使用 `cancel` 接口修改 |
|
||
| `cancelled_by` | 取消人,由后端写入 |
|
||
| `cancelled_at` | 取消时间,由后端写入 |
|
||
| `rejected_by` | 撤销人,由后端写入 |
|
||
| `rejected_at` | 撤销时间,由后端写入 |
|
||
|
||
说明:
|
||
|
||
- 本次新增的“未回复提醒配置字段”不属于状态字段,允许通过普通创建/更新接口维护
|
||
|
||
## content_type 说明
|
||
|
||
`content_type` 和 `content_id` 是可选的"关联业务对象"字段,用于把任务挂靠到系统中的某个具体业务单据或对象上。
|
||
|
||
### content_type 是什么
|
||
|
||
`content_type` 是一个整数,对应后端数据库 `django_content_type` 表的主键(`id`)。
|
||
该表记录了系统中所有 Django 模型的元信息,每一行代表一个模型,格式为 `app_label` + `model`。
|
||
|
||
**前端不应硬编码 content_type 整数 ID**,因为这个 ID 在不同部署环境中可能不同。
|
||
正确做法:调用 `/api/v2/content-types/` 接口(见下方"查询可用 content_type"一节)获取当前环境的实际 ID。
|
||
|
||
### content_type_label 字段
|
||
|
||
响应体中的 `content_type_label` 字段是人类可读的模型标识,格式为 `"app_label.model"`,例如:
|
||
|
||
- `"printing.plateorder"` — 开版单
|
||
- `"printing.printingjob"` — 印刷任务
|
||
- `"business.purchaseorder"` — 采购单
|
||
|
||
该字段**只读**,用于前端展示或调试,不作为提交 content_type 时的值。
|
||
|
||
### 当前系统中可关联的主要业务对象
|
||
|
||
| `content_type_label` | 中文说明 |
|
||
|---|---|
|
||
| `printing.plateorder` | 开版单 |
|
||
| `printing.printingorder` | 印刷单 |
|
||
| `printing.printingjob` | 印刷任务 |
|
||
| `business.purchaseorder` | 采购单 |
|
||
| `business.presalesorder` | 预销售单 |
|
||
| `business.salesorder` | 销售单 |
|
||
| `business.prepurchaseorder` | 预采购单 |
|
||
| `business.purchasereturnorder` | 采购退货单 |
|
||
| `business.salesreturnorder` | 销售退货单 |
|
||
| `business.paymentorder` | 付款单 |
|
||
| `business.receiptorder` | 收款单 |
|
||
| `stock.transferorder` | 调拨单 |
|
||
| `shipment.shipment` | 发货单 |
|
||
| `stateflow.process` | 工艺流程实例 |
|
||
|
||
> 上述列表是"有意义的"业务关联对象;系统本身不限制可关联的模型类型,技术上任何有效 ContentType ID 都被接受。
|
||
|
||
### 查询可用 content_type
|
||
|
||
- URL: `/api/v2/content-types/`
|
||
- Method: `GET`
|
||
|
||
响应示例:
|
||
|
||
```json
|
||
[
|
||
{"id": 7, "app_label": "business", "model": "paymentorder", "label": "business.paymentorder", "name": "付款单"},
|
||
{"id": 8, "app_label": "business", "model": "presalesorder", "label": "business.presalesorder", "name": "预销售单"},
|
||
...
|
||
]
|
||
```
|
||
|
||
前端应在运行时调用此接口获取 `id`,不应硬编码,因为不同部署环境的 ID 可能不同。
|
||
|
||
## 数据结构
|
||
|
||
### MissionCategory
|
||
|
||
```json
|
||
{
|
||
"id": 1,
|
||
"merchant": 10,
|
||
"name": "通用",
|
||
"created_at": "2026-04-10T12:00:00+08:00",
|
||
"updated_at": "2026-04-10T12:00:00+08:00"
|
||
}
|
||
```
|
||
|
||
### Mission
|
||
|
||
```json
|
||
{
|
||
"id": 1,
|
||
"merchant": 10,
|
||
"description": "跟进客户问题",
|
||
"category": 1,
|
||
"category_name": "通用",
|
||
"is_urgent": false,
|
||
"is_completed": false,
|
||
"is_cancelled": false,
|
||
"notify_if_unreplied": false,
|
||
"unreplied_notify_interval_minutes": null,
|
||
"unreplied_notify_max_count": 5,
|
||
"unreplied_notify_sent_count": 0,
|
||
"unreplied_last_notified_at": null,
|
||
"cancelled_at": null,
|
||
"creator": {
|
||
"id": 20,
|
||
"name": "张三",
|
||
"merchant_id": 10
|
||
},
|
||
"cancelled_by": null,
|
||
"participants": [
|
||
{
|
||
"id": 21,
|
||
"name": "李四",
|
||
"merchant_id": 10
|
||
}
|
||
],
|
||
"content_type": null,
|
||
"content_type_label": null,
|
||
"content_id": null,
|
||
"extra": {
|
||
"source": "wechat",
|
||
"ticket_no": "TK-001"
|
||
},
|
||
"has_ending_reply": false,
|
||
"can_reply": true,
|
||
"created_at": "2026-04-10T12:00:00+08:00",
|
||
"updated_at": "2026-04-10T12:00:00+08:00"
|
||
}
|
||
```
|
||
|
||
### MissionReply
|
||
|
||
```json
|
||
{
|
||
"id": 100,
|
||
"mission": 1,
|
||
"merchant": 10,
|
||
"responder": {
|
||
"id": 20,
|
||
"name": "张三",
|
||
"merchant_id": 10
|
||
},
|
||
"content": "已处理",
|
||
"extra": {
|
||
"attachment_ids": [1001, 1002]
|
||
},
|
||
"replied_at": "2026-04-10T12:10:00+08:00",
|
||
"ends_task": true,
|
||
"is_rejected": false,
|
||
"rejected_by": null,
|
||
"rejected_at": null,
|
||
"created_at": "2026-04-10T12:10:00+08:00",
|
||
"updated_at": "2026-04-10T12:10:00+08:00"
|
||
}
|
||
```
|
||
|
||
### MissionWithReplies
|
||
|
||
在 `Mission` 结构基础上,额外返回 `replies` 字段:
|
||
|
||
```json
|
||
{
|
||
"id": 1,
|
||
"merchant": 10,
|
||
"description": "跟进客户问题",
|
||
"category": 1,
|
||
"category_name": "通用",
|
||
"is_urgent": false,
|
||
"is_completed": false,
|
||
"is_cancelled": false,
|
||
"notify_if_unreplied": false,
|
||
"unreplied_notify_interval_minutes": null,
|
||
"unreplied_notify_max_count": 5,
|
||
"unreplied_notify_sent_count": 0,
|
||
"unreplied_last_notified_at": null,
|
||
"cancelled_at": null,
|
||
"creator": {
|
||
"id": 20,
|
||
"name": "张三",
|
||
"merchant_id": 10
|
||
},
|
||
"cancelled_by": null,
|
||
"participants": [],
|
||
"content_type": 33,
|
||
"content_type_label": "printing.printingorder",
|
||
"content_id": 123,
|
||
"extra": {
|
||
"source": "printing-order"
|
||
},
|
||
"has_ending_reply": false,
|
||
"can_reply": true,
|
||
"created_at": "2026-04-10T12:00:00+08:00",
|
||
"updated_at": "2026-04-10T12:00:00+08:00",
|
||
"replies": [
|
||
{
|
||
"id": 100,
|
||
"mission": 1,
|
||
"merchant": 10,
|
||
"responder": {
|
||
"id": 20,
|
||
"name": "张三",
|
||
"merchant_id": 10
|
||
},
|
||
"content": "已处理",
|
||
"extra": {
|
||
"attachment_ids": [1001, 1002]
|
||
},
|
||
"replied_at": "2026-04-10T12:10:00+08:00",
|
||
"ends_task": false,
|
||
"is_rejected": false,
|
||
"rejected_by": null,
|
||
"rejected_at": null,
|
||
"created_at": "2026-04-10T12:10:00+08:00",
|
||
"updated_at": "2026-04-10T12:10:00+08:00"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
### MissionLite
|
||
|
||
用于按印花订单查询任务时的轻量响应结构,不返回参与者、结束回应状态和回复列表:
|
||
|
||
```json
|
||
{
|
||
"id": 1,
|
||
"merchant": 10,
|
||
"description": "跟进客户问题",
|
||
"category": 1,
|
||
"category_name": "通用",
|
||
"is_urgent": false,
|
||
"is_completed": false,
|
||
"is_cancelled": false,
|
||
"notify_if_unreplied": false,
|
||
"unreplied_notify_interval_minutes": null,
|
||
"unreplied_notify_max_count": 5,
|
||
"unreplied_notify_sent_count": 0,
|
||
"unreplied_last_notified_at": null,
|
||
"cancelled_at": null,
|
||
"creator": {
|
||
"id": 20,
|
||
"name": "张三",
|
||
"merchant_id": 10
|
||
},
|
||
"cancelled_by": null,
|
||
"content_type": 33,
|
||
"content_type_label": "printing.printingorder",
|
||
"content_id": 123,
|
||
"extra": {
|
||
"source": "printing-order"
|
||
},
|
||
"created_at": "2026-04-10T12:00:00+08:00",
|
||
"updated_at": "2026-04-10T12:00:00+08:00"
|
||
}
|
||
```
|
||
|
||
## 任务分类列表
|
||
|
||
- URL: `/api/v2/mission-categories/`
|
||
- Method: `GET`
|
||
|
||
响应:`MissionCategory[]`
|
||
|
||
## 创建任务分类
|
||
|
||
- URL: `/api/v2/mission-categories/`
|
||
- Method: `POST`
|
||
|
||
请求参数:
|
||
|
||
| 参数 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|
|
||
| `name` | string | 是 | 分类名称,同商户下唯一 |
|
||
|
||
请求示例:
|
||
|
||
```json
|
||
{
|
||
"name": "售后"
|
||
}
|
||
```
|
||
|
||
成功响应:`201 Created`,返回 `MissionCategory`
|
||
|
||
## 任务分类详情
|
||
|
||
- URL: `/api/v2/mission-categories/<category_id>/`
|
||
- Method: `GET`
|
||
|
||
成功响应:`MissionCategory`
|
||
|
||
## 更新任务分类
|
||
|
||
- URL: `/api/v2/mission-categories/<category_id>/`
|
||
- Method: `PATCH`
|
||
|
||
允许更新:
|
||
|
||
| 参数 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| `name` | string | 分类名称,同商户下唯一 |
|
||
|
||
成功响应:`MissionCategory`
|
||
|
||
## 删除任务分类
|
||
|
||
- URL: `/api/v2/mission-categories/<category_id>/`
|
||
- Method: `DELETE`
|
||
|
||
说明:
|
||
|
||
- 如果该分类已经被任务使用,则删除会被拒绝,返回 `400`
|
||
|
||
成功响应:`204 No Content`
|
||
|
||
## 任务列表
|
||
|
||
- URL: `/api/v2/missions/`
|
||
- Method: `GET`
|
||
|
||
查询参数:
|
||
|
||
| 参数 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| `category` | int | 任务分类 ID |
|
||
| `is_urgent` | boolean | `true` / `false` |
|
||
| `is_completed` | boolean | `true` / `false` |
|
||
| `is_cancelled` | boolean | `true` / `false` |
|
||
| `content_type` | int | Django ContentType ID |
|
||
| `content_id` | int | 关联业务对象 ID |
|
||
|
||
响应:`Mission[]`
|
||
|
||
## 创建任务
|
||
|
||
- URL: `/api/v2/missions/`
|
||
- Method: `POST`
|
||
|
||
请求参数:
|
||
|
||
| 参数 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|
|
||
| `description` | string | 是 | 任务描述 |
|
||
| `category` | int | 否 | 任务分类 ID;不传时默认使用当前商户下名称为“通用”的分类,不存在则自动创建 |
|
||
| `content_type` | int/null | 否 | Django ContentType ID;必须与 `content_id` 同时提供或同时省略 |
|
||
| `content_id` | int/null | 否 | 关联业务对象 ID;必须与 `content_type` 同时提供或同时省略 |
|
||
| `extra` | object/null | 否 | 任务扩展字段,原样保存为 JSON;可传 `null` |
|
||
| `notify_if_unreplied` | boolean | 否 | 是否开启“未回复持续提醒”,默认 `false` |
|
||
| `unreplied_notify_interval_minutes` | int/null | 否 | 未回复提醒间隔(分钟);开启未回复提醒时必填 |
|
||
| `unreplied_notify_max_count` | int | 否 | 最大提醒次数,默认 `5` |
|
||
| `participant_ids` | int[] | 否 | 参与者员工 ID 列表,必须属于当前商户 |
|
||
|
||
说明:
|
||
|
||
- `creator`、`merchant` 由当前登录用户的 employee 自动写入
|
||
- `category_name` 为只读字段,由后端根据分类表返回
|
||
- `is_urgent`、`is_completed`、`is_cancelled` 均按默认值创建,不接受请求参数
|
||
- 若关联对象存在 `merchant_id` 字段,后端会校验它必须属于当前商户
|
||
- 若 `notify_if_unreplied=true`,则必须同时传入 `unreplied_notify_interval_minutes`
|
||
- `unreplied_notify_sent_count` 与 `unreplied_last_notified_at` 为只读运行时字段,由后端维护
|
||
|
||
请求示例:
|
||
|
||
```json
|
||
{
|
||
"description": "跟进客户问题",
|
||
"category": 1,
|
||
"extra": {
|
||
"source": "wechat",
|
||
"ticket_no": "TK-001"
|
||
},
|
||
"notify_if_unreplied": true,
|
||
"unreplied_notify_interval_minutes": 30,
|
||
"unreplied_notify_max_count": 5,
|
||
"participant_ids": [21, 22]
|
||
}
|
||
```
|
||
|
||
成功响应:`201 Created`,返回 `Mission`
|
||
|
||
## 任务详情
|
||
|
||
- URL: `/api/v2/missions/<mission_id>/`
|
||
- Method: `GET`
|
||
|
||
成功响应:`Mission`
|
||
|
||
跨商户访问返回 `404`
|
||
|
||
## 按印花订单查询任务及回复
|
||
|
||
- URL: `/api/v2/missions/by-printing-order/<printing_order_id>/`
|
||
- Method: `GET`
|
||
|
||
查询参数:
|
||
|
||
| 参数 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| `category_ids` | int[] / comma-separated string | 可选任务分类筛选。支持重复参数 `?category_ids=1&category_ids=2`,也支持逗号分隔 `?category_ids=1,2` |
|
||
| `include_details` | boolean | 是否返回完整详情,默认 `true`。传 `false` 时返回轻量结构,不带 `participants`、`has_ending_reply`、`can_reply`、`replies` |
|
||
|
||
说明:
|
||
|
||
- 只查询 `content_type=printing.printingorder` 且 `content_id=<printing_order_id>` 的任务
|
||
- 只返回当前登录员工所属商户下的任务
|
||
- `include_details=true` 时返回 `MissionWithReplies[]`
|
||
- `include_details=false` 时返回 `MissionLite[]`
|
||
- 完整模式下每个任务会内嵌其全部回复,按 `replied_at`、`id` 升序返回
|
||
- `Mission.extra` 与 `MissionReply.extra` 都会原样返回
|
||
- 该接口启用了 180 秒的低层缓存;缓存键会区分当前商户、`printing_order_id`、`category_ids`、`include_details`
|
||
- 在缓存有效期内,如果任务、参与者或回复刚发生变化,接口结果最多可能延迟约 3 分钟刷新
|
||
- 若该 `printing_order_id` 不属于当前商户,返回 `404`
|
||
|
||
请求示例:
|
||
|
||
```http
|
||
GET /api/v2/missions/by-printing-order/123/
|
||
GET /api/v2/missions/by-printing-order/123/?category_ids=1,2
|
||
GET /api/v2/missions/by-printing-order/123/?include_details=false
|
||
GET /api/v2/missions/by-printing-order/123/?category_ids=2&include_details=false
|
||
```
|
||
|
||
成功响应:
|
||
|
||
- `include_details=true`:`MissionWithReplies[]`
|
||
- `include_details=false`:`MissionLite[]`
|
||
|
||
## 更新任务
|
||
|
||
- URL: `/api/v2/missions/<mission_id>/`
|
||
- Method: `PATCH`
|
||
|
||
允许更新:
|
||
|
||
| 参数 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| `description` | string | 任务描述 |
|
||
| `category` | int | 任务分类 ID |
|
||
| `content_type` | int/null | 关联对象类型;必须与 `content_id` 同时提供 |
|
||
| `content_id` | int/null | 关联对象 ID;必须与 `content_type` 同时提供 |
|
||
| `extra` | object/null | 任务扩展字段,原样保存为 JSON;可传 `null` |
|
||
| `notify_if_unreplied` | boolean | 是否开启“未回复持续提醒” |
|
||
| `unreplied_notify_interval_minutes` | int/null | 未回复提醒间隔(分钟) |
|
||
| `unreplied_notify_max_count` | int | 最大提醒次数 |
|
||
| `participant_ids` | int[] | 重置参与者列表 |
|
||
|
||
禁止更新状态字段,见“基本约定”
|
||
|
||
补充说明:
|
||
|
||
- 更新 `notify_if_unreplied`、`unreplied_notify_interval_minutes` 时,后端会重置当前任务的未回复提醒计数与上次提醒时间
|
||
- 更新 `unreplied_notify_max_count` 不会重置已提醒次数
|
||
|
||
成功响应:`Mission`
|
||
|
||
## 删除任务
|
||
|
||
- URL: `/api/v2/missions/<mission_id>/`
|
||
- Method: `DELETE`
|
||
|
||
当前不提供删除能力,固定返回:
|
||
|
||
```json
|
||
{
|
||
"detail": "Mission 删除接口未提供,请使用 cancel 接口取消任务"
|
||
}
|
||
```
|
||
|
||
HTTP 状态码:`405 Method Not Allowed`
|
||
|
||
## 获取任务回应列表
|
||
|
||
- URL: `/api/v2/missions/<mission_id>/replies/`
|
||
- Method: `GET`
|
||
|
||
查询参数:
|
||
|
||
| 参数 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| `ends_task` | boolean | `true` / `false`,筛选是否为结束回应 |
|
||
| `is_rejected` | boolean | `true` / `false`,筛选是否已被撤销 |
|
||
|
||
响应:`MissionReply[]`,按 `replied_at` 升序排列
|
||
|
||
## 创建任务回应
|
||
|
||
- URL: `/api/v2/missions/<mission_id>/replies/`
|
||
- Method: `POST`
|
||
|
||
请求参数:
|
||
|
||
| 参数 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|
|
||
| `content` | string | 是 | 回应内容 |
|
||
| `ends_task` | boolean | 否 | 是否结束任务,默认 `false` |
|
||
| `extra` | object/null | 否 | 回应扩展字段,原样保存为 JSON;可传 `null` |
|
||
|
||
说明:
|
||
|
||
- `responder` 使用当前登录用户的 employee
|
||
- `extra` 由后端原样存储并原样返回,不做结构校验
|
||
- 如果 `ends_task=true`,后端会同步设置 `Mission.is_completed=true`
|
||
- 已取消任务、或已有有效结束回应的任务不允许继续回应
|
||
|
||
成功响应:`201 Created`,返回 `MissionReply`
|
||
|
||
## 重新打开任务
|
||
|
||
- URL: `/api/v2/missions/<mission_id>/reopen/`
|
||
- Method: `POST`
|
||
- 额外权限:`mission.reopen_mission`
|
||
|
||
请求体可为空:
|
||
|
||
```json
|
||
{}
|
||
```
|
||
|
||
前置条件:
|
||
|
||
- 当前用户必须具备 `mission.reopen_mission`
|
||
- 任务未取消
|
||
- 任务已完成
|
||
- 任务存在有效的 `ends_task=true` 回应
|
||
|
||
执行效果:
|
||
|
||
- `Mission.is_completed=false`
|
||
- 相关结束回应被标记为 `ends_task=false`
|
||
- 相关结束回应记录 `is_rejected=true`、`rejected_by=当前员工`、`rejected_at=当前时间`
|
||
|
||
成功响应:`Mission`
|
||
|
||
无权限响应:`403 Forbidden`
|
||
|
||
## 取消任务
|
||
|
||
- URL: `/api/v2/missions/<mission_id>/cancel/`
|
||
- Method: `POST`
|
||
|
||
请求体可为空:
|
||
|
||
```json
|
||
{}
|
||
```
|
||
|
||
执行效果:
|
||
|
||
- `Mission.is_cancelled=true`
|
||
- `Mission.cancelled_by=当前员工`
|
||
- `Mission.cancelled_at=当前时间`
|
||
- 不强行修改 `Mission.is_completed`
|
||
- 后端会停止当前任务后续的未回复提醒,并保留任务上的提醒历史字段供查看
|
||
|
||
成功响应:`Mission`
|
||
|
||
## 设置紧急状态
|
||
|
||
- URL: `/api/v2/missions/<mission_id>/set-urgent/`
|
||
- Method: `POST`
|
||
|
||
请求参数:
|
||
|
||
| 参数 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|
|
||
| `is_urgent` | boolean | 是 | 新的紧急状态 |
|
||
|
||
请求示例:
|
||
|
||
```json
|
||
{
|
||
"is_urgent": true
|
||
}
|
||
```
|
||
|
||
成功响应:`Mission`
|
||
|
||
## 撤销任务回应
|
||
|
||
- URL: `/api/v2/mission-replies/<reply_id>/reject/`
|
||
- Method: `POST`
|
||
- 额外权限:`mission.reject_mission_reply`
|
||
|
||
请求体可为空:
|
||
|
||
```json
|
||
{}
|
||
```
|
||
|
||
执行效果:
|
||
|
||
- 当前回应标记为 `is_rejected=true`
|
||
- 当前回应的 `rejected_by`、`rejected_at` 由后端写入
|
||
- 如果当前回应原本是唯一有效的结束回应,则对应任务会被重新置为未完成
|
||
- 如果任务重新回到“没有任何有效回复”的状态,后端会重置未回复提醒计数,并从新的空窗期重新开始计算后续提醒
|
||
|
||
成功响应:`MissionReply`
|
||
|
||
无权限响应:`403 Forbidden`
|
||
|
||
## 未回复提醒规则
|
||
|
||
当任务开启 `notify_if_unreplied=true` 时,系统会通过每分钟一次的后台定时任务检查是否需要发送“未回复提醒”。
|
||
|
||
判定规则:
|
||
|
||
1. 任务开启了未回复提醒
|
||
2. 任务未完成
|
||
3. 任务未取消
|
||
4. 任务当前没有任何有效回复(`is_rejected=false` 的回复)
|
||
5. `unreplied_notify_sent_count < unreplied_notify_max_count`
|
||
6. 到达提醒时间:
|
||
- 从未提醒过:`created_at + unreplied_notify_interval_minutes`
|
||
- 已提醒过:`unreplied_last_notified_at + unreplied_notify_interval_minutes`
|
||
|
||
发送成功后:
|
||
|
||
- `unreplied_notify_sent_count` 自增 1
|
||
- `unreplied_last_notified_at` 更新为本次成功发送时间
|
||
|
||
收到有效回复后:
|
||
|
||
- 当前未回复提醒周期会被停止
|
||
- `unreplied_notify_sent_count` 与 `unreplied_last_notified_at` 会被重置
|
||
|
||
如果后续因为撤销回复或 reopen 重新回到“无有效回复”状态:
|
||
|
||
- 系统会把该任务视为一个新的未回复周期重新开始计时
|