日期: 2026-06-12
状态: 已实现(2026-06-12)
范围: web-admin + backend(质检工单三 Tab、配置/调整检测、我的质检任务)
质检工单页(入库 / 出库 / 临时三个 Tab)通过「配置检测」「调整检测」生成质检任务,但任务无负责人指派。质检专员无法在独立入口查看「分给自己的任务」并填写结果。
本变更引入任务负责人(单人或多人的集合),并在「质检管理」下新增我的质检任务菜单页。
| 问题 | 决策 |
|---|---|
| 多人负责时,完成语义? | A — 任一负责人可独立完成(开始、填写结果、完成);completed_by 记录实际操作人 |
| 工单页 vs 我的任务页操作权限? | A — 管理覆盖:我的任务页仅 assignee 可操作;工单展开行持有 biz:qcTask:list 可督办全部任务 |
| 负责人数据存储方式? | 关联表 biz_qc_task_assignee(非逗号分隔字段) |
| 负责人指派粒度? | 每个检测项目(对应一条 biz_qc_task)独立指派 |
| 配置时负责人是否必填? | 是 — 每个已勾选的 lab/third 项目至少 1 人 |
| 项 | 现状 |
|---|---|
| 配置 API | POST /web/admin/qc-work-orders/{id}/configure |
| 任务生成 | 每个 lab/third 明细行 → create_task_for_line;保留项不重建 |
| 任务操作 | QcWorkOrderTaskSubList.vue:开始 / 填写结果 / 查看 / 删除 |
| 我的视角参考 | my-qc-material-usage(mine-only + 独立 menuCode) |
| 工作流参考 | wf_task.assignee_user_id + task-pending 过滤模式 |
当前缺失:biz_qc_task 无 assignee;list_tasks 无「我的任务」过滤。
qc-work-order/index.vue 配置弹窗中,每个已勾选的实验室 / 第三方检测项目旁增加负责人多选(el-select multiple filterable)。sys_user(展示 nickName(userNo),与流程设计器一致)。_sync_* 逻辑);ywc):若检测项目仍保留,允许改负责人(仅影响「我的任务」可见性,不改 completed_by);不建议移除已完成项对应的检测项目(现有逻辑已限制删除进行中/已完成任务的场景,保持后端既有校验)。QcWorkOrderTaskSubList.vue(或抽取的共用组件)任务卡片 meta 区展示负责人(el-tag 或 muted 文本,多人用顿号连接)。biz:qcTask:list 的用户仍可按现有状态机操作(管理督办)。/#/quality-manage/my-qc-taskweb-admin/src/views/quality-inspection/my-qc-task/index.vue质检管理 → 我的质检任务,menuCode: biz:myQcTask:listorder/index.vue,任务卡片与结果弹窗复用 QcWorkOrderTaskSubList 抽取逻辑。筛选区(filter-block):
| 字段 | 类型 |
|---|---|
| 关键词 | 任务编号 / 项目名称 / 工单号 / 样本编码 |
| 任务状态 | dzx / jxz / ywc |
| 任务类型 | sysz / dsfjc |
| 工单类型 | inbound / outbound / temporary |
列表列 / 卡片信息:
QcWorkOrderTaskSubList)查看详情:
SystemViewDialog 或现有任务查看逻辑OutboundQcViewDialog操作权限(严格):
current_user_id ∈ assignee_user_ids 时展示「开始」「填写结果」三处对齐(参照 2026-06-11-my-qc-material-usage-menu.sql):
web-admin/src/router/modules/sqxp.tsbackend/app/api/menu.pydocs/sql/migrations/2026-06-12-my-qc-task-menu.sql + docs/sql/zkxw.sql| 菜单 | path | perms | order_num(建议) |
|---|---|---|---|
| 我的质检任务 | my-qc-task |
biz:myQcTask:list |
5(在「我的物料领用记录」之后) |
角色授权:默认给质检相关角色;超管租户管理员在菜单管理中分配。
biz_qc_task_assigneeCREATE TABLE `biz_qc_task_assignee` (
`id` varchar(64) NOT NULL COMMENT '主键',
`task_id` varchar(64) NOT NULL COMMENT '质检任务ID',
`user_id` varchar(64) NOT NULL COMMENT '负责人用户ID',
`tenant_no` varchar(64) NOT NULL COMMENT '租户编号',
`order_num` int DEFAULT 0 COMMENT '展示顺序',
`remark` varchar(512) DEFAULT NULL COMMENT '备注',
`create_by` varchar(64) DEFAULT NULL,
`create_dept_id` varchar(64) DEFAULT NULL,
`create_time` datetime DEFAULT NULL,
`update_by` varchar(64) DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
`del_flag` tinyint DEFAULT 0 COMMENT '删除标志',
PRIMARY KEY (`id`),
KEY `idx_qc_task_assignee_task` (`task_id`, `del_flag`),
KEY `idx_qc_task_assignee_user` (`user_id`, `tenant_no`, `del_flag`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='质检任务负责人';
唯一性在应用层保证:同一
task_id+user_id未删除记录不重复插入。
WorkOrderConfigureBody 增加:
lab_item_assignees: Dict[str, List[str]] = Field(default_factory=dict, alias="labItemAssignees")
third_party_item_assignees: Dict[str, List[str]] = Field(default_factory=dict, alias="thirdPartyItemAssignees")
lab_test_item_id / third_party_item_id)lab_item_ids 中每个 id 必须在 lab_item_assignees 中有非空列表;third 同理_task_to_dict / _task_row_to_dict 增加:
| 字段 | 类型 | 说明 |
|---|---|---|
assigneeUserIds |
string[] |
负责人 ID 列表 |
assigneeUserNames |
string |
负责人姓名,顿号分隔 |
biz:qcTask:list 操作(管理覆盖)。POST /web/admin/qc-work-orders/{work_order_id}/configure
biz:qcWorkOrder:list(不变)_sync_work_order_lab_items / _sync_work_order_third_party_items 任务创建或保留后,调用 _sync_task_assignees(task_id, user_ids)。user_id 须属于当前 tenant_no 且用户有效。GET /web/admin/qc-tasks/mine
biz:myQcTask:listpage, pageSize, keyword, taskType, taskStatus, qcBizType(工单类型)JOIN biz_qc_task_assignee ON task_id AND user_id = 当前用户 AND del_flag=0create_time DESC(任务)GET /qc-tasks 列表项结构一致,附带工单摘要字段(workOrderNo, workOrderType, qcBizType, sampleCode)对以下端点增加 可选严格模式 参数或根据请求来源/menuCode 区分;推荐实现:新增内部函数 _require_task_assignee_or_qc_admin(task, user, strict=False):
| 端点 | 我的任务页调用 | 工单页调用 |
|---|---|---|
POST /qc-tasks/{id}/start |
strict=True:须 assignee |
strict=False:仅需 biz:qcTask:list |
POST /qc-tasks/{id}/complete-with-result |
同上 | 同上 |
PUT /qc-tasks/{id}/attachments |
同上 | 同上 |
实现方式(推荐):请求头或 query operateScope=mine|manage:
mine:biz:myQcTask:list + assignee 校验manage(默认):biz:qcTask:list,不校验 assignee前端:
my-qc-task 所有写请求带 operateScope=mineQcWorkOrderTaskSubList 不带或 operateScope=manageGET /web/admin/qc-tasks:不变;可选后续增加 assigneeUserId 筛选(v1 不必须)。
从 QcWorkOrderTaskSubList.vue 抽取:
| 组件 | 职责 |
|---|---|
QcTaskCardList.vue |
任务卡片列表 + 操作按钮显隐 |
QcTaskResultDialog.vue |
填写检测结果弹窗(参数 / 物料 / 结论) |
Props:
tasks: QcTask[]operateScope: 'mine' | 'manage'loading, onRefresh避免 1500+ 行逻辑双份维护。
el-select 同一行或下一行缩进width 保持 900px 或略增至 960px 以容纳选人控件ElMessageBox.alert + scroll-to-error(与规范一致)沿用 status-tag-registry.ts 既有 qcTaskStatus、qcTaskType、qcTaskConclusion 映射。
backend/app/crud/qc_task_assignee.py(或合入 qc_task.py):
sync_assignees_for_task(db, task_id, user_ids, tenant_no, user_id)soft_delete_assignees_by_task_ids(db, task_ids, tenant_no)list_assignees_by_task_ids(db, task_ids) -> Dict[task_id, List[user]]is_user_assignee(db, task_id, user_id) -> boolqc_work_order.py → _sync_work_order_lab_items / _sync_work_order_third_party_items:
_row_to_dict(任务)须含 assigneeUserIds(只读)labItemAssignees / thirdPartyItemAssigneespython scripts/check_field_consistency.py| 场景 | 预期 |
|---|---|
| 配置检测,每项选 1 人 | 生成任务 + assignee;我的任务可见 |
| 配置检测,某项未选人 | 400 校验错误 |
| 调整检测改负责人 | assignee 更新;新负责人可见,旧负责人不可见(未完成时) |
| 调整检测新增项目 | 新任务 + 新 assignee |
| 调整检测移除项目 | 任务与 assignee 软删 |
| 我的任务:assignee 开始/填结果 | 成功 |
| 我的任务:非 assignee 写操作 | 403 |
| 工单展开行:非 assignee 有 qcTask:list | 仍可操作 |
| 多人 assignee,一人完成 | 任务 ywc;他人列表变已完成 |
| 历史无 assignee 任务 | 不出现在我的任务;工单页可操作 |
| 层级 | 文件 |
|---|---|
| SQL | docs/sql/migrations/2026-06-12-qc-task-assignee.sql, 2026-06-12-my-qc-task-menu.sql, docs/sql/zkxw.sql |
| Backend | models.py, qc_task.py, qc_work_order.py, qc.py, menu.py |
| Frontend | sqxp.ts, qc-work-order/index.vue, my-qc-task/index.vue, 抽取组件, qc-task.ts, qc-work-order.ts, api.d.ts |
| 图谱 | ./scripts/update-graph.sh backend frontend |
在 openspec/changes/ 或归档后 openspec/specs/ 补充:
api-conventions:质检任务 assignee 与 operateScope 鉴权ui-conventions:配置检测负责人选择、我的质检任务 参考页登记请评审本文档。 确认无修改后,进入 writing-plans 生成实现任务分解。