weicw-dshsa
|
4fe0c8a968
|
✨ 调度首页把司机已拒单的运单列为重新派单待处理,并在司机端让该运单脱离
|
2026-10-10 01:48:49 +08:00 |
|
weicw-dshsa
|
b66984d3a1
|
✨ 认证审核详情下发审核人与审核时间
|
2026-10-09 20:47:22 +08:00 |
|
weicw-dshsa
|
143c6f99fb
|
🐛 修复司机端档案按脱敏手机号匹配导致本人档案查不到
|
2026-10-09 20:13:38 +08:00 |
|
weicw-dshsa
|
9f9ce7842e
|
♻️ 司机端可完成状态白名单收敛为单一常量并订正注释
|
2026-10-08 10:07:00 +08:00 |
|
weicw-dshsa
|
7c488b6f09
|
✨ 司机打完末位到货卸货签收节点且回单无需确认时自动完成运单
|
2026-10-08 09:24:30 +08:00 |
|
weicw-dshsa
|
9f8ea5412d
|
✨ 运单过程判定补充到货卸货签收、末位打卡与回单无需确认完成三项
|
2026-10-08 09:09:17 +08:00 |
|
weicw-dshsa
|
f3ae784f20
|
🐛 导入运单地点名称为空时司机端回退显示详细地址
|
2026-10-08 00:15:35 +08:00 |
|
weicw-dshsa
|
44197a4cff
|
🐛 审核通过与重新提交时清空档案上的旧驳回原因
司机/车辆档案上的 certification_reject_reason 是展示缓存,没有驳回原因时应为 NULL(建表即 DEFAULT NULL,数据订正脚本也写 NULL)。但框架的 not_null 更新策略会跳过 patch 里的 null 字段,把 null 交给 updateById 到不了 SQL,于是两处都留下了陈旧文案:审核通过后状态已是「已通过」,档案上却还挂着上一次的驳回原因;被驳回后重新提交,旧原因会一直挂到审核通过,而提交侧本就写明「新提交不能继承上一次的驳回文案」。现在这两条路径各显式发一条只改该列的语句,带主键条件,不碰生效快照指针、不碰车辆绑定,驳回时仍照常写入原因。改用 ALWAYS 更新策略会让改手机号、绑定车辆这类无关操作也清掉该列,故不做。
|
2026-10-07 23:00:28 +08:00 |
|
weicw-dshsa
|
5496f487c7
|
🐛 车辆停用与未认证分开提示,不再把停用报成「认证没通过」
接单门槛对「车辆停用」和「车辆未认证」返回同一句「该车辆尚未通过认证审核,暂不可接单,请先提交认证」。生产上有一辆车已认证、只是被停用,司机照着提示做了两轮重新认证仍然接不了单——停用要找调度启用、认证才要提交资料,本是两件事。现在按运营状态优先逐车给出原因:停用报「该车辆已停用,请联系调度启用」,未认证才报认证。
|
2026-10-07 19:30:31 +08:00 |
|
weicw-dshsa
|
f3dc451802
|
🐛 个人认证通过后姓名与身份证号也写回司机档案
审核通过时只写回证件内容,姓名与身份证号被当作「身份标识」跳过:司机申报「黄大富」,档案里却还是建档时的「黄宇富」,司机端卡片显示档案名、「重新认证」表单回填快照名,同一个页面上两个名字。现在审核通过即认可整份申报内容,姓名与身份证号一并写回,档案与生效值一致。身份证号写回前先确认它没有落在另一名司机名下——该列没有唯一索引,直接写会静默产生两条同证件号的档案,管理端的证件号查重从此失效。
|
2026-10-07 19:15:29 +08:00 |
|
weicw-dshsa
|
ac6318d174
|
✨ 新增存量司机/车辆补生效快照的订正脚本
「能否接单」的判据是生效快照指针,该列随认证门槛一起新增时对存量对象一律为 NULL,门槛默认开启后存量司机与车辆全部被判未认证、接不了单。脚本给尚无快照的对象补一条已通过记录并把指针指过去,含备份、校验与回退;幂等,且能在已订正过的库上续跑(从段内最大号之后接着发号,不撞主键)。
|
2026-10-07 18:21:38 +08:00 |
|
weicw-dshsa
|
7d8f2df56f
|
🐛 审核未命中目标档案时整体回滚,不再静默置为已通过
审核通过时对司机/车辆档案的 updateById 命中 0 行只返回 false、不抛异常,而这个返回值原先被丢弃,于是「认证记录已通过、档案一个字没变」能静默成立:生效快照指针没写进去,对象下次接单仍被判未认证,审核页却显示已通过。现在命中 0 行即抛异常并回滚整次审核,宁可报错也不留下状态与档案互相矛盾的数据。
|
2026-10-07 18:21:29 +08:00 |
|
weicw-dshsa
|
2e5eae4d32
|
✨ 打卡照片按类型最多传 9 张,照片列加宽为 text
- 节点打卡提交新增 photoItems(带显式类型),photos 原样保留供旧版小程序按下标回推
- 打卡照片是每个打卡节点必有的类型,不由过程配置决定,与各凭证类型各自最多 9 张
- 新版提交要求每个类型至少 1 张;旧版仍只要求至少 1 张,避免打断未升级的小程序
- 管理端订正只校验每类上限,不校验必填
- photos 由 varchar(2000) 改 text:36 张约 4000 字符,旧列宽约 17 张即溢出
- 基线建表脚本补 COLLATE=utf8mb4_0900_ai_ci(与本机库实际排序规则一致)
|
2026-10-07 16:49:19 +08:00 |
|
weicw-dshsa
|
e9156ab56b
|
🔀 合并异常上报门禁实现
|
2026-10-07 13:40:37 +08:00 |
|
weicw-dshsa
|
1038063231
|
♻️ 上报门禁的节点编码比较忽略首尾空白,移除失去调用点的判据方法
|
2026-10-07 13:33:07 +08:00 |
|
weicw-dshsa
|
3d3ed0ca27
|
♻️ 收紧上报门禁查询、去掉平行列表接口并统一节点编码比较
|
2026-10-07 13:24:02 +08:00 |
|
weicw-dshsa
|
3e687c8519
|
🔀 合并异常上报门禁后端实现
|
2026-10-07 13:17:50 +08:00 |
|
weicw-dshsa
|
f9654fbe30
|
✨ 节点卡片下发整单异常标记与相关异常列表,列表支持按运单精确过滤
|
2026-10-07 12:25:31 +08:00 |
|
weicw-dshsa
|
75cd448e2d
|
✨ 异常上报校验上报人必须是该运单的承运司机
|
2026-10-07 12:18:49 +08:00 |
|
weicw-dshsa
|
7e84b670b6
|
✨ 节点异常上报增加打卡与重复上报校验
|
2026-10-07 12:16:22 +08:00 |
|
weicw-dshsa
|
bf37c47856
|
✨ 接单后自动将接单节点置为已打卡
管理端打卡时间轴上的「接单」节点此前恒显示未打卡:接单动作只写运单字段,不落打卡流水,
而时间轴的节点来源含接单/回单,没有流水即判为未打卡。
改为按运单的接单事实派生:司机确认接单即为已打卡,时间取接单时间;项目「无需确认接单」时,
运单越过接单阶段(进行中/已完成/已取消)即为已打卡,但没有完成时刻——运单上没有任何字段
记着那一刻,时间栏留空,不拿创建时间或更新时间编一个。
不写打卡流水的原因:接单环节有 5 个产生点(司机确认、免确认落库、复制运单、导入进行中、
配载单开始),其中两处是绕过 Java 逻辑的批量 SQL;接单事实另有 4 个清除点。写流水要在每处
挂点,漏一处就出现「待接单却已打卡」或「进行中却未打卡」;派生只需在 listPunchRecords 一处判定,
且历史运单立即正确,无需回填。打卡表 (waybill_id, node_code) 也没有唯一约束,幂等只能靠代码自保。
配套:
- 接单节点不再允许补录或取消打卡:它由接单动作决定,人工订正只会造出一条与运单事实打架的
流水(时间轴显示已打卡、运单却还没人接单),故后端拒绝、前端不展示编辑入口
- 接单节点判据提为 WaybillProcessSupport.isAcceptNode(nodeCode, nodeName) 公开方法,
时间轴与补录校验共用同一份,不再各写一处硬编码
- 补 8 个时间轴用例(真接单带时间/待接单/已拒单/免确认进行中无时间/免确认草稿/免确认待执行/
免确认已取消/普通节点不受影响)+ 1 个补录拒绝用例
|
2026-10-06 12:36:17 +08:00 |
|
weicw-dshsa
|
4e5b6ce8f3
|
✨ 全局入口上报异常不再要求指定节点
从小程序首页快捷格、打卡页底部按钮进入上报时不再要求选择节点,node_code / node_name 落空;
要指定环节只能从节点卡片进入(入口即已确定环节,节点名仍从过程配置回填、不信任请求体)。
未指明节点的异常无从定位阻断区间,按「阻断该运单全部未打卡节点」处理,含在途。
此前「异常必须归属节点」的校验与相应术语表述一并作废。
|
2026-10-06 12:36:07 +08:00 |
|
weicw-dshsa
|
c50a86d5c4
|
✨ 运单详情打卡记录支持管理端编辑(含打卡状态)
新增 POST /waybill-manage/punch-record/save:按运单当前过程配置补录或修正
节点打卡与在途打卡,打卡状态也在可编辑之列。
- punched=false 即取消打卡:清除该节点全部打卡流水(时间轴上「未打卡」的判据
就是没有流水);在途节点没有节点 key 可定位单条,故清空该运单全部在途流水
- 节点以当前过程配置为准回写 key/name,前端带旧值也不会写歪
- 编辑按字段显式更新:updateById 会跳过 null 字段,清空地址/货量/照片保存后不生效
- 编辑不改 exception_flag(与异常处置表绑定);管理端补录 driver_id 留空
- 凭证图按 [{type,url}] 回写,避免展示层按下标回推类型时换序串标
- 补 8 个服务单测 + 3 个 MockMvc 端点绑定测试
|
2026-10-06 04:40:43 +08:00 |
|
weicw-dshsa
|
19ddc445da
|
🐛 修复在途打卡绕过异常门禁:未了结异常落在在途之后时仍可打卡
在途的异常阻断此前按过程配置里节点的位置区间计算:异常节点及其后的节点不可打卡。
异常报在「卸货」这类排在在途之后的节点时,区间只有卸货、签收,在途被放行,
等于车越接近目的地越能报在途;而异常报在「装货」(在途之前)反而会锁住在途。
改为运单级判定:该运单只要存在未了结异常,在途就不可打卡,与异常归属哪个节点无关。
普通打卡节点仍按区间(异常所在节点及其后)阻断。判定集中在
WaybillProcessSupport.blockedNodeKeys,卡片禁用态与 /enroute/submit 的强制校验共用它。
异常落在非打卡节点上(接单/回单、或已从过程配置删掉的节点)时没有可跳转的具体异常,
故 blockedExceptionId 可能为空,卡片只显示不可打卡原因。
|
2026-10-06 03:17:25 +08:00 |
|
weicw-dshsa
|
ffed7d328c
|
✨ 打卡照片改为必填
节点打卡与在途打卡都必须上传照片,缺照片直接拒绝。前端已做必填校验,此处拦的是
绕过客户端直接调接口的情况;空白字符串不算已上传。
|
2026-10-06 00:29:28 +08:00 |
|
weicw-dshsa
|
7c30ead839
|
✨ 异常处置支持归属过程节点并新增打卡门禁
异常上报强制选择过程节点,节点归属写入 node_code / node_name;节点存在未了结
异常时,该节点及其后节点不可打卡(异常门禁),被拦节点仍可展开查看回填内容。
另新增顺序门禁:前置打卡节点未完成时后续节点不可打卡且不可展开;在途节点不受
顺序门禁约束,但仍受异常门禁约束。
配套:
- 过程配置「上传货量为是、货量类型为空」的脏配置订正为不采集货量
- 网关补充 /blade-resource/** 路由(图片上传,小程序打卡与异常上报照片均经此)
|
2026-10-05 15:10:24 +08:00 |
|
weicw-dshsa
|
7296a5af21
|
✨ 异常处置跟进支持上传附件
跟进记录新增 attachments_json 列,存 [{name, url}] 形式的 JSON 数组。
跟进说明与附件至少填其一即可:只传附件时,follow_content 列为 NOT NULL,
故写入固定文案「已上传跟进附件」,列表按该文案展示。
建表脚本补 COLLATE:原先只写 CHARSET,落到 MySQL 8 服务器默认排序规则,
与库中实际的 utf8mb4_0900_ai_ci 不一致。
|
2026-10-05 01:09:33 +08:00 |
|
weicw-dshsa
|
8d35abd23e
|
✨ 异常处置新增编辑功能
运管员可订正已上报的异常内容:异常类型、异常原因、上报说明、现场照片。
车牌、项目、承运商、配载单号由上报时从运单回填,不开放编辑,避免与运单脱钩。
编辑不改动处置状态。状态只能经跟进与完成流转,因为运单详情、运单列表、
首页计数与待办四处都以 disposal_status IN (pending, processing) 判定未完成,
允许编辑改状态会让已结案的异常重新长出来,而那四处判定无从知晓。
每次编辑按字段逐项比对生成变更说明,写入一条跟进记录留痕。
变更说明会内嵌修改前后的原文,长文本字段一次编辑就可能超过跟进内容的
varchar(500) 上限,故按 500 截断。
Permission 表达式用 hasMenu('exception_disposal_edit'):
@PreAuth 的值由 SpEL 求值,root object 是 AuthFun,
写成裸字符串会被当作属性访问而在请求时抛错。
|
2026-10-05 00:54:08 +08:00 |
|
weicw-dshsa
|
e3d860668b
|
📝 删除认证分支注释里的叙事性措辞
把「本改造的核心」「这正是要避免的事」「本次改造要保住的东西」这类
写作时的叙事从注释中去掉,只留读者需要的事实(反直觉的约束、坑、兼容性)。
测试的 @DisplayName 同步去掉「改造前/改造期间」等时间状语。
注释与文案调整,无逻辑改动;CertificationGateTest 等 35 个测试通过。
|
2026-10-04 23:55:22 +08:00 |
|
weicw-dshsa
|
5061df8c78
|
📝 删除认证迁移脚本里的解释性注释
SQL 本身(列名、列 COMMENT、IF 条件)已经把意图说清楚了,注释在复述它、
或是在讲当时的排查过程,对读者没有增量信息。只留一处真正反直觉的:
唯一索引不对 NULL 去重,故 tenant_id 必须 NOT NULL。
注释 31 -> 8 行,DDL 未动,重跑两遍验证。
|
2026-10-04 23:49:33 +08:00 |
|
weicw-dshsa
|
4a65951adc
|
📝 精简认证迁移脚本注释
上一版注释把决策理由、备选方案、实测数据都写进了脚本,篇幅盖过 SQL 本身
(cert_record 注释 58 行 / 非空 170 行),后续阅读反而更难抓到重点。
按同目录既有脚本的密度收敛:只留「从 SQL 本身看不出来」的事实
(字段业务含义、不可回退的指针语义、排序规则不能改的原因),
删掉论证过程与常识性说明。
cert_record 注释 58 -> 31 行,另两个 14 -> 6 行;
DDL 一个字未动,重跑一遍验证仍无报错。
|
2026-10-04 23:46:39 +08:00 |
|
weicw-dshsa
|
cdd8acb9a8
|
🔀 合并认证迁移脚本整理分支到 master
三个认证迁移脚本补幂等守卫、统一注释格式,DDL 效果不变(已在 dev 库连跑两遍验证)。
|
2026-10-04 23:43:10 +08:00 |
|
weicw-dshsa
|
378aa11842
|
♻️ 认证迁移脚本补幂等并统一注释格式
三个认证相关迁移脚本按项目既有约定整理,DDL 效果不变:
- driving_vehicle 扩长、owner_name/vin 加列两处原为裸 ALTER,重复执行会报
「Duplicate column」或白白重建表;改为 DELIMITER 存储过程 + information_schema
判定,与 doc/sql/transport 下 upgrade_* 的既有写法一致,可重复执行。
扩长那条额外判定 character_maximum_length < 100:MODIFY COLUMN 会重建整表,
已达标就不必再跑一次。
- cert_record 的菜单段补注 parent_id 的出处(与 blade_transport_driver.sql /
blade_transport_vehicle.sql / blade_vehicle_dispatch.sql 同一 ID),并说明
ON DUPLICATE KEY UPDATE 会把 parent_id / name 回写,对旧环境重跑即可收敛。
- 去掉注释里的 markdown 粗体(doc/sql/transport 的既有排版不用 markdown),
统一以 30 个破折号的横幅开头。
已在 dev 库 transport 连跑两遍验证:两遍均无报错,且列定义 116 行、索引 29 行、
三表排序规则与整理前逐项一致。
|
2026-10-04 23:43:05 +08:00 |
|
weicw-dshsa
|
ec98954351
|
🔀 合并认证记录功能分支到 master
认证记录不可变快照数据模型、司机端提交与记录查询、管理端审核、
小程序证件 OCR 适配、接单可用性门槛(带开关可回退),含迁移脚本与单元测试。
|
2026-10-04 23:38:39 +08:00 |
|
weicw-dshsa
|
7c4c887d74
|
🐛 修认证流程清空司机车辆绑定,导致车辆列表消失
Driver.drivingVehicle 标了 @TableField(updateStrategy = FieldStrategy.ALWAYS),
该策略忽略 null 直接写:任何一次 updateById 只要 patch 里没带这个字段,
就会把库里的 driving_vehicle 写成 NULL。而司机端的车辆列表正是按这一列
的车牌匹配出来的(DriverAppServiceImpl.myVehicles 开头就判空返回空列表),
清空即页面显示「暂无绑定车辆」,且司机在界面上无法自行恢复。
两条链路都会触发:
- 提交认证:updateDriverDisplayCache 只 patch id/状态/驳回原因;
- 审核通过:本次改动新增的快照写回,同样只 patch 证件字段。
已在两处 updateById 前把该车的原值搬进 patch,并补回归测试:
先确认去掉修复后测试确实失败(expected 桂A12345,桂B67890 but was null)。
保留 ALWAYS 策略不动——它保证了「能显式清空车辆绑定」这一能力,
问题在于 patch 式更新必须自己带上原值,而不是删掉策略。
|
2026-10-04 23:24:22 +08:00 |
|
weicw-dshsa
|
4fa6d4c430
|
🐛 个人认证通过后写回司机档案,并补齐资格证字段
个人认证通过时只切了生效指针与认证状态,证件内容一个字都没落到
blade_transport_driver:认证状态显示「已通过」,司机档案里却仍是
管理端当初录入的旧值(甚至为空),管理端与司机端各看各的。
车辆侧早有 applySnapshotToVehicle 做这件事,司机侧一直没有对应实现。
- 新增 applySnapshotToDriver,审核通过时与指针合并在同一次 UPDATE 写回。
只搬司机申报的证件内容,不碰身份标识(姓名/身份证号,由管理端建档确定)
与内部管理归属(司机类型/岗位/驾驶车辆/所属组织)。
- 快照缺失、解析失败或字段对不上时只跳过写回,不阻断审核:审核是独立于
写回的业务动作,不该因为一份读不懂的快照而失败,否则历史快照对应的
对象再也审不过去。
- PersonCertSubmitRequest 补 qualificationType / qualificationBack /
qualificationValidStart / qualificationLongTerm 四个字段。
- qualificationUrl 改名为 qualificationFront,与司机档案列
qualification_front 及管理端用词统一;改名前的记录存的仍是旧键,
写回时回退读一次旧键,避免已填的封面页在审核通过时被丢掉。
- 补测试:证件内容写回、不覆盖身份字段、驳回不写回、历史快照跳过写回
但仍照常通过审核。
qualificationValidStart 只进快照、不写档案:司机档案表没有对应的开始日期列,
管理端的「从业资格证有效期起」同样是只收不存。此处保持一致,不新增列。
|
2026-10-04 22:11:10 +08:00 |
|
weicw-dshsa
|
17ae367100
|
🐛 认证审核菜单名改为「司机审核 / 车辆审核」
原名「认证审核-司机 / 认证审核-车辆」与需求文档的表述不一致,
后台菜单显示为「司机审核」「车辆审核」——与 .scratch 里
审核页分页签那轮需求的措辞对齐。
只改 blade_menu 的 name 字段,code / alias / path / 权限码均不变,
故不影响权限校验与前端路由。
注意:该 INSERT 是 ON DUPLICATE KEY UPDATE,改脚本本身不会改库里已有的行,
要在已有环境生效需重跑本脚本(新环境按脚本建库则直接是新名)。
|
2026-10-04 19:16:38 +08:00 |
|
weicw-dshsa
|
ee135cd150
|
🐛 重新认证也要过内容校验,不再只校验新建车辆
起先 validateCertContent 只在 createVehicleForDriver 里调用,走 request.id 的重新认证路径
一句都不校验:待审内容虽然要等审核通过才写进车辆档案,但它已经是一条不可变记录,
并会在通过时按字段写回车辆行,于是「内容校验」对重新认证形同虚设。
- 内容校验提到 submitVehicleCert 里、resolveBoundVehicle 之前,两条路径共用;
- 「所属组织非空」拆成 requireOrganizationForNewVehicle,仍只在新车建档时要求:
该列只在 INSERT 时需要,它属于内部管理归属,拿它拦住重新认证只会让司机无从下手。
- 补 2 个用例:重新认证传空「所有人」必须被拒;司机档案没有所属组织时重新认证仍应放行。
- 顺带把 7 个此前只传车牌/ID 的用例改用字段齐全的请求:否则它们会因为「车牌颜色不能为空」
提前失败,看着还绿、其实已经不再验证原本要验证的越权与作废逻辑。
|
2026-10-03 17:56:56 +08:00 |
|
weicw-dshsa
|
11e62c172c
|
🐛 修车辆重新认证长期有效字段回显,有效期不再要求起期
- 卡片接口不再把「长期」当日期下发,也不在长期有效时下发上一版证件残留的止期:
两者都会被「重新认证」表单原样回填再原样提交,前者进日期框后按 LocalDate 反序列化直接报错,
后者会让一辆长期有效的车带着一个早已作废的止期一路写回车辆行。
- 车辆有效期校验收敛为「止期必填、起期可空」,和管理端车辆表单同一口径:
起期只在两端都有值时才比较先后。司机端表单本来也不采集起期。
- 补 6 个测试:3 个盯卡片回显(含长期有效 + 残留止期、无止期两种),
3 个盯有效期校验(起期可空、止期必填、长期有效时止期可空)。
|
2026-10-03 17:46:53 +08:00 |
|
weicw-dshsa
|
04a7846328
|
✨ 车辆认证扩到6张证件图,字段与车辆档案对齐;补齐建车必填列
司机端车辆认证此前只有 3 张图、5 个字段,且语义与车辆管理不一致
(「副页」字段里装的其实是主页反面)。本次把证件内容整体对齐车辆表列:
- 车辆表新增 owner_name(所有人:行驶证登记的单位名称,不是司机)与 vin;
- 提交请求与司机端车辆卡片全量对齐表列,行驶证四张图各自独立、
不再把「主页反面」与「副页正面」挤在同一个字段;
- 业务关系新增为司机自选(自有/管理挂靠/业务合作),不再由后端替用户猜。
顺带修掉三处会直接让功能不可用的缺陷:
1. 司机建车必失败:organization_name、approved_load_kg、business_relation、
energy_type、registration_no 五列 NOT NULL 且无默认值,而建车链路一个都不设置,
严格模式下 INSERT 直接报「doesn't have a default value」。已补齐并加服务端校验
(司机提交链路此前一句都不查,全靠前端)。
2. OCR 自动填充从未生效:后端按契约透传百度原始结果(中文键),
前端读的却是扁平字段名,永远 undefined 且不报错。新增 OcrFieldSupport
做归一化(键名别名容错、数值/日期/「长期」归一化、外廓尺寸拆三段、
有效期区间拆起止),响应的 fields 即前端直接回填的字段。
3. 审核通过不写回车辆档案:状态已通过、内容却还是旧的,自相矛盾。
现把生效快照的证件内容与指针合并成同一次 UPDATE 写回;快照是改造前
旧格式时明确报错,而不是静默写一堆空值。
|
2026-10-03 16:34:47 +08:00 |
|
weicw-dshsa
|
214ff38ef8
|
🐛 修复道路运输证OCR恒失败:上游不得替它补默认正反面
OcrTypeMapping.normalizeSide 对空值恒返回 front,控制器把这个 front 传给下游,
而道路运输证没有正副面参数(supportsSide 为 false),下游于是判
「传了 side 但该证件不支持」并直接抛错——小程序不传 side、传 front、
传空串三种方式实测全部失败,该证件 OCR 从来没能用过。
改为未指定时返回 null,把「默认取正面」交给知晓证件类型的一侧决定,
并补测试钉住这条契约。
|
2026-10-03 15:35:22 +08:00 |
|
weicw-dshsa
|
cc997c1c0c
|
✨ 审核列表新增司机姓名与手机号,并修正驾驶车辆绑定校验
审核页的司机姓名与手机号取司机档案的**当前值**,不是提交时的历史值:
手机号从未进入过认证快照(只有司机档案这一个来源),而队列的用途是
「找得到人、联系得上」。司机侧的认证对象就是记录本身;车辆侧记录不含任何
司机信息,取提交该记录的司机。存量订正记录里没有系统账号的那些司机解析不到,
两列为空属正常状态。
筛选必须发生在分页之前,故列表改为自定义 SQL;在 Java 层补字段再过滤会变成
「先分页再过滤」,每页条数与总数都不准。姓名搜索同时匹配档案当前姓名与提交时的
旧名,改名后按新名、旧名都搜得到。
顺带修掉两处既有缺陷:
1. 管理端保存绑定多辆车的司机会误报「驾驶车辆不存在」——小程序把车牌逗号并列
写入 driving_vehicle,管理端却拿整串去车牌表精确查,两边口径不一致。
2. 「一个司机最多 5 辆车」后端从未校验,且 driving_vehicle 原为 varchar(30),
5 个车牌连分隔符要 39 字符,超长写入会被静默截断成半个车牌(还会被当成一辆车)。
列扩到 varchar(100) 并在写入前校验数量与车牌格式。
|
2026-10-03 14:35:59 +08:00 |
|
weicw-dshsa
|
bd01122409
|
🐛 修复认证记录提交人记成司机档案ID
提交时把 driver.getId()(司机档案ID)当提交人写进了 submit_user,
而该字段要靠 UserCache.getUserRealName(userId) 翻译成姓名,
两处ID都是雪花ID、类型也相同,传错不报任何错,
只在审核页表现为「提交人」显示成一串数字。
改为 driver.getUserId(),并补回归测试锁住(用两个不同的ID常量,
传错必然断言失败)。
|
2026-10-02 19:58:11 +08:00 |
|
weicw-dshsa
|
2983ef78af
|
✨ 认证记录列表支持按审核状态查询
审核页要按「待审核 / 已通过 / 已驳回」分页签展示,而原接口把状态写死成
审核中(status=0),已通过/已驳回的记录根本查不出来。
新增可选的 status 参数;不传时仍按审核中处理,保持原有调用方行为不变。
|
2026-10-02 19:58:06 +08:00 |
|
weicw-dshsa
|
fbced4e6a0
|
✨ 支持司机新增未登记车辆(原实现会让小程序「+ 新增车辆」必然失败)
小程序的车辆录入页允许司机直接填车牌提交,且空列表时提示
「暂无绑定车辆,点击「+ 新增车辆」添加」。但原实现只按「已完成绑定」查找车辆,
未登记的车牌一律抛「车辆不存在或未绑定」——而司机名下还没有这辆车,也就永远无从绑定,
形成死结:该入口必然提交失败(属票 07 的验收点)。
改为按车牌区分三种情形:
- 未登记 → 就地建档(写入识别信息与证件内容)并把车牌追加到司机名下;
- 已登记且属于本人 → 复用,不重复建档(容忍车牌写法差异);
- 已登记但不在本人名下 → 拒绝,**不顺手改归属**(避免抢车)。
关键约束:新建车辆**不带生效快照指针**,故建档本身不会让一辆未审核通过的车变得可用
——是否已认证仍只由审核通过决定。
4 个新用例覆盖上述三种情形与空车牌拒绝。全模块 89 个测试通过。
|
2026-10-02 17:35:33 +08:00 |
|
weicw-dshsa
|
c66af4c162
|
✨ 补车辆认证删除接口(契约与小程序都已在调用,后端却缺失)
api-contract.md 承诺 DELETE /driver/auth/vehicle/{id},小程序
api/auth.ts 的 deleteVehicleAuth 也从 subpackages/auth/vehicle.vue 真实调用它,
但后端一直没实现——该操作此前必然 404。
实现要点:
- 对车辆做**逻辑删除**(deleteLogic,is_deleted=1),认证记录**一律保留**:
记录是不可变快照,也是「曾通过即永久可用」这一判定的依据,物理删除会让历史无从追溯;
- 越权校验复用同一套车牌绑定判定,写法差异(间隔符/大小写)不影响结果。
3 个用例:逻辑删除而非物理删除(显式断言从不调用 removeById/removeIds)、
越权拒绝、脏车牌仍可识别。全模块 85 个测试通过。
|
2026-10-02 17:32:07 +08:00 |
|
weicw-dshsa
|
4de1ea5209
|
🐛 修 code-review 指出的三处问题:车牌匹配、提交人姓名为空、分页写法
1) **车牌匹配漏了规范化兜底(最严重)**
DriverWaybillServiceImpl.assertCertified 把 splitPlates 返回的**规范化**车牌
直接与 plate_no 原始列做精确 IN。库中存在带间隔符/横线/大小写差异的车牌时
会命中 0 行,导致「名下无可用车辆」→ **已认证的司机被误判为未认证而拒绝接单**,
与本次改造的核心验收「已认证的车重新提交后仍可正常接单」相悖。
DriverCertServiceImpl.findByPlateWithinBound 同样问题:先精确 IN 取候选再规范化
filter,而 filter 只能收窄不能放宽,漏掉的候选永远找不回来(等于没做规范化匹配)。
改法:把「精确 IN 或 规范化后相等」抽成 VehiclePlateSupport.applyPlateMatch,
三处调用点(含原先自己实现的 DriverAppServiceImpl.myVehicles)统一使用。
并加测试断言 SQL 表达式覆盖 Java 侧剔除的全部字符、且必须带 OR 兜底,
防止两边日后悄悄分叉。
2) **审核详情的提交人姓名恒为空**:CertAuditDetailVO.submitUserName 声明了却从未赋值,
违反「VO 展示字段须由服务端用 UserCache 填好」的规范。已补。
3) **分页未走项目统一写法**:原用 Page.of 手搓,全模块无先例。改为
Controller 收 Query + Condition.getPage(query),与 AccidentRecordController 等一致。
Query 绑定的正是 current/size,故三端契约不受影响。
顺带删除无任何调用者的 ICertAuditService.getRecordOrNull(推测性抽象 + 纯转发)。
82 个测试通过。
|
2026-10-02 17:30:48 +08:00 |
|
weicw-dshsa
|
0309d26184
|
✅ 权限表达式抽为共享常量并补可求值性测试
@PreAuth 里的 SpEL 字符串由框架在**请求时**求值,root object 是 AuthFun。
函数名写错既不过编译期、也不在启动期暴露,只会在真实调用时抛异常
(表现为接口 500)——正好是最难在开发阶段发现的一类错。
故把两个表达式抽到 CertAuditPermissions,并在测试中用与框架相同的
SpelExpressionParser + AuthFun 作为 root object 实际解析求值,覆盖:
- 只授司机菜单 / 只授车辆菜单 / 两个都没有;
- 只有查看权限、没有审核按钮权限时必须拒绝(能看≠能审);
- 表达式必须引用票 01 建的真实菜单码,且不得再出现角色名判断。
顺带消除控制器里与共享常量重复的两份字符串。
6 个新用例;全模块 79 个测试通过。
|
2026-10-02 17:08:22 +08:00 |
|
weicw-dshsa
|
60c1d626a2
|
🐛 认证审核接口改用菜单权限码,并补回被漏掉的审核岗位
原写法 @PreAuth("hasAnyRole('administrator','admin')") 有两个实际缺陷:
1. 库中**并不存在 admin 角色**(实查 blade_role:超级管理员 administrator、
运管 yunguan、财务 caiwu、录单员 ludan…),该分支永远不成立;
2. 真正承担认证审核的「运管」岗位**被排除在外**——即审核功能上线后没人能审。
改为按本项目的权限模型走菜单码(票 01 已建好这四个码):
cert_certification_audit_driver / _vehicle(列表与详情)
cert_certification_audit_driver_audit / _vehicle_audit(审核动作)
用 SpEL 而非 @PreAuth(menu = "..."),是因为同一组接口由 bizType 区分同时服务
司机与车辆两侧,单值 menu 表达不了「二者之一」。
已核对框架实现:AuthAspect 把 value 交给 SpEL 求值,root object 即 AuthFun,
而 hasMenu 是它的公开方法,故该表达式可用;menu() 非空时才会先行校验。
73 个测试通过。
|
2026-10-02 17:05:42 +08:00 |
|
weicw-dshsa
|
d61f1bcae4
|
♻️ 门槛里的启用判断改用 BladeConstant.DB_STATUS_NORMAL
原先写死 Integer.valueOf(1),虽然值与常量一致,但读代码的人无从判断
「1 到底是启用还是别的什么」。改用框架常量后语义自明,
将来若有人改动状态取值也不会遗漏此处。
已核对:车辆表 status 实际取值为 1(18 辆)与 2(2 辆),
BladeConstant.DB_STATUS_NORMAL 确为 1,判断逻辑未变。
73 个测试通过。
|
2026-10-02 17:01:34 +08:00 |
|
weicw-dshsa
|
f351bad545
|
✨ 接单叠加认证可用性门槛,带开关可快速回退
在原有运营状态(启用/停用)之上叠加一层「是否已认证」:
- 车辆:启用 且 存在生效快照;司机:存在生效快照。
判据是**生效快照指针**而非「最新提交状态」展示缓存,这一区别正是本改造的核心:
司机重新提交认证会把展示缓存变成「审核中」,若照它判定,司机一提交就接不了单
——那恰恰是本次改造要消除的问题。生效快照只在审核通过时切换,故曾通过即持续可用。
两个开关默认开启,可通过配置关闭以便线上快速回退到改造前行为:
transport.certification.vehicle-gate-enabled / driver-gate-enabled
门槛落在 DriverWaybillServiceImpl.accept():司机本人与名下**任一**车辆满足即可。
运营状态优先于认证——停用的车即便已认证也不可用(认证只叠加不覆盖)。
顺带消除第三份重复的车牌匹配实现:DriverWaybillServiceImpl 里的
splitPlates/normalizePlate 与 VehiclePlateSupport 逐行相同,改为委托同一实现。
10 个门槛用例(含「重新提交后仍可用」「停用车即便已认证也不可用」)
与全模块 73 个测试通过:mvn -o test -pl blade-service/blade-transport -am
|
2026-10-02 16:46:04 +08:00 |
|
weicw-dshsa
|
6831ba6fca
|
✅ 补个人认证「提交→审核→生效」闭环测试
司机认证最关键的一条业务闭环,单看提交侧或审核侧都验证不到:
提交之后司机侧查到的必须仍是旧生效值(否则等于提交即自动认证),
审核通过之后才变成新值(否则认证永远不生效)。
用内存 Map 承接记录读写,让提交服务与审核服务真实共享同一份状态,
避免两边各自 mock 成「恰好一致」——那种测试对集成缺陷是盲的。
5 个用例覆盖:
- 提交后仍是旧值、审核通过后才变新值;
- 驳回后生效值不变(已认证司机不会被驳回下线);
- 从未认证时审核前查不到生效值;
- 连续提交两次只剩一条待审,且被作废的那条不能再被审核;
- 已通过的记录不可再审(防止把生效快照改坏)。
全模块 63 个测试通过:mvn -o test -pl blade-service/blade-transport -am
|
2026-10-02 16:36:41 +08:00 |
|
weicw-dshsa
|
2edbacf838
|
✨ 小程序证件 OCR 薄适配层,含类型映射
小程序按既有契约 POST {imageUrl, type, side?} 到 /driver/auth/ocr,
后端转调已有的百度 OCR 能力(recognizeUrl)。
映射的必要性在于两侧命名对「行驶证」和「驾驶证」的用词正好相反:
驾驶证 —— 小程序传 driver,后端 OCR 用 driving_license
行驶证 —— 小程序传 vehicle,后端 OCR 用 vehicle_license
把入参直接透传下游,调用方不会收到任何错误,只会拿到另一种证件的字段,
问题要到人工核对时才发现。故用显式白名单逐一对应。
采用白名单而非「透传 + 兜底为通用识别」,是因为从业资格证没有对应的百度接口:
静默降级成通用文字识别会让前端以为识别成功,实际拿到一堆通用文本。
该类型明确报错并提示手动填写。
正反面:小程序目前不传 side,按 front 处理(正页是常用场景)。
10 个映射用例覆盖五个小程序类型、后端既有命名、大小写/分隔符变体、
未知类型、空值、不支持类型与 side 归一化。
全模块 58 个测试通过:mvn -o test -pl blade-service/blade-transport -am
|
2026-10-02 16:31:42 +08:00 |
|
weicw-dshsa
|
5747975152
|
✨ 管理端认证审核接口,并弃用旧车辆审核入口
审核作用于**一条认证记录**,不是车辆行或司机行。两条路径的差别是本次改造的关键:
- 通过:记录转已通过 + 写审核人/审核时间,并把该对象的生效快照指针**切换**到它
(切换而非追加,故一个对象至多一条生效快照);
- 驳回:记录转已驳回并留原因,生效快照指针**一个字都不动**。
因此「已认证的车被驳回」不会掉出可用池,只是这次提交没被采纳。
已终态(已通过/已驳回/已作废)的记录拒绝再次审核。理由:若允许,
把指针指着的那条「已通过」改成「已驳回」,生效值就凭空消失了。
审核详情同时返回待审快照与当前生效值两侧,供审核页做字段级 diff
(这正是「看出司机改了什么」的实质要求),并附 certified 标记,
便于前端提示「本次驳回不影响该对象继续使用」。
旧接口 POST /transport-vehicle/audit-certification 置为 @Deprecated 并加告警日志:
它作用于车辆行且原地覆盖,在生效值/待审值分离后语义已不成立。
保留而不删除是为了避免小程序历史版本或其它系统 404;它只写展示缓存,
不再影响可用性判定(可用性只看 effective_cert_record_id)。
修复过程中被测试抓到两个真实问题:
1. 通过路径原先对同一行连发两次 UPDATE(先切指针、再刷展示缓存),
合并为一次,消除了「后写覆盖先写」的可能;
2. 新增 EffectivePointerUpdateSqlTest,直接断言 MyBatis-Plus 生成的 UPDATE SET 片段:
指针列必须被「值非 null 才写」的 if 包住——驳回传 null 因此物理上碰不到它。
把「靠约定」变成「靠语句」,若有人给该字段加 ALWAYS 策略,测试立刻变红。
13 个审核用例 + 全模块 48 个测试通过:mvn -o test -pl blade-service/blade-transport -am
|
2026-10-02 16:26:20 +08:00 |
|
weicw-dshsa
|
63762b9dd0
|
✨ 司机端认证提交与记录查询接口(车辆/个人)
实现司机在小程序上提交认证、查看生效值与认证记录的能力。
提交链路的结构性保证(这是本次改造的核心约束「提交审核不影响车辆正常使用」):
- 提交只产生一条新的待审记录,**绝不修改 effective_cert_record_id**,
因此已认证的车重新提交后依然可用;待审内容在审核通过前只存在于记录表里;
- 同对象至多一条待审:落新记录前先把前一条待审转已作废,
且只动作待审——已通过/已驳回是终态,尤其不碰生效快照指着的那条;
- 新记录状态显式设为待审:框架会把空 status 静默填成 1,而 1 在本表是「已通过」,
不显式设置会让一次提交凭空变成审核通过;
- 新记录清空驳回原因,避免出现「审核中」却带着上一次驳回文案。
越权校验:司机只能提交/查看本人及本人绑定车辆的认证(复用 VehiclePlateSupport),
不可查看者返回业务异常而不是空列表——空列表会被误读成「没有记录」。
新增:
- DriverAuthController(/driver/auth/**,兼容 /blade-transport/driver/auth/**)
- IDriverCertService / DriverCertServiceImpl
- PersonCertSubmitRequest / VehicleCertSubmitRequest
- TransportCertRecordVO.statusText(状态文案统一在 Wrapper 翻译,四端一套说法)
- IDriverAppService.currentDriverEntity()(认证写入需要司机实体)
17 个用例覆盖票 02 的三条验收点与不变式(含「重新提交后生效值仍是旧的」)。
全模块 33 个测试通过:mvn -o test -pl blade-service/blade-transport -am
|
2026-10-02 16:17:06 +08:00 |
|
weicw-dshsa
|
e891100a23
|
✨ 认证记录状态机规则集中为 CertificationRuleSupport 并补测试
把「什么状态能做什么」从持久化里拎出来单独验证。这几条规则是认证改造的地基,
改坏的后果都是线上事故,故先锁住行为再写业务:
- prepareForSubmit:新提交一律待审,并清空驳回原因(否则会继承上一次的驳回文案,
出现「审核中」却带着驳回原因的自相矛盾状态);
- supersedeIfPending:再次提交只作废前一条待审,已通过/已驳回/已作废都是终态不碰
——尤其是不得改动已通过的记录,它可能正被生效快照指针指着;
- isCertified:唯一判据是生效快照指针,故「曾通过即永久保持」;
- isAuditable:只有待审可审,终态再审会把生效快照改坏;
- statusText:四种状态各一个中文说法,与列注释、前端文案保持一致。
TransportCertRecord.REJECT_REASON_MAX_LENGTH 与 reject_reason 列宽(200)对齐。
9 个用例覆盖上述规则与边界(null、未知状态、超长原因)。
可离线执行:mvn -o test -pl blade-service/blade-transport -am
|
2026-10-02 16:10:34 +08:00 |
|
weicw-dshsa
|
8a2d83b3cd
|
♻️ 车牌软关联逻辑抽为 VehiclePlateSupport 并补测试
司机 driving_vehicle 与车辆表 plate_no 之间没有外键,只有文本关联,且库中存在
间隔符/横线/大小写差异,一个字段还可能并列多辆车。认证提交的越权校验
(只能操作本人绑定车辆)依赖这套匹配:漏判会让司机改不了自己的车,
误判会让司机改到别人的车,故先把规则集中并锁住行为。
- 新增 VehiclePlateSupport:splitPlates / normalize / isBound;
isBound 对空值一律判不绑定(不能因为双方都为空就放行,那等于越权)。
- DriverAppServiceImpl 原先自己实现了一份 splitPlates/normalizePlate,
改为委托同一个实现,避免两处口径分叉。
- 6 个用例覆盖分隔符变体、去重、规范化、脏数据与绑定判定。
可离线执行:mvn -o test -pl blade-service/blade-transport -am
|
2026-10-02 16:08:47 +08:00 |
|
weicw-dshsa
|
9f3914463e
|
✅ blade-transport 引入 JUnit 5 测试基础设施
本模块此前没有可自动执行的测试:无 src/test 目录、pom 无测试依赖、
父 pom 无 surefire、全仓 0 个 @Test(仅有的 6 个 *Test.java 实际是 main() 手跑脚本)。
而认证改造的提交/审核链路带状态机语义(同对象至多一条待审、提交不得修改生效快照等),
必须用可重复执行的单元测试守住,否则只能靠人肉 review。
- blade-transport/pom.xml 增加 spring-boot-starter-test(test scope,版本由 blade-bom 管理);
- 加一个基础设施自检用例,确认 JUnit 5 在本模块能被发现并执行。
可离线执行:mvn -o test -pl blade-service/blade-transport -am
|
2026-10-02 16:03:50 +08:00 |
|
weicw-dshsa
|
36d23cb426
|
📝 认证记录相关文件去掉外部文档引用,注释改为自解释
前一次提交的注释大量引用本仓库之外、同事看不到的东西:
docs/adr/0001、docs/adr/0002、GLOSSARY.md、.scratch/ 下的 spec 与 ticket 编号、
以及 ADR-0002 / D10 / 不变式 I1~I3 这类代号。这些都在另一个 git 仓库
(weicw/tms-erp)里,单独 checkout 本仓库的人根本找不到,只会困惑。
改为把结论直接写在注释里:
- 生效快照指针为何「一经设置永不回退」(原来只写「见 ADR-0002」);
- 为何 redis 状态字段不能用 0 兜底;
- 为何生成列要排除 is_deleted、为何 tenant_id 必须 NOT NULL;
- changeStatus 为何被禁用(原来写「破坏 I3 的留痕」)。
顺带对齐本仓库的既有排版习惯:
- 横幅破折号由 77 个改为 30 个(与 blade_annual_inspection_record.sql 等一致);
- 去掉 SQL 注释里的 markdown 粗体(本目录无其他脚本这么写)。
仅注释变更:SQL 的 diff 已逐行核对,非注释行改动为 0,DDL 一字未动;
迁移重跑仍 exit 0,audit-migrations 通过,mvn clean compile 成功。
|
2026-10-02 15:47:39 +08:00 |
|
weicw-dshsa
|
87f4c3a830
|
✨ 新增认证记录不可变快照数据模型与迁移脚本
按 ADR-0001/0002 建立司机与车辆共用的认证记录表 blade_transport_cert_record
(biz_type 区分、载荷存 JSON、检索字段提升为真实列),并为司机/车辆表补生效快照指针。
不变式结构性保证:
- I1 同对象至多一条待审:生成列 pending_biz_id + 唯一索引,数据库层拦截;
生成列同时排除 is_deleted,避免逻辑删除的待审记录永久占用唯一键。
- I3 快照不可变:snapshot_json 等 5 列标 FieldStrategy.NEVER,永不进入 UPDATE。
- status 承载审核状态(0审核中/1已通过/2已驳回/3已作废),新增时必须显式设置:
框架 resolveEntity 会把 null 的 status 静默填成 1(即「已通过」),
且继承来的 changeStatus 可直接写 status,两条通道均已封堵。
其他:司机表补身份证有效期三列并订正排序规则为 utf8mb4_general_ci
(原先为 0900_ai_ci,与车辆表 JOIN 已发生过 Illegal mix of collations);
生效快照指针加 @JsonProperty(READ_ONLY),防止以 /submit 请求体自行「认证」自己;
同步基线建表脚本与认证审核菜单/权限码。本票不含任何业务接口。
|
2026-10-02 14:40:56 +08:00 |
|
weicw-dshsa
|
c86c5ff968
|
🔀 合并 fix/issue-2-10-import-batch-rollback
导入链路整批修复(issues #2-#10 + 违章/记录类/台账类/运输对账等):
- 所有批量导入改为「任一行失败即整批回滚」
- 失败明细返回原表全量并逐列标红(不再只给错误行)
- 读取阶段异常兜底,不再暴露 HTTP 500 技术文案
- 空表提示改为「未读取到数据行,请确认表头下方已填写内容」
- 修复常用货物型号必填漏校验、运输对账动态费用列静默转 0、
失败明细行号错位等
详见该分支 16 个提交。
|
2026-09-26 15:30:04 +08:00 |
|
weicw-dshsa
|
4ccc28e991
|
🐛 修复三处导入校验缺陷与失败明细行号错位
对全仓 31 处导入入口做了一次「导入校验 vs 新增/编辑校验」的一致性审计,
以下三处是审计中严重度最高的、且业务口径无歧义的缺陷:
1) 常用货物:型号必填只在新增/编辑生效,导入侧被放过
submit(CommonCargo) 走 validate(cargo, requireModel=true),而导入调
submit(cargo, false) —— 页面上存不进去的数据(型号为空)却能通过导入写进库。
CommonCargoExcel 的「型号」列也没标 *,用户按模板填根本不知道它必填。
改法:去掉 requireModel 开关(该参数已成死参数,留着只会让两边再次分叉),
导入与新增/编辑共用同一个 validate;模板表头改 *型号。
2) 运输对账:动态费用列填非数字被静默改成 0.00
VehicleReconciliationFeeReader / CargoReconciliationFeeReader 的 decimal()
在 catch (NumberFormatException) 后直接返回 ZERO —— 「一百元」变成 0.00 存进
feeItemsJson,参与结算金额与自动匹配,属静默写脏数据。
改法:抛新增的 ImportCellReadException(blade-common),带上行号/列名/原值,
由既有读取阶段兜底导出原表全量明细。
3) 运输计划:文案「数量/里程必须为正数」与规则不符
条件只判 < 0(0 是合法值),新增/编辑侧的文案是「不能小于0」。统一为「不能小于0」。
顺带修掉一个更基础的错位:
ImportFailureExcelUtil.readFailureRowIndex 直接拿
ExcelDataConvertException.getRowIndex() 当失败明细的行下标,但前者是
【绝对 0 基行号】(表头=0),后者只对数据行计数。错误恰好落在最后一行时
靠 clamping 侥幸正确,落在首行就会把原因标到下一行 —— 实测首行出错时原因
被标到了第 3 行(应为第 2 行)。现统一换算(-1)并把两类异常收口到
readFailureExcelRowIndex。
验证:
- mvn clean install -DskipTests 通过。
- 全套 16 个导入回归脚本 469 项断言全绿,其中:
- 运单核对新增用例 04(首行读取失败须标在第 2 行)、05(动态费用列填中文
必须报错),运单核对套件 28 项全绿;
- 常用货物新增用例 08(型号为空须整批回滚),套件 29 项全绿;
- 读取失败套件 4 项全绿,证明行号修正未破坏既有断言。
|
2026-09-26 12:45:17 +08:00 |
|
weicw-dshsa
|
9bf7fdfe99
|
⚡ 空表导入提示改为「未读取到数据行,请确认表头下方已填写内容」
原提示「导入数据不能为空」在用户上传「只有表头、未填数据行」的文件时容易误解
(文件并非空文件,只是没填内容)。全项目 27 个模块、30 处统一替换该文案。
验证:mvn install -DskipTests 通过;空表上传返回新文案;
13 个导入回归脚本 383 项断言全绿。
|
2026-09-26 11:50:57 +08:00 |
|
weicw-dshsa
|
2d185f0de6
|
🐛 导入单元格无法转换时改为返回可读失败明细,兜底 26 个导入接口
问题(用户实测反馈):金额列填「一万二千元」这类无法转换的内容时,EasyExcel 在
ExcelUtil.read(...) 阶段就抛 ExcelDataConvertException,根本走不到行级校验;
控制器只 catch ImportFailureException,异常穿透到全局处理器,用户看到的是
HTTP 500 + 「Convert data ... to class java.math.BigDecimal error」这类技术文案,
且完全拿不到失败明细。
影响面:全部 27 个导入接口(读阶段的 ExcelUtil.read 都在 try 内、只 catch
ImportFailureException),非维修记录独有。
改动:
- ImportFailureExcelUtil 新增三个能力(blade-common,公共层一次覆盖各模块):
1) describeReadFailure:把 ExcelDataConvertException 转成
「第N行「列名」格式不正确:<原值>」,列名按列序号反查 @ExcelProperty;
2) readRawRows:以原始文本(Map)方式重读文件,不做类型转换因此绝不抛异常,
用于拿回「原表全部行」;
3) exportReadFailure:一站式兜底(重读 → 导出全量行 + 仅出错行带原因 +
按列标红),返回 false 表示非转换类异常,调用方继续抛出保持原行为。
- 26 个导入控制器在现有 catch 之后追加 catch(Exception) 兜底,未改动原有
行级校验与整批回滚逻辑。
验证:
- 实测维修记录/费用项/币种汇率三个模块:HTTP 500→200,返回全量明细,
文案如「第5行「费用」格式不正确:一万二千元」(行号经单行/四行文件双向校准)。
- 既有回归无退化:记录类 80/80、台账 32/32、港口码头 45/45、货物类型 24/24、
费用项 20/20、币种汇率 25/25。
- 新增 scripts/api-read-failure-test.sh(4 断言)固化该场景。
|
2026-09-26 11:37:07 +08:00 |
|
weicw-dshsa
|
be02a5e942
|
🐛 修复运输对账导入无回滚与运输计划明细不全(批次4)
本批是 16 个模块收尾,两个特殊模块:
1) 运输对账(importVehicles / importCargoes)——最严重的一例:
既无 setRollbackOnly 也不抛异常。方法开头 resetExternal(id) 清空既有外部账单,
循环末尾无条件插入本批正确行,然后 return failures。一旦有失败行:
旧外部账单已被清空、新账单只插入了部分——数据损坏且不可恢复。
改法:任一行失败时抛 ImportFailureException(rows),让 resetExternal 清空
与本批插入在同一事务内一起回滚。另把失败原因写回原行(异常携带原表 rows,
只写 Vehicle/CargoReconciliationFailureExcel 副本会丢原因)。
控制器改 catch 异常导出原表全量(用 export 保留按列标红)。
2) 运输计划(importTransportPlan)——失败明细只返回 errorMap.values()(仅错误行)。
改为抛 ImportFailureException(data) 携带原表全量;控制器 catch 后导出。
验证:mvn install -DskipTests 通过;全项目 12 个导入回归脚本 379 项断言全绿。
全项目已无 TransactionAspectSupport...setRollbackOnly() 调用残留。
注:运输对账需先建对账草稿(多张前置表)才能端到端回归,
本批仅完成代码改造与编译验证,回归用例待补(见后续说明)。
|
2026-09-26 11:10:37 +08:00 |
|
weicw-dshsa
|
962bcc7879
|
🐛 台账/主数据类导入(4 个模块)失败明细返回全量原表
覆盖:设备台账 / 保养计划(blade-transport)、铁路站点 / 机场主数据(blade-system)。
问题同前两批:收集 errorList 后 setRollbackOnly 并 return,控制器据此导出
「仅错误行」——失败明细不是原表全量,用户无法对照原表修正。
改动(同构):
- 服务层:抛 ImportFailureException(data),明细携带原表全部行;
回滚由异常触发(替代 setRollbackOnly)。注意 blade-system 的两个模块
用的是静态导入 TransactionAspectSupport,模式略有差异。
- 控制器:catch 异常取 getFailureList() 导出(用 export 保留按列标红),
补上传文件校验。
验证:mvn install -DskipTests 通过;台账回归 32/32,记录类回归 80/80。
|
2026-09-26 10:58:15 +08:00 |
|
weicw-dshsa
|
96010cf542
|
🐛 记录类导入(第二批 4 个模块)失败明细返回全量原表
覆盖:里程记录 / 油电记录 / 其他费用记录 / 运输变更记录。
问题同第一批:收集 errorList 后 setRollbackOnly 并 return,控制器据此导出
「仅错误行」——失败明细不是原表全量,用户无法对照原表修正。
改动(同构):
- 服务层:抛 ImportFailureException(data),明细携带原表全部行;
回滚由异常触发(替代 setRollbackOnly)。
- 控制器:catch 异常取 getFailureList() 导出(用 export 保留按列标红),
补上传文件校验。
验证:mvn install -DskipTests 通过;记录类回归 80/80
(10 模块 × 2 用例,含第一批 6 个模块的回归确认)。
|
2026-09-26 10:52:02 +08:00 |
|
weicw-dshsa
|
f24209fa8e
|
🐛 记录类导入(6 个模块)失败明细返回全量原表
问题:这 6 个模块(事故记录/年检记录/ETC记录/保险记录/维修记录/换胎记录)
在收集 errorList 后 setRollbackOnly 并 return,控制器据此导出「仅错误行」——
失败明细不是原表全量,用户看不到哪几行是对的、不便对照原表修正。
改动(6 个模块同构处理):
- 服务层:改为抛 ImportFailureException(data),明细携带**原表全部行**;
整批回滚由异常触发(替代 setRollbackOnly,语义不变)。
- 控制器:catch 异常后取 getFailureList() 导出,并补上传文件校验。
用 export(...) 保留按列标红(exportFailureReasonOnly 会丢失该能力)。
验证:mvn install -DskipTests 通过;记录类回归 48/48
(scripts/api-records-import-test.sh,6 模块 × 2 用例)。
标志性断言:3 行正确 + 第 4 行错 → 明细返回全部 4 行、仅第 4 行带原因、
库中零写入;全部正确 → 正常入库。
|
2026-09-26 10:46:39 +08:00 |
|
weicw-dshsa
|
81824b5062
|
🐛 违章记录导入失败明细返回全量原表
问题:importViolationRecord 收集 errorList 后 setRollbackOnly 并 return,
控制器据此导出「仅错误行」——失败明细不是原表全量,用户看不到哪几行是对的、
也不便对照原表修正(用户反馈:违章记录没有返回全量表格)。
改动:
- 服务层:改为抛 ImportFailureException(data),明细携带**原表全部行**;
整批回滚由异常触发(替代 setRollbackOnly,语义不变)。
- 控制器:catch 异常后取 getFailureList() 导出,并补上传文件校验。
用 export(...) 而非 exportFailureReasonOnly(...):后者会把 markErrorColumns
置 false、只标红失败原因列,导致「按列标红」能力丢失(实测 5 个既有用例
标红列变空);export(...) 同时保留全量行与按列标红。
验证:mvn install -DskipTests 通过;违章记录回归 40/40
(既有 9 用例,标红列断言全绿:03 类型 / 04 事项 / 05 事项 / 06 类型 / 08 车牌号/船号);
用户实际上传文件实测:失败明细返回全量 5 行、仅错误行带原因、标红[车船类型,状态]、
库中零写入。其余 8 个导入模块回归 187 项全绿,无连带影响。
|
2026-09-26 10:30:39 +08:00 |
|
weicw-dshsa
|
f2b6ca2834
|
🐛 行政区划导入补事务实现整批回滚,缓存清理移到成功路径
问题:RegionServiceImpl.importRegion 是唯一没有 @Transactional 的导入板块,
循环内吞掉异常后正常 return,已落库行直接提交。且 cacheChanged 标志导致
「先清缓存、再提交事务」:循环内已有行 submit 成功 → 后面行失败 → 方法
正常返回 → 惰性树缓存被清/重算成失败批次的中间状态,库回滚后缓存脏掉。
改动:
- 服务层:补 @Transactional(rollbackFor = Exception.class);错误收集完后
抛 ImportFailureException(org.springblade.common.excel)触发整批回滚。
- 缓存语义重构:submit 拆出 clearCache 参数(公开 submit(region) 行为不变,
手工新增仍即时清缓存);导入路径传 false 不逐行清缓存,
统一移到方法末尾成功路径上——异常抛出后不可达,失败批次缓存保持原状。
- 控制器:改 catch 异常导出(exportFailureReasonOnly)+ 补上传文件校验。
验证:mvn install -DskipTests 通过;行政区划回归 25/25
(tests/fixtures/region/),Redis 断言覆盖:成功路径缓存被清、
失败路径缓存键原样保留、基线行不被失败批次污染。
|
2026-09-25 08:20:06 +08:00 |
|
weicw-dshsa
|
c5e5433dc8
|
🐛 修复运单管理导入未整批回滚
问题:WaybillServiceImpl.importWaybill 虽有 @Transactional,但循环内吞掉
异常后正常 return,Spring 照常提交——失败行之前的正确行已落库。
本票回滚边界比其它板块宽:submit 虽只写运单主表,但 carrierJson 构造、
多个宽容日期解析都在循环内,失败原因需覆盖;关联表写入在 import-batch
链路,不在本票范围。
改动:
- 服务层:错误收集完后抛 ImportFailureException(org.springblade.common.excel)
触发整批回滚。catch 里原本就把原因写在原行对象上,无需额外处理。
- 控制器:改 catch 异常导出(exportFailureReasonOnly)+ 补上传文件校验。
验证:mvn install -DskipTests 通过;运单管理回归 19/19
(tests/fixtures/waybill-import/manage-excel/,含 02_一行错误多行正确_应零写入)。
既有 import-batch 链路的 *.json 与 excel/ 用例未改动。
|
2026-09-25 08:20:06 +08:00 |
|
weicw-dshsa
|
a8808942a3
|
🐛 修复评分量化表导入未整批回滚(按评定表分组粒度)
问题:CreditScoreQuantificationServiceImpl.importCreditScoreQuantification
循环单位是「评定表名称」分组(每分组一次 submit,写主表+项目+选项等多表),
异常被 catch 吞掉后正常 return,Spring 照常提交——失败分组之前的
正确分组已经落库。
改动:
- 服务层:任一分组失败、errorList 非空时抛 ImportFailureException
(org.springblade.common.excel)触发整批回滚,失败分组之前已 submit
的正确分组一起退掉。失败明细粒度保留既有行为:覆盖失败分组的全部行。
「评定表名称」为空的行不走 submit、保持早退标错路径。
- 控制器:改 catch 异常导出(exportFailureReasonOnly)+ 补上传文件校验。
验证:mvn install -DskipTests 通过;评分量化表回归 15/15
(tests/fixtures/credit-score/,含 02_后组失败前组正确_应零写入)。
另确认既有语义:与库中重名的分组走覆盖式更新(saveOrUpdate),非错误。
|
2026-09-25 08:20:06 +08:00 |
|
weicw-dshsa
|
82d823e68d
|
🐛 修复费用项导入未整批回滚,失败原因写回原行
问题:FeeItemServiceImpl.importFeeItem 虽有 @Transactional,但循环内吞掉
异常后正常 return,Spring 照常提交——失败行之前的正确行已落库。
改动:
- 服务层:错误收集完后抛 ImportFailureException(org.springblade.common.excel)
触发整批回滚;同时把失败原因写回原行对象 excel.setErrorMessage——
抛出异常时携带的是原表 data,导出工具从行对象的 errorMessage 字段取原因,
只写在 FeeItemImportFailureExcel 副本上会导致失败明细原因为空。
- 控制器:改 catch 异常导出(exportFailureReasonOnly)+ 补上传文件校验,
对齐 PortTerminalController 写法。
验证:mvn install -DskipTests 通过;费用项回归 20/20
(tests/fixtures/fee-item/,含 02_一行错误多行正确_应零写入)。
|
2026-09-25 08:20:06 +08:00 |
|
weicw-dshsa
|
30e1ada0cc
|
🐛 修复币种汇率导入未整批回滚,派生写随事务一起退
问题:CurrencyServiceImpl.importCurrency 无 @Transactional,循环内吞掉异常
后正常 return,失败行之前的正确行已落库。且循环内除 save 外还有
rebuildEnabledValidity 派生写(按 code 重算启用记录有效期区间),
若只回滚主表遗漏派生写,会留下「主表回滚了、有效期却按失败批次算过」的脏数据。
改动:
- 服务层:补 @Transactional(rollbackFor = Exception.class),错误收集完后
抛 ImportFailureException(org.springblade.common.excel),
主表 save 与派生写 rebuildEnabledValidity 在同一事务内一起回滚。
- CurrencyExcel.errorMessage 由 @ExcelProperty 改为 @ExcelIgnore:
原先导出模板会多出 errorMessage 空列(与 issue #12 运单模板同款问题)。
- 控制器:改 catch 异常导出 + 补上传文件校验,对齐 PortTerminal 写法。
验证:mvn install -DskipTests 通过;币种回归 25/25(含派生区间
正确性断言与零写入断言);同批修复顺带覆盖 issue #12 同类问题。
|
2026-09-25 08:20:06 +08:00 |
|
weicw-dshsa
|
cd2052e5d0
|
🐛 修复常用线路导入未整批回滚
问题:CommonRouteServiceImpl.importCommonRoute 循环内吞掉异常后正常 return,
方法正常返回导致 Spring 照常提交事务。方法虽有 @Transactional(rollbackFor =
Exception.class),但异常被吞后注解救不了——失败行之前的正确行已经落库。
改动:
- 服务层:错误收集完毕后若 failureList 非空,抛 ImportFailureException
(org.springblade.common.excel)触发整批回滚。catch 里原本就把原因
写在原行对象上,失败明细原因不丢,无需额外处理。
- 控制器:改为 catch 异常 → 取 failureList 导出(exportFailureReasonOnly)
→ return null,并补上传文件校验,对齐 PortTerminalController 写法。
验证:
- mvn install -DskipTests 全量编译通过。
- 常用线路回归 29/29 通过(新增 tests/fixtures/common-route/,
scripts/api-common-route-import-test.sh),含 02_一行错误多行正确_应零写入、
07_与库中线路重名(基线行不受回滚影响)。
- 港口码头 45/45、常用货物 25/25 基线回归通过,确认无连带影响。
|
2026-09-25 08:20:06 +08:00 |
|
weicw-dshsa
|
07b2f2766e
|
🐛 修复常用货物导入未整批回滚,失败明细原因写回原行
问题:CommonCargoServiceImpl.importCommonCargo 循环内吞掉异常后正常 return,
方法正常返回导致 Spring 照常提交事务。方法虽有 @Transactional(rollbackFor =
Exception.class),但异常被吞后注解救不了——失败行之前的正确行已经落库。
改动:
- 服务层:错误收集完毕后若 failureList 非空,抛 ImportFailureException
(org.springblade.common.excel,#2 已迁入 blade-common)触发整批回滚。
- 修复失败明细原因为空的问题:catch 里除写入 failureExcel 副本外,
还必须把原因写回原行对象 excel.setErrorMessage(...)——抛出异常时携带的是
原表 data,导出工具从行对象的 errorMessage 字段取原因,只写副本会丢。
- 控制器:改为 catch 异常 → 取 failureList 导出 → return null,并补上传
文件校验,对齐 PortTerminalController 写法。
验证:
- mvn install -DskipTests 全量编译通过。
- 常用货物回归 25/25 通过(新增 tests/fixtures/common-cargo/,
scripts/api-common-cargo-import-test.sh),含 02_一行错误多行正确_应零写入。
- 港口码头基线回归 45/45 通过,确认无连带影响。
|
2026-09-25 08:20:06 +08:00 |
|
weicw-dshsa
|
99c4bf4f7d
|
🐛 修复货物类型导入未整批回滚,并把导入回滚异常迁到公共模块
问题:CargoTypeServiceImpl.importCargoType 循环内吞掉异常后正常 return,
方法正常返回导致 Spring 照常提交事务,@Transactional 起不到回滚作用。
含 1 行错误的文件会写入前面若干行正确数据,与「任一行失败即整批零写入」口径不符。
改动:
- ImportFailureException 由 org.springblade.system.excel 迁至
org.springblade.common.excel(与 ImportFailureExcelUtil 同包)。
blade-transport 只依赖 blade-system-api,原先拿不到该异常,
迁到 blade-common 后 blade-system 与 blade-transport 均可引用。
- CargoTypeServiceImpl.importCargoType 补 @Transactional(rollbackFor = Exception.class),
错误收集完毕后抛 ImportFailureException 触发回滚,不再 return failureList。
- CargoTypeController.importCargoType 由「拿返回值导出」改为
「catch 异常 → 取 failureList 导出 → return null」,并补上传文件校验,
对齐 PortTerminalController 的写法。
- PortTerminalController / PortTerminalServiceImpl 仅调整 import 指向新包,行为不变。
验证:
- mvn install -DskipTests 全量编译通过。
- 港口码头回归 45/45 通过,确认「异常搬家」未破坏既有基线。
- 货物类型回归 24/24 通过,含 02_一行错误多行正确_应零写入(库中零写入)。
|
2026-09-25 08:20:05 +08:00 |
|
weicw-dshsa
|
6b97685165
|
🐛 修复网关经 blade-common 传递依赖启动失败
fd6563f 为 LenientDateParser 引入的 blade-starter-log(compile scope)
把 blade-core-tool 等整棵依赖树传递给所有依赖 common 的模块。网关
(WebFlux) 的 pom 排除了 spring-boot-starter-web(无 spring-webmvc),
而 blade-core-tool 的自动配置 BladeConverterConfiguration implements
WebMvcConfigurer 且无 @ConditionalOnClass 守卫,Spring 解析该配置类时
抛 FileNotFoundException 导致网关启动即崩。
修复:starter-log 改为 provided —— 编译期 ServiceException 可见,
不再向下游传递。业务服务运行时的 ServiceException 由 blade-core-boot
传递提供,行为不变。
验证:网关以原 classpath 启动成功(Started GateWayApplication in
16.4s);blade-common 与全仓 BUILD SUCCESS。
|
2026-09-21 10:44:30 +08:00 |
|
weicw-dshsa
|
fd6563f53b
|
✨ 批量导入日期宽容解析:兼容 2026-08-02 与 2026-8-2 等书写变体
- blade-common 新增 LenientDateParser(宽容解析:- / . 分隔符、补零与否、
时间可省略秒/分;拒绝两位年份、日在前、无分隔符)
- 新增 LenientDateStringConverter / LenientDateTimeStringConverter:
Excel 数值日期转文本透传,文本解析留待服务层以进入失败明细流程
- 8 个裸走 fastexcel 内置转换的导入 DTO(保险/年检/事故/其他费用/运单/
币种/用户生日/设备台账)日期字段改为 String 承载,服务层统一经
LenientDateParser 解析,失败报「<列名> 日期格式无法识别:<原值>」
- MaintenancePlanDateTimeConverter / TireReplacementDateStringConverter
内部委托公共解析器,6 个 DTO 注解零改动
- 运输计划、运单批量、运输对账、换胎 4 处手动解析点收敛至同一工具类
- UserMapper 导出 SQL 的生日改 DATE_FORMAT 输出,保持导出格式不变
口径见根工作区 docs/import-spec.md(weicw/tms-erp#1)。
回归:port-terminal 45 断言、violation-record 40 断言(含新增不补零
用例 09)、waybill-import 48 断言、insurance-record 新增用例 6 断言,
全部通过。
|
2026-09-21 09:47:50 +08:00 |
|
weicw-dshsa
|
ddfa52a2ac
|
⚡ 收窄运输方式枚举为公路/铁路/水路/航空四种
运输计划导入校验白名单去掉「公路整车、公路配载/零担、跨境海运」
运单批量导入字典兜底值去掉多余枚举,仅保留四种运输方式
|
2026-09-21 06:24:31 +08:00 |
|
weicw-dshsa
|
37d0ebc21e
|
⚡ 导入失败明细去掉空单元格底纹
标红统一只改红色字体,不再对空单元格加浅红底纹(IndexedColors.ROSE)。
底纹原本是为「必填项为空时红字在屏幕上看不见」而加,但它超出
AGENTS.md §6.11「仅出错字段/列使用红色文字」的口径,视觉上也偏重。
- markRed(Cell, boolean) 简化为 markRed(Cell),删除 redFillStyleCache 与 isBlankValue
- 空单元格的红色字体样式照旧写入 styles.xml,api-violation-xlsx-cols.js
按字体色判定,回归用例 03/04 不受影响
- 影响所有使用 ImportFailureExcelUtil 的导入模块(20+ 个)
|
2026-09-21 05:52:31 +08:00 |
|
weicw-dshsa
|
993f802111
|
⚡ 精简运单导入车牌号校验的失败原因
一次车牌号错误原来最多会叠出「长度不能少于7位」「首位必须是省份简称、
第二位必须是英文字母」「格式不正确」三条原因,导出的失败明细里这一格很长。
现将公路运输下的必填、长度与格式统一为一条「车牌号校验不通过」。
- 校验强度不变:长度 7/8 位本就由 VEHICLE_NO_PATTERN 蕴含,省份简称白名单照旧
- 保留「车牌号」字样,失败明细仍能按列名拆词匹配并标红车牌号列;车牌为空时
走空单元格红底纹分支,比原来只有文字更容易定位
- 未改动「同一配载标识号下,车牌号不一致」,该原因由 tests/fixtures/waybill-import
用例 04 断言
|
2026-09-21 05:45:49 +08:00 |
|
weicw-dshsa
|
4c96583701
|
🐛 修复码头导入父港口取列不一致导致的静默丢数据
importTerminals 中 setParentCode 取「港口编码」列,而抑制连带报错时
却用「上级港口编码」判断父行是否已声明。用户若把完整编码填入
「码头编码」并让「港口编码」留空,父港口解析失败的异常会被误判为
「父行已声明」而吞掉,码头被静默丢弃且接口返回成功。
- splitByCategory 增加码头行「港口编码」非空校验,明确报错
- 抑制逻辑改为与 setParentCode 取同一列
|
2026-09-21 05:34:59 +08:00 |
|
weicw-dshsa
|
8485efe00d
|
🐛 修复导入失败明细无法按列标红的问题
4e1a162 移除了按列名匹配逻辑后只剩失败原因列标红。
现恢复并修正误标红:命中片段被更长片段覆盖时只保留更长的列
(避免原因含「车船类型」时把子串「类型」列一起标红)。
|
2026-09-21 05:21:27 +08:00 |
|
weicw-dshsa
|
b02aff8ff6
|
✨ 运单导入支持多货物合并与配载路线串联
- 同一运单标识号的多行货物合并为一条运单,各行转为货物明细写入 goodsJson,数量与其他费用合计按行累加
- 新增组内一致性校验:发货地址、到货地址、数量单位、配载标识号不一致时报错,避免无法合并的数据静默落库
- 配载单路线按导入顺序串联,上一票到货地与下一票发货地重合时去重写入途经地,到货地取末票
|
2026-09-21 04:19:55 +08:00 |
|
weicw-dshsa
|
37309b24f9
|
🐛 维修记录导出移除多余的“导出失败原因”列
- MaintenanceRecordExportExcel 仅为把父类 @ExcelIgnore 的 errorMessage 重新暴露成
第 18 列“导出失败原因”而存在,正式导出该列恒为空白,属遗留冗余
- 删除该字段与对应 import,导出回归 17 列,与导入模板字段顺序一致
- 导入失败明细导出不依赖本类:ImportFailureExcelUtil 自行按字段构建列并过滤
errorMessage,再反射读取失败原因追加“导入失败原因”列,逻辑不受影响
|
2026-09-20 20:34:56 +08:00 |
|
weicw-dshsa
|
56c7bc020a
|
🐛 修复维修记录批量导出文件空白的问题
- MaintenanceRecordExcel 的 createTime/updateTime 字段类型为 java.util.Date,
但仍绑定了 MaintenancePlanDateTimeConverter(Converter<LocalDateTime>),
导出写单元格时 Date 强转 LocalDateTime 抛 ClassCastException,
写流中断导致下载到损坏的 xlsx,打开后一片空白
- 移除这两个 Date 审计字段上的 converter,仅保留 @DateTimeFormat("yyyy-MM-dd HH:mm:ss"),
与 AccidentRecordExportExcel 等同模块导出模型写法保持一致
- 维修时间、出厂时间仍为 LocalDateTime,转换器保留不变,导入解析不受影响
|
2026-09-20 20:31:02 +08:00 |
|
weicw-dshsa
|
af1430eaee
|
🐛 修复未配置 MinIO 时 transport 服务无法启动的问题
凭证图片 MinIO 客户端此前为无条件装配,缺少 file.storage.minio.endpoint
配置时会在启动阶段直接抛 IllegalArgumentException,导致整个
blade-transport 服务起不来,并在关闭失败上下文时连带抛出
nacosGracefulShutdownDelegate 的 BeanCreationNotAllowedException,
掩盖了真正的失败原因。
- VoucherMinioConfig 增加 @ConditionalOnProperty,未配置 endpoint 时不注册客户端
- ProcessConfigController、VoucherManageServiceImpl 改用 ObjectProvider
可选注入,避免构造器注入因 bean 缺失而启动失败
- 新增 minioClient() 访问器,在真正调用时给出"未配置"的明确提示,
与已有 validateMinioConfig() 的提示风格保持一致
未配置 MinIO 时服务可正常启动,凭证相关接口仅在使用时提示配置缺失;
已配置 MinIO 时行为不变。
|
2026-09-20 19:31:58 +08:00 |
|
weicw-dshsa
|
304061774e
|
🔀 合并 dev 分支到 master
解决 9 个文件的冲突,取舍如下:
- 导出模型:采用 dev 的 *ExportExcel 命名与拆分,并保留 master 的
@DateTimeFormat(dev 改名时漏加,会导致时间列显示为 Date.toString)。
- PortTerminal 导入:保留 master 的两阶段导入 + ImportFailureException
全量回滚(ImportFailureException 仅 master 有,合并后的 controller 依赖它),
导出失败明细改用 dev 的 exportFailureReasonOnly(仅标红失败原因列)。
- PortTerminal 导入模板:采用 dev 的"港口编码/码头编码"两列结构,
相应补上 resolveImportCode 归并规则,并在构建实体时显式赋 code/parentCode。
- PortTerminal 导出:采用 dev 的 PortTerminalExportExcel(接口已如此声明),
并保留 updateUserName 审计人翻译。
- 违章记录导入:保留 dev 的多错误收集 + 导入失败明细导出流水线,
删除已被拆列取代的 violationTypeOrItem 映射,补上 clearIrrelevantField,
并为导入校验补齐"对侧字段应留空"规则以与表单校验一致。
验证:mvn compile -DskipTests 全模块 BUILD SUCCESS。
|
2026-09-20 18:04:43 +08:00 |
|
weicw-dshsa
|
98697af6df
|
🐛 修复违章记录导入的类型与事项字段混淆问题
- 导入模型将合并的"类型/事项"列拆分为"*类型"与"*事项"两列,与导出模型保持一致
- 校验与清空逻辑改为按车船类型严格匹配:车辆只允许填类型,船舶只允许填事项,误填对侧字段直接报错而非静默丢弃
- 将清空对侧字段的时机从 prepare 移到 validate 之后,避免用户误填内容被静默丢弃
- 提取 CAR/SHIP 常量,替换散落的"车辆"/"船舶"字面量
|
2026-09-20 17:51:29 +08:00 |
|
weicw-dshsa
|
9668f6059a
|
🐛 修复导出文件创建时间与更新时间列为空的问题
- 导出模型的 createTime/updateTime 由 LocalDateTime 改为 java.util.Date,与 BaseEntity 审计字段类型保持一致,避免 BeanUtil.copyProperties 因类型不兼容而静默跳过
- 覆盖车/船务管理 12 个页面导出模型及基础数据等 11 个导出模型,并为新增 Date 字段补齐 @DateTimeFormat("yyyy-MM-dd HH:mm:ss")
- 运单导入显式清空审计时间,避免把导入文件中的创建/更新时间带入实体
|
2026-09-20 16:32:31 +08:00 |
|
weicw-dshsa
|
cc33bc5ef2
|
🐛 修复港口码头批量导入的一二级顺序与全量回滚问题
对应 BUG.xlsx 序号 1 与序号 2。
序号 1(同表混装一二级数据):
- 改为两阶段导入,先落库港口(一级)再落库码头(二级),
消除对 Excel 行序的依赖;码头优先引用本批次新增的港口
序号 2(全失败即整批回滚):
- 逐行收集错误,只要有一行失败就抛异常触发整批回滚,不再部分成功
- 失败明细按【原表全部行】返回,未出错的行不标注,用户只需改错行
附带修复:
- 父港口找不到时改抛专用 ParentPortNotFoundException:
上级港口声明在本文件里、但那一行自身校验失败时,不再连带给码头行报错,
避免用户看到"两行都错"的假象;父港口确实漏填时仍照常报错
- 批内重复编码在落库前预检并定位到行,两行都标注原因
- 父港口区域信息为空(历史数据)时保留码头自身填写的值,
此前会被覆盖成空值导致码头无法导入
|
2026-09-20 06:27:33 +08:00 |
|