For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: 派发生产任务时指定负责人;新增「我的生产任务」双 Tab 页(当前 / 历史);支持任意状态下转发与管理员改派;我的任务页严格按负责人过滤,工单页保持管理覆盖。
Architecture: biz_production_task.current_assignee_user_id 存当前唯一负责人;biz_production_task_handover 记录转发/改派历史。API 层复用 QC 的 operateScope=mine|manage 鉴权模式。前端复用 WorkOrderTaskSubList + TaskExecutionDialog,新增 my-production-task/index.vue。
Tech Stack: MySQL 5.7 · FastAPI · SQLAlchemy · Vue 3 · Element Plus · pnpm
Design Spec: docs/superpowers/specs/2026-06-13-production-task-assignee-my-tasks-design.md
| 文件 | 职责 |
|---|---|
docs/sql/migrations/2026-06-13-production-task-assignee.sql |
任务表字段 + handover 表 |
docs/sql/migrations/2026-06-13-my-production-task-menu.sql |
菜单 INSERT |
backend/app/models/models.py |
BizProductionTaskHandover 模型 + 任务字段 |
backend/app/crud/production_task.py |
create/list_mine/forward/reassign/assert_assignee |
backend/app/schemas/production_task.py |
Create/Forward/Reassign body |
backend/app/api/production.py |
新路由 + operateScope 挂到写接口 |
backend/app/api/menu.py |
菜单种子 |
web-admin/src/api/production-task.ts |
mine/forward/reassign API |
web-admin/src/views/production/my-production-task/index.vue |
双 Tab 页面 |
web-admin/src/views/production/production-work-order/DispatchTaskDialog.vue |
派发选负责人 |
web-admin/src/views/production/production-work-order/WorkOrderTaskSubList.vue |
listMode + 负责人展示 + 改派/转发 |
web-admin/src/views/production/production-work-order/TaskExecutionDialog.vue |
operateScope + 转发按钮 |
web-admin/src/views/production/production-work-order/ForwardTaskDialog.vue |
新建 转发/改派共用弹窗 |
web-admin/src/router/modules/sqxp.ts |
路由注册 |
web-admin/src/App.vue |
panelTitleBarTextRules |
Files:
docs/sql/migrations/2026-06-13-production-task-assignee.sqlModify: docs/sql/zkxw.sql(同步表结构片段)
[ ] Step 1: 编写 migration SQL
-- docs/sql/migrations/2026-06-13-production-task-assignee.sql
ALTER TABLE `biz_production_task`
ADD COLUMN `current_assignee_user_id` varchar(64) DEFAULT NULL
COMMENT '当前负责人用户ID' AFTER `task_status`;
CREATE TABLE IF NOT EXISTS `biz_production_task_handover` (
`id` varchar(64) NOT NULL COMMENT '主键',
`task_id` varchar(64) NOT NULL COMMENT '生产任务ID',
`from_user_id` varchar(64) NOT NULL COMMENT '转出用户ID',
`to_user_id` varchar(64) NOT NULL COMMENT '接收用户ID',
`handover_time` datetime NOT NULL COMMENT '转发时间',
`remark` varchar(512) DEFAULT NULL COMMENT '转发说明',
`tenant_no` varchar(64) NOT NULL COMMENT '租户编号',
`order_num` int DEFAULT 0,
`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,
PRIMARY KEY (`id`),
KEY `idx_prod_task_handover_task` (`task_id`, `del_flag`),
KEY `idx_prod_task_handover_from` (`from_user_id`, `tenant_no`, `del_flag`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='生产任务转发记录';
Run: 在测试库执行上述 SQL
Expected: biz_production_task 新增列;biz_production_task_handover 表存在
docs/sql/zkxw.sql 对应 DDLFiles:
backend/app/models/models.pyModify: backend/app/schemas/production_task.py
[ ] Step 1: BizProductionTask 增加列
在 BizProductionTask 的 task_status 后添加:
current_assignee_user_id = Column(String(64), nullable=True, comment="当前负责人用户ID")
BizProductionTaskHandover 模型参照 design spec §5.3,放在 BizProductionTask 附近。
backend/app/schemas/production_task.py:
class ProductionTaskCreate(BaseModel):
model_config = ConfigDict(populate_by_name=True)
work_order_id: str
assignee_user_id: str = Field(..., alias="assigneeUserId")
task_type: Optional[str] = 'cell_storage'
task_name: Optional[str] = None
route_id: Optional[str] = None
description: Optional[str] = None
remark: Optional[str] = None
class ProductionTaskForwardBody(BaseModel):
model_config = ConfigDict(populate_by_name=True)
to_user_id: str = Field(..., alias="toUserId")
remark: Optional[str] = None
class ProductionTaskAssigneeUpdate(BaseModel):
model_config = ConfigDict(populate_by_name=True)
assignee_user_id: str = Field(..., alias="assigneeUserId")
remark: Optional[str] = None
Files:
Modify: backend/app/crud/production_task.py
[ ] Step 1: 扩展 _task_to_dict
增加字段(批量 list 时由 enrich 函数补充姓名):
"currentAssigneeUserId": t.current_assignee_user_id or "",
"currentAssigneeUserName": "", # enrich 填充
def _validate_tenant_user_ids(db: Session, user_ids: List[str], tenant_no: str) -> None:
# 去重、非空;查询 sys_user 有效且 tenant_no 匹配;缺失则 raise ValueError
[ ] Step 3: 修改 create_production_task
body 读取 assignee_user_id,校验必填;
创建时设置 task.current_assignee_user_id = assignee_user_id。
[ ] Step 4: 新增 assert_task_assignee
def assert_task_assignee(db, task_id: str, user_id: str, tenant_no: str) -> BizProductionTask:
task = get_task(...)
if (task.current_assignee_user_id or "") != user_id:
raise PermissionError("非当前任务负责人,无权操作")
return task
forward_production_taskdef forward_production_task(
db, task_id, *, from_user_id, to_user_id, tenant_no, operator_id, create_dept_id, remark=None
) -> BizProductionTask:
if from_user_id == to_user_id:
raise ValueError("不能转发给自己")
_validate_tenant_user_ids(db, [to_user_id], tenant_no)
task = assert_task_assignee(db, task_id, from_user_id, tenant_no) # mine 场景
# 插入 BizProductionTaskHandover
task.current_assignee_user_id = to_user_id
task.update_by = operator_id
task.update_time = datetime.now()
db.add(task)
return task
[ ] Step 6: 新增 reassign_production_task(管理员改派)
不强制 assert 当前用户是 assignee;
from_user_id = 原 current_assignee_user_id 或 operator_id;
remark 默认「管理员改派」;
同样写 handover + 更新 current。
[ ] Step 7: 新增 list_mine_production_tasks
Query 参数:scope=current|history
# current: current_assignee_user_id == assignee_user_id
# history: EXISTS handover WHERE from_user_id == me AND current_assignee_user_id != me
复用 list_production_tasks 的 keyword / task_status / 工单 enrich 逻辑(可抽 _enrich_task_rows)。
[ ] Step 8: _enrich_assignee_names
批量查 sys_user 填 currentAssigneeUserName;history 列表额外填 handoverTime(子查询 MAX handover_time where from_user_id=me)。
Run: python scripts/check_field_consistency.py
Expected: production_task 相关无缺失字段告警
Files:
Modify: backend/app/api/production.py
[ ] Step 1: 新增 _assert_production_task_write_access
参照 backend/app/api/qc.py 的 _assert_task_write_access:
def _assert_production_task_write_access(db, user, task_id, tenant_no, operate_scope):
scope = (operate_scope or "manage").strip().lower()
user_id = user.get("user_id")
role = user.get("role")
codes = get_user_menu_codes(db, user_id) if role != SUPER_ADMIN_ROLE else set()
if scope == "mine":
if role != SUPER_ADMIN_ROLE and "production:my-task:list" not in codes:
raise PermissionError("无菜单访问权限")
production_task_svc.assert_task_assignee(db, task_id, user_id, tenant_no)
elif role != SUPER_ADMIN_ROLE and "production:work-order:list" not in codes:
raise PermissionError("无菜单访问权限")
| Method | Path | 权限 |
|---|---|---|
| GET | /production-tasks/mine |
require_menu_code("production:my-task:list") |
| POST | /production-tasks/{id}/forward |
require_any_menu_code("production:my-task:list", "production:work-order:list") |
| PUT | /production-tasks/{id}/assignee |
require_menu_code("production:work-order:list") |
forward:operateScope=mine 时 assert assignee;manage 时仅校验 work-order list。
[ ] Step 3: 为写接口挂 operateScope
在以下端点增加 operateScope: Optional[str] = Query(None) 并调用 _assert_production_task_write_access:
PUT /production-tasks/{id}/statusPOST|PUT|DELETE steps 相关PUT step reagents/consumables/data-collection/outputsPOST inputs/outputsGET 详情保持不变(mine 页只读也允许看)。
ProductionTaskCreate.assignee_user_id 必填,400 若缺失或用户无效。
Files:
docs/sql/migrations/2026-06-13-my-production-task-menu.sqldocs/sql/zkxw.sqlbackend/app/api/menu.pyweb-admin/src/router/modules/sqxp.tsModify: web-admin/src/App.vue
[ ] Step 1: 菜单 SQL
INSERT INTO `sys_menu` (...) VALUES (
'94000000000000000000000000000001', '我的生产任务', 'PRM00000000000000000000000000001', 'C',
'my-production-task', '/production/my-production-task/index',
'production:my-task:list',
1, '1', '1', 'zkxw', 4, NULL, ...
) ON DUPLICATE KEY UPDATE ...;
parent_id = PRM00000000000000000000000000001(生产管理),order_num = 4(生产工单之后)。
menu.py 生产管理 children 增加{
"path": "my-production-task",
"component": "/production/my-production-task/index",
"meta": {
"title": "我的生产任务",
"menuCode": "production:my-task:list",
},
},
sqxp.ts 路由在 production-work-order 路由后添加 my-production-task 子路由,component 指向新页面。
App.vue panelTitleBarTextRules添加 '我的生产任务'。
Files:
Modify: web-admin/src/api/production-task.ts
[ ] Step 1: 类型与 operateScope
export type ProductionTaskOperateScope = 'mine' | 'manage'
export function fetchMyProductionTasks(params: {
page?: number
pageSize?: number
keyword?: string
taskStatus?: string
workOrderType?: string
scope: 'current' | 'history'
}) {
return request.get({ url: '/web/admin/production-tasks/mine', params })
}
export function fetchForwardProductionTask(
id: string,
data: { toUserId: string; remark?: string },
operateScope?: ProductionTaskOperateScope
) {
return request.post({
url: `/web/admin/production-tasks/${id}/forward`,
params: data,
...(operateScope === 'mine' ? { params: { ...data, operateScope: 'mine' } } : {})
})
}
export function fetchReassignProductionTask(id: string, data: { assigneeUserId: string; remark?: string }) {
return request.put({ url: `/web/admin/production-tasks/${id}/assignee`, params: data })
}
operateScope参照 web-admin/src/api/qc-task.ts,mine 模式请求带 operateScope=mine:
fetchUpdateProductionTaskStatusstep CRUD 等(TaskExecutionDialog 使用的全部写接口)
[ ] Step 3: fetchCreateProductionTask 增加 assigneeUserId
Files:
web-admin/src/views/production/production-work-order/DispatchTaskDialog.vueCreate: web-admin/src/composables/useTenantUserOptions.ts(若 QC 侧无共用 composable 则新建)
[ ] Step 1: form 增加 assigneeUserId
const form = reactive({
taskName: '',
routeId: '',
description: '',
remark: '',
assigneeUserId: ''
})
const rules = {
taskName: [{ required: true, message: '请输入任务名称', trigger: 'blur' }],
assigneeUserId: [{ required: true, message: '请选择负责人', trigger: 'change' }]
}
form-grid-2 内、taskName 下方或同排:
<el-form-item label="负责人" prop="assigneeUserId" class="form-col-span-2">
<el-select v-model="form.assigneeUserId" filterable placeholder="请选择负责人" style="width: 100%">
<el-option
v-for="u in userOptions"
:key="u.id"
:label="`${u.nickName}(${u.userNo})`"
:value="u.id"
/>
</el-select>
</el-form-item>
[ ] Step 3: handleCreateTask 传 assigneeUserId
[ ] Step 4: 弹窗打开时 loadUserOptions()
复用 QC 配置检测的用户列表 API(如 fetchUserList from admin API)。
Files:
web-admin/src/views/production/production-work-order/ForwardTaskDialog.vueModify: web-admin/src/views/production/production-work-order/WorkOrderTaskSubList.vue
[ ] Step 1: 新建 ForwardTaskDialog.vue
Props: visible, taskId, mode: 'forward' | 'reassign', operateScope
Emit: success
表单:下一负责人 + 备注;提交调 forward 或 reassign API。
WorkOrderTaskSubList 增加 propslistMode?: 'workOrder' | 'mine-current' | 'mine-history'
mineFilters?: { keyword, taskStatus, workOrderType }
page?, pageSize?, refreshToken?
workOrder:原逻辑,fetchProductionTaskList({ workOrderId })mine-*:调 fetchMyProductionTasks({ scope: 'current'|'history', ...mineFilters, page, pageSize })emit update:total 供分页
[ ] Step 3: 卡片 meta 展示负责人
<span class="work-order-task-card__meta-item">
负责人:{{ row.currentAssigneeUserName || '—' }}
</span>
| listMode | 按钮 |
|---|---|
| mine-current | 执行/查看 + 转发(当前用户是 assignee 时) |
| mine-history | 仅查看 |
| workOrder | 现有 + 改派(dropdown) |
operateScope computedconst operateScope = computed(() =>
props.listMode?.startsWith('mine') ? 'mine' : 'manage'
)
进入 TaskExecutionDialog 时传入 :operate-scope="operateScope"。
Files:
Modify: web-admin/src/views/production/production-work-order/TaskExecutionDialog.vue
[ ] Step 1: props
operateScope?: 'mine' | 'manage' | 'history' // history 强制 readonly
readonly?: boolean // 已有;history 模式设为 true
非 readonly 且 operateScope !== 'history' 时显示;任意 taskStatus 均可(D3)。
找到 task execution 使用的 status/step API 调用,mine 时附加 query。
Files:
Create: web-admin/src/views/production/my-production-task/index.vue
[ ] Step 1: 页面骨架
参照 my-qc-task/index.vue:
panel-top 标题「我的生产任务」el-tabs:当前任务 / 历史执行filter-block(关键词、任务状态、工单类型)WorkOrderTaskSubList with listMode="mine-current" / "mine-history"分页 list-pager-bar
[ ] Step 2: Tab 切换重置 page 并 refresh
[ ] Step 3: filter hint 文案
当前:仅展示当前指派给您的生产任务。
历史:展示您曾负责并已转出的任务,仅可查看。
[ ] Step 4: 高度自适应
复用 my-qc-task 的 ResizeObserver 逻辑。
| 场景 | 预期 |
|---|---|
| 派发未选负责人 | 400 |
| A 当前可见,B 不可见 | ✓ |
| dpz/jxz/ywc 均可转发 | ✓ |
| A 转发后历史 Tab 只读 | ✓ |
| 管理员改派 | handover 有记录;新负责人当前可见 |
| mine 非 assignee 写操作 | 403 |
| 工单页 manage 督办 | 成功 |
Run: ./scripts/update-graph.sh backend frontend
Run: pnpm lint(web-admin 改动文件)
Expected: 无新增 error
| Spec 章节 | Task |
|---|---|
| §4.1 派发选负责人 | Task 7 |
| §4.2 工单展示负责人 + 改派 | Task 8 |
| §4.3 执行 + 转发 | Task 9 |
| §4.4 我的生产任务双 Tab | Task 10 |
| §4.5 菜单 | Task 5 |
| §5 数据模型 | Task 1–2 |
| §6 API | Task 3–4 |
| §6.3 operateScope | Task 4, 6, 9 |
| §6.4 管理员改派 | Task 3, 8 |
| D1–D10 全部决策 | 已写入 spec,本 plan 全覆盖 |