| 项 | 内容 |
|---|---|
| 状态 | 已定稿(待实现) |
| 日期 | 2026-07-23 |
| 范围 | 审批待办「转交」:替换处理人;引擎 / API / 详情 UI / 进度文案 / 已办列表 |
| 交互 Demo | docs/mockups/oa-approval-transfer-demo.html |
| 关联 | 加签 add_sign;进度人员行 2026-07-23-oa-or-and-sign-display-design.md;打回终态 2026-07-15-oa-return-copy-new-instance-design.md |
当前 OA 审批详情在待办处理人视角提供:同意 / 拒绝 / 打回 / 加签。缺少「把本人待办交给他人处理」的能力;请假、出差等场景只能依赖加签(本人待办仍在)或线下协调。
产品确认增加 转交,语义对齐常见 OA「替换处理人」,而非代理委托。
目标
transferred),目标人新增同节点 pending;实例仍 running,节点不自动推进。非目标
allowTransfer 开关。sign_mode 不变)。| 项 | 决定 |
|---|---|
| 语义 | 替换处理人:A 待办 → transferred;B 新建 pending |
| 转交说明 | 可选(对齐加签说明) |
| 应用开关 | 无;所有应用一律可转交 |
| 选人范围 | 租户内有效用户;排除本人;排除本节点已有 pending 的用户 |
| 再转交 | 允许连续转交 |
| 实现路径 | 关旧待办 + 建新待办(不用原地改 assignee_user_id) |
与加签区别
| | 转交 | 加签 | |--|------|------| | 本人待办 | 结束 | 仍在 | | 选人 | 单选 | 可多选 | | 节点人数 | 替换一人 | 追加一人或多 |
新增 transfer_task(db, task_id, *, tenant_no, user_id, target_user_id, comment=None),对齐 add_sign / return_task 的权限与校验风格。
del_flag=0。assignee_user_id == user_id(本人待办)。task_type == "approval" 且 status == "pending"。status == "running"。target_user_id 非空、≠ user_id。del_flag=0、status=="1"。node_key 的 pending 任务 assignee 集合中。不满足时抛 OaEngineError,文案明确(无权 / 仅待处理可转交 / 用户无效 / 已在待办中等)。
status = "transferred"comment_text = 说明 trim 后文本,可空update_by / update_time 更新OaTask:
node_key / node_name / sign_mode / round_no 继承原任务(round_no 与实例 current_round 对齐,同加签)assignee_user_id = target_user_idstatus = "pending"resolve_source = "transfer"remark 可存说明快照(与加签一致,可选)_add_instance_event:event_type="transfer",actor_user_id=user_id,task_id/node_key 指向原任务;comment_text 可用用户填写的说明,或在说明为空时写入简短审计句(如「转交给 {targetUserId}」)。现有事件表无独立 payload 字段;进度展示以 oa_task 行为权威,事件仅审计。db.commit();返回 get_instance_detail。_aggregate_node_status:在现有优先级(rejected / returned > pending > approved …)上,将 transferred 与 approved 同等对待——不因存在 transferred 把节点标为终态;同节点仍有 pending 时节点为审批中。approved / rejected / returned 基础上 SHALL 包含 transferred。transferred 的历史行不被改写为 done(与「本人已同意不被覆盖」同一原则:只动仍为 pending 的任务)。B 持有 pending 后可再次转交 C:重复 4.1–4.2。进度同节点下按任务时间顺序展示多行(已转交 / 待处理)。
POST /api/admin/oa/tasks/{task_id}/transfer
require_admin_or_super_admin + 租户)。targetUserId: str(必填)comment: Optional[str] = Nonesuccess_response(instance_detail, message="已转交")error_response(400, str(e))前端:web-admin/src/api/oaApproval.ts 增加 fetchTransferOaTask(taskId, { targetUserId, comment? })。
权威交互:docs/mockups/oa-approval-transfer-demo.html(Fresh Mint)。
canApprove(存在本人 pending 审批任务)。allowTransfer / allowAddSign;转交始终在 canApprove 时展示。el-icon(如 Position / Right 一类,与现有按钮规范一致)。el-dialog:dialog-form-layout、label-position="top"、无 backdrop blur、modal-class 与现有协议/加签弹窗一致。el-select filterable);选项来源同加签用户列表;前端可再过滤本人与本节点 pending 处理人(后端仍须二次校验)。刷新实例详情;原用户无 pending → 操作区消失;进度见 §7。
transferred → 已转交(详情 status 映射、进度人员行、打印同源)。formatProgressPersonLines:
{姓名} 转交给{目标姓名} {时间}{姓名} 转交给{目标姓名} {说明} {时间}{姓名} 已转交 {时间}(兼容旧数据){姓名} {说明} {时间}build_progress_items 的 people[] SHALL 为 transferred 项补齐 transferToUserId / transferToUserName(同节点 resolve_source=transfer 且 create_by=转交人的新任务处理人)。mute 或独立中性(勿用 danger);cancelled 仍为 danger,避免与转交混淆。ACTED_STATUS(或等价集合)SHALL 包含 transferred,以便走「已处理」拼行分支而非「待处理」。pending 的 assignee;转交后更新为新人。formatProgressPersonLines)。backend/tests/test_oa_engine.py(风格对齐加签用例):
transferred,新任务 pending + resolve_source=transfer。transferred(若有直接测 list kind=done 的辅助逻辑则一并覆盖)。前端:至少手工走通 Demo 与详情页;若已有进度 formatter 单测,补 transferred 一行用例。
| 层 | 路径 |
|---|---|
| 引擎 | backend/app/services/oa_engine.py |
| API / schema | backend/app/api/oa_approval.py(及现有 Oa body schema 文件) |
| 测试 | backend/tests/test_oa_engine.py |
| API 客户端 | web-admin/src/api/oaApproval.ts |
| 详情 | web-admin/src/views/oa-approval/instances/detail.vue |
| 进度文案 | web-admin/src/utils/oa-progress-person-lines.ts |
| 打印(若共用状态映射) | web-admin/src/utils/oa-approval-print.ts 等按需 |
| Demo | docs/mockups/oa-approval-transfer-demo.html |
无需新表;oa_task.status 增加取值 transferred(字符串枚举,无 DDL 强制时以约定为准)。
| 风险 | 缓解 |
|---|---|
已办列表漏 transferred |
与打回修订同一模式,查询显式纳入 |
与 cancelled/done 混淆 |
独立状态 + 进度文案「已转交」 |
| 聚合把仅含 transferred 的节点判错 | 有 pending 优先;测会签/或签样例 |
| 加签按钮旁误点 | Demo 与文案区分;实现后 UI 对照 Demo |