forked from erp-dev/erp
feat: notifier beta
This commit is contained in:
437
docs/api_v2_mission_api.md
Normal file
437
docs/api_v2_mission_api.md
Normal file
@@ -0,0 +1,437 @@
|
||||
# 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,
|
||||
"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,
|
||||
"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": "已处理",
|
||||
"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"
|
||||
}
|
||||
```
|
||||
|
||||
## 任务分类列表
|
||||
|
||||
- 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` 同时提供或同时省略 |
|
||||
| `participant_ids` | int[] | 否 | 参与者员工 ID 列表,必须属于当前商户 |
|
||||
|
||||
说明:
|
||||
|
||||
- `creator`、`merchant` 由当前登录用户的 employee 自动写入
|
||||
- `category_name` 为只读字段,由后端根据分类表返回
|
||||
- `is_urgent`、`is_completed`、`is_cancelled` 均按默认值创建,不接受请求参数
|
||||
- 若关联对象存在 `merchant_id` 字段,后端会校验它必须属于当前商户
|
||||
|
||||
请求示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"description": "跟进客户问题",
|
||||
"category": 1,
|
||||
"participant_ids": [21, 22]
|
||||
}
|
||||
```
|
||||
|
||||
成功响应:`201 Created`,返回 `Mission`
|
||||
|
||||
## 任务详情
|
||||
|
||||
- URL: `/api/v2/missions/<mission_id>/`
|
||||
- Method: `GET`
|
||||
|
||||
成功响应:`Mission`
|
||||
|
||||
跨商户访问返回 `404`
|
||||
|
||||
## 更新任务
|
||||
|
||||
- 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` 同时提供 |
|
||||
| `participant_ids` | int[] | 重置参与者列表 |
|
||||
|
||||
禁止更新状态字段,见“基本约定”
|
||||
|
||||
成功响应:`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` |
|
||||
|
||||
说明:
|
||||
|
||||
- `responder` 使用当前登录用户的 employee
|
||||
- 如果 `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`
|
||||
Reference in New Issue
Block a user