2026-08-31-production-cascade-complete-design.md 7.7 KB

生产「完成任务 / 完成工单」状态级联 — 设计文档

日期: 2026-08-31
状态: 已实现(2026-08-31)
范围: 生产工单、生产任务、工艺步骤(web-admin + backend)
页面: 【生产工单】/#/production-group/production/production-work-order、【我的生产任务】/#/production-group/production/my-production-task(共用任务执行弹窗)

1. 背景

当前行为:

入口 现状
任务执行弹窗 ·「完成任务」 前后端均校验「全部工艺步骤已完成」;未完成则拦截。步骤上仍有「执行此步骤」「完成步骤」。
卡片 ·「完成工单」 仅将工单标为 ywc,不同步完成下属任务与步骤。
我的生产任务 不展示「完成工单」;与生产工单共用 TaskExecutionDialog。

用户诉求:完成上级时自动级联完成下级状态,不再因下级未完成而阻止操作;业务明细(投入产出、步骤填报等)不强制补全。

2. 已确认的产品决策

问题 决策
实现路径 方案 B:在现有「完成任务」「完成工单」接口内做级联(同一事务)
完成工单时未完成任务的结论 弹窗统一选择成功(cg)/失败(sb),再级联写入所有本次新完成的任务
级联完成步骤的完成人/时间 当前操作人 + 当前时间(与手动「完成步骤」一致)
完成任务时的 I/O、储物格、步骤完整性校验 全部去掉;只改状态,不因明细未填拦截
完成工单级联任务范围 工单下所有未删除且未完成任务(含 dpz / dzx / jxz)
已完成任务 不动(结论与步骤保持原样)
单步「执行此步骤 / 完成步骤」 保留,可继续逐步操作
我的生产任务 · 完成工单入口 不新增(卡片仍不展示)

3. 行为与范围

3.1 完成任务(任务执行弹窗顶栏)

  1. 仍弹出结论弹窗(成功/失败 + 可选备注)。
  2. 不再因「尚有未完成工艺步骤」拦截(前端 + 后端同步去掉)。
  3. 不再因投入/产出未填、储物格未分配而拦截。
  4. 提交时后端在置任务 ywc 前,将该任务下所有未删除且 step_status != ywc 的步骤一次性置为 ywc:
    • completed_by = 当前操作人
    • completed_time = 当前时间
    • 已有 started_time 的步骤保留;未开始的步骤可不补 started_time(与手动完成步骤路径对齐即可)
  5. 结论必填、任务 completed_time、投入物消耗 _consume_task_input_cell_products、以及 sync_production_work_order_status_from_tasks 保持现状(完成任务本身不把工单直接标成 ywc)。

3.2 完成工单(生产工单卡片)

  1. 点击后先弹统一结论弹窗(成功/失败,可选备注),不再只是简单 confirm。
  2. 弹窗可提示:将同步完成该工单下所有未完成任务及其工艺步骤。
  3. 确认后同一事务内级联:
    • 未完成步骤 → ywc(完成人/时间同上)
    • 未完成任务 → ywc,写入统一 conclusion;弹窗有备注时写入任务 remark
    • 工单 → ywc;弹窗备注写入工单 remark(若有)
  4. 已是 ywc 的任务:结论、步骤不动。

3.3 明确不做

  • 不自动补全步骤/任务业务明细(试剂、产出物、数据采集等)
  • 不改派发、步骤负责人权限、单步执行流程
  • 不改工单 Tab / 列表卡片布局(仅完成工单交互从 confirm → 结论弹窗)
  • 不在「我的生产任务」开放完成工单

4. 后端设计

4.1 共享内部方法

_force_complete_task_steps(db, task_id, tenant_no, user_id, now):

  • 条件:BizProductionTaskStep.del_flag=0 且 step_status != 'ywc'
  • 写入:step_status='ywc',completed_by=user_id,completed_time=now,update_by / update_time
  • 不单独 commit

4.2 完成任务

入口不变:现有更新任务状态为 ywc 的路径(update_task_status)。

变更:

  1. 删除「尚有未完成的工艺步骤,请完成全部步骤后再完成任务」校验。
  2. 置任务 ywc 之前调用 _force_complete_task_steps。
  3. 其余逻辑(结论校验、消耗、工单状态同步)不变。

4.3 完成工单

入口不变:PUT /production-work-orders/{wo_id}/complete。

ProductionWorkOrderComplete 扩展:

字段 必填 说明
conclusion 是 cg / sb,写入所有本次新完成的任务
remark 否 写入工单备注;若有值则同时写入本次新完成任务的 remark

级联顺序(同一事务、一次 commit):

1. 校验工单存在且非 ywc;conclusion 合法
2. 查工单下 del_flag=0 且 task_status != ywc 的任务
3. 对每个上述任务:
   a. _force_complete_task_steps
   b. task_status=ywc,conclusion=统一结论,completed_time=now(若空)
   c. 走与「完成任务」一致的侧效(含投入物消耗)
4. 工单 work_order_status=ywc,写 remark(若有)
5. sync_schedule_from_production_work_order
6. commit

实现约束:

  • 级联过程中不要对每个任务单独 commit。
  • 级联过程中跳过 sync_production_work_order_status_from_tasks(避免中途把工单写成 jxz),最后一步直接置工单 ywc。
  • 工单下无未完成任务:仍要求选结论;仅改工单状态(结论不落任务)。

4.4 错误边界

条件 行为
工单已 ywc 400「工单已完成」
conclusion 缺失或非法 400
权限 沿用现有 complete 接口,不新增

5. 前端设计

5.1 完成任务

  • 文件:useTaskStepEditor.ts(handleCompleteTask)
  • 去掉:validateAllStepsComplete()、投入/产出完整校验、储物格确认
  • 保留:CompleteProductionTaskDialog → 现有完成任务 API
  • 成功后刷新任务详情;步骤应全部为 ywc

5.2 完成工单

  • 文件:production-work-order/index.vue 的 handleCompleteSingle
  • 用结论弹窗替换简单 confirm(可复用/轻抽 CompleteProductionTaskDialog,标题「完成工单」,增加级联说明文案)
  • 提交:fetchCompleteProductionWorkOrder(id, { conclusion, remark })
  • API 传参:当前实现用 query params;后端期望 Body。实现时改为请求体 data 传 conclusion/remark,并核对后端能收到
  • 「我的生产任务」:不展示完成工单;调用形态可顺带对齐,不新增入口

5.3 文案

场景 文案
完成任务成功 保持现有「任务已完成」类提示
完成工单弹窗标题 完成工单
完成工单成功 工单已完成

6. 主要改动文件

层 文件
Backend app/crud/production_task.py、app/crud/production_work_order.py、app/schemas/production_work_order.py
Frontend useTaskStepEditor.ts、production-work-order/index.vue、结论弹窗复用/抽取、api/production-work-order.ts

7. 测试要点

  1. 任务有未完成步骤 → 完成任务并选结论 → 任务与全部步骤变 ywc,完成人/时间为当前用户。
  2. 任务步骤已全部完成 → 完成任务行为与改前一致(含结论写入)。
  3. 工单含 dpz/dzx/jxz 任务与未完成步骤 → 完成工单选「失败」→ 工单 ywc;上述任务均为 ywc+sb;步骤均为 ywc;已完成任务结论不变。
  4. 工单已完成 → 仍拒绝。
  5. 完成工单不传结论 → 400。
  6. 回归:单步执行/完成步骤、派发、我的生产任务执行弹窗仍可用。

8. 非目标回顾

  • 不做前端循环调多接口的半成功方案
  • 不新建独立 force-complete API(方案 C)
  • 不强制补全业务明细数据