9.4 KiB
9.4 KiB
运输计划 · 承运商资质附件 — 设计文档
日期: 2026-06-29
状态: 已批准
前置:openspec/changes/transport-plan-management/specs/vehicle-driver/spec.md、docs/superpowers/specs/2026-06-19-pl-vehicle-personnel-cert-design.md
页面:web-admin/#/pl/carrier(承运商管理)
目标
在承运商档案中增加三类必填资质/协议附件,并基于运输协议有效期控制承运商车辆是否可用于运输安排:
- 营业执照(附件,必填)
- 道路经营许可证(附件,必填)
- 运输协议(附件,必填 + 协议有效期必填)
协议过期时:承运商展示「协议已过期」;该承运商名下车辆不可被选择用于安排/调整运输。
已确认业务规则
| 规则 | 决策 |
|---|---|
| 协议过期展示 | 承运商详情/列表展示 el-tag「协议已过期」 |
| 协议过期选车 | 该承运商名下车辆不出现在安排/计划选车列表;后端 arrange 接口硬校验 |
| 合作状态 | 不自动改为「已终止」 |
| 历史数据(无附件的旧承运商) | B:旧数据可保留不完整;补全且协议有效前不可安排运输 |
| 调整运输(协议已过期) | B:承运商协议过期时禁止任何调整运输(须先更新协议) |
| 附件数量 | 每类最多 5 个(对齐 CRM 客户证件) |
| 文件类型 | JPG / PNG / PDF,单文件 ≤ 20MB |
说明:用户对「历史数据」与「调整运输」均回复 B;若仅指其中一项,评审时更正即可。
非目标(本期不做)
- 营业执照、道路经营许可证的到期日与到期提醒
- 协议过期自动写入
pl_document_reminder/ 提醒中心 - 协议过期自动变更承运商合作状态
- 复用
pl_cert动态证书子表(固定三字段更简单,见方案选型)
方案选型
采用方案 A:承运商表固定字段(非 pl_cert 扩展)
| 字段 | DB 列名 | 类型 | 新建必填 | 说明 |
|---|---|---|---|---|
| 营业执照 | business_license_urls |
varchar(2000) | ✅ | MinIO URL,逗号分隔 |
| 道路经营许可证 | road_transport_license_urls |
varchar(2000) | ✅ | 同上 |
| 运输协议 | transport_agreement_urls |
varchar(2000) | ✅ | 同上 |
| 协议有效期 | transport_agreement_expire_date |
date | ✅ | 仅运输协议 |
计算字段(API 返回,不落库)
| 字段 | 逻辑 |
|---|---|
qualificationComplete |
三类 URL 均非空且 transport_agreement_expire_date 非空 |
transportAgreementExpired |
qualificationComplete 且 expire_date < today |
数据模型变更
pl_carrier 新增列(位于 status 与 tenant_no 之间)
ALTER TABLE `pl_carrier`
ADD COLUMN `business_license_urls` varchar(2000) DEFAULT NULL COMMENT '营业执照附件URL,逗号分隔' AFTER `status`,
ADD COLUMN `road_transport_license_urls` varchar(2000) DEFAULT NULL COMMENT '道路经营许可证附件URL,逗号分隔' AFTER `business_license_urls`,
ADD COLUMN `transport_agreement_urls` varchar(2000) DEFAULT NULL COMMENT '运输协议附件URL,逗号分隔' AFTER `road_transport_license_urls`,
ADD COLUMN `transport_agreement_expire_date` date DEFAULT NULL COMMENT '运输协议有效期' AFTER `transport_agreement_urls`;
同步更新:docs/sql/pl_tables.sql、docs/sql/shanxia2.0.sql。
后端设计
Schema(backend/app/schemas/pl/base_data.py)
CarrierCreate:四字段均必填(validator)CarrierUpdate:四字段 optional;若传入则按新建同等校验(非空、日期合法)CarrierRead:含四字段 +qualificationComplete+transportAgreementExpired(computed)
校验规则
新建承运商
- 三类
*_urls去空白后非空 transport_agreement_expire_date必填、合法 date
更新承运商(历史数据 B)
- 允许仅更新名称/联系人等,不强制一次性补全附件
- 一旦传入任一附件/有效期字段,则按完整规则校验
运输资格(安排/选车用)
承运商同时满足方可参与运输:
qualificationComplete == true
AND transportAgreementExpired == false
AND status == '1'(合作中)
API 变更
| 接口 | 变更 |
|---|---|
GET/POST/PUT /transport/carrier |
读写新字段;Read 带计算字段 |
GET /transport/vehicle |
新增 query:excludeIneligibleCarrier(默认 false)为 true 时排除: vehicle_type=carrier 且所属承运商不满足运输资格 |
POST /transport/order/arrange/{plan_id} |
选车后校验承运商运输资格;不通过 → 400 |
arrange 错误文案(建议)
- 资质不全:
该承运商资质附件不完整,无法安排运输 - 协议过期:
该承运商运输协议已过期,无法安排运输 - 调整运输且当前计划车辆所属承运商协议过期:
该承运商运输协议已过期,请先更新协议后再调整运输(HTTP 400,禁止提交)
辅助函数
建议 app/services/pl_carrier_service.py:
carrier_qualification_complete(carrier) -> boolcarrier_agreement_expired(carrier, today: date) -> boolcarrier_eligible_for_transport(carrier, today: date) -> boolassert_carrier_eligible_for_transport(db, carrier_id, tenant_no)— arrange 与 vehicle 过滤共用
前端设计
1. 承运商列表 / 编辑(views/pl/carrier/index.vue)
- 弹窗宽度:
520px→720px - 新增分区 「资质附件」(参考 CRM
CustomerFormDialog证件区) - 组件:
AttachmentUploadField× 3accept="image/*,.pdf"folder="pl/carrier/license"/permit/agreementlimit=5
- 运输协议下方:
el-date-picker type="date",value-format="YYYY-MM-DD" - 新建:四字段
formRules必填;提交前hasUploading()检查 - 编辑:同字段展示;历史不完整时可保存基础信息,但卡片/查看态标注「资质不全」
卡片列表增强(建议)
qualificationComplete === false→el-tag type="warning"「资质不全」transportAgreementExpired === true→el-tag type="danger"「协议已过期」
2. 查看弹窗(pl-carrier-view-dialog)
- 资质附件:可预览/下载(复用
AttachmentUploadFielddisabled 或查看态附件列表) - 协议有效期 + 过期 Tag
3. 安排运输(pl-plan-arrange-dialog)
vehicleApi.list({ vehicleStatus: 'available', excludeIneligibleCarrier: true })- 调整运输 B:打开弹窗时若当前计划已安排车辆,且其承运商
transportAgreementExpired或!qualificationComplete:- 表单项只读或禁用提交
- 顶部
el-alert type="warning":请先更新承运商资质/协议
- 提交 arrange 前无需额外前端拦截(后端兜底),但可 preempt 提示
4. 计划表单预选车辆(pl-plan-form-dialog)
- 与安排运输相同:
excludeIneligibleCarrier: true
5. API 类型(api/pl/index.ts)
扩展 Carrier 接口与 VehicleQuery。
OpenSpec 更新
更新 openspec/changes/transport-plan-management/specs/vehicle-driver/spec.md 中 承运商管理:
Scenario: 承运商资质附件维护
- WHEN 管理员新增承运商
- THEN 系统 SHALL 要求上传营业执照、道路经营许可证、运输协议,并填写运输协议有效期
- AND 附件 SHALL 使用
AttachmentUploadField卡片化布局,URL 逗号分隔存库
Scenario: 协议过期阻断运输
- WHEN 承运商运输协议有效期早于当前日期
- THEN 系统 SHALL 展示「协议已过期」
- AND 该承运商名下车辆 SHALL NOT 出现在安排运输与计划预选车辆列表
- AND 安排/调整运输接口 SHALL 拒绝使用该承运商车辆
- AND 协议过期时 SHALL 禁止调整运输,直至更新协议
Scenario: 历史承运商兼容
- WHEN 存在未补全资质附件的历史承运商
- THEN 系统 SHALL 允许保留基础档案
- AND 在其资质补全且协议有效前 SHALL NOT 允许安排运输
影响范围
| 层级 | 文件 |
|---|---|
| SQL | docs/sql/pl_tables.sql, docs/sql/shanxia2.0.sql, 迁移脚本 |
| Model | backend/app/models/pl_models.py |
| Schema | backend/app/schemas/pl/base_data.py |
| Service | backend/app/services/pl_carrier_service.py(新建) |
| API | backend/app/api/pl/base_data.py, backend/app/api/pl/transport.py |
| 前端 | views/pl/carrier/index.vue, pl-carrier-view-dialog, pl-plan-arrange-dialog, pl-plan-form-dialog, api/pl/index.ts |
| OpenSpec | vehicle-driver/spec.md |
验收标准
- 新建承运商:缺任一附件或协议有效期 → 前端/后端均拦截
- 历史承运商无附件:可编辑保存基础字段;其车辆不在安排运输选车列表
- 补全资质且协议未过期:车辆恢复可选
- 协议过期:承运商展示「协议已过期」;车辆不可选;arrange 返回 400
- 已安排计划 + 承运商后过期:打开「调整运输」不可提交,提示先更新协议
- 自有车辆(
vehicle_type=self)不受承运商规则影响 - 查看弹窗可预览/下载三类附件
工作量估算
约 2 人日(含 DDL、CRUD、表单/查看、选车过滤、arrange 校验、联调)。