diff --git a/docs/mockups/oa-approval-transfer-demo.html b/docs/mockups/oa-approval-transfer-demo.html new file mode 100644 index 00000000..0cfb6957 --- /dev/null +++ b/docs/mockups/oa-approval-transfer-demo.html @@ -0,0 +1,689 @@ + + + + + + OA 审批 · 转交 Demo(Fresh Mint) + + + +
+
+

OA 审批 ·【转交】交互 Demo

+

在现有「同意 / 拒绝 / 打回 / 加签」旁增加「转交」。本页演示审批详情顶栏、转交弹窗与转交后进度展示。

+
+ 已定语义:转交 = 将本人当前待办交给另一人处理;转交后本人不再持有该待办;进度记录「已转交」。 + 与加签区别:加签是新增审批人,本人待办仍在。说明可选;无应用开关;可选租户内用户(排除本人与本节点已有待办)。 +
+
+ +
+ + + + +
+ + +
+
+
+
+ +

差旅报销 · 张三 · 2026-07-23

+ 审批中 +
+
+ + + + + +
+
+ +
+

表单内容

+
+
+ +
张三
+
+
+ +
研发中心 / 平台组
+
+
+ +
¥ 2,860.00
+
+
+ +
合肥
+
+
+ +
客户现场实施与验收
+
+
+
+ +
+

审批进度

+
+
+
起
+
+
提交 已提交
+
张三 · 07-23 09:12
+
+
+
+
审
+
+
部门负责人 审批中
+
当前处理人:李四
+
李四 · 待处理
+
+
+
+
审
+
+
财务复核 未到达
+
王五
+
+
+
+
+
+
+ + +
+
+
+
+

转交弹窗示意

+ 交互稿 +
+
+ +
+
+

+ 字段对齐现有「加签」弹窗:选择用户 + 说明。差异点:转交人为单选(一人接手),说明可选。 +

+
+
+

字段

+
    +
  • 转交给(必填,单选用户)
  • +
  • 转交说明(可选)
  • +
  • 不可选:自己、已在本节点待办中的人
  • +
+
+
+

提交后效果

+
    +
  • 本人待办关闭为「已转交」
  • +
  • 目标人新增同节点 pending 待办
  • +
  • 进度展示「李四 已转交 …」+「赵六 待处理」
  • +
  • 无应用开关;全应用可转交;允许再转交
  • +
+
+
+
+
+ + +
+
+
+
+ +

差旅报销 · 张三 · 2026-07-23

+ 审批中 +
+
+ 李四已转交,本人操作区消失(非当前处理人) +
+
+ +
+

审批进度(转交后)

+
+
+
起
+
+
提交 已提交
+
张三 · 07-23 09:12
+
+
+
+
审
+
+
部门负责人 审批中
+
当前处理人:赵六
+
+ 李四 · 已转交 · 07-23 10:05 +
转交说明:出差中,请赵六代为审批
+ 赵六 · 待处理 +
+
+
+
+
审
+
+
财务复核 未到达
+
王五
+
+
+
+
+
+
+ + +
+
+
+
+

转交 vs 加签

+
+
+
+
+

转交

+
    +
  • 替换处理人:A → B
  • +
  • A 待办结束(已转交)
  • +
  • 通常单选一人
  • +
  • 不改变节点人数语义(仍是「谁来批」)
  • +
  • 适合:请假/出差临时交接
  • +
+
+
+

加签

+
    +
  • 追加处理人:A + B(+C…)
  • +
  • A 待办仍在
  • +
  • 可多选
  • +
  • 影响或签/会签收口
  • +
  • 适合:需要他人共同意见
  • +
+
+
+
+
+
+ + + + +
+ + + + diff --git a/docs/superpowers/specs/2026-07-23-oa-approval-transfer-design.md b/docs/superpowers/specs/2026-07-23-oa-approval-transfer-design.md new file mode 100644 index 00000000..d6348e9d --- /dev/null +++ b/docs/superpowers/specs/2026-07-23-oa-approval-transfer-design.md @@ -0,0 +1,208 @@ +# OA 审批 · 转交(Transfer)设计 + +| 项 | 内容 | +|----|------| +| 状态 | 已定稿(待实现) | +| 日期 | 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` | + +--- + +## 1. 背景 + +当前 OA 审批详情在待办处理人视角提供:**同意 / 拒绝 / 打回 / 加签**。缺少「把本人待办交给他人处理」的能力;请假、出差等场景只能依赖加签(本人待办仍在)或线下协调。 + +产品确认增加 **转交**,语义对齐常见 OA「替换处理人」,而非代理委托。 + +--- + +## 2. 目标与非目标 + +**目标** + +- 当前待办处理人可将**本人这一份** pending 审批任务转交给租户内另一有效用户。 +- 转交后:原处理人待办结束(`transferred`),目标人新增同节点 pending;实例仍 `running`,节点不自动推进。 +- 进度可追溯(含连续转交 A→B→C);「已处理」列表含转交记录。 +- 全应用可用,**不**增加设计器开关。 + +**非目标** + +- 设计器 `allowTransfer` 开关。 +- 代理/委托(责任仍算原审批人)。 +- 一次转交多人、转交并同意。 +- 按部门或节点候选池收窄选人。 +- 小程序端、钉钉式独立「转交墙」UI。 +- 改变或签/会签收口规则(仅替换本人任务,`sign_mode` 不变)。 + +--- + +## 3. 产品决策(已确认) + +| 项 | 决定 | +|----|------| +| 语义 | **替换处理人**:A 待办 → `transferred`;B 新建 pending | +| 转交说明 | **可选**(对齐加签说明) | +| 应用开关 | **无**;所有应用一律可转交 | +| 选人范围 | 租户内有效用户;排除本人;排除本节点已有 `pending` 的用户 | +| 再转交 | **允许**连续转交 | +| 实现路径 | **关旧待办 + 建新待办**(不用原地改 `assignee_user_id`) | + +**与加签区别** + +| | 转交 | 加签 | +|--|------|------| +| 本人待办 | 结束 | 仍在 | +| 选人 | 单选 | 可多选 | +| 节点人数 | 替换一人 | 追加一人或多 | + +--- + +## 4. 引擎行为(SHALL) + +新增 `transfer_task(db, task_id, *, tenant_no, user_id, target_user_id, comment=None)`,对齐 `add_sign` / `return_task` 的权限与校验风格。 + +### 4.1 前置条件 + +1. 任务存在、租户匹配、`del_flag=0`。 +2. `assignee_user_id == user_id`(本人待办)。 +3. `task_type == "approval"` 且 `status == "pending"`。 +4. 实例 `status == "running"`。 +5. `target_user_id` 非空、≠ `user_id`。 +6. 目标用户:同租户、`del_flag=0`、`status=="1"`。 +7. 目标用户**不在**同实例同 `node_key` 的 `pending` 任务 assignee 集合中。 + +不满足时抛 `OaEngineError`,文案明确(无权 / 仅待处理可转交 / 用户无效 / 已在待办中等)。 + +### 4.2 写入步骤 + +1. 当前任务: + - `status = "transferred"` + - `comment_text` = 说明 trim 后文本,可空 + - `update_by` / `update_time` 更新 +2. 同节点新建 `OaTask`: + - `node_key` / `node_name` / `sign_mode` / `round_no` 继承原任务(`round_no` 与实例 `current_round` 对齐,同加签) + - `assignee_user_id = target_user_id` + - `status = "pending"` + - `resolve_source = "transfer"` + - `remark` 可存说明快照(与加签一致,可选) + - 公共字段按现有任务创建约定填写 +3. `_add_instance_event`:`event_type="transfer"`,`actor_user_id=user_id`,`task_id`/`node_key` 指向原任务;`comment_text` 可用用户填写的说明,或在说明为空时写入简短审计句(如「转交给 {targetUserId}」)。现有事件表无独立 payload 字段;**进度展示以 `oa_task` 行为权威**,事件仅审计。 +4. `db.commit()`;返回 `get_instance_detail`。 + +### 4.3 节点聚合与列表 + +- `_aggregate_node_status`:在现有优先级(`rejected` / `returned` > `pending` > `approved` …)上,将 `transferred` 与 `approved` 同等对待——**不**因存在 `transferred` 把节点标为终态;同节点仍有 `pending` 时节点为审批中。 +- 「已处理」任务查询:在现有 `approved` / `rejected` / `returned` 基础上 **SHALL 包含** `transferred`。 +- 或签一人通过取消同节点其余 pending 时:行为不变;已 `transferred` 的历史行不被改写为 `done`(与「本人已同意不被覆盖」同一原则:只动仍为 `pending` 的任务)。 + +### 4.4 连续转交 + +B 持有 pending 后可再次转交 C:重复 4.1–4.2。进度同节点下按任务时间顺序展示多行(已转交 / 待处理)。 + +--- + +## 5. API(SHALL) + +`POST /api/admin/oa/tasks/{task_id}/transfer` + +- 鉴权:与现有 approve / add-sign 相同(`require_admin_or_super_admin` + 租户)。 +- Body(Pydantic): + - `targetUserId: str`(必填) + - `comment: Optional[str] = None` +- 成功:`success_response(instance_detail, message="已转交")` +- 失败:`error_response(400, str(e))` + +前端:`web-admin/src/api/oaApproval.ts` 增加 `fetchTransferOaTask(taskId, { targetUserId, comment? })`。 + +--- + +## 6. 前端 UI(SHALL) + +权威交互:`docs/mockups/oa-approval-transfer-demo.html`(Fresh Mint)。 + +### 6.1 详情顶栏 + +- 条件:`canApprove`(存在本人 pending 审批任务)。 +- 按钮顺序建议:同意 → 拒绝 → 打回(若允许)→ 加签(若允许)→ **转交**。 +- **不**依赖 `allowTransfer` / `allowAddSign`;转交始终在 `canApprove` 时展示。 +- 图标:Leading `el-icon`(如 `Position` / `Right` 一类,与现有按钮规范一致)。 + +### 6.2 转交弹窗 + +- `el-dialog`:`dialog-form-layout`、`label-position="top"`、无 backdrop blur、`modal-class` 与现有协议/加签弹窗一致。 +- 字段: + - 转交给:单选用户(`el-select` filterable);选项来源同加签用户列表;前端可再过滤本人与本节点 pending 处理人(后端仍须二次校验)。 + - 转交说明:可选 textarea。 +- 底栏:取消 / 确定转交(Close / Check 图标)。 + +### 6.3 成功后 + +刷新实例详情;原用户无 pending → 操作区消失;进度见 §7。 + +--- + +## 7. 进度与文案(SHALL) + +- 任务状态文案:`transferred` → **已转交**(详情 status 映射、进度人员行、打印同源)。 +- 人员行格式对齐 `formatProgressPersonLines`: + - 无说明:`{姓名} 已转交 {时间}` + - 有说明:`{姓名} {说明} {时间}`(与同意/拒绝「有 comment 优先用 comment」一致) +- Tone:建议 `mute` 或独立中性(勿用 danger);`cancelled` 仍为 danger,避免与转交混淆。 +- `ACTED_STATUS`(或等价集合)SHALL 包含 `transferred`,以便走「已处理」拼行分支而非「待处理」。 +- 当前处理人展示:取同节点仍为 `pending` 的 assignee;转交后更新为新人。 + +--- + +## 8. 测试(SHALL) + +`backend/tests/test_oa_engine.py`(风格对齐加签用例): + +1. 成功转交:原任务 `transferred`,新任务 pending + `resolve_source=transfer`。 +2. 说明可空。 +3. 不可转给自己;不可转给本节点已有 pending 用户;无效用户报错。 +4. 非 pending / 非本人 / 实例非 running 报错。 +5. 会签:同节点另一人 pending 不受影响。 +6. 连续转交两次成功。 +7. 已办查询含 `transferred`(若有直接测 list kind=done 的辅助逻辑则一并覆盖)。 + +前端:至少手工走通 Demo 与详情页;若已有进度 formatter 单测,补 `transferred` 一行用例。 + +--- + +## 9. 改动面清单 + +| 层 | 路径 | +|----|------| +| 引擎 | `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 强制时以约定为准)。 + +--- + +## 10. 风险与缓解 + +| 风险 | 缓解 | +|------|------| +| 已办列表漏 `transferred` | 与打回修订同一模式,查询显式纳入 | +| 与 `cancelled`/`done` 混淆 | 独立状态 + 进度文案「已转交」 | +| 聚合把仅含 transferred 的节点判错 | 有 pending 优先;测会签/或签样例 | +| 加签按钮旁误点 | Demo 与文案区分;实现后 UI 对照 Demo | + +--- + +## 11. 验收标准 + +1. 待办人可打开转交弹窗,选人后成功;说明可空。 +2. 进度显示原人已转交、新人待处理;当前处理人更新。 +3. 原人「已处理」可见该单;新人「待处理」可见。 +4. 会签只换自己那份;连续转交可用。 +5. 转给自己 / 重复 pending 用户 / 非待办态均失败且有提示。