325 lines
16 KiB
Markdown
325 lines
16 KiB
Markdown
# 生产任务 · 工艺步骤级派发 — 需求分析与设计
|
||
|
||
> 日期: 2026-06-25
|
||
> 状态: **已评审,可实施**
|
||
> 范围: web-admin + backend(生产工单派发、任务执行、我的生产任务)
|
||
|
||
---
|
||
|
||
## 1. 背景与目标
|
||
|
||
### 1.1 现状
|
||
|
||
| 项 | 现状 |
|
||
|----|------|
|
||
| 派发粒度 | `DispatchTaskDialog.vue` 创建 **整条生产任务** 时指定 **单一任务负责人**(`biz_production_task.current_assignee_user_id`) |
|
||
| 步骤模型 | `biz_production_task_step` 有工序与执行状态(`dzx/jxz/ywc`),**无负责人、无计划开始时间** |
|
||
| 我的生产任务 | 按 `current_assignee_user_id = 当前用户` 过滤任务 |
|
||
| 任务执行 | `TaskExecutionDialog.vue`:当前负责人对 **全部步骤** 可操作 |
|
||
| 类似实现 | 质检任务 **`biz_qc_task_assignee`**:每检测项多人负责,**任一可完成** |
|
||
|
||
### 1.2 客户需求(原文摘要)
|
||
|
||
1. **派发按工艺步骤**,而非整条生产任务整体派发。
|
||
2. **列表仍按工单 + 生产任务展示**;展开/进入执行后,**仅派给自己的步骤可操作**,其他步骤 **只读可见**。
|
||
3. 一个工艺步骤可 **同时派给多人**;**任一负责人** 可开始/完成该步骤。
|
||
4. 每个步骤派发时可设置 **计划开始时间**(展示/排序,**不限制**提前执行)。
|
||
5. 同一生产任务内,**多个步骤可派给同一人**。
|
||
6. 支持 **创建时一并派发(B)** 与 **工艺配置后单独派发(A)** 两种入口。
|
||
7. 已派给 A 的步骤,**可改派** 给其他人(更新负责人列表)。
|
||
8. **未指定负责人的步骤**:仅管理员在 **生产工单页** 可见可操作;**不出现在** 任何人的「我的生产任务」。
|
||
|
||
---
|
||
|
||
## 2. 产品决策
|
||
|
||
| # | 问题 | 决策 | 状态 |
|
||
|---|------|------|------|
|
||
| D1 | 「我的生产任务」列表粒度? | **工单 + 任务卡片**(非步骤级平铺列表) | ✅ |
|
||
| D2 | 未派给自己的步骤如何展示? | **只读可见**(可见完整工艺链路与状态,不可操作) | ✅ |
|
||
| D3 | 一步多人时的完成语义? | **任一负责人可独立完成**(与质检任务一致;`completed_by` 记实际操作人) | ✅ |
|
||
| D4 | 计划开始时间含义? | **仅展示/排序**,不阻断执行 | ✅ |
|
||
| D5 | 派发入口? | **A + B 均支持**,共用同一套步骤派发能力 | ✅ |
|
||
| D6 | 未派步骤可见性? | **仅管理员**(工单页 `operateScope=manage`);mine 不可见 | ✅ |
|
||
| D7 | 数据模型方案? | **方案 1**:`biz_production_task_step_assignee` + 步骤 `planned_start_time` | ✅ |
|
||
| D8 | 任务级负责人字段? | 创建时 **不再必填**;「我的生产任务」改按 **步骤负责人** 过滤 | ✅ |
|
||
| D9 | 任务级「转发」? | **保留代码但标记 deprecated**;协作改由 **步骤改派** 完成 | ✅ |
|
||
| D10 | 原材料/产出/纸质文档? | **任一步骤负责人** 在 mine 视角均可编辑(与步骤协作一致) | ✅ |
|
||
| D11 | mine 端能否自行改派? | **否**;改派仅 **工单管理页**(`operateScope=manage`) | ✅ |
|
||
|
||
---
|
||
|
||
## 3. 业务流程(目标态)
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────────────┐
|
||
│ 生产工单 · 派发生产任务 │
|
||
│ 阶段一:任务名称、工艺路线(可选)、描述 — 【移除任务级负责人】 │
|
||
│ 阶段二:编辑工艺步骤(现有三栏编辑器) │
|
||
└─────────────────────────────────────────────────────────────────────────┘
|
||
│ 若选了工艺路线(B) │ 未选路线 / 后补步骤(A)
|
||
▼ ▼
|
||
┌────────────────────────────┐ ┌────────────────────────────┐
|
||
│ 创建后立即打开「步骤派发」 │ │ 任务卡片 · 「步骤派发」 │
|
||
│ 每步:多人 + 计划开始时间 │ │ 同上 │
|
||
└────────────────────────────┘ └────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────────┐
|
||
│ 我的生产任务 · 工单 + 任务卡片 │
|
||
│ 过滤:当前用户是 ≥1 个步骤的负责人 │
|
||
│ 展开 → 进入执行:自己的步骤可操作;其他步骤只读;未派步骤 mine 不可见 │
|
||
└─────────────────────────────────────────────────────────────────────────┘
|
||
│
|
||
管理员工单页 · 步骤改派
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────────┐
|
||
│ sync 步骤负责人列表 + 更新 planned_start_time │
|
||
│ dzx/jxz:改派后新负责人可操作;ywc:仅影响可见性,不 reopen 步骤 │
|
||
└─────────────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## 4. 数据模型
|
||
|
||
### 4.1 新增 / 变更
|
||
|
||
**步骤表扩展** `biz_production_task_step`:
|
||
|
||
```sql
|
||
ALTER TABLE biz_production_task_step
|
||
ADD COLUMN planned_start_time datetime DEFAULT NULL COMMENT '计划开始时间' AFTER step_status;
|
||
|
||
ALTER TABLE biz_production_task_step
|
||
ADD COLUMN completed_by varchar(64) DEFAULT NULL COMMENT '完成步骤的用户ID' AFTER completed_time;
|
||
```
|
||
|
||
**步骤负责人关联表** `biz_production_task_step_assignee`(对齐 `biz_qc_task_assignee`):
|
||
|
||
```sql
|
||
CREATE TABLE biz_production_task_step_assignee (
|
||
id varchar(64) NOT NULL COMMENT '主键',
|
||
step_id varchar(64) NOT NULL COMMENT '生产任务步骤ID',
|
||
user_id varchar(64) NOT NULL COMMENT '负责人用户ID',
|
||
tenant_no varchar(64) NOT NULL DEFAULT 'zkxw' COMMENT '租户编号',
|
||
order_num int DEFAULT 0 COMMENT '展示顺序',
|
||
remark varchar(512) DEFAULT NULL COMMENT '备注',
|
||
create_by varchar(64) DEFAULT NULL COMMENT '创建人id',
|
||
create_dept_id varchar(64) NOT NULL DEFAULT '' COMMENT '创建人部门ID',
|
||
create_time datetime NOT NULL COMMENT '创建时间',
|
||
update_by varchar(64) DEFAULT NULL COMMENT '更新人id',
|
||
update_time datetime NOT NULL COMMENT '更新时间',
|
||
del_flag tinyint NOT NULL DEFAULT 0 COMMENT '删除标记',
|
||
PRIMARY KEY (id),
|
||
KEY idx_step_assignee_step (step_id),
|
||
KEY idx_step_assignee_user (user_id, tenant_no)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='生产任务步骤负责人';
|
||
```
|
||
|
||
### 4.2 任务级字段(兼容)
|
||
|
||
| 字段 | 处理 |
|
||
|------|------|
|
||
| `biz_production_task.current_assignee_user_id` | **保留列**;新创建任务可为 NULL;API 创建 body **移除 assigneeUserId 必填** |
|
||
| `biz_production_task_handover` | **保留**;UI 不再主推「任务转发」,文档标注 deprecated |
|
||
|
||
### 4.3 历史数据迁移(可选脚本)
|
||
|
||
- 若旧任务 `current_assignee_user_id` 非空且无步骤负责人:可将该用户写入 **全部现有步骤** 的 assignee(一次性迁移),保证旧任务仍在「我的生产任务」可见。
|
||
- 无 assignee 且无步骤负责人的旧任务:行为与「未派步骤」一致,仅 manage 可见。
|
||
|
||
---
|
||
|
||
## 5. API 设计
|
||
|
||
### 5.1 步骤派发(批量)
|
||
|
||
```
|
||
PUT /api/web/admin/production-tasks/{taskId}/steps/dispatch
|
||
```
|
||
|
||
**Body**(camelCase 与现有约定一致):
|
||
|
||
```json
|
||
{
|
||
"steps": [
|
||
{
|
||
"stepId": "uuid",
|
||
"assigneeUserIds": ["u1", "u2"],
|
||
"plannedStartTime": "2026-06-25T09:00:00"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
**规则:**
|
||
|
||
- 至少 **1 个 step** 在请求中且 `assigneeUserIds.length >= 1`(允许部分步骤暂不派)。
|
||
- 未出现在请求中的步骤:**不修改** 其负责人与时间。
|
||
- 出现的步骤:**全量 sync** 负责人(软删旧 + 插入新,复用 `qc_task_assignee.sync_assignees` 模式)。
|
||
- `plannedStartTime` 可选;传 null 表示清空。
|
||
- 权限:`production:work-order:list`(manage);mine 端 **403**。
|
||
|
||
**响应:** 任务详情(含 steps、assignees、plannedStartTime、assigneeNames)。
|
||
|
||
### 5.2 创建生产任务
|
||
|
||
```
|
||
POST /api/web/admin/production-tasks
|
||
```
|
||
|
||
- **移除** `assigneeUserId` 必填校验。
|
||
- 可选扩展:同 body 内嵌 `stepDispatch` 数组(B 入口一次提交);或创建成功后前端再调 §5.1。
|
||
|
||
### 5.3 我的生产任务列表
|
||
|
||
```
|
||
GET /api/web/admin/production-tasks/mine
|
||
```
|
||
|
||
**过滤逻辑变更:**
|
||
|
||
- **current**:存在 `biz_production_task_step_assignee.user_id = 当前用户` 且 `del_flag=0` 的 **至少一个步骤** 的任务。
|
||
- **history**(若保留):曾出现在步骤 assignee 但当前已不在任一步 assignee 列表的任务(可选首版简化:与 current 合并或暂不实现 history 变更)。
|
||
|
||
> 首版:**替换** 原 `current_assignee_user_id = 我` 为主过滤条件;history 沿用 handover 逻辑仅作兼容,不作为步骤协作主路径。
|
||
|
||
### 5.4 步骤写操作鉴权
|
||
|
||
| 操作 | mine | manage |
|
||
|------|------|--------|
|
||
| 开始/完成/保存 **已派给自己** 的步骤 | ✅ | ✅ |
|
||
| 操作 **未派给自己** 的步骤 | ❌ 只读 | ✅ |
|
||
| 操作 **未派任何人** 的步骤 | ❌ 不可见 | ✅ |
|
||
| 编辑任务输入/产出/附件 | ✅ 若本人是任一步 assignee | ✅ |
|
||
| 步骤派发/改派 | ❌ | ✅ |
|
||
|
||
实现:在 `production_task` CRUD 增加 `assert_step_assignee(step_id, user_id)`;manage 路径跳过。
|
||
|
||
### 5.5 任务详情 / 列表 enrichment
|
||
|
||
- `_task_to_dict` / 步骤 `_step_to_dict` 增加:
|
||
- `assigneeUserIds: string[]`
|
||
- `assigneeNames: string[]`(或 `assignees: {userId, nickName, userNo}[]`)
|
||
- `plannedStartTime`
|
||
- `completedBy` / `completedByName`
|
||
- 列表接口批量 `_enrich_step_assignees`(对齐 QC `_enrich_assignee_names`)。
|
||
|
||
---
|
||
|
||
## 6. 前端设计
|
||
|
||
### 6.1 新增组件
|
||
|
||
| 组件 | 职责 |
|
||
|------|------|
|
||
| `DispatchStepDialog.vue` | 步骤派发表格:工序名、负责人多选、计划开始时间;提交 §5.1 |
|
||
|
||
### 6.2 改造组件
|
||
|
||
| 组件 | 变更 |
|
||
|------|------|
|
||
| `DispatchTaskDialog.vue` | **移除** 任务级「负责人」表单项与校验;选工艺路线且创建成功后 **可选打开** `DispatchStepDialog`(B) |
|
||
| `WorkOrderTaskSubList.vue` | 管理视角:任务卡片 meta 展示各步负责人 Tag + 计划开始时间;按钮「步骤派发 / 调整派发」 |
|
||
| `TaskExecutionDialog.vue` | mine:`canEditStep(step)` = 当前用户在 step.assigneeUserIds;否则只读;未派步骤不渲染或 manage 才显示 |
|
||
| `StepDetailPanel.vue` | 禁用开始/完成/保存按钮当 `!canEditStep` |
|
||
| `useTaskStepEditor.ts` | 传入 `operateScope`;步骤操作前校验 assignee |
|
||
| `production-task.ts` | 新增 `fetchDispatchProductionTaskSteps`;创建 body 去掉 assigneeUserId |
|
||
| `production-mine-task-groups.ts` | mine 列表依赖后端新过滤(前端无需按 task assignee 过滤) |
|
||
|
||
### 6.3 步骤派发表格 UI
|
||
|
||
| 列 | 控件 |
|
||
|----|------|
|
||
| 序号 / 工序名称 | 只读 |
|
||
| 负责人 | `el-select multiple filterable remote`,展示 `nickName(userNo)`,≥1 |
|
||
| 计划开始时间 | `el-date-picker type="datetime"`,可选 |
|
||
|
||
- 弹窗:`dialog-form-layout`,`label-position="top"`。
|
||
- 底栏:取消 / 确定(Close / Check 图标)。
|
||
|
||
### 6.4 执行弹窗 · 步骤列表视觉
|
||
|
||
- **可操作步骤**:现有高亮样式(`is-active`)。
|
||
- **只读步骤**:降低 opacity 或 `readonly` class;隐藏开始/完成/保存;保留状态 Tag。
|
||
- **未派步骤(mine)**:不展示(manage 正常展示并可操作)。
|
||
|
||
### 6.5 Deprecated UI
|
||
|
||
- 任务级「转发」「改派」按钮:管理页 **隐藏或替换** 为「步骤派发」;API 保留不删。
|
||
|
||
---
|
||
|
||
## 7. 改派规则
|
||
|
||
| 步骤状态 | 改负责人 | 改计划开始时间 | 步骤是否 reopen |
|
||
|----------|----------|----------------|-----------------|
|
||
| `dzx` | ✅ | ✅ | — |
|
||
| `jxz` | ✅ | ✅ | 否,新负责人接手进行中步骤 |
|
||
| `ywc` | ✅(仅影响 mine 可见性) | ✅ | **否** |
|
||
|
||
---
|
||
|
||
## 8. 任务 / 工单状态联动
|
||
|
||
- **任务状态**(`dpz/jxz/ywc`)逻辑 **不变**:仍由步骤聚合 + 现有 `sync_production_work_order_status_from_tasks` 驱动。
|
||
- **未派步骤** 不参与 mine 过滤;manage 仍可执行未派步骤(管理员兜底)。
|
||
|
||
---
|
||
|
||
## 9. 权限与菜单
|
||
|
||
| 能力 | menuCode |
|
||
|------|----------|
|
||
| 生产工单(manage、步骤派发) | `production:work-order:list` |
|
||
| 我的生产任务 | `production:my-task:list` |
|
||
|
||
无需新增菜单;步骤派发挂在工单页任务操作区。
|
||
|
||
---
|
||
|
||
## 10. 测试要点
|
||
|
||
1. B 入口:选路线 → 创建 → 步骤派发 → 各 assignee 在 mine 见任务,仅自己步骤可操作。
|
||
2. A 入口:无路线创建 → 手工加步骤 → 步骤派发 → 同上。
|
||
3. 一步多人:A、B 均可见任务;A 完成后 B 见只读已完成。
|
||
4. 同人多步:mine 展开见多个可操作步骤。
|
||
5. 计划开始时间:列表/卡片展示;未到时间仍可执行。
|
||
6. 未派步骤:mine 不可见;manage 可见可操作。
|
||
7. 改派:`dzx/jxz/ywc` 按 §7;mine 不可改派。
|
||
8. 旧任务兼容(若跑迁移脚本):原 task assignee 仍可见。
|
||
|
||
---
|
||
|
||
## 11. 文件清单(实施参考)
|
||
|
||
| 层 | 文件 |
|
||
|----|------|
|
||
| SQL | `docs/sql/migrations/2026-06-25-production-step-dispatch.sql`,同步 `docs/sql/zkxw.sql` |
|
||
| Backend Model | `backend/app/models/models.py` — `BizProductionTaskStepAssignee` + 步骤新字段 |
|
||
| Backend CRUD | `backend/app/crud/production_task_step_assignee.py`(新建,对齐 qc_task_assignee) |
|
||
| Backend CRUD | `backend/app/crud/production_task.py` — mine 过滤、step assert、complete 写 completed_by |
|
||
| Backend Schema | `backend/app/schemas/production_task.py` — DispatchStepsBody |
|
||
| Backend API | `backend/app/api/production.py` — PUT steps/dispatch;调整 create/mine |
|
||
| Frontend API | `web-admin/src/api/production-task.ts` |
|
||
| Frontend | `DispatchStepDialog.vue`(新建) |
|
||
| Frontend | `DispatchTaskDialog.vue`, `WorkOrderTaskSubList.vue`, `TaskExecutionDialog.vue`, `StepDetailPanel.vue`, `useTaskStepEditor.ts` |
|
||
|
||
---
|
||
|
||
## 12. 与 OpenSpec / 既有 spec 关系
|
||
|
||
- supersede 部分:`2026-06-13-production-task-assignee-my-tasks-design.md` 中 **任务级单一负责人 + 任务转发** 产品路径;本 spec 以 **步骤级多人 + 步骤改派** 为准。
|
||
- 对齐 `api-conventions`:租户隔离、软删除、`operateScope=mine|manage`。
|
||
- 对齐 `ui-conventions`:Fresh Mint 弹窗、按钮图标、Tag 展示负责人。
|
||
|
||
---
|
||
|
||
## 13. 版本记录
|
||
|
||
| 日期 | 说明 |
|
||
|------|------|
|
||
| 2026-06-25 | 初稿:步骤级派发方案 1,产品决策 D1–D11 已确认 |
|