Commit Graph

268 Commits

Author SHA1 Message Date
b2894lxlx 42ca5ee7bc Merge remote-tracking branch 'websoft/dev'
# Conflicts:
#	blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/DriverWaybillServiceImpl.java
2026-10-12 10:39:38 +08:00
b2894lxlx a2e9e020b1 mk调试 2026-10-11 23:55:02 +08:00
b2894lxlx 68fede2caf 🐛 完善港口码头/铁路导入失败原因与软删除恢复,并修复运单导入列表筛选
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-10 16:20:21 +08:00
b2894lxlx 4e7193893f ✨ 组织与人员支持OA增量同步,并完善用户启停与性别空值
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-10 13:56:29 +08:00
weicw-dshsa 4fe0c8a968 ✨ 调度首页把司机已拒单的运单列为重新派单待处理,并在司机端让该运单脱离 2026-10-10 01:48:49 +08:00
b2894lxlx e20afc0d55 ✨ 合同结算币种贯通应收应付与结算,并完善合同编号与字段
合同结算币种写入应收应付与预结算;总单运费默认币种统一为 RMB;同步合同申请日期、主要内容、部门合同编号前缀及用印材料字典等能力。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-10 00:53:17 +08:00
weicw-dshsa b66984d3a1 ✨ 认证审核详情下发审核人与审核时间 2026-10-09 20:47:22 +08:00
weicw-dshsa 143c6f99fb 🐛 修复司机端档案按脱敏手机号匹配导致本人档案查不到 2026-10-09 20:13:38 +08:00
b2894lxlx ef9eab737f ✨ 优化主数据校验与运单导入空值处理
电报略码改为选填且填写时唯一;用户支持账号姓名手机模糊查询;合同名称允许重复;项目情况说明扩至1000字;导入运单未填里程费用不再落库-1。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-09 17:07:56 +08:00
b2894lxlx 5ed2a5c0fc ✨ 新增小程序司机端运单行驶轨迹接口
按打卡记录/计划时间自动推导起止日期后查询 LBS 轨迹。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-08 23:27:35 +08:00
b2894lxlx d5c6d10352 ⚡ 小程序司机端运单改为按手机号匹配,取消车牌过滤
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-08 19:37:26 +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 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 1038063231 ♻️ 上报门禁的节点编码比较忽略首尾空白,移除失去调用点的判据方法 2026-10-07 13:33:07 +08:00
weicw-dshsa 3d3ed0ca27 ♻️ 收紧上报门禁查询、去掉平行列表接口并统一节点编码比较 2026-10-07 13:24:02 +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 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
b2894lxlx 7e9caf5045 🐛 兼容列表查询传入逗号分隔的组织ID
用户绑定多个组织时 deptId 为逗号拼接字符串,绑定为 Long 会失败,现取第一个有效 ID。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-04 20:48:03 +08:00
b2894lxlx 683351d764 ✨ 放开组织类型层级约束,并修复调度数量单位回填
组织树不再按类型约束上下级;计量维度扩展整车/里程/吨·公里;运单从货物明细补齐数量单位,用户查询支持模糊匹配。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-04 20:26:16 +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