2026-07-04-pl-hazard-cert-ready-design.md 11 KB

危化品证「证书齐备」人工确认 — 设计文档

日期: 2026-07-04
状态: 已实现(2026-07-04)
前置: 现有 pl_plan_product.purchase_cert_url / transport_cert_url 双证校验逻辑;/#/pl/plan-cert 危化品证上传页
界面模式: P06 复杂业务列表 + 弹窗表单(延续危化品证上传页)

背景与问题

现状

环节 行为
危化品识别 以 CRM 产品主数据 isToxic / isExplosive 为准
证书存储 计划产品行 pl_plan_product.purchase_cert_url(购买证)、transport_cert_url(合法使用证明)
上传页校验 上传弹窗保存时 强制 每个危化品产品两个 URL 均非空
安排运输校验 前端 buildMissingHazardCertMessage + 后端 transport.py / _validate_toxic_products 均要求 双证齐全

客户反馈

实际业务中,是否需要购买证、合法使用证明,以及是否两个都要,取决于多种现场条件(产品类型、单据类型、客户资质、运输方式等),规则复杂且频繁变化,难以在系统中穷举。

当前「双证强制」导致:

  • 只需上传一种证的业务场景无法保存、无法标记完成;
  • 操作员被迫上传占位文件或反复与开发沟通改规则;
  • 系统规则与客户实际合规判断脱节。

目标

  1. 危化品证上传页增加「证书齐备」人工确认能力;
  2. 运输计划安排运输改为校验「证书齐备状态」,不再校验两个 URL 是否同时存在;
  3. 证书文件仍可在上传页按需上传(0~2 个均可),供存档与查看。

方案对比

方案 A:计划级「证书齐备」标志(推荐)

在 pl_plan 增加 hazard_cert_ready(0/1)及可选审计字段(hazard_cert_ready_by、hazard_cert_ready_time)。

优点 缺点
与「安排运输按整单校验」一致,改动面小 一单多危化品时无法逐行独立确认
列表可加一列 Tag,一眼可见 计划产品变更后需定义是否自动撤销齐备
后端一处字段即可 gate 安排运输 依赖人工责任心,需审计字段

方案 B:产品级「证书齐备」标志

在 pl_plan_product 每行增加 cert_ready。

优点 缺点
多产品粒度更细 安排运输需「所有危化品行齐备」聚合逻辑
与现有证书 URL 同表,语义近 UI 更复杂(每行按钮或弹窗内逐行确认)

方案 C:配置化规则引擎(按产品/单据类型判定要几个证)

优点 缺点
理论上可自动化 客户已明确规则复杂、难维护,与诉求相反
开发成本高、持续运维

推荐:方案 A(计划级标志),配合审计字段与产品变更自动撤销。若后续确需逐产品确认,可演进为方案 B,API 可预留。


已确认设计(其余待拍板项见 §七)

# 决策 说明
D1 齐备粒度:计划级 pl_plan.hazard_cert_ready,仅对「含至少一个危化品产品」的计划有意义
D2 无危化品计划免校验 计划不含易制毒/易制爆产品时,安排运输不检查齐备标志
D3 上传不再强制双证 上传弹窗保存时允许购买证/合法使用证明 0~2 个任意组合;至少保留「有危化品产品行」才允许保存附件
D4 安排运输只查齐备标志 替换现有 purchase_cert_url && transport_cert_url 校验(前后端一致)
D5 齐备为人工显式操作 【危化品证上传】列表工具栏 + 查看弹窗 hero 提供「证书齐备」;需二次确认
D6 可撤销齐备 提供「取消齐备」;已归档/已作废计划不可操作
D7 产品变更自动撤销 计划编辑导致危化品产品集合变化(增删改 productId 或危化品行)时,自动 hazard_cert_ready=0
D8 上传证书不自动齐备 保存附件 ≠ 证书齐备;须单独点击「证书齐备」
D9 运输计划页无上传入口 维持已移除「上传证书」;仅提示「请至危化品证上传页确认证书齐备」
D10 零附件可确认齐备 ✅ 2026-07-04 不要求任何附件即可点击「证书齐备」;人工确认即视为通过(证在客户处、纯备案等场景)
D11 齐备后可继续补传附件 ✅ 2026-07-04 hazard_cert_ready=1 不阻断 后续在危化品证上传页打开上传弹窗、补充/更新购买证或合法使用证明;齐备状态保持,除非 D7 触发撤销

一、数据模型

1.1 pl_plan 新增字段

字段 类型 说明
hazard_cert_ready tinyint, default 0 危化品证书是否已人工确认齐备:0-否 1-是
hazard_cert_ready_by varchar(64), nullable 确认人 user id
hazard_cert_ready_time datetime, nullable 确认时间

DDL 写入 docs/sql/shanxia2.0.sql(及迁移片段如项目惯例)。

1.2 既有字段保留

  • pl_plan_product.purchase_cert_url / transport_cert_url 保留,继续用于存档与列表「有/无」展示;
  • 不再作为安排运输的硬性条件。

二、后端 API

2.1 标记 / 取消齐备

PATCH /api/transport/plan/{id}/hazard-cert-ready
Body: { "ready": true | false }

规则:

  • 计划存在且未归档、未作废;
  • ready=true:计划须含至少一个危化品产品(CRM 标识),否则 400;不校验 是否已上传任何附件(D10);
  • ready=false:清空 hazard_cert_ready_by/time;
  • 写 update_by;可选写操作日志。

权限:pl:plan-cert:edit 或与上传证书同权限 pl:plan-cert:list + 编辑(与菜单权限对齐,实现时查现有 plan-cert 权限码)。

2.2 安排运输校验(替换)

_validate_toxic_products 与 transport.py 内联校验改为:

# 伪代码
if plan_has_hazard_products(plan):
    if not plan.hazard_cert_ready:
        raise HTTPException(400, "该计划危化品证书尚未确认齐备,请至危化品证上传页操作")

删除对 purchase_cert_url / transport_cert_url 的非空检查。

2.3 计划更新时撤销齐备

在 update_plan(或产品明细 diff 逻辑)中:若危化品产品集合或危化品行 id 集合变化 → hazard_cert_ready=0,清空 by/time。

2.4 列表 / 详情返回

_row_to_dict / Plan schema 增加:

  • hazardCertReady (bool/int)
  • hazardCertReadyBy / hazardCertReadyTime(详情与危化品证上传列表展示)

三、前端

3.1 危化品证上传页 plan-cert/index.vue

列表

  • 新增列「证书齐备」:el-tag,success=已齐备 / warning=待确认 / info=无需(无危化品);
  • 工具栏(选中单行且含危化品、未归档、未作废):
    • 未齐备 → 主按钮「证书齐备」(CircleCheck 图标),确认框后调 API;
    • 已齐备 → 描边「取消齐备」(CircleClose),确认框后调 API。

上传弹窗 PlPlanCertUploadDialog

  • 去掉保存时对双证非空的 ElMessage.warning 拦截;
  • 已齐备计划仍可打开上传弹窗并保存附件(D11);不因 hazardCertReady=1 禁用「上传证书」;
  • 提示文案改为:「请按实际业务上传所需证书;可先点击『证书齐备』放行运输,之后再补充附件。」

查看弹窗 hero-actions

  • 与工具栏同样的齐备 / 取消齐备按钮。

3.2 运输计划 plan/index.vue + PlPlanArrangeDialog

  • 提交前:若计划含危化品且 !hazardCertReady,ElMessageBox.alert:
    「该计划危化品证书尚未确认齐备,请至【危化品证上传】页面操作。」
  • 移除 buildMissingHazardCertMessage 对 URL 的检查(可保留 composable 供列表展示「有/无」,或重命名用途)。

3.3 列表证书展示

  • PlPlanListCertCell / PlPlanListProductCell 继续展示各证「有/无」,不作为运输门槛;
  • 可选:计划级齐备 Tag 与产品级有/无并存,便于操作员自查。

四、状态流转

[计划含危化品]
        │
        ├──(可选) 零附件──► 点击「证书齐备」+ 确认 ──► hazard_cert_ready=1 ──► 可安排运输
        │
        └──(可选) 先传部分附件 ──► 同上
                    │
                    └── 已齐备后仍可「上传证书」补传/更新附件(齐备状态不变,D11)
                    │
        编辑计划(危化品行变化) ──► 自动撤销齐备 (hazard_cert_ready=0)
        点击「取消齐备」 ──► hazard_cert_ready=0

无危化品计划:hazard_cert_ready 保持 0,安排运输跳过校验。


五、影响范围(实现清单)

层 文件/模块
SQL docs/sql/shanxia2.0.sql
Model backend/app/models/pl_models.py
Schema backend/app/schemas/pl/plan.py
Service pl_plan_service.py:_validate_toxic_products、update_plan 撤销逻辑、新增 set_hazard_cert_ready
API plan.py:PATCH hazard-cert-ready;transport.py:校验替换
FE API web-admin/src/api/pl/index.ts
FE 页 plan-cert/index.vue
FE 组件 pl-plan-cert-upload-dialog、pl-plan-arrange-dialog
FE 类型 Plan interface、usePlToxicProductCertCheck.ts(调整或拆分)

非目标:不改 CRM 产品危化品标识;不改司机/车辆危化品证(hazmat_cert_no)逻辑。


六、风险与缓解

风险 缓解
人工误点齐备导致无证运输 二次确认文案强调合规责任;记录确认人/时间;列表保留附件有/无
计划变更后仍显示已齐备 D7 自动撤销
历史已双证齐全的计划 迁移:含危化品且双证 historically 齐全 可批量 hazard_cert_ready=1(可选脚本,非必须)
后端被绕过 安排运输 API 服务端强制校验齐备标志

七、待产品确认(实现前需答复)

# 问题 状态
1 齐备粒度:计划级还是产品级? 默认 计划级(D1),若无异议按此实现
2 零附件是否允许齐备 ✅ 已确认:允许(D10);人工点确认即通过
3 齐备后是否可补传附件 ✅ 已确认:可以(D11);齐备不锁死上传入口
4 权限:「证书齐备」是否与「上传证书」同一角色即可? 待确认(默认:是,沿用 pl:plan-cert:list 菜单权限)
5 历史数据:是否对已有双证齐全的计划批量标记已齐备? 待确认(默认:否,由操作员按需点确认)

八、验收标准

  • 危化品证上传页可对含危化品的计划执行「证书齐备 / 取消齐备」,列表 Tag 正确
  • 上传弹窗可只传 0/1/2 个证并保存成功
  • 零附件也可点击「证书齐备」并成功;安排运输可通过
  • 已齐备后仍可打开上传弹窗补充/更新附件,齐备状态不被上传动作清除
  • 未齐备时,运输计划「安排运输」前后端均拦截,提示去危化品证上传页
  • 已齐备且无其他阻塞时可正常安排运输
  • 编辑计划变更危化品产品后,齐备状态自动清除
  • 无危化品计划安排运输不受本功能影响