2026-05-26-outbound-qc-work-order-design.md 12 KB

出库质检工单功能设计

日期:2026-05-26 状态:待实现 方案:A — 在现有质检工单页面内新增出库 Tab

1. 需求概述

在现有质检工单页面 (quality-inspection/qc-work-order) 中新增"出库质检工单"Tab,展示由中试服务申请单/输注计划触发的出库质检工单。支持查看(含完整申请单+输注计划信息)、编辑备注、配置检测。不支持新建和删除。输注计划取消/删除时,关联的出库质检工单自动作废。

1.1 关键约束

  • 出库质检工单仅由外部触发创建(输注计划页面),出库 Tab 不提供新建入口
  • 编辑仅限备注字段
  • 不支持删除操作
  • 配置检测功能与现有入库/临时质检完全一致
  • 输注计划取消时后端自动作废关联质检工单
  • 工单类型 biz_type:pilot_service=中试服务、clinical_application=临床应用

1.2 已有基础设施

组件 状态 说明
biz_qc_work_order.work_order_type='outbound' 已有 数据库字段已支持
biz_qc_work_order.qc_biz_type='outbound' 已有 数据库字段已支持
biz_qc_work_order.infusion_schedule_id 已有 关联输注计划
create_outbound_qc_work_order() 已有 后端创建逻辑已实现
POST /web/admin/pilot-infusion-schedule/create-qc-work-order 已有 API 端点已存在

1.3 需新增的数据库字段

重要发现:biz_qc_work_order 表当前没有 biz_type 字段来区分"中试服务/临床应用"。biz_production_work_order 已有此字段(通过 2026-05-26-outbound-work-order.sql 新增),但质检工单表没有。

需新增 SQL:

ALTER TABLE biz_qc_work_order
  ADD COLUMN biz_type VARCHAR(20) NULL COMMENT '业务类型: pilot_service=中试服务, clinical_application=临床应用' AFTER infusion_schedule_id;

同时更新 create_outbound_qc_work_order() 函数,创建出库质检工单时写入 biz_type='pilot_service'(来自中试服务申请单触发的场景)。

2. 前端设计

2.1 Tab 结构

在 web-admin/src/views/quality-inspection/qc-work-order/index.vue 的 el-tabs 中新增第 4 个 Tab:

┌──────────┬──────────┬──────────┬──────────┐
│ 入库质检  │ 临时质检  │ 出库质检  │ 全部工单  │
│ inbound   │ temporary│ outbound │ all      │
└──────────┴──────────┴──────────┴──────────┘
  • activeTypeTab 类型扩展为 'inbound' | 'temporary' | 'outbound' | 'all'
  • Tab 切换时重置分页并重新加载数据
  • API 调用复用 fetchQcWorkOrderList,传入 workOrderType='outbound'

2.2 列表筛选条件

筛选项 类型 说明
工单状态 el-select 待配置(dpz) / 已配置(ypz) / 已完成(ywc) / 已作废(yzf)
业务类型 el-select 中试服务(pilot_service) / 临床应用(clinical_application)
创建时间 el-date-picker 日期范围选择
关键词 el-input 搜索工单号、申请单号、申请单名称

2.3 表格列

列名 字段 宽度 说明
序号 — — 分页计算
工单号 workOrderNo min-width:160 CKZJ 前缀
业务类型 bizType min-width:100 el-tag: pilot_service=primary, clinical_application=warning
申请单号 applicationNo min-width:160 从关联申请单带入
申请单名称 applicationName min-width:200 从关联申请单带入
渠道名称 channelName min-width:140 从关联申请单带入
输注时间 infusionTime min-width:160 从输注计划带入
检测方式 计算字段 min-width:140 格式化 "实验室 \ 第三方"
备注 remark min-width:160 —
状态 workOrderStatus min-width:100 el-tag: dpz=info, ypz=warning, ywc=success, yzf=danger
创建时间 createTime min-width:160 —
操作 — min-width:260, fixed="right" 查看/编辑/配置检测

操作列按钮可见性:

按钮 显示条件
查看 所有状态
编辑(备注) 非已完成、非已作废
配置检测 待配置、已配置
删除 不显示
新增 不显示

2.4 查看对话框 — OutboundQcViewDialog.vue

新建组件:web-admin/src/views/quality-inspection/qc-work-order/OutboundQcViewDialog.vue

使用 SystemViewDialog 组件,宽度 1200px,4列网格,compact 模式。

Section 结构

Section 1: 工单基本信息

字段 来源
工单号 workOrderNo
工单类型 workOrderType → el-tag
业务类型 bizType → el-tag
工单状态 workOrderStatus → el-tag
检测方式 计算字段(实验室/第三方)
配置时间 configuredTime
配置人 configuredBy
备注 remark

Section 2: 中试服务申请单信息

字段 来源
申请单号 application.applicationNo
申请单名称 application.applicationName
申请单状态 application.applicationStatus → el-tag
渠道名称 application.channelName

Section 3: 患者信息

字段 来源
患者姓名 patient.patientName
性别 patient.sex
年龄 patient.age
联系电话 patient.phoneNo
证件号码 patient.idCardNo
紧急联系人 patient.emergencyContact
紧急联系电话 patient.emergencyPhone
临床诊断 patient.clinicalDiagnosis(跨列)
诊断附件 patient.diagnosisAttachments(跨列,附件预览组件)

Section 4: 输注方案信息

字段 来源
细胞类型 infusionPlan.cellType
规格 infusionPlan.specText
总疗程数 infusionPlan.totalCourseCount
疗程间隔 infusionPlan.courseInterval
输注途径 infusionPlan.infusionRoute
输注开始日期 infusionPlan.infusionStartDate

Section 5: 本次输注计划信息

字段 来源
输注时间 infusionSchedule.infusionTime
输注地点 infusionSchedule.infusionLocation
输注方式 infusionSchedule.infusionMethod
生产状态 infusionSchedule.scheduleStatus → el-tag
输注状态 infusionSchedule.infusionStatus → el-tag
质检状态 infusionSchedule.qcStatus → el-tag
取消原因 infusionSchedule.cancelReason(仅已取消时显示)

Section 6: 产品明细(表格)

列 字段
项目编码 projectCode
项目名称 projectName
细胞类型 cellTypeName
规格 specText
协议单价 agreementPrice
实际单价 actualPrice
份数 quantity
产品状态 productStatus → el-tag

Section 7+: 检测结果(动态,每个任务一个 Section)

复用现有的任务结果展示逻辑(实验室参数表 + 第三方附件),与入库质检查看对话框的检测结果 Section 一致。

数据加载

  1. 调用新聚合 API GET /web/admin/qc-work-orders/{id}/outbound-detail
  2. 一次性获取工单 + 申请单 + 患者 + 方案 + 计划 + 产品 + 任务结果的全部数据
  3. 无需前端多次请求

状态标签映射

所有状态/类型字段使用 el-tag 渲染,复用 status-tag-registry.ts 中的映射函数:

  • workOrderStatus: dpz=info, ypz=warning, ywc=success, yzf=danger
  • applicationStatus: dks=info, jxz=warning, ywc=success, yzf=danger
  • scheduleStatus: dsc=info, ysc=primary, yjf=success, yqx=danger
  • infusionStatus: dtz=info, yrqr=warning, yqx=danger, ywc=success
  • qcStatus: dzc=info, yzj=success, yqx=danger
  • productStatus: dtz=info, yrqr=warning, yqx=danger, ywc=success

3. 后端设计

3.1 列表 API 扩展返回字段

修改文件:backend/app/crud/qc_work_order.py

当 work_order_type='outbound' 时,在列表 SQL 中 LEFT JOIN 以下链路:

biz_qc_work_order
  → biz_pilot_infusion_schedule (ON infusion_schedule_id)
    → biz_pilot_infusion_plan (ON infusion_plan_id)
      → biz_pilot_application (ON pilot_application_id)

在 _row_to_dict() 中为 outbound 类型额外返回:

字段 SQL 来源
bizType biz_qc_work_order.biz_type(新增字段,pilot_service/clinical_application)
applicationNo biz_pilot_application.application_no
applicationName biz_pilot_application.application_name
channelName biz_pilot_application.channel_name
infusionTime biz_pilot_infusion_schedule.infusion_time

新增列表查询参数:bizType(可选),用于前端按业务类型筛选。

3.2 新增出库质检查看聚合 API

新增端点:GET /web/admin/qc-work-orders/{id}/outbound-detail

修改文件:

  • backend/app/api/qc.py — 新增路由
  • backend/app/crud/qc_work_order.py — 新增 get_outbound_qc_detail() 函数

返回数据结构:

{
  "workOrder": {
    "id", "workOrderNo", "workOrderType", "workOrderStatus",
    "bizType", "hasLab", "hasThirdParty", "remark",
    "configuredTime", "configuredBy", "createTime"
  },
  "application": {
    "applicationNo", "applicationName", "applicationStatus", "channelName"
  },
  "patient": {
    "patientName", "sex", "age", "phoneNo", "idCardNo",
    "emergencyContact", "emergencyPhone",
    "clinicalDiagnosis", "diagnosisAttachments"
  },
  "infusionPlan": {
    "cellType", "specText", "totalCourseCount",
    "courseInterval", "infusionRoute", "infusionStartDate"
  },
  "infusionSchedule": {
    "infusionTime", "infusionLocation", "infusionMethod",
    "scheduleStatus", "infusionStatus", "qcStatus", "cancelReason"
  },
  "products": [
    {
      "projectCode", "projectName", "cellTypeName", "specText",
      "agreementPrice", "actualPrice", "quantity", "productStatus"
    }
  ],
  "tasks": [
    {
      "taskNo", "taskType", "taskStatus", "conclusion",
      "results": [...],
      "thirdPartyAttachments": "...",
      "materialUsages": [...]
    }
  ]
}

实现:通过工单的 infusion_schedule_id JOIN 链路一次性获取,tasks 复用现有的任务查询逻辑。

3.3 输注计划取消时自动作废质检工单

修改文件:backend/app/crud/pilot_infusion_schedule_mgmt.py

在输注计划取消/删除的状态更新逻辑中,新增:

# 当输注计划状态变更为取消时
if new_status in ('yqx',):
    # 查找关联的未完成出库质检工单
    pending_orders = session.query(BizQcWorkOrder).filter(
        BizQcWorkOrder.infusion_schedule_id == schedule_id,
        BizQcWorkOrder.work_order_status.notin_(['ywc', 'yzf']),
        BizQcWorkOrder.del_flag == '0'
    ).all()
    for order in pending_orders:
        order.work_order_status = 'yzf'

3.4 不需要改动的部分

功能 原因
配置检测 完全复用 configure_work_order()
质检任务执行 复用现有任务开始/完成/填写结果流程
工单创建 复用 create_outbound_qc_work_order()
编辑备注 复用现有 PUT 端点

4. 涉及文件清单

新增文件

文件 说明
web-admin/src/views/quality-inspection/qc-work-order/OutboundQcViewDialog.vue 出库质检查看对话框组件
docs/sql/2026-05-26-qc-work-order-add-biz-type.sql 质检工单表新增 biz_type 字段

修改文件

文件 改动
web-admin/src/views/quality-inspection/qc-work-order/index.vue 新增 outbound Tab、列表列、筛选条件、操作按钮
web-admin/src/api/qc-work-order.ts 新增 fetchOutboundQcDetail API 函数
web-admin/src/utils/status-tag-registry.ts 确保 outbound 相关状态标签映射完整
backend/app/api/qc.py 新增 GET /qc-work-orders/{id}/outbound-detail 路由
backend/app/crud/qc_work_order.py 扩展 _row_to_dict() outbound 字段 + 新增聚合查询函数 + 列表查询支持 bizType 筛选
backend/app/crud/pilot_infusion_schedule_mgmt.py 输注计划取消时自动作废关联质检工单
backend/app/schemas/qc_work_order.py 新增出库详情返回 Schema