11 KiB
危化品证「证书齐备」人工确认 — 设计文档
日期: 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 均要求 双证齐全 |
客户反馈
实际业务中,是否需要购买证、合法使用证明,以及是否两个都要,取决于多种现场条件(产品类型、单据类型、客户资质、运输方式等),规则复杂且频繁变化,难以在系统中穷举。
当前「双证强制」导致:
- 只需上传一种证的业务场景无法保存、无法标记完成;
- 操作员被迫上传占位文件或反复与开发沟通改规则;
- 系统规则与客户实际合规判断脱节。
目标
- 危化品证上传页增加「证书齐备」人工确认能力;
- 运输计划安排运输改为校验「证书齐备状态」,不再校验两个 URL 是否同时存在;
- 证书文件仍可在上传页按需上传(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 个证并保存成功
- 零附件也可点击「证书齐备」并成功;安排运输可通过
- 已齐备后仍可打开上传弹窗补充/更新附件,齐备状态不被上传动作清除
- 未齐备时,运输计划「安排运输」前后端均拦截,提示去危化品证上传页
- 已齐备且无其他阻塞时可正常安排运输
- 编辑计划变更危化品产品后,齐备状态自动清除
- 无危化品计划安排运输不受本功能影响