# 四页面新增功能实施计划 > **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:** 为4个页面(入库质检工单、质检任务、入库生产工单、生产任务)新增"手动创建"功能,支持用户独立新增实体记录。 **Architecture:** 后端新增3个手动创建接口(生产任务已有),前端4个页面各自增加新增按钮和表单弹窗。工单/任务不再强依赖上游实体(样本接收记录/工单),通过空字符串默认值兼容现有 DB schema。 **Tech Stack:** FastAPI + Pydantic v2 (后端), Vue 3 + Element Plus (前端) **初始状态约定:** - 质检工单 → `dpz`(待配置) - 生产工单 → `dpz`(待配置) - 质检任务 → `dzx`(待执行) - 生产任务 → `dpz`(待配置) --- ## File Structure ### Backend (新建) | 文件 | 职责 | |------|------| | `backend/app/schemas/qc_work_order.py` | 质检工单 CreateBody schema | | `backend/app/schemas/qc_task.py` | 质检任务 CreateBody schema | | `backend/app/schemas/production_work_order.py` | **修改** 追加 CreateBody schema | ### Backend (修改) | 文件 | 职责 | |------|------| | `backend/app/crud/qc_work_order.py` | 新增 `create_qc_work_order_manual()` | | `backend/app/crud/qc_task.py` | 新增 `create_qc_task_manual()` | | `backend/app/crud/production_work_order.py` | 新增 `create_production_work_order_manual()` | | `backend/app/api/qc.py` | 新增 `POST /qc-work-orders` 和 `POST /qc-tasks` 路由 | | `backend/app/api/production.py` | 新增 `POST /production-work-orders` 路由 | ### Frontend (修改) | 文件 | 职责 | |------|------| | `web-admin/src/api/qc-work-order.ts` | 新增 `fetchCreateQcWorkOrder()` | | `web-admin/src/api/qc-task.ts` | 新增 `fetchCreateQcTask()` | | `web-admin/src/api/production-work-order.ts` | 新增 `fetchCreateProductionWorkOrder()` | | `web-admin/src/views/quality-inspection/qc-work-order/index.vue` | 新增按钮 + 创建弹窗 | | `web-admin/src/views/quality-inspection/qc-task/index.vue` | 新增按钮 + 创建弹窗 | | `web-admin/src/views/production/production-work-order/index.vue` | 新增按钮 + 创建弹窗 | | `web-admin/src/views/production/production-task/index.vue` | 新增按钮 + 工单选择 + 复用 DispatchTaskDialog | --- ## Task 1: 质检工单 — 后端手动创建接口 **Files:** - Create: `backend/app/schemas/qc_work_order.py` - Modify: `backend/app/crud/qc_work_order.py` - Modify: `backend/app/api/qc.py` ### Step 1: 创建 Pydantic CreateBody schema 创建 `backend/app/schemas/qc_work_order.py`: ```python from pydantic import BaseModel, ConfigDict, Field from typing import Optional class QcWorkOrderCreateBody(BaseModel): """手动创建质检工单""" model_config = ConfigDict(populate_by_name=True) protocol_no: Optional[str] = Field(None, alias="protocolNo", description="协议号") sample_code: Optional[str] = Field(None, alias="sampleCode", description="样本编码") reception_source: Optional[str] = Field("cell_storage", alias="receptionSource", description="来源类型") qc_biz_type: Optional[str] = Field("inbound", alias="qcBizType", description="质检业务类型") remark: Optional[str] = Field(None, description="备注") ``` - [ ] 创建 schema 文件 ### Step 2: CRUD 层新增手动创建方法 在 `backend/app/crud/qc_work_order.py` 末尾新增: ```python def create_qc_work_order_manual( db: Session, *, tenant_no: str, user_id: Optional[str] = None, create_dept_id: str = "", protocol_no: str = "", sample_code: str = "", reception_source: str = "cell_storage", qc_biz_type: str = "inbound", remark: str = "", ) -> BizQcWorkOrder: """手动创建质检工单(不关联接收记录)""" wo = BizQcWorkOrder( id=generate_uuid(), work_order_no=_gen_daily_no(db, tenant_no, "ZJ"), reception_id="", protocol_sample_id="", collection_protocol_id="", protocol_no=protocol_no, sample_code=sample_code, reception_source=reception_source, qc_biz_type=qc_biz_type, work_order_status="dpz", has_lab="0", has_third_party="0", tenant_no=tenant_no, remark=remark, create_by=user_id, create_dept_id=create_dept_id, ) db.add(wo) db.flush() return wo ``` - [ ] 在 qc_work_order.py 末尾新增 `create_qc_work_order_manual` ### Step 3: API 路由新增 POST 端点 在 `backend/app/api/qc.py` 的 `@router.get("/qc-work-orders")` 之前(约第549行前),新增: ```python @router.post("/qc-work-orders") async def create_qc_work_order( body: QcWorkOrderCreateBody, db: Session = Depends(get_db), user: dict = Depends(require_menu_code("biz:qcWorkOrder:list")), ): try: tenant_no = _get_tenant_no(db, user) wo = wo_svc.create_qc_work_order_manual( db, tenant_no=tenant_no, user_id=user.get("user_id"), create_dept_id=user.get("dept_id", ""), protocol_no=body.protocol_no or "", sample_code=body.sample_code or "", reception_source=body.reception_source or "cell_storage", qc_biz_type=body.qc_biz_type or "inbound", remark=body.remark or "", ) db.commit() return success_response(wo_svc._wo_to_dict(wo), message="创建成功") except PermissionError as e: return error_response(403, str(e)) except Exception as e: db.rollback() return error_response(400, str(e)) ``` 同时在文件顶部 import: ```python from app.schemas.qc_work_order import QcWorkOrderCreateBody ``` - [ ] 新增 POST 路由和 import ### Step 4: 验证 - [ ] 启动后端,访问 `/docs`,确认 `POST /api/web/admin/qc-work-orders` 出现 --- ## Task 2: 质检任务 — 后端手动创建接口 **Files:** - Create: `backend/app/schemas/qc_task.py` - Modify: `backend/app/crud/qc_task.py` - Modify: `backend/app/api/qc.py` ### Step 1: 创建 Pydantic CreateBody schema 创建 `backend/app/schemas/qc_task.py`: ```python from pydantic import BaseModel, ConfigDict, Field from typing import Optional class QcTaskCreateBody(BaseModel): """手动创建质检任务""" model_config = ConfigDict(populate_by_name=True) task_type: str = Field(..., alias="taskType", description="检测类型 sysz/dsfjc") item_code: str = Field(..., alias="itemCode", description="项目编码") item_name: str = Field(..., alias="itemName", description="项目名称") company_id: Optional[str] = Field(None, alias="companyId", description="第三方公司ID") company_name: Optional[str] = Field(None, alias="companyName", description="第三方公司名") fee_amount: Optional[float] = Field(None, alias="feeAmount", description="费用") sample_code: Optional[str] = Field(None, alias="sampleCode", description="样本编码") qc_biz_type: Optional[str] = Field("inbound", alias="qcBizType", description="质检业务类型") work_order_id: Optional[str] = Field(None, alias="workOrderId", description="关联工单ID(可选)") remark: Optional[str] = Field(None, description="备注") ``` - [ ] 创建 schema 文件 ### Step 2: CRUD 层新增手动创建方法 在 `backend/app/crud/qc_task.py` 末尾新增: ```python def create_qc_task_manual( db: Session, *, tenant_no: str, user_id: Optional[str] = None, create_dept_id: str = "", task_type: str = "sysz", item_code: str = "", item_name: str = "", company_id: Optional[str] = None, company_name: Optional[str] = None, fee_amount: Optional[float] = None, sample_code: str = "", work_order_id: str = "", remark: str = "", ) -> BizQcTask: """手动创建质检任务(可独立于工单)""" # 生成任务号:ZJRW + 日期 + 序号 day = datetime.now().strftime("%Y%m%d") like = f"ZJRW{day}%" cnt = db.query(BizQcTask).filter( BizQcTask.tenant_no == tenant_no, BizQcTask.task_no.like(like), ).count() task_no = f"ZJRW{day}{cnt + 1:04d}" task = BizQcTask( id=generate_uuid(), work_order_id=work_order_id or "", task_no=task_no, task_type=task_type, source_line_id="", sample_code=sample_code, item_code=item_code, item_name=item_name, company_id=company_id, company_name=company_name, fee_amount=fee_amount, task_status="dzx", tenant_no=tenant_no, remark=remark, create_by=user_id, create_dept_id=create_dept_id, ) db.add(task) db.flush() return task ``` 注意:需要在文件顶部确认已 import `datetime`, `generate_uuid`, `BizQcTask`。 - [ ] 在 qc_task.py 末尾新增 `create_qc_task_manual` ### Step 3: API 路由新增 POST 端点 在 `backend/app/api/qc.py` 的 `@router.get("/qc-tasks")` 之前,新增: ```python @router.post("/qc-tasks") async def create_qc_task( body: QcTaskCreateBody, db: Session = Depends(get_db), user: dict = Depends(require_menu_code("biz:qcTask:list")), ): try: tenant_no = _get_tenant_no(db, user) task = task_svc.create_qc_task_manual( db, tenant_no=tenant_no, user_id=user.get("user_id"), create_dept_id=user.get("dept_id", ""), task_type=body.task_type, item_code=body.item_code, item_name=body.item_name, company_id=body.company_id, company_name=body.company_name, fee_amount=body.fee_amount, sample_code=body.sample_code or "", work_order_id=body.work_order_id or "", remark=body.remark or "", ) db.commit() return success_response(task_svc._task_to_dict(task), message="创建成功") except PermissionError as e: return error_response(403, str(e)) except Exception as e: db.rollback() return error_response(400, str(e)) ``` 同时在文件顶部 import: ```python from app.schemas.qc_task import QcTaskCreateBody ``` - [ ] 新增 POST 路由和 import ### Step 4: 验证 - [ ] 启动后端,访问 `/docs`,确认 `POST /api/web/admin/qc-tasks` 出现 --- ## Task 3: 生产工单 — 后端手动创建接口 **Files:** - Modify: `backend/app/schemas/production_work_order.py` - Modify: `backend/app/crud/production_work_order.py` - Modify: `backend/app/api/production.py` ### Step 1: 新增 CreateBody schema 在 `backend/app/schemas/production_work_order.py` 中追加: ```python class ProductionWorkOrderCreate(BaseModel): """手动创建生产工单""" model_config = ConfigDict(populate_by_name=True) protocol_no: Optional[str] = Field(None, alias="protocolNo", description="协议号") sample_code: Optional[str] = Field(None, alias="sampleCode", description="样本编码") reception_source: Optional[str] = Field("cell_storage", alias="receptionSource", description="来源类型") remark: Optional[str] = Field(None, description="备注") ``` - [ ] 追加 schema ### Step 2: CRUD 层新增手动创建方法 在 `backend/app/crud/production_work_order.py` 末尾新增: ```python def create_production_work_order_manual( db: Session, *, tenant_no: str, user_id: Optional[str] = None, create_dept_id: str = "", protocol_no: str = "", sample_code: str = "", reception_source: str = "cell_storage", remark: str = "", ) -> BizProductionWorkOrder: """手动创建生产工单(不关联接收记录)""" wo = BizProductionWorkOrder( id=generate_uuid(), work_order_no=_generate_work_order_no(db, tenant_no), reception_id="", protocol_sample_id="", collection_protocol_id="", protocol_no=protocol_no, sample_code=sample_code, reception_source=reception_source, work_order_status="dpz", tenant_no=tenant_no, remark=remark, create_by=user_id, create_dept_id=create_dept_id, ) db.add(wo) db.flush() return wo ``` - [ ] 新增 `create_production_work_order_manual` ### Step 3: API 路由新增 POST 端点 在 `backend/app/api/production.py` 的 `@router.get("/production-work-orders")` 之前,新增: ```python @router.post("/production-work-orders") async def create_production_work_order( body: ProductionWorkOrderCreate, user: dict = Depends(require_admin_or_super_admin), db: Session = Depends(get_db), ): try: tenant_no = _get_tenant_no(db, user) wo = production_work_order_svc.create_production_work_order_manual( db, tenant_no=tenant_no, user_id=user.get("user_id"), create_dept_id=user.get("dept_id", ""), protocol_no=body.protocol_no or "", sample_code=body.sample_code or "", reception_source=body.reception_source or "cell_storage", remark=body.remark or "", ) db.commit() return success_response(production_work_order_svc._wo_to_dict(wo), message="创建成功") except ValueError as e: return error_response(400, str(e)) except Exception as e: db.rollback() return error_response(400, str(e)) ``` 同时在文件顶部 import: ```python from app.schemas.production_work_order import ProductionWorkOrderCreate ``` 注意:检查 `production_work_order_svc` 是否已 import,以及是否需要 import `require_admin_or_super_admin`(应已有)。 - [ ] 新增 POST 路由和 import ### Step 4: 验证 - [ ] 启动后端,访问 `/docs`,确认 `POST /api/web/admin/production-work-orders` 出现 --- ## Task 4: 前端 API 层 — 新增创建函数 **Files:** - Modify: `web-admin/src/api/qc-work-order.ts` - Modify: `web-admin/src/api/qc-task.ts` - Modify: `web-admin/src/api/production-work-order.ts` **注意:** `production-task.ts` 已有 `fetchCreateProductionTask()`,无需修改。 ### Step 1: 质检工单 API 在 `web-admin/src/api/qc-work-order.ts` 末尾追加: ```typescript export function fetchCreateQcWorkOrder(data: { protocolNo?: string sampleCode?: string receptionSource?: string qcBizType?: string remark?: string }) { return request.post({ url: '/web/admin/qc-work-orders', params: data }) } ``` - [ ] 追加 `fetchCreateQcWorkOrder` ### Step 2: 质检任务 API 在 `web-admin/src/api/qc-task.ts` 末尾追加: ```typescript export function fetchCreateQcTask(data: { taskType: string itemCode: string itemName: string companyId?: string companyName?: string feeAmount?: number sampleCode?: string qcBizType?: string workOrderId?: string remark?: string }) { return request.post({ url: '/web/admin/qc-tasks', params: data }) } ``` - [ ] 追加 `fetchCreateQcTask` ### Step 3: 生产工单 API 在 `web-admin/src/api/production-work-order.ts` 末尾追加: ```typescript export function fetchCreateProductionWorkOrder(data: { protocolNo?: string sampleCode?: string receptionSource?: string remark?: string }) { return request.post({ url: '/web/admin/production-work-orders', params: data }) } ``` - [ ] 追加 `fetchCreateProductionWorkOrder` --- ## Task 5: 质检工单页面 — 新增弹窗 **Files:** - Modify: `web-admin/src/views/quality-inspection/qc-work-order/index.vue` **参考模板页:** `src/views/system/unit/index.vue` 的 handleAdd / dialog 模式 ### Step 1: 在 `