1
0
forked from erp-dev/erp
Files
erpnew/docs/api_v2_mission_api.md
2026-07-05 13:53:17 +08:00

19 KiB
Raw Permalink Blame History

Mission 任务模块 API 文档

更新日期2026-07-03

本文档面向前端,描述 mission 中立任务模块的对外 API。当前 mission API 仅在 api_v2 提供;已检查 api_v1/urls.pyapi_v1 暂无 mission 相关接口。

1. 基本约定

  • Base URL: /api/v2
  • 认证:所有 mission 接口均需要登录。
  • 当前员工:后端使用 request.user.employee 作为当前业务员工。
  • 商户隔离:任务、任务分类、参与者、回应均按当前员工所属 merchant 隔离。
  • 参与者对象:任务参与者是 basic_info.Employee,不是 Django User
  • 删除任务:不提供物理删除任务接口;业务结束请使用取消接口。
  • 普通创建/更新接口不允许直接修改状态字段,状态变化必须走独立状态接口。

普通创建/更新禁止提交字段:

字段 说明
is_urgent 是否紧急,使用 set-urgent 接口修改
is_completed 是否完成由结束回应、reopen、reject 流程维护
is_cancelled 是否取消,使用 cancel 接口修改
cancelled_by 取消人,由后端写入
cancelled_at 取消时间,由后端写入
rejected_by 回应撤销人,由后端写入
rejected_at 回应撤销时间,由后端写入

2. API v1 状态

已检查 api_v1/urls.pyapi_v1/views,当前没有 mission 模块接口。

如前端需要任务模块,请使用本文档中的 /api/v2/... 接口。

3. 核心数据结构

3.1 EmployeePayload

任务模块中所有人员字段均使用员工对象摘要:

{
  "id": 21,
  "name": "李四",
  "merchant_id": 10
}

3.2 MissionCategory

{
  "id": 1,
  "merchant": 10,
  "name": "通用",
  "payload_processor": "",
  "speech_enabled": false,
  "created_at": "2026-07-03T10:00:00+08:00",
  "updated_at": "2026-07-03T10:00:00+08:00"
}

字段说明:

字段 类型 说明
id number 任务分类 ID
merchant number 所属商户 ID
name string 分类名称,同商户内唯一
payload_processor string payload 增强器,可为空;当前可选 structured_description_v1
speech_enabled boolean 是否启用任务播报
created_at string 创建时间
updated_at string 更新时间

3.3 Mission

{
  "id": 1,
  "merchant": 10,
  "description": "请跟进这张生产单",
  "category": 1,
  "category_name": "通用",
  "is_urgent": false,
  "is_completed": false,
  "is_cancelled": false,
  "notify_if_unreplied": true,
  "unreplied_notify_interval_minutes": 30,
  "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": 33,
  "content_type_label": "printing.printingorder",
  "content_id": 123,
  "extra": {
    "source": "printing-order"
  },
  "has_ending_reply": false,
  "can_reply": true,
  "created_at": "2026-07-03T10:00:00+08:00",
  "updated_at": "2026-07-03T10:00:00+08:00"
}

字段说明:

字段 类型 说明
id number 任务 ID
merchant number 所属商户 ID
description string 任务描述
category number MissionCategory.id
category_name string 分类名称
is_urgent boolean 是否紧急
is_completed boolean 是否完成
is_cancelled boolean 是否取消
notify_if_unreplied boolean 是否开启未回复提醒
unreplied_notify_interval_minutes number/null 未回复提醒间隔,单位分钟
unreplied_notify_max_count number 未回复最大提醒次数,默认 5
unreplied_notify_sent_count number 已发送未回复提醒次数
unreplied_last_notified_at string/null 上一次未回复提醒时间
cancelled_at string/null 取消时间
creator EmployeePayload 创建员工
cancelled_by EmployeePayload/null 取消员工
participants EmployeePayload[] 最终展开后的任务参与员工列表
content_type number/null django_content_type.id
content_type_label string/null 可读模型标识,例如 printing.printingorder
content_id number/null 关联对象 ID
extra object/null 扩展字段
has_ending_reply boolean 是否已有结束任务的有效回应
can_reply boolean 当前是否允许继续回应
created_at string 创建时间
updated_at string 更新时间

3.4 MissionLite

MissionLite 用于轻量查询,字段与 Mission 基本一致,但不返回 participantshas_ending_replycan_reply

3.5 MissionReply

{
  "id": 100,
  "mission": 1,
  "merchant": 10,
  "responder": {
    "id": 20,
    "name": "张三",
    "merchant_id": 10
  },
  "content": "已处理",
  "extra": {
    "attachment_ids": [1001, 1002]
  },
  "replied_at": "2026-07-03T10:10:00+08:00",
  "ends_task": true,
  "is_rejected": false,
  "rejected_by": null,
  "rejected_at": null,
  "created_at": "2026-07-03T10:10:00+08:00",
  "updated_at": "2026-07-03T10:10:00+08:00"
}

字段说明:

字段 类型 说明
id number 回应 ID
mission number Mission.id
merchant number 所属商户 ID
responder EmployeePayload 回应员工
content string 回应内容
extra object/null 扩展字段
replied_at string 回应时间
ends_task boolean 是否结束任务
is_rejected boolean 是否已被撤销
rejected_by EmployeePayload/null 撤销员工
rejected_at string/null 撤销时间
created_at string 创建时间
updated_at string 更新时间

3.6 MissionWithReplies

Mission 结构基础上额外返回 replies

{
  "id": 1,
  "description": "请跟进这张生产单",
  "participants": [],
  "replies": [
    {
      "id": 100,
      "mission": 1,
      "content": "已处理",
      "ends_task": true,
      "is_rejected": false
    }
  ]
}

4. 参与者参数规则

任务创建和任务更新支持两类参与者参数:

参数 类型 说明
participant_ids number[] 显式参与员工列表,传 Employee.id
employee_type_ids number[] 职位列表,传 EmployeeType.id,后端会展开为该职位下的在职员工

最终参与者计算规则:

最终参与者 = participant_ids 中的员工 + employee_type_ids 对应职位下的在职员工

详细规则:

  • participant_ids 传的是 Employee.id
  • employee_type_ids 传的是 EmployeeType.id
  • employee_type_ids 只允许传当前商户下的职位。
  • 职位展开时只加入 status=ACTIVE 的员工。
  • 重复员工会自动去重。
  • 职位下没有员工不会报错。
  • 传入不存在或跨商户的 EmployeeType.id 会返回 400。
  • PATCH /missions/{mission_id}/ 中,只要传了 participant_idsemployee_type_ids,即表示重新设置最终参与者列表,不是增量追加。
  • PATCH /missions/{mission_id}/ 中,如果两个参数都不传,则不修改原参与者。

清空参与者:

{
  "participant_ids": [],
  "employee_type_ids": []
}

5. content_type 规则

content_typecontent_id 用于把任务挂靠到业务对象上。

  • content_typedjango_content_type.id
  • content_id 是对应业务对象主键。
  • 两者必须同时提交或同时省略。
  • 前端不应硬编码 content_type,不同环境的 ID 可能不同。
  • 推荐通过 GET /api/v2/content-types/ 获取可用值。

响应中的 content_type_label 是只读辅助字段,格式为:

app_label.model

例如:

printing.printingorder
business.salesorder

当前允许前端用于 mission 关联的业务对象:

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 工艺流程实例

6. 接口列表

6.1 查询可用 content_type

GET /api/v2/content-types/

响应:200 OK

[
  {
    "id": 33,
    "app_label": "printing",
    "model": "printingorder",
    "label": "printing.printingorder",
    "name": "印刷单"
  }
]

6.2 查询任务分类列表

GET /api/v2/mission-categories/

响应:200 OK

[
  {
    "id": 1,
    "merchant": 10,
    "name": "通用",
    "payload_processor": "",
    "speech_enabled": false,
    "created_at": "2026-07-03T10:00:00+08:00",
    "updated_at": "2026-07-03T10:00:00+08:00"
  }
]

6.3 创建任务分类

POST /api/v2/mission-categories/

请求体:

{
  "name": "生产跟进",
  "speech_enabled": true,
  "payload_processor": "structured_description_v1"
}

请求字段:

字段 类型 必填 说明
name string 分类名称,同商户内唯一
speech_enabled boolean 是否启用播报,默认 false
payload_processor string 可为空;可选 structured_description_v1

响应:201 Created,返回 MissionCategory

常见错误:

{"name": ["分类名称已存在"]}

6.4 查询任务分类详情

GET /api/v2/mission-categories/{category_id}/

响应:200 OK,返回 MissionCategory

6.5 更新任务分类

PATCH /api/v2/mission-categories/{category_id}/

请求体:

{
  "name": "售后跟进",
  "speech_enabled": false,
  "payload_processor": ""
}

响应:200 OK,返回 MissionCategory

6.6 删除任务分类

DELETE /api/v2/mission-categories/{category_id}/

响应:

  • 204 No Content:删除成功。
  • 400 Bad Request:分类已被任务使用,不能删除。

错误示例:

{"detail": "任务分类已被使用,不能删除"}

6.7 查询任务列表

GET /api/v2/missions/

查询参数:

参数 类型 必填 说明
category number 按任务分类 ID 过滤
is_urgent boolean 按是否紧急过滤,支持 1/0/true/false/yes/no
is_completed boolean 按是否完成过滤
is_cancelled boolean 按是否取消过滤
content_type number 按 content_type ID 过滤
content_id number 按关联对象 ID 过滤

响应:200 OK,返回 Mission[]

[
  {
    "id": 1,
    "description": "请跟进这张生产单",
    "category": 1,
    "category_name": "通用",
    "participants": [],
    "can_reply": true
  }
]

6.8 创建任务

POST /api/v2/missions/

请求体:

{
  "description": "请跟进这张生产单",
  "category": 1,
  "content_type": 33,
  "content_id": 123,
  "extra": {
    "source": "printing-order"
  },
  "participant_ids": [101, 102],
  "employee_type_ids": [3, 4],
  "notify_if_unreplied": true,
  "unreplied_notify_interval_minutes": 30,
  "unreplied_notify_max_count": 5
}

请求字段:

字段 类型 必填 说明
description string 任务描述,不能为空
category number MissionCategory.id不传则使用默认“通用”分类
content_type number/null django_content_type.idcontent_id 必须同时提供或同时省略
content_id number/null 关联业务对象 IDcontent_type 必须同时提供或同时省略
extra object/null 扩展字段
participant_ids number[] 显式参与员工 ID 列表,传 Employee.id
employee_type_ids number[] 参与职位 ID 列表,传 EmployeeType.id展开为在职员工
notify_if_unreplied boolean 是否开启未回复提醒,默认 false
unreplied_notify_interval_minutes number/null 未回复提醒间隔;开启提醒时必填
unreplied_notify_max_count number 最大提醒次数,默认 5

响应:201 Created,返回 Mission

常见错误:

{"detail": "参与者不存在或不属于任务所属商户"}
{"detail": "员工职位不存在或不属于任务所属商户"}
{"unreplied_notify_interval_minutes": ["开启未回复提醒时必须设置提醒间隔"]}

6.9 查询任务详情

GET /api/v2/missions/{mission_id}/

响应:200 OK,返回 Mission

6.10 更新任务

PATCH /api/v2/missions/{mission_id}/

请求体示例:

{
  "description": "更新后的任务描述",
  "category": 2,
  "extra": {
    "channel": "wechat"
  },
  "participant_ids": [101],
  "employee_type_ids": [3],
  "notify_if_unreplied": true,
  "unreplied_notify_interval_minutes": 20,
  "unreplied_notify_max_count": 8
}

可更新字段:

字段 类型 说明
description string 任务描述,不能为空
category number MissionCategory.id
content_type number/null content_id 必须同时提交;可提交 null 清空关联
content_id number/null content_type 必须同时提交;可提交 null 清空关联
extra object/null 扩展字段;提交 null 可清空
participant_ids number[] 显式员工参与者列表
employee_type_ids number[] 按职位展开的参与者列表
notify_if_unreplied boolean 是否开启未回复提醒
unreplied_notify_interval_minutes number/null 未回复提醒间隔
unreplied_notify_max_count number 未回复最大提醒次数

响应:200 OK,返回 Mission

注意:

  • participant_idsemployee_type_ids 表示重新设置最终参与者列表,不是增量追加。
  • 如果两个字段都不传,则不修改参与者。
  • 若提交 content_typecontent_id,两者必须同时出现在请求体中。
  • 状态字段不能通过该接口更新。

清空任务关联对象:

{
  "content_type": null,
  "content_id": null
}

清空参与者:

{
  "participant_ids": [],
  "employee_type_ids": []
}

6.11 删除任务

DELETE /api/v2/missions/{mission_id}/

不支持。

响应:405 Method Not Allowed

{"detail": "Mission 删除接口未提供,请使用 cancel 接口取消任务"}

6.12 按印刷单查询任务

GET /api/v2/missions/by-printing-order/{printing_order_id}/

查询指定印刷单关联的任务。

查询参数:

参数 类型 必填 说明
category_ids number[]/string 分类过滤。支持重复参数或逗号分隔,例如 ?category_ids=1,2?category_ids=1&category_ids=2
include_details boolean 是否返回详情。默认 truefalse 时返回 MissionLite[]

响应:

  • include_details=true 或未传:200 OK,返回 MissionWithReplies[]
  • include_details=false200 OK,返回 MissionLite[]

示例:

GET /api/v2/missions/by-printing-order/123/?category_ids=1,2&include_details=true

常见错误:

{"include_details": "必须是布尔值"}
{"category_ids": "必须是整数 ID 列表"}

6.13 查询任务回应列表

GET /api/v2/missions/{mission_id}/replies/

查询参数:

参数 类型 必填 说明
ends_task boolean 按是否结束任务过滤
is_rejected boolean 按是否已撤销过滤

响应:200 OK,返回 MissionReply[]

6.14 创建任务回应

POST /api/v2/missions/{mission_id}/replies/

请求体:

{
  "content": "已处理完成",
  "ends_task": true,
  "extra": {
    "attachment_ids": [1001, 1002]
  }
}

请求字段:

字段 类型 必填 说明
content string 回应内容,不能为空
ends_task boolean 是否结束任务,默认 false
extra object/null 扩展字段

响应:201 Created,返回 MissionReply

行为说明:

  • 回应人固定为当前登录用户关联的 Employee。
  • 如果 ends_task=true,任务会被标记为完成。
  • 已取消任务或已有未撤销结束回应的任务不可继续回应。

6.15 重新打开任务

POST /api/v2/missions/{mission_id}/reopen/

权限要求:当前用户需要 Django 权限 mission.reopen_mission

响应:200 OK,返回 Mission

行为说明:

  • 用于重新打开已完成任务。
  • 会撤销已有结束任务效果,使任务回到未完成状态。

常见错误:

{"detail": "缺少重新打开任务权限"}

6.16 取消任务

POST /api/v2/missions/{mission_id}/cancel/

响应:200 OK,返回 Mission

行为说明:

  • 取消人固定为当前登录用户关联的 Employee。
  • 取消后 is_cancelled=truecancelled_bycancelled_at 由后端写入。

6.17 设置任务紧急状态

POST /api/v2/missions/{mission_id}/set-urgent/

请求体:

{
  "is_urgent": true
}

请求字段:

字段 类型 必填 说明
is_urgent boolean 是否紧急

响应:200 OK,返回 Mission

6.18 撤销任务回应

POST /api/v2/mission-replies/{reply_id}/reject/

权限要求:当前用户需要 Django 权限 mission.reject_mission_reply

响应:200 OK,返回 MissionReply

行为说明:

  • 撤销人固定为当前登录用户关联的 Employee。
  • 如果撤销的是结束任务回应,任务可能会被重新打开。

常见错误:

{"detail": "缺少撤销任务回应权限"}

7. 常见状态码

状态码 场景
200 OK 查询、更新、状态操作成功
201 Created 创建任务、分类、回应成功
204 No Content 删除任务分类成功
400 Bad Request 参数非法、跨商户、业务状态不允许
401 Unauthorized 未登录
403 Forbidden 缺少 reopen_missionreject_mission_reply 等权限
404 Not Found 对象不存在或不属于当前商户
405 Method Not Allowed 不支持的删除任务操作

8. 前端接入建议

  • 创建/更新任务时,participant_ids 使用 Employee.idemployee_type_ids 使用 EmployeeType.id
  • 如果只想按职位添加参与者,可以只传 employee_type_ids
  • 如果 PATCH 不想改变参与者,不要传 participant_idsemployee_type_ids
  • 如果 PATCH 想清空参与者,两个字段都传空数组。
  • content_type 不要硬编码,应从 /api/v2/content-types/ 获取。
  • 普通任务编辑页不要提交状态字段,紧急、取消、重新打开、撤销回应都走独立接口。
  • 响应中的 participants 是后端最终展开后的员工列表,前端展示以该字段为准。

更新日期2026-07-03