比较提交

...
492 次代码提交
作者 SHA1 备注 提交日期
lc 36a85b8669 docs(changelog): 交付供应商暂停与拉黑接口(#6392)
changelog-filename-gate / validate (pull_request) Successful in 2s
2026-08-26 15:45:16 +08:00
lc 43b9c16a36 Merge pull request 'docs(changelog): 交付行政区划 ID 字符串契约(#6409)' (#75) from chore/6409-api-changelog into main
changelog-filename-gate / validate (push) Successful in 2s
2026-08-26 15:30:01 +08:00
lc fd76eea701 docs(changelog): 交付行政区划 ID 字符串契约(#6409)
changelog-filename-gate / validate (pull_request) Successful in 2s
2026-08-26 15:29:26 +08:00
Mimingguang 49f67134fd chore(changelog): #6406 管理端 verified (ref=080ea8df)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-26 15:24:50 +08:00
API Changelog Bot 314c228654 feat: 开票申请按税号自动回填企业工商信息(#6406 / PR #6415)
changelog-filename-gate / validate (push) Successful in 2s
新增 GET /v3/admin/invoice/company-info?taxNo=,按税号返回元典工商照面 +
本系统历史开票抬头两段数据,后端不合并由前端取舍;已合并 dev-v3 并部署测试服,
网关 API 实测 companyInfo / lastInvoiceTitle 往返一致,非法税号返回 581526。
2026-08-26 15:08:20 +08:00
Mimingguang 3e8ea93caf chore(changelog): #6391 管理端 verified (ref=74b3d8bf)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-26 14:53:22 +08:00
Mimingguang 33c0aa2c08 chore(changelog): #6343 管理端 verified (ref=d84c6c25)
changelog-filename-gate / validate (push) Failing after 1s
2026-08-26 14:16:40 +08:00
lc 6831ec3128 docs: 交付供应商法人证件接口(#6391)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-26 11:57:09 +08:00
Mimingguang 42a16b78c6 chore(changelog): #6397 管理端 verified (ref=f2a4200d)
changelog-filename-gate / validate (push) Failing after 1s
2026-08-26 11:49:48 +08:00
lc 257ecb1233 fix(changelog): 对齐 #6343 前端状态元数据
changelog-filename-gate / validate (push) Successful in 2s
2026-08-26 11:32:39 +08:00
lc e9b52319c9 docs(changelog): #6343 供应商类型可为空
changelog-filename-gate / validate (push) Failing after 2s
2026-08-26 11:30:55 +08:00
lc 4060c65261 docs: 交接供应商注册合同接口(#6397)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-26 11:13:31 +08:00
Mimingguang 0fcf0801cf chore(changelog): #6304 管理端 verified (ref=25fb4b27)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-25 17:04:58 +08:00
lc e1b0a667cd docs(api): 发布供应商资质有效期契约
changelog-filename-gate / validate (push) Successful in 2s
changelog-filename-gate / validate (pull_request) Successful in 2s
2026-08-25 16:23:36 +08:00
Mimingguang c3acb6e822 chore(changelog): #6316 供应商详情新增资源信息分页前端已验证(ref=de665364)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-25 14:48:12 +08:00
Mimingguang 8bdd0d9057 chore(changelog): #6312 供应商敏感字段与数值格式校验收紧前端已验证(ref=187b7c3b)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-25 14:27:33 +08:00
lc 1eafac1a59 docs(supplier): publish resource info page API for #6316
changelog-filename-gate / validate (push) Successful in 2s
2026-08-25 13:10:51 +08:00
lc ded9289d98 供应商敏感字段校验收紧交付(#6312)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-25 12:39:57 +08:00
Mimingguang 119c459808 docs(changelog): #6317 供应商详情中文名与资质状态前端 verified(ref=33fe59ac)
changelog-filename-gate / validate (push) Failing after 1s
2026-08-25 12:24:18 +08:00
lc 06fa788882 供应商详情展示字段交付(#6317)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-25 12:12:53 +08:00
Mimingguang a74320185f docs(changelog): #6313 景区供应商全称列前端 verified(ref=3c0edfd7)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-25 11:26:24 +08:00
lc e2b36e1b60 docs(changelog): #6313 景区列表增加供应商全称
changelog-filename-gate / validate (push) Successful in 3s
2026-08-25 11:20:23 +08:00
Mimingguang 3ae7d06158 chore(changelog): #6275 联系人角色字典与默认规则前端 verified(ref=f8a0d72d)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-24 22:49:05 +08:00
lc 0c3b9056e6 文档:下发供应商联系人默认与角色字典契约(#6275)
changelog-filename-gate / validate (push) Successful in 3s
2026-08-24 22:37:31 +08:00
Mimingguang 6b3d84ba7b chore(changelog): #6273 供应商审批编号列前端 verified(ref=a46da334)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-24 21:25:43 +08:00
lc 491adfc28e Merge pull request 'docs(changelog): 记录 #6273 供应商审批编号扩展' (#73) from changelog/6273-supplier-approval-record-display into main
changelog-filename-gate / validate (push) Successful in 1s
Reviewed-on: #73
2026-08-24 21:20:24 +08:00
lc 2cbdcfb13a docs(changelog): 记录 #6273 审批编号扩展
changelog-filename-gate / validate (pull_request) Successful in 3s
2026-08-24 21:18:26 +08:00
Mimingguang 2481ff8f5a chore(changelog): #6266 供应商审批记录展示字段前端 verified(ref=cd7fd4c4)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-24 18:35:27 +08:00
lc c591d15518 docs: 下发供应商审批记录展示契约(#6266)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-24 18:29:11 +08:00
Mimingguang c52cc720e8 chore(changelog): #6265 供应商移除审批/提交备注前端 verified(ref=757c2f52)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-24 18:03:03 +08:00
Mimingguang 944c79f51a chore(changelog): #6258 供应商联系人默认标识前端 verified(ref=36d66367)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-24 17:52:43 +08:00
lc f4b6d94611 docs(changelog): 记录供应商备注字段契约变更
changelog-filename-gate / validate (push) Successful in 2s
2026-08-24 17:46:33 +08:00
lc 6d59634818 docs(changelog): 记录供应商默认联系人字段
changelog-filename-gate / validate (push) Successful in 2s
2026-08-24 17:41:14 +08:00
Mimingguang 2333614961 chore(changelog): #6241/#6257 供应商契约变更前端 verified(ref=a3ef713b)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-24 16:56:11 +08:00
lc 97a52f3d71 docs(changelog): 记录供应商初始账户上限变更
changelog-filename-gate / validate (push) Successful in 2s
2026-08-24 16:30:31 +08:00
lc 97ca1fd45d docs(changelog): 记录供应商资质校验变更
changelog-filename-gate / validate (push) Successful in 2s
Refs wx/HL#6241
2026-08-24 15:35:34 +08:00
Mimingguang 22db05c349 chore(changelog): 标记 #6204 司机档案资产装备字段前端已 verified(ref be171bf7)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-24 09:35:24 +08:00
API Changelog Bot和Claude 89a08e4e50 changelog(mp): AI推荐产品多维筛选开放接口 (#6207)
changelog-filename-gate / validate (push) Successful in 2s
新增 GET /mp/product/ai-recommend 免登录开放接口,供 AI 推荐
调用。支持多维筛选(关键词/目的地/天数/季节/标签/报价/出发
日期/人数/资源类型等),排除私人定制 CUSTOM。

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-23 13:48:45 +00:00
API Changelog Bot 6657de1404 docs(changelog): #6204 司机档案新增设备与车上装备字段
changelog-filename-gate / validate (push) Successful in 2s
2026-08-23 10:21:59 +00:00
Mimingguang 4484d924e6 chore(changelog): 标记 #6153/#6195 供应商模块前端已 verified(ref 9e1aba14)
changelog-filename-gate / validate (push) Failing after 3s
2026-08-23 18:20:15 +08:00
API Changelog Bot 4759d2302a 重写 #6210 前端缺陷条目对齐模板:补头信息块/接口清单/契约对照/验证证据/联系人,剔除后端实现细节,frontmatter 回正 not_required(保留前端 verified 状态)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-23 17:21:24 +08:00
lc 8f45e333f4 docs(supplier): align frontend changelog with template
changelog-filename-gate / validate (push) Successful in 3s
2026-08-23 17:14:43 +08:00
Mimingguang 0cedc09d76 chore(changelog): 标记 #6210 客户自订回显前端 verified(ref=97baecb6)
changelog-filename-gate / validate (push) Failing after 1s
2026-08-23 17:01:32 +08:00
lc e6e352e92f docs(supplier): publish frontend integration API pack
changelog-filename-gate / validate (push) Successful in 2s
2026-08-23 16:32:46 +08:00
API Changelog Bot ab46f0d0d5 docs(changelog): #6210 调整订单弹窗客户自订未回显重交丢失——前端缺陷交接(DB+网关实证,后端契约完整)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-23 16:28:16 +08:00
Mimingguang 91fe677e90 chore(changelog): 标记 #6152 异常桶前端 verified(ref=36261d83)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-23 15:58:05 +08:00
lc 1c5badc7b4 docs(changelog): 发布供应商注册与账户接口说明
changelog-filename-gate / validate (push) Successful in 2s
2026-08-23 15:04:51 +08:00
lc 3f10b2478e docs(changelog): 发布供应商资源关系接口说明
changelog-filename-gate / validate (push) Successful in 1s
Refs #6195

Refs #6197

Refs #6200
2026-08-23 14:02:20 +08:00
lc d58a2baca5 docs(changelog): 发布供应商归档失败关闭说明
changelog-filename-gate / validate (push) Successful in 2s
Refs #6174
2026-08-23 13:57:49 +08:00
lc cda1516aee 供应商接口接入网关与权限矩阵(#6191)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-23 10:27:35 +08:00
wx da7f0d888a docs(changelog): #6152 补各接口请求/响应 JSON 示例(网关实测片段,前端可照 Mock)
changelog-filename-gate / validate (push) Successful in 1s
2026-08-22 09:48:55 +00:00
wx df55131c3f docs(changelog): #6152 补正文头部信息块(PR/服务/作者/更新时间,对齐 6117 完整模板)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-22 09:39:55 +00:00
wx 13a48155d0 docs: 车务派单异常桶+处置完成写口+详情已取消行字段+异常留痕 changelog (#6152)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-22 09:10:44 +00:00
Mimingguang 937d06002f docs(changelog): #6155 前端 verified(mmg, ref 8569529c)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-22 16:32:57 +08:00
API Changelog Bot和Claude acf586b8f3 docs(changelog): #6155 补全出行信息身份证国籍/民族自动兜底(非身份证需前端补输入框)
changelog-filename-gate / validate (push) Successful in 2s
Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-22 07:35:54 +00:00
yaosutu 3c0a8ce1a7 docs(changelog): 导游/摄影核单确认状态去签名重置-修改接口-管理后台 (#6168)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-22 15:28:41 +08:00
Mimingguang ca44f7dbc2 docs(changelog): #6152 前端 verified(mmg, ref 9871cbb1)
changelog-filename-gate / validate (push) Failing after 1s
2026-08-22 11:17:55 +08:00
API Changelog Bot d64fb9b8f0 docs(changelog): 行级释放占用对已取消全程槽行误拦截-前端缺陷告知(根治 #6152)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-22 10:31:43 +08:00
API Changelog Bot d0b68d526e docs(changelog): #6140 房务操作日志补「订单异常」留痕 + CLOSE 类型徽标中文化
changelog-filename-gate / validate (push) Successful in 2s
2026-08-22 09:40:01 +08:00
Mimingguang d16f03e052 docs(changelog): #6125 前端 verified(mmg, ref 8a2c26af)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-21 17:16:21 +08:00
API Changelog Bot e2bf0b7dde docs(changelog): #6125 房务工作台详情透出终止未用标记+异常原因(前端待渲染 ItineraryPanel)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-21 15:43:15 +08:00
Mimingguang 163ba33516 docs(changelog): #6112 前端 verified(mmg, ref d58ad932)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-21 12:54:30 +08:00
API Changelog Bot 32bc988a8a docs(changelog): #6112 看板详情透出终止行程取消原因(前端待渲染 canceled 行 cancelReason)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-21 12:42:38 +08:00
Mimingguang d2eb4cb817 docs(changelog): #6117 前端 verified(mmg, ref ec7f2a9a)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-21 12:00:11 +08:00
Mimingguang a3eee13f65 docs(changelog): #6111 渲染子项前端 verified(配房行程未用标记+释放)
changelog-filename-gate / validate (push) Failing after 1s
订单详情配房行程页 EXCEPTION 单补三处渲染:异常原因文案、未用房晚「未用」标记、
行级「资源释放」按钮(DELETE assignment 软删+恢复库存);正常单零变化。
frontend_ref=9172700f。
2026-08-21 11:35:43 +08:00
yaosutu b7357dbfb7 docs(changelog): 导游/摄影核单去EXCLUDED改全量替换,确认状态统一settlementConfirmStatus(#6117 / PR #6119)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-21 11:28:19 +08:00
API Changelog Bot e56d1c6fd8 docs(changelog): #6111 前端待渲染-配房行程未用房晚标记+异常原因+行级释放按钮
changelog-filename-gate / validate (push) Successful in 2s
后端 #6116 已上线 TEST(订单 26-9250 网关实测字段已返回)。
本条前端向告知:配房行程页补渲染未用房晚标记/异常原因/行级释放按钮,
字段已具备(exceptionReason(Label)、assignments[].unusedForTerminate/unusedLabel),
行级释放复用 DELETE /v3/admin/order/assignments/{id}。frontend_status=pending, owner=mmg。
2026-08-21 02:33:40 +00:00
Mimingguang 46079e505c docs(changelog): #6114 前端 verified(快照回显+行级释放)
changelog-filename-gate / validate (push) Failing after 3s
车务看板已取消派单行回显 cancelled* 派车快照,行内加行级「释放占用」入口按该行
serviceDates 释放;与 #6107 整单级入口并存。frontend_ref=0d3cdf64。
2026-08-21 09:31:25 +08:00
API Changelog Bot 188426d9d0 docs(changelog): 已取消派单显示派车快照+按未用天行级释放(#6114)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-20 10:17:41 +00:00
API Changelog Bot和Claude 9b09336538 docs(house): 配房行程标记终止未用房晚+异常原因透传(#6111 后端能力)
changelog-filename-gate / validate (push) Successful in 2s
Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-20 10:09:34 +00:00
Mimingguang afef353fc2 docs(changelog): #6111 前端 verified(异常单禁最终确认/清空配房)
changelog-filename-gate / validate (push) Failing after 2s
房务订单详情弹窗 EXCEPTION 单禁用「最终确认/清空配房」(置灰+tooltip),「标记完成」
按勘误保留可点(#4307 异常收尾出口零改动)。frontend_ref=a586343b。
2026-08-20 16:59:24 +08:00
API Changelog Bot 42d0d0eec0 docs(house): 勘误-终止订单仅禁用最终确认/清空配房,标记完成保留(#4307 异常收尾出口)
changelog-filename-gate / validate (push) Successful in 3s
2026-08-20 08:15:47 +00:00
API Changelog Bot 0c62e86ced docs(house): 终止行程订单配房三按钮禁用(#6111 子项,纯前端渲染逻辑告知)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-20 07:59:38 +00:00
Mimingguang 71aa64896e docs(changelog): #6107 前端 verified(释放占用入口已接入)
changelog-filename-gate / validate (push) Failing after 2s
车务看板订单详情抽屉车辆执行段新增整单级「释放车辆/司机占用」按钮,调
clear-cancelled-occupancy 一键清已取消派单脏占用;与逐日软清 #5936 语义不同不混用。
frontend_ref=2ebfddc7。
2026-08-20 15:15:31 +08:00
API Changelog Bot 8f5ecc3b6f docs(fleet): 6107 changelog 补网关实测证据(clear-cancelled 幂等空集 200)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-20 06:41:03 +00:00
API Changelog Bot f6a6aa67ca docs(fleet): 6107 告知 clear-cancelled-occupancy 端点(终止行程后已取消派单释放车/司机占用入口)
changelog-filename-gate / validate (push) Successful in 2s
端点 #5921 已交付部署但当初漏发 changelog,前端不知其存在导致看板详情缺释放按钮。
本次纯告知取值+UI挂载点,后端无代码变更。
2026-08-20 06:34:25 +00:00
Mimingguang 5056ed423a docs(changelog): #6077 二次告知前端 verified(操作人字段已展示)
changelog-filename-gate / validate (push) Failing after 2s
订单详情客户信息卡新增展示最后操作房务/车务(v3Adapter 投影 overview.
customerInfo.houseOperatorName/vehicleOperatorName);住宿每晚 stayDate 前端早已
展示(RoomArrangeCard),零改动。frontend_ref=a684caf2。
2026-08-20 09:50:37 +08:00
API Changelog Bot 996fcf0105 docs(changelog): 二次告知前端-订单详情最后操作人(6077)+住宿每晚stayDate已返回
changelog-filename-gate / validate (push) Successful in 1s
2026-08-20 01:34:13 +00:00
Mimingguang 6e3ed604fb docs(changelog): #6079 前端 verified(releaseLines 双通道已交付)
changelog-filename-gate / validate (push) Failing after 1s
前端在终止行程弹窗提交体新增 releaseLines(与 lineUsages 独立双通道),
车辆未用行只进 releaseLines 驱动 fleet 截断、房未用行双进;空则不带键
走兼容路径。frontend_ref=7ce54680。
2026-08-19 17:02:52 +08:00
API Changelog Bot和Claude cdffec0f00 docs(changelog): #6079 终止行程按勾选未用行释放房车资源(releaseLines 双通道解耦)
changelog-filename-gate / validate (push) Successful in 1s
Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-19 08:42:20 +00:00
API Changelog Bot 020076ec47 Merge branch 'main' of https://git.1814.love:8443/wx/hl-api-changelog
changelog-filename-gate / validate (push) Successful in 2s
2026-08-19 07:53:16 +00:00
API Changelog Bot 5dd236bf43 docs(guide): 明确 not_required 条目禁回写 frontend_owner/verified_at(#6077 实例) 2026-08-19 07:52:58 +00:00
API Changelog Bot 5ba2fc6082 docs(changelog): #6077 响应示例 + 修 frontmatter 门禁(not_required 清空 frontend_owner/verified_at) 2026-08-19 07:52:15 +00:00
API Changelog Bot 54f234fd0f docs(changelog): #6077 not_required 清空残留 frontend_owner/verified_at(门禁E_FRONTEND)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-19 07:48:59 +00:00
API Changelog Bot 790fb18ea1 docs(changelog): #6077 补「响应示例」一节(真实网关响应节选)
顶层 4 字段当前实现为 null,以 overview.customerInfo 内同名字段为准;
附已配房未派车实测示例。
2026-08-19 07:48:06 +00:00
Mimingguang c0019c8eba docs(changelogs-v2): #6077 回写 not_required(frontend_owner=mmg)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-19 15:41:19 +08:00
API Changelog Bot ebbd8ad6a3 docs(changelog): #6077 订单详情新增最后操作房务/车务人员 4 个可选字段(PR #6080)
changelog-filename-gate / validate (push) Successful in 2s
GET /v3/admin/order/{id} 响应顶层及 overview.customerInfo 新增
houseOperatorId/houseOperatorName/vehicleOperatorId/vehicleOperatorName,
无操作/无对应需求时为 null,前端无必须动作。
2026-08-19 07:30:14 +00:00
Mimingguang 7e1e6657ec docs(changelogs-v2): #6052/#6057 回写 not_required(frontend_owner=mmg)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-19 09:14:18 +08:00
Mimingguang 012e2e2a9a docs(changelogs-v2): #6045 回写 verified(frontend_ref=e94c0333)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-19 09:07:25 +08:00
API Changelog Bot 9d7a1663e2 chore(6057): 多槽位越需求索引派车业务码 605911/605912 替代 500(已部署实测)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-19 01:33:38 +08:00
API Changelog Bot 2ee06034ef docs(changelog): #6052 新增 + #6022 补 target_release(解门禁)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-18 21:20:01 +08:00
API Changelog Bot 4130f26911 docs(changelog): 整程行改期换版stale详情回拨成待派车(#6052 / PR #6053) 2026-08-18 21:17:50 +08:00
API Changelog Bot 1cf12fc336 docs(changelog): #6045 status_note去重+补关联联系人段 2026-08-18 21:17:46 +08:00
API Changelog Bot 1028ae4da5 docs(changelog): #6022 响应示例去后端类名SnapshotCellVO,改字段名说明(前端视角) 2026-08-18 21:17:46 +08:00
API Changelog Bot 6b26d283c9 docs(changelog): #6045 确认执行页行程短信按槽位独立选择契约交接(前端契约 pending)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-18 18:31:17 +08:00
Mimingguang 7075d4362d docs(changelogs-v2): #6033 回写 verified(frontend_ref=9bd9e23b)
changelog-filename-gate / validate (push) Failing after 1s
2026-08-18 17:06:38 +08:00
Mimingguang ce2e35ea07 docs(changelogs-v2): #6022 回写 verified(frontend_ref=c157cde4) 2026-08-18 17:01:47 +08:00
API Changelog Bot d22d6ea2a7 docs(changelog): 4篇负责人改wx+6014/6016改pending+补关联联系人段
changelog-filename-gate / validate (push) Successful in 1s
2026-08-18 16:58:11 +08:00
API Changelog Bot e1b4f9ebbe docs(changelog): #6014/#6016/#6022/#6033 补「关联/联系人」段(Issue/PR/Commit链接+后端负责人) 2026-08-18 16:55:38 +08:00
API Changelog Bot 82af878a37 docs(changelog): 住宿安排回配回显+加急显隐契约 canUrge(#6033 / PR #6036)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-18 16:40:32 +08:00
API Changelog Bot 5c84441822 docs(changelog): #6022 frontmatter 改回 pending(有前端动作),补响应示例
changelog-filename-gate / validate (push) Successful in 2s
2026-08-18 16:27:48 +08:00
API Changelog Bot 9b90e2dab2 docs(changelog): #6022 补逐日车费响应示例(SnapshotCellVO 字段+JSON 样例) 2026-08-18 16:25:47 +08:00
Mimingguang d7c80b13ed docs(changelogs-v2): #6022 not_required(车费合计/状态派生后端口径,前端零改动)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-18 16:11:40 +08:00
API Changelog Bot c44af6b3f8 docs(changelog): 一键清空需求回待派车+逐日车费按天拆分(#6022 / PR #6029)
changelog-filename-gate / validate (push) Successful in 1s
2026-08-18 15:47:59 +08:00
Mimingguang 7a28cc5a98 docs(changelogs-v2): #6016 not_required(房务异常桶/REFUND待办后端驱动,前端零改动)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-18 14:16:07 +08:00
Mimingguang fda17dc2be docs(changelogs-v2): #6014 not_required(前端无豁免镜像,状态纯读后端)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-18 14:13:43 +08:00
API Changelog Bot 776045488b docs(changelog): 终止行程房侧资源释放标记(#6016 / PR #6020)
changelog-filename-gate / validate (push) Successful in 1s
2026-08-18 12:26:22 +08:00
API Changelog Bot 8dd344fec5 docs(changelog): 改期换版纯改期残留回拨成待派车(#6014 / PR #6017)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-18 11:37:20 +08:00
Mimingguang fee4dcac7b docs(changelogs-v2): 回写 #5923/#5931/#5934 not_required + #5928/#5828/#5936 verified
changelog-filename-gate / validate (push) Failing after 1s
2026-08-16 15:30:05 +08:00
API Changelog Bot 046f8bed2c docs(changelog): #5828 已取消卡片不显示旧车司机+下线换车请求tab(PR#5938)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-16 01:02:44 +08:00
API Changelog Bot 68ae0e1c63 chore: index 移除误暂存的他人文件(5888/前端确认页),保留磁盘待其属主处理
changelog-filename-gate / validate (push) Successful in 2s
2026-08-16 00:49:49 +08:00
API Changelog Bot 0d84396a56 fix: changelog 文件名日期前缀对齐推送日 16(5934/5936) 2026-08-16 00:49:29 +08:00
API Changelog Bot ba993200c5 docs(changelog): #5931 看板矩阵Map跨层清理(fleetCount下线) + #5935 按日期清改期残留(新端点) 2026-08-16 00:47:42 +08:00
API Changelog Bot ffa788058b fix: #5934 补标准接口章节标题 2026-08-15 23:55:54 +08:00
API Changelog Bot a890c12997 chore: 移出误纳的前端暂存文件(仅提交5934/5936) 2026-08-15 23:55:12 +08:00
API Changelog Bot 4c683d0358 chore: 移出误纳的他人暂存文件 5888(仅提交本批5934/5936) 2026-08-15 23:54:42 +08:00
API Changelog Bot fa26d0a1ec fix: #5934 change_type 改为合法枚举 修改接口 2026-08-15 23:53:38 +08:00
API Changelog Bot 7dd6635195 docs(changelog): #5936 排车软清司机车辆(新端点) + #5934 车务契约漂移补录 2026-08-15 23:52:40 +08:00
API Changelog Bot a98151dc0a docs(changelog): #5928 保单分页POST契约 + #5923 已取消tab只收订单真取消
changelog-filename-gate / validate (push) Successful in 1s
2026-08-15 21:33:15 +08:00
Mimingguang 5f6d86ea19 docs(changelogs-v2): #5969 not_required(生产零改动,测试口径跟随固证)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-15 16:09:14 +08:00
yaosutu dd56a2b0e5 docs(changelog): 核单车辆费用归其他支出(#5969 / PR #5970)
changelog-filename-gate / validate (push) Successful in 2s
单团核算表 vehicleLines 行删 4 字段,5 类车辆费用行迁到 otherExpenseLines,
expenseType 值域扩为 6 类;管理后台端 changelog。
2026-08-15 14:24:50 +08:00
Mimingguang 8e1485fc32 docs(changelogs-v2): #5963 verified(前端单团核算表拍平适配)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-15 09:31:16 +08:00
yaosutu 34e50005f9 docs(changelog): 单团核算表出参重构——收入拍平逐项+成本7分类明细数组+保险独立子块(#5963)
changelog-filename-gate / validate (push) Successful in 2s
- 删 perCapita 人均三指标 + hotelCost 等 7 个成本分类小计 + costCategories 套层 + incomeLines[].details 嵌套
- incomeLines 拍平逐项行(4 type 各至少一行,无明细给占位行 amount=聚合值)
- 成本改 hotelLines 等 7 分类明细数组平铺顶层,空分类 []
- 新增 insuranceInfo 保险子块;insurancePremium 顶层保留且计入 totalCost
- PR #5966 已合并 dev-v3(c8cae25131),测试服部署 + 网关实调验证通过
2026-08-14 17:45:57 +08:00
Mimingguang 84c22ea77a docs(changelogs-v2): #5955 verified(前端 9 卡尾款三口径适配)
changelog-filename-gate / validate (push) Failing after 1s
2026-08-14 14:27:46 +08:00
yaosutu 983c274860 docs(changelog): 主报账表baseInfo尾款口径三新字段透出+outstandingAmount下线(#5955 / PR #5958)管理后台
changelog-filename-gate / validate (push) Successful in 2s
2026-08-14 11:01:58 +08:00
Mimingguang 094146d793 docs(changelogs-v2): #5953 not_required(零生产代码,测试固证)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-13 15:12:26 +08:00
yaosutu 0a689d93c5 docs(changelog): 主报账表展示其他收入/其他支出明细(不影响报账人净额)(#5953 / PR #5954)管理后台
changelog-filename-gate / validate (push) Successful in 1s
2026-08-13 14:32:18 +08:00
Mimingguang 17bc59e6d8 docs(changelogs-v2): #5937/#5933 verified,#5929/#5932/#5927 not_required
changelog-filename-gate / validate (push) Failing after 2s
2026-08-13 09:32:09 +08:00
API Changelog Bot 0a1b497397 docs: 补齐#5932变更接口清单
changelog-filename-gate / validate (push) Successful in 3s
2026-08-13 03:03:04 +08:00
API Changelog Bot 5b2de4a2a0 docs: 发布#5932车务错误码契约 2026-08-13 03:02:38 +08:00
API Changelog Bot f5cf9b2f53 docs: 补齐#5929空筛选终审证据
changelog-filename-gate / validate (push) Successful in 2s
2026-08-13 02:33:57 +08:00
API Changelog Bot 03d38eca14 docs: 补充#5929纯费用车队补救证据
changelog-filename-gate / validate (push) Successful in 2s
2026-08-13 01:16:17 +08:00
API Changelog Bot和Claude Opus 4.8 747510fe08 docs(fleet): 发布#5929对账聚合契约
changelog-filename-gate / validate (push) Successful in 2s
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-13 00:38:29 +08:00
API Changelog Bot和Claude Opus 4.8 a2626f6590 docs(fleet): 发布#5927幂等契约变更
changelog-filename-gate / validate (push) Successful in 2s
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-12 23:47:45 +08:00
API Changelog Bot和Claude Opus 4.8 ae331af398 fix(docs): 补齐#5926前端发布版本
changelog-filename-gate / validate (push) Successful in 2s
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-12 22:57:36 +08:00
API Changelog Bot和Claude Opus 4.8 621ec3c9f1 fix(docs): 补齐#5933部署验证元数据
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-12 22:55:48 +08:00
API Changelog Bot 70fefbcf45 docs(changelog): #5926 废弃整槽取消指引,逐日残留取消统一指向#5937 2026-08-12 22:53:44 +08:00
API Changelog Bot和Claude Opus 4.8 257b72ff59 docs(fleet): 标记#5933测试服契约已验证
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-12 22:52:57 +08:00
API Changelog Bot 36d2f83ead docs(changelog): #5937 补标准接口清单与验证证据章节
changelog-filename-gate / validate (push) Successful in 2s
2026-08-12 22:51:38 +08:00
API Changelog Bot b4c44254d3 docs(changelog): #5937 取消改期残留派车切换逐日精确端点(PR #5939/#5941) 2026-08-12 22:51:38 +08:00
Mimingguang c2092c8932 docs(changelogs-v2): #5926 前端 verified
changelog-filename-gate / validate (push) Failing after 2s
排车栅格改期残留行明文回显 + 删除后重拉 candidates,frontend_ref=01ae772f
2026-08-12 20:30:36 +08:00
Mimingguang dfbd18506c docs(changelogs-v2): #5912/#5916/#5914 前端 verified,#5915 not_required
changelog-filename-gate / validate (push) Failing after 1s
#5912 改期残留三字段消费 frontend_ref=6c417cac
#5916 核单两报表瘦身 frontend_ref=ea2916fc
#5914 换版原因渲染 frontend_ref=a254f29f
#5915 删换车请求状态实证 not_required frontend_ref=58428593
2026-08-12 19:03:39 +08:00
API Changelog Bot e1e155577e docs(changelog): 确认执行页逐日车费仍只显示1天——0538f4b4未合入主分支/未发布(前端缺陷,后端已复核数据完整)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-12 18:57:46 +08:00
API Changelog Bot d461dbe895 docs(changelog): #5926 追加前端缺陷点2——取消/删除派车后须重拉candidates刷新栅格(26-3559实测:后端已生效取消,前端未刷新仍显示旧行)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-12 18:55:11 +08:00
API Changelog Bot 50b22e6b6b docs(changelog): #5926 排车Step2栅格改期残留旧实派行不回显明文(前端渲染,后端已补字段) (PR #5930)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-12 18:29:26 +08:00
API Changelog Bot 57bf865c3b docs(changelog): 看板删除换车请求状态(#5915 / PR #5925)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-12 17:55:45 +08:00
API Changelog Bot和Claude Opus 4.8 1083e3ba5e docs(changelog): #5914 看板详情新增换版原因reassignReasons 实测证据回填
changelog-filename-gate / validate (push) Successful in 2s
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-12 17:38:20 +08:00
yaosutu d98db3e76e docs(changelog): 核单两报表出参瘦身合并版(#5876 + #5916 / PR #5881 + #5920)管理后台
changelog-filename-gate / validate (push) Failing after 2s
orderHeader 拍平 + 审计字段下线 + outstandingAmount 替代 primaryReporterDueAmount
+ finalize warnings 结构化 + summary 新增 settled,以 #5916 合并后最终态为准
2026-08-12 17:11:30 +08:00
API Changelog Bot和Claude Opus 4.8 0d2122d4b6 docs(changelog): #5912 改期后旧实派车栅格不可见——栅格并入旧行日期+改期残留标记字段(PR #5918)
changelog-filename-gate / validate (push) Successful in 2s
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-12 16:56:29 +08:00
Mimingguang 0329ca28ac docs(changelogs-v2): 两条前端缺陷已修复交付
changelog-filename-gate / validate (push) Successful in 2s
①确认执行页逐日车费多车折叠:frontend_ref=0538f4b4。
②调整订单脱敏值误回传:frontend_ref=d4d25a1c。
均翻 implemented + 补前端修复说明。hl-admin v2.1 已 push。
2026-08-12 16:16:50 +08:00
API Changelog Bot 5c285a39c0 docs(changelog): 前端缺陷-调整订单弹窗手机号证件号脱敏值误回传(mmg)
changelog-filename-gate / validate (push) Successful in 1s
2026-08-12 15:22:53 +08:00
API Changelog Bot 950381cfcc docs(changelog): 前端缺陷-确认执行页逐日车费多车只显示一行(mmg)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-12 15:19:09 +08:00
Mimingguang 320e48ac61 docs(changelogs-v2): #5910 复核确认闭环修复前端 not_required
changelog-filename-gate / validate (push) Failing after 2s
纯后端复核闭环修复,无接口契约变化;前端 dispatchPlanGeneration 透传回 confirm、
staleFinalizedPlan/finalizedByFleet 系后端派生状态,零改动自动受益。
frontend_status 补 frontend_owner/ref=db1f3507 + 前端复核说明。
2026-08-12 14:41:12 +08:00
API Changelog Bot 0dfcfd1fc9 docs(changelog): 改订单人数复核确认无法闭环修复(#5910)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-12 14:35:34 +08:00
Mimingguang 56e89ee029 docs(changelogs-v2): #5849 派单 Step2 多日误拦前端根因条 not_required
changelog-filename-gate / validate (push) Failing after 2s
前端复核:changelog 所指 candidateServiceDate 仅单日根因属实,但致障链已被 08-11
候选证据门禁放宽盖过(validateDailyVehiclePlan 默认 requireCandidateEvidence=false,
三调用方均未开启),多日置灰不复现。frontend_status 翻 not_required,frontend_ref=0e5a0277。
2026-08-12 14:33:29 +08:00
Mimingguang 7c5eafada3 docs(changelogs-v2): #5870/5871 前端已接入交付
changelog-filename-gate / validate (push) Successful in 2s
frontend_status 翻 implemented,frontend_ref=b9b17dbf,补前端接入说明(slotDisplayNo
展示序号 + requirementMismatchMessage 候选文案)。hl-admin v2.1 已 push。
2026-08-12 14:14:54 +08:00
API Changelog Bot de40c74d73 changelogs-v2: 派单 Step2 下一步多日行程被误拦——前端缺陷根因与修复指引(#5849)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-12 13:39:55 +08:00
API Changelog Bot 1aeb52b8cd changelogs-v2: #5870/#5871 契约兑现——详情 slotDisplayNo + 候选 mismatch 原因(PR #5908/#5909)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-12 13:01:32 +08:00
Mimingguang 42184e66cb docs(changelogs-v2): 回写 #5895 看板代际筛选与槽位头字段前端 not_required
changelog-filename-gate / validate (push) Failing after 2s
BUG1 取值修复前端透传自动受益;BUG5 vehicleCategoryLabel 前端零消费,车型大类
已走 requiredVehicleTypeLabel 显示,接入新字段属可选卡头增强未做,实证 not_required。
2026-08-12 12:56:45 +08:00
API Changelog Bot b3c2f52ca7 docs(changelog): #5895 看板代际筛选放宽+槽位头车型大类字段(PR #5904)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-12 12:37:58 +08:00
Mimingguang 03f4599f91 docs(changelogs-v2): 回写 #5895 前端 not_required
changelog-filename-gate / validate (push) Failing after 2s
前端零消费 vehicleCategoryLabel/vehicleCategoryKey(排车页卡头字段,#5904 新增
尚未接入),后端别名取值修复对前端透明,实证 not_required。
2026-08-12 12:24:32 +08:00
API Changelog Bot d7d2083276 docs(changelog): #5895 排车页槽位卡头车型大类标签修复(PR #5907)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-12 12:18:32 +08:00
Mimingguang c8ec9e440b docs(changelogs-v2): 回写 #5827/#5876/#5899 前端消费结论
changelog-filename-gate / validate (push) Failing after 1s
- #5827 implemented (753503c8):向导 4 步改 3 步提交即派定,删 Step3DriverConfirm
  +useDispatchMessage,三写端点顶层 sendItinerarySms。
- #5876 implemented (1f716683):finalize 软预警改读 item.message,兼容过渡期字符串。
- #5899 not_required:纯后端状态机修复,前端只读字段不变自动受益。
2026-08-12 12:01:49 +08:00
API Changelog Bot和Claude Sonnet 4.6 e7410b4d95 chore: 5899 改订单人数后车务未重走配车——换版后自动重新盖章抵消作废定稿
changelog-filename-gate / validate (push) Successful in 2s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-08-12 11:56:41 +08:00
yaosutu d1e98fa028 docs(changelog): 核单 finalize warnings 结构化带行id + summary 新增 settled 标识(#5876 / PR #5881)管理后台
changelog-filename-gate / validate (push) Failing after 1s
2026-08-12 09:12:56 +08:00
Mimingguang 360d32fbea docs(changelogs-v2): 标记 #5838 用房每晚客户自订 implemented (f3b08c5d)
changelog-filename-gate / validate (push) Successful in 1s
2026-08-11 21:56:20 +08:00
Mimingguang c1e421867a docs(changelogs-v2): 标记 frontend 派单 Step2 置灰修复 implemented (bce7fbed)
changelog-filename-gate / validate (push) Successful in 1s
2026-08-11 21:28:38 +08:00
Mimingguang d50b369c8f docs(changelogs-v2): 标记 frontend 派单弹窗需求信息补全 implemented (a18e9db9)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-11 21:11:57 +08:00
Mimingguang 0266bd0c37 docs(changelog): 主报账人报账表出参重构统一字段(#5820/#5859)前端已实现 fd070dc2
changelog-filename-gate / validate (push) Failing after 2s
适配 4 项:adapter 改读 baseInfo、driver 汇总卡 6 字段改读 baseInfo+转账方向推导、
删 vehicleLines 项、补 date/reimburseAmount 字段翻译;group 分支零改动。
测试:ReportModal.spec 重构+1,returnDetailAdapter.spec +4,settlement 91+4 全绿。
2026-08-11 20:24:41 +08:00
API Changelog Bot 5644bbf4e0 docs(changelog): 派车取消司机确认环节一步到位派定(#5827 / PR #5873)——含测试服实测证据
changelog-filename-gate / validate (push) Successful in 2s
2026-08-11 19:31:49 +08:00
API Changelog Bot de43d84f12 changelog(#5838): 用房需求每晚客户自订标记
changelog-filename-gate / validate (push) Successful in 2s
2026-08-11 19:10:46 +08:00
API Changelog Bot 3da4d00882 docs(changelog): #5849 根因更正与详解——已定稿豁免绑死 readOnly 永不生效;判定式逐行代入真实数据;绕过手段实测无效
changelog-filename-gate / validate (push) Successful in 2s
2026-08-11 18:51:03 +08:00
lc a4fb47b2e3 补充派单操作日志快照契约(#5862)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-11 18:48:41 +08:00
API Changelog Bot 45ea603be0 docs(changelog): #5849 前端补完——两行最小改动、立即绕过办法、新增槽位 excludeAssignmentId 误传
changelog-filename-gate / validate (push) Successful in 2s
2026-08-11 18:37:55 +08:00
API Changelog Bot 738e239a07 docs(changelog): 补入 #5849 前端根因——候选证据戳对服务端回显日格恒 null(部署包已核实)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-11 18:32:18 +08:00
API Changelog Bot 2490021161 docs(changelog): 派单 Step2 下一步置灰——后端实测已排除,收敛到前端判定(#5849 前端部分)
changelog-filename-gate / validate (push) Successful in 1s
2026-08-11 18:28:25 +08:00
API Changelog Bot 84286cc925 docs(changelog): 派单弹窗需求信息两处各缺一半——后端字段已就绪转前端(原 #5848)
changelog-filename-gate / validate (push) Successful in 1s
2026-08-11 18:22:26 +08:00
yaosutu 627c4c8721 changelog(#5867): 出行人智能批量导入纳入"至少一名成人填手机号"硬校验(581136,PR #5868)
changelog-filename-gate / validate (push) Failing after 2s
补充 #5855 changelog:smart-parse(dryRun=false 正式落库)与 5 个保存入口复用同一
成人手机门禁;dryRun=true 预览不校验。部署测试服网关实调通过:无成人手机导入被
581136 阻断且 DB 零写入,含 1 成人手机导入 200 放行落库。
2026-08-11 18:15:46 +08:00
Mimingguang c2ec420f36 docs(changelog): 配房候选定制师主选/副选标识(#5846)前端已实现 8f33923a
changelog-filename-gate / validate (push) Successful in 1s
PickHotelModal 候选标签改按 consultantChoiceLabel 渲染(主选 warning/副选 default/非点名不显),
兼容期回退「定制师推荐」。测试:pick-hotel-modal.spec 3 用例全绿。
2026-08-11 18:06:39 +08:00
yaosutu d362c3acb1 docs(changelog): 主报账人报账表出参重构统一字段(#5820/#5859)管理后台
changelog-filename-gate / validate (push) Failing after 2s
破坏性变更通知:顶层平铺汇总字段收拢进 baseInfo、expenseLines 统一 12 扁平字段、
删除 vehicleLines 与 6 个冗余字段、orderHeader 补 returnDate/travelerCount。
对应后端 PR #5839 + #5865,前端必须同步改造。
2026-08-11 18:02:05 +08:00
Mimingguang 57c7dcd2aa docs(changelog): 出行人保存校验至少一成人填手机号(#5855)前端已实现 24f31813
changelog-filename-gate / validate (push) Failing after 2s
实证保存链路天然兼容(统一拦截器 toast),并按 §11 建议落地表单提交前提示增强:
无成人填手机号时 message.warning 提前提示、不阻断由后端 581136 兜底。
测试:TravelerInfoEditor spec +2,11 全绿。
2026-08-11 18:00:33 +08:00
API Changelog Bot 5236c14599 changelog(#5846): 配房候选定制师主选/副选标识
changelog-filename-gate / validate (push) Successful in 2s
2026-08-11 17:57:10 +08:00
Mimingguang 5fd8827cfe docs(changelog): 房务最终确认放开部分配房(#5842)前端已实现 ddb3b823
changelog-filename-gate / validate (push) Successful in 2s
adapter 透传 unarrangedDayNumbers/unconfirmedDayNumbers,新增纯函数分列拼接二次确认文案;
OrderDetailModal 最终确认两列表非空先弹二次确认、均空保持直接确认;日期错位仍后端硬拦。
测试:adapter spec +3 透传 +4 文案用例,housekeeper 44 全绿。
2026-08-11 17:56:07 +08:00
Mimingguang 738560e3af docs(changelog): 车务二轮审计整改契约增量(#5818b)前端已实现 a4174560
changelog-filename-gate / validate (push) Successful in 2s
前端落地实证出的 2 项:A1 保险任务状态下拉补 CANCELLED(已撤销,50 条已撤销任务恢复可见);
A2 派单进度步骤条补 SKIPPED 渲染(holdMode=DIRECT 直派跳确认,置灰已跳过+进度位计入)。
其余 A3/B1-B5/C 经 grep+源码实证 not_required 或后端修复前端自动受益。
测试:insurance spec +1 + order-drawer-progress spec 3 用例,fleet/board 431+insurance 14 全绿。
2026-08-11 17:41:58 +08:00
API Changelog Bot 05f0f548d2 docs(changelog): 车务派车候选接口显式返回 selectable(#5850 / PR #5861)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-11 17:41:24 +08:00
yaosutu 231f2e0411 changelog(#5855): 出行人保存新增"至少一名成人必须填手机号"服务端硬校验(PR #5858)
changelog-filename-gate / validate (push) Failing after 2s
涉及 PUT traveler-info / POST batch-edit / POST add 三个保存入口,
新增错误码 581136;validate 接口 blockReasons 文案同步收紧为"成人"。
入参/出参结构无变化,前端按 code!=200 toast 约定即可兼容。
2026-08-11 17:40:31 +08:00
yst f3712c9162 docs(changelog): 核单两报表订单头 backend_status 翻转 deployed(#5840 已部署测试服生效)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-11 17:39:37 +08:00
API Changelog Bot 1eaff7273f changelog(#5842): 房务最终确认放开部分配房 + 未配/未确认晚号字段
changelog-filename-gate / validate (push) Successful in 2s
2026-08-11 17:37:11 +08:00
API Changelog Bot 0ab42ab0d4 changelog(#5818): 第二轮审计整改契约增量——CANCELLED 可筛/SKIPPED 新取值/错误码纠偏/h5 附件白名单(PR #5864)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-11 17:26:33 +08:00
Mimingguang f407b0765b docs(changelog): 核单两报表加订单头orderHeader(#5840)前端实证 not_required
changelog-filename-gate / validate (push) Failing after 1s
前端实证 not_required:出参纯增量、向后兼容、前端非必须接入(§11.1)。
ReportModal 标题栏取核单详情页已加载主对象 order 的 teamNo/productName,
非为标题另发请求,无重复请求可清;报表数据当前零读取 orderHeader;
行为统一(去快照分叉)对前端透明。hl-admin 零代码改动。
2026-08-11 17:18:49 +08:00
yaosutu 690046d0b2 docs(changelog): 核单两报表统一实时路径+出参新增订单头orderHeader(#5840)管理后台
changelog-filename-gate / validate (push) Failing after 2s
- PR #5854 / Issue #5840 / merge commit 452ebd63
- GET /v3/admin/order/{orderId}/settlement/reports/group 出参加 orderHeader
- GET /v3/admin/order/{orderId}/settlement/reports/reimbursement 出参加 orderHeader
- 两报表去掉快照读分叉统一实时计算(对前端透明,reportStatus 取值不变)
2026-08-11 17:05:03 +08:00
Mimingguang 23dfa84f64 chore(changelog): #5810b 前端 not_required(实证零改动)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-11 16:58:06 +08:00
Mimingguang 4e381e13d0 chore(changelog): #5851 前端 not_required(实证零改动)
changelog-filename-gate / validate (push) Failing after 1s
2026-08-11 16:54:32 +08:00
Mimingguang c5996d43ce chore(changelog): 抢单前联系对方发不出消息 前端 implemented(9b824f5c)
changelog-filename-gate / validate (push) Successful in 3s
2026-08-11 16:51:26 +08:00
API Changelog Bot 5cedd5fb44 changelog(#5851 #5852 #5853): 换版即作废定稿 + 行程 day 端点下线——测试服实测通过(PR #5856 #5857)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-11 16:46:35 +08:00
Mimingguang 63fd34d7fd chore(changelog): #5824 前端 implemented(aa9c087b)
changelog-filename-gate / validate (push) Successful in 1s
2026-08-11 15:39:03 +08:00
Mimingguang 514a2e167a docs(changelog): #5818 车务审计整改前端 implemented(46a57557)
changelog-filename-gate / validate (push) Successful in 1s
2026-08-11 15:20:12 +08:00
API Changelog Bot 76c446312b changelog(#5824): 换版后看板缺口与订单车控修复——测试服实测通过(PR #5843)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-11 14:53:48 +08:00
API Changelog Bot 1c022e7943 changelog(frontend): 抢单前联系对方发不出消息(后端实测双视角均可发送)
changelog-filename-gate / validate (push) Successful in 1s
2026-08-11 14:44:56 +08:00
Mimingguang 02e8d75fd3 docs(changelog): #5830 房务订单详情 Tab 前端 implemented(dbec5600)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-11 14:42:05 +08:00
Mimingguang 698a64d1a1 chore(changelog): #5822 前端 implemented(408ffc63)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-11 14:15:20 +08:00
API Changelog Bot e4fe3ccbf1 changelog(#5818): 车务全量审计整改契约变化——保险错误码迁段/新增业务码/对账与看板响应变化(PR #5837)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-11 13:07:37 +08:00
API Changelog Bot baaf9a0e2e changelog(#5822 #5830): 车务槽位删除放开+逐日计划恒空修复 / 房务订单详情 Tab
changelog-filename-gate / validate (push) Successful in 2s
2026-08-11 12:16:49 +08:00
Mimingguang 3094d055b6 chore(changelog): #5816 前端 implemented(b22d6c14)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-11 12:12:14 +08:00
yaosutu 036f1558a1 changelog(#5816): 主报账对账 transferStatus 彻底下线——报账表出参删字段 + recon 读/写路径声明下线(PR #5826)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-11 12:04:57 +08:00
Mimingguang b0cabd9436 chore(changelog): 派单 Step2 三缺陷 前端 implemented(313609db)
changelog-filename-gate / validate (push) Successful in 1s
2026-08-11 10:03:48 +08:00
Mimingguang de72a4f9e6 chore(changelog): #5810 前端 implemented(b6f9c44a)
changelog-filename-gate / validate (push) Successful in 1s
2026-08-11 09:51:51 +08:00
API Changelog Bot 28e3bc46cb changelog(#5810): requirementFleetText 格式改车队组成写法(PR #5817)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-11 09:43:00 +08:00
Mimingguang 44e1599741 chore(changelog): #5809 #5781 前端 implemented(3993f15a)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-11 09:36:12 +08:00
API Changelog Bot 5755a954a8 changelog(frontend): 派单 Step2 统一选车弹窗空白+建议标签催办+需求展示区
changelog-filename-gate / validate (push) Successful in 1s
2026-08-11 09:24:57 +08:00
API Changelog Bot 4ab1d52c8c changelog(#5810): 换版槽位人工制新契约——需求语句+605062日期门禁+槽位统一原样渲染(PR #5815)
changelog-filename-gate / validate (push) Successful in 2s
取代 #5788 前端契约:superseded 三字段语义已死,删除全部标旧渲染分支;
新增 requirementFleetText 需求语句展示;派车推进类接口接住 605062。
#5788 条目标 not_required 并指向本条。
2026-08-11 09:00:51 +08:00
yaosutu 71a0544914 docs(changelog): 单团核算表扩充逐项明细出参(#5781 / PR #5786)
changelog-filename-gate / validate (push) Failing after 2s
incomeLines[i] 新增 details 收入逐项、costCategories[i] 新增 lines 成本逐项(按 category 窄化);
配套新增 insurance_biz_type / settlement_refund_source 两个字典。纯出参增量,向后兼容。
2026-08-10 22:42:28 +08:00
yaosutu 7921162dfa docs(changelog): 完成核单去转账/签字凭据采集(#5809 / PR #5813)
changelog-filename-gate / validate (push) Failing after 2s
finalize 改无请求体;recon 入参与报账表出参各删 4 个凭据字段;
ReqVO ignoreUnknown=false,前后端必须同批上线。
2026-08-10 21:46:16 +08:00
Mimingguang 31ed8a0e31 chore(changelog): #5808 前端 implemented(55311b31)
changelog-filename-gate / validate (push) Successful in 1s
2026-08-10 20:12:15 +08:00
API Changelog Bot 5f50581ba1 changelog(#5808): 消息中心纳管车务团队会话消息(PR #5812)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-10 19:52:09 +08:00
Mimingguang fabb787f81 chore(changelog): #5788 前端回退 pending——遵 17:54 暂停令 revert 2.8(3441e69e),等 #5810 新契约
changelog-filename-gate / validate (push) Successful in 1s
2026-08-10 19:13:22 +08:00
Mimingguang fd6638a1b0 chore(changelog): #5788 前端 implemented(§2.8 重做 064d0be2)
changelog-filename-gate / validate (push) Successful in 1s
2026-08-10 18:05:51 +08:00
Mimingguang c550f00901 chore(changelog): #5788 前端 claimed(§2.8 重做 064d0be2) 2026-08-10 18:05:08 +08:00
API Changelog Bot 95368c0303 changelog(v2): #5788 暂停 2.8 施工——换版策略升级走 #5810(槽位人工制+需求语句+日期门禁),落地后出新契约
changelog-filename-gate / validate (push) Successful in 2s
2026-08-10 17:54:07 +08:00
API Changelog Bot cb60e2cf67 changelog(v2): #5788 二次打回 pending——wx 最终口径:旧数据渲染为槽位条目,按 2.8 规格重做(b31ac7c3 其余项已过)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-10 17:32:11 +08:00
API Changelog Bot a86e136b47 changelog(v2): #5788 形态重定——旧数据必须渲染为槽位条目(2.8 完整实现规格:结构/操作/接口参数/数据源/验收),推翻窄条定稿
changelog-filename-gate / validate (push) Successful in 2s
2026-08-10 17:31:39 +08:00
Mimingguang 4c782a118b chore(changelog): #5788 前端 implemented(返工 b31ac7c3)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-10 17:28:23 +08:00
Mimingguang af1756768f chore(changelog): #5788 前端 claimed(返工 b31ac7c3) 2026-08-10 17:27:51 +08:00
API Changelog Bot ec43d39803 changelog(v2): #5788 形态定稿——旧数据窄条形态 wx 已接受,剩数据源遮蔽+exclude 同源两项
changelog-filename-gate / validate (push) Successful in 1s
2026-08-10 17:26:47 +08:00
API Changelog Bot 926336c5aa changelog(v2): #5788 a75efc05 复测未过打回 pending——4 项前端返工(数据源遮蔽/exclude同源/去除锁定/任何槽位可删,后端 PR #5802 已兜底选车)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-10 16:54:14 +08:00
API Changelog Bot ad04e0b450 chore: .gitattributes 固定钩子与脚本为 LF(防 CRLF 化后 sh 无法执行)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-10 16:37:46 +08:00
API Changelog Bot和Claude Fable 5 b8596041d7 docs: 发布门禁硬规则——给前端推送的必须是测试环境已存在可实测的+pre-push 钩子
- guide §2.1: 接口类条目推送前必须走完 PR 合并→部署测试服→测试服真实 API 验证,backend_status=deployed 才许 push;预告式推送一律禁止(2026-08-10 wx 定,前端投诉实证 #5599/#5567/#5633)
- .githooks/pre-push: push 前自动跑文件名+frontmatter 校验,违规拦截;启用 git config core.hooksPath .githooks
- 文件名类型枚举文档同步(7 类+frontend 字面量)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-10 16:37:21 +08:00
API Changelog Bot和Claude Fable 5 0e911a98f3 chore(changelog): 回填 #5599/#5567/#5633 部署实测状态(未部署即推送整改)+5 条枚举/结构合规
- #5599/#5567/#5633(yst 8-06~8-07 推送时未部署测试服): 2026-08-10 复核确认代码已随 order-v3 8-10 部署上测试服,补验证证据章节(部署点位+DB 列+网关实测),backend_status 回填 deployed/gateway verified
- #5444、#5730-5732: backend_status released→deployed(枚举合法化,状态语义不变)
- #5784 补验证证据章节、#5788 章节结构规范化、#5797 清理 not_required 残留前端字段

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-10 16:37:20 +08:00
API Changelog Bot和Claude Fable 5 65ddaae00f fix(scripts): 校验规则去假阳性——前端/修复类条目合法化+路径参数不误判占位符
- CHANGE_TYPES 扩:修复/前端缺陷/前端优化/前端修复(文件名+frontmatter 同步);纯前端条目 issue 段允许 frontend 字面量、backend_status 允许 not_required(接口类仍禁)
- E_PLACEHOLDER 只拦双花括号/TODO/待补充,不再误杀 {orderId} 等 REST 路径参数
- E_SECTIONS 仅约束接口类条目,章节名宽匹配(变更接口/变更清单/接口变化/行为变化等)
- 核心门禁保持硬:接口类必须 backend_status=deployed 才允许发布(E_BACKEND_PENDING)
- 背景:规则假阳性致 CI 长期常红被忽略,真违规(未部署即推送)淹没其中;npm test 46/46 绿

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-10 16:36:48 +08:00
Mimingguang 469ae00f98 chore(changelog): #5788 换版保留派单槽位标旧 前端已实现(implemented) ref=a75efc05(fleetItemIndex 同源押后)
changelog-filename-gate / validate (push) Failing after 1s
2026-08-10 16:29:53 +08:00
Mimingguang 0959c16268 chore(changelog): #5788 换版保留派单槽位标旧 前端认领(claimed) 2026-08-10 16:29:24 +08:00
Mimingguang 872ba16ea3 chore(changelog): 工单A 车务看板聊天角标实时化 前端 not_required(已接 no-op,依赖后端 #5792 部署)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-10 16:14:26 +08:00
Mimingguang 595b1a6d2f chore(changelog): 工单B 订单详情用车安排按车聚合 前端已实现(implemented) ref=728413e6(沿用徽标留契约后接)
changelog-filename-gate / validate (push) Failing after 1s
2026-08-10 16:05:24 +08:00
Mimingguang 5a071d8fe2 chore(changelog): 工单B 订单详情用车安排按车聚合 前端认领(claimed) 2026-08-10 16:04:49 +08:00
API Changelog Bot f108466c7a docs: 车务聊天定制师端已读回执修复 changelog (#5797/PR #5799)
changelog-filename-gate / validate (push) Failing after 1s
2026-08-10 16:03:20 +08:00
API Changelog Bot 672942369e changelog(v2): #5788 跟进 PR #5798 占位行排除放行+展示布局口径(旧数据行操作能力一致)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-10 15:52:28 +08:00
API Changelog Bot ff7e119073 changelog(v2): #5788 换版保留派单可改派+vehicleSlots 标旧字段(PR #5796)
changelog-filename-gate / validate (push) Failing after 1s
2026-08-10 15:38:48 +08:00
API Changelog Bot和Claude Opus 5 a133aa7a50 docs(changelog): 车务看板聊天角标实时化(#5792 后端已齐待前端接) + 订单详情用车安排按车聚合与沿用语义(前端优化×2)
changelog-filename-gate / validate (push) Failing after 2s
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-10 14:57:44 +08:00
API Changelog Bot和Claude Opus 5 c7bd95e01f chore(changelog): #5784 回填后端部署与实测状态(PR #5785/#5787/#5789)
changelog-filename-gate / validate (push) Failing after 2s
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-10 14:47:57 +08:00
Mimingguang c76ef049cc chore(changelog): #5784 需求换版保留旧派车 前端已实现(implemented) ref=188e0d64
changelog-filename-gate / validate (push) Failing after 1s
2026-08-10 14:13:24 +08:00
Mimingguang fc9ca84692 chore(changelog): #5784 需求换版保留旧派车 前端认领(claimed) 2026-08-10 14:13:05 +08:00
Mimingguang 793e81fab7 chore(changelog): frontend-fleet-batch-register-driver-confirm-disabled 前端已实现(implemented) ref=f02dc8e3
changelog-filename-gate / validate (push) Failing after 1s
2026-08-10 14:02:16 +08:00
Mimingguang 8e1da77703 chore(changelog): frontend-fleet-batch-register-driver-confirm-disabled 前端认领(claimed) 2026-08-10 14:01:56 +08:00
API Changelog Bot和Claude Opus 5 6cfed6863a docs(changelog): #5784 需求换版保留旧派车待人工核对(看板详情新增徽章字段,前端待接)
changelog-filename-gate / validate (push) Failing after 1s
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-10 13:24:44 +08:00
API Changelog Bot和Claude Opus 5 719031462f docs(changelog): #5782 补端到端实测数据(fence 352ms/回配 36 秒/时区正确)
changelog-filename-gate / validate (push) Failing after 2s
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-10 12:29:03 +08:00
API Changelog Bot和Claude Opus 5 a4e5ed7dc5 docs(changelog): #5782 派车确认后车控状态卡 10 分钟修复(PR #5783)
changelog-filename-gate / validate (push) Failing after 2s
fence 释放调用误用 getCheckedData 解 Result<Void> 致释放事件永久失败,
fence 只能等 10 分钟租约过期;顺带修 4 处 UTC 落库早 8 小时。
接口契约无变化,前端无需改动,但配车完成时间等字段口径已修正。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-10 12:22:15 +08:00
API Changelog Bot和Claude Opus 5 9f29dae489 docs(changelog): 补「关联/联系人」章节与 author(GIT) 后缀
changelog-filename-gate / validate (push) Failing after 1s
按 BACKEND_CHANGELOG_DELIVERY_GUIDE §5 规范:author 补 (GIT) 后缀,正文末尾
补「关联 / 联系人」章节(后端负责人 @wx、前端负责人 @mmg),并链上前置前端
改动 4c81471c 与 08-09 那条相关 changelog。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-10 12:16:12 +08:00
API Changelog Bot和Claude Opus 5 d38c24b1d2 docs(changelog): 多槽位原子提交后「登记司机已确认」按钮恒灰(前端缺陷)
changelog-filename-gate / validate (push) Failing after 1s
26-9313 两槽位原子提交后弹窗保持开启停在待确认页,登记按钮 disabled。
后端已实测排除:batch 响应逐槽返回 assignment.id、看板列表行 assignmentId
非空、DB 两行 holding 身份完整。断点在前端 batch 分支不设 activeAssignmentId,
且依赖父层刷新+重开 watch 的恢复链在多槽位场景没走通。附建议修法与临时绕过。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-10 12:12:28 +08:00
Mimingguang 28340e8013 chore(changelog): #5778 房型 BIG_BED 下线 前端已实现(implemented) ref=ca770153
changelog-filename-gate / validate (push) Failing after 2s
2026-08-10 11:17:19 +08:00
Mimingguang 5363980fe5 chore(changelog): #5778 房型 BIG_BED 下线 前端认领(claimed) 2026-08-10 11:16:33 +08:00
Mimingguang a664ab410a chore(changelog): #5778 frontend_status 非法值 none 修正为 pending(前端实证有改动) 2026-08-10 11:15:50 +08:00
API Changelog Bot b3a2cf07e7 chore(changelog): #5778 房型字典 BIG_BED 下线合并 QUEEN(方案A,前端无需改动)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-10 10:59:08 +08:00
Mimingguang 579a64e543 chore(changelog): frontend-fleet-assign-modal-close-on-next 前端已实现(implemented) ref=4c81471c
changelog-filename-gate / validate (push) Failing after 1s
2026-08-10 10:41:22 +08:00
Mimingguang 8c7ebe19c1 chore(changelog): frontend-fleet-assign-modal-close-on-next 前端认领(claimed) 2026-08-10 10:40:52 +08:00
API Changelog Bot 289fa89a70 chore(changelog): #5770 时间线读侧合成4类里程碑+keyword/生效日修复 · #5777 discount清单车务放行(0810 审查扫尾)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-10 10:18:48 +08:00
Mimingguang 93428611ea chore(changelog): frontend-fleet-step4-confirm-daily-fee-continuity 前端已实现(implemented) ref=ffb2df89
changelog-filename-gate / validate (push) Failing after 2s
2026-08-10 10:09:35 +08:00
Mimingguang 10b9ea32f0 chore(changelog): frontend-fleet-step4-confirm-daily-fee-continuity 前端认领(claimed) 2026-08-10 10:08:59 +08:00
API Changelog Bot 3b1d6f3767 frontend fleet: 确认执行页逐日车费未随接续段遍历仍只显示第一段(mmg 车·师傅已修好,逐日车费漏改,后端数据完整)
changelog-filename-gate / validate (push) Failing after 1s
2026-08-10 10:05:55 +08:00
Mimingguang 8225112e9f chore(changelog): #5776 确认执行页接续段+短信口径 前端已实现(implemented) ref=6709c157
changelog-filename-gate / validate (push) Failing after 1s
2026-08-10 10:01:38 +08:00
Mimingguang 44f016b99d chore(changelog): #5776 确认执行页接续段+短信口径 前端认领(claimed) 2026-08-10 10:01:38 +08:00
API Changelog Bot 6aed45f380 docs(changelog): #5776 问题①补充逐日车费同源(只显示第一段,缺接续段费用)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-10 09:58:38 +08:00
Mimingguang 86927d4039 chore(changelog): #5739 核单指纹下线 前端已实现(implemented) ref=19d001a4
changelog-filename-gate / validate (push) Failing after 1s
2026-08-10 09:50:42 +08:00
Mimingguang 360981f42f chore(changelog): #5739 核单指纹下线 前端认领(claimed) 2026-08-10 09:50:22 +08:00
API Changelog Bot 214915b1ea chore(changelog): 前端缺陷-确认执行页车辆接续只显示第一段+不发送短信口径澄清(#5776)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-10 09:47:08 +08:00
Mimingguang c70ca66473 chore(changelog): #5750 派单操作时间线 前端已实现(implemented) ref=a9a48643
changelog-filename-gate / validate (push) Failing after 2s
2026-08-10 09:29:57 +08:00
Mimingguang 3953ec74c2 chore(changelog): #5750 派单操作时间线 前端认领(claimed) 2026-08-10 09:29:23 +08:00
yaosutu a24f7cc724 docs(changelog): #5739 核单报表快照指纹彻底下线(PR #5764)
changelog-filename-gate / validate (push) Failing after 1s
- GET /v3/admin/order/{orderId}/settlement/reports/group 出参删除 sourceFingerprint,reportStatus 枚举删除 STALE
- GET /v3/admin/order/{orderId}/settlement/reports/reimbursement 同步变更
- 承接 #5704 写入路径指纹下线,本次为报表读取路径收尾批次
2026-08-09 23:04:57 +08:00
API Changelog Bot 5158b4ef7e docs(changelog): #5744 补充追加验收(PR 5761/5763)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-09 18:44:44 +08:00
API Changelog Bot 0fbd9f321b changelog(order-v3): #5751 车务管理员查看订单详情与打印行程单误拦修复
changelog-filename-gate / validate (push) Successful in 2s
2026-08-09 18:35:19 +08:00
API Changelog Bot f438c9bd63 changelog #5750:派单操作时间线接口(查看日志按钮数据源)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-09 17:56:39 +08:00
API Changelog Bot 443ffdfab5 docs(changelog): 全项目报错文案中文治理(#5746)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-09 17:55:31 +08:00
Mimingguang 7939795d8f chore(changelog): 核单完成按钮校验逻辑简化 前端已实现(implemented) ref=ce4d98b3
changelog-filename-gate / validate (push) Failing after 1s
2026-08-09 17:37:06 +08:00
Mimingguang 8b53273713 chore(changelog): 核单完成按钮校验逻辑简化 前端认领(claimed) 2026-08-09 17:36:40 +08:00
Mimingguang 5e53e06f35 chore(changelog): frontend-house-detail-tabs-empty 前端已实现(implemented) ref=fa59235d
changelog-filename-gate / validate (push) Failing after 1s
2026-08-09 16:53:26 +08:00
Mimingguang 82fe6c6059 chore(changelog): frontend-house-detail-tabs-empty 前端认领(claimed) 2026-08-09 16:53:26 +08:00
API Changelog Bot 96da306c1d feat(fleet): 前端缺陷-待确认页点下一步窗口关闭应保持开启进确认执行
changelog-filename-gate / validate (push) Failing after 2s
2026-08-09 16:41:27 +08:00
yaosutu 737e3fcb4c docs: 核单完成按钮校验逻辑简化 changelog
changelog-filename-gate / validate (push) Failing after 1s
2026-08-09 16:28:04 +08:00
API Changelog Bot 1a2a1bdb65 docs(changelog): #5744 lint 修正(frontmatter+占位符)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-09 16:16:18 +08:00
API Changelog Bot 2f613a6ea9 docs(changelog): #5744 补 frontmatter 2026-08-09 16:15:14 +08:00
API Changelog Bot fe3fe0e248 docs(changelog): #5744 改派后vehicle_control_status卡PROCESSING修复(五层根因) 2026-08-09 16:14:35 +08:00
API Changelog Bot 4110192fd4 feat(house): 前端缺陷-房务订单详情定制师需求/配房行程/操作日志tab全空但后端数据正常
changelog-filename-gate / validate (push) Failing after 1s
2026-08-09 16:05:58 +08:00
Mimingguang 186231976e chore(changelog): 接续分tab口径B前端已落地(implemented 84ed152e)
changelog-filename-gate / validate (push) Failing after 2s
改派待确认预览合并草稿段+其他接续段按司机分 tab(按日精确拆分,含已确认段)。实证真根因是草稿新选择未合入预览而非终态过滤。
2026-08-09 15:58:01 +08:00
API Changelog Bot b0fee56955 docs(fleet): 接续分tab补充-新建派车batchMode槽位内接续司机也丢tab(26-3559实证)
changelog-filename-gate / validate (push) Failing after 1s
2026-08-09 15:20:29 +08:00
API Changelog Bot b2ac18ff52 docs(fleet): 接续通知分tab reopen-口径B需展示全部接续司机tab(含已确认段)
changelog-filename-gate / validate (push) Failing after 1s
2026-08-09 14:44:48 +08:00
Mimingguang 1554534753 chore(changelog): #5729 核单报表中文名前端已适配(implemented 4f5f4e47)
changelog-filename-gate / validate (push) Failing after 1s
修正 frontmatter frontend_status 非法值 not_implemented -> pending 后走状态机:pending -> claimed -> implemented,frontend_ref 4f5f4e47。ReportModal 明细 code 列改由后端 xxxName/statusText 承载,缺 name 回退 code。
2026-08-09 14:33:43 +08:00
Mimingguang 2a612a98cc chore(changelog): 5730-5732汇总单前端标 not_required(子项已各自消费)
changelog-filename-gate / validate (push) Failing after 1s
#5730 本地兜底表补 BIG_BED(hl-admin@3ec1a933);#5732 纯后端 render 修复前端零改动。汇总单无需前端改代码,transition pending -> not_required。
2026-08-09 14:31:29 +08:00
Mimingguang 1f5b1eea47 chore(changelog): 接续派车通知分tab+接续标注前端已接入(frontend-fleet-continuity-notify-tabs)
changelog-filename-gate / validate (push) Failing after 2s
frontend_status pending -> implemented,frontend_ref d7f78a17。①改派预览接 render-batch 按司机分 tab;②顶部接续槽位卡片「接续 i/N」标注。
2026-08-09 14:25:13 +08:00
yaosutu 1d88fab99d feat(order-v3): 核单报表出参强类型化补中文名(#5729)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-09 14:17:09 +08:00
API Changelog Bot d50c0d1804 feat(fleet+house): 告知前端-房型BIG_BED中文(#5730)+预览日期分段(#5732)后端已修复部署
changelog-filename-gate / validate (push) Failing after 1s
2026-08-09 12:02:21 +08:00
API Changelog Bot 1ecc2b91d5 changelog #5732:派车通知预览日期按 serviceDates 分段(接续场景)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-09 11:56:24 +08:00
API Changelog Bot a09466557f docs(fleet): 接续通知changelog补render-batch真实请求响应+日期分段后端问题指引
changelog-filename-gate / validate (push) Failing after 2s
2026-08-09 11:27:17 +08:00
API Changelog Bot 5293bb84cf feat(fleet): 前端缺陷-车辆接续派车通知多司机分tab(接render-batch)+按日改派汇总显示接续
changelog-filename-gate / validate (push) Failing after 2s
2026-08-09 11:23:47 +08:00
Mimingguang 5349d91d27 docs(changelog): 5730 前端兜底表补 BIG_BED,implemented 3ec1a933
changelog-filename-gate / validate (push) Failing after 1s
2026-08-09 11:13:30 +08:00
API Changelog Bot 8af58c6c26 docs(changelog): 房型 BIG_BED 字典补中文全链路显示大床房(#5730)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-09 10:58:20 +08:00
Mimingguang 46730e7a73 docs(changelog): reassign-display 按天表格整段改派残留补修,ref 82f5b771
changelog-filename-gate / validate (push) Failing after 1s
2026-08-09 10:51:12 +08:00
API Changelog Bot 96db84a917 docs(fleet): 改派回显缺陷补充按天表格数据源接口dailyVehiclePlan
changelog-filename-gate / validate (push) Failing after 2s
2026-08-09 10:47:22 +08:00
API Changelog Bot 3b86274217 docs(fleet): 改派回显缺陷补充-按天表格始终不回显新选择
changelog-filename-gate / validate (push) Failing after 1s
2026-08-09 10:43:12 +08:00
Mimingguang 154338d76d docs(changelog): frontend-fleet-reassign-display 改派槽位列回显修复,implemented cb763a74
changelog-filename-gate / validate (push) Failing after 1s
2026-08-09 10:35:03 +08:00
API Changelog Bot 2b069a2d37 docs(fleet): 改派回显缺陷补充接口地址/参数/响应详情
changelog-filename-gate / validate (push) Failing after 1s
2026-08-09 10:32:53 +08:00
API Changelog Bot f802d92994 feat(fleet): 前端缺陷-改派选完车/司机后槽位列不回显(仍显示待重新选择)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-09 10:27:57 +08:00
Mimingguang d023480172 docs(changelog): 5697 行程链接预览为后端渲染,前端实证 not_required
changelog-filename-gate / validate (push) Failing after 1s
2026-08-09 00:05:50 +08:00
Mimingguang 8e1ec2ff65 docs(changelog): frontend-fleet-batch3slot 实证为旧批量形态已替换,关闭 not_required
changelog-filename-gate / validate (push) Failing after 2s
2026-08-09 00:04:15 +08:00
API Changelog Bot 4efa7e3a17 feat(fleet): 前端缺陷-3槽位派单batchCreate请求体缺requestId+common包装且丢槽(TEST实测)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-08 23:48:34 +08:00
Mimingguang a5e9bcda50 chore(changelog): #5704 implemented (hl-admin@d32e14b9) 核单指纹下线前端实证
changelog-filename-gate / validate (push) Failing after 2s
2026-08-08 23:11:51 +08:00
yaosutu 3928b35212 docs(changelog): 撤回含错误指纹说法的 #5674 白名单,只读字段清单并入 #5704
changelog-filename-gate / validate (push) Failing after 1s
2026-08-08 22:44:38 +08:00
Mimingguang a0b43444db chore(changelog): #5725 not_required 前端实证(confirm两路径无605042特判天然受益)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-08 21:48:16 +08:00
API Changelog Bot 09a155a1e7 docs(changelog): confirm 两路径一致解除 AMBIGUOUS 拦截(#5725)
changelog-filename-gate / validate (push) Failing after 1s
2026-08-08 21:43:21 +08:00
Mimingguang b955b244df chore(changelog): #5712 #5708 implemented (hl-admin@a9ddbd48) 含前端实证
changelog-filename-gate / validate (push) Failing after 2s
2026-08-08 20:24:36 +08:00
yaosutu f6ca749fe3 docs(changelog): 车辆核单金额放开可编辑(#5712)+车辆下拉新增dayPrice(#5708)
changelog-filename-gate / validate (push) Failing after 2s
- 5712: PUT /v3/admin/order/{orderId}/settlement/step3/vehicles FLEET行amount放开可编辑
- 5708: GET /v3/admin/order/{orderId}/settlement/vehicle-options 出参新增dayPrice参考价
2026-08-08 20:12:16 +08:00
Mimingguang 40e47b1b6a chore(changelog): #5701 补修实证 confirm解除605042+已冻结组605020 前端not_required维持
changelog-filename-gate / validate (push) Failing after 1s
2026-08-08 18:18:21 +08:00
API Changelog Bot 2792bf31fa docs(changelog): confirm解除605042拦截+已冻结组605020修复(#5701 补修)
changelog-filename-gate / validate (push) Failing after 1s
2026-08-08 18:13:12 +08:00
Mimingguang da23030b62 chore(changelog): #5674 白名单 implemented (hl-admin@9694bb68) 含字段对照实证
changelog-filename-gate / validate (push) Failing after 1s
2026-08-08 17:10:49 +08:00
API Changelog Bot 957622305b changelog #5706 移除:internal Feign 接口应归 hl-backend-changelog(后端同事向),非 hl-api-changelog(前端向)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-08 16:59:10 +08:00
API Changelog Bot 988058474c changelog #5706 修正:internal Feign 接口,consumer 改 internal + frontend_status 改 not_required,交接对象改为后端同事(order核单侧/腰苏图),前端无关
changelog-filename-gate / validate (push) Successful in 2s
2026-08-08 16:57:29 +08:00
API Changelog Bot ed376947fc changelog #5706:车辆异步下拉options出参加dayPrice车型当日牌价(核单选型参考价)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-08 16:43:48 +08:00
yaosutu 16c743d37e docs(changelog): 核单域下线数据指纹乐观锁(#5704 / PR #5709)
changelog-filename-gate / validate (push) Failing after 1s
- 6 个端点删除 expectedSourceFingerprint/version 入参与 sourceFingerprint/version 出参
- 错误码 584108/584110/584325 下线,车辆来源漂移改挂 584315
- 字段删除硬破坏契约,前端须先停传旧字段再与后端同批发布
2026-08-08 16:32:31 +08:00
yaosutu ffdfd6057a docs(changelog): 核单导游/摄影费用保存接口入参字段白名单澄清(#5674)
changelog-filename-gate / validate (push) Failing after 2s
保存请求 VO 对未声明字段显式拒绝,前端原样回传 GET 响应对象会带出
sourceType 等只读派生字段触发 400。本文档给出两接口保存入参白名单、
字段约束、必须剥掉的只读字段清单及示例。
2026-08-08 16:25:33 +08:00
Mimingguang 080fe9528d chore(changelog): #5701 not_required 前端实证(人工登记MANUAL_CONTACT天然受益零改动)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-08 15:38:43 +08:00
API Changelog Bot 0a64dd8ccf docs(changelog): 登记司机确认不被通知结果确认中拦截(#5701)
changelog-filename-gate / validate (push) Failing after 1s
2026-08-08 15:33:01 +08:00
Mimingguang 4ac2465003 chore(changelog): #5693 一步到位 implemented (hl-admin@23d6e7b1) 含口径取舍说明
changelog-filename-gate / validate (push) Failing after 2s
2026-08-08 15:15:04 +08:00
Mimingguang fee1e9a5aa chore(changelog): #5698 前端交接项1 implemented (hl-admin@106aa658)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-08 14:54:23 +08:00
API Changelog Bot e69a5b9550 docs(changelog): 5697 行程链接预览恢复真链接(管理后台)
changelog-filename-gate / validate (push) Failing after 1s
2026-08-08 14:53:35 +08:00
API Changelog Bot 7ca2565338 changelog(#5698): 改派修复——已派全程行改派生效 + 清除司机/车辆后槽位空态待重选(前端交接 pending)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-08 14:42:33 +08:00
API Changelog Bot 6daaf40faa docs(changelog): #5693 补充wx一步拖拽改派口径(前端交互另行分流)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-08 14:41:12 +08:00
API Changelog Bot 76301f2c02 docs(changelog): 前端任务——矩阵拖拽改派一步到位(drop后直接调change,#5693 分流)
changelog-filename-gate / validate (push) Failing after 1s
2026-08-08 14:40:19 +08:00
Mimingguang aa3a32080c chore(v2): 标记 #5676 统一选择文件 admin 已实现 + 矩阵场景实证(hl-admin@f4223996)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-08 14:28:48 +08:00
API Changelog Bot 07f4db337d docs(5676): 补充矩阵派单场景——一行派车应用所有行程日对应槽位
changelog-filename-gate / validate (push) Failing after 1s
2026-08-08 14:26:09 +08:00
Mimingguang 4fb4821b14 chore(v2): #5691 admin not_required(按天行已带 serviceDates 空兜底)+ #5693 前端实证确认
changelog-filename-gate / validate (push) Failing after 1s
2026-08-08 13:29:03 +08:00
API Changelog Bot b14f70292d docs(changelog): #5693 lint修正(路径占位符改写)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-08 13:24:12 +08:00
API Changelog Bot fda2f2ea49 docs(changelog): #5693 矩阵拖拽改派多槽位评估+候选排除语义锁定
changelog-filename-gate / validate (push) Failing after 2s
2026-08-08 13:23:23 +08:00
API Changelog Bot 2e26fd4a8b changelog #5691:改派页确认改单日期对所有出行日回显(已派全程行finalized=0修复)
changelog-filename-gate / validate (push) Failing after 3s
2026-08-08 13:21:42 +08:00
Mimingguang f1254e37b5 chore(v2): #5681 admin 前端实证确认 not_required(整组快照守卫/逐日车费为正确消费方)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-08 12:58:33 +08:00
API Changelog Bot dc8a3ef559 changelog(fleet): #5681 多槽位确认执行逐日车费与整组快照代际修复
changelog-filename-gate / validate (push) Successful in 2s
2026-08-08 12:54:15 +08:00
Mimingguang b3c427bf23 chore(v2): 标记 #5689 admin 前端无需改动(实证无错误码特判、直渲后端文本)
changelog-filename-gate / validate (push) Failing after 1s
2026-08-08 12:40:07 +08:00
API Changelog Bot 869d75c988 docs(changelog): 5689 派单通知模板加载失败修复(管理后台)
changelog-filename-gate / validate (push) Failing after 1s
2026-08-08 12:35:27 +08:00
Mimingguang df0463e589 chore(v2): 标记 #5666b admin 前端已实现 (hl-admin@45cf94a1) + 矩阵未派清单 VO 缺字段说明
changelog-filename-gate / validate (push) Failing after 1s
2026-08-08 12:29:32 +08:00
Mimingguang 61bf4a46f4 chore(v2): 标记 #5676 admin 前端已实现(统一选择 f4223996 + 按天改派 3df533a5)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-08 12:11:37 +08:00
Mimingguang 6399b0aba9 chore(v2): 标记 #5592 admin 前端已实现 (hl-admin@dcb5f128)
changelog-filename-gate / validate (push) Failing after 1s
2026-08-08 11:52:39 +08:00
API Changelog Bot 15a82f9d45 docs(changelog): 前端任务——「发送派单通知」按钮改名「下一步」(避免歧义)
changelog-filename-gate / validate (push) Failing after 1s
2026-08-08 11:47:15 +08:00
Mimingguang f60ce32c10 chore(v2): 标记 #5675 admin 前端无需改动(预览已带派车组定位参数、降级文案直渲)
changelog-filename-gate / validate (push) Failing after 1s
2026-08-08 11:28:40 +08:00
API Changelog Bot f3a25fb629 docs(changelog): 行程单预览即生成可见短链(#5675)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-08 11:18:42 +08:00
API Changelog Bot 85dcb1a129 docs(changelog): 修正——矩阵派车可派订单列表信息补全(非排车页)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-08 11:01:37 +08:00
Mimingguang 2531b4a711 chore(v2): 标记 #5674 admin 前端无需改动(实证无错误码特判、直显后端 message)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-08 10:59:32 +08:00
yaosutu afeb26cf31 docs(changelog): 核单导游摄影费用解析失败错误码 584125 细化为 584128(#5674)
changelog-filename-gate / validate (push) Failing after 2s
PR #5677 已合并 dev-v3:4 个核单导游/摄影费用接口请求体解析失败/Bean 校验失败
错误码由 584125 细化为 584128,message 透出具体字段原因;请求体为空仍 584125 不变。
2026-08-08 10:56:40 +08:00
Mimingguang 8af962ba55 chore(v2): 标记 #5679 admin 前端已实现 (hl-admin@701233df)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-08 10:52:37 +08:00
API Changelog Bot 827f7301e9 docs(changelog): 前端任务——统一选择改单次调 change 整体改派(#5676 分流)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-08 10:44:51 +08:00
Mimingguang 506f9dd715 chore(v2): 标记 #5665 admin 前端已实现 (hl-admin@f1c00ba8)
changelog-filename-gate / validate (push) Failing after 2s
改派页增加/删除槽位:addAssignmentSlot 封装 + AssignmentSlotAddModal 弹窗
+ 删除走既有 deleteAssignmentSlot 跟随后端 canDelete;改派槽位表切到
resolveBoardAssignmentSlots 覆盖未派占位行;增删后刷新提示需重新确认。
2026-08-08 10:32:28 +08:00
API Changelog Bot c6924d4c3d docs(changelog): 前端任务——确认执行提示合并+去抖+友好化(#5679 分流)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-08 10:29:27 +08:00
API Changelog Bot 14b83d5801 docs(changelog): 前端优化——排车页信息丰富(建议车型/价格/司机等展示补全)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-08 10:16:18 +08:00
Mimingguang b58a9afe59 chore(v2): 标记 #5664 admin 前端已实现 (hl-admin@91530f73)
changelog-filename-gate / validate (push) Failing after 2s
多司机微信预览按司机分 tab:render-batch 批量取预览 + previewItems/
activePreviewKey 分 tab + 逐项 success 隔离 + 单司机回退单渲染不变。
2026-08-08 10:06:59 +08:00
Mimingguang 5fd2ef9bb8 chore(v2): 标记 #5663 admin 前端已实现 (hl-admin@9784e7aa)
changelog-filename-gate / validate (push) Successful in 2s
差异提示优先用后端 differenceLabel 不透英文码名;600211/600112 前端无
硬编码展示分支,走全局拦截器透传后端文案,无需前端改。
2026-08-08 09:50:13 +08:00
Mimingguang 3c2e093ef6 chore(v2): #5662 implemented + #5666 前端实证无需改动
changelog-filename-gate / validate (push) Failing after 2s
#5662 改派页清除草稿后补选择车辆/司机入口(hl-admin@c63ce28f)。
#5666 实查 HEAD 两症状已无活代码路径(c6b107b8/d97cc730 早已消除),
矩阵活路径已消费 suggestedDriverId、batch 不传部分收费日,判 not_required。
2026-08-08 09:48:25 +08:00
Mimingguang 20255492d0 chore(v2): 标记 #5655 admin 前端已实现 (hl-admin@ee7a5d58)
changelog-filename-gate / validate (push) Failing after 1s
族B→族A 切换已上线:直连 guide-fees/photographer-fees + 类别级指纹乐观锁
+ 并入 CategoryTable + 人员下拉仅预填姓名 + 不接 confirm + 候选最小实现。
如实标注待确认项:人员指纹冲突错误码按车辆域 584108 复用,待后端确认。
2026-08-08 09:42:52 +08:00
API Changelog Bot 3fa393d0d7 docs(5592): frontend_status=verified(改需求回待派车实测通过)
changelog-filename-gate / validate (push) Failing after 1s
2026-08-08 09:29:50 +08:00
Mimingguang ad9b2a5c52 chore(v2): 标记 #5656 admin 前端已实现(复用 #5642 列,零改动)
changelog-filename-gate / validate (push) Failing after 2s
#5656 即 #5642 所述后端补 fleet-detail-context→BoardOrderDetailVO 链路。
前端所属地列早已透传 nativePlace(ref 7e7085b6),后端补字段后自动生效。
2026-08-08 09:24:24 +08:00
Mimingguang 54e1cb6f28 chore(v2): 标记 #5666 candidates 注释对齐前端无需改动
changelog-filename-gate / validate (push) Successful in 2s
纯文档注解对齐+测试锁定,无运行时行为变更,前端消费口径为既有行为复述。
另核实 #5657/#5667 后端自标 not_required 属实(前端不强制派满建议数/
矩阵选择器本就读 requirementId),状态正确无需改动。
2026-08-08 09:23:32 +08:00
API Changelog Bot 7eb2308d20 docs(5596): frontend_status=verified(选车页预校验警告实测生效)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-08 09:19:11 +08:00
API Changelog Bot ce9da1a372 docs(5642): frontend_status=verified(协调台实测所属地正常显示)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-08 08:56:50 +08:00
API Changelog Bot 3041884f3c docs(changelog): 5663 fleet 英文/技术黑话提示统一改中文友好(管理后台接口)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-07 21:38:07 +08:00
API Changelog Bot 0a7781ae00 docs(changelog): 5663 fleet 英文/技术黑话提示统一改中文友好(管理后台接口)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-07 21:37:37 +08:00
API Changelog Bot cf2861ee02 docs(changelog): 5663 fleet 英文/技术黑话提示统一改中文友好(管理后台接口) 2026-08-07 21:37:22 +08:00
API Changelog Bot 07271c7ede changelog(fleet): #5667 矩阵未派订单清单补requirementId关联
changelog-filename-gate / validate (push) Successful in 2s
2026-08-07 21:14:07 +08:00
API Changelog Bot 0fa10a8846 docs(changelog): candidates收费日注释对齐+子集收费回显锁定(#5666)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-07 20:54:29 +08:00
API Changelog Bot 81e6d3aa44 docs(changelog): 改派时支持增加/删除槽位(#5665)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-07 20:27:00 +08:00
API Changelog Bot bbd6d7b864 docs(changelog): 前端任务——矩阵派车司机回填+收费日(#5666 分流,后端契约正常)
changelog-filename-gate / validate (push) Failing after 1s
2026-08-07 20:19:15 +08:00
API Changelog Bot d178008c4f changelog #5664:派单多司机微信预览批量渲染端点(含前端分tab交接)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-07 20:14:37 +08:00
API Changelog Bot b9f4c54df5 docs(5662): 改派对齐初次派车——车辆和司机可任选一侧先选
changelog-filename-gate / validate (push) Failing after 2s
2026-08-07 19:13:38 +08:00
API Changelog Bot ced26c2548 docs(changelog): 改派选司机按钮 #5662 文件名修正
changelog-filename-gate / validate (push) Failing after 2s
2026-08-07 19:10:38 +08:00
API Changelog Bot f909409c16 docs(changelog): 改派选司机按钮前端任务关联工单 # 2026-08-07 19:09:57 +08:00
API Changelog Bot a6475f4efa docs(changelog): 前端任务——改派页加选择司机按钮(后端 change 已支持 newDriverId) 2026-08-07 19:07:46 +08:00
API Changelog Bot d65e40a936 docs(changelog): #5657 确认执行不强制派满建议车辆数
changelog-filename-gate / validate (push) Successful in 1s
2026-08-07 18:34:52 +08:00
yaosutu 04f5a4c5e9 docs(changelog): 核单导游/摄影族B接口下线-删除接口-管理后台 (#5655)
changelog-filename-gate / validate (push) Failing after 1s
- 删除族B嵌套接口4个路由(staff-fees/guides、staff-fees/photographers 的 GET/PUT),调用返回404
- 删除族B专属错误码 584023/584024/584025/584028
- 前端切换目标:族A扁平接口 guide-fees / photographer-fees(已在线)
- 关联 PR #5658,merge commit 7d29484da7
2026-08-07 18:16:25 +08:00
API Changelog Bot 5de8b3497f changelog #5654:修复应用到槽位丢价(批量逐日未传价按日历兜底)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-07 18:06:19 +08:00
API Changelog Bot 70c648a70f docs(5642): 更正——派单详情缺 nativePlace 系后端 fleet 链路漏加,非前端问题,恢复 implemented
changelog-filename-gate / validate (push) Failing after 2s
2026-08-07 17:40:32 +08:00
API Changelog Bot 7dc8033c95 docs(5642): 补 nativePlace 字段名(heredoc 反引号被吞)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-07 17:33:46 +08:00
API Changelog Bot 88d1e4843e docs(5642): 前端核查——派单页所属地仍显示脱敏名,未生效 nativePlace,frontend_status 打回 claimed
changelog-filename-gate / validate (push) Failing after 2s
2026-08-07 17:32:27 +08:00
API Changelog Bot 987d468cac docs(changelog): holdMode=0直派兼容全程占位行拓扑校验(#5649)
changelog-filename-gate / validate (push) Successful in 1s
2026-08-07 17:07:34 +08:00
Mimingguang c810f5be2d chore(v2): 标记 #5640/#5642 admin 前端已实现
changelog-filename-gate / validate (push) Failing after 2s
#5642 出行人所属地优先展示后端解析 nativePlace(ref 7e7085b6)
#5640 司机详情页一键直投全年保险与手动选并存(ref 845d8827)
2026-08-07 16:49:44 +08:00
API Changelog Bot ef246da67c changelog #5640:司机详情页直接投保全年保险(含前端交接+生产年险计划配置遗留)
changelog-filename-gate / validate (push) Failing after 1s
2026-08-07 16:17:38 +08:00
API Changelog Bot 46eb07b972 docs(changelog): 出行人所属地后端解析返回nativePlace(#5642)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-07 16:12:19 +08:00
API Changelog Bot a031db038b docs(changelog): #5643 lint 修正(章节名/占位符/frontmatter)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-07 15:49:30 +08:00
API Changelog Bot daa80e084d docs(changelog): #5643 派车价日历回显+调价/行程链接文案
changelog-filename-gate / validate (push) Failing after 1s
2026-08-07 15:47:57 +08:00
Mimingguang 306c31943d chore(changelog): 回写 #5644 管理后台司机手机号放开可改已交付 (hl-admin@0e8340a1)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-07 14:55:38 +08:00
Mimingguang 465547976e chore(changelog): 回写 #5633 管理后台订单详情核单徽标已交付 (hl-admin@18f8e23b)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-07 14:49:02 +08:00
API Changelog Bot b382c6c40b docs: 5644 changelog gateway verified(网关验证 12/12)
changelog-filename-gate / validate (push) Failing after 1s
2026-08-07 14:47:29 +08:00
API Changelog Bot f215878bab docs: 07_5644 司机手机号支持车务管理员直接修改(放开phone可改)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-07 14:47:17 +08:00
yaosutu a38e197c1c docs(changelog): 订单详情出参补 reviewStatus/reviewStatusName(#5633,PR #5635)
changelog-filename-gate / validate (push) Failing after 1s
- 接口:GET /v3/admin/order/{id}(管理后台)
- data.main 段新增 reviewStatus / reviewStatusName,与核单列表 tab 同枚举同文案
- NONE 与 PENDING 同显「待核算」对齐列表归一;null 与非法值有容错约定
2026-08-07 14:38:02 +08:00
Mimingguang 6791f74cc3 chore(changelog): 纠正 #5636 前端为已实现——撤回对账退款列对齐核单重设计 (hl-admin@d897c3d4)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-07 14:05:10 +08:00
API Changelog Bot c3d7f4b48f docs(changelog): 对账vehicle-fee对齐核单重设计(#5636)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-07 13:58:31 +08:00
Mimingguang 37355a753e chore(changelog): #5629 确认前端无需改动(precheck 未接线,预览走 candidates)
changelog-filename-gate / validate (push) Successful in 1s
2026-08-07 12:12:14 +08:00
API Changelog Bot 1042d7ad62 docs(changelog): precheck对不存在车辆/司机返回明确conflict原因(#5629)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-07 12:06:05 +08:00
Mimingguang 8fc0df51b5 chore(changelog): 回写 #5610 管理后台车队对账实际结算只读化已交付 (hl-admin@d4ac54f5)
changelog-filename-gate / validate (push) Successful in 1s
2026-08-07 11:52:45 +08:00
API Changelog Bot 64637bb344 changelog #5630:房型分类字典白名单校验 + 存量 BIG_BED 归一(#5630)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-07 11:39:19 +08:00
API Changelog Bot d5f8f64bcb docs(changelog): 06_5610 核单完毕车辆费用写入fleet对账(从 backend-changelog 移入,管理后台前端交接)
changelog-filename-gate / validate (push) Failing after 1s
2026-08-07 11:36:27 +08:00
Mimingguang faaefbe8de chore(changelog): 回写 #5599 管理后台已交付修正版 (hl-admin@01bd3875)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-07 11:33:03 +08:00
Mimingguang 22e0b40614 chore(changelog): 回写 #5592 管理后台一键清空已交付 (hl-admin@790e76ab)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-07 11:04:05 +08:00
Mimingguang f32db894e4 chore(changelog): #5601 确认前端无需改动(pageNo/status 为后端兼容别名)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-07 10:50:11 +08:00
API Changelog Bot 372db232c9 docs(changelog): #5592 口径确认为一键清空(DELETE /slots 既有接口,非一键重派)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-07 10:49:13 +08:00
Mimingguang 2e7ea21ef1 chore(changelog): 回写 #5581/#5593 管理后台已交付
changelog-filename-gate / validate (push) Failing after 1s
- #5581 餐厅/导游/摄影资源下拉+默认单价预填 implemented (hl-admin@479c44ce);餐食独立餐厅列待后端 meal 契约加餐厅字段
- #5593 保险任务适配 REFUND_CHECK 退保检查 implemented (hl-admin@2b2dedfe)
2026-08-07 10:45:18 +08:00
Mimingguang da21377d9d chore(changelog): 回写 #5596/#5598 管理后台适配,#5613/#5618 确认前端无需改动
changelog-filename-gate / validate (push) Successful in 2s
2026-08-07 09:45:42 +08:00
API Changelog Bot 6c8ccae1d2 changelog(5626): fleet 管理端接口角色权限收紧(非车务角色403拦截)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-06 23:15:20 +08:00
API Changelog Bot 9c9d2ddbae changelog #5618:precheck 补黑名单司机校验(#5618)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-06 22:36:00 +08:00
wx 62253a2646 chore(changelog): 5613 派单恢复取消500修复——DAILY_V3快照拓扑按最终方案实际覆盖槽位
changelog-filename-gate / validate (push) Failing after 2s
2026-08-06 19:45:48 +08:00
API Changelog Bot 4dddd378c7 changelog: #5603 需求换版/取消后孤儿派单对账清理(新增接口)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-06 18:22:54 +08:00
API Changelog Bot 1662671ff6 changelog(v2): 派单预校验证件到期强提醒不拦截——驾照/年检/保险过期 warning + 候选驾照过期标记(#5596)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-06 18:13:58 +08:00
yaosutu be67501c86 docs(changelog): 终止行程重复提交改一律581049(#5598 / PR #5604)
changelog-filename-gate / validate (push) Successful in 1s
- COMPLETED 订单再次提交 terminate 由同正文 200 重放改为一律 581049「订单已终止,禁止重复提交」,零副作用
- 581049 文案由「终止行程重试与首次终止边界或请求不一致」改为「订单已终止,禁止重复提交」
- 首次终止(TRAVELLING→COMPLETED)行为不变;入参/出参字段结构不变
- 取代 04_5460 同正文重放契约,前端收到 581049 应视为订单已终止并改走查询接口取退款结果
2026-08-06 17:33:55 +08:00
API Changelog Bot b6181f2c0a changelog(v2): change逐日调整中途日期误报605028修复——全程行服务期内任意日期可改派(#5612)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-06 17:27:27 +08:00
API Changelog Bot 20e55c2d2a changelog(v2): 接口参数校验3缺陷——pageNo兼容别名+看板不存在订单报错+保险任务status兼容校验(#5601)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-06 17:09:25 +08:00
API Changelog Bot 557bbf4ad1 changelog(v2): 退保前校验保单已出单,未出单撤销投保任务(#5594)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-06 16:29:30 +08:00
API Changelog Bot c6c031e6f3 docs(changelog): #5595 全程行换司机605909误拦修复——判定放宽+存量迁移工具
changelog-filename-gate / validate (push) Failing after 2s
2026-08-06 16:06:47 +08:00
API Changelog Bot 79906d0320 docs(changelog): #5593 取消派单退保幂等——REFUND_CHECK独立类型+重试不调保司+锁短重试
changelog-filename-gate / validate (push) Successful in 1s
2026-08-06 15:42:30 +08:00
yaosutu f6fb5e16d8 docs(changelog): 补 Front Matter 必填 key frontend_owner/frontend_ref(#5599)
changelog-filename-gate / validate (push) Failing after 1s
2026-08-06 15:08:59 +08:00
yaosutu 82191f0931 docs(changelog): 核单餐食餐厅下拉值独立存储(#5599)
管理后台核单餐食 保存/修改/回显 接口新增 restaurantId/restaurantName
两字段(成对、非必填),与手动录入 mealName 完全独立不联动(PR #5600)。
2026-08-06 15:08:33 +08:00
API Changelog Bot 6207073ea7 chore(changelog): 需求变更后一键按新需求重派(#5592)
changelog-filename-gate / validate (push) Failing after 1s
2026-08-06 14:48:33 +08:00
yaosutu c1f336acd9 docs(changelog): 补 Front Matter(#5581)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-06 14:31:24 +08:00
yaosutu 1a04b55e8c docs(changelog): 新增核算餐厅导游摄影资源下拉选项接口(#5581)
管理后台核单场景新增 3 个资源下拉选项查询接口(PR #5583):
- GET /admin/resource-options/restaurants
- GET /admin/resource-options/guides
- GET /admin/resource-options/photographers
2026-08-06 14:30:42 +08:00
API Changelog Bot cfe34b9439 changelog(5589): HOLD通知派车组不存在500修复(后端完成,网关验证通过)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-06 13:23:55 +08:00
API Changelog Bot 5aa3c55dc2 changelog(#5588): 司机/车辆占用缓存态对账任务(修正脏busy并释放过期holding占用)
changelog-filename-gate / validate (push) Successful in 1s
2026-08-06 13:00:28 +08:00
API Changelog Bot b85c4bd5aa changelog(5586): 投保成功出单后司机档案保险状态自动同步为有保(INSURED回调兜底重绑)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-06 11:54:23 +08:00
Mimingguang d893c56d8a chore(changelog): 核账 #5575 前端无需改动
changelog-filename-gate / validate (push) Failing after 2s
修改原因:用车需求幂等修复新增可选成功分支值。

修改内容:确认现有页面不穷举 branchTaken,回写 not_required。

实际验证:核对 API、响应解包、提交成功流程和直接测试。

Changelog:#5575 source 文档。
2026-08-06 11:38:28 +08:00
Mimingguang b6b796f06f chore(changelog): 领取 #5575 管理后台核账
changelog-filename-gate / validate (push) Failing after 1s
修改原因:用车需求幂等修复新增可选分支值,需要核对前端兼容性。

修改内容:标记 claimed 并登记负责人。

实际验证:核对 source 请求响应契约。

Changelog:#5575 source 文档。
2026-08-06 11:35:04 +08:00
Mimingguang 6dea6462ad chore(changelog): 完成 #5571 管理后台适配
changelog-filename-gate / validate (push) Successful in 2s
修改原因:空值与零价发送司机已完成前端适配。

修改内容:回写 implemented 与业务提交引用。

实际验证:pnpm checkpoint 通过。

Changelog:#5571 source 文档。
2026-08-06 11:33:34 +08:00
Mimingguang d450378994 chore(changelog): 完成 #5572 管理后台适配
changelog-filename-gate / validate (push) Failing after 1s
修改原因:已派全程槽联动删除已完成前端适配。

修改内容:回写 implemented 与业务提交引用。

实际验证:pnpm checkpoint 通过。

Changelog:#5572 source 文档。
2026-08-06 11:27:58 +08:00
Mimingguang 1a17cf5e55 chore(changelog): 完成 #5567 管理后台适配
changelog-filename-gate / validate (push) Failing after 1s
修改原因:历史车辆费用安全空态已完成前端适配。

修改内容:回写 implemented 与业务提交引用。

实际验证:pnpm checkpoint 通过。

Changelog:#5567 source 文档。
2026-08-06 11:17:55 +08:00
API Changelog Bot a76c7a80b9 chore(changelog): 用车需求重复提交幂等(#5575)
changelog-filename-gate / validate (push) Failing after 1s
2026-08-06 11:07:46 +08:00
Mimingguang ce4ce083c1 chore(changelog): 完成 #5562 管理后台适配
changelog-filename-gate / validate (push) Failing after 1s
修改原因:全程槽模型已完成前端适配。

修改内容:回写 implemented 与业务提交引用。

实际验证:pnpm checkpoint 通过。

Changelog:#5562 source 文档。
2026-08-06 10:14:09 +08:00
Mimingguang 2981268e8f chore(changelog): 完成 #5574 管理后台适配
changelog-filename-gate / validate (push) Successful in 2s
修改原因:拉黑常驻司机状态与回退建议已完成前端消费。

修改内容:回写 implemented 和业务提交引用。

实际验证:pnpm checkpoint 定向验证通过。

Changelog:#5574 source 文档。
2026-08-06 10:05:31 +08:00
Mimingguang bb13ec8089 chore(changelog): 领取 #5574 管理后台适配
changelog-filename-gate / validate (push) Successful in 1s
修改原因:派单候选新增常驻司机赛季与拉黑回退原因,需要管理后台消费。

修改内容:标记 claimed 并登记 pi-main-session。

实际验证:核对 source 字段与候选契约。

Changelog:#5574 source 文档。
2026-08-06 09:54:51 +08:00
Mimingguang da4c53221e chore(changelog): 完成 #5558 #5573 管理后台适配
changelog-filename-gate / validate (push) Successful in 1s
修改原因:保单在线查看与槽位候选请求契约已完成管理后台交付。

修改内容:回写 implemented、v2.1 业务提交引用和验证日期。

实际验证:pnpm checkpoint 全量通过。

Changelog:#5558、#5573 对应 source 文档。
2026-08-06 09:52:20 +08:00
API Changelog Bot d1571345d6 changelog(#5574): 派车候选透传常驻司机赛季状态并对拉黑常驻给出明确自动代入原因
changelog-filename-gate / validate (push) Successful in 1s
2026-08-06 09:35:21 +08:00
Mimingguang ff25eb178d chore(changelog): 领取 #5558 #5562 #5573 #5572 #5571 #5567 管理后台适配
changelog-filename-gate / validate (push) Failing after 2s
修改原因:六项管理后台契约已进入当前批次,需要按依赖完成实现与核账。

修改内容:统一标记 claimed,并登记 pi-main-session 负责人及实现范围。

实际验证:逐份核对 frontmatter、ticket 与 source 路径。

Changelog:#5558、#5562、#5573、#5572、#5571、#5567 对应 2026-08 source 文档。
2026-08-06 09:24:11 +08:00
yaosutu ca81deaa8d 新增历史终止订单车辆核单安全空态说明
changelog-filename-gate / validate (push) Failing after 1s
2026-08-06 08:22:19 +08:00
API Changelog Bot 264e05e604 changelog(5571): 派车价0与未填价格允许发送司机(0价不再被非负金额拦截,anchor #5571)
changelog-filename-gate / validate (push) Successful in 1s
2026-08-06 01:35:07 +08:00
API Changelog Bot a0fec0eef4 changelog(5572): 派车全程槽删除支持已派车联动取消释放(anchor #5572 前端交接)
changelog-filename-gate / validate (push) Failing after 1s
2026-08-06 01:25:19 +08:00
API Changelog Bot e255fcf0d9 chore(changelog): 派车候选按槽位座位需求校验(#5573)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-06 01:05:27 +08:00
API Changelog Bot b9f0184499 chore(changelog): 移除误入一期目录的 5562 草稿
changelog-filename-gate / validate (push) Successful in 2s
2026-08-05 22:46:10 +08:00
API Changelog Bot 55cdfbef70 chore(changelog): 5562 全程槽模型(替代方案①手写版)
changelog-filename-gate / validate (push) Failing after 1s
2026-08-05 22:45:55 +08:00
API Changelog Bot 2e01157b2c docs(changelog): 5558 端到端验证按 wx 指示跳过,标注验收依据
changelog-filename-gate / validate (push) Successful in 2s
2026-08-05 22:20:26 +08:00
API Changelog Bot fd0b4d683a docs(changelog): 5558 补充 MOCKPOL 清理证据 + 链接补全 yst 格式(v2)
changelog-filename-gate / validate (push) Successful in 1s
2026-08-05 22:03:37 +08:00
API Changelog Bot 090b25a484 docs(changelog): 2026-08 批量补齐 author/关联联系人章节(yst格式),5558 从 v1 目录迁至 v2
changelog-filename-gate / validate (push) Failing after 2s
2026-08-05 22:01:46 +08:00
API Changelog Bot 776d869ba4 chore(changelog): 司机保单 policyPdfUrl 在线查看 + 投保缺省绑定全年保险(#5558)
changelog-filename-gate / validate (push) Successful in 2s
2026-08-05 20:51:45 +08:00
API Changelog Bot d2f16b9e96 chore(changelog): 派车详情按车型聚合为全程槽(#5562)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-05 20:28:44 +08:00
Mimingguang 21a013dedb chore(changelog): 完成 #5559 管理后台适配
changelog-filename-gate / validate (push) Successful in 1s
修改原因:派单候选司机自动建议已完成管理后台接入和安全校验。

修改内容:回写 implemented、v2.1 业务提交引用与验证结论。

实际验证:pnpm checkpoint 通过差异空白、Prettier、ESLint、Stylelint、暗色选择器、断点检查和定向 Vitest。

Changelog:changelogs-v2/2026-08/05_5559_矩阵派单司机自动代入-修改接口-管理后台.md(#5559)。
2026-08-05 19:54:53 +08:00
Mimingguang 85a0cf29bd chore(changelog): 领取 #5559 管理后台适配
changelog-filename-gate / validate (push) Successful in 1s
修改原因:派单候选已新增司机自动代入建议,需要管理后台接入。

修改内容:将 #5559 标记为 claimed 并登记当前实现范围。

实际验证:核对 changelog frontmatter、候选字段和 issue 路径。

Changelog:changelogs-v2/2026-08/05_5559_矩阵派单司机自动代入-修改接口-管理后台.md(#5559)。
2026-08-05 18:49:14 +08:00
API Changelog Bot aba61fd5fb changelog(#5559): 派单候选接口司机自动代入建议(suggestedDriverId/reason/message)
changelog-filename-gate / validate (push) Successful in 1s
2026-08-05 18:38:30 +08:00
yaosutu 16e592a497 新增车辆Tab三接口汇总通知
changelog-filename-gate / validate (push) Failing after 1s
2026-08-05 17:59:12 +08:00
Mimingguang 58adddcf30 chore(changelog): 完成 #5549 管理后台核账
changelog-filename-gate / validate (push) Successful in 2s
修改原因:司机保险可售计划和不可售错误码已完成前端消费核对。

修改内容:回写 implemented、v2.1 业务提交引用与验证结论。

实际验证:pnpm checkpoint 通过差异空白、Prettier、ESLint 和定向 Vitest。

Changelog:changelogs-v2/2026-08/05_5549_司机保险换可售产品与不可售友好报错-修改接口-管理后台.md(#5549)。
2026-08-05 17:58:50 +08:00
Mimingguang eb07619159 chore(changelog): 领取 #5549 管理后台适配
changelog-filename-gate / validate (push) Successful in 1s
修改原因:司机保险计划和不可售错误码已部署,需要管理后台核对并完成消费。

修改内容:将 #5549 标记为 claimed,并登记 pi-main-session 负责人。

实际验证:核对 changelog frontmatter 状态、负责人和 issue 路径。

Changelog:changelogs-v2/2026-08/05_5549_司机保险换可售产品与不可售友好报错-修改接口-管理后台.md(#5549)。
2026-08-05 17:49:21 +08:00
API Changelog Bot e11d5482c6 changelog: #5549 司机保险换可售产品与不可售友好报错
changelog-filename-gate / validate (push) Successful in 1s
2026-08-05 17:46:04 +08:00
API Changelog Bot 8757c2dc06 changelog: #5549 司机保险换可售产品与不可售友好报错
changelog-filename-gate / validate (push) Failing after 2s
2026-08-05 17:45:22 +08:00
API Changelog Bot c310c462fd changelog(#5552): 补 frontend_ref 说明(前端字段已存在,仅后端取值变化)
changelog-filename-gate / validate (push) Successful in 1s
2026-08-05 17:28:12 +08:00
API Changelog Bot 0cb9a139a1 changelog(#5552): 派车板详情日历价列兑底回显(board 订单详情 calendarPrice 语义) 2026-08-05 17:28:03 +08:00
Mimingguang b99b00940d chore(changelog): 更新 #5530 日期范围修复引用
changelog-filename-gate / validate (push) Failing after 2s
修改原因:补齐候选区标题仍显示单日的遗漏。

修改内容:frontend_ref 更新为 hl-admin@82255a9b0bd1e0e1560da161a80ec12325688655。

实际验证:候选区真实 DOM 日期范围断言和定向 checkpoint 通过。
2026-08-05 16:30:38 +08:00
Mimingguang aba0dbf019 chore(changelog): 完成 #5550 管理后台适配
changelog-filename-gate / validate (push) Failing after 2s
修改原因:派单页面已支持删除任意未派单车辆槽位。

修改内容:回写 implemented,并记录 hl-admin@99fc5bfcc0d52aed3d3e663ca2df247583a53409。

实际验证:业务全量 checkpoint 和生产构建通过,提交已进入 origin/v2.1。
2026-08-05 16:09:22 +08:00
Mimingguang 17cfdacf0c chore(changelog): 领取 #5550 管理后台适配
changelog-filename-gate / validate (push) Failing after 1s
修改原因:派单页面需要增加未派单车辆槽位删除入口。

修改内容:状态更新为 claimed,并记录 pi-main-session owner。

实际验证:核对删除接口、槽位状态门禁和刷新要求。
2026-08-05 15:59:37 +08:00
API Changelog Bot 20d3da2fe4 changelog: #5550 派单车辆槽位可删除(新增接口)
changelog-filename-gate / validate (push) Failing after 1s
2026-08-05 15:57:31 +08:00
Mimingguang 5c5991a13b chore(changelog): 完成 #5539 最终契约迁移
changelog-filename-gate / validate (push) Successful in 2s
修改原因:核单统一资源下拉已迁移到仅启用资源和中文字段最终契约。

修改内容:回写 implemented,并记录 hl-admin@0a8a72ed6a978a9f14187679188f4c8308e354cd。

实际验证:全量 checkpoint 和生产构建通过,reviewer finding 清零。
2026-08-05 15:28:02 +08:00
Mimingguang 96c73b5d08 chore(changelog): 完成 #5429 管理后台适配
changelog-filename-gate / validate (push) Successful in 2s
修改原因:核单门票游玩资源已接入统一日期价格分页选择。

修改内容:回写 implemented,并记录 hl-admin@0a8a72ed6a978a9f14187679188f4c8308e354cd。

实际验证:业务全量 checkpoint 和生产构建通过,提交已进入 origin/v2.1。
2026-08-05 15:23:55 +08:00
Mimingguang 9ef3ad6bab chore(changelog): 领取 #5429 和 #5539 管理后台适配
changelog-filename-gate / validate (push) Successful in 2s
修改原因:核单门票游玩资源选择需接入统一分页接口及最终字段契约。

修改内容:两份 source 更新为 claimed,并记录 pi-main-session owner。

实际验证:核对 #5539 对 #5429 的字段删除与改名关系。
2026-08-05 15:03:24 +08:00
Mimingguang 8d5e8014b0 chore(changelog): 更新 #5537 页面修复引用
changelog-filename-gate / validate (push) Failing after 2s
修改原因:保单列表继续移除冗余页头并修复长保单号列溢出。

修改内容:frontend_ref 更新为 hl-admin@d5235e2d89ce009fbad251cf1428ba304333524c。

实际验证:定向 checkpoint 通过,业务提交已进入 origin/v2.1。
2026-08-05 15:01:04 +08:00
yaosutu 89bbf236be 纠正核单资源接口通知目录至二期管理后台
changelog-filename-gate / validate (push) Successful in 2s
2026-08-05 14:57:01 +08:00
Mimingguang ed25da9e0b chore(changelog): 更新 #5537 前端交付引用
changelog-filename-gate / validate (push) Failing after 2s
修改原因:保单 Tab 后续修复了 Tabs 高度链和分页溢出。

修改内容:frontend_ref 更新为 hl-admin@1a203d31f4cf859be0cb5dd2734fc1ab0b3719d3。

实际验证:定向 checkpoint 通过,业务提交已进入 origin/v2.1。
2026-08-05 14:56:02 +08:00
Mimingguang 8315af15eb chore(changelog): 完成 #5537 管理后台适配
changelog-filename-gate / validate (push) Failing after 2s
修改原因:车务保险已完成保单视图与司机名筛选接入。

修改内容:回写 implemented,并记录 hl-admin@85b621a4b9dd225b9c7ab80928f5845d27359265。

实际验证:业务全量 checkpoint 和生产构建通过,提交已进入 origin/v2.1。
2026-08-05 14:49:32 +08:00
Mimingguang d808b57efc chore(changelog): 完成 #5530 前端显示修复
changelog-filename-gate / validate (push) Failing after 1s
修改原因:统一派单候选需按完整服务区间显示并排除非全程可用项。

修改内容:回写 implemented,并记录 hl-admin@a4ac5dd0d13a572e43e3a0dbb1abea7c049ea9ea。

实际验证:业务 checkpoint 和定向 Vitest 通过,提交已进入 origin/v2.1。
2026-08-05 14:46:39 +08:00
Mimingguang a475527ff8 chore(changelog): 领取 #5537 管理后台适配
changelog-filename-gate / validate (push) Failing after 1s
修改原因:车务保险需要新增保单视图并补司机名筛选。

修改内容:状态更新为 claimed,并记录 pi-main-session owner。

实际验证:核对保单列表、详情和任务筛选契约。
2026-08-05 14:34:05 +08:00
Mimingguang d2225c72ec chore(changelog): 核账 #5536 前端无需改动
changelog-filename-gate / validate (push) Failing after 2s
修改原因:后端新增 /orders 列表别名,但保留现有 /list,前端无需切换路径。

修改内容:回写 verified,引用已验证的保险订单页面提交 ef497e8e30d2df2d55d97f5554c8c5e921dc49ef。

实际验证:只读核对列表 /list、详情 /orders/{id}、页面消费与既有测试,未发现前端缺口。
2026-08-05 14:32:28 +08:00
API Changelog Bot cd846d5894 changelog: #5537 车务保险保单查看与司机名筛选(新增接口)
changelog-filename-gate / validate (push) Failing after 1s
2026-08-05 12:31:48 +08:00
Mimingguang fc8456c3ea chore(changelog): 领取 #5536 管理后台回归
changelog-filename-gate / validate (push) Successful in 1s
修改原因:后端已补保险订单 /orders 别名,需要核对既有前端调用。

修改内容:状态更新为 claimed,owner 归并为 pi-main-session。

实际验证:核对接口契约与管理后台消费范围。
2026-08-05 11:37:23 +08:00
yaosutu d3d21efceb 更新核单资源下拉可选范围与中文字段契约
changelog-filename-gate / validate (push) Successful in 1s
2026-08-05 11:29:19 +08:00
Mimingguang 95b2b5a155 chore(changelog): 完成 #5533 管理后台适配
changelog-filename-gate / validate (push) Successful in 1s
修改原因:司机列表和详情已消费新增车型、车队及关联订单字段。

修改内容:回写 implemented,并记录 hl-admin@005ba4cf9151e39aac5bcf4c5e5480411d68264e。

实际验证:业务全量 checkpoint 和生产构建通过,提交已进入 origin/v2.1。
2026-08-05 11:26:25 +08:00
API Changelog Bot 4deff2accf changelog: #5536 保险订单 v3 补 /orders 列表别名
changelog-filename-gate / validate (push) Successful in 2s
2026-08-05 11:20:50 +08:00
Mimingguang 47831d2226 chore(changelog): 完成 #5530 投保快捷项精简
changelog-filename-gate / validate (push) Failing after 1s
修改原因:按赛季与按年快捷预填重复。

修改内容:回写 implemented,并记录 hl-admin@aa7061b0edeaf68a8baf306a858a91d8be8cb9a7。

实际验证:业务 checkpoint 通过且提交已进入 origin/v2.1。
2026-08-05 11:19:39 +08:00
Mimingguang 64f0bdb60e chore(changelog): 领取 #5530 和 #5533 管理后台适配
changelog-filename-gate / validate (push) Failing after 2s
修改原因:开始处理投保快捷项精简及司机列表详情字段适配。

修改内容:两份 source 更新为 claimed,并记录 pi-main-session owner。

实际验证:核对 source 路径、ticket 与 pending 状态。
2026-08-05 11:03:13 +08:00
Mimingguang 5ac7c3452c chore(changelog): 领取 #5530 前端显示修复
changelog-filename-gate / validate (push) Failing after 1s
修改原因:开始处理用户实测的订单样式和派单候选显示问题。

修改内容:将管理后台状态更新为 claimed,并记录 pi-main-session owner。

实际验证:核对 source 路径与 pending 状态。
2026-08-05 11:00:51 +08:00
Mimingguang ccb4de62ee chore(changelog): 修正 #5479 前端交付引用
changelog-filename-gate / validate (push) Failing after 2s
修改原因:frontend_ref 仅记录裸 SHA,批次门禁无法确认对应 hl-admin 仓库。

修改内容:补充标准 hl-admin@ 前缀,业务提交保持不变。

实际验证:业务提交 e0c5f4f75087107fd0d82fbdc104c76d732292dc 已进入 origin/v2.1。
2026-08-05 10:55:24 +08:00
Mimingguang dfcffb1d3c chore(changelog): 修正 #5520 前端交付引用
changelog-filename-gate / validate (push) Failing after 1s
修改原因:保险订单页修正 ProTable 布尔错误态,成功响应不再误显示加载失败。

修改内容:将 #5520 frontend_ref 更新为 hl-admin@ef497e8e30d2df2d55d97f5554c8c5e921dc49ef。

实际验证:定向 checkpoint 通过,业务提交已精确推送 origin/v2.1。
2026-08-05 10:43:45 +08:00
Mimingguang d830838e90 chore(changelog): 更新 #5520 前端交付引用
changelog-filename-gate / validate (push) Failing after 1s
修改原因:保险订单列表补充请求竞态修复,避免成功响应被旧取消请求覆盖为失败态。

修改内容:将 #5520 frontend_ref 更新为 hl-admin@4c9df1c387b2f62637a0ff27c597e85082ee2715。

实际验证:定向 checkpoint 通过,业务提交已精确推送 origin/v2.1。
2026-08-05 10:37:27 +08:00
API Changelog Bot 7b8cf6c15e changelog: #5533 修正 frontmatter 状态与章节命名
changelog-filename-gate / validate (push) Successful in 1s
2026-08-05 10:29:37 +08:00
API Changelog Bot 6ef4eb60c6 changelog: #5533 司机列表车型大类/车队展示筛选 + 详情关联订单字段(dev-v3,author wx(GIT))
changelog-filename-gate / validate (push) Failing after 2s
2026-08-05 10:29:19 +08:00
Mimingguang deb92b41af chore(changelog): 完成 #5520 管理后台适配
changelog-filename-gate / validate (push) Failing after 1s
修改原因:保险订单页面已补齐分页、保费与保障日期兼容展示,需要同步 source 终态。

修改内容:将 #5520 标记为 implemented,并记录 hl-admin@0d0edbb0a1214cb19dde6cfd153cc48ea3385438。

实际验证:pnpm checkpoint 定向检查全部通过,业务提交已精确推送 origin/v2.1。
2026-08-05 10:27:20 +08:00
yaosutu 2982d27323 新增核单门票游玩统一资源日期价格接口说明
changelog-filename-gate / validate (push) Successful in 1s
2026-08-05 10:15:53 +08:00
API Changelog Bot a4ab64254b docs(changelog): 投保界面去掉按赛季快捷预填(与按年重复,wx 确认无此需求)
changelog-filename-gate / validate (push) Failing after 1s
2026-08-05 10:01:37 +08:00
Mimingguang 8e2af4e81c chore(changelog): 完成 #5515 管理后台适配
changelog-filename-gate / validate (push) Failing after 1s
修改原因:保险任务来源筛选、来源展示及页面入口和布局已完成,需要同步 source 终态。

修改内容:将 #5515 标记为 implemented,并记录 hl-admin@1553c988ac6065e693769a95f3f412c4e43df5e7。

实际验证:两次 pnpm checkpoint 全量通过,业务提交已推送 origin/v2.1。
2026-08-05 09:58:28 +08:00
Mimingguang 407494fa43 chore(changelog): 领取 #5515 #5520 前端适配
changelog-filename-gate / validate (push) Failing after 2s
修改原因:用户验收要求补齐保险任务来源筛选,并为实际保费字符串展示增加明确回归。

修改内容:将 #5515、#5520 source 从 not_required 调整为 claimed,并登记 pi-main-session。

实际验证:核对保险任务筛选 DOM、请求参数及保险订单 totalPremium 列表/详情消费链路。
2026-08-05 09:34:33 +08:00
API Changelog Bot a094aeb9f0 docs(changelog): 前端样式与派单候选显示问题交接(#5530 锚点)
changelog-filename-gate / validate (push) Failing after 2s
2026-08-05 09:26:30 +08:00
API Changelog Bot 5545cff81c docs(changelog): 交接前端两个显示问题(样式暗色+派单候选全程空闲/日期范围) 2026-08-05 09:25:03 +08:00
Mimingguang 9a51716e91 chore(changelog): 完成 #5368 管理后台适配
changelog-filename-gate / validate (push) Successful in 2s
修改原因:合同管理已完成订单号搜索与现有 v3 admin 链路收口,需要同步 source 终态。

修改内容:将 #5368 标记为 implemented,并记录 hl-admin@5925a3ff810b5ef0dbce027a0057e343a1910446。

实际验证:pnpm checkpoint 全量验证通过,业务提交已推送 origin/v2.1。
2026-08-05 09:22:47 +08:00
Mimingguang 3f72b09769 chore(changelog): 领取 #5368 管理后台适配
changelog-filename-gate / validate (push) Successful in 2s
修改原因:合同管理仍缺订单号搜索,且部分现有合同配置与旅行社调用未统一到 v3 契约。

修改内容:将 changelogs-v2/2026-08/04_5368_v3合同管理完整接口与订单号搜索-修改接口-管理后台.md 标记为 claimed,并登记 pi-main-session。

实际验证:只读核对合同列表真实 DOM、API 路径、直接调用方和既有测试,确认是部分实现。
2026-08-05 09:12:49 +08:00
Mimingguang 2f365dda19 chore(changelog): 核账 #5505 前端无需改动
changelog-filename-gate / validate (push) Failing after 1s
修改原因:HOLD 空 code 降级仅调整后端通知通道与 outbox 终态,前端字段和枚举均未变化。

修改内容:将 changelogs-v2/2026-08/04_5505_HOLD派车短信空串code降级-修改接口-管理后台.md 标记为 not_required。

实际验证:只读核对通知日志 status=3、failReason 展示及 HOLD canRetry 门禁,现有页面可正确处理且不会误开放重试。
2026-08-05 09:11:56 +08:00
yaosutu b3e977c66b 纠正Fleet管理接口为二期前端通知
changelog-filename-gate / validate (push) Failing after 1s
2026-08-05 08:34:30 +08:00
API Changelog Bot 2544dc7289 changelog: #5520 保险订单 totalPremium 恒 0 修复(保游金额字符串解析)
changelog-filename-gate / validate (push) Failing after 1s
2026-08-04 23:18:18 +08:00
API Changelog Bot a76ac60052 changelog: #5515 保险任务列表枚举校验+source筛选生效(PR #5522)
changelog-filename-gate / validate (push) Failing after 1s
2026-08-04 23:05:15 +08:00
共修改 232 个文件,包含 31694 行新增和 20 行删除
+2
查看文件
@@ -0,0 +1,2 @@
.githooks/* text eol=lf
scripts/*.mjs text eol=lf
+25
查看文件
@@ -0,0 +1,25 @@
#!/bin/sh
# changelog 发布门禁(推送前强制校验)
# 启用(每台机一次): git config core.hooksPath .githooks
# 拦截目标: 接口类 changelog 未部署测试服(backend_status != deployed)就推送给前端,
# 以及文件名/frontmatter 结构违规。规则实现见 scripts/validate-changelog-*.mjs。
zero=0000000000000000000000000000000000000000
status=0
while read local_ref local_sha remote_ref remote_sha; do
# 删除远端分支的推送没有本地内容可校验
[ "$local_sha" = "$zero" ] && continue
if [ "$remote_sha" = "$zero" ]; then
base=$(git rev-parse --verify origin/main 2>/dev/null) || continue
else
base=$remote_sha
fi
[ "$base" = "$local_sha" ] && continue
node scripts/validate-changelog-filenames.mjs --base "$base" --head "$local_sha" || status=1
node scripts/validate-changelog-frontmatter.mjs --base "$base" --head "$local_sha" || status=1
done
if [ "$status" -ne 0 ]; then
echo "" >&2
echo "推送被 changelog 发布门禁拦截:接口类条目必须测试服已部署+实测(backend_status=deployed)后才能推送给前端。" >&2
echo "修正文件后重试;规则详见 BACKEND_CHANGELOG_DELIVERY_GUIDE.md §2.1。" >&2
fi
exit $status
@@ -0,0 +1,41 @@
---
schema: "hl-changelog/v2"
ticket: "5888"
title: "修复调整订单加费被核单金融守卫误拦——定制师本人无法提交(584086)"
consumer: "admin"
change_type: "修复缺陷"
author: "wx(GIT)"
backend_status: "deployed"
gateway_status: "not_required"
frontend_status: "not_required"
frontend_owner: ""
frontend_ref: ""
target_release: ""
verified_at: "2026-08-12"
status_note: "后端已修复并部署测试服。定制师本人调整订单产生加费差额不再 584086;同时补上 submit 全链路订单归属校验(跨单操作 581008),行为对前端透明。"
updated_at: "2026-08-12"
base: "dev-v3"
---
# 修复:调整订单加费被核单金融守卫误拦(#5888 / #5891)
> **服务**: hl-order-service-v3
> **PR**: #5889 + #5892(已合并 dev-v3 并部署测试服)
> **日期**: 2026-08-12
> **背景**: 定制师本人操作「调整订单」,产生加费差额(priceDelta>0)即报 `584086 无权修改核单资金数据,仅主管、管理员或财务可操作`,无法提交。减费方向不受影响。
---
## 修复内容(对前端透明,无接口契约变化)
1. **移除误加的金融角色守卫**:`DiscountService.insertActiveSurcharge` 是「调整订单算价差额写入专用」方法,7-21 核单其他收入 PR 给它误加了 `SettlementWriteGuard`(只放行主管/管理员/财务),导致定制师本人被拦。已移除,与减费侧(`insertActiveDiscount`)口径对齐。
2. **补全 submit 全链路订单归属校验**(#5891):`AdjustmentService.submit` 锁定订单后新增 `OrderViewGuard.assertOrderAccessible` —— ADMIN/SUPER_ADMIN 放行;房务角色 581045;其余角色须为本单定制师(`consultantId == adminId`),否则 **581008 无权查看此订单**。
## 行为变化
| 场景 | 旧 | 新 |
|---|---|---|
| 定制师本人调整订单加费 | ❌ 584086 | ✅ 正常提交 |
| 非本单定制师/车务等调整他人订单 | ⚠️ 可提交(越权) | ❌ 581008 拦截 |
| 房务角色提交调整 | ⚠️ 可提交(越权) | ❌ 581045 拦截 |
@@ -0,0 +1,70 @@
---
schema: "hl-changelog/v2"
ticket: "frontend"
title: "确认执行页「车·师傅」多段/已派槽位显示空白:单段分支读 UI 选中态 props 而非执行段数据"
consumer: "admin"
change_type: "前端缺陷"
author: "wx(GIT)"
backend_status: "not_required"
gateway_status: "not_required"
frontend_status: "pending"
frontend_owner: "mmg"
frontend_ref: ""
target_release: ""
verified_at: ""
status_note: "后端零改动。已用测试服真实 API 核实(订单 26-3698,看板 GET /admin/fleet/board/orders/2086270138171994114):activeAssignments 返回 1 条完整执行段(vehiclePlate=蒙A-H7777 / vehicleModel=丰田汉兰达 / vehicleSeats=7 / driverName=阿拉坦 / driverPhone=135****5019 / startDate=08-17 / endDate=08-19),父层 confirmationAssignments 即取自该数据。根因在前端 Step4Confirm.vue:confirmationSegments.length<=1 时走单段分支,读的是父层 vehicle/driver props(= AssignModal 的 selVehicleObj/selDriverObj,useVehicleDriverPicker 的 UI 当前选中态),用户未做改派选择时为空 → 显示空白。应对单段分支也 fallback 到 confirmationSegments[0](或直接统一走 segments 分支)。"
updated_at: "2026-08-12"
base: "dev-v3"
---
# 确认执行页「车·师傅」多段/已派槽位显示空白(前端)
> **页面**:车务管理 → 派单看板 → 订单派车弹窗 → Step4「确认执行」→「车 · 师傅」区
> **后端**:本条**零改动**。下面结论来自测试服真实 API(订单 26-3698)。
---
## 一、现象
确认执行页(Step4)「车 · 师傅」区显示空白/不全:车辆「· · 座」、师傅「·」,明明该槽位已派 1 车 3 天。
## 二、后端已排除(数据完整)
`GET /admin/fleet/board/orders/2086270138171994114` → `activeAssignments` 返回 **1 条聚合执行段**:
```json
{
"vehiclePlate": "蒙A-H7777",
"vehicleModel": "丰田汉兰达",
"vehicleSeats": 7,
"driverName": "阿拉坦",
"driverPhone": "135****5019",
"serviceDate": null,
"startDate": "2026-08-17",
"endDate": "2026-08-19"
}
```
(单槽位聚合整段,startDate~endDate=3 天。字段完整,非空。)
## 三、根因(前端)
`AssignModal.vue` 把 `confirmationAssignments`(= `activeAssignments`)作为 `:assignments` 传给 `Step4Confirm.vue`,同时传 `:vehicle="selVehicleObj"` `:driver="selDriverObj"`。
`Step4Confirm.vue` 渲染逻辑(`confirmationSegments` computed):
- **多段分支**(`confirmationSegments.length > 1`):遍历 `confirmationSegments` 正确展示。
- **单段分支**(`length <= 1`,当前场景命中):读父层 props `vehicle?.plate / driver?.name` —— 即 `selVehicleObj/selDriverObj`(`useVehicleDriverPicker` 的 **UI 当前选中态**)。用户直接从已派状态进入 Step4 未做改派选择时,这两个对象为 **null** → 显示空白。
即:单段执行时错误依赖了「本次 UI 是否选中过车辆/司机」,而不是回退到服务端已有的执行段数据。
## 四、修复建议
- 单段分支也改为读 `confirmationSegments[0]`(vehiclePlate/vehicleModel/vehicleSeats + driverName/driverPhone),与多段分支同一数据源;
- 或直接去掉单段分支,统一走 `confirmationSegments` 遍历(数据已由父层聚合好)。
## 五、验收
- [ ] 已派 1 车 3 天的槽位进 Step4,「车·师傅」显示 蒙A-H7777 · 丰田汉兰达 · 7座 / 阿拉坦 · 135****5019
- [ ] 未做任何改派选择时也能正确回显(不再依赖 UI 选中态)
- [ ] 多段接续(同一槽位不同天不同车/司机)仍按段展示不受影响
+21 -2
查看文件
@@ -10,9 +10,11 @@
文件名:
```text
DD_issue_业务标题-{新增接口|修改接口|删除接口}-{管理后台|小程序端}.md
DD_issue_业务标题-{新增接口|修改接口|删除接口|修复|前端缺陷|前端优化|前端修复}-{管理后台|小程序端}.md
```
纯前端条目(无后端工单)issue 段写字面量 `frontend`,如 `10_frontend_标题-前端缺陷-管理后台.md`。
例如:
```text
@@ -44,10 +46,27 @@ target_release: ""
verified_at: ""
```
- 需要前端修改:`frontend_status: "pending"`
- 需要前端修改:`frontend_status: "pending"`(此时前端侧可回写 `frontend_owner` 认领 + `verified_at` 实测日期)
- 不需要前端修改:`frontend_status: "not_required"`
- 后端不要代替前端填写 `implemented`、`released` 或 `verified`
**`not_required` 条目任何人(含前端)不得回写 `frontend_owner` / `frontend_ref` / `target_release` / `verified_at`**——这 4 个字段是「前端需要动作」的认领/验收标记,`not_required` 语义是「前端零改动、无需认领」,填了就会被发布门禁(E_FRONTEND 残留校验)拦下。前端要表达「已知悉」用评论/口头即可,不动 frontmatter。若前端评估后认为其实需要适配,应把 `frontend_status` 改成 `pending` 再回写 owner,而不是在 `not_required` 上叠字段。(2026-08-19 #6077 实例:mmg 回写 `not_required` 条目的 `frontend_owner=mmg`+`verified_at`,合并后被门禁拦,清空后放行。)
## 2.1 发布门禁(硬规则,2026-08-10 wx 定)
**给前端推送的 changelog,内容必须是测试环境已经存在、可实测到的。**
- 接口类条目(新增接口/修改接口/删除接口):推送前必须走完「PR 合并 → 部署测试服 → 测试服真实 API 验证」,frontmatter 必须 `backend_status: "deployed"`,并在正文「验证证据」章节贴实测结果。
- `backend_status` 为 `merged` / `pending` / `implemented` 等未部署状态的条目**禁止 push**(校验规则 E_BACKEND_PENDING 会拦)。「先给前端契约、部署随后」的预告式推送一律禁止——前端拿到 changelog 会立刻联调,接口不在等于空耗与误判。
- 纯前端条目(前端缺陷/前端优化/前端修复):`backend_status: "not_required"`,change_type 用对应前端类型;`frontend_status: "not_required"` 时不得残留 frontend_owner / frontend_ref / target_release / verified_at。
- 背景:2026-08-06~08-07 三条未部署即推送的条目(#5599/#5567/#5633)导致前端在测试环境验不到字段(2026-08-10 投诉属实);当时仓库 CI 因校验规则假阳性长期常红被忽略,规则已于 2026-08-10 修正(前端条目类型合法化、`{orderId}` 路径参数不再误判为占位符),此后 **CI 红 = 真违规,必须当场修复回填**。
**推送校验(强制)**:
- 推荐一次性启用本地钩子,之后 push 自动拦截:`git config core.hooksPath .githooks`
- 未启用钩子则每次 push 前手动跑 §3 的两条校验命令,红了不许推。
- 仓库 CI(changelog-filename-gate)对每次 push 复检;push 后请回看 Gitea Actions 状态,红 X 必须当场处理。
## 2.5 写作方法论(对齐 yst 团队 changelog-conventions SKILL,2026-08-04 起执行)
**受众优先**:触达 `/admin/*` `/mp/*` `/v3/admin/*` `/v3/mp/*` 等对外前缀的改动**一律**写前端 changelog,哪怕"前端代码零改动"(前端 AI 可能有 workaround 需清理信号)。`/v3/internal/*` Feign 接口**必须拆出去**单独走后端 changelog,不许和 admin/mp 接口塞同一份(反例:# traveler 11 接口事故)。
+2
查看文件
@@ -4,6 +4,8 @@
`/v3/admin/*` 接口写入 `changelogs-v2/`:
项目例外:`/admin/fleet/*` 虽无 `/v3` 前缀,但由二期车管管理后台消费,同样写入 `changelogs-v2/`。
```text
changelogs-v2/YYYY-MM/DD_issue_业务标题-{新增接口|修改接口|删除接口}-管理后台.md
```
@@ -0,0 +1,392 @@
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>供应商详情资源信息分页 API 接口规范 · v1.0</title>
<style>
:root {
--ink: #172033;
--muted: #667085;
--line: #dfe5ef;
--soft: #f6f8fb;
--blue: #1677ff;
--blue-soft: #eaf3ff;
--green: #15803d;
--green-soft: #eaf8ef;
--amber: #a15c00;
--amber-soft: #fff7e6;
--red: #b42318;
--code: #101828;
}
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
margin: 0;
color: var(--ink);
background: #eef2f7;
font: 14px/1.65 -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif;
}
.page {
width: min(1180px, calc(100% - 40px));
margin: 28px auto 64px;
background: #fff;
border: 1px solid var(--line);
border-radius: 16px;
box-shadow: 0 18px 48px rgba(16, 24, 40, .08);
overflow: hidden;
}
header {
padding: 42px 48px 34px;
color: #fff;
background: linear-gradient(135deg, #123d78, #1677ff 68%, #39a0ff);
}
header h1 { margin: 10px 0 8px; font-size: 30px; line-height: 1.3; }
header p { margin: 0; opacity: .9; }
.eyebrow { font-size: 12px; letter-spacing: .12em; text-transform: uppercase; opacity: .78; }
.badges { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 22px; }
.badge {
display: inline-flex;
align-items: center;
min-height: 28px;
padding: 3px 10px;
border: 1px solid rgba(255,255,255,.35);
border-radius: 999px;
background: rgba(255,255,255,.14);
font-size: 12px;
}
main { padding: 12px 48px 54px; }
nav {
position: sticky;
top: 0;
z-index: 2;
display: flex;
gap: 20px;
margin: 0 -48px 24px;
padding: 13px 48px;
overflow-x: auto;
background: rgba(255,255,255,.96);
border-bottom: 1px solid var(--line);
backdrop-filter: blur(8px);
}
nav a { color: #344054; text-decoration: none; white-space: nowrap; font-size: 13px; }
nav a:hover { color: var(--blue); }
section { scroll-margin-top: 62px; padding-top: 22px; }
h2 { margin: 0 0 14px; font-size: 22px; }
h3 { margin: 24px 0 10px; font-size: 16px; }
p { margin: 8px 0; }
code {
padding: 2px 5px;
border-radius: 4px;
background: var(--soft);
color: #175cd3;
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
font-size: .93em;
}
pre {
margin: 12px 0;
padding: 18px 20px;
overflow: auto;
border-radius: 10px;
background: var(--code);
color: #d1e9ff;
font: 12px/1.65 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
pre code { padding: 0; color: inherit; background: transparent; }
table { width: 100%; border-collapse: collapse; margin: 12px 0 18px; }
th, td { padding: 10px 12px; border: 1px solid var(--line); text-align: left; vertical-align: top; }
th { background: var(--soft); color: #344054; font-weight: 600; }
td:first-child code { white-space: nowrap; }
.endpoint {
display: flex;
align-items: center;
gap: 10px;
margin: 12px 0 16px;
padding: 14px 16px;
border: 1px solid #b9d8ff;
border-radius: 10px;
background: var(--blue-soft);
overflow-x: auto;
}
.method { padding: 4px 9px; border-radius: 6px; color: #fff; background: var(--blue); font-weight: 700; }
.path { font: 600 14px/1.4 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; white-space: nowrap; }
.callout {
margin: 14px 0;
padding: 13px 15px;
border-left: 4px solid var(--blue);
border-radius: 6px;
background: var(--blue-soft);
}
.callout.ok { border-color: var(--green); background: var(--green-soft); }
.callout.warn { border-color: #f59e0b; background: var(--amber-soft); }
.callout strong { display: block; margin-bottom: 2px; }
.grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; margin: 16px 0; }
.card { padding: 15px; border: 1px solid var(--line); border-radius: 10px; background: #fff; }
.card b { display: block; margin-bottom: 4px; color: #344054; }
.card span { color: var(--muted); }
.status-ok { color: var(--green); font-weight: 700; }
.status-pending { color: var(--amber); font-weight: 700; }
ul, ol { padding-left: 22px; }
li + li { margin-top: 5px; }
footer { padding: 24px 48px; border-top: 1px solid var(--line); background: var(--soft); color: var(--muted); }
@media (max-width: 760px) {
.page { width: 100%; margin: 0; border: 0; border-radius: 0; }
header, main, footer { padding-left: 20px; padding-right: 20px; }
nav { margin-left: -20px; margin-right: -20px; padding-left: 20px; padding-right: 20px; }
.grid { grid-template-columns: 1fr; }
table { display: block; overflow-x: auto; white-space: nowrap; }
}
@media print {
@page { size: A4; margin: 14mm; }
body { background: #fff; }
.page { width: 100%; margin: 0; border: 0; box-shadow: none; }
header { print-color-adjust: exact; -webkit-print-color-adjust: exact; }
nav { display: none; }
main { padding: 10px 0 20px; }
footer { padding: 16px 0 0; }
section { break-inside: avoid-page; }
pre { white-space: pre-wrap; word-break: break-word; }
a { color: inherit; text-decoration: none; }
}
</style>
</head>
<body>
<article class="page">
<header>
<div class="eyebrow">HL Supplier API · Admin</div>
<h1>供应商详情资源信息分页 API 接口规范</h1>
<p>v1.0 · Issue #6316 · 2026-08-25</p>
<div class="badges">
<span class="badge">已实现 · 可联调</span>
<span class="badge">后端 deployed</span>
<span class="badge">Gateway verified</span>
<span class="badge">前端 pending</span>
<span class="badge">只读接口</span>
</div>
</header>
<main>
<nav aria-label="文档目录">
<a href="#overview">概览</a>
<a href="#request">请求</a>
<a href="#response">响应</a>
<a href="#fields">字段</a>
<a href="#semantics">业务口径</a>
<a href="#errors">错误码</a>
<a href="#frontend">前端接入</a>
<a href="#verification">验证</a>
<a href="#rollback">撤回</a>
</nav>
<section id="overview">
<h2>1. 接口概览</h2>
<div class="endpoint"><span class="method">GET</span><span class="path">/admin/supplier/items/{supplierId}/resource-info/page</span></div>
<p>用于供应商管理详情页“资源信息”页签,分页展示该供应商当前有效关系对应的资源权威信息。关系来源为本系统 <code>supplier_resource_rel</code>;Resource 提供九类本地资源,Fleet 提供车辆资源。</p>
<div class="grid">
<div class="card"><b>实现状态</b><span class="status-ok">已实现 · 可联调</span></div>
<div class="card"><b>调用方</b><span>管理后台;前端接入待完成</span></div>
<div class="card"><b>数据副作用</b><span>无写库、Redis、MQ、配置或审计副作用</span></div>
</div>
<div class="callout ok"><strong>契约真相</strong>本文以合并提交 <code>4f032cd6f</code> 的 Controller、请求/响应 VO、Service 权限门禁及 TEST Gateway 验收为准。</div>
</section>
<section id="request">
<h2>2. 请求契约</h2>
<h3>2.1 路径与查询参数</h3>
<table>
<thead><tr><th>参数</th><th>位置</th><th>类型</th><th>必填</th><th>约束与默认值</th></tr></thead>
<tbody>
<tr><td><code>supplierId</code></td><td>path</td><td>string</td><td>是</td><td>正整数;Snowflake ID 必须按字符串传递</td></tr>
<tr><td><code>page</code></td><td>query</td><td>integer</td><td>否</td><td>默认 1,最小 1;公共分页兼容 <code>pageNo</code></td></tr>
<tr><td><code>pageSize</code></td><td>query</td><td>integer</td><td>否</td><td>默认 20,范围 1..100</td></tr>
<tr><td><code>resourceModule</code></td><td>query</td><td>string</td><td>否</td><td>为空查询全部;非空按关系冻结模块精确筛选</td></tr>
</tbody>
</table>
<h3>2.2 支持的资源模块</h3>
<table>
<thead><tr><th>编码</th><th>moduleName</th><th>数据归属</th></tr></thead>
<tbody>
<tr><td><code>SCENIC</code></td><td>景区管理</td><td>Resource</td></tr>
<tr><td><code>RESTAURANT</code></td><td>餐厅管理</td><td>Resource</td></tr>
<tr><td><code>SUPPLIES</code></td><td>备品管理</td><td>Resource</td></tr>
<tr><td><code>SUPPLIES_COMBO</code></td><td>组合配品</td><td>Resource</td></tr>
<tr><td><code>ACTIVITY</code></td><td>游玩项目管理</td><td>Resource</td></tr>
<tr><td><code>HOTEL</code></td><td>酒店管理</td><td>Resource</td></tr>
<tr><td><code>SERVICE</code></td><td>服务管理</td><td>Resource</td></tr>
<tr><td><code>COST_ITEM</code></td><td>额外成本</td><td>Resource</td></tr>
<tr><td><code>STAFF</code></td><td>服务人员管理</td><td>Resource</td></tr>
<tr><td><code>VEHICLE</code></td><td>车队管理-车队管理</td><td>Fleet(内部批量聚合)</td></tr>
</tbody>
</table>
<h3>2.3 调用示例</h3>
<pre><code>GET /admin/supplier/items/2091715622923657217/resource-info/page?page=1&amp;pageSize=20&amp;resourceModule=SCENIC
Authorization: Bearer &lt;有效管理端访问令牌&gt;</code></pre>
<div class="callout warn"><strong>权限是双门禁</strong>服务端仅允许 ADMIN、FINANCE、SUPER_ADMIN,并同时要求 <code>supplier:view</code> 与 <code>supplier:resource:view</code>。不能只通过隐藏页签代替服务端授权。</div>
</section>
<section id="response">
<h2>3. 响应结构</h2>
<p>统一返回 <code>Result&lt;PageResult&lt;SupplierResourceInfoRespVO&gt;&gt;</code>。业务失败通常仍是 HTTP 200,调用方必须检查 <code>code</code>、<code>success</code> 与 <code>message</code>。</p>
<pre><code>{
"code": 200,
"message": "success",
"success": true,
"data": {
"records": [
{
"relationId": "2091715622923657218",
"resourceModule": "SCENIC",
"moduleName": "景区管理",
"resourceId": "2091715622923657001",
"resourceName": "示例景区",
"coverUrl": null,
"city": "海拉尔",
"isCharged": true,
"isChargedName": "是",
"settleTypeCode": "CASH",
"settleTypeName": "现付",
"tags": [
{ "tagId": "2084636804090089473", "tagName": "自然风光", "tagColor": "#52C41A" }
],
"seasons": [
{ "seasonCode": "spring", "seasonName": "春" }
],
"statusCode": "ENABLED",
"statusName": "启用",
"enabled": true,
"resourceAvailable": true,
"updateTime": "2026-08-25 10:00:00"
}
],
"total": 1,
"page": 1,
"pageSize": 20
}
}</code></pre>
</section>
<section id="fields">
<h2>4. records[] 字段</h2>
<table>
<thead><tr><th>字段</th><th>类型</th><th>可空</th><th>说明</th></tr></thead>
<tbody>
<tr><td><code>relationId</code></td><td>string</td><td>否</td><td>供应商资源关系 ID</td></tr>
<tr><td><code>resourceModule</code></td><td>string</td><td>否</td><td>关系冻结的资源模块编码</td></tr>
<tr><td><code>moduleName</code></td><td>string</td><td>否</td><td>模块中文名</td></tr>
<tr><td><code>resourceId</code></td><td>string</td><td>否</td><td>资源 ID;资源缺失仍保留关系原值</td></tr>
<tr><td><code>resourceName</code></td><td>string</td><td>是</td><td>当前资源名称</td></tr>
<tr><td><code>coverUrl</code></td><td>string</td><td>是</td><td>当前有效封面 URL</td></tr>
<tr><td><code>city</code></td><td>string</td><td>是</td><td>城市展示值</td></tr>
<tr><td><code>isCharged</code></td><td>boolean</td><td>是</td><td>是否收费;不适用/未知为 null</td></tr>
<tr><td><code>isChargedName</code></td><td>string</td><td>是</td><td>是否收费中文名</td></tr>
<tr><td><code>settleTypeCode</code></td><td>string</td><td>是</td><td>结算方式编码</td></tr>
<tr><td><code>settleTypeName</code></td><td>string</td><td>是</td><td>结算方式中文名</td></tr>
<tr><td><code>tags</code></td><td>array</td><td>否</td><td>标签列表;无数据为 []</td></tr>
<tr><td><code>seasons</code></td><td>array</td><td>否</td><td>标准季节列表;无数据为 []</td></tr>
<tr><td><code>statusCode</code></td><td>string</td><td>是</td><td>资源当前权威状态编码</td></tr>
<tr><td><code>statusName</code></td><td>string</td><td>是</td><td>归一化状态中文名</td></tr>
<tr><td><code>enabled</code></td><td>boolean</td><td>是</td><td>归一化启用标记</td></tr>
<tr><td><code>resourceAvailable</code></td><td>boolean</td><td>否</td><td>false 表示关系保留但资源已删除/缺失</td></tr>
<tr><td><code>updateTime</code></td><td>string</td><td>是</td><td>资源本身更新时间;yyyy-MM-dd HH:mm:ss</td></tr>
</tbody>
</table>
<h3>4.1 子结构</h3>
<table>
<thead><tr><th>数组</th><th>字段</th><th>说明</th></tr></thead>
<tbody>
<tr><td><code>tags[]</code></td><td><code>tagId</code>、<code>tagName</code>、<code>tagColor</code></td><td>标签 ID 沿用各资源模块的字符串表达</td></tr>
<tr><td><code>seasons[]</code></td><td><code>seasonCode</code>、<code>seasonName</code></td><td>标准季节编码与中文名</td></tr>
</tbody>
</table>
</section>
<section id="semantics">
<h2>5. 业务口径</h2>
<ul>
<li>只读取当前有效的供应商资源关系,按关系 <code>update_time DESC, rel_id DESC</code> 稳定排序。</li>
<li>响应中的 <code>updateTime</code> 是资源主数据更新时间,不是关系更新时间。</li>
<li>标量字段不适用、未知或资源缺失时返回 <code>null</code>;<code>tags</code> 与 <code>seasons</code> 永远返回数组。</li>
<li>资源被软删除或不存在时不丢弃关系行:<code>resourceAvailable=false</code>,名称、状态、更新时间等当前资源字段为 null。</li>
<li>十类资源以本系统权威数据为准;展示形式可参考现有资源列表,但不要从参考图硬编码字段值或状态。</li>
<li>供应商处于草稿、审批中、合作中、暂停、黑名单、归档等任意生命周期状态时均可只读查询。</li>
<li>Fleet/字典依赖出现空响应、非成功、重复、缺失、额外或非法数据时返回 395039,不降级为部分成功。</li>
</ul>
<div class="callout"><strong>内部依赖说明</strong>Resource 通过内部 Token 调用 <code>POST /internal/fleet/vehicles/supplier-resource-info/batch</code> 聚合车辆信息。该路径不面向管理端,前端不得调用、转发或持有内部 Token。</div>
</section>
<section id="errors">
<h2>6. 错误码</h2>
<table>
<thead><tr><th>业务码</th><th>场景</th><th>管理端建议</th></tr></thead>
<tbody>
<tr><td><code>401</code></td><td>未认证或登录态失效</td><td>按统一登录续期/退出逻辑处理</td></tr>
<tr><td><code>400</code></td><td>supplierId、page 或 pageSize 等参数不合法</td><td>修正请求,不自动重试</td></tr>
<tr><td><code>395001</code></td><td>供应商不存在</td><td>关闭失效详情或刷新列表</td></tr>
<tr><td><code>395034</code></td><td>resourceModule 不受支持</td><td>仅使用本文十个稳定编码</td></tr>
<tr><td><code>395039</code></td><td>Fleet、字典或资源必要依赖不可用/响应不完整</td><td>提示稍后重试,不展示旧数据冒充成功</td></tr>
</tbody>
</table>
<pre><code>{
"code": 395034,
"message": "不支持的资源模块",
"data": null,
"success": false
}</code></pre>
</section>
<section id="frontend">
<h2>7. 管理端接入清单</h2>
<ol>
<li>在供应商详情“账号信息”页签后新增“资源信息”页签;仅在页签打开时加载数据。</li>
<li>建议列:资源名称(封面 + 名称)、资源模块、城市、是否收费、结算方式、标签、季节、状态、更新时间。</li>
<li>所有 ID 按字符串保存、传参和比较,禁止转换为 JavaScript number。</li>
<li>优先展示服务端中文字段;未知字段显示“—”,不得前端猜测状态或字典名称。</li>
<li><code>resourceAvailable=false</code> 时保留行并明确显示“资源已删除/不可用”。</li>
<li>模块筛选或页容量改变时回到第 1 页;pageSize 最大 100。</li>
<li>按 <code>code/success</code> 判断业务结果;不要仅依据 HTTP 200。</li>
<li>页签为只读展示,不增加绑定、改绑、解绑、启停或删除按钮。</li>
</ol>
<h3>7.1 建议验收场景</h3>
<table>
<thead><tr><th>场景</th><th>预期</th></tr></thead>
<tbody>
<tr><td>有资源关系</td><td>按分页显示,中文字段、数组、字符串 ID 正常</td></tr>
<tr><td>无资源关系</td><td>records=[]、total=0,不显示错误空态</td></tr>
<tr><td>按模块筛选</td><td>返回行的 resourceModule 全部等于筛选值</td></tr>
<tr><td>关系存在但资源缺失</td><td>保留关系行,resourceAvailable=false</td></tr>
<tr><td>无双权限/未登录</td><td>服务端拒绝,页面不泄露数据</td></tr>
<tr><td>依赖暂不可用</td><td>展示 395039 对应提示,不展示不完整成功页</td></tr>
</tbody>
</table>
</section>
<section id="verification">
<h2>8. 实现与验收状态</h2>
<ul>
<li><strong>代码:</strong>PR #6330 已合并 <code>dev-v3</code>,合并提交 <code>4f032cd6f6698607a2f1524437533d595975fc9a</code>。</li>
<li><strong>自动化:</strong>Resource 全量 2043 项零失败;Fleet 可运行全量 3853 项零失败;GatewayRouteAuditTest 3 项零失败;独立审计套件再次通过。</li>
<li><strong>TEST:</strong>任务 <code>cc1fe248</code>、<code>2697d374</code> 精确部署同一合并提交,Resource/Fleet 双实例与 Nacos 各 2 实例健康。</li>
<li><strong>真实 Gateway:</strong>有效管理端会话只读查询 3 个供应商,实际取得 1 条 SCENIC 关系;18 字段、字符串 ID、数组、时间和模块筛选均通过。</li>
<li><strong>负向:</strong>395001、395034、page/pageSize 参数 400 与未认证 401 均实测通过。</li>
<li><strong>车辆样本:</strong>TEST 当时无 VEHICLE 供应商关系;未伪造数据,跨服务路径由双服务真实部署健康与内部契约/批量/失败关闭测试覆盖。</li>
<li><strong>环境恢复:</strong>任务 <code>45e843e5</code>、<code>c05eda6e</code> 已回切包含本次合并的 <code>dev-v3</code>;Resource 8082/8182、Fleet 8087/8187 及 Nacos 各 2 个实例健康,临时部署分支已删除。</li>
</ul>
<div class="callout ok"><strong>数据清理</strong>TEST 验收全部为 GET 只读请求,没有创建或修改供应商、资源、数据库、Redis、MQ 或配置数据。</div>
</section>
<section id="rollback">
<h2>9. 撤回方案</h2>
<ol>
<li>从最新 <code>dev-v3</code> 创建回退分支,执行 <code>git revert -m 1 --no-edit 4f032cd6f6698607a2f1524437533d595975fc9a</code>,经独立 PR 合入。</li>
<li>依次重新构建并滚动部署 Resource、Fleet,分别保持双实例可用。</li>
<li>本次无数据库、Redis、MQ、Nacos 或其他配置变更,无需 DDL、DML、缓存清理、消息补偿或配置恢复,也无不可逆影响。</li>
<li>管理端停止调用新增 GET 和读取本次字段;既有供应商详情、账号和资源管理接口不受影响。</li>
<li>经 Gateway 复测新增路径撤回、既有供应商详情正常,并确认两服务双实例和 Nacos 健康。</li>
</ol>
</section>
</main>
<footer>
关联:Issue #6316 · PR #6330 · 后端负责人 @lc · 本文件为可离线、可打印单页接口规范。
</footer>
</article>
</body>
</html>
@@ -0,0 +1,234 @@
---
schema: "hl-changelog/v2"
ticket: "6207"
title: "AI 推荐产品多维筛选开放接口(免登录,排除私人定制)"
consumer: "mp"
author: "wx(GIT)"
change_type: "新增接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "pending"
frontend_owner: "mmg"
frontend_ref: ""
target_release: ""
verified_at: "2026-08-23"
status_note: "GET /mp/product/ai-recommend 免登录开放接口,AI 推荐用。默认返回 PUBLISHED + CORE/GROUP(排除 CUSTOM 私人定制),支持多维筛选。后端/网关已测试服验证,前端待消费。"
updated_at: "2026-08-23"
base: "dev-v3"
---
# 【新增接口·小程序端】AI 推荐产品多维筛选开放接口(#6207)
> **PR**: #6220 | **服务**: hl-mp-service / hl-product-service-v2 / hl-gateway | **作者**: wx | **更新时间**: 2026-08-23
> 免登录开放接口,供 AI 做产品推荐调用。**除私人定制(CUSTOM)以外的全部已上架(PUBLISHED)产品**,多维筛选,全部条件可选可组合。
---
## 一、背景
AI 做产品推荐需要一个查询接口:能筛选除私人定制以外的全部已上架产品,条件越多越好(目的地、天数、报价范围、团期、包含资源、人数、季节等),**不需要登录**。
---
## 二、变更接口清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|------|------|------|----------|------|
| 1 | AI推荐产品查询 | GET | `/mp/product/ai-recommend` | 🆕 新增 | 免登录,多维筛选,分页 |
> 网关白名单已放行(`JwtAuthFilter` SKIP_URLS),无 token 可直接调用。
---
## 三、接口详情
### 1. AI推荐产品查询 `GET /mp/product/ai-recommend`
BFF 透传至 product-service `GET /internal/mp/product/ai-query`。pageSize 最大 50。
**数据范围(硬性)**:
- `product.status = PUBLISHED`(已上架)
- `product_type IN (CORE, GROUP)`(**排除 CUSTOM 私人定制**)
#### 入参(全部可选,可任意组合)
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|------|------|------|------|------|------|
| keyword | Query | String | 否 | ≤100 字符 | 关键词/目的地(匹配产品名/副标题) |
| productType | Query | String | 否 | CORE/GROUP | 产品类型(默认 CORE+GROUP,传单一值可收窄) |
| category | Query | String | 否 | family/honeymoon/photography/experience/driving | 产品分类 |
| lineId | Query | Long | 否 | - | 产品线ID |
| minDays | Query | Integer | 否 | ≥1 | 最短天数 |
| maxDays | Query | Integer | 否 | ≥1 | 最长天数 |
| seasons | Query | String | 否 | spring/summer/autumn/winter,逗号分隔多值 | 季节 |
| tags | Query | String | 否 | 逗号分隔多值 | 产品标签 |
| minPrice | Query | BigDecimal | 否 | - | 最低起步价 |
| maxPrice | Query | BigDecimal | 否 | - | 最高起步价 |
| startDate | Query | String | 否 | yyyy-MM-dd | 出发日期起始 |
| endDate | Query | String | 否 | yyyy-MM-dd | 出发日期结束 |
| partySize | Query | Integer | 否 | ≥1 | 人数(仅与 startDate+endDate 组合时生效,过滤「订不下」的产品) |
| resourceType | Query | String | 否 | SCENIC/ACTIVITY/RESTAURANT/SERVICE/CUSTOM | 包含资源类型 |
| resourceKeyword | Query | String | 否 | - | 包含资源关键词 |
| orderBy | Query | String | 否 | sort/price_asc/price_desc/newest | 排序 |
| page | Query | Integer | 否 | 默认1,≥1 | 页码 |
| pageSize | Query | Integer | 否 | 默认10,1~50 | 每页条数(**最大 50**,>50 返 400) |
> **seasons/tags 传法**:逗号分隔多值,如 `seasons=summer,winter`、`tags=亲子,摄影`。
#### 出参 `Result<PageResult<MpProductAiQueryItemVO>>`
| 字段 | 类型 | 说明 |
|------|------|------|
| records[].productId | String | 产品ID(雪花,字符串防精度丢失) |
| records[].productNo | String | 产品编号 |
| records[].productType | String | CORE/GROUP |
| records[].name | String | 产品名称 |
| records[].subtitle | String | 副标题 |
| records[].introduction | String | 产品简介 |
| records[].category | String | 产品分类 |
| records[].tripDays / tripNights | Integer | 天数 / 晚数 |
| records[].coverImageUrl | String | 封面图 |
| records[].carouselImages | String[] | 轮播图 |
| records[].tags / seasons | String[] | 标签 / 季节 |
| records[].lineId | String | 产品线ID |
| records[].lineName | String | 产品线名称 |
| records[].startPrice | String | 起步价(字符串) |
| records[].startPriceLabel | String | `¥3980起/人` |
| records[].paymentType | String | FULL / DEPOSIT |
| records[].status | String | PUBLISHED |
| records[].sortOrder | Integer | 排序号 |
| records[].earliestBookingDate | String | 最早可订日期 yyyy-MM-dd |
| records[].availableDateSummary | String | 可订日期摘要(如 `2026-09-11 起`) |
| records[].availabilitySummary | String | 余位摘要(GROUP: `8个班期可报名,余位充足(2026-09-11 ~ 2026-10-30)`;CORE: `9天可订(2026-08-23 ~ 2026-08-31)`) |
| records[].matchedDestinations | String[] | 匹配到的目的地/途经点摘要 |
| total | Integer | 总条数 |
| page / pageSize | Integer | 页码 / 每页条数 |
#### 请求示例
```
GET /mp/product/ai-recommend?productType=GROUP&seasons=summer&minPrice=0&maxPrice=20000&page=1&pageSize=5
```
#### 响应示例(测试服实测)
```json
{
"code": 200,
"message": "成功",
"data": {
"records": [
{
"productId": "2056947670512971778",
"productNo": "G260423004",
"productType": "GROUP",
"name": "测试小蒙马-多档-固定金额",
"subtitle": "",
"introduction": "测试产品简介",
"category": "photography",
"tripDays": 5,
"tripNights": 4,
"coverImageUrl": "https://hlgl-test.oss-cn-beijing.aliyuncs.com/...",
"tags": ["小蒙马"],
"seasons": ["summer"],
"lineId": "2001",
"lineName": "测试产品线",
"startPrice": "8800.00",
"startPriceLabel": "¥8800起/人",
"paymentType": "FULL",
"status": "PUBLISHED",
"sortOrder": 0,
"earliestBookingDate": "2026-09-11",
"availableDateSummary": "2026-09-11 起",
"availabilitySummary": "8个班期可报名,余位充足(2026-09-11 ~ 2026-10-30)"
}
],
"total": 5,
"page": 1,
"pageSize": 5
},
"success": true
}
```
#### 空数据响应(无匹配条件)
```json
{
"code": 200,
"message": "成功",
"data": { "records": [], "total": 0, "page": 1, "pageSize": 5 },
"success": true
}
```
#### 错误响应(参数防御)
```json
{
"code": 400,
"message": "每页条数不能大于50",
"data": null,
"success": false
}
```
---
## 四、契约约束与正确调用方式
### 筛选语义(后端为准)
- **所有条件 AND 组合**:同时传多个条件时,返回同时满足全部条件的产品。
- **seasons / tags 多值取 OR**:`seasons=summer,winter` 表示「夏季 **或** 冬季」。
- **报价范围按起步价过滤**:起步价 = GROUP 未来班期最低成人价 或 CORE 价格日历未来最低价,`minPrice/maxPrice` 作用于该值。
- **人数(partySize)过滤语义**:**仅当同时传了出发日期范围(startDate/endDate 至少一个)+ partySize 才生效**——过滤「订不下」的产品:
- GROUP:看日期范围内是否有余位 ≥ partySize 的可报名班期(ENROLLING/NEARLY_FULL)
- CORE:看日期范围内是否有库存(dailyStock - sold)≥ partySize 的日期
- **只传 partySize 不传日期 → 不触发人数过滤**。
- **目的地关键词**:匹配产品名/副标题 **或** 途经点名称 **或** 行程节点名称(任一处命中即算)。
- **日期倒置自动修正**:startDate 晚于 endDate 时后端自动交换,不报错。
### ✅ 正确 / ⚠️ 注意
| 场景 | 行为 |
|------|------|
| ✅ 无条件调用 | 返回全部在售(CORE+GROUP 且 PUBLISHED)分页 |
| ✅ `seasons=summer,winter` | 夏季或冬季的产品 |
| ✅ `minPrice=1000&maxPrice=5000` | 起步价在区间内的产品 |
| ✅ `startDate=2026-09-01&endDate=2026-10-01&partySize=2` | 该日期范围内能订下 2 人的产品 |
| ⚠️ `pageSize=999` | 400 拒绝(上限 50) |
| ⚠️ 只传 `partySize` 不传日期 | 人数条件不生效 |
---
## 五、测试环境已验证(2026-08-23)
```
GET /mp/product/ai-recommend?page=1&pageSize=5 → 200 total=22 ✓
GET /mp/product/ai-recommend?keyword=草原&page=1&pageSize=5 → 200 total=13 ✓
GET /mp/product/ai-recommend?productType=GROUP&page=1&pageSize=3 → 200 total=6 ✓
GET /mp/product/ai-recommend?category=family&page=1&pageSize=5 → 200 total=12 ✓
GET /mp/product/ai-recommend?seasons=summer,winter&page=1&pageSize=5 → 200 total=19 ✓
GET /mp/product/ai-recommend?minPrice=1000&maxPrice=5000&page=1&pageSize=3 → 200 ✓
GET /mp/product/ai-recommend?orderBy=price_asc&page=1&pageSize=5 → 200 ✓(第一条约 2980 便宜档)
GET /mp/product/ai-recommend?productType=GROUP&seasons=summer&minPrice=0&maxPrice=20000 → 200 total=5 ✓
GET /mp/product/ai-recommend?startDate=2026-08-24&endDate=2026-10-22 → 200 total=14 ✓
GET /mp/product/ai-recommend?pageSize=999 → 400 每页条数不能大于50 ✓
GET /mp/product/ai-recommend?category=driving&seasons=winter&keyword=不存在xyz → 200 empty ✓
```
免登录(无 token)经网关调用全部返回 200。
---
## 六、相关历史
- 关联 Issue: [wx/HL#6207](https://git.1814.love:8443/wx/HL/issues/6207)
- 关联 PR: [wx/HL#6220](https://git.1814.love:8443/wx/HL/pulls/6220)
### 联系人
- **后端负责人**: @wx
- **前端负责人**: @mmg
@@ -1,4 +1,5 @@
---
author: "yst(GIT)"
schema: "hl-changelog/v2"
ticket: "5380"
title: "核单人员页签收口与车辆空态契约"
@@ -623,3 +624,13 @@ Authorization: Bearer JWT_TOKEN
### 13.2 联系人
- **后端负责人**: @yst
## 关联/联系人
### 链接
- [后端工单 #5380](https://git.1814.love:8443/wx/HL/issues/5380)
### 联系人
- **后端负责人**: @yst
@@ -1,4 +1,5 @@
---
author: "wx(GIT)"
schema: "hl-changelog/v2"
ticket: "5374"
title: "保险任务与派单候选补齐真实团号契约"
@@ -1,4 +1,5 @@
---
author: "wx(GIT)"
schema: "hl-changelog/v2"
ticket: "5336"
title: "修改派单 requestId 持久幂等:同键重放冻结结果、不同载荷 605059"
@@ -1,4 +1,5 @@
---
author: "wx(GIT)"
schema: "hl-changelog/v2"
ticket: "5364"
title: "连续执行段司机通知、回复与整组确认隔离"
@@ -7,9 +7,9 @@ change_type: "修改接口"
author: "yaosutu(GIT)"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "pending"
frontend_owner: ""
frontend_ref: ""
frontend_status: "implemented"
frontend_owner: "pi-main-session"
frontend_ref: "hl-admin@5925a3ff810b5ef0dbce027a0057e343a1910446"
target_release: ""
verified_at: "2026-08-04T22:35:00+08:00"
status_note: "PR #5501 已合并 dev-v3;deploy-panel 任务 0eae2ffb 成功,hl-order-service-v3 8086/8186 双实例 UP。已通过有效管理后台鉴权验证 Gateway 合同列表 12 个只读用例与目标合同详情;列表/详情 teamNo 一致。QA 报告因未保存含 PII 的详情截图仍为 PARTIAL,不影响已完成的运行时功能门禁。"
@@ -875,3 +875,15 @@ name:string!(max64),mchId:string!(max32),appId:string!(max64),apiV3Key:string!,m
- **Head commit**: [f66d236f2aea2d0a63db8cb58d59f2ae74e2b6fb](https://git.1814.love:8443/wx/HL/commit/f66d236f2aea2d0a63db8cb58d59f2ae74e2b6fb)
- **前置契约**: PR #5386 / commit `c9d1b12618` 的 `teamNo` 与 v3 写侧说明
- **后端负责人**: 腰苏图
## 关联/联系人
### 链接
- [后端工单 #5368](https://git.1814.love:8443/wx/HL/issues/5368)
- [后端 PR #5501](https://git.1814.love:8443/wx/HL/pulls/5501)
- Merge commit: `45117d3d58`
### 联系人
- **后端负责人**: @wx
@@ -5,7 +5,7 @@ title: "Step2 canonical full snapshot 与稳定槽位"
consumer: "admin"
author: "wx(GIT)"
change_type: "修改接口"
backend_status: "released"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "verified"
frontend_owner: "Pi"
@@ -1,4 +1,5 @@
---
author: "wx(GIT)"
schema: "hl-changelog/v2"
ticket: "5463"
title: "派单司机/员工手机号密文解密失败降级容错"
@@ -588,3 +588,15 @@ POST、PUT 返回单个 `OtherIncomeItem`;GET 返回 `items[] + deductions[] +
- **后端负责人**: @yaosutu
- **QA 验证**: Issue #5477 接口验收已完成(管理后台真实网关,TARGETED_FALLBACK)
## 关联/联系人
### 链接
- [后端工单 #5477](https://git.1814.love:8443/wx/HL/issues/5477)
- [后端 PR #5488](https://git.1814.love:8443/wx/HL/pulls/5488)
- Merge commit: `da1ee4ebc1`
### 联系人
- **后端负责人**: @yst
@@ -1,4 +1,5 @@
---
author: "wx(GIT)"
schema: "hl-changelog/v2"
ticket: "5479"
title: "看板列表同槽位跨段换车 assignmentSlots 按派车组拆分"
@@ -8,7 +9,7 @@ backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "pi-main-session"
frontend_ref: "e0c5f4f75087107fd0d82fbdc104c76d732292dc"
frontend_ref: "hl-admin@e0c5f4f75087107fd0d82fbdc104c76d732292dc"
target_release: ""
verified_at: "2026-08-04"
status_note: "看板列表 assignmentSlots 修复:同槽位跨段换车(同 slot 多 assignment_group_id)时由仅返回首段改为按派车组返回多段(每段含各自区间/车辆/司机/司机手机号);slotSummary 各段区间合计覆盖全槽;单段槽位行为不变。前端若按单条槽位渲染需适配多段展示。"
@@ -95,3 +95,15 @@ base: "dev-v3"
- order-v3:`OrderDetailConverterTest` 新增零值 scale=2 + 序列化断言(41/41),order-v3 verify 7443 例全过。
- 网关 TEST 实测(#5482):finance 零值 `balancePaidAmount="0.00"`/`fullPaidAmount="0.00"` 与 `totalAmount="1000.00"` 同形态(部署前 `"0"`)。
- 网关 TEST(#5480):当前环境无候选车辆需求数据(全需求 vehicles=0),端到端候选金额验证暂不可行;由序列化单测(protocolPrice="860.00" String 断言)+ 同 VO dailyVehicleFees String 回归 + 代码注解证据覆盖。
## 关联/联系人
### 链接
- [后端工单 #5480](https://git.1814.love:8443/wx/HL/issues/5480)
- [后端 PR #5487](https://git.1814.love:8443/wx/HL/pulls/5487)
- Merge commit: `cbf08a4c02`
### 联系人
- **后端负责人**: @wx
@@ -1,4 +1,5 @@
---
author: "wx(GIT)"
schema: "hl-changelog/v2"
ticket: "5505"
title: "HOLD 派车短信空串 code 降级:不再被阿里云拒收,通知链路收敛"
@@ -6,7 +7,7 @@ consumer: "admin"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "pending"
frontend_status: "not_required"
frontend_owner: ""
frontend_ref: ""
target_release: ""
@@ -0,0 +1,79 @@
---
schema: "hl-changelog/v2"
ticket: "5520"
title: "保险订单 totalPremium 恒 0 修复(保游金额字符串解析)"
consumer: "admin"
change_type: "修改接口"
author: "wx(GIT)"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "pi-main-session"
frontend_ref: "hl-admin@ef497e8e30d2df2d55d97f5554c8c5e921dc49ef"
target_release: ""
verified_at: ""
status_note: "后端完成:PR #5521 已合并 dev-v3 并部署 TEST;网关实测新投保 totalPremium=\"88.00\"(修复前恒 \"0\"),DB 落库 88.00 与 raw_response 一致;存量 252 行已回填全量一致 253/253。行为修复:保单列表/详情/详情弹窗的 totalPremium 从恒 0 变为平台实际保费。"
updated_at: "2026-08-04"
base: "dev-v3"
---
# 保险订单 totalPremium 恒 0 修复(#5520)
> **服务**: hl-order-service-v3(+hl-fleet-service 对账联动)
> **PR**: #5521
> **Issue**: #5520(P1)
> **联系人**: @wx
> **日期**: 2026-08-04
> **影响范围**: 管理后台司机保险保单列表/详情 totalPremium 展示、退保/对账金额计算
---
## 变更说明
**根因**:jackson-databind 2.13 的 `TextNode` 未覆盖 `decimalValue()`,保游响应中的字符串金额节点(`"TotalPremium":"88.00"`)调用时走基类默认实现恒返回 `BigDecimal.ZERO`,导致投保落库 `insurance_order.total_premium` 恒 0.00。
**修复**:新增 `BaoyouMoney` 安全解析(数值节点走 decimalValue、文本节点按 BigDecimal 解析、null/空串/非法兜底),替换保险链路 5 处金额解析(投保落库 TotalPremium、保单查询 TotalPremium、回调 OrderMoney、保游余额 Balance、费率 Premium)。
## 变更接口
| 方法 | 路径 | 来源 |
|---|---|---|
| POST | /admin/fleet/drivers/{driverId}/insurance/purchase | 管理后台-司机保险 |
| GET | /admin/fleet/drivers/{driverId}/insurance/policies | 管理后台-司机保险 |
| POST | /admin/fleet/drivers/{driverId}/insurance/policies/{insuranceOrderId}/cancel | 管理后台-司机保险 |
| GET | /admin/fleet/reconciliation/insurance | 管理后台-保险对账 |
## 接口行为变化
| 接口 | 字段 | 修复前 | 修复后 |
|---|---|---|---|
| `POST /admin/fleet/drivers/{driverId}/insurance/purchase` | totalPremium | `"0"`(恒) | `"88.00"`(平台实际保费) |
| `GET /admin/fleet/drivers/{driverId}/insurance/policies` | totalPremium | `"0"` | `"88.00"` |
| 退保链路 | 退费计算基数 | 0 | 平台实际保费 |
| 保险对账(baoyou 口径) | 摊销金额 | 0 | 保单实际保费(新链路) |
字段类型、命名、契约结构均无变化,仅值语义修正。
## 存量数据
- TEST 环境 252 行存量保单(245 INSURED + 7 CANCELLED)已按 `raw_response.TotalPremium` 精确回填 `total_premium=88.00`,全量 253/253 与平台响应一致。
- 存量 `fleet_insurance_task` 任务快照 premium_amount=0 为历史创建时未关联保单 id 的派生快照,不做模糊回填(避免错配);新链路任务金额从保单 total_premium 复制自动正确。
## 验证证据
- 网关实测(api.test.1814.love:9443,admin,2026-08-04):新投保 totalPremium="88.00"(修复前恒 "0"),DB total_premium=88.00 与 raw_response 一致
- 存量 252 行回填后全量 253/253 raw==列 一致;退保金额保持 88.00、update_time 刷新
- 定向测试:BaoyouMoneyTest 4/4 + savePurchaseResult 字符串金额回归,保险域 354/354 全绿(PR #5521)
## 关联/联系人
### 链接
- [后端工单 #5520](https://git.1814.love:8443/wx/HL/issues/5520)
- [后端 PR #5521](https://git.1814.love:8443/wx/HL/pulls/5521)
- Merge commit: `3bc4ff3ba8`
### 联系人
- **后端负责人**: @wx
@@ -0,0 +1,720 @@
---
author: "yst(GIT)"
schema: "hl-changelog/v2"
ticket: "5356"
title: "车辆 Tab 三接口汇总"
consumer: "admin"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "partial"
frontend_status: "implemented"
frontend_owner: "Pi"
frontend_ref: "v2.1@21dccf38d1413b098cfd5a456d3fb76611581ebb"
target_release: ""
verified_at: "2026-08-02"
status_note: "汇总 #5356、#5360、#5380 已实现的车辆 Tab 现行契约;管理后台使用 Step3 GET/PUT 和 vehicle-options,并按 settlementReady/blockReasonCode 区分车辆两类空态。"
updated_at: "2026-08-05"
base: "dev-v3"
---
# 🔧【修改接口·管理后台】车辆 Tab 三接口汇总 (#5356 / #5360 / #5380)
> **服务**:`hl-order-service-v3` | **更新时间**:2026-08-05 | **消费端**:管理后台
## 1. 接口背景
车辆核单 Tab 需要一份可直接对接的完整契约:先用车辆下拉接口检索手工行候选,再读取车辆核单草稿,最后按草稿版本全量保存。本文汇总三个现行接口,并纳入车辆草稿查询的最新空状态语义;不替代或修改三份历史通知。
## 2. 变更清单
| # | 接口名 | 方法 | 路径 | 变更类型 | 说明 |
|---|---|---|---|---|---|
| 1 | 查询车辆核单草稿 | `GET` | `/v3/admin/order/{orderId}/settlement/step3/vehicles` | 修改 | 返回车辆核单全量草稿;空结果用 `settlementReady/blockReasonCode` 区分是否可继续核单 |
| 2 | 全量保存车辆核单草稿 | `PUT` | `/v3/admin/order/{orderId}/settlement/step3/vehicles` | 修改 | 携带 `version` 全量保存,保护 `FLEET` 权威行并返回保存后的完整草稿 |
| 3 | 查询核单车辆异步下拉 | `GET` | `/v3/admin/order/{orderId}/settlement/vehicle-options` | 新增 | 按车牌、品牌型号、车型大类或常驻司机姓名检索候选车辆 |
三个接口均要求管理后台登录态和订单查看权限,房务角色不可访问;无接口级特殊限流。两个 GET 为只读幂等,PUT 以当前 `version` 和全量 `items` 保存。
## 3. 接口详情
### 3.1 查询车辆核单草稿
- **接口说明**:查询车辆 Tab 当前全量明细、草稿版本、确认状态以及车辆费用是否具备完成核单条件。
- **方法与路径**:`GET /v3/admin/order/{orderId}/settlement/step3/vehicles`
- **认证**:管理后台登录态;需满足订单查看权限;房务角色不可访问。
- **幂等性**:是,只读查询。
- **限流**:未声明独立限流规则。
**路径参数**
| 字段 | 类型 | 必填 | 说明与校验 |
|---|---|---|---|
| `orderId` | String(Long) | 是 | 订单 ID,必须为正整数;按字符串传递 |
无 Query 参数、无请求体。
**统一响应外层**
| 字段 | 类型 | 可空 | 说明 |
|---|---|---|---|
| `code` | Integer | 否 | 成功为 `200` |
| `message` | String | 否 | 结果说明 |
| `data` | VehicleDraft/null | 失败时为空 | 成功时为车辆核单草稿 |
| `traceId` | String | 是 | 链路追踪 ID |
| `success` | Boolean | 否 | `code=200` 时为 `true` |
**成功响应 `data`**
| 字段 | 类型 | 可空 | 说明 |
|---|---|---|---|
| `orderId` | String(Long) | 否 | 订单 ID,按字符串返回 |
| `version` | Long | 否 | 当前草稿版本;首次空结果为 `0` |
| `totalAmount` | Decimal | 否 | 全部车辆明细金额合计;空结果为 `0.00` |
| `allConfirmed` | Boolean | 否 | 非空明细是否全部确认;空状态取值见判定表 |
| `settlementReady` | Boolean | 否 | 车辆费用是否具备完成核单条件 |
| `blockReasonCode` | String/null | 是 | 不具备条件时的机器可读原因;具备条件时为 `null` |
| `items` | VehicleItem[] | 否 | 当前全量明细;无明细时为 `[]` |
**`data.items[]`**
| 字段 | 类型 | 可空 | 说明 |
|---|---|---|---|
| `id` | String(Long) | 否 | 车辆核单明细 ID |
| `sourceType` | String | 否 | `FLEET` 或 `MANUAL` |
| `sourceTypeName` | String | 否 | 车务或手工 |
| `serviceDate` | String(date) | 否 | 服务日期,`YYYY-MM-DD` |
| `vehicleId` | String(Long) | 是 | 车辆 ID |
| `vehiclePlate` | String | 是 | 车牌号 |
| `vehicleModelId` | String(Long) | 是 | 车型 ID |
| `vehicleModelName` | String | 是 | 车型名称 |
| `driverId` | String(Long) | 是 | 司机 ID |
| `driverName` | String | 是 | 司机姓名 |
| `amount` | Decimal | 否 | 核单金额 |
| `paymentMethod` | String | 否 | 付款方式编码,见 §6.2 |
| `paymentMethodName` | String | 否 | 付款方式名称 |
| `settlementConfirmStatus` | String | 否 | 确认状态编码,见 §6.3 |
| `settlementConfirmStatusName` | String | 否 | 未确认或已确认 |
| `remark` | String | 是 | 备注 |
| `voucherUrls` | String[] | 否 | 凭证 URL;无凭证时为 `[]` |
**错误码**
| code | 含义 | 触发场景 |
|---|---|---|
| `400` | 请求参数错误 | `orderId` 不是正整数 |
| `403` | 无访问权限 | 登录态或角色无权访问 |
| `581007` | 订单不存在 | `orderId` 对应订单不存在 |
| `584071` | 无权访问该订单 | 当前账号不在订单可访问范围内 |
| `584100` | 车辆费用暂时不可用 | 车辆费用来源调用失败、响应身份不匹配或必要字段无效 |
| `584101` | 车辆费用尚未满足核单条件 | 已有非空车辆明细,但来源未完结或费用条件未满足 |
`584102` 不再表示“有需求但费用尚未生成”;该场景现在返回 `code=200` 的阻断空状态。
**业务边界与空状态判定**
| 场景 | `items` | `totalAmount` | `settlementReady` | `blockReasonCode` | `allConfirmed` | 结果 |
|---|---|---|---|---|---|---|
| 无当前用车需求 | `[]` | `0.00` | `true` | `null` | `true` | 成功,可继续完成核单 |
| 有当前用车需求,但费用尚未生成 | `[]` | `0.00` | `false` | `VEHICLE_FEE_NOT_READY` | `false` | 成功,但不能完成核单 |
| 有明细、来源就绪,仍有未确认行 | 非空 | 明细合计 | `true` | `null` | `false` | 成功,需先确认明细 |
| 有明细、来源就绪且全部确认 | 非空 | 明细合计 | `true` | `null` | `true` | 成功,可继续完成核单 |
- `items=[]` 不是失败判据,必须读取 `settlementReady`。
- `allConfirmed=true` 只说明没有未确认行,能否完成核单仍以 `settlementReady` 为准。
- 车辆来源失败或必要字段无效仍返回业务错误,不转换为空结果。
**典型成功请求**
```http
GET /v3/admin/order/900000000001/settlement/step3/vehicles
Authorization: Bearer <管理后台访问令牌>
```
无请求体。
**典型成功响应**
```json
{
"code": 200,
"message": "成功",
"data": {
"orderId": "900000000001",
"version": 4,
"totalAmount": 1200.00,
"allConfirmed": true,
"settlementReady": true,
"blockReasonCode": null,
"items": [
{
"id": "930000000001",
"sourceType": "FLEET",
"sourceTypeName": "车务",
"serviceDate": "2026-08-01",
"vehicleId": "880000000001",
"vehiclePlate": "藏A12345",
"vehicleModelId": "870000000001",
"vehicleModelName": "七座商务车",
"driverId": "860000000001",
"driverName": "张师傅",
"amount": 1200.00,
"paymentMethod": "COMPANY_PAID",
"paymentMethodName": "公司付款",
"settlementConfirmStatus": "CONFIRMED",
"settlementConfirmStatusName": "已确认",
"remark": "金额已核对",
"voucherUrls": []
}
]
},
"traceId": null,
"success": true
}
```
**边界请求:有需求但费用未就绪**
```http
GET /v3/admin/order/900000000003/settlement/step3/vehicles
Authorization: Bearer <管理后台访问令牌>
```
无请求体。
**边界响应**
```json
{
"code": 200,
"message": "成功",
"data": {
"orderId": "900000000003",
"version": 0,
"totalAmount": 0.00,
"allConfirmed": false,
"settlementReady": false,
"blockReasonCode": "VEHICLE_FEE_NOT_READY",
"items": []
},
"traceId": null,
"success": true
}
```
**边界请求:无当前用车需求**
```http
GET /v3/admin/order/900000000002/settlement/step3/vehicles
Authorization: Bearer <管理后台访问令牌>
```
无请求体。
**边界响应**
```json
{
"code": 200,
"message": "成功",
"data": {
"orderId": "900000000002",
"version": 0,
"totalAmount": 0.00,
"allConfirmed": true,
"settlementReady": true,
"blockReasonCode": null,
"items": []
},
"traceId": null,
"success": true
}
```
**业务失败请求:车辆来源暂时不可用**
```http
GET /v3/admin/order/900000000004/settlement/step3/vehicles
Authorization: Bearer <管理后台访问令牌>
```
无请求体。
**业务失败响应**
```json
{
"code": 584100,
"message": "车务车辆总车费暂时不可用,请稍后重试",
"data": null,
"traceId": null,
"success": false
}
```
### 3.2 全量保存车辆核单草稿
- **接口说明**:携带查询所得版本,全量保存车辆核单行并返回保存后的完整草稿。
- **方法与路径**:`PUT /v3/admin/order/{orderId}/settlement/step3/vehicles`
- **认证**:管理后台登录态;需满足订单查看及核单写权限;房务角色不可访问。
- **幂等性**:业务语义为全量替换;成功后版本递增,原请求不可原样重放,使用旧版本重试会返回 `584108`。
- **限流**:未声明独立限流规则。
**路径参数**
| 字段 | 类型 | 必填 | 说明与校验 |
|---|---|---|---|
| `orderId` | String(Long) | 是 | 订单 ID,必须为正整数;按字符串传递 |
无 Query 参数。
**请求体**
| 字段 | 类型 | 必填 | 说明与校验 |
|---|---|---|---|
| `version` | Long | 是 | GET 返回的草稿版本,最小 `0` |
| `items` | VehicleItem[] | 是 | 全量明细;现存 `FLEET` 行必须全部原样带回 |
| `items[].id` | String(Long) | FLEET/更新时是 | 已保存行 ID;手工新行为空 |
| `items[].sourceType` | String | 是 | `FLEET` 或 `MANUAL` |
| `items[].serviceDate` | String(date) | 是 | 服务日期,`YYYY-MM-DD` |
| `items[].vehicleId` | String(Long) | 否 | 正整数车辆 ID |
| `items[].vehiclePlate` | String | 否 | 车牌,最长 64 字符 |
| `items[].vehicleModelId` | String(Long) | 否 | 正整数车型 ID |
| `items[].vehicleModelName` | String | 否 | 车型名,最长 128 字符 |
| `items[].driverId` | String(Long) | 否 | 正整数司机 ID |
| `items[].driverName` | String | 否 | 司机名,最长 64 字符 |
| `items[].amount` | Decimal | 是 | 大于等于 `0.00`;最多 10 位整数、2 位小数 |
| `items[].paymentMethod` | String | 是 | `CASH_PAID/SIGNED/COMPANY_PAID` |
| `items[].settlementConfirmStatus` | String | 是 | `UNCONFIRMED/CONFIRMED` |
| `items[].remark` | String | 否 | 最长 500 字符 |
| `items[].voucherUrls` | String[] | 否 | 最多 9 个 HTTP/HTTPS URL;单个最长 1024 字符 |
请求对象和明细对象均不接受未声明字段。
**成功响应**
响应类型同 §3.1 的 `VehicleDraft`,包含 `orderId/version/totalAmount/allConfirmed/settlementReady/blockReasonCode/items` 及完整明细字段;`version` 返回保存后的新版本。
**错误码**
| code | 含义 | 触发场景 |
|---|---|---|
| `400` | 参数校验失败 | 必填缺失、格式/长度/枚举错误或出现未知字段 |
| `403` | 无访问权限 | 登录态、角色或核单写权限不足 |
| `581007` | 订单不存在 | `orderId` 对应订单不存在 |
| `584071` | 无权访问该订单 | 当前账号不在订单可访问范围内 |
| `584089` | 核单或结算已完成 | 当前订单已不能修改资金明细 |
| `584106` | 确认状态非法 | 非 `UNCONFIRMED/CONFIRMED` |
| `584107` | 手工新增行必须先未确认 | `id=null` 的 `MANUAL` 新行直接传 `CONFIRMED` |
| `584108` | 车辆草稿版本冲突 | PUT 的 `version` 已过期 |
| `584109` | 车务来源字段不可改删 | 修改、删除或漏传现存 `FLEET` 行的权威字段 |
**业务边界**
- `FLEET` 行的服务日期、车辆、司机、金额和付款方式不可修改或删除;仅允许修改确认状态、备注和凭证。
- 全量保存必须带回所有现存 `FLEET` 行;`MANUAL` 行可新增、修改,或通过不再提交该行来删除。
- 手工新行首次只能提交 `UNCONFIRMED`;取得 `id` 后,下一次 PUT 才可改为 `CONFIRMED`。
- `version` 冲突后必须重新 GET,并基于最新全量草稿重新编辑和保存。
**典型成功请求**
```http
PUT /v3/admin/order/900000000001/settlement/step3/vehicles
Authorization: Bearer <管理后台访问令牌>
Content-Type: application/json
```
```json
{
"version": 3,
"items": [
{
"id": "930000000001",
"sourceType": "FLEET",
"serviceDate": "2026-08-01",
"vehicleId": "880000000001",
"vehiclePlate": "藏A12345",
"vehicleModelId": "870000000001",
"vehicleModelName": "七座商务车",
"driverId": "860000000001",
"driverName": "张师傅",
"amount": 1200.00,
"paymentMethod": "COMPANY_PAID",
"settlementConfirmStatus": "CONFIRMED",
"remark": "金额已核对",
"voucherUrls": []
}
]
}
```
**典型成功响应**
```json
{
"code": 200,
"message": "成功",
"data": {
"orderId": "900000000001",
"version": 4,
"totalAmount": 1200.00,
"allConfirmed": true,
"settlementReady": true,
"blockReasonCode": null,
"items": [
{
"id": "930000000001",
"sourceType": "FLEET",
"sourceTypeName": "车务",
"serviceDate": "2026-08-01",
"vehicleId": "880000000001",
"vehiclePlate": "藏A12345",
"vehicleModelId": "870000000001",
"vehicleModelName": "七座商务车",
"driverId": "860000000001",
"driverName": "张师傅",
"amount": 1200.00,
"paymentMethod": "COMPANY_PAID",
"paymentMethodName": "公司付款",
"settlementConfirmStatus": "CONFIRMED",
"settlementConfirmStatusName": "已确认",
"remark": "金额已核对",
"voucherUrls": []
}
]
},
"traceId": null,
"success": true
}
```
**边界请求:新增金额为 0 的手工未确认行**
```http
PUT /v3/admin/order/900000000001/settlement/step3/vehicles
Authorization: Bearer <管理后台访问令牌>
Content-Type: application/json
```
```json
{
"version": 4,
"items": [
{
"sourceType": "MANUAL",
"serviceDate": "2026-08-02",
"vehicleId": "880000000002",
"vehiclePlate": "藏A54321",
"vehicleModelId": "870000000001",
"vehicleModelName": "七座商务车",
"driverId": null,
"driverName": null,
"amount": 0.00,
"paymentMethod": "CASH_PAID",
"settlementConfirmStatus": "UNCONFIRMED",
"remark": null,
"voucherUrls": []
}
]
}
```
**边界响应**
```json
{
"code": 200,
"message": "成功",
"data": {
"orderId": "900000000001",
"version": 5,
"totalAmount": 0.00,
"allConfirmed": false,
"settlementReady": true,
"blockReasonCode": null,
"items": [
{
"id": "930000000002",
"sourceType": "MANUAL",
"sourceTypeName": "手工",
"serviceDate": "2026-08-02",
"vehicleId": "880000000002",
"vehiclePlate": "藏A54321",
"vehicleModelId": "870000000001",
"vehicleModelName": "七座商务车",
"driverId": null,
"driverName": null,
"amount": 0.00,
"paymentMethod": "CASH_PAID",
"paymentMethodName": "现金已付",
"settlementConfirmStatus": "UNCONFIRMED",
"settlementConfirmStatusName": "未确认",
"remark": null,
"voucherUrls": []
}
]
},
"traceId": null,
"success": true
}
```
**业务失败请求:提交过期版本**
```http
PUT /v3/admin/order/900000000001/settlement/step3/vehicles
Authorization: Bearer <管理后台访问令牌>
Content-Type: application/json
```
```json
{
"version": 3,
"items": []
}
```
**业务失败响应**
```json
{
"code": 584108,
"message": "车辆核单明细已变化,请刷新后重试",
"data": null,
"traceId": null,
"success": false
}
```
### 3.3 查询核单车辆异步下拉
- **接口说明**:`keyword` 可匹配车牌、品牌型号、车型大类和常驻司机姓名;返回轻量车辆候选。
- **方法与路径**:`GET /v3/admin/order/{orderId}/settlement/vehicle-options`
- **认证**:管理后台登录态;管理员、超级管理员可查看任意订单,其他允许角色仅可查看本人作为定制师的订单;房务角色不可访问。
- **幂等性**:是,只读查询。
- **限流**:未声明独立限流规则。
**路径与 Query 参数**
| 字段 | 位置 | 类型 | 必填 | 默认值 | 说明与校验 |
|---|---|---|---|---|---|
| `orderId` | path | String(Long) | 是 | — | 订单 ID,必须为正整数;按字符串传递 |
| `keyword` | query | String | 否 | 空 | 模糊匹配车牌、品牌型号、车型大类或常驻司机姓名;空白表示不过滤 |
| `limit` | query | Integer | 否 | `10` | 非正数按 10 处理;超过 20 按 20 处理 |
无请求体。
**统一响应外层**
| 字段 | 类型 | 可空 | 说明 |
|---|---|---|---|
| `code` | Integer | 否 | 成功为 `200` |
| `message` | String | 否 | 结果说明 |
| `data` | VehicleOption[] | 失败时为空 | 没有匹配项时为 `[]` |
| `traceId` | String | 是 | 链路追踪 ID |
| `success` | Boolean | 否 | `code=200` 时为 `true` |
**`data[]`**
| 字段 | 类型 | 可空 | 说明 |
|---|---|---|---|
| `vehicleId` | String(Long) | 否 | 车辆 ID,按字符串返回 |
| `plate` | String | 是 | 车牌 |
| `modelName` | String | 是 | 品牌型号 |
| `typeName` | String | 是 | 车型大类名称 |
| `primaryDriverId` | String(Long) | 是 | 常驻司机 ID;无常驻司机时为 `null` |
| `primaryDriverName` | String | 是 | 常驻司机姓名;无常驻司机时为 `null` |
| `label` | String | 否 | 展示文案,依次包含车牌、品牌型号、车型大类和常驻司机;无常驻司机时最后一段为“无常驻司机” |
`data[]` 只包含以上七个字段,不包含车辆费用、付款方式或核单确认状态。
**错误码**
| code | 含义 | 触发场景 |
|---|---|---|
| `400` | 订单 ID 必须大于 0 | `orderId <= 0` |
| `581007` | 订单不存在 | `orderId` 对应订单不存在 |
| `581008` | 无权查看此订单 | 非管理员访问其他定制师订单,或上下文缺少订单归属判断所需的管理员 ID |
| `581045` | 房务角色无权查看订单详情 | 房务管理员或房务组长调用 |
| `584072` | 车务司机车辆信息暂时不可用 | 车辆候选信息不可用 |
登录态无效或缺失时,请求在进入接口前由统一认证拦截。
**业务边界**
- 最多返回 20 条;没有匹配项返回 `[]`。
- `keyword` 为空或空白时不过滤;`limit <= 0` 按 10,`limit > 20` 按 20。
- 本接口只查询候选车辆;成功响应不表示已选择、保存或确认车辆。
- `vehicleId` 与非空 `primaryDriverId` 必须按字符串处理。
**典型成功请求**
```http
GET /v3/admin/order/2079454953641836546/settlement/vehicle-options?keyword=%E5%BC%A0%E5%B8%88%E5%82%85&limit=10
Authorization: Bearer <管理后台访问令牌>
```
无请求体。
**典型成功响应**
```json
{
"code": 200,
"message": "成功",
"data": [
{
"vehicleId": "9202101",
"plate": "蒙A-88888",
"modelName": "丰田汉兰达",
"typeName": "SUV",
"primaryDriverId": "9204101",
"primaryDriverName": "张师傅",
"label": "蒙A-88888***丰田汉兰达***SUV***张师傅"
}
],
"traceId": null,
"success": true
}
```
**边界请求:最大条数且无匹配结果**
```http
GET /v3/admin/order/2079454953641836546/settlement/vehicle-options?keyword=%E4%B8%8D%E5%AD%98%E5%9C%A8&limit=20
Authorization: Bearer <管理后台访问令牌>
```
无请求体。
**边界响应**
```json
{
"code": 200,
"message": "成功",
"data": [],
"traceId": null,
"success": true
}
```
**业务失败请求:订单 ID 非法**
```http
GET /v3/admin/order/0/settlement/vehicle-options
Authorization: Bearer <管理后台访问令牌>
```
无请求体。
**业务失败响应**
```json
{
"code": 400,
"message": "订单 ID 必须大于 0",
"data": null,
"traceId": null,
"success": false
}
```
## 6. 枚举 / 数据字典
### 6.1 `sourceType`
**所属字段**:车辆草稿请求/响应 `items[].sourceType` | **类型**:String | **必填**:是
| 值 | 中文 | 说明 |
|---|---|---|
| `FLEET` | 车务 | 车务同步的权威行,业务字段不可修改或删除 |
| `MANUAL` | 手工 | 管理后台手工维护的车辆核单行 |
### 6.2 `paymentMethod`
**所属字段**:车辆草稿请求/响应 `items[].paymentMethod` | **类型**:String | **必填**:是
| 值 | 中文 | 说明 |
|---|---|---|
| `CASH_PAID` | 现金已付 | 现金支付 |
| `SIGNED` | 签单 | 按签单方式结算 |
| `COMPANY_PAID` | 公司付款 | 由公司支付 |
### 6.3 `settlementConfirmStatus`
**所属字段**:车辆草稿请求/响应 `items[].settlementConfirmStatus` | **类型**:String | **必填**:是
| 值 | 中文 | 说明 |
|---|---|---|
| `UNCONFIRMED` | 未确认 | 当前车辆费用行尚未完成核单确认 |
| `CONFIRMED` | 已确认 | 当前车辆费用行已完成核单确认 |
### 6.4 `blockReasonCode`
**所属字段**:车辆草稿响应 `data.blockReasonCode` | **类型**:String/null
| 值 | 中文 | 说明 |
|---|---|---|
| `VEHICLE_FEE_NOT_READY` | 车辆费用尚未就绪 | 有当前用车需求,但尚无可返回的车辆费用明细;此时 `settlementReady=false` |
| `null` | 无阻断原因 | 此时 `settlementReady=true`;为 JSON 空值,不是字符串 `"null"` |
车辆下拉接口不包含枚举或数据字典字段。
## 10. 修改前后对比
### 10.1 字段级对比
| 字段 | 改前 | 改后 |
|---|---|---|
| GET 草稿 `data.settlementReady` | 不对管理后台输出 | 返回 Boolean,明确车辆费用是否具备完成核单条件 |
| GET 草稿 `data.blockReasonCode` | 不存在 | 返回 String/null;未就绪时为 `VEHICLE_FEE_NOT_READY` |
| 车辆下拉 `data[]` | 无独立候选接口 | 返回七字段轻量候选数组 |
### 10.2 行为级对比
| 行为 | 改前 | 改后 |
|---|---|---|
| 无当前用车需求 | 空明细但无公开就绪原因字段 | `items=[]`、`settlementReady=true`、`blockReasonCode=null` |
| 有需求但费用未生成 | 返回 `584102` | 成功空结果:`items=[]`、`settlementReady=false`、`blockReasonCode=VEHICLE_FEE_NOT_READY` |
| 保存车辆草稿 | 车辆入口与字段口径分散 | 使用 Step3 PUT,携带 `version` 和全量 `items` |
| 手工选择车辆 | 无专用异步候选契约 | 使用 `vehicle-options` 按关键词查询,最多 20 条 |
## 11. 影响评估 / 回滚
- **是否破坏向后兼容**:GET 空状态行为有兼容影响;依赖 `584102` 或仅看 `items.length` 的旧逻辑需调整。新增字段和车辆下拉接口本身向后兼容。
- **前端是否必须同步上线**:是。车辆 Tab 必须读取 `settlementReady`,并在 PUT 版本冲突后重新查询;需要手工车辆选择时使用 `vehicle-options`。
- **回滚边界**:前端不得回滚到捕获 `584102` 识别未就绪空态的版本,也不得恢复已下线的旧车辆费用入口。
## 12. 注意事项
- GET 返回 `code=200` 且 `items=[]` 时,必须读取 `settlementReady`,不能直接判失败或无条件放行。
- 完成核单前同时检查 `settlementReady` 与 `allConfirmed`。
- 清理对 GET `584102` 的空态兼容逻辑;未就绪现在由 `blockReasonCode=VEHICLE_FEE_NOT_READY` 表达。
- PUT 必须提交 GET 返回的当前 `version` 和全量明细;不要遗漏或改写 `FLEET` 权威字段。
- 订单、明细、车辆、车型和司机 ID 均按字符串处理;金额按 Decimal 处理。
- 车辆下拉只提供候选,不返回费用或确认状态;选中后仍需组装 `MANUAL` 行并通过 Step3 PUT 保存。
## 13. 关联 / 联系人
### 13.1 Issue、PR 与提交
| 范围 | Issue | PR | Feature commit | Merge commit |
|---|---|---|---|---|
| 车辆 Step3 GET/PUT | [#5356](https://git.1814.love:8443/wx/HL/issues/5356) | [#5362](https://git.1814.love:8443/wx/HL/pulls/5362) | [6e396f6fc4](https://git.1814.love:8443/wx/HL/commit/6e396f6fc48fbf6581e87224bb85f2c811759727) | [cfac945db2](https://git.1814.love:8443/wx/HL/commit/cfac945db268640b0b9e60b4d8c7ab55739a69e3) |
| 车辆异步下拉 | [#5360](https://git.1814.love:8443/wx/HL/issues/5360) | [#5361](https://git.1814.love:8443/wx/HL/pulls/5361) | [5be7985164](https://git.1814.love:8443/wx/HL/commit/5be7985164cdae5417cdeb2a2be7d104dc8fdae8) | [0ff4ef45](https://git.1814.love:8443/wx/HL/commit/0ff4ef45ccd0f4ebb1d3be00b27cde06f26bce0b) |
| GET 空状态语义 | [#5380](https://git.1814.love:8443/wx/HL/issues/5380) | [#5393](https://git.1814.love:8443/wx/HL/pulls/5393) | — | [e4c1720871](https://git.1814.love:8443/wx/HL/commit/e4c1720871f33db38936d709caa7696db199ad1f) |
### 13.2 联系人
- **后端负责人**:@yst / yaosutu
- **前端消费方**:管理后台车辆核单 Tab
## 关联/联系人
### 链接
- [后端工单 #5356](https://git.1814.love:8443/wx/HL/issues/5356)
### 联系人
- **后端负责人**: @yst
@@ -0,0 +1,323 @@
---
schema: "hl-changelog/v2"
ticket: "5429"
title: "核单门票/游玩统一资源日期价格下拉"
consumer: "admin"
author: "yst"
change_type: "新增接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "pi-main-session"
frontend_ref: "hl-admin@0a8a72ed6a978a9f14187679188f4c8308e354cd"
target_release: ""
verified_at: ""
status_note: "hl-resource-service;PR #5528 与补丁 PR #5534 已合并并部署测试服,Gateway 真实验收通过;等待管理后台接入。"
updated_at: "2026-08-05"
base: "dev-v3"
---
# 【✨ 新增接口·管理后台】核单门票/游玩统一资源日期价格下拉(#5429)
> **PR**: [#5528](https://git.1814.love:8443/wx/HL/pulls/5528)、[#5534](https://git.1814.love:8443/wx/HL/pulls/5534)
> **服务**: hl-resource-service
> **更新时间**: 2026-08-05
## 1. 接口背景
管理后台核单 Step 2 新增门票/游玩项目时,需要在同一个分页结果中搜索景区和游玩项目,并按实际游玩日期取得协议价、结算价和建议核算单价。该接口统一返回两类资源;即使当天未配置价格,也仍可返回资源供人工核单。
## 变更接口
| # | 接口名 | 方法 | 路径 | 变更类型 | 说明 |
|---|--------|------|------|----------|------|
| 1 | 分页查询门票/游玩资源选项 | GET | `/admin/resource-options/ticket-items` | 新增接口 | 按游玩日期统一查询景区和游玩项目,并返回资源级日期价格 |
## 3. 接口详情
- **使用场景**:核单 Step 2 新增或搜索实际发生的门票/游玩项目。
- **认证**:需要有效的管理后台 JWT,使用 `Authorization: Bearer <token>`。
- **幂等性**:幂等,只读查询。
- **限流**:无接口专属限流约定。
- **响应类型**:`Result<PageResult<TicketResourceOptionRespVO>>`。
- **请求体**:无。
## 4. 接口入参
### 4.1 Query 参数
| 字段 | 类型 | 必填 | 默认值 | 校验规则 | 说明 |
|------|------|------|--------|----------|------|
| `dayDate` | String | 是 | 无 | ISO 日期 `yyyy-MM-dd` | 实际游玩日期;价格字段只匹配这一天的资源价格 |
| `keyword` | String | 否 | `null` | 最长 100 个字符 | 资源名称模糊搜索;自动去除首尾空格;去除后为空等同未传 |
| `resourceType` | String | 否 | `null` | `SCENIC` 或 `ACTIVITY` | 不传时同时查询景区和游玩项目 |
| `status` | Integer | 否 | `null` | `0` 或 `1` | 不传时同时包含已启用和已下架资源 |
| `page` | Integer | 否 | `1` | 最小值 1 | 当前页码 |
| `pageSize` | Integer | 否 | `20` | 1~100 | 每页条数 |
### 4.2 请求体字段
无请求体。
## 5. 出参字段
### 5.1 统一响应与分页字段
| 字段 | 类型 | 可空 | 说明 |
|------|------|------|------|
| `code` | Integer | 否 | 业务状态码;成功为 `200` |
| `message` | String | 否 | 响应消息;成功为 `成功` |
| `success` | Boolean | 否 | `code == 200` 时为 `true` |
| `traceId` | String | 是 | 链路追踪 ID |
| `data` | Object | 否 | 分页结果 |
| `data.records` | Array | 否 | 本页资源列表;无匹配资源时为 `[]` |
| `data.total` | Integer | 否 | 符合条件的资源总数 |
| `data.page` | Integer | 否 | 当前页码 |
| `data.pageSize` | Integer | 否 | 每页条数 |
### 5.2 `data.records[]` 资源字段(完整 13 项)
| 字段 | 类型 | 可空 | 说明 |
|------|------|------|------|
| `resourceType` | String | 否 | 资源类型:`SCENIC` 景区、`ACTIVITY` 游玩项目 |
| `resourceId` | String | 否 | 资源 ID;固定按 JSON String 返回,不要转换为 JavaScript `Number` |
| `resourceName` | String | 否 | 资源名称;名称为 `null`、空字符串或纯空白的资源不会返回 |
| `status` | Integer | 否 | `0` 已下架、`1` 已启用 |
| `statusName` | String | 否 | 与 `status` 对应:`已下架` 或 `已启用` |
| `city` | String | 是 | 城市;景区优先返回城市名称;允许 `null` 或空字符串 |
| `settleType` | String | 是 | 结算方式:`cash`、`sign`、`company`;资源未配置时可为 `null` |
| `dayDate` | String | 否 | 本次查询的实际游玩日期,格式 `yyyy-MM-dd` |
| `protocolPrice` | Decimal | 是 | 该日期的协议价;未配置时为 `null` |
| `settlementPrice` | Decimal | 是 | 该日期的结算价;未配置时为 `null` |
| `ticketUnitPrice` | Decimal | 是 | 建议核算单价:优先取结算价,结算价为空时回退协议价;两者都为空时为 `null` |
| `priceConfigured` | Boolean | 否 | `ticketUnitPrice` 非空时为 `true`,否则为 `false` |
| `specName` | String | 否 | 固定返回 `成人票` |
## 6. 枚举 / 数据字典
### 6.1 `resourceType`
**所属字段**:Query `resourceType`、响应 `data.records[].resourceType`
**类型**:String
| 值 | 中文 | 说明 |
|----|------|------|
| `SCENIC` | 景区 | 来源为景区资源 |
| `ACTIVITY` | 游玩项目 | 来源为活动/游玩项目资源 |
### 6.2 `status` / `statusName`
**所属字段**:Query `status`、响应 `data.records[].status/statusName`
| `status` | `statusName` | 说明 |
|----------|--------------|------|
| `1` | `已启用` | 排序时优先返回;可用于当前资源选择 |
| `0` | `已下架` | 默认查询仍会返回,满足事后核单;传 `status=1` 可排除 |
### 6.3 `settleType`(字典 `resource_settle_type`)
**所属字段**:响应 `data.records[].settleType`
**类型**:String / null
| 值 | 中文 | 说明 |
|----|------|------|
| `cash` | 现付 | 资源结算方式为现付 |
| `sign` | 签单 | 资源结算方式为签单 |
| `company` | 公司付款 | 资源结算方式为公司付款 |
### 6.4 价格字段关系
| 条件 | `ticketUnitPrice` | `priceConfigured` |
|------|-------------------|-------------------|
| `settlementPrice` 非空 | 取 `settlementPrice` | `true` |
| `settlementPrice` 为空、`protocolPrice` 非空 | 取 `protocolPrice` | `true` |
| 两个价格都为空 | `null` | `false` |
## 7. 错误码
| code | 含义 | 触发场景 |
|------|------|----------|
| `200` | 成功 | 查询完成;没有匹配资源时仍为成功,`records=[]` |
| `400` | 参数校验失败 | 缺少/无法解析 `dayDate`,`keyword` 超过 100 字符,`resourceType` 非法,`status` 非 0/1,或分页参数越界 |
| `401` | 未认证或认证失效 | 未携带有效的管理后台 JWT |
| `500` | 系统异常 | 查询过程发生未预期异常 |
## 8. 示例
### 8.1 典型成功:同时返回景区和游玩项目
**请求**:
```http
GET /admin/resource-options/ticket-items?dayDate=2026-08-03&keyword=体验&page=1&pageSize=20
Authorization: Bearer <admin-token>
```
无请求体。
**响应**:
```json
{
"code": 200,
"message": "成功",
"data": {
"records": [
{
"resourceType": "SCENIC",
"resourceId": "2079454953641836546",
"resourceName": "草原景区体验区",
"status": 1,
"statusName": "已启用",
"city": "呼伦贝尔市",
"settleType": "sign",
"dayDate": "2026-08-03",
"protocolPrice": 100.00,
"settlementPrice": 88.00,
"ticketUnitPrice": 88.00,
"priceConfigured": true,
"specName": "成人票"
},
{
"resourceType": "ACTIVITY",
"resourceId": "2079454953641836550",
"resourceName": "骑马体验",
"status": 0,
"statusName": "已下架",
"city": null,
"settleType": "cash",
"dayDate": "2026-08-03",
"protocolPrice": 66.00,
"settlementPrice": null,
"ticketUnitPrice": 66.00,
"priceConfigured": true,
"specName": "成人票"
}
],
"total": 2,
"page": 1,
"pageSize": 20
},
"traceId": "a1b2c3d4-e5f6-7890",
"success": true
}
```
### 8.2 边界情况:当天无价格
**请求**:
```http
GET /admin/resource-options/ticket-items?dayDate=2026-12-31&resourceType=SCENIC&status=1&page=1&pageSize=20
Authorization: Bearer <admin-token>
```
无请求体。
**响应**:
```json
{
"code": 200,
"message": "成功",
"data": {
"records": [
{
"resourceType": "SCENIC",
"resourceId": "2079454953641836548",
"resourceName": "免费公园",
"status": 1,
"statusName": "已启用",
"city": "拉萨市",
"settleType": null,
"dayDate": "2026-12-31",
"protocolPrice": null,
"settlementPrice": null,
"ticketUnitPrice": null,
"priceConfigured": false,
"specName": "成人票"
}
],
"total": 1,
"page": 1,
"pageSize": 20
},
"traceId": "b2c3d4e5-f6a7-8901",
"success": true
}
```
### 8.3 业务失败:缺少游玩日期
**请求**:
```http
GET /admin/resource-options/ticket-items?page=1&pageSize=20
Authorization: Bearer <admin-token>
```
无请求体。
**响应**:
```json
{
"code": 400,
"message": "游玩日期不能为空",
"data": null,
"traceId": "c3d4e5f6-a7b8-9012",
"success": false
}
```
## 9. 业务边界
- 默认统一查询 `SCENIC` 与 `ACTIVITY`,`total` 是两类资源合并后的总数,不是分别分页后相加。
- 默认同时包含已启用和已下架资源;结果按“已启用优先 → 名称升序 → 资源类型升序 → 资源 ID 升序”稳定排序。
- 软删除资源不返回;资源名称为 `null`、空字符串或纯空白时也不返回,且不会计入 `total`。
- `keyword` 只匹配资源名称;不会匹配城市或资源 ID。
- 当天没有价格不会排除资源;此时允许人工核单,价格字段按第 6.4 节返回。
- 页码超过最后一页时,返回 `code=200`、`records=[]`,`total` 仍为符合条件的总数。
- `city` 和 `settleType` 是可空字段,不能作为能否选择资源的判断条件。
## 验证证据
- PR #5528 与补丁 PR #5534 已合并到 `dev-v3`。
- `hl-resource-service` 已部署测试服,经 Gateway 真实 HTTP 验收;补丁后全页扫描 121 条资源,空名称记录为 0,`resourceId` 按 String 返回。
## 10. 影响评估
- **是否破坏向后兼容**:否;这是新增只读接口,不改变已有接口。
- **前端是否必须同步上线**:否;后端上线后前端可按需接入。
- **ID 类型要求**:`resourceId` 必须始终按 String 保存和传递。
## 11. 注意事项
- 选择行的核算单价使用 `ticketUnitPrice`,不要在前端重新实现结算价/协议价优先级。
- `priceConfigured=false` 不代表资源不可选,只表示该游玩日期没有可自动带出的价格。
- 不要根据 `city` 是否为空过滤资源。
- 不要在前端把两个资源类型拆成两次请求再自行合并分页;本接口已经提供统一分页和 `total`。
## 12. 关联 / 联系人
### 12.1 链接
- **Issue**: [#5429](https://git.1814.love:8443/wx/HL/issues/5429)
- **功能 PR**: [#5528](https://git.1814.love:8443/wx/HL/pulls/5528)
- **功能 Merge commit**: [5ab2fb780](https://git.1814.love:8443/wx/HL/commit/5ab2fb7802772f99af9ee2715bb921e502a6f07b)
- **补丁 PR**: [#5534](https://git.1814.love:8443/wx/HL/pulls/5534)
- **补丁 Merge commit**: [87e8a96ba](https://git.1814.love:8443/wx/HL/commit/87e8a96ba16cbc505092562c7fae0f9e88984a5a)
### 12.2 联系人
- **后端负责人**: @yst
## 关联/联系人
### 链接
- [后端工单 #5429](https://git.1814.love:8443/wx/HL/issues/5429)
### 联系人
- **后端负责人**: @yst
@@ -0,0 +1,83 @@
---
schema: "hl-changelog/v2"
ticket: "5515"
title: "车务保险任务列表枚举校验补全 + source 来源筛选生效"
consumer: "admin"
change_type: "修改接口"
author: "wx(GIT)"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "pi-main-session"
frontend_ref: "hl-admin@1553c988ac6065e693769a95f3f412c4e43df5e7"
target_release: ""
verified_at: ""
status_note: "后端完成:PR #5522 已合并 dev-v3 并部署 TEST;非法枚举/分页返 400 明确错误码,source 筛选生效(BAOYOU=206)。前端若传 source 参数无需改动;旧传非法枚举值需适配 400 响应。"
updated_at: "2026-08-05"
base: "dev-v3"
---
# 车务: 保险任务列表枚举校验补全 + source 来源筛选生效
> **服务**: hl-fleet-service
> **PR**: #5522
> **Issue**: #5515(#5516 分页校验同 PR)
> **日期**: 2026-08-05
> **影响范围**: 管理后台车务保险菜单的任务列表筛选参数
---
## ⚠️ 关键变化
`GET /admin/fleet/insurance/tasks` 三个筛选参数行为变更:
1. **`taskType` 非法值不再静默空结果**:`taskType=NOT_A_TYPE` 此前 `code=200` + `total=0`;现在返 `400`,message=`任务类型必须是 PURCHASE(投保)/REFUND(退保) 之一`。
2. **`taskStatus` 非法值不再静默空结果**:`taskStatus=BAD_STATUS` 此前 `code=200` + `total=0`;现在返 `400`,message=`任务状态必须是 PENDING/PROCESSING/SUCCESS/RESOLVED/IGNORED 之一`。
3. **`source` 参数新增并生效**:此前 `source=BAOYOU` 被 Spring 静默忽略(返全量 207);现在按来源过滤(BAOYOU=206 / OFFLINE=1),非法值返 `400`(`来源必须是 BAOYOU(保游)/OFFLINE(线下) 之一`)。
同源收紧(同 PR):`GET /admin/fleet/matrix/grid` 与 `GET /admin/fleet/matrix/month-counts` 的 `season` 非法值返 `400`(`司机赛季必须是 active/pending/archived/blacklist 之一`);`GET /admin/fleet/board/expiry` 与 `GET /admin/fleet/board/orders` 分页参数 page/pageSize 非法(非数字/负数/0/超 100)返 `400`(页码最小为1 等),与 drivers/vehicles 列表口径一致。
## 变更接口清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|------|------|------|----------|------|
| 1 | 保险任务列表 | GET | `/admin/fleet/insurance/tasks` | 校验补全+新增参数 | taskType/taskStatus 非法值 400;新增 source 筛选 |
| 2 | 矩阵主数据 | GET | `/admin/fleet/matrix/grid` | 校验补全 | season 非法值 400 |
| 3 | 矩阵月度统计 | GET | `/admin/fleet/matrix/month-counts` | 校验补全 | season 非法值 400 |
| 4 | 证件到期看板 | GET | `/admin/fleet/board/expiry` | 校验补全 | page/pageSize 非法值 400 |
| 5 | 看板列表 | GET | `/admin/fleet/board/orders` | 校验补全 | page/pageSize 非法值 400 |
## 接口详情
### 1. 保险任务列表 `GET /admin/fleet/insurance/tasks`
**`source` 参数(新增)**:
- 类型:string;枚举:`BAOYOU`(保游·线上)/ `OFFLINE`(线下);空/缺省=全部
- 生效:与 taskType/taskStatus 等 AND 过滤下推 DB(`source = ?` 等值条件)
**校验规则**(taskType/taskStatus/source 均 `@Pattern`):
- 非法值 → `code=400`,message 包含合法枚举(不再静默空结果)
- 合法值行为不变(taskType=PURCHASE→28、taskStatus=PENDING→25 等回归不变)
**示例**:
```
GET /admin/fleet/insurance/tasks?source=BAOYOU&taskType=PURCHASE
→ 200,仅返回 source=BAOYOU 的投保任务
GET /admin/fleet/insurance/tasks?taskType=NOT_A_TYPE
→ 400 任务类型必须是 PURCHASE(投保)/REFUND(退保) 之一
```
## 关联/联系人
### 链接
- [后端工单 #5515](https://git.1814.love:8443/wx/HL/issues/5515)
- [后端 PR #5522](https://git.1814.love:8443/wx/HL/pulls/5522)
- Merge commit: `f061e02d44`
### 联系人
- **后端负责人**: @wx
@@ -0,0 +1,49 @@
---
schema: "hl-changelog/v2"
ticket: "5530"
title: "前端样式与派单候选显示问题(用户实测反馈)"
consumer: "admin"
author: "wx(GIT)"
change_type: "修改接口"
backend_status: "not_required"
gateway_status: "not_required"
frontend_status: "implemented"
frontend_owner: "pi-main-session"
frontend_ref: "hl-admin@82255a9b0bd1e0e1560da161a80ec12325688655"
target_release: ""
verified_at: ""
status_note: "用户(wx)测试环境实测反馈的两个前端显示问题,交接前端处理。"
updated_at: "2026-08-05"
base: "dev-v3"
---
# 前端样式与派单候选显示问题(用户实测反馈)
> **服务**: 前端(管理后台) | **日期**: 2026-08-05 | **来源**: wx 测试环境实测
本文件交接**两个前端显示问题**(用户手动测试实测发现),请前端(mmg)处理。后端 API 契约未变,以下为前端展示层问题。
## 问题 1:订单详情-行程/用车需求区域样式暗色显示异常
- **页面**:订单详情 → 行程/用车需求区域(web.test.1814.love)
- **现象**:该区域样式显示为**暗色**(暗色主题/暗色显示异常),与正常亮色主题不符,影响可读性。
- **期望**:恢复正常亮色/正确主题样式。
- **排查方向**:该页面主题/CSS 渲染(是否误用暗色主题或样式异常)。
## 问题 2:派单"统一选择车辆/司机"候选显示两个问题
- **页面**:车务派单 → 统一选择车辆/司机弹窗(fleet/board)
- **问题 2a(全程空闲筛选)**:全程选择司机/车辆时,筛选结果应只显示**全程(如 08-28~08-31 四天)都空闲**的司机/车辆。当前显示不对——包含了非全程空闲(部分天占用)的候选。
- **问题 2b(日期范围显示)**:候选的服务日期当前显示为**单日**(2026-08-28),用户需要显示**日期范围**(2026-08-28 至 2026-08-31,全程)。
- **期望**:
- 全程选择时只返回/显示全程空闲的司机/车辆(可用性按全程判断)
- 服务日期显示为范围(startDate 至 endDate),非单日
- **后端说明**:`POST /admin/fleet/assignments/candidates` 已支持 startDate/endDate 范围入参与档期冲突返回,前端可用此判断全程可用性并展示范围;若需后端补"全程空闲"过滤字段或范围返回,请在工单反馈,后端配合。
## 关联 / 联系人
### 联系人
- **反馈人**: @wx
- **后端对接**: @wx(如需后端配合 candidates 字段/过滤)
- **前端处理**: @mmg
@@ -0,0 +1,50 @@
---
schema: "hl-changelog/v2"
ticket: "5530"
title: "投保界面去掉"按赛季"快捷预填选项(与按年重复)"
consumer: "admin"
author: "wx(GIT)"
change_type: "修改接口"
backend_status: "not_required"
gateway_status: "not_required"
frontend_status: "implemented"
frontend_owner: "pi-main-session"
frontend_ref: "hl-admin@aa7061b0edeaf68a8baf306a858a91d8be8cb9a7"
target_release: ""
verified_at: ""
status_note: "wx 确认无"按赛季买"需求,投保界面"按赛季"与"按年"快捷预填重复,去掉"按赛季"保留"按年"。"
updated_at: "2026-08-05"
base: "dev-v3"
---
# 投保界面去掉"按赛季"快捷预填选项(与按年重复)
> **服务**: 前端(司机投保-保游网界面) | **日期**: 2026-08-05 | **来源**: wx 确认
## 背景(wx 确认)
司机投保界面(保游网)的保障起止**快捷预填**有两个选项:"**按赛季**"(7-01~次年6-30)和"**按年**"(自然年)。
wx 确认:**没有"按赛季买"保险的需求**——"按赛季"(旅游经营年度 7-01~次年6-30)与"按年"(年度覆盖)语义重复,造成选择困扰。
## 处理(前端)
**去掉"按赛季"快捷预填选项**,保留"按年"(及手动改起止)。
- 位置:`hl-ui/src/views/fleet/drivers/index.vue`(投保保障起止快捷预填按钮)
- 去掉"按赛季"按钮/选项;保留"按年"快捷预填 + 手动修改起止
- 后端无契约变更(投保入参不变,仅前端去掉冗余预填选项)
## 说明
- "按赛季"(7-01~次年6-30)本质是旅游经营年度的年保,与"按年"(annual)重复
- 保险类型实际只有 annual(年保)/ perTrip(按行程),无独立"按赛季"类型
- 后端 Controller 注释提到"按赛季/按年快捷预填"仅为说明,不影响功能(如需同步清理注释可后续提)
## 关联 / 联系人
### 联系人
- **需求确认**: @wx
- **前端处理**: @mmg
- **后端对接**: @wx(无需改动,仅前端)
@@ -0,0 +1,103 @@
---
schema: "hl-changelog/v2"
ticket: "5533"
title: "司机列表新增车型大类/所属车队展示与筛选,详情关联订单补齐接送机/金额/定制师"
consumer: "admin"
author: "wx(GIT)"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "pi-main-session"
frontend_ref: "hl-admin@005ba4cf9151e39aac5bcf4c5e5480411d68264e"
target_release: ""
verified_at: ""
status_note: ""
updated_at: "2026-08-05"
base: "dev-v3"
---
# 车务司机管理:列表车型大类/所属车队展示与筛选 + 详情关联订单字段补齐
> **服务**: hl-fleet-service
> **PR**: #5538
> **Issue**: #5533
> **日期**: 2026-08-05
> **影响范围**: 管理后台司机列表 / 司机详情关联订单区域
## 变更接口
| 接口 | 方法 | 路径 | 变更 |
|---|---|---|---|
| 司机档案分页查询 | GET | `/admin/fleet/drivers/page` | 列表项新增车型大类/所属车队字段;新增 `vehicleTypeKeys`、`teamIds` 筛选参数 |
| 司机档案详情查询 | GET | `/admin/fleet/drivers/(司机ID)` | `relatedOrders[]` 新增接送机地点、日费/总费、定制师字段 |
## 二、响应字段
### 2.1 司机列表 `records[]`(顶层新增)
| 字段 | 类型 | 必填性 | 值 | 说明 |
|---|---|---|---|---|
| `residentVehicleTypeKey` | `String` / null | 否 | `suv2`/`mpv`/`sedan`/`bus` 等 | 权威常驻车辆第一辆的车型大类 key(与派单候选弹窗分类一致);无常驻车辆为 null |
| `residentVehicleTypeName` | `String` / null | 否 | `SUV系列`/`商务车`/`轿车系列`/`大巴系列` | 车型大类中文名;无常驻车辆为 null |
| `residentTeamId` | `String` / null | 否 | 车队雪花 ID(JSON 字符串) | 权威常驻车辆第一辆的所属车队 ID;无常驻车辆为 null |
| `residentTeamName` | `String` / null | 否 | `合作车队B` | 所属车队名;无常驻车辆为 null |
`residentVehicles[]` 子项同步新增:`vehicleTypeKey`、`vehicleTypeName`、`fleetTeamId`、`fleetTeamName`。
### 2.2 司机列表新增筛选参数
| 参数 | 类型 | 必填性 | 说明 |
|---|---|---|---|
| `vehicleTypeKeys` | `List<String>` | 否 | 车型大类 key 多选过滤(逗号分隔),常驻车辆挂在任一大类下即命中;不传不过滤 |
| `teamIds` | `List<Long>` | 否 | 所属车队 ID 多选过滤,常驻车辆属于任一支车队即命中;不传不过滤 |
### 2.3 司机详情 `relatedOrders[]`(新增)
| 字段 | 类型 | 必填性 | 值 | 说明 |
|---|---|---|---|---|
| `pickupAt` | `String` / null | 否 | `满洲里` | 接机地点(fleet_assignment.pickup_at 快照);无记录为 null |
| `dropoffAt` | `String` / null | 否 | `满洲里` | 送机地点(fleet_assignment.dropoff_at 快照);无记录为 null |
| `dailyFee` | `String` / null | 否 | `800.00` | 协议日费(protocol_price 快照,JSON 字符串);无费用为 null |
| `totalFee` | `String` / null | 否 | `800.00` | 派车组总费(vehicle_fee_total 快照,JSON 字符串);无费用为 null |
| `customizerName` | `String` / null | 否 | `王骁` | 定制师名(planner_name 快照) |
原有字段(orderId/orderNo/teamNo/customerName/tripStartDate/tripEndDate/destination/orderStatus/vehicleType/licensePlate)不变;`destination` 保留为 pickup/dropoff 兼容拼接。
## 三、兼容性与前端事项
- 全部为向后兼容的响应字段扩展 + 可选筛选参数,不改既有字段语义、分页结构。
- 车型大类 key 以 vehicle_type 表 type_key 为准(与派单候选弹窗分类一致,如 `suv2`),前端筛选值应复用候选弹窗/字典数据源。
- 后端未修改 `mmg/hl-ui`,前端消费状态保持 `pending`。
## 验证证据
- 定向测试 158 项全绿(DriverServiceTest 144 / VehicleResidentReadPortImplTest 7 / DriverMapperPageExcludeTest 3 / DriverRelatedOrderReadPortImplTest 4);fleet verify 3130 项仅 1 既有基线 flaky 失败(Step2CanonicalSnapshotServiceTest 时间敏感,stash 验证与本次无关),0 Errors;spotless 0 违规。
- 测试环境网关实测:
- 列表:朝鲁门(suv2/SUV系列/北疆协作车队)、菜单师傅46622(mpv/商务车/自有)、王信(sedan/轿车系列/合作车队A);无常驻车辆司机全字段 null
- 筛选:`vehicleTypeKeys=suv2` 3 人、`suv2,mpv` 多选 8 人、`teamIds=合作车队B` 1 人、组合筛选 1 人、不存在大类空结果正确
- 详情:乌云毕力格 relatedOrders 2 条——pickup/dropoff=满洲里、teamNo=26-4081、status=in_progress、dailyFee=0.00/totalFee=800.00、customizer=王骁、customer=卫予轩
## 五、关联 / 联系人
### 5.1 链接
- **Issue**: [#5533](https://git.1814.love:8443/wx/HL/issues/5533)
- **PR**: [#5538](https://git.1814.love:8443/wx/HL/pulls/5538)
- **Merge commit**: [9215f86ee](https://git.1814.love:8443/wx/HL/commit/9215f86eeccd9e1a1bd17e90ea6d2c1784a4db54)
### 5.2 联系人
- **后端负责人**: @wx
## 关联/联系人
### 链接
- [后端工单 #5533](https://git.1814.love:8443/wx/HL/issues/5533)
- [后端 PR #5538](https://git.1814.love:8443/wx/HL/pulls/5538)
- Merge commit: `9215f86ee6`
### 联系人
- **后端负责人**: @wx
@@ -0,0 +1,67 @@
---
schema: "hl-changelog/v2"
ticket: "5536"
title: "保险订单 v3 补 /orders 列表别名(对齐 v2 与前端调用)"
consumer: "admin"
change_type: "新增接口"
author: "wx(GIT)"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "verified"
frontend_owner: "pi-main-session"
frontend_ref: "hl-admin@ef497e8e30d2df2d55d97f5554c8c5e921dc49ef"
target_release: ""
verified_at: "2026-08-05"
status_note: "后端完成:PR #5541 已合并 dev-v3 并部署 TEST;网关实测 /v3/admin/insurance/orders 200 total=255,与 /list 完全一致(修复前 404)。前端保险订单页无需改动,回归确认后置 verified。"
updated_at: "2026-08-05"
base: "dev-v3"
---
# 保险订单 v3 补 /orders 列表别名(#5536)
> **服务**: hl-order-service-v3
> **PR**: #5541
> **Issue**: #5536(P1)
> **联系人**: @wx
> **日期**: 2026-08-05
> **影响范围**: 管理后台-保险管理-保险订单页(前端已调 /orders 复数路径)
---
## 背景
前端保险订单页调 `GET /v3/admin/insurance/orders` → **404 数据加载失败**。v3 只有 `/v3/admin/insurance/list`(实测 code=200 total=255),缺 `/orders` 复数别名;v2(`/admin/insurance/orders`)与前端调用均为复数路径。
## 变更接口
| 方法 | 路径 | 来源 |
|---|---|---|
| GET | /v3/admin/insurance/orders | 管理后台-保险订单页 |
## 变更说明
`AdminInsuranceController.listOrders` 路由映射由 `"/list"` 扩展为 `/list` 与 `/orders` 两个路径——**同一方法同返回**(分页参数 `InsuranceQueryRequest` 与 /list 完全一致),不新增逻辑。
## 接口行为变化
| 接口 | 修复前 | 修复后 |
|---|---|---|
| `GET /v3/admin/insurance/orders` | 404 | 200,`PageResult<InsuranceOrderVO>`(total=255,与 /list 一致) |
| `GET /v3/admin/insurance/list` | 200 | 不变 |
## 验证证据
- 网关实测(api.test.1814.love:9443,admin,2026-08-05):`/v3/admin/insurance/orders` 200 total=255;`/v3/admin/insurance/list` 200 total=255;首条 `insuranceOrderId=2084823362831306753 / extPolicyNo=MOCKPOL-... / totalPremium="88.00"`,两路径响应一致
- 定向测试:AdminInsuranceControllerTest 19/19(新增 `/orders` 别名与 `/list` 同返回断言用例)
## 关联/联系人
### 链接
- [后端工单 #5536](https://git.1814.love:8443/wx/HL/issues/5536)
- [后端 PR #5541](https://git.1814.love:8443/wx/HL/pulls/5541)
- Merge commit: `2936d67f1b`
### 联系人
- **后端负责人**: @wx
@@ -0,0 +1,352 @@
---
schema: "hl-changelog/v2"
ticket: "5539"
title: "核单资源下拉可选范围与中文字段契约"
consumer: "admin"
author: "yst"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "pi-main-session"
frontend_ref: "hl-admin@0a8a72ed6a978a9f14187679188f4c8308e354cd"
target_release: ""
verified_at: ""
status_note: "hl-resource-service;PR #5540 已合并并部署测试服,Gateway 真实验收通过;等待管理后台完成破坏性契约迁移。"
updated_at: "2026-08-05"
base: "dev-v3"
---
# 【⚠️ 修改接口·管理后台】核单资源下拉可选范围与中文字段契约(#5539)
> **PR**: [#5540](https://git.1814.love:8443/wx/HL/pulls/5540)
> **服务**: hl-resource-service
> **更新时间**: 2026-08-05
## 1. 接口背景
核单门票/游玩统一资源下拉首版会返回下架资源,且资源类型、结算方式只有编码,默认核算价字段名也不够明确。本次收紧为只返回启用资源,并调整请求与响应字段。删除字段和字段改名属于破坏性契约变化,接入方需要按第 12 节迁移。
## 变更接口
| # | 接口名 | 方法 | 路径 | 变更类型 | 说明 |
|---|--------|------|------|----------|------|
| 1 | 分页查询门票/游玩资源选项 | GET | `/admin/resource-options/ticket-items` | 修改接口 | 仅返回启用资源,删除状态字段,增加中文名称字段并重命名默认核算价 |
## 3. 接口详情
- **使用场景**:核单 Step 2 新增或搜索可选的门票/游玩项目。
- **认证**:需要有效的管理后台 JWT,使用 `Authorization: Bearer <token>`。
- **幂等性**:幂等,只读查询。
- **限流**:无接口专属限流约定。
- **响应类型**:`Result<PageResult<TicketResourceOptionRespVO>>`。
- **请求体**:无。
## 4. 接口入参
### 4.1 Query 参数(修改后完整字段)
| 字段 | 类型 | 必填 | 默认值 | 校验规则 | 说明 |
|------|------|------|--------|----------|------|
| `dayDate` | String | 是 | 无 | ISO 日期 `yyyy-MM-dd` | 实际游玩日期;价格字段只匹配这一天的资源价格 |
| `keyword` | String | 否 | `null` | 最长 100 个字符 | 资源名称模糊搜索;自动去除首尾空格;去除后为空等同未传 |
| `resourceType` | String | 否 | `null` | `SCENIC` 或 `ACTIVITY` | 不传时同时查询景区和游玩项目 |
| `page` | Integer | 否 | `1` | 最小值 1 | 当前页码 |
| `pageSize` | Integer | 否 | `20` | 1~100 | 每页条数 |
### 4.2 已删除的 Query 参数
| 字段 | 修改前 | 修改后 |
|------|--------|--------|
| `status` | 可选,`0` 已下架、`1` 已启用;不传查询全部 | **已删除**;接口固定只返回启用资源 |
### 4.3 请求体字段
无请求体。
## 5. 出参字段
### 5.1 统一响应与分页字段
| 字段 | 类型 | 可空 | 说明 |
|------|------|------|------|
| `code` | Integer | 否 | 业务状态码;成功为 `200` |
| `message` | String | 否 | 响应消息;成功为 `成功` |
| `success` | Boolean | 否 | `code == 200` 时为 `true` |
| `traceId` | String | 是 | 链路追踪 ID |
| `data` | Object | 否 | 分页结果 |
| `data.records` | Array | 否 | 本页启用资源列表;无匹配资源时为 `[]` |
| `data.total` | Integer | 否 | 符合条件的启用资源总数 |
| `data.page` | Integer | 否 | 当前页码 |
| `data.pageSize` | Integer | 否 | 每页条数 |
### 5.2 `data.records[]` 资源字段(修改后完整 13 项)
| 字段 | 类型 | 可空 | 说明 |
|------|------|------|------|
| `resourceType` | String | 否 | 资源类型编码:`SCENIC` 或 `ACTIVITY` |
| `resourceTypeName` | String | 否 | 资源类型中文名:`景区` 或 `游玩项目` |
| `resourceId` | String | 否 | 资源 ID;固定按 JSON String 返回,不要转换为 JavaScript `Number` |
| `resourceName` | String | 否 | 资源名称;名称为 `null`、空字符串或纯空白的资源不会返回 |
| `city` | String | 是 | 城市;景区优先返回城市名称;原值为 `null`、空字符串或纯空白时统一返回 `null` |
| `settleType` | String | 是 | 结算方式编码;空值/空白统一为 `null`;未知非空编码去除首尾空格后原值返回 |
| `settleTypeName` | String | 是 | 结算方式中文名;`cash/sign/company` 分别为现付/签单/公司付款;编码为空或未知时为 `null` |
| `dayDate` | String | 否 | 本次查询的实际游玩日期,格式 `yyyy-MM-dd` |
| `protocolPrice` | Decimal | 是 | 该日期的协议价;未配置时为 `null` |
| `settlementPrice` | Decimal | 是 | 该日期的结算价;未配置时为 `null` |
| `defaultUnitPrice` | Decimal | 是 | 默认核算单价:优先取结算价,结算价为空时回退协议价;两者都为空时为 `null` |
| `priceConfigured` | Boolean | 否 | `defaultUnitPrice` 非空时为 `true`,否则为 `false` |
| `specName` | String | 否 | 固定返回 `成人票` |
### 5.3 已删除或改名的响应字段
| 修改前字段 | 修改后 | 迁移说明 |
|------------|--------|----------|
| `status` | **已删除** | 接口已固定过滤为启用资源,不再返回状态值 |
| `statusName` | **已删除** | 接口已固定过滤为启用资源,不再返回状态文案 |
| `ticketUnitPrice` | 改名为 `defaultUnitPrice` | 价格优先级不变:结算价优先、协议价回退 |
## 6. 枚举 / 数据字典
### 6.1 `resourceType` / `resourceTypeName`
| `resourceType` | `resourceTypeName` | 说明 |
|----------------|--------------------|------|
| `SCENIC` | `景区` | 景区资源 |
| `ACTIVITY` | `游玩项目` | 活动/游玩项目资源 |
### 6.2 `settleType` / `settleTypeName`
| `settleType` | `settleTypeName` | 说明 |
|--------------|------------------|------|
| `cash` | `现付` | 资源结算方式为现付 |
| `sign` | `签单` | 资源结算方式为签单 |
| `company` | `公司付款` | 资源结算方式为公司付款 |
| `null` | `null` | 原编码为空或空白 |
| 其他非空编码 | `null` | 编码去除首尾空格后原值返回,中文名为空 |
### 6.3 价格字段关系
| 条件 | `defaultUnitPrice` | `priceConfigured` |
|------|--------------------|-------------------|
| `settlementPrice` 非空 | 取 `settlementPrice` | `true` |
| `settlementPrice` 为空、`protocolPrice` 非空 | 取 `protocolPrice` | `true` |
| 两个价格都为空 | `null` | `false` |
## 7. 错误码
| code | 含义 | 触发场景 |
|------|------|----------|
| `200` | 成功 | 查询完成;没有匹配资源时仍为成功,`records=[]` |
| `400` | 参数校验失败 | 缺少/无法解析 `dayDate`,`keyword` 超过 100 字符,`resourceType` 非法,或分页参数越界 |
| `401` | 未认证或认证失效 | 未携带有效的管理后台 JWT |
| `500` | 系统异常 | 查询过程发生未预期异常 |
## 8. 示例
### 8.1 典型成功:启用景区与游玩项目
**请求**:
```http
GET /admin/resource-options/ticket-items?dayDate=2026-08-03&keyword=体验&page=1&pageSize=20
Authorization: Bearer <admin-token>
```
无请求体。
**响应**:
```json
{
"code": 200,
"message": "成功",
"data": {
"records": [
{
"resourceType": "SCENIC",
"resourceTypeName": "景区",
"resourceId": "2079454953641836546",
"resourceName": "草原景区体验区",
"city": "呼伦贝尔市",
"settleType": "sign",
"settleTypeName": "签单",
"dayDate": "2026-08-03",
"protocolPrice": 100.00,
"settlementPrice": 88.00,
"defaultUnitPrice": 88.00,
"priceConfigured": true,
"specName": "成人票"
},
{
"resourceType": "ACTIVITY",
"resourceTypeName": "游玩项目",
"resourceId": "2079454953641836550",
"resourceName": "骑马体验",
"city": "海拉尔区",
"settleType": "cash",
"settleTypeName": "现付",
"dayDate": "2026-08-03",
"protocolPrice": 66.00,
"settlementPrice": null,
"defaultUnitPrice": 66.00,
"priceConfigured": true,
"specName": "成人票"
}
],
"total": 2,
"page": 1,
"pageSize": 20
},
"traceId": "a1b2c3d4-e5f6-7890",
"success": true
}
```
### 8.2 边界情况:空白城市、未知结算编码且当天无价格
**请求**:
```http
GET /admin/resource-options/ticket-items?dayDate=2026-12-31&resourceType=ACTIVITY&page=1&pageSize=20
Authorization: Bearer <admin-token>
```
无请求体。
**响应**:
```json
{
"code": 200,
"message": "成功",
"data": {
"records": [
{
"resourceType": "ACTIVITY",
"resourceTypeName": "游玩项目",
"resourceId": "2079454953641836558",
"resourceName": "特色体验",
"city": null,
"settleType": "other",
"settleTypeName": null,
"dayDate": "2026-12-31",
"protocolPrice": null,
"settlementPrice": null,
"defaultUnitPrice": null,
"priceConfigured": false,
"specName": "成人票"
}
],
"total": 1,
"page": 1,
"pageSize": 20
},
"traceId": "b2c3d4e5-f6a7-8901",
"success": true
}
```
### 8.3 业务失败:缺少游玩日期
**请求**:
```http
GET /admin/resource-options/ticket-items?page=1&pageSize=20
Authorization: Bearer <admin-token>
```
无请求体。
**响应**:
```json
{
"code": 400,
"message": "游玩日期不能为空",
"data": null,
"traceId": "c3d4e5f6-a7b8-9012",
"success": false
}
```
## 9. 业务边界
- 无论是否携带旧版 `status` 参数,接口都固定只返回已启用资源;调用方不应继续传该参数。
- 下架资源、软删除资源、名称为 `null`/空字符串/纯空白的资源均不返回,也不计入 `total`。
- 默认统一查询 `SCENIC` 与 `ACTIVITY`;结果按“名称升序 → 资源类型升序 → 资源 ID 升序”稳定排序。
- `keyword` 只匹配资源名称;不会匹配城市或资源 ID。
- 当天没有价格不会排除资源,`defaultUnitPrice=null`、`priceConfigured=false`。
- `city` 或 `settleType` 为空不影响资源是否返回;空白值会被规范为 `null`。
- 未知非空结算编码保留在 `settleType`,但 `settleTypeName=null`。
- 页码超过最后一页时,返回 `code=200`、`records=[]`,`total` 仍为符合条件的启用资源总数。
## 验证证据
- PR #5540 已合并到 `dev-v3`,`hl-resource-service` 已部署测试服。
- Gateway 真实 HTTP 验收确认仅启用过滤、新旧字段、String ID、结算方式映射、价格优先级、双价缺失、筛选与鉴权均按本文契约生效。
## 10. 修改前后对比
### 10.1 字段级对比
| 位置 | 修改前 | 修改后 |
|------|--------|--------|
| Query | `dayDate/keyword/resourceType/status/page/pageSize` | `dayDate/keyword/resourceType/page/pageSize` |
| 资源状态 | `status/statusName` | 两个字段均删除 |
| 资源类型中文名 | 无 | 新增 `resourceTypeName` |
| 结算方式中文名 | 无 | 新增 `settleTypeName` |
| 默认核算价 | `ticketUnitPrice` | 改名为 `defaultUnitPrice` |
| 城市空白值 | 可能返回空字符串/纯空白 | 统一返回 `null` |
| 结算编码空白值 | 可能返回空字符串/纯空白 | 统一返回 `null` |
### 10.2 行为级对比
| 行为 | 修改前 | 修改后 |
|------|--------|--------|
| 可选资源范围 | 默认包含启用和下架,可通过 `status` 筛选 | 固定只返回启用资源 |
| 默认核算价优先级 | 结算价优先,协议价回退 | 不变,仅字段改名 |
| 未知结算编码 | 只有原始编码 | 保留原始编码,中文名为 `null` |
| 排序 | 启用优先,再按名称/类型/ID | 全部为启用资源,按名称/类型/ID |
## 11. 影响评估 / 回滚
- **是否破坏向后兼容**:是;请求删除 `status`,响应删除和改名字段。
- **前端是否必须同步上线**:已接入首版接口的前端必须同步迁移;尚未接入的前端直接按新契约实现。
- **回滚影响**:若后端回滚到首版,`resourceTypeName/settleTypeName/defaultUnitPrice` 将消失,旧字段和下架资源会重新出现;前后端需保持同一契约版本。
## 12. 前端迁移清单
- [ ] 删除请求中的 `status` 参数和相关状态筛选逻辑。
- [ ] 删除对响应 `status`、`statusName` 的读取、展示与过滤。
- [ ] 将所有 `ticketUnitPrice` 读取改为 `defaultUnitPrice`。
- [ ] 展示资源类型时读取 `resourceTypeName`;编码判断仍使用 `resourceType`。
- [ ] 展示结算方式时读取 `settleTypeName`,并允许该字段为 `null`。
- [ ] 允许 `city`、`settleType`、`settleTypeName`、三个价格字段为 `null`。
- [ ] 不再在前端筛除下架资源;接口结果已经只包含启用资源。
- [ ] `resourceId` 继续按 String 保存和传递。
## 13. 关联 / 联系人
### 13.1 链接
- **Issue**: [#5539](https://git.1814.love:8443/wx/HL/issues/5539)
- **PR**: [#5540](https://git.1814.love:8443/wx/HL/pulls/5540)
- **Merge commit**: [7edbb6026](https://git.1814.love:8443/wx/HL/commit/7edbb6026d7f0d3551ed8c43ca57ea1698ebfeff)
- **前置 Issue**: [#5429](https://git.1814.love:8443/wx/HL/issues/5429)
### 13.2 联系人
- **后端负责人**: @yst
## 关联/联系人
### 链接
- [后端工单 #5539](https://git.1814.love:8443/wx/HL/issues/5539)
- [后端 PR #5540](https://git.1814.love:8443/wx/HL/pulls/5540)
- Merge commit: `7edbb6026d`
### 联系人
- **后端负责人**: @yst
@@ -0,0 +1,83 @@
---
schema: "hl-changelog/v2"
ticket: "5549"
title: "司机保险切换到可售产品 + 不可售产品友好报错"
consumer: "admin"
change_type: "修改接口"
author: "wx(GIT)"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "pi-main-session"
frontend_ref: "hl-admin@085f4d7b58c3d61414df8d0461ab51e9eb61ea47"
target_release: "v2.1"
verified_at: "2026-08-05"
status_note: "管理后台现有投保弹窗已完全消费 driver-plan-options 动态计划,540034 由全局拦截器展示后端友好文案且页面不重复 toast;补充回归测试锁定计划 ID 字符串透传、动态选项和错误分支。后端完成:PR #5553/#5556/#5557 合并 dev-v3 并部署 TEST;网关实测畅心游真实投保成功(保单 11209006600507256500)、不可售产品 540034 友好报错、plan-options 过滤真实生效。"
updated_at: "2026-08-05"
base: "dev-v3"
---
# 司机保险切换到可售产品 + 不可售产品友好报错(#5549)
> **服务**: hl-order-service-v3
> **PR**: #5553 / #5556 / #5557
> **Issue**: #5549(P1)
> **联系人**: @wx
> **日期**: 2026-08-05
> **影响范围**: 管理后台-司机档案-保险投保;fleet 司机保险页(Feign 消费 driver-purchase / driver-plan-options)
---
## 背景
畅心游产品费率码旧值(BY919212138521)失效导致投保必 404(#5545 排查);保游 GetProductList 下架产品本地不更新、司机端仍可选。需求:司机保险切到可售产品(未来星等)、不可售产品报错友好。
## 变更接口
| 方法 | 路径 | 来源 |
|---|---|---|
| POST | /v3/internal/insurance/driver-purchase | fleet 司机保险投保(Feign) |
| GET | /v3/internal/insurance/driver-plan-options | fleet 司机保险计划下拉(Feign) |
## 变更说明
1. **同步链路**(保险产品同步 /v3/admin/insurance/sync-products):以保游 GetProductList 为权威可售列表,列表外的存量启用产品标记 INACTIVE(下架自动失效)
2. **投保链路** driver-purchase:
- 本地拦截:产品 INACTIVE(下架标记)→ 新错误码 **540034**
- 保游 404(费率码失效)→ 翻译 **540034**
- 保游业务拒绝(501 URL 地址受限 / 地址受限 / 下架 / 失效)→ 翻译 **540034**(替代 540030 裸透传)
3. **plan-options**:过滤 INACTIVE 产品与孤儿计划的计划;司机端不再看到下架产品
## 接口行为变化
| 接口 | 修复前 | 修复后 |
|---|---|---|
| `POST driver-purchase`(不可售产品) | 540030「为投保人投保失败: [501]url地址受限」/ 裸 404 | **540034「该产品已下架/不可售,请更换可售产品」** |
| `POST driver-purchase`(可售产品) | 不变 | 不变(畅心游真实投保成功,保单号非 MOCK) |
| `GET driver-plan-options` | 仅畅心游 20万计划 | 畅心游 20万 + 未来星 20/30/50万(未来星产品计划 usage_category 已标注 BOTH);INACTIVE 产品被过滤 |
## 新增错误码
| 错误码 | 消息 |
|---|---|
| 540034 | 该产品已下架/不可售,请更换可售产品 |
## 验证证据
- 网关实测(2026-08-05,内部接口 SSH 直连 8086):
- 畅心游投保 → 200,extOrderNo=BX2026080517395620000670,回调后 INSURED + 真实保单号 **11209006600507256500**(非 MOCK)
- 未来星投保 → **540034**「该产品已下架/不可售,请更换可售产品」(保游 501 URL 受限翻译)
- plan-options → 4 计划(畅心游+未来星 20/30/50万);临时标 INACTIVE 后过滤只剩畅心游,恢复后 4 计划
- 定向测试:InsuranceCreateServiceTest/InsuranceManageServiceTest/InsuranceQueryServiceTest 111/111(新增 5 用例:540034 本地拦截/404 翻译/501 翻译/plan-options 过滤/同步标 INACTIVE)
## 关联/联系人
### 链接
- [后端工单 #5549](https://git.1814.love:8443/wx/HL/issues/5549)
- [后端 PR #5557](https://git.1814.love:8443/wx/HL/pulls/5557)
- Merge commit: `269b565cd9`
### 联系人
- **后端负责人**: @wx
@@ -0,0 +1,64 @@
---
schema: "hl-changelog/v2"
ticket: "5552"
title: "派车板详情日历价列快照缺失时按车型实时兑底回显(不再显示 ¥0)"
consumer: "admin"
author: "wx(GIT)"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "pi-main-session"
frontend_ref: "N/A:前端字段已存在,仅后端取值变化,无需前端改动"
target_release: ""
verified_at: ""
status_note: ""
updated_at: "2026-08-05"
base: "dev-v3"
---
# 派车板订单详情:日历价列兑底回显
> **服务**: hl-fleet-service
> **PR**: #5554、#5555
> **Issue**: #5552
> **日期**: 2026-08-05
> **影响范围**: 管理后台派车板订单详情(每日派车计划 + 当前派车逐日费用)
## 变更接口
| 接口 | 方法 | 路径 | 变更 |
|---|---|---|---|
| 派车板订单详情 | GET | `/admin/fleet/board/orders/(订单ID)` | `dailyVehiclePlan[].calendarPrice`、`currentAssignment.dailyVehicleFees[].calendarPrice` 在快照缺失(历史派车时日历未设价,`vehicle_fee_calendar_price` 为 NULL)时,按车辆车型(vehicleModelId,价格日历取价键)+ 服务日实时取日历价兑底回显 |
### 响应字段语义变更
| 字段 | 类型 | 旧语义 | 新语义 |
|---|---|---|---|
| `dailyVehiclePlan[].calendarPrice` | `BigDecimal` / null | 已派行快照缺失时为 null(前端显示 ¥0) | 快照缺失时兑底为当前日历价(如 800.00);快照有值保持冻结价 |
| `dailyVehicleFees[].calendarPrice` | `BigDecimal` / null | 同上 | 同上,`calendarPriceMissing` 同步变 false |
| `dailyVehiclePlan[].assignmentPrice` | `BigDecimal` | 协议价快照 | **不变**(快照保持,不随兑底篡改) |
| `dailyVehiclePlan[].priceSource` | `String` | CALENDAR/OVERRIDE/MISSING 判定 | **不变**(按兑底后日历价与协议价比较判定) |
取价键说明:`fleet_pricing_calendar` 按 `vehicle_model_id`(车型)维护;兑底链路为 `vehicle_id → vehicle_model_id → 日历价`,绝不按 vehicleId 查日历。
## 验证证据
- 网关实测 `GET /admin/fleet/board/orders/2080599963561005058`:
- 蒙A-H7777(2026-08-01~03):`calendarPrice=800.00`(原 NULL)、`assignmentPrice=600/610/620`(快照保持)、`priceSource=OVERRIDE`
- 蒙A-E5555:`calendarPrice=2500.00`(原 NULL)
- `currentAssignment.dailyVehicleFees`(2026-08-04):`calendarPrice=800.00`、`calendarPriceMissing=false`(原 NULL/true)
- 新派车行(蒙C05E05 08-20~25):`calendarPrice=1000.00` CALENDAR(快照落库正确,不受影响)
- 测试:BoardOrderServiceTest 80 + VehicleServiceTest 113 全绿;spotless 0 违规
## 关联/联系人
### 链接
- [后端工单 #5552](https://git.1814.love:8443/wx/HL/issues/5552)
- [后端 PR #5555](https://git.1814.love:8443/wx/HL/pulls/5555)
- Merge commit: `da565dec88`
### 联系人
- **后端负责人**: @wx
@@ -0,0 +1,104 @@
---
author: "wx(GIT)"
schema: "hl-changelog/v2"
ticket: "5558"
title: "司机保单新增 policyPdfUrl(在线查看保单 PDF)+ 投保 bindAnnual 缺省语义变更"
consumer: "admin"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "pi-main-session"
frontend_ref: "hl-admin@3e535fe3ad6a406529eb95d7787cefe11b9584cd"
target_release: "v2.1"
verified_at: "2026-08-06"
status_note: "司机详情与车务保险列表/详情仅在 policyPdfUrl 非空时显示查看保单并安全新窗口预览;空值隐藏且不再回退旧下载接口,投保沿用 bindAnnual 缺省绑定全年保险语义。"
updated_at: "2026-08-05"
base: "dev-v3"
---
# 司机险:保单行在线查看保单 PDF + 投保缺省绑定全年保险
> **服务**:hl-fleet-service + hl-order-service-v3 + hl-common
> **PR**:#5563
> **Issue**:[wx/HL #5558](https://git.1814.love:8443/wx/HL/issues/5558)
> **日期**:2026-08-05
> **影响范围**:管理后台司机详情「我的保单」区域、车务保险保单 Tab
## 变更接口
| 接口 | 方法 | 路径 | 变更 |
|---|---|---|---|
| 司机我的保单列表 | GET | `/admin/fleet/drivers/<driverId>/insurance/policies` | 每条记录新增 `policyPdfUrl` |
| 司机险保单列表(车务保险) | GET | `/admin/fleet/insurance/policies` | 每条记录新增 `policyPdfUrl` |
| 司机险保单详情 | GET | `/admin/fleet/insurance/policies/<insuranceOrderId>` | 响应新增 `policyPdfUrl` |
| 司机险投保 | POST | `/admin/fleet/drivers/<driverId>/insurance/purchase` | `bindAnnual` 缺省语义变更 |
## 二、响应字段
| 字段 | 类型 | 必填性 | 值 | 说明 |
|---|---|---|---|---|
| `policyPdfUrl` | `String` | 条件返 | 保游生成后上传 OSS 的 PDF 直链 | 保单行「查看保单」按钮数据源;空值=保单 PDF 未生成/无电子保单(MOCK 单、MANUAL 年保单),前端应隐藏查看入口 |
响应示例(司机我的保单列表):
```json
{
"code": 200,
"data": [
{
"insuranceOrderId": "2084941753793552386",
"policyNo": "11209006600507254235",
"status": "INSURED",
"totalPremium": "7.00",
"policyPdfUrl": "https://hlgl-test.oss-cn-beijing.aliyuncs.com/insurance/policy/2026/08/05/policy_2084941753793552386.pdf"
}
],
"success": true
}
```
> 投保出参(purchase 响应)也携带 `policyPdfUrl` 字段,但出单受理瞬间 PDF 尚未异步生成,恒为空。
## 三、入参语义变更(bindAnnual 缺省)
| 入参 | 旧语义 | 新语义 |
|---|---|---|
| `bindAnnual` 缺省(不传) | false:只出单不动档案 | **true:直接购买默认全年保险**,出单成功后自动绑定司机档案(insurance_type=annual + 保单号/保费/起止回填 + annualSource=baoyou) |
| `bindAnnual: false` | 只出单不动档案 | 不变:只出单不动档案 |
| `bindAnnual: true` | 出单后绑定档案 | 不变 |
**背景**:司机详情页投保不传 `bindAnnual`,旧语义下保单落库但档案保险状态不同步(有保单显示但档案 `insurance_type=none`)。
## 四、兼容性与前端事项
- 三处响应均为**向后兼容的字段扩展**,不修改既有字段与分页结构。
- `bindAnnual` 缺省语义变更:前端若存在"只出单不动档案"的调用场景,需显式传 `false`;司机详情页/保险订单页投保路径无需改动(缺省即绑定档案)。
- 前端事项:
1. 司机详情「我的保单」列表与车务保险保单 Tab:保单行增加「查看保单」按钮,`policyPdfUrl` 非空时可点击;浏览器内嵌预览(`window.open(policyPdfUrl)` 或 iframe),**不触发下载**。
2. `policyPdfUrl` 为空时隐藏查看入口。
- 后端未修改 `mmg/hl-ui`,前端消费状态保持 `pending`。
## 验证证据
- `DriverInsuranceServiceTest`:25 项通过(含 #5558 缺省绑定新语义用例)。
- order-v3 保险域全量:229 项通过(三链 `policyPdfUrl` 断言)。
- fleet verify:仅 2 个仓库基线失败(`Step2CanonicalSnapshotServiceTest`、`ReleaseEOccupancyMysql8033RecoveryTest`,dev-v3 干净工作区同失败,与本次改动无关)。
- 测试服部署:hl-fleet-service + hl-order-service-v3 滚动部署成功(20:13/20:14)。
- 网关验证:三个查询接口 `policyPdfUrl` 透传通过;真实保游单返回 OSS PDF 直链(Content-Type: application/pdf,浏览器内嵌预览),MOCK 单返回 null。
- MOCKPOL 残留清理(2026-08-05 21:40):manifest `5558-70cdf37dc3be`(hl-data-cleanup/v1,test)批准执行,删除 mock 时段假保单全关联 4 行(`insurance_order`/`insured_person`/`insurance_status_log`/`fleet_insurance_task`),备份至 `manifests/5558-mock-policy-cleanup.backup.json`;网关复验司机46622 我的保单=空列表、车务保单列表=4 条真单(PDF 全直链)、档案 `insurance_type=none` 未变。
- 投保端到端(缺省绑定档案)验证:保游测试环境 20:15 起 `POST /Insurance/Insuran` 真实投保请求 Read timed out(第三方不可用,17:02~17:57 曾成功出单)。按 wx 指示**跳过保游端到端**(2026-08-05 22:20),以 DriverInsuranceServiceTest 缺省绑定单测 + 契约链路代码审查 + 无保单场景网关验证为验收依据;预期投保成功 → 档案 `insurance_type=annual` + 四件套回填(bindAnnual 缺省=true 已部署)。
- oasdiff:`not_configured`,一期项目没有稳定 OAS3 导出与已配置工具,使用源码和 JSON 序列化测试回退。
- Spring Cloud Contract:`not_configured`,使用生产者及消费者 reactor 测试回退。
## 关联/联系人
### 链接
- **后端工单**: [#5558](https://git.1814.love:8443/wx/HL/issues/5558)
- **后端 PR**: [#5563](https://git.1814.love:8443/wx/HL/pulls/5563)
- **Merge commit**: [`b0685cca8d`](https://git.1814.love:8443/wx/HL/commit/b0685cca8d)
### 联系人
- **后端负责人**: @wx
@@ -0,0 +1,77 @@
---
schema: "hl-changelog/v2"
ticket: "5559"
title: "派单候选接口新增司机自动代入建议(suggestedDriverId/reason/message)"
consumer: "admin"
author: "wx(GIT)"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "pi-main-session"
frontend_ref: "hl-admin@c6b107b89320e3bc9103314cd8eb5ef32897f51f"
target_release: "v2.1"
verified_at: "2026-08-05"
status_note: "管理后台矩阵/看板共用派单弹窗已接入三类司机自动建议;建议仅使用本次真实可用候选并携车辆、司机二次校验,NONE 清空本轮旧司机并展示后端提示,多槽位排除、人工改选、跨常驻确认和请求竞态门禁保持。"
updated_at: "2026-08-05"
base: "dev-v3"
---
# 矩阵派单司机自动代入:候选接口返回代入建议
> **服务**: hl-fleet-service
> **PR**: #5560、#5561
> **Issue**: #5559
> **日期**: 2026-08-05
> **影响范围**: 管理后台派单弹窗(矩阵派单/看板共用候选接口)
## 变更接口
| 接口 | 方法 | 路径 | 变更 |
|---|---|---|---|
| 派单候选资源查询 | POST | `/admin/fleet/assignments/candidates` | 响应新增 `suggestedDriverId`、`suggestedDriverReason`、`suggestedDriverMessage`(选车后司机自动代入建议) |
## 响应字段(顶层新增)
| 字段 | 类型 | 必填性 | 值 | 说明 |
|---|---|---|---|---|
| `suggestedDriverId` | `Long` / null | 否 | 司机雪花 ID | 已选车辆的自动代入司机;未选车或无空闲司机为 null |
| `suggestedDriverReason` | `String` | 否 | `RESIDENT_AVAILABLE` / `RESIDENT_BUSY_FALLBACK` / `FIRST_AVAILABLE` / `NONE` | 代入原因码 |
| `suggestedDriverMessage` | `String` | 否 | 中文文案 | 后端可直接展示的代入原因 |
### 代入规则
1. 已选车辆(`selectedVehicleId`)有**常驻司机且空闲** → 代入常驻司机(`RESIDENT_AVAILABLE`);常驻司机权威源为车辆候选列表 `primaryDriverId`(与前端展示同源),不依赖 `VehicleDO.primary_driver_id` 投影
2. 常驻司机**档期冲突/停用/休息** → 回退代入司机候选排序后第一个**纯空闲**司机(`RESIDENT_BUSY_FALLBACK`)
3. **无常驻司机** → 代入排序后第一个空闲司机(`FIRST_AVAILABLE`;SMART 排序:可用性→评分→完成单量→年限)
4. **无任何空闲司机或未选车** → `suggestedDriverId=null`、`NONE`
空闲判定与候选一致(无 blocking 档期冲突);同城衔接共享(`CITY_JUNCTION_SHAREABLE`)不自动代入(需人工决策)。
## 前端配合
派单弹窗**选车后**以 `suggestedDriverId` 填充司机选择:
- 现有逻辑只代入常驻司机(且常驻忙时不回退、无常驻不代入)→ 改用 `suggestedDriverReason` 三态:`RESIDENT_AVAILABLE`/`RESIDENT_BUSY_FALLBACK`/`FIRST_AVAILABLE` 均自动选中对应司机;`NONE` 保持手动选择并展示 `suggestedDriverMessage`
- `suggestedDriverId` 为 null 时清空司机选择(`NONE`)
## 验证证据
- 网关实测(TEST,2026-08-05):
- 蒙A-K1999/S6666/T1557 常驻空闲 → `RESIDENT_AVAILABLE`(代入常驻司机,其 `available=true`)
- 蒙C04E04(无常驻)→ `FIRST_AVAILABLE`(代入朝鲁门,`available=true`)
- 蒙A-H7777(常驻阿拉坦 08-10~12 有 2 个 blocking 档期冲突)→ `RESIDENT_BUSY_FALLBACK`(回退朝鲁门,`available=true`)
- 蒙A-G8888(常驻司机停用,候选列表仍有 `primaryDriverId`)→ `RESIDENT_BUSY_FALLBACK`(回退空闲司机)
- 未传 `selectedVehicleId` → `suggestedDriverId=null`、`NONE`
- 测试:AssignmentCandidateServiceTest 41 全绿(新增 7 场景:常驻可用/档期冲突回退/停用回退/无常驻/无空闲/未选车/VehicleDO 投影缺失);fleet 全量 3155 仅 1 既有基线 flaky;spotless 0 违规
## 关联/联系人
### 链接
- [后端工单 #5559](https://git.1814.love:8443/wx/HL/issues/5559)
- [后端 PR #5561](https://git.1814.love:8443/wx/HL/pulls/5561)
- Merge commit: `efb981ca2a`
### 联系人
- **后端负责人**: @wx
@@ -0,0 +1,67 @@
---
schema: "hl-changelog/v2"
ticket: "5562"
title: "用车需求槽位模型改为全程槽(expand 生成按车型全程行,车务每槽派 1 辆管全程)"
consumer: "admin"
author: "wx(GIT)"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "pi-main-session"
frontend_ref: "hl-admin@0da93eaef206f5daa85b99f45ecd0fd07873d5fc"
target_release: "v2.1"
verified_at: "2026-08-06"
status_note: "后端完成:PR #5568(全程槽模型)+ #5569(换版沿用修复)已合并 dev-v3 并部署 TEST;网关验证通过(全新展开 2 条全程行 / 换版保持全程行 / 每槽派 1 辆管全程 / 整组删 removedRowCount=1 / 按天派生展示不回归)。前端槽位列表与派车交互按全程槽语义适配。"
updated_at: "2026-08-05"
base: "dev-v3"
generated: "2026-08-05T22:45:18+08:00"
---
# 用车需求槽位模型改为全程槽(expand 生成按车型全程行,车务每槽派 1 辆管全程)
> 后端完成:PR #5568/#5569 已合并 dev-v3 并部署 TEST,网关验证 7/7 通过。
## 关联 / 联系人
### 链接
- **Issue**: [#5562](https://git.1814.love:8443/wx/HL/issues/5562)
- **PR**: [#5568](https://git.1814.love:8443/wx/HL/pulls/5568)(全程槽模型)、[#5569](https://git.1814.love:8443/wx/HL/pulls/5569)(换版沿用修复)
- **Merge commit**: [e051fb93d](https://git.1814.love:8443/wx/HL/commit/e051fb93d)、[41792d8b9](https://git.1814.love:8443/wx/HL/commit/41792d8b9)
### 联系人
- **后端负责人**: @wx
## 背景(wx 口径)
槽位**数据模型本身**改为全程槽:定制师需求(例 1 SUV + 1 商务 × 4 天)→ `expand` 默认生成 **2 条全程行**(SUV 全程槽 + 商务全程槽,各覆盖整个服务期),车务在每槽派 1 辆管全程的车,槽可修改/删除。**不是**按天 8 条散装切片 + 展示层聚合。存量按天数据不迁移(兼容运行),对账/逐日展示/行程/矩阵等按天界面从全程行派生,保持不变。
## 变更接口
| 方法 | 路径 | 来源 |
|---|---|---|
| `PUT` | `/v3/admin/order/{id}/vehicle-requirement` | `VehicleRequirementAdminController`(order-v3)→ 触发 fleet expand |
路径前缀 `/v3/admin/**` 与 `/admin/fleet/**` 已由网关登录/角色校验收口,无需新增网关规则。**契约字段无变化**:需求提交 VO(fleet[] 车型组合)与既有看板/详情/候选/派车/删除接口字段全部不变,变化在 Fleet 落库模型与派生行为。
## 模型行为(fleet_assignment)
- **新展开**:每需求×车型 1 条全程行——`start_date`/`end_date` 覆盖整个服务期,`service_date`/`assignment_group_id` 均为 NULL(1SUV+1商务×4天 = 2 条 unassigned 行)
- **派车**:create/batchCreate 在全程行上直接升级为 1 条 `assigned` 全程行(每槽 1 辆管全程);改派在槽上换车/司机
- **删除**:`DELETE /admin/fleet/assignments/slots/{slotId}` 整组删(removedRowCount=1)+ `fleet_assignment_slot_removal` 持久化防展开复活
- **换版**:服务期一致时全程行沿用(rebind 保持 group_id IS NULL);日期变化取消重建
- **按天派生**(显示/对账/快照层不变):看板 `dailyVehiclePlan`、矩阵、DAILY_V3 快照、Step2 canonical 候选、对账/保险均从全程行按服务期展开逐日
## 前端/调用方动作
1. 车务槽位列表默认呈现"一条管全程"的槽位(详情 `vehicleSlots[]`、看板 `assignmentSlots[]` 已是全程区间语义);**删除按钮**调 `DELETE /admin/fleet/assignments/slots/{slotId}`(605007 已派拒绝/605012 不存在)
2. 派车弹窗按全程区间提交(`startDate`=服务开始、`endDate`=服务结束、每槽 1 辆 1 司机);最终方案提交仍按逐日 `dailyPlan[]`(同槽各日须同一车/司机,后端整槽聚合)
3. 逐日细节(每日车/司机/价格/接送)继续用 `dailyVehiclePlan`,展示不变
## 验证证据
- 定向测试:fleet verify 全绿(3159 用例 + Testcontainers);新增全程行展开/派车/换版沿用/DAILY_V3 派生/看板派生测试
- 网关验证(TEST):全新展开 2 条全程行落库 → 换版保持全程行 → 每槽派 1 辆管全程(assigned 全程行)→ 整组删 removedRowCount=1 → 详情 1 条全程槽(canDelete/阻断原因)→ dailyVehiclePlan 派生 6 天不回归
- 兼容性结论:存量按天数据兼容运行(不迁移);legacy 区间行迁移逻辑保留
@@ -0,0 +1,108 @@
---
schema: "hl-changelog/v2"
ticket: "5537"
title: "车务保险保单查看(手动保单可见)+ 任务/保单筛选加司机名"
consumer: "admin"
change_type: "新增接口"
author: "wx(GIT)"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "pi-main-session"
frontend_ref: "hl-admin@d5235e2d89ce009fbad251cf1428ba304333524c"
target_release: ""
verified_at: ""
status_note: "后端完成:PR #5543 已合并 dev-v3(merge e0cf4a47e)并部署 TEST;网关验证通过(保单列表/司机名筛选/详情/非法状态 400)。前端需在车务保险菜单新增保单 Tab(见展示矩阵)。"
updated_at: "2026-08-05"
base: "dev-v3"
---
# 车务: 保险保单查看(手动保单可见)+ 司机名筛选
> **服务**: hl-fleet-service + hl-order-service-v3(内部接口)
> **PR**: #5543
> **Issue**: [#5537](https://git.1814.love:8443/wx/HL/issues/5537)
> **日期**: 2026-08-05
## 背景
车务保险页面(`/admin/fleet/insurance`)此前只有任务视图(`tasks` 接口 = `fleet_insurance_task` 投退保流水),**手动投保的保单(`insurance_order` bizType=DRIVER)不可见**(排查实证:任务表 PURCHASE+SUCCESS+BAOYOU=0,手动投保从不落任务)。本次新增**保单维度**展示 + 手动投保成交自动落任务。
## 变更接口
| 方法 | 路径 | 来源 |
|---|---|---|
| `GET` | `/admin/fleet/insurance/policies` | `FleetInsuranceTaskController`(fleet) |
| `GET` | `/admin/fleet/insurance/policies/{insuranceOrderId}` | 同上 |
| `GET` | `/admin/fleet/insurance/tasks` | 同上(**新增 `driverName` 参数**) |
| `GET` | `/v3/internal/insurance/policy-page` | `InternalInsuranceController`(order,Feign 内部) |
| `GET` | `/v3/internal/insurance/policy/{insuranceOrderId}` | 同上(Feign 内部) |
路径前缀 `/admin/fleet/**` 已由网关登录/角色校验与 `FleetAdminRoleGuardInterceptor`(VEHICLE_MANAGER / SUPER_ADMIN)收口,无需新增网关规则。
## 1. 保单列表 `GET /admin/fleet/insurance/policies`
请求参数(query,均选填):
| 参数 | 类型 | 说明 |
|---|---|---|
| `page` / `pageSize` | int | 分页(pageSize ≤100) |
| `driverName` | string | 司机名/被保人姓名模糊搜索(两步查 insured_person) |
| `policyNo` | string | 保单号精确(ext_policy_no) |
| `status` | string | PENDING=待出单 / INSURING=出单中 / INSURED=已承保 / CANCELLED=已退保 / FAILED=投保失败;非法枚举返 400 明确业务错误 |
| `coverageStartDateFrom` / `coverageStartDateTo` | date | 保障起期区间(按 start_date) |
响应 `data`(PageResult):
| 字段 | JSON 类型 | 说明 |
|---|---|---|
| `insuranceOrderId` | string(Long) | 保单 ID(雪花字符串) |
| `policyNo` | string | 保单号 |
| `extOrderNo` | string | 保游外部订单号(可空) |
| `totalPremium` | string(BigDecimal) | 保费(元) |
| `status` / `statusLabel` | string | 状态码 + 中文标签 |
| `source` | string | BAOYOU / MANUAL |
| `coverageStartDate` / `coverageEndDate` | date | 保障期间 |
| `insuredName` | string | 被保人姓名(首位;司机险一人一单) |
| `productName` / `planName` | string | 险种(产品·计划,可空) |
| `driverId` | string(Long) | 司机 ID(bizId) |
| `createTime` | string | 创建时间 |
**展示矩阵**:
- 数据源:`insurance_order`(bizType=DRIVER,与司机详情保单区域同源)+ `insured_person` + `insurance_plan/product`
- 列建议:保单号 / 被保人 / 险种(产品·计划)/ 保费 / 保障期间 / 状态 / 创建时间
- **保额**:产品/计划/费率表均无权威结构化保额字段,**不展示保额列**(如需展示需保游产品侧补字段,另行排期)
- 状态色:INSURED 绿、PENDING/INSURING 橙、CANCELLED 灰、FAILED 红
- 空态:空列表 + 提示"暂无保单"
## 2. 保单详情 `GET /admin/fleet/insurance/policies/{insuranceOrderId}`
响应 `data`:列表项全部字段 + `extPolicyNo` / `insuredPersons`(姓名+脱敏证件号,保前 3 尾 4)/ `planId` / `policyHolderName` / `remark` / `updateTime`。
错误码:**540201** 保单不存在或非司机险 / **605601** 保险服务不可用 / 401 未登录。
## 3. 任务列表新增 `driverName` 筛选
`GET /admin/fleet/insurance/tasks?driverName=斯琴`:按任务快照 `driver_name` 模糊匹配。**原有枚举校验(taskType/taskStatus/source 非法值 400)保持不变**。
## 4. 手动投保落任务(后端行为变更)
手动投保(`POST /admin/fleet/drivers/{driverId}/insurance/purchase`)出单成功(保单状态 INSURED)后,自动在 `fleet_insurance_task` 落一条 PURCHASE+SUCCESS 流水(bizKey=`MANUAL_PURCHASE:{保单ID}`,幂等;落库失败仅告警不反噬投保)。任务列表(含司机名筛选)可查到手动保单任务;**受理期(INSURING)保单不落任务**,由保单 Tab 覆盖可见性。
## 前端配合
1. 车务保险菜单新增**保单 Tab**(复用 tasks 页面框架),列与筛选见展示矩阵;
2. tasks Tab 筛选区增加**司机名**输入框(模糊搜索);
3. 保单号点击打开详情抽屉(被保人证件号已脱敏,无需前端二次处理)。
## 关联/联系人
### 链接
- [后端工单 #5537](https://git.1814.love:8443/wx/HL/issues/5537)
- [后端 PR #5543](https://git.1814.love:8443/wx/HL/pulls/5543)
- Merge commit: `e0cf4a47ef`
### 联系人
- **后端负责人**: @wx
@@ -0,0 +1,305 @@
---
schema: "hl-changelog/v2"
ticket: "5567"
title: "历史终止订单车辆核单空态"
consumer: "admin"
change_type: "修改接口"
author: "yst(GIT)"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "pi-main-session"
frontend_ref: "hl-admin@4a2dcc8e20fe23ffc2b3d35ae8f02e62661b642d"
target_release: "v2.1"
verified_at: "2026-08-06"
status_note: "PR #5570 已合并 dev-v3;2026-08-10 复核确认测试服已部署、网关链路实测连通(见文末验证证据章节)。管理后台待适配新增阻断枚举。"
updated_at: "2026-08-10"
base: "dev-v3"
---
# 🔧【修改接口·管理后台】历史终止订单车辆核单空态 (#5567)
> **PR**:[#5570](https://git.1814.love:8443/wx/HL/pulls/5570) | **服务**:`hl-order-service-v3` | **更新时间**:2026-08-06 | **消费端**:管理后台
## 1. 接口背景
部分历史终止订单只有旧版车辆费用记录,无法还原为当前车辆核单的权威金额。此类订单只需要安全展示为“缺少权威车辆费用来源、不可完成核单”,不应把它当作车务临时故障,也不得把未知金额当成 0 元已确认。
## 2. 变更清单
| # | 接口名 | 方法 | 路径 | 变更类型 | 说明 |
|---|---|---|---|---|---|
| 1 | 查询车辆核单草稿 | `GET` | `/v3/admin/order/{orderId}/settlement/step3/vehicles` | 修改 | `blockReasonCode` 新增 `LEGACY_VEHICLE_FEE_SOURCE_MISSING`;严格历史终止 LEGACY 场景由 `584100` 改为 `code=200` 的安全阻塞空态 |
## 3. 接口详情
### 3.1 查询车辆核单草稿
- **接口说明**:查询车辆 Tab 当前全量明细、草稿版本、确认状态,以及车辆费用是否具备完成核单条件。
- **使用场景**:进入管理后台订单核单的车辆 Tab 或刷新车辆核单状态。
- **认证**:需要管理后台登录态和订单查看权限;房务角色不可访问。
- **幂等性**:是,只读查询。
- **限流**:未声明接口级独立限流规则。
## 4. 接口入参
### 4.1 路径参数 / Query 参数
| 字段 | 位置 | 类型 | 必填 | 说明与校验 |
|---|---|---|---|---|
| `orderId` | Path | String(Long) | 是 | 订单 ID,必须为正整数;按字符串传递,避免大整数精度损失 |
无 Query 参数。
### 4.2 请求体字段
GET 请求无请求体。
## 5. 出参字段
响应类型:`Result<SettlementVehicleFeesRespVO>`。
### 5.1 统一响应外层
| 字段 | 类型 | 可空 | 说明 |
|---|---|---|---|
| `code` | Integer | 否 | 成功为 `200`;失败见 §7 |
| `message` | String | 否 | 结果说明 |
| `data` | VehicleDraft/null | 失败时为空 | 成功时为车辆核单草稿 |
| `traceId` | String | 是 | 链路追踪 ID |
| `success` | Boolean | 否 | `code=200` 时为 `true` |
### 5.2 成功响应 `data`
| 字段 | 类型 | 可空 | 说明 |
|---|---|---|---|
| `orderId` | String(Long) | 否 | 订单 ID,按字符串返回 |
| `version` | Long | 否 | 当前车辆核单草稿版本;安全阻塞空态为 `0` |
| `totalAmount` | Decimal/null | 是 | 当前明细总金额;`LEGACY_VEHICLE_FEE_SOURCE_MISSING` 时必须为 `null`,表示金额未知,不是 `0.00` |
| `allConfirmed` | Boolean | 否 | 非空明细是否全部确认;LEGACY 安全阻塞空态固定为 `false` |
| `settlementReady` | Boolean | 否 | 车辆费用是否具备完成核单条件;LEGACY 安全阻塞空态固定为 `false` |
| `blockReasonCode` | String/null | 是 | 不具备条件时的机器可读原因,完整取值见 §6;具备条件时为 `null` |
| `items` | VehicleItem[] | 否 | 当前全量明细;LEGACY 安全阻塞空态固定为 `[]` |
### 5.3 `data.items[]`
| 字段 | 类型 | 可空 | 说明 |
|---|---|---|---|
| `id` | String(Long) | 否 | 车辆核单明细 ID |
| `sourceType` | String | 否 | 来源类型:`FLEET` 或 `MANUAL` |
| `sourceTypeName` | String | 否 | 来源名称:车务或手工 |
| `serviceDate` | String(date) | 否 | 服务日期,格式 `YYYY-MM-DD` |
| `vehicleId` | String(Long) | 是 | 车辆 ID |
| `vehiclePlate` | String | 是 | 车牌号 |
| `vehicleModelId` | String(Long) | 是 | 车型 ID |
| `vehicleModelName` | String | 是 | 车型名称 |
| `driverId` | String(Long) | 是 | 司机 ID |
| `driverName` | String | 是 | 司机姓名 |
| `amount` | Decimal | 否 | 核单金额 |
| `paymentMethod` | String | 否 | 付款方式编码 |
| `paymentMethodName` | String | 否 | 付款方式名称 |
| `settlementConfirmStatus` | String | 否 | 确认状态编码:`UNCONFIRMED` 或 `CONFIRMED` |
| `settlementConfirmStatusName` | String | 否 | 确认状态名称:未确认或已确认 |
| `remark` | String | 是 | 备注 |
| `voucherUrls` | String[] | 否 | 凭证 URL;无凭证时为 `[]` |
## 6. 枚举 / 数据字典
### 6.1 `blockReasonCode`
**所属字段**:`data.blockReasonCode` | **类型**:String/null | **可空**:是
| 值 | 中文 | 说明 |
|---|---|---|
| `VEHICLE_FEE_NOT_READY` | 车辆费用尚未就绪 | 有当前用车需求,但尚无可返回的车辆费用明细;`settlementReady=false`、`totalAmount=0.00`、`allConfirmed=false`、`items=[]` |
| `LEGACY_VEHICLE_FEE_SOURCE_MISSING` | 历史车辆费用权威来源缺失 | 历史终止 LEGACY 场景无法确认权威车辆金额;`settlementReady=false`、`totalAmount=null`、`allConfirmed=false`、`items=[]` |
| `null` | 无阻断原因 | 车辆费用来源已就绪;为 JSON 空值,不是字符串 `"null"` |
### 6.2 `items[].sourceType`
| 值 | 中文 | 说明 |
|---|---|---|
| `FLEET` | 车务 | 车务来源的车辆核单明细 |
| `MANUAL` | 手工 | 管理后台手工维护的车辆核单明细 |
### 6.3 `items[].paymentMethod`
| 值 | 中文 | 说明 |
|---|---|---|
| `CASH_PAID` | 现金已付 | 现金支付 |
| `SIGNED` | 签单 | 按签单方式结算 |
| `COMPANY_PAID` | 公司付款 | 由公司支付 |
### 6.4 `items[].settlementConfirmStatus`
| 值 | 中文 | 说明 |
|---|---|---|
| `UNCONFIRMED` | 未确认 | 当前车辆费用行尚未完成核单确认 |
| `CONFIRMED` | 已确认 | 当前车辆费用行已完成核单确认 |
## 7. 错误码
| code | 含义 | 触发场景 |
|---|---|---|
| `200` | 查询成功 | 包括历史终止 LEGACY 安全阻塞空态;此时以 `settlementReady` 和 `blockReasonCode` 判断是否可继续 |
| `400` | 请求参数错误 | `orderId` 不是正整数 |
| `403` | 无访问权限 | 登录态、角色或权限不允许访问 |
| `581007` | 订单不存在 | `orderId` 对应订单不存在 |
| `584071` | 无权访问该订单 | 当前账号不在订单可访问范围内 |
| `584100` | 车辆费用暂时不可用 | 真实车辆快照损坏、依赖故障、响应身份不匹配或必要字段无效;本次不把这些故障转换为空态 |
| `584101` | 车辆费用尚未满足核单条件 | 已有非空车辆明细,但来源未完结或费用条件未满足 |
## 8. 示例
### 8.1 典型成功:历史终止 LEGACY 安全阻塞空态
**请求**:
```http
GET /v3/admin/order/9223372036854775000/settlement/step3/vehicles
Authorization: Bearer <管理后台访问令牌>
```
无请求体。
**响应**:
```json
{
"code": 200,
"message": "成功",
"data": {
"orderId": "9223372036854775000",
"version": 0,
"totalAmount": null,
"allConfirmed": false,
"settlementReady": false,
"blockReasonCode": "LEGACY_VEHICLE_FEE_SOURCE_MISSING",
"items": []
},
"traceId": null,
"success": true
}
```
### 8.2 边界情况:无当前用车需求
**场景说明**:该场景同样返回空数组,但它是合法可继续状态,金额为真实的 `0.00`,与历史 LEGACY 金额未知完全不同。
**请求**:
```http
GET /v3/admin/order/900000000002/settlement/step3/vehicles
Authorization: Bearer <管理后台访问令牌>
```
无请求体。
**响应**:
```json
{
"code": 200,
"message": "成功",
"data": {
"orderId": "900000000002",
"version": 0,
"totalAmount": 0.00,
"allConfirmed": true,
"settlementReady": true,
"blockReasonCode": null,
"items": []
},
"traceId": null,
"success": true
}
```
### 8.3 业务失败:真实车辆快照损坏或依赖故障
**请求**:
```http
GET /v3/admin/order/900000000004/settlement/step3/vehicles
Authorization: Bearer <管理后台访问令牌>
```
无请求体。
**响应**:
```json
{
"code": 584100,
"message": "车务车辆总车费暂时不可用,请稍后重试",
"data": null,
"traceId": null,
"success": false
}
```
## 9. 业务边界
- **适用场景**:仅当订单属于历史终止场景,并被判定为缺少当前权威车辆费用来源的 LEGACY 数据时,返回 `code=200` 和 `LEGACY_VEHICLE_FEE_SOURCE_MISSING`。
- **不可放行**:该安全空态固定为 `totalAmount=null`、`allConfirmed=false`、`settlementReady=false`、`items=[]`。金额是未知,不得转成 `0`,也不得按“0 元且已确认”处理。
- **判断顺序**:先检查 `settlementReady`,再读取 `blockReasonCode`;不能仅凭 `code=200`、`items=[]` 或 `version=0` 判断可完成核单。
- **故障边界**:真实车辆快照损坏、依赖故障、响应身份不匹配或必要字段无效仍可返回 `584100`,不伪装为 LEGACY 安全空态。
- **其他订单**:非历史终止 LEGACY 场景沿用原有车辆核单成功、未就绪或失败契约。
## 10. 修改前后对比
### 10.1 字段级对比
| 字段 | 原来 | 现在 |
|---|---|---|
| `data.blockReasonCode` | `VEHICLE_FEE_NOT_READY` 或 `null` | 新增 `LEGACY_VEHICLE_FEE_SOURCE_MISSING` |
| LEGACY 空态 `data.totalAmount` | 无成功响应字段值 | `null`,明确表示金额未知 |
| LEGACY 空态 `data.allConfirmed` | 无成功响应字段值 | `false` |
| LEGACY 空态 `data.settlementReady` | 无成功响应字段值 | `false` |
| LEGACY 空态 `data.items` | 无成功响应字段值 | `[]` |
### 10.2 行为级对比
| 行为 | 原来 | 现在 |
|---|---|---|
| 历史终止 LEGACY 数据缺少权威车辆费用来源 | 返回 `code=584100`“车务车辆总车费暂时不可用” | 返回 `code=200` 的安全阻塞空态,`blockReasonCode=LEGACY_VEHICLE_FEE_SOURCE_MISSING` |
| 真实车辆快照损坏或依赖故障 | 返回 `584100` | 仍可返回 `584100`,行为不变 |
## 11. 影响评估 / 回滚
### 11.1 影响评估
- **是否破坏向后兼容**:响应字段结构不变,枚举为新增值;但历史终止 LEGACY 场景由失败响应改为成功阻塞响应,依赖捕获 `584100` 的旧控制流需要适配。
- **前端是否必须同步上线**:需要识别新增枚举值,并按 `settlementReady=false` 保持阻塞;不得把 `totalAmount=null` 转成 0 或把空数组视为已确认。
### 11.2 回滚方案
- 若接口行为回滚,历史终止 LEGACY 场景会恢复为 `584100`;前端应同时兼容该错误码和本次新增的安全阻塞空态,避免回滚期间误放行。
## 12. 注意事项
- `totalAmount=null` 表示无法确认权威金额;`0.00` 才表示确定为 0 元,两者不可互换。
- `items=[]` 不代表车辆核单已完成;必须同时读取 `settlementReady` 和 `allConfirmed`。
- `LEGACY_VEHICLE_FEE_SOURCE_MISSING` 是机器可读阻断原因,不是车务临时不可用的别名。
- 不要清除对 `584100` 的失败处理:真实快照损坏和依赖故障仍可能返回该错误码。
## 13. 关联 / 联系人
### 13.1 链接
- **Issue**:[#5567](https://git.1814.love:8443/wx/HL/issues/5567)
- **PR**:[#5570](https://git.1814.love:8443/wx/HL/pulls/5570)
- **Merge commit**:[fbc42f31b173](https://git.1814.love:8443/wx/HL/commit/fbc42f31b17301b078a9b63c3c064eb983807f79)
### 13.2 联系人
- **后端负责人**:@yst / yaosutu
- **前端消费方**:管理后台车辆核单 Tab
## 验证证据(2026-08-10 复核回填,wx)
> 本条 changelog 2026-08-06 推送时 backend_status=pending(未部署),违反「测试服部署+实测后才通知前端」流程。2026-08-10 复核补齐部署与验证证据如下:
- 测试服 hl-order-service-v3 运行版本为 2026-08-10 15:10 构建(dev-v3),晚于 PR #5570 合并点(2026-08-06 08:17),本变更代码已在运行实例中。
- `GET /v3/admin/order/{orderId}/settlement/step3/vehicles` 经网关 9443 + 真 admin token 实测链路连通(普通订单返回既有业务码,行为正常)。
- 测试库当前无 `flow_status=TERMINATED` 的历史终止订单,`LEGACY_VEHICLE_FEE_SOURCE_MISSING` 安全空态场景暂无法端到端复现,该场景行为以合并代码 + 部署点位确认;如前端联调需要真实数据请联系后端造数。
@@ -0,0 +1,72 @@
---
schema: "hl-changelog/v2"
ticket: "5571"
title: "派车价0与未填价格允许发送司机(0价不再被非负金额拦截)"
consumer: "admin"
change_type: "修改接口"
author: "wx(GIT)"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "pi-main-session"
frontend_ref: "hl-admin@e2a060d09a66cdb5b89184e3c35a3fbfd923064f"
target_release: "v2.1"
verified_at: "2026-08-06"
status_note: "后端完成:PR #5577 + #5580 已合并 dev-v3 并部署 TEST;网关实测 0 价 batchCreate 发送司机成功(assigned/protocolPrice=0.00)。前端需确认校验规则放行 0/空价并适配日格价格默认值展示(anchor #5571,hl-ui v2.1 已有 DailyVehicleFeeList 编辑入口,需前端部署后核验)。"
updated_at: "2026-08-06"
base: "dev-v3"
generated: "2026-08-06T01:33:44+08:00"
---
# 派车价0与未填价格允许发送司机(0价不再被非负金额拦截)
> **服务**: hl-fleet-service
> **PR**: [#5577](https://git.1814.love:8443/wx/HL/pulls/5577) + [#5580](https://git.1814.love:8443/wx/HL/pulls/5580)
> **Issue**: [#5571](https://git.1814.love:8443/wx/HL/issues/5571)
> **日期**: 2026-08-06
## 背景
#5571(P1 阻断)协调台浏览器实测:26-4220 派车 2 全程槽派好车/司机后,日格"本次派车价"显示 ¥0.00,行内报"**价格应为非负金额,整数最多 10 位、小数最多 2 位**","下一步·发送给司机"被前端表单校验拦死(0/8 日格无法完成)。wx 口径:**实际派车价格为 0 是允许的**(含团费/内部结算等场景)——0 价不得拦截发送司机。
## 校验出处定位
- 该文案出自**前端** hl-ui v2.1 `src/views/fleet/board/utils/daily-vehicle-plan.js` 提交门禁(`ASSIGNMENT_PRICE_PATTERN` 拒绝空值)与 `DailyVehiclePlanMatrix` 输入校验;**后端 dev-v3 无此文案**。
- 触发链:后端详情 `dailyVehiclePlan[].assignmentPrice` 曾回显 `null`(逐日行未冻结价格时直接取单值 `protocolPrice`),前端显示层兜底为 ¥0.00 但提交校验拿到空值即拦截。
## 变更接口
| 方法 | 路径 | 来源 | 变更 |
|---|---|---|---|
| `POST` | `/admin/fleet/assignments/batch` | `AssignmentController`(fleet) | 语义变更:用车日 `assignmentPrice` 允许为空或 0(未填→日历参考价代入);0 价为合法派车价 |
| `GET` | `/admin/fleet/board/orders/<orderId>` | `BoardOrderController`(fleet) | 语义变更:`dailyVehiclePlan[].assignmentPrice` 不再回显 null——快照价→协议价→日历参考价→0 兜底;`priceSource` 同步(快照源优先,全缺=MISSING) |
| `POST` | `/admin/fleet/assignments/<assignmentId>/change` 等 | `AssignmentController`(fleet) | 语义变更:DAILY_V3 快照豁免矩阵仅约束免费日;收费日 0 价(无豁免原因)不再被拦截 |
字段结构均不变(无新增/删除/改名),仅取值语义与门禁口径调整。
## 前端/调用方动作(anchor #5571)
1. **校验规则放行 0 与空价**:`daily-vehicle-plan.js` 提交门禁与矩阵输入校验应允许 `0` 与空值(空值按 0/日历价兜底,由后端回显保证非 null);仅负数与超精度(整数≤10 位、小数≤2 位)拒绝
2. **日格价格默认值展示**:后端已按"日历参考价代入→0 兜底"回显;前端如遇 `assignmentPrice=null` 的历史数据(修复前已存),可显示 `0.00` 或 `-`,不得触发"价格应为非负金额"拦截
3. **编辑入口**:hl-ui v2.1 已具备 `DailyVehicleFeeList` 日格价格输入框(editable 状态);若当前部署版本无编辑入口,请升级前端或按后端候选参考价自动代入
4. 与日历参考价不一致的 0 价仍必须填写改价原因(`priceAdjustmentReason`,#5292 口径),前端原因输入逻辑保持不变
## 验证证据
- 定向测试:VehicleFeeQuoteServiceTest 16/16(未填→日历价代入、显式 0 价、0 日历价)、AssignmentServiceTest 371/371(null/0 放行、负数/缺司机拒绝)、BoardOrderServiceTest 84/84(回显兜底链:快照 0 优先/日历价回退/全缺 0+MISSING)、DailyVehicleAssignmentSnapshotFactoryTest 9/9(收费日 0 价免豁免、免费日必填豁免);fleet 全量 `mvn -pl hl-fleet-service -am verify`:3168 tests,0 failures,0 errors,4 skipped(含 spotless:check)
- 网关验证(TEST):0 价 batchCreate(HL20260804104759654,5 日 dailyPlan 全 0 价 + 改价原因,holdMode=0)→ code=200 发送司机成功:assigned、protocolPrice=0.00、vehicleFeeTotal=0.00、MANUAL;详情回显 2080599963561005058 8/8 日格 assignmentPrice 非 null 且为逐日快照价(600-730)而非旧 protocolPrice 单值;候选接口日历价参考回显不变(1500.00 CALENDAR)
- 环境说明:MySQL 集成测试依赖 127.0.0.1:3306 固定映射,本机 Docker 端口 TIME_WAIT 竞争导致部分用例偶发失败,清理残留容器+等待端口消退后单独重跑全绿
## 关联/联系人
### 链接
- [后端工单 #5571](https://git.1814.love:8443/wx/HL/issues/5571)
- [后端 PR #5577](https://git.1814.love:8443/wx/HL/pulls/5577)(null/0 门禁放开 + 回显兜底链)+ [#5580](https://git.1814.love:8443/wx/HL/pulls/5580)(快照豁免矩阵放开收费日 0 价)
- Merge commits: [349f97cc5](https://git.1814.love:8443/wx/HL/commit/349f97cc52d572c2465f90d05f797e655be60291)(#5577)、[ce28c53a8](https://git.1814.love:8443/wx/HL/commit/ce28c53a829860b240695792ac6a99e387d9d96e)(#5580)
- 关联:[#5292 逐日派车模型(0 价口径)](https://git.1814.love:8443/wx/HL/issues/5292)、[#5562 全程槽模型](https://git.1814.love:8443/wx/HL/issues/5562)
### 联系人
- **后端负责人**: @wx
- **前端消费**: 待认领(hl-admin)
@@ -0,0 +1,100 @@
---
schema: "hl-changelog/v2"
ticket: "5572"
title: "派车全程槽删除支持已派车联动取消释放(删除按钮点击无响应修复)"
consumer: "admin"
change_type: "修改接口"
author: "wx(GIT)"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "pi-main-session"
frontend_ref: "hl-admin@045434c1926505d7524239e00464d74e66e52d6b"
target_release: "v2.1"
verified_at: "2026-08-06"
status_note: "后端完成:PR #5576 + #5579 已合并 dev-v3 并部署 TEST;网关验证通过(已派车槽删除联动取消+释放占用 cancelledAssignmentCount=5、605007 仅剩 completed/finalized、slot_removal 防复活、修复占用上下文 500)。前端需修复删除按钮 handler 静默 return 并适配已派车槽删除交互(anchor #5572)。"
updated_at: "2026-08-06"
base: "dev-v3"
generated: "2026-08-06T00:10:04+08:00"
---
# 派车全程槽删除支持已派车联动取消释放
> **服务**: hl-fleet-service
> **PR**: [#5576](https://git.1814.love:8443/wx/HL/pulls/5576) + [#5579](https://git.1814.love:8443/wx/HL/pulls/5579)(占用上下文修复)
> **Issue**: [#5572](https://git.1814.love:8443/wx/HL/issues/5572)
> **日期**: 2026-08-06
## 背景
#5572(P1)协调台实测:26-4220 派车页已派车/待确认全程槽的「删除」按钮点击完全无响应。定位结论:
1. **前端**(hl-ui,本单交接):`AssignModal.handleDeleteVehicleSlot` 对已派车槽(`isExistingAssignment`)或非草稿模式**静默 return**(无确认/toast),且 #5562 全程槽 changelog 前端未消费(pending)——按钮显示但点击无事件;
2. **后端**(本单修复):删除接口对 `holding`/`assigned` 槽返回 605007,与 #5562「槽可修改/删除」口径及 #5572 验收「已派车槽位删除的联动(释放车辆/司机占用、日格清理)」冲突。
## 变更接口
| 方法 | 路径 | 来源 |
|---|---|---|
| `DELETE` | `/admin/fleet/assignments/slots/{slotId}` | `AssignmentController`(fleet) |
路径前缀 `/admin/fleet/**` 已由网关登录/角色校验与 `FleetAdminRoleGuardInterceptor`(VEHICLE_MANAGER / SUPER_ADMIN)收口,无需新增网关规则。
## 1. 删除车辆槽位 `DELETE /admin/fleet/assignments/slots/{slotId}`(口径变更)
请求参数不变:`slotId`(PathVar)+ `reason`(Body 选填 ≤200 字)。
**删除规则(业务口径,#5572 变更)**:
- **可删**(含已派车):槽位行均为 `unassigned`/普通 `canceled` 历史,**或存在 `holding`/`assigned`(已派车/待确认)行**——删除前联动取消派车:逐行 `assigned→canceled`(CAS)+ 状态机 + 取消事件(**释放车辆/司机占用、保险退保意图、需求重开**)+ 操作日志;看板逐日派生自然过滤 canceled(日格清理)
- **拒绝(605007)**:槽位存在 `completed` 行(已完成行程保留历史),或**已最终确认方案(dispatchPlanFinalized=1)的取消行**(防 reconcile 复活 + 对账关联)
- **拒绝(605027)**:行程已出发(today > 服务开始日)的已派车槽位,与取消派单口径一致
- **605012**:槽位不存在
**删除动作(事务内)**:
1. (有已派车时)联动取消该槽全部 `holding`/`assigned` 行并释放占用
2. 软删该槽位全部 `unassigned` 每日切片(canceled 历史行保留——对账/保险 REFUND 关联不丢失)
3. `fleet_assignment_slot_removal` 写入删除意图(**条件放宽**:纯已派车槽 removed=0 也写,防重新展开复活)
4. Step2 canonical 快照:`retainedSlotIds` 移除该槽位 + `snapshotVersion` 递增 + `contentDigest` 重算
5. 派单操作日志追加 `slot_removed`(幂等键 `slot-remove:{slotId}`)
**响应 `data`(新增字段)**:
| 字段 | JSON 类型 | 说明 |
|---|---|---|
| `slotId` | string(Long) | 被删除槽位 ID |
| `requirementId` / `orderId` | string(Long) | 归属需求/订单 |
| `removedRowCount` | int | 软删除的未派单切片行数 |
| `cancelledAssignmentCount` | int | **新增**:联动取消的已派车/待确认行数(0=无已派车) |
| `retainedSlotIds` | array(string) | 删除后快照保留槽位集合 |
| `snapshotVersion` | string(Long) | 删除后快照版本(无快照为 null) |
**错误码变更**:**605007** 文案由「槽位已派车或已确认,请先取消派车后再删除」改为「槽位已完成派车或已最终确认,不可删除」;新增 **605027**(行程已出发,不能删除已派车槽位)。
## 2. 订单详情 `GET /admin/fleet/board/orders/{orderId}`(语义变更,字段不变)
`vehicleSlots[].canDelete`:已派车/待确认槽位由 `false` 改为 **`true`**(删除时联动取消释放);仅 `completed`/finalized 取消行或订单只读时仍为 `false`。`deleteBlockReason` 文案同步更新。
## 前端/调用方动作(anchor #5572)
1. **修复删除按钮点击无响应**:`AssignModal.handleDeleteVehicleSlot` 对 `isExistingAssignment`/`!slotDraftMode` 的静默 return 需改为可见反馈;已派车槽位删除应弹二次确认(提示将联动取消派车并释放车辆/司机占用)后调 `DELETE /admin/fleet/assignments/slots/{slotId}`
2. **已派车槽位删除入口**:删除按钮 `v-if="!slot.isExistingAssignment"` 需放开至已派车槽(后端已支持联动释放);或保留按 `canDelete` 控制并展示 605007/605027 错误 toast(**注意前端写死的 605007 文案已过时**,需改为「槽位已完成派车或已最终确认,不可删除」)
3. **#5562 全程槽语义适配**(原 pending):全程行(service_date NULL)的 `isExistingAssignment` 判定、删除后刷新候选(`cancelledAssignmentCount` 可作删除结果提示)
## 验证证据
- 定向测试:AssignmentServiceTest 371/371(+3:已派车槽联动取消删除成功/已出发 605027/completed 605007)、BoardOrderServiceTest 84/84(已派车槽 canDelete=true)、AssignmentControllerTest 41/41;spotless:check 通过
- 网关验证(TEST):已派车槽 DELETE 200 + cancelledAssignmentCount=5(5 条 assigned 行联动取消)+ 行全部 canceled + 占用释放 + slot_removal 持久化;修复前网关实测 500(缺 occupancy context)已由 PR #5579 修复
- 环境说明:fleet verify 3167 用例 Failures=0;MySQL 集成测试 13/13(FleetAssignmentSlotRemovalMysqlTest 3/3 + ReleaseEOccupancyMysql8033RecoveryTest 10/10,3306 竞争窗口补跑)
## 关联/联系人
### 链接
- [后端工单 #5572](https://git.1814.love:8443/wx/HL/issues/5572)
- [后端 PR #5576](https://git.1814.love:8443/wx/HL/pulls/5576) + [#5579](https://git.1814.love:8443/wx/HL/pulls/5579)
- 关联:[#5562 全程槽模型](https://git.1814.love:8443/wx/HL/issues/5562)、[#5550 槽位删除](https://git.1814.love:8443/wx/HL/issues/5550)
### 联系人
- **后端负责人**: @wx
- **前端消费**: 待认领(hl-admin)
@@ -0,0 +1,68 @@
---
schema: "hl-changelog/v2"
ticket: "5573"
title: "派车候选按槽位座位需求校验(SUV槽5座不再误标座位不足)"
consumer: "admin"
author: "wx(GIT)"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "pi-main-session"
frontend_ref: "hl-admin@3e535fe3ad6a406529eb95d7787cefe11b9584cd"
target_release: "v2.1"
verified_at: "2026-08-06"
status_note: "后端完成:PR #5578 已合并 dev-v3 并部署 TEST;网关验证通过(商务槽 7 座/SUV 槽 5 座在整单 10-12 人下不再误标座位不足,车型匹配保留)。候选接口字段无变化,前端零改动;需确认派车弹窗仍传 fleetItemIndex/requiredVehicleType。"
updated_at: "2026-08-06"
base: "dev-v3"
generated: "2026-08-06T01:05:02+08:00"
---
# 派车候选按槽位座位需求校验(SUV槽5座不再误标座位不足)
> 后端完成:PR #5578 已合并 dev-v3 并部署 TEST,网关验证 4/4 通过。
## 关联 / 联系人
### 链接
- **Issue**: [#5573](https://git.1814.love:8443/wx/HL/issues/5573)
- **PR**: [#5578](https://git.1814.love:8443/wx/HL/pulls/5578)
- **Merge commit**: [49e0331fe](https://git.1814.love:8443/wx/HL/commit/49e0331fe)
### 联系人
- **后端负责人**: @wx
## 背景
26-4220(乘客 10 人,SUV 槽 5 座 + 商务槽 7 座)派车:候选面板此前按**整单 headcount**(10 人)校验每辆候选车,SUV 槽所有 SUV(5-7 座)误标"需求不匹配·座位不足"(可选但误导),考斯特 19 座也被标不匹配。
## 口径
槽位级派车按**槽位座位需求**校验:SUV 槽 5 座 → 车辆座位数 ≥ 5 即匹配;乘客分配跨槽(SUV 载 4 + 商务载 6 = 10)。车型匹配保留(SUV 槽优先 SUV,其他车型仍标不匹配原因)。
## 变更接口
| 方法 | 路径 | 来源 |
|---|---|---|
| `POST` | `/admin/fleet/assignments/candidates` | `AssignmentController`(fleet) |
路径前缀 `/admin/fleet/**` 已由网关登录/角色校验收口,无需新增网关规则。**请求/响应字段无变化**:后端从 order-v3 当前需求按 `fleetItemIndex`(count 展开定位)推导槽位要求座位数;推导不到(缺 orderId/fleetItemIndex 或需求不可达)时回退整单 `headcount` 旧行为。
## 行为变化
- `seatsEnough` / `requirementMatched` 的座位维度:有槽位座位需求时按"车辆座位数 ≥ 槽位要求座位数"判定(不再用整单 headcount)
- 车型匹配(`requiredVehicleType` vs 车辆车型 key)逻辑不变
- `headcount` 参数保留(展示/回退用),无字段删除
## 前端/调用方动作
1. 派车弹窗**保持传 `fleetItemIndex`(当前槽位序号)与 `requiredVehicleType`(槽位车型)**——修复依赖这两个参数定位槽位座位需求
2. 展示逻辑不变:`seatsEnough=false` 才标"座位不足",`requirementMatched=false` 才标"需求不匹配"
## 验证证据
- 定向测试:AssignmentCandidateServiceTest 43/43(+2:槽位 5 座配 10-12 人订单不误标 / 无槽位序号回退 headcount);fleet verify 3143 用例全绿
- 网关验证(TEST):商务槽 7 座(headcount=10)7 座车 seatsEnough=true;SUV 槽 5 座(headcount=12)SUV 5-7 座 seatsEnough=true;mpv 车在 suv 槽仍 requirementMatched=false(车型不匹配正确标注)
- 兼容性结论:无契约变化;未传 fleetItemIndex 的旧调用保持原 headcount 校验
@@ -0,0 +1,80 @@
---
schema: "hl-changelog/v2"
ticket: "5574"
title: "派车候选透传常驻司机赛季状态并对拉黑常驻给出明确自动代入原因"
consumer: "admin"
author: "wx(GIT)"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "pi-main-session"
frontend_ref: "hl-admin@d97cc730b019f5947766f3778e2f5b3ca03a5280"
target_release: "v2.1"
verified_at: "2026-08-06"
status_note: "后端完成:PR #5582 已合并 dev-v3 并部署 TEST,网关验证 3/3 通过。候选车辆 VO 新增 primaryDriverSeason 字段(新增字段,兼容);suggestedDriverReason 新增 RESIDENT_BLACKLISTED 值(新增值,兼容)。前端可在车辆候选行标注'常驻司机已拉黑',并在自动代入提示中区分拉黑与档期冲突。"
updated_at: "2026-08-06"
base: "dev-v3"
generated: "2026-08-06T09:40:00+08:00"
---
# 派车候选透传常驻司机赛季状态并对拉黑常驻给出明确自动代入原因
> 后端完成:PR #5582 已合并 dev-v3 并部署 TEST,网关验证 3/3 通过。
## 关联 / 联系人
### 链接
- **Issue**: [#5574](https://git.1814.love:8443/wx/HL/issues/5574)
- **PR**: [#5582](https://git.1814.love:8443/wx/HL/pulls/5582)
- **Merge commit**: [83dd24d1b](https://git.1814.love:8443/wx/HL/commit/83dd24d1b)
### 联系人
- **后端负责人**: @wx
## 背景
工单 #5574 三个现象经 TEST 库实证 + 候选链路代码核对,**均为测试环境数据状态**而非候选过滤 bug:
1. 巴特尔(`2065272153565020161`)`season=blacklist`(06-15 拉黑 reason=4444)——司机候选 SQL 按 `season=ACTIVE` 过滤,黑名单司机不进候选是业务正确语义(#5139 契约:黑名单仍按现有业务守卫阻断);另一同名 active 巴特尔已软删(06-12)
2. 蒙A-G8888 `vehicle_status=busy`(今日起 08-14~26 有 9 条在途 assigned 派单,正确)但候选区间 08-28~31 无冲突显示"所选服务日期内可用"(也正确)——两者口径不同但不矛盾,候选 VO 已透传 `vehicleStatus` 供前端展示
3. 测A88V01 已软删(06-12 创建 20 秒后删除)——车辆候选 @TableLogic 自动过滤软删,正确
## 变更接口
| 方法 | 路径 | 来源 |
|---|---|---|
| `POST` | `/admin/fleet/assignments/candidates` | `AssignmentController`(fleet) |
路径前缀 `/admin/fleet/**` 已由网关登录/角色校验收口,无需新增网关规则。**兼容性**:仅新增字段与新增枚举值,无删除/无类型变化。
## 行为变化
### 车辆候选新增字段
| 字段 | 类型 | 说明 |
|---|---|---|
| `primaryDriverSeason` | String/null | 常驻司机赛季状态(`active`/`pending`/`archived`/`blacklist`);无常驻或常驻已软删为 `null` |
车辆候选此前显示常驻司机姓名(`primaryDriverName`)但司机候选无此人(blacklist 被正确排除)时,前端无法向用户解释"常驻司机去哪了";新增字段后可按 `primaryDriverSeason=blacklist` 标注"常驻司机已拉黑"。
### suggestedDriverReason 新增枚举值
| 值 | 语义 |
|---|---|
| `RESIDENT_BLACKLISTED` | 常驻司机已拉黑(season=blacklist),已回退自动代入空闲司机 |
此前已选车辆常驻司机为 blacklist 时,`getAssignmentCandidate` 返回 null(与档期冲突/休整同落 null),自动代入回退原因误报 `RESIDENT_BUSY_FALLBACK`("常驻司机不空闲");现按 season 区分,返回 `RESIDENT_BLACKLISTED`("常驻司机已拉黑")。既有 `RESIDENT_BUSY_FALLBACK` 语义不变(档期冲突/休整/待激活/停用)。
## 前端/调用方动作
1. 车辆候选行可按 `primaryDriverSeason === "blacklist"` 显示"常驻司机已拉黑"标注(可选优化)
2. 自动代入提示按 `suggestedDriverReason` 展示后端 message(`RESIDENT_BLACKLISTED` 已有明确文案)
3. `vehicleStatus` 已透传(busy=今日起有在途派单),可在候选行展示"当前忙碌/所选区间可用"(可选优化)
## 验证证据
- 定向测试:AssignmentCandidateServiceTest 45/45(+2:blacklist 常驻自动代入 RESIDENT_BLACKLISTED / 车辆候选 primaryDriverSeason 透传);fleet verify 全绿(含 MySQL 集成测试)
- 网关验证(TEST):G8888 车辆候选 `primaryDriverSeason=blacklist` + `vehicleStatus=busy` + `available=true`(区间无冲突);司机候选 22 人含"巴特尔"=0(blacklist 正确排除);selectedVehicle=G8888 → `suggestedDriverReason=RESIDENT_BLACKLISTED` + "常驻司机已拉黑,已回退自动代入空闲司机"
@@ -0,0 +1,64 @@
---
schema: "hl-changelog/v2"
ticket: "5575"
title: "用车需求重复提交幂等(FOR UPDATE锁修复+同内容重放不产生新行)"
consumer: "admin"
author: "wx(GIT)"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "not_required"
frontend_owner: "pi-main-session"
frontend_ref: "N/A:请求字段和成功控制流不变,现有页面不穷举 branchTaken。"
target_release: "v2.1"
verified_at: "2026-08-06"
status_note: "后端完成:PR #5584/#5585 已合并 dev-v3 并部署 TEST;网关验证 3/3(连续同内容重放 2 次均返回 IDEMPOTENT_NOOP 同 requirementId,无新行;内容变化仍走 PENDING_EDIT);存量 v3 双行已按清理 manifest 清理。响应新增 branchTaken=IDEMPOTENT_NOOP 取值(前端可据此提示'内容未变化'),其余契约不变。"
updated_at: "2026-08-06"
base: "dev-v3"
generated: "2026-08-06T11:07:21+08:00"
---
# 用车需求重复提交幂等(FOR UPDATE锁修复+同内容重放不产生新行)
> 后端完成:PR #5584/#5585 已合并 dev-v3 并部署 TEST,网关验证 3/3 通过。
## 关联 / 联系人
### 链接
- **Issue**: [#5575](https://git.1814.love:8443/wx/HL/issues/5575)
- **PR**: [#5584](https://git.1814.love:8443/wx/HL/pulls/5584)、[#5585](https://git.1814.love:8443/wx/HL/pulls/5585)
- **Merge commit**: [1839b2aa4](https://git.1814.love:8443/wx/HL/commit/1839b2aa4)、[dac3e9347](https://git.1814.love:8443/wx/HL/commit/dac3e9347)
### 联系人
- **后端负责人**: @wx
## 背景
订单 2080600006514872322 需求 V3 两条记录(2085009136168177665 PROCESSING + 2085009096510935041 PENDING,同 version=3)——重复提交双写(双击/重试/重放)。
## 修复
1. **并发双写**:`VehicleRequirementMapper.selectLatestByOrderIdForUpdate` 的 `.last("FOR UPDATE").last("LIMIT 1")`——MyBatis-Plus `last()` 覆盖式,LIMIT 1 覆盖掉 FOR UPDATE → 提交事务退化为快照读,并发提交基于同一快照算出同 version 双行。修复为单段 `.last("LIMIT 1 FOR UPDATE")`(MySQL 语法 FOR UPDATE 须在 LIMIT 后)
2. **顺序重复提交**:PENDING/PENDING_REVIEW 分支先做内容语义比较(fleet/行程日期/接送机/特殊标签/备注,JsonNode 解析比较兼容存量空格/字段序差异),完全一致时返回 `IDEMPOTENT_NOOP` 分支的当前版本——不插新行、不失活旧行、不触发 expand/reconcile/outbox
## 变更接口
| 方法 | 路径 | 来源 |
|---|---|---|
| `PUT` | `/v3/admin/order/{id}/vehicle-requirement` | `VehicleRequirementAdminController`(order-v3) |
**请求/响应字段无变化**。响应 `branchTaken` 新增取值 `IDEMPOTENT_NOOP`(重复提交时返回当前 requirementId/version 不变)。
## 前端/调用方动作
1. 提交按钮**可重复点击**:同内容重复提交返回 `branchTaken=IDEMPOTENT_NOOP`,前端可提示"内容未变化"或直接忽略,**无需**做前端防抖(后端已幂等)
2. 内容变化提交仍走 `PENDING_EDIT`/`DONE_ADJUST`,行为不变
## 验证证据
- 定向测试:RequirementServiceTest 198/198(+2:同内容→IDEMPOTENT_NOOP 且 insert/update/expand 未调用;内容变化→PENDING_EDIT);MapperTest 7/7(+2 SQL 形态断言);VehicleRequirementConcurrentVersionMysqlTest 4/4(+1 真实 MySQL LIMIT 1 FOR UPDATE 并发用例)
- 网关验证(TEST):HL20260805165915481 连续同内容重放 2 次均返回 IDEMPOTENT_NOOP 同 requirementId(2085199671193411585)v1,无新行;存量带空格 fleet JSON 语义比较正确
- 数据清理:2080600006514872322 v3 双行按 manifest 清理(删 2085009096510935041,保留 2085009136168177665),v1-v5 各版本唯一
- 兼容性结论:无契约变化;存量数据语义比较兼容;未传字段的旧调用保持原行为
@@ -0,0 +1,391 @@
---
schema: "hl-changelog/v2"
ticket: "5581"
title: "核算餐厅/导游/摄影资源下拉选项接口"
consumer: "admin"
author: "yst"
change_type: "新增接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "mmg"
frontend_ref: "hl-admin@479c44ce399995782504887e0f3aa68274a24e19"
target_release: ""
verified_at: "2026-08-06"
status_note: "hl-resource-service;PR #5583 已合并 dev-v3 并部署测试服,Gateway 实调验证通过(3 接口 + 必填/关键词/鉴权边界全绿);等待管理后台接入。"
updated_at: "2026-08-07"
base: "dev-v3"
---
# 核算餐厅 / 导游 / 摄影资源下拉选项接口(新增 3 个)
- **变更类型**:新增接口
- **端类型**:管理后台
- **日期**:2026-08-06
- **服务**:hl-resource-service(资源服务)
- **关联 Issue**:#5581 新增核算餐厅导游摄影资源下拉接口
---
## 1. 接口背景
管理后台核单(settlement)场景在录入餐厅 / 导游 / 摄影的实际费用时,需要下拉选择对应的资源(餐厅资源、导游人员、摄影人员),并直接看到该资源的默认单价用于预填费用。
本次在资源服务新增 3 个统一前缀的资源下拉选项查询接口,供管理后台核单页消费。接口只返回"识别资源 + 展示名 + 价格"所需的最小字段集合,与订单侧的人员分配(staffAssignment)无任何关联。
---
## 2. 变更清单
| # | 方法 | 路径 | 说明 |
|---|------|------|------|
| 1 | GET | `/admin/resource-options/restaurants` | 分页查询餐厅资源选项 |
| 2 | GET | `/admin/resource-options/guides` | 分页查询导游资源选项(固定 STAFF_TYPE=GUIDE) |
| 3 | GET | `/admin/resource-options/photographers` | 分页查询摄影资源选项(固定 STAFF_TYPE=PHOTOGRAPHER) |
三个接口均为**新增**,无既有接口被修改或删除。
---
## 3. 接口详情
| 项 | 说明 |
|---|------|
| 使用场景 | 管理后台核单录入费用时,下拉选择餐厅 / 导游 / 摄影资源 |
| 认证 | 需要登录态,请求头携带 `Authorization: Bearer <token>`,未携带返回 401 |
| 幂等性 | GET 查询接口,天然幂等,可安全重试 |
| 限流 | 无业务级限流,受网关通用限流约束 |
| 分页 | 三个接口均为分页查询,返回统一分页结构 `PageResult` |
---
## 4. 接口入参
### 4.1 GET /admin/resource-options/restaurants
全部为 Query 参数:
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| pageNo | Integer | 是 | 页码,从 1 开始 |
| pageSize | Integer | 是 | 每页条数 |
| keyword | String | 否 | 餐厅名称关键词,模糊匹配;服务端自动 trim,纯空白等价于不传 |
| city | String | 否 | 城市,精确匹配 |
### 4.2 GET /admin/resource-options/guides
全部为 Query 参数:
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| pageNo | Integer | 是 | 页码,从 1 开始 |
| pageSize | Integer | 是 | 每页条数 |
| serviceDate | LocalDate | **是** | 服务日期,格式 `yyyy-MM-dd`;用于匹配当日人员价格,缺失返回 400 |
| keyword | String | 否 | 人员姓名关键词,模糊匹配;服务端自动 trim,纯空白等价于不传 |
注:服务端固定按 `STAFF_TYPE=GUIDE` 过滤,**不含助理导游**,调用方无需也不支持传 staffType。
### 4.3 GET /admin/resource-options/photographers
入参与 guides 完全一致(serviceDate 必填),服务端固定按 `STAFF_TYPE=PHOTOGRAPHER` 过滤。
---
## 5. 出参字段
统一响应包装:`Result<PageResult<T>>`,`code=200` 表示成功。
实测响应顶层字段:`{ code, message, data, traceId, success }`(注意是 `message` 不是 `msg`);其中分页数据在 `data` 内,字段为 `{ records, total, page, pageSize }`(注意列表字段是 `records` 不是 `list`)。
### 5.1 餐厅资源选项 RestaurantResourceOptionRespVO
| 字段 | 类型 | 说明 |
|------|------|------|
| resourceId | String | 餐厅资源 ID,雪花 ID 序列化为字符串(防 JS 精度丢失)。**仅用于识别资源,不是订单侧人员分配 ID** |
| resourceName | String | 餐厅名称 |
| city | String \| null | 城市。取值规则:cityName 优先、city 回退,两者均空白时为 null |
| settleType | null | 固定 null(餐厅无结算方式概念) |
| settleTypeName | null | 固定 null |
| pricePerPerson | BigDecimal | 餐厅人均价。**餐厅唯一的价格来源**(不是日期价) |
| defaultUnitPrice | BigDecimal \| null | 默认单价,恒等于人均价;未配置人均价时为 null |
| priceConfigured | Boolean | 是否已配置人均价 |
### 5.2 人员资源选项 StaffResourceOptionRespVO(guides / photographers 共用)
| 字段 | 类型 | 说明 |
|------|------|------|
| resourceId | String | staff 表 staff_id,雪花 ID 序列化为字符串(防 JS 精度丢失)。**仅用于识别资源,明确不是 staffAssignmentId** |
| resourceName | String | 人员姓名 |
| staffType | String | 人员类型编码:`GUIDE` / `PHOTOGRAPHER` |
| staffTypeName | String | 人员类型名称:`导游` / `摄影师` |
| settleType | String \| null | 结算方式编码:`cash` / `sign` / `company`;空白时为 null;未知编码原样保留返回 |
| settleTypeName | String \| null | 结算方式名称:`现付` / `签单` / `公司付款`;编码为空或未知时为 null |
| serviceDate | LocalDate | 服务日期,即入参 serviceDate,是共享人员类型价格的匹配日期 |
| protocolPrice | BigDecimal \| null | 当日共享协议价 |
| settlementPrice | BigDecimal \| null | 当日共享结算价 |
| defaultUnitPrice | BigDecimal \| null | 默认单价:结算价优先、协议价回退,两者均空时为 null |
| priceConfigured | Boolean | 是否至少配置了一种当日价格 |
注:响应**不暴露** calendarStatus 字段。
---
## 6. 枚举 / 数据字典
### 6.1 staffType(人员类型,仅本接口出现的两个值)
| 编码 | 名称(staffTypeName) |
|------|----------------------|
| GUIDE | 导游 |
| PHOTOGRAPHER | 摄影师 |
### 6.2 settleType(结算方式)
| 编码 | 名称(settleTypeName) |
|------|----------------------|
| cash | 现付 |
| sign | 签单 |
| company | 公司付款 |
说明:编码为空时 settleType / settleTypeName 均为 null;出现上表之外的未知编码时,settleType 原样返回、settleTypeName 为 null。
---
## 7. 错误码
| HTTP / code | 触发条件 | 返回 message |
|---|---|---|
| 400 | guides / photographers 未传 serviceDate | 服务日期不能为空 |
| 401 | 未携带有效的 Authorization 头(未登录 / token 失效) | 缺少有效的 Authorization 头 |
---
## 8. 示例
### 8.1 典型成功
请求(餐厅):
```
GET /admin/resource-options/restaurants?pageNo=1&pageSize=10&keyword=七间房&city=海拉尔
```
响应(实测):
```json
{
"code": 200,
"message": "成功",
"data": {
"records": [
{
"resourceId": "2023382108491247617",
"resourceName": "七间房全羊馆",
"city": "海拉尔",
"settleType": null,
"settleTypeName": null,
"pricePerPerson": 120.00,
"defaultUnitPrice": 120.00,
"priceConfigured": true
}
],
"total": 1,
"page": 1,
"pageSize": 10
},
"traceId": null,
"success": true
}
```
请求(导游):
```
GET /admin/resource-options/guides?pageNo=1&pageSize=10&serviceDate=2026-08-06&keyword=李雪梅
```
响应(实测):
```json
{
"code": 200,
"message": "成功",
"data": {
"records": [
{
"resourceId": "1002",
"resourceName": "李雪梅",
"staffType": "GUIDE",
"staffTypeName": "导游",
"settleType": "cash",
"settleTypeName": "现付",
"serviceDate": "2026-08-06",
"protocolPrice": 300.00,
"settlementPrice": 299.00,
"defaultUnitPrice": 299.00,
"priceConfigured": true
}
],
"total": 1,
"page": 1,
"pageSize": 10
},
"traceId": null,
"success": true
}
```
请求(摄影):
```
GET /admin/resource-options/photographers?pageNo=1&pageSize=10&serviceDate=2026-08-06
```
响应结构与导游一致,staffType 为 `PHOTOGRAPHER`、staffTypeName 为 `摄影师`。
### 8.2 边界情况
keyword 为纯空白(自动 trim 后等价于不传,按全量分页返回):
```
GET /admin/resource-options/restaurants?pageNo=1&pageSize=10&keyword=%20%20
```
响应:正常 200,keyword 不生效,返回全量分页数据。
无任何匹配结果(空数组,注意 total=0、records 为空数组而非 null):
```json
{
"code": 200,
"message": "成功",
"data": {
"records": [],
"total": 0,
"page": 1,
"pageSize": 10
},
"traceId": null,
"success": true
}
```
人员当日未配置任何价格(defaultUnitPrice 为 null、priceConfigured 为 false):
```json
{
"code": 200,
"message": "成功",
"data": {
"records": [
{
"resourceId": "1003",
"resourceName": "张三",
"staffType": "GUIDE",
"staffTypeName": "导游",
"settleType": null,
"settleTypeName": null,
"serviceDate": "2026-08-06",
"protocolPrice": null,
"settlementPrice": null,
"defaultUnitPrice": null,
"priceConfigured": false
}
],
"total": 1,
"page": 1,
"pageSize": 10
},
"traceId": null,
"success": true
}
```
### 8.3 业务失败
guides / photographers 缺失必填的 serviceDate:
```
GET /admin/resource-options/guides?pageNo=1&pageSize=10
```
响应:
```json
{
"code": 400,
"message": "服务日期不能为空",
"data": null,
"traceId": null,
"success": false
}
```
未登录调用:
```
GET /admin/resource-options/restaurants?pageNo=1&pageSize=10
(不携带 Authorization 头)
```
响应:
```json
{
"code": 401,
"message": "缺少有效的 Authorization 头",
"data": null,
"traceId": "00fef1580108417f",
"success": false
}
```
---
## 9. 业务边界
适用:
- 管理后台核单录入费用时,下拉选择餐厅 / 导游 / 摄影资源。
不适用 / 特殊边界:
- resourceId **仅用于识别资源**:餐厅接口的 resourceId 是餐厅资源 ID;人员接口的 resourceId 是 staff 表 staff_id,**明确不是订单侧的 staffAssignmentId**,不能拿它去调订单人员分配相关接口。
- 餐厅价格只有"人均价"一个来源,不存在按日期变化的价格;defaultUnitPrice 恒等于 pricePerPerson。
- 人员价格是"共享人员类型价格",按 serviceDate 匹配当日协议价 / 结算价;当日两种价格均未配置时 defaultUnitPrice 为 null、priceConfigured 为 false。
- defaultUnitPrice 取值规则固定为"结算价优先、协议价回退",调用方不需要自行二选一。
- guides 接口固定只返回 GUIDE 类型人员,**不含助理导游**;photographers 固定只返回 PHOTOGRAPHER 类型。
- 餐厅的 settleType / settleTypeName 固定为 null,不是数据缺失。
---
## 10. 修改前后对比
新增接口,无修改前后对比。
---
## 11. 影响评估 / 回滚
新增接口,无回滚影响:
- 不破坏任何既有接口与字段,无兼容性问题。
- 不要求前端同步上线;前端未接入时接口存在但不影响任何现有功能。
- 如需回滚,下线 3 个新端点即可,无数据 / 状态残留。
---
## 12. 注意事项
- 三个接口的资源 ID 均为雪花 ID 序列化后的 **String 类型**,前端请勿按 Number 处理,避免精度丢失。
- guides / photographers 的 serviceDate 是**必填**项(格式 `yyyy-MM-dd`),缺失直接 400;restaurants 无此参数。
- keyword 服务端自动 trim,前端无需预处理空白。
- 人员 settleType 可能出现上表之外的未知编码,此时 settleType 原样返回、settleTypeName 为 null,需按未知编码兜底处理。
- 响应不暴露 calendarStatus 字段。
---
## 13. 关联 / 联系人
- Issue:https://git.1814.love:8443/wx/HL/issues/5581
- PR:https://git.1814.love:8443/wx/HL/pulls/5583
- Commit:https://git.1814.love:8443/wx/HL/commit/258a7d9485cd2c0a8cbeca32b3b1e272d44b5376
- 后端负责人:腰苏图
- 接口已在测试服(web.test.1814.love:9443)实调验证通过。
@@ -0,0 +1,70 @@
---
schema: "hl-changelog/v2"
ticket: "5586"
title: "投保成功出单后司机档案保险状态自动同步为有保(INSURED回调兜底重绑)"
consumer: "admin"
change_type: "修改接口"
author: "wx(GIT)"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "not_required"
frontend_owner: ""
frontend_ref: ""
target_release: ""
verified_at: ""
status_note: "后端完成:PR #5587 已合并 dev-v3 并部署 TEST;网关实测 bindAnnual=false 投保(档案 none)→ INSURED 回调 → 档案自动兜底重绑 annual+保单号;退保→解绑→再投保闭环正常。纯后端数据同步修复,无前端契约变更。"
updated_at: "2026-08-06"
base: "dev-v3"
generated: "2026-08-06T11:58:00+08:00"
---
# 投保成功出单后司机档案保险状态自动同步为有保(INSURED回调兜底重绑)
> **服务**: hl-fleet-service
> **PR**: [#5587](https://git.1814.love:8443/wx/HL/pulls/5587)
> **Issue**: [#5586](https://git.1814.love:8443/wx/HL/issues/5586)
> **日期**: 2026-08-06
## 背景
协调台实测(2026-08-06 11:14):司机"菜单师傅"(2073742230014644225)真实保游投保成功出单(insurance_order 2085202532040155138,INSURED,保单号 11209006600507258063,¥3),但 `fleet_driver.insurance_type` 仍 none、policy_no 空——投保成功→司机档案保险状态同步链路未闭合。#5558 已修"投保 bindAnnual 缺省绑定全年保险"(受理即绑),但档案无保(投保受理绑定缺失,或 FAILED/CANCELLED 通知先于 INSURED 乱序到达把绑定解掉后未重绑)时,INSURED 回调仍被"绑定一致性/来源守卫"提前跳过。
## 变更接口
| 方法 | 路径 | 来源 | 变更 |
|---|---|---|---|
| `POST` | `/internal/fleet/drivers/insurance/annual-policy-status` | `InternalDriverInsuranceController`(fleet) | 语义变更:INSURED 通知在 CAS 补填未命中且档案无保(none/空)时**兜底重绑年保**(type=annual+保单号+保费+保障起止+insurance_order_id+source=baoyou) |
字段结构不变,仅通知处理语义调整。**行为矩阵**:
| 档案状态 | INSURED 通知 | FAILED/CANCELLED 通知 |
|---|---|---|
| 绑该单(annual+baoyou+orderId 匹配) | CAS 补填保单号(原行为) | CAS 解绑回 none(原行为) |
| **档案无保(none/空,orderId=null)** | **兜底重绑年保(#5586 新增)** | 解绑 CAS 短路(affectedRows=0,静默) |
| 绑别的单 / perTrip / manual 台账年保 | 跳过(不覆盖换绑与手动语义) | 跳过 |
## 前端/调用方动作
- **无需前端改动**(纯后端数据同步修复,接口字段不变)。
- 司机详情"投保"后刷新即可看到档案有保(保险 Tab 展示源=档案 insurance 字段 + 保单列表)。
## 验证证据
- 定向测试:DriverServiceTest 147/147(+3:档案 none+INSURED→兜底重绑 / perTrip 档案→不动 / 缺保障起止→跳过);既有守卫测试(绑定不一致/source 非 baoyou/FAILED 解绑/INSURED 补填)保持通过;DriverInsuranceServiceTest 25/25、DriverPolicyStatusOutboxEffectServiceTest 2/2。
- fleet 全量 `mvn -pl hl-fleet-service -am verify`:BUILD SUCCESS(3168 tests,0 failures,0 errors,4 skipped,含 spotless)。
- 网关验证(TEST,司机=菜单师傅):① bindAnnual=true 投保→受理即绑 annual→INSURED 回调补填保单号;② 退保→保单 CANCELLED→档案解绑回 none;③ **bindAnnual=false 投保(档案保持 none)→ INSURED 回调→档案自动兜底重绑**(type=annual、policyNo=11209006600507256613、orderId=2085211341932400641、source=baoyou);④ 司机详情"有保"显示与 insurance_order 一致。
- 历史数据批量同步 SOP:internal 端点幂等重放 INSURED 通知(档案 none 自动兜底重绑);本环境 Nacos 断连期间无法经网关直达 internal 端点(403 属正常,Feign LB 直连),重放由 Nacos 可达环境执行。
## 关联/联系人
### 链接
- [后端工单 #5586](https://git.1814.love:8443/wx/HL/issues/5586)
- [后端 PR #5587](https://git.1814.love:8443/wx/HL/pulls/5587)
- Merge commit: [df0c5d2c7](https://git.1814.love:8443/wx/HL/commit/df0c5d2c7029f19eae85c39ad9c04223faeffc5e)
- 关联:[#5558 投保缺省绑定全年保险](https://git.1814.love:8443/wx/HL/issues/5558)、[#3760 保游年险绑定](https://git.1814.love:8443/wx/HL/issues/3760)
### 联系人
- **后端负责人**: @wx
- **前端消费**: 无需改动
@@ -0,0 +1,69 @@
---
schema: "hl-changelog/v2"
ticket: "5588"
title: "司机/车辆占用缓存态对账任务(修正脏busy并释放过期holding占用)"
consumer: "admin"
author: "wx(GIT)"
change_type: "新增接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "not_required"
frontend_owner: ""
frontend_ref: ""
target_release: ""
verified_at: ""
status_note: "后端完成:PR #5591 已合并 dev-v3 并部署 TEST,网关验证 3/3 通过。新增 internal 对账端点(Quartz 触发),无前端 API 变化。"
updated_at: "2026-08-06"
base: "dev-v3"
generated: "2026-08-06T13:10:00+08:00"
---
# 司机/车辆占用缓存态对账任务(修正脏busy并释放过期holding占用)
> 后端完成:PR #5591 已合并 dev-v3 并部署 TEST,网关验证 3/3 通过。
## 关联 / 联系人
### 链接
- **Issue**: [#5588](https://git.1814.love:8443/wx/HL/issues/5588)
- **PR**: [#5591](https://git.1814.love:8443/wx/HL/pulls/5591)
- **Merge commit**: [deecd62b3](https://git.1814.love:8443/wx/HL/commit/deecd62b3)
### 联系人
- **后端负责人**: @wx
## 背景
协调台 E2E 实证:派单发送被"尚未通过候选校验"拦截,根因是 driver_status/vehicle_status 未释放回 idle——**16 个 busy 司机中 6 个无 active 占用(37%),车辆同样**,可派资源被大面积误锁。
代码链路核对结论:取消派单释放占用的既有链路(publishCanceledEvents → OCCUPANCY_RECOMPUTE outbox → hasActiveAssignmentBy* 反算 → applyOccupancy 守卫)已覆盖全部取消入口。TEST 库脏 busy 实际根因:
1. **5 个司机从未有派单却 busy**(外部批量写入缓存列,无事件链路可修复)
2. **holding 单服务日自然过期后无事件触发反算**(如乌力吉/蒙C04E04:08-03~05 holding 单 08-05 结束后占用永久残留)——`AssignmentCompleteJob` 只完结 assigned,不处理过期 holding
## 变更接口
| 方法 | 路径 | 来源 | 说明 |
|---|---|---|---|
| `POST` | `/internal/fleet/jobs/occupancy-reconcile/run` | `FleetJobInternalController`(fleet) | **新增** internal 端点,由 hl-user-service Quartz(sys_job)单点触发;返回本轮写入的 OCCUPANCY_RECOMPUTE 意图数 |
`/internal/*` 经 InternalAuthInterceptor 校验 X-Internal-Token,走内网 Feign LB 直连不经网关(admin token 直 curl 403 属正常)。**无前端 API 变化**。
## 行为变化
新增 `OccupancyReconcileJob`(占用缓存态对账):
- **对账口径**:以 active 派单(holding/assigned 且 end_date >= today)为唯一真相;busy 但无 active 占用的司机/车辆为脏态
- **执行方式**:扫 busy 司机/车辆 + 过期 holding 行资源,逐一写 OCCUPANCY_RECOMPUTE 意图(Outbox),由既有处理器在资源锁内反算并按守卫写回 busy/idle
- **安全性**:不改派单行、不直接改缓存列、不绕过业务守卫(rest/pending/maint 人工态不被覆盖);幂等(无 active 占用才回 idle);单资源失败不反噬整轮
- **附带修复**:过期 holding(服务日已过但从未产生事件)行资源的占用一并释放
## 前端/调用方动作
无。对账由 sys_job 定时触发(建议每日一次),无需前端配合。
## 验证证据
- 定向测试:OccupancyReconcileJobTest 4/4;AssignmentServiceTest 372、AssignmentCandidateServiceTest 45 全过
- fleet verify **3184 项**(含 MySQL 8.0.33 集成)0 失败;spotless 通过
- 网关验证(TEST,12:58):对账前脏 busy 司机=6 车辆=5;触发对账端点(32 条 recompute 意图全 SUCCESS);对账后脏 busy **归零**(原 6 司机 5 车辆全部 idle);候选复验朝鲁门(有 active 占用)仍 busy + available=false(ASSIGNMENT_CONFLICT),**未被误释放**
@@ -0,0 +1,51 @@
---
schema: "hl-changelog/v2"
ticket: "5589"
title: "HOLD 通知派车组不存在 500 修复(全程槽占位消费组 id 回填 + 单行组查询回退)"
consumer: "admin"
change_type: "修改接口"
author: "wx(GIT)"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "not_required"
frontend_owner: ""
frontend_ref: ""
target_release: "v2.1"
verified_at: "2026-08-06"
status_note: "后端完成:PR #5590 已合并 dev-v3 并部署 TEST(13:20 滚动 DONE);网关验证全链路 PASS:batchCreate holdMode=1 200(修复前 500 派车组不存在)、组 id 回填=行 id、通知日志/outbox 正常、司机确认→确认执行 assigned。前端无需配合。"
updated_at: "2026-08-06"
base: "dev-v3"
generated: "2026-08-06T12:50:00+08:00"
---
# HOLD 通知派车组不存在 500 修复
> **服务**: hl-fleet-service
> **PR**: [#5590](https://git.1814.love:8443/wx/HL/pulls/5590)
> **Issue**: [#5589](https://git.1814.love:8443/wx/HL/issues/5589)
> **日期**: 2026-08-06
> **影响**: 🟢 **缺陷修复**,无契约变更。管理后台 HOLD 通知派车(holdMode=1)此前 500「HOLD 通知派车组不存在」,本次修复后全链路可用。前端无需改代码。
## 背景
#5589(P1)协调台实测:`batchCreate` 派单 holdMode=0(直接 assigned)成功,holdMode=1(HOLD 通知)500 `IllegalStateException: HOLD 通知派车组不存在: groupId=…`。
**根因**:#5562 全程槽模型下,全程/单行占位行的 `assignment_group_id` 保持 NULL(有意设计),占位消费升级(`consumePlaceholderToActive`)也未回填。HOLD 通知链路对单行组使用「组 id=行 id」回退语义(`effectiveGroupId`),但组查询(`selectByAssignmentGroupId`)只按 `assignment_group_id` 匹配 → 查空 → 发送结果提交 500。
## 修复内容(内部,无接口/字段变化)
1. **占位消费回填组 id**:`consumePlaceholderToActive` 消费单行占位时 `assignment_group_id=自身行 id`(与历史行迁移回填约定一致,新数据根治);
2. **组查询单行组回退**:`selectByAssignmentGroupId` / `selectByAssignmentGroupIdForUpdate` 按组 id 查空时,回退 `assignment_id=groupId AND assignment_group_id IS NULL`(覆盖存量 NULL 组行,发送授权/结果提交/行程短信统一入口);
3. **CAS 回写回退**:`markHoldNotificationSent` 按组更新 0 行时按行 id 回退更新(单行组 hold_sent_at 回写)。
## 受影响接口(行为修正,无字段增减)
```
POST /admin/fleet/assignments/batch-create (holdMode=1 不再 500)
POST /admin/fleet/assignment-hold-notifications (发送授权/重试对单行组可用)
```
## 验证
- 定向:FleetAssignmentMapperTest 61/61(+4:组 id 回填/双回退)、AssignmentHoldNotificationResultServiceTest 16/16(+1:全程单行组 commitSent)、AssignmentServiceTest 372/372、HOLD 通知域 253/253;fleet 全量 3183 仅 2 个 MySQL 集成 Error 为 3306 端口竞争(其他会话容器),空闲窗口补跑全绿(MutationFence 2/2 + InsuranceCostFence 2/2 + ReleaseE 10/10)
- 网关:TEST 13:20 部署 → batchCreate holdMode=1 **200**(修复前 500)→ 行 holding + 组 id 回填=行 id → HOLD 通知日志/outbox 正常(无行程短链产品降级为站内通知,非异常)→ 司机确认 driver_confirmed → 车务确认执行 **assigned + confirmedAt** → DB 对账全绿
@@ -0,0 +1,79 @@
---
schema: "hl-changelog/v2"
ticket: "5592"
title: "需求变更后一键按新需求重派(删除旧派车后自动推荐车辆+司机)"
consumer: "admin"
author: "wx(GIT)"
change_type: "新增接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "verified"
frontend_owner: "mmg"
frontend_ref: "hl-admin@790e76ab1cadf44d81e610152432fb806144d898"
target_release: ""
verified_at: ""
status_note: "2026-08-07 协调台实测:26-6457 改需求(SUV→商务车)后从 assigned 回「待派车」(旧派单清空待重派),页面含「一键清空」入口,改需求→重派流程通,标 verified。"
updated_at: "2026-08-07"
base: "dev-v3"
generated: "2026-08-06T14:48:09+08:00"
---
# 需求变更后一键按新需求重派(删除旧派车后自动推荐车辆+司机)
> 后端完成:PR #5597 已合并 dev-v3 并部署 TEST,网关验证 3/3 通过。
## ⚠️ 口径最终确认(wx,2026-08-07):要的是【一键清空】
**不是"一键重派",是"一键清空"**——定制师改出发日期/人数/用车需求后,车务点【一键清空】把之前配置完的车辆清空。
**前端实现**:
- 【一键清空】按钮 = 调**既有接口** `DELETE /admin/fleet/assignments/slots/{slotId}`(Body: `{"reason":"需求变更,一键清空"}`),**不需要新接口**
- 删除联动取消已派车、日切片/快照/看板自动一致;返回 removedRowCount/cancelledAssignmentCount/retainedSlotIds
- 清空后:车务按新需求**手动**重新派(`auto-recommend` 仅推荐参考,**不自动配**)
- 错误码:605012 槽位不存在 / 605007 已最终确认不可删 / 605027 已出发不可删
下文的 auto-recommend 仅作推荐数据源(可选),清空动作走 DELETE /slots/{slotId}。
## 关联 / 联系人
### 链接
- **Issue**: [#5592](https://git.1814.love:8443/wx/HL/issues/5592)
- **PR**: [#5597](https://git.1814.love:8443/wx/HL/pulls/5597)
- **Merge commit**: [99baa37a8](https://git.1814.love:8443/wx/HL/commit/99baa37a8)
### 联系人
- **后端负责人**: @wx
## 背景与口径(wx 2026-08-06 工单评论明确)
定制师改需求后车务手动删旧配置太麻烦 → 要"一键按新需求重派"。**关键约束**:系统不得自动取消/改派/重派任何派车——所有写操作必须车务手动点击;系统只做推荐/填充。**不是**自动标记待调整方案。
## 变更接口
| 方法 | 路径 | 来源 |
|---|---|---|
| `POST` | `/admin/fleet/assignments/slots/{slotId}/auto-recommend` | `AssignmentController`(fleet) |
**只读接口,不产生任何写操作**:按槽位车型/座位/日期/人数复用既有候选查询,推荐可用·车型匹配·座位充足的车辆 + 可用司机(常驻匹配优先)。
**请求**:无 Body(仅 PathVar slotId,空缺待派槽位)。
**响应**(`SlotAutoRecommendRespVO`):
- `recommendedVehicle`:推荐车辆(vehicleId/plate/modelName/seats/passengerCapacity/vehicleTypeName/fleetTeamName/residentMatch)
- `recommendedDriver`:推荐司机(driverId/name/maskedPhone/years/rating/driverStatus/residentMatch)
- `vehicleAlternatives` / `driverAlternatives`:备选列表(各前 5)
- `recommendNote`:推荐说明;`noRecommendation`:无可用推荐时 true
- **错误码**:605012 槽位不存在
## 前端/调用方动作
1. 派车页(需求变更后):车务删除旧派车(既有 `DELETE /slots/{slotId}`)后,空缺槽位展示【一键重派】入口
2. 点击调用 `auto-recommend` → 展示推荐车辆+司机与备选(可切换)
3. 车务确认后走**既有派车接口**(candidates + create/assign 流程)提交——**系统绝不自动写**,确认必须车务手动点击
## 验证证据
- 定向测试:AssignmentServiceTest +3(推荐 top 匹配车/司机与备选;无可用候选返回 noRecommendation;槽位不存在 605012;**只读断言**:insert/update 均未调用);回归 421 用例全绿
- 网关验证(TEST):HL20260806115413191(mpv 7 座 6 人,unassigned 槽 343603476254822400)→ 推荐 蒙A-G8888 别克GL8 7 座 + 司机 巴雅尔(8 年)+ 备选 5+5 + note"车型匹配·座位充足·档期可用";**DB 复核槽位仍 unassigned(无写操作)**;不存在槽位 → 605012
- 兼容性结论:新增只读接口,无既有行为变更;verify 3170 用例全绿
@@ -0,0 +1,70 @@
---
schema: "hl-changelog/v2"
ticket: "5593"
title: "取消派单退保幂等:退保检查任务独立类型+重试不调保司+任务锁短重试"
consumer: "admin"
author: "wx"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "mmg"
frontend_ref: "hl-admin@2b2dedfe65aea63746b62de5188f82630461cc80"
target_release: ""
verified_at: "2026-08-06"
status_note: "后端完成:PR #5605 合并 dev-v3(ef5199207)并部署 TEST;网关实测取消派单退保幂等——每保单仅 1 条 REFUND 明细(同保单不重复退保)、REFUND_CHECK 独立类型(退保检查)逐服务日收敛、taskType=REFUND 筛选不再混入检查任务。前端需在任务列表/筛选/详情展示 REFUND_CHECK(退保检查)类型标签。"
updated_at: "2026-08-07"
base: "dev-v3"
generated: "2026-08-06T15:40:15+08:00"
---
# 取消派单退保幂等:退保检查任务独立类型+重试不调保司+任务锁短重试
> 服务端已部署 TEST 并网关验证;前端展示适配项见"前端/调用方动作"。
## 关联 / 联系人
### 链接
- **Issue**: [#5593](https://git.1814.love:8443/wx/HL/issues/5593)
- **PR**: [#5605](https://git.1814.love:8443/wx/HL/pulls/5605)
- **Merge commit**: [ef5199207](https://git.1814.love:8443/wx/HL/commit/ef5199207)
### 联系人
- **后端负责人**: @wx
## 变更接口
| 方法 | 路径 | 来源 | 变更 |
|---|---|---|---|
| `GET` | `/admin/fleet/insurance/tasks` | `FleetInsuranceTaskController`(fleet) | 查询参数 `taskType` 新增取值 `REFUND_CHECK`(退保检查);`taskType=REFUND` 只返回真实调保司退保的明细任务,不再混入 REFUND_CHECK 汇总任务 |
| `POST` | `/admin/fleet/insurance/tasks/<taskId>/retry` | `FleetInsuranceTaskController`(fleet) | 语义变更:`REFUND_CHECK` 类型任务重试只收敛服务日退保检查结论,**绝不调用保司退保**(修复前 REFUND_CHECK 任务复用 REFUND 类型,重试会走退保逻辑) |
## 契约影响文件
- `hl-fleet-service/src/main/java/com/hulalv/fleet/insurance/enums/FleetInsuranceTaskTypeEnum.java`(新增 `REFUND_CHECK("REFUND_CHECK","退保检查")`)
- `hl-fleet-service/src/main/java/com/hulalv/fleet/insurance/vo/FleetInsuranceTaskPageReqVO.java`(taskType 枚举校验 + REFUND_CHECK)
- `hl-fleet-service/src/main/java/com/hulalv/fleet/insurance/FleetInsuranceTaskService.java`(REFUND_CHECK 构造按 bizKey 前缀自动解析类型;retryRefundCheck 不调保司;tryLockTask 瞬时锁竞争短重试 500ms×1)
## 根因与修复说明
- 取消派单同保单出现"2 条 REFUND 都 SUCCESS":其中 1 条是 **REFUND_CHECK 逐服务日退保检查汇总**(纯本地收敛、不调保司),因任务类型枚举只有 PURCHASE/REFUND,检查任务 taskType 复用 REFUND,管理端按 taskType=REFUND 查询同保单出现 2 条 → 重复退保观感;**保游侧实际只退 1 次**(cancel 仅在 REFUND 明细执行)
- 潜在真重复源:REFUND_CHECK 任务被人工重试时旧代码走 `retryRefund` 会调保司退保——已修复(检查任务重试只收敛不调保司)
- 附带:司机险任务锁瞬时竞争导致的"任务锁暂不可用"PENDING 积压——`tryLockTask` 获取失败后短等待 500ms 重试一次
## 前端/调用方动作
1. **任务列表类型展示**:`taskTypeLabel` 新增"退保检查"(REFUND_CHECK),任务列表/详情可区分"退保"(REFUND 明细)与"退保检查"(REFUND_CHECK 汇总),避免同保单重复退保观感
2. **类型筛选**:任务筛选器 taskType 可选值增加 `REFUND_CHECK`;`REFUND` 筛选现在只返回真实退保明细(历史 REFUND_CHECK 任务仍为 REFUND 老值,属存量数据不迁移)
3. **重试按钮**:REFUND_CHECK 任务可重试(只收敛检查结论,不会触发退保);提示文案建议区分"重试退保"与"重试退保检查"
## 验证证据
- 定向测试:FleetInsuranceTaskServiceTest 139/139(+3:REFUND_CHECK 重试收敛不调保司 / 明细缺失保持待处理 / 服务日有效派单拒绝重试)、FleetInsuranceTaskControllerTest 13/13、AssignmentInsuranceOutboxProcessorTest 44/44;fleet 全量 verify BUILD SUCCESS(含 spotless,10:54 min)
- 网关验证(TEST,海日汗 perTrip 2085268464900960257 取消):
- 取消后每保单仅 **1 条 REFUND 明细**(08-20 保单 2085268465328758786、08-23 保单 2085268539798626306 各 1 条,均 SUCCESS 且保单 CANCELLED)——同保单不重复退保
- **REFUND_CHECK(退保检查)独立类型**逐服务日 4 条(08-20~23)全部 SUCCESS(有保单日"全部退保明细已成功"、无保单日"无需退保")
- `taskType=REFUND` 筛选只返回 2 条明细(不再混入检查任务);`taskType=REFUND_CHECK` 筛选返回 4 条检查任务
- 已取消派单重复取消被状态机拒绝(605020)
- 兼容性结论:历史 REFUND_CHECK 任务(taskType 存量 REFUND)不迁移,仅在列表中显示原"退保"标签;新产生任务使用 REFUND_CHECK 类型;接口字段结构不变
@@ -0,0 +1,66 @@
---
schema: "hl-changelog/v2"
ticket: "5594"
title: "退保前校验保单已出单,未出单撤销投保任务而非退保成功"
consumer: "admin"
author: "wx(GIT)"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "not_required"
frontend_owner: ""
frontend_ref: ""
target_release: ""
verified_at: ""
status_note: "后端完成:PR #5606 已合并 dev-v3 并部署 TEST,网关验证通过。退保收敛前校验保单已出单(INSURED),未出单时撤销投保任务并收敛退保为撤销终态,不再产生'未投保却退保成功'假象。"
updated_at: "2026-08-06"
base: "dev-v3"
generated: "2026-08-06T16:10:00+08:00"
---
# 退保前校验保单已出单,未出单撤销投保任务而非退保成功
> 后端完成:PR #5606 已合并 dev-v3 并部署 TEST,网关验证通过。
## 关联 / 联系人
### 链接
- **Issue**: [#5594](https://git.1814.love:8443/wx/HL/issues/5594)
- **PR**: [#5606](https://git.1814.love:8443/wx/HL/pulls/5606)
- **Merge commit**: [a95d949b](https://git.1814.love:8443/wx/HL/commit/a95d949b)
### 联系人
- **后端负责人**: @wx
## 背景
TEST 实证(道尔吉 08-30):派单取消退保时,投保任务(PURCHASE)仍处于 PENDING(错误 100503「司机险任务锁暂不可用」,insurance_order_id 为空),但同日退保检查(REFUND_CHECK)已收敛 SUCCESS——形成「未投保成功却退保成功」假象。
根因:`refundServiceDateIfNoActiveAssignment` 在退保候选保单(INSURED/INSURING)为空时直接收敛 REFUND_CHECK 为 SUCCESS;`retryRefund`/`refundPolicyUnderLifecycleLock` 在无保单或非退保候选时按幂等「退保成功」收敛——未出单投保任务被悬挂、退保却显示成功,投保/退保状态机不一致。
## 变更接口
| 方法 | 路径 | 来源 | 说明 |
|---|---|---|---|
| `GET` | `/fleet/driver-insurance/task/list` | `DriverInsuranceController`(fleet) | 状态枚举新增 `CANCELLED`(已撤销)终态:未出单投保任务撤销后任务列表展示「已撤销」,退保任务同样收敛为「已撤销」而非「成功」 |
无请求/响应字段增减;仅 `FleetInsuranceTaskStatusEnum` 新增 `CANCELLED` 状态值,管理后台任务状态展示与筛选可见新增状态。**无前端 API 变化**。
## 行为变化
- **退保前校验保单已出单**:`refundServiceDateIfNoActiveAssignment` 发现该司机该服务日无已出单保单(INSURED)且存在未出单投保任务(PURCHASE PENDING/PROCESSING 且 insurance_order_id 为空)时,先撤销投保任务为 `CANCELLED`(终态),再收敛退保任务为撤销终态,**不再产生「退保成功」假象**
- **幂等边界**:已有保险订单的投保中任务(如退保后重投)不撤销,避免误伤合法在途投保
- **投保/退保状态机一致性**:PURCHASE 未出单 → CANCELLED(撤销,无保单);REFUND/REFUND_CHECK 在无投保任务时保持既有幂等 SUCCESS(权威保单本就无可退);撤销场景统一收敛 CANCELLED
- **汇总收敛**:`summarizeRefundChecks` 将 CANCELLED 计为撤销收敛,避免误判 RETRYABLE_FAILURE 无限重试
## 前端/调用方动作
无。任务列表状态展示自动透出新枚举值「已撤销」,无需前端配合。
## 验证证据
- 定向测试:FleetInsuranceTaskServiceTest 142/142(含 3 个新增用例:取消退保撤销投保、无任务幂等成功、重试退保撤销);保险域 187 项全过
- fleet verify **3199 项**(含 MySQL 集成)0 失败;spotless 通过
- 网关验证(TEST,16:22 部署后):① 任务列表 200,道尔吉 08-30 存量任务可见(PURCHASE PENDING 未出单 + REFUND SUCCESS 旧假象),部署未破坏存量;② 保单接口实证 08-30 起保保单 0 张("未投保却退保成功"场景实锤);③ 对已 SUCCESS REFUND 任务 retry 幂等安全(返回 SUCCESS、不调保司、不重复退保)
@@ -0,0 +1,48 @@
---
schema: "hl-changelog/v2"
ticket: "5595"
title: "全程行换司机不再被605909误拦(历史跨日派单迁移判定放宽 + 存量迁移工具)"
consumer: "admin"
change_type: "修改接口"
author: "wx(GIT)"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "not_required"
frontend_owner: ""
frontend_ref: ""
target_release: "v2.1"
verified_at: "2026-08-06"
status_note: "后端完成:PR #5602/#5607/#5609 已合并 dev-v3 并部署 TEST(15:52 滚动 DONE);迁移工具已执行(5/5 存量行 group_id 回清);网关验证三轮换司机全 PASS:change 200(修复前 605909)、旧行 canceled、新行 assigned 全程形态、退旧投新占用正确。前端无需配合。"
updated_at: "2026-08-06"
base: "dev-v3"
generated: "2026-08-06T16:10:00+08:00"
---
# 全程行换司机不再被 605909 误拦(历史跨日派单迁移判定放宽 + 存量迁移工具)
> **服务**: hl-fleet-service
> **PR**: [#5602](https://git.1814.love:8443/wx/HL/pulls/5602)、[#5607](https://git.1814.love:8443/wx/HL/pulls/5607)、[#5609](https://git.1814.love:8443/wx/HL/pulls/5609)
> **Issue**: [#5595](https://git.1814.love:8443/wx/HL/issues/5595)
> **日期**: 2026-08-06
> **影响**: 🟢 **缺陷修复**,无契约变更(`POST /admin/fleet/assignments/{assignmentId}/change` 行为修复)。已派/待确认**全程行**(#5562 全程槽模型,`service_date` 为 NULL、`start_date~end_date` 覆盖整个服务期)此前 change 被 605909「发现未完成迁移的历史跨日派单」拦截,本次修复后换车/换司机/退旧投新全链路可用。前端无需改代码。
## 背景
#5595(P1)E2E 实测:档期冲突A 已派全程行(`2085213644705927170`,assigned,8/20~8/23)换司机 → 605909 拦截,换人走不通。
**根因**(两条链叠加):
1. #5589 在 `consumePlaceholderToActive` 把全程行升级回填 `assignment_group_id=自身行 id`,使 #5562 全程槽模型的全程行(`group_id` 应为 NULL)被 `ensureDailySlices`/`normalizeActiveSlotRows` 误判为「历史跨日聚合行」→ change/confirm 触发 605909;
2. 即使迁移清回 `group_id`,change 整槽替换产物(`group_id=新组`、`service_date` NULL)在**再次 change** 时仍因 `isFullTripRow`(要求 `group_id IS NULL`)与 `cancelActiveSlotRange`(全程行分支要求 `group_id IS NULL`)被误判 → 605909/605020。
## 修复内容(内部,无接口/字段变化)
1. **占位消费不再回填组 id**:`consumePlaceholderToActive` 移除 `assignment_group_id=自身行 id` 回填,全程行升级保持 `group_id IS NULL`(#5562 模型一致);HOLD 通知单行组命中由 `selectByAssignmentGroupId`/`ForUpdate`/`markHoldNotificationSent` 的 `assignment_id + group_id IS NULL` 兜底保证(#5589 能力保留);
2. **全程形态行判定放宽**:`isFullTripRow` 从「`group_id IS NULL` 且多日」放宽为「`service_date IS NULL` 且 `start/end` 完整」——change 整槽替换产物(带新组 id)同样按全程行处理;`ensureDailySlices`/`normalizeActiveSlotRows` 对全程形态行豁免拆天,不再触发 605909;
3. **改派保持全程形态**:`buildReplacementSlice` 对全程形态行保持 `service_date` NULL、`start/end` 覆盖整个服务期(修复前被压成 effectiveDate 单日切片,丢服务期剩余日期);change 冲突检查/日志范围覆盖整个服务期;
4. **整槽取消放宽**:`cancelActiveSlotRange` 全程行分支由「`service_date IS NULL AND group_id IS NULL`」放宽为「`service_date IS NULL`」(外层已限定槽位匹配);
5. **存量迁移工具**:`hl-workflow/tools/migrate_5595_fulltrip_single_row_group.py`——把 #5589 回填产生的「单行组全程行」(`group_id=自身`、`service_date` NULL、多日、in-flight)幂等回清 `group_id=NULL`,带 manifest 回滚;TEST 已执行 5/5。
## 接口行为
- `POST /admin/fleet/assignments/{assignmentId}/change`(换车/换司机):全程形态行(assigned/holding)**200**,旧行 canceled、新行 assigned 且保持全程形态(`service_date` NULL、`start/end` 覆盖全程),退旧投新占用正确(旧司机释放、新司机建立)。
- 历史跨日聚合行(`service_date` 非 NULL 的旧版多日行)仍按 605909 保护(#5318 语义保留)。
@@ -0,0 +1,83 @@
---
schema: "hl-changelog/v2"
ticket: "5596"
title: "派单预校验增加驾照/年检/车辆保险到期强提醒(不拦截,车务人工判断)"
consumer: "admin"
author: "wx(GIT)"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "verified"
frontend_owner: "hl-ui"
frontend_ref: "hl-admin@572d25e64b5d5ed2cb325dcbb377978c425d4f1e"
target_release: ""
verified_at: ""
status_note: "2026-08-07 协调台实测:派车选车页对司机显示「无保险」「全年保险不覆盖本行程」「常驻司机已拉黑」等预校验警告(驾照/年检/保险提醒生效),标 verified。"
updated_at: "2026-08-07"
base: "dev-v3"
generated: "2026-08-06T18:30:00+08:00"
---
# 派单预校验增加驾照/年检/车辆保险到期强提醒(不拦截)
> 后端完成:PR #5617 已合并 dev-v3 并部署 TEST,网关验证通过。
## 关联 / 联系人
### 链接
- **Issue**: [#5596](https://git.1814.love:8443/wx/HL/issues/5596)
- **PR**: [#5617](https://git.1814.love:8443/wx/HL/pulls/5617)
- **Merge commit**: [f846361f](https://git.1814.love:8443/wx/HL/commit/f846361f)
### 联系人
- **后端负责人**: @wx
## 背景
协调台实测:司机王信驾照 **2022-02-05 已过期 4 年**,但派单 precheck 无驾照到期校验——仅提示档期冲突/跨常驻,过期司机仍可正常派单(安全合规隐患)。
**口径(wx 定)**:驾照/证件到期**不拦截,强提醒即可**——车务人工判断是否派单。
## 变更接口
### `POST /admin/fleet/assignments/precheck`(修改响应)
`warnings` 数组新增 3 个非阻断强提醒类型(只进 warnings、不影响 `conflict` 阻断判定):
| type | 触发条件 | 文案示例 |
|---|---|---|
| `license_expired` | 司机驾照到期日早于本单服务结束日 | 司机驾照已于 2022-02-05 过期(本单服务期间证件失效),请人工确认是否派单 |
| `veh_inspect_expired` | 车辆年检(行驶证)到期日早于本单服务结束日 | 车辆年检已于 2025-01-01 过期(本单服务期间证件失效),请人工确认是否派单 |
| `veh_insure_expired` | 车辆保险到期日早于本单服务结束日 | 车辆保险已于 2025-06-01 过期(本单服务期间无保险保障),请人工确认是否派单 |
判定基准取**服务结束日**(行程期间任一天证件失效都提醒),无结束日回退开始日;证件到期日为空不提示。
### `POST /admin/fleet/assignments/candidates`(修改响应)
`drivers.records[]`(司机候选)新增字段:
| 字段 | 类型 | 说明 |
|---|---|---|
| `licenseExpire` | string(date) | 驾照到期日;未填为空 |
| `licenseExpired` | boolean | 驾照是否已过期(相对请求服务日期;候选页醒目提示用) |
| `licenseExpiredMessage` | string | 醒目提示文案,如「司机驾照已于 2022-02-05 过期,请人工确认」;未过期为空 |
## 行为变化
- **过期司机派单不再无感放行**:precheck 对驾照/年检/保险过期的车、司机给出强提醒 warning,弹窗醒目展示「驾照已过期」,但**不拦截**——车务人工判断是否派单
- **候选页醒目提示**:司机候选列表直接透出 `licenseExpired` 标记与文案,前端可标红「驾照已过期」
- **不改变既有阻断逻辑**:证件到期不影响 `conflict`/`conflicts`,档期冲突、资源不可用、跨常驻等既有判定不变
- 写接口(create/change)**不新增拦截**,与口径一致(人说的算)
## 前端/调用方动作
- **派单弹窗(precheck)**:warnings 出现 `license_expired` / `veh_inspect_expired` / `veh_insure_expired` 时醒目展示(红色警示样式),确认后仍可正常提交派单
- **候选页**:司机候选 `licenseExpired=true` 时展示「驾照已过期」醒目标签(可用 `licenseExpiredMessage` 直接展示),不限制选择
## 验证证据
- 定向测试 572 项全绿:AssignmentServiceTest 378(新增 2 例:过期证件强提醒不阻断 conflict=false、证件未过期无提示)、AssignmentCandidateServiceTest 47(新增 2 例:候选驾照过期标记与文案、有效驾照不标记)、DriverServiceTest 147
- fleet 全量 verify 3203 项,仅 ReleaseEMixedBinaryHarnessTest 2 个 Windows 进程时序用例 flaky 失败(单独重跑 23/23 全绿、干净基线同样全绿、失败用例每次不同=并行负载竞争,与本次改动无关);MySQL 8.0.33 集成 12/12 单独复跑全绿;spotless 通过
- 网关验证(TEST,18:10 部署后):① precheck 过期司机王信+有效车 → HTTP 200、conflict=false(不阻断)、warnings 含 `license_expired`「司机驾照已于 2022-02-05 过期(本单服务期间证件失效),请人工确认是否派单」;② 对照有效驾照司机 → 无任何证件到期提醒;③ 候选接口王信 `licenseExpired=true`、`licenseExpiredMessage`「司机驾照已于 2022-02-05 过期,请人工确认」;共 10/10 通过
@@ -0,0 +1,312 @@
---
schema: "hl-changelog/v2"
ticket: "5598"
title: "终止行程重复提交改一律 581049:COMPLETED 订单再次提交不再重放首次结果"
consumer: "admin"
change_type: "修改接口"
author: "yst(GIT)"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "hl-ui"
frontend_ref: "hl-admin@f1874ef91e12e49cf9014f4ad17b008fe08996aa"
target_release: ""
verified_at: ""
status_note: "PR #5604 已合并 dev-v3 并部署 TEST,网关实测:COMPLETED 订单再次提交 terminate 一律返回 581049「订单已终止,禁止重复提交」(同正文也不再 200 重放)。前端如依赖 #5460 的同正文重放取回结果逻辑需适配。"
updated_at: "2026-08-07"
base: "dev-v3"
---
# 🔧【修改接口·管理后台】终止行程重复提交改一律 581049 (#5598)
> **PR**:[#5604](https://git.1814.love:8443/wx/HL/pulls/5604) | **服务**:`hl-order-service-v3` | **更新时间**:2026-08-06 | **消费端**:管理后台
## 1. 接口背景
终止行程(出行中提前结束订单)是**有副作用的写操作**:首次提交会把订单从 TRAVELLING 推进到 COMPLETED、生成终止退款单、写核单退款关联。此前(#5460)对"首次成功但响应丢失"的场景提供了幂等重放:同正文重放返回 200 和既有退款结果。实测中发现该重放语义让"重复提交"与"首次提交"边界模糊,且重放判定依赖请求指纹快照,对升级前的历史订单还要做语义等价兜底,复杂度高、收益低。
本次收紧为**状态机幂等**:订单一旦 COMPLETED(已终止/已完成),再次提交终止**一律拒绝**,返回 `581049「订单已终止,禁止重复提交」`,零副作用(不重写退款、不重发事件、不做指纹比对)。
**首次正常终止(TRAVELLING → COMPLETED)行为完全不变**,仍返回 200 和退款结果。
## 变更接口清单
| # | 接口名 | 方法 | 路径 | 变更类型 | 说明 |
|---|---|---|---|---|---|
| 1 | 终止行程(出行中) | `POST` | `/v3/admin/order/:id/terminate` | 修改 | COMPLETED 订单重复提交:同正文重放由 `200` 返回既有结果改为一律 `581049`;581049 文案由「终止行程重试与首次终止边界或请求不一致」改为「订单已终止,禁止重复提交」 |
入参字段结构、出参字段结构**均无变化**。
## 3. 接口详情
### 3.1 终止行程(出行中)
- **接口说明**:出行中因特殊原因提前终止订单,订单进入 COMPLETED 状态,由核单/结算流程继续处理;后端按权威数据重算退款金额。
- **使用场景**:管理后台订单详情页,出行中订单执行"终止行程"操作。
- **认证**:需要管理后台登录态和订单操作权限;房务角色不可操作。
- **幂等性**:**不再提供重放幂等**。首次提交成功即生效;订单 COMPLETED 后任何再次提交(无论正文是否与首次一致)一律返回 `581049`,零副作用。
- **限流**:未声明接口级独立限流规则。
## 4. 接口入参
### 4.1 路径参数 / Query 参数
| 字段 | 位置 | 类型 | 必填 | 说明与校验 |
|---|---|---|---|---|
| `id` | Path | Long | 是 | 订单 ID(路径写作 `:id`) |
无 Query 参数。
### 4.2 请求体字段
请求体类型:`OrderTerminateTripReqVO`(**本次无变化**)。
| 字段 | 类型 | 必填 | 说明与校验 |
|---|---|---|---|
| `cancelReason` | String | 是 | 终止原因 + 调整说明(合并,不单列 adjustReason) |
| `endDayNumber` | Integer | 是 | 停在第几天(截断点,1-based),最小 1 |
| `lineUsages[]` | Array | 否 | 统一资源行已用判定列表;优先级高于旧分组数组,`lineKey` 来自 refund-preview 的 `refundLines[].lineKey` |
| `lineUsages[].lineKey` | String | 是(数组内) | 退款资源行 key,示例 `ITINERARY_NODE:97010:2` |
| `lineUsages[].used` | Boolean | 是(数组内) | 是否已使用 |
| `rooms[]` | Array | 否 | 住宿已用判定列表;兼容旧入参,新逻辑优先使用 `lineUsages` |
| `tickets[]` | Array | 否 | 门票/活动已用判定列表;兼容旧入参,`refId` = 行程节点 nodeId |
| `services[]` | Array | 否 | 服务已用判定列表;兼容旧入参,`refId` = 行程节点 nodeId |
| `supplies[]` | Array | 否 | 备品已用判定列表;兼容旧入参,`refId` 与预览返回一致 |
| `rooms[]/tickets[]/services[]/supplies[]` 元素 | Object | — | 结构为 refId Long 必填 + used Boolean 必填 |
| `vehicles[]` | Array | 否 | 用车每天已用判定列表;仅兼容接收,`used` 不参与计算,后端按车辆 serviceDate 与终止日权威重算 |
| `vehicles[].refId` | Long | 是(数组内) | 配车记录 ID(同段车跨天 refId 相同,靠 dayNumber 区分) |
| `vehicles[].dayNumber` | Integer | 是(数组内) | 第几天(1-based) |
| `vehicles[].used` | Boolean | 是(数组内) | 兼容字段:必填,但车辆退款金额不采用该值 |
| `adjustAmount` | Decimal | 否 | 人工调整额(允许负,默认 0;说明并入 cancelReason) |
## 5. 出参字段
响应类型:`Result<OrderTerminateTripRespVO>`(**本次无变化**)。
### 5.1 统一响应外层
| 字段 | 类型 | 可空 | 说明 |
|---|---|---|---|
| `code` | Integer | 否 | 成功为 `200`;失败见第 7 节 |
| `message` | String | 否 | 结果说明 |
| `data` | Object/null | 失败时为空 | 成功时为终止结果 |
| `traceId` | String | 是 | 链路追踪 ID |
| `success` | Boolean | 否 | `code=200` 时为 `true` |
### 5.2 成功响应 `data`
| 字段 | 类型 | 可空 | 说明 |
|---|---|---|---|
| `terminateRefundId` | String(Long) | 否 | 终止退款主表 ID,按字符串返回 |
| `baselineRefund` | String(Decimal) | 否 | 系统建议基线 = max(0, 已付金额 - 已用金额),按字符串返回 |
| `adjustAmount` | String(Decimal) | 否 | 人工调整额(入参回显,默认 0),按字符串返回 |
| `finalRefund` | String(Decimal) | 否 | 最终返还额 = max(0, baselineRefund + adjustAmount),按字符串返回 |
| `settlementRefundId` | String(Long) | 是 | 关联的核单退款结算 ID(核单模块写入后回填),按字符串返回 |
| `newStatus` | String | 否 | 终止后订单粗状态,固定 `COMPLETED` |
| `newFlowStatus` | String | 否 | 终止后流程细状态,固定 `PENDING_REVIEW` |
## 6. 枚举 / 数据字典
### 6.1 `data.newStatus`(订单粗状态,本接口相关取值)
| 值 | 中文 | 说明 |
|---|---|---|
| `TRAVELLING` | 出行中 | 终止前状态;只有该状态可首次提交终止 |
| `COMPLETED` | 已完成 | 终止后状态;该状态下再次提交一律 581049 |
### 6.2 `data.newFlowStatus`(流程细状态)
| 值 | 中文 | 说明 |
|---|---|---|
| `PENDING_REVIEW` | 待核单 | 终止成功后进入核单流程 |
本次无数值新增/删除/改义。
## 7. 错误码
| code | 含义 | 触发场景 |
|---|---|---|
| `200` | 终止成功 | 订单为 TRAVELLING 且校验通过;订单推进 COMPLETED 并生成终止退款 |
| `400` | 请求参数错误 | 缺 `cancelReason`/`endDayNumber`、数组内必填字段缺失等 |
| `581007` | 订单不存在 | `id` 对应订单不存在 |
| `581018` | 出行中取消仅适用于出行中订单 | 订单非 TRAVELLING 且非 COMPLETED(待出行/已取消等)时提交终止 |
| `581044` | 终止行程:结束日之前的资源必须标记为已使用 | 结束日前资源 used=false |
| `581047` | 终止行程:结束日不在订单行程范围内 | `endDayNumber` 越界 |
| `581048` | 终止行程:本地车辆费用服务日与订单行程不一致 | 车辆费用服务日与订单行程对不上 |
| **`581049`** | **订单已终止,禁止重复提交**(原「终止行程重试与首次终止边界或请求不一致」) | **订单已 COMPLETED 时再次提交终止,无论正文是否与首次一致** |
| `584100` | 车务车辆总车费暂时不可用,请稍后重试 | Fleet 车辆费用事实不可用,fail closed |
## 8. 示例
### 8.1 典型成功:出行中订单首次终止(行为不变)
**请求**:
```http
POST /v3/admin/order/2084280231786430466/terminate
Authorization: Bearer <管理后台访问令牌>
Content-Type: application/json
```
```json
{
"cancelReason": "客户高反送医终止",
"endDayNumber": 2,
"adjustAmount": 0,
"lineUsages": [
{
"lineKey": "HOTEL_ASSIGNMENT:96011:1",
"used": true
},
{
"lineKey": "ITINERARY_NODE:97010:1",
"used": true
}
],
"vehicles": [
{
"refId": 9000004500000001,
"dayNumber": 1,
"used": true
}
]
}
```
**响应**:
```json
{
"code": 200,
"message": "成功",
"data": {
"terminateRefundId": "2084497785524011009",
"baselineRefund": "6500.00",
"adjustAmount": "0.00",
"finalRefund": "6500.00",
"settlementRefundId": "2084497785561759746",
"newStatus": "COMPLETED",
"newFlowStatus": "PENDING_REVIEW"
},
"traceId": null,
"success": true
}
```
### 8.2 边界情况:COMPLETED 订单重复提交(本次变化点)
**场景说明**:首次终止已成功(无论响应是否丢失),对同一订单再次提交终止——与首次正文完全相同或不同,结果一样。改前同正文重放会返回 200 和首次结果;改后一律 581049,零副作用。
**请求**:同 8.1(正文可与首次一致,也可不一致)。
**响应**(TEST 网关实测):
```json
{
"code": 581049,
"message": "订单已终止,禁止重复提交",
"data": null,
"traceId": null,
"success": false
}
```
### 8.3 业务失败:结束日越界
**请求**:
```http
POST /v3/admin/order/2084280231786430466/terminate
Authorization: Bearer <管理后台访问令牌>
Content-Type: application/json
```
```json
{
"cancelReason": "客户临时改行程",
"endDayNumber": 99
}
```
**响应**:
```json
{
"code": 581047,
"message": "终止行程:结束日不在订单行程范围内",
"data": null,
"traceId": null,
"success": false
}
```
## 9. 业务边界
- **适用场景**:订单为 TRAVELLING(出行中)时首次提交终止,走正常终止流程,返回 200 和退款结果。
- **不适用场景**:
- 订单已 COMPLETED(已终止/已完成):任何再次提交一律 `581049`,不产生任何副作用。
- 订单为其他状态(待出行/已取消等):`581018`。
- **特殊边界**:终止是有副作用操作,`581049` 不等于"重试成功";前端拿到 581049 后如需终止结果(terminateRefundId / finalRefund),应改走订单详情 / 退款相关查询接口取数,不要再重放 terminate。
- **金额口径不变**:车辆已用仍以车辆 serviceDate 与终止日权威判定,`vehicles[].used` 仅为兼容字段。
## 10. 修改前后对比
### 10.1 字段级对比
| 项 | 原来 | 现在 |
|---|---|---|
| 入参字段结构 | `OrderTerminateTripReqVO` 全字段 | 不变 |
| 出参字段结构 | `OrderTerminateTripRespVO` 全字段 | 不变 |
| 581049 错误文案 | 终止行程重试与首次终止边界或请求不一致 | **订单已终止,禁止重复提交** |
### 10.2 行为级对比
| 场景 | 原来(#5460) | 现在 |
|---|---|---|
| TRAVELLING 订单首次终止 | `200` 返回退款结果,订单推进 COMPLETED | **不变** |
| COMPLETED 订单**同正文**重放 | `200`,返回既有 terminateRefundId / baselineRefund / adjustAmount / finalRefund / settlementRefundId | **`581049` 订单已终止,禁止重复提交**,零副作用 |
| COMPLETED 订单**不同正文**重试 | `581049`(旧文案) | `581049`(新文案),行为不变 |
| 升级前已终止的历史订单重放 | 按快照语义等价校验,等价返 200 / 不等价 581049 | 一律 `581049` |
## 11. 影响评估 / 回滚
### 11.1 影响评估
- **是否破坏向后兼容**:**是,行为级破坏**。依赖"同正文重放返回 200 取回首次结果"的前端重试/补偿逻辑会失效——现在重放拿到的是 581049。
- **前端是否必须同步上线**:**建议同步**。适配方式:
1. 终止提交后若因超时/网络原因未收到响应,重试时收到 `581049` 应视为"订单已终止"(首次实际已成功),按成功路径收尾(刷新订单详情),不要当普通错误提示"提交失败"。
2. 如需展示首次终止的退款结果,收到 581049 后拉订单详情/退款查询接口取数,不再从重放响应获取。
3. 清理 #5460 时期按"同正文重放取回结果"编写的 workaround。
- 首次终止路径零变化,不重试的正常操作流程无感。
### 11.2 回滚方案
- 后端回滚即恢复 #5460 重放语义(同正文 200 / 不同正文 581049 旧文案)。前端兼容策略"581049 = 已终止,拉详情取数"在回滚后仍然成立(只是同正文重放会重新拿到 200),无需反向适配。
## 12. 注意事项
- `581049` 新文案是"订单已终止,禁止重复提交",**不要再按旧文案"边界或请求不一致"做文案匹配**;按 code 判断。
- 收到 `581049` 时订单已是 COMPLETED,不要引导用户"修改正文后重试"——任何正文都会被拒。
- 终止结果字段(terminateRefundId / finalRefund 等)只有首次终止的 200 响应返回;之后只能从查询类接口获取。
- `581018` 与 `581049` 分工:非 TRAVELLING 且未终止过 → 581018;已 COMPLETED → 581049。
## 验证证据
- `mvn -pl hl-order-service-v3 -am verify` 全绿(含重复终止一律 581049 的回归测试)。
- TEST 网关实测(2026-08-06):COMPLETED 订单再次提交 terminate 返回 `code=581049`、`message=订单已终止,禁止重复提交`、`success=false`,零副作用;TRAVELLING 订单首次终止仍 200 返回退款结果。
- 已部署 TEST(PR #5604 合并 dev-v3 后滚动发布)。
## 13. 关联 / 联系人
### 13.1 链接
- **Issue**:[#5598](https://git.1814.love:8443/wx/HL/issues/5598)
- **PR**:[#5604](https://git.1814.love:8443/wx/HL/pulls/5604)
- **Merge commit**:[047bb72951](https://git.1814.love:8443/wx/HL/commit/047bb72951)
- **被取代的契约**:[04_5460_终止行程幂等重放契约恢复-修改接口-管理后台.md](./04_5460_终止行程幂等重放契约恢复-修改接口-管理后台.md)(同正文重放语义本次起作废)
### 13.2 联系人
- **后端负责人**:@yst / yaosutu(腰苏图)
- **前端消费方**:管理后台订单详情 - 终止行程操作
@@ -0,0 +1,328 @@
---
schema: "hl-changelog/v2"
ticket: "5599"
title: "核单餐食餐厅下拉值独立存储"
consumer: "admin"
author: "yst"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "mmg"
frontend_ref: "hl-admin@01bd3875046cd32e9497e2f00a9eb0f782a197dd"
verified_at: ""
target_release: ""
updated_at: "2026-08-10"
base: "dev-v3"
status_note: "PR #5600 已合并 dev-v3;2026-08-10 复核确认测试服已部署并验证(见文末验证证据章节)。restaurantId 关联资源服务餐厅下拉接口 PR #5583"
---
# 核单餐食餐厅下拉值独立存储(不覆盖餐食名称)
- **变更类型**:修改接口
- **端类型**:管理后台
- **服务**:hl-order-service-v3
- **日期**:2026-08-06
## 1. 接口背景
核单「餐食」Tab 原来只有手动录入的 `mealName`(餐食名称)一个文本字段承载餐食/餐厅信息。业务上需要把「从餐厅资源库选择的餐厅」作为独立结构化数据存下来,便于后续按餐厅维度统计与对账,且**不能覆盖**运营手动填写的餐食名称。
本次变更:餐食费用的「新增 / 修改 / 回显」三个接口同时新增 `restaurantId` + `restaurantName` 两个字段,与 `mealName` 完全独立、互不联动。
## 2. 变更清单
| # | 接口 | 变更 | 说明 |
|---|------|------|------|
| 1 | POST /v3/admin/order/{orderId}/settlement/meals | 入参 +2 字段 | 新增 restaurantId / restaurantName(成对、非必填) |
| 2 | PUT /v3/admin/order/{orderId}/settlement/meals/{settlementId} | 入参 +2 字段 | 新增 restaurantId / restaurantName(成对、非必填) |
| 3 | GET /v3/admin/order/{orderId}/settlement/meals | 出参 +2 字段 | 回显新增 restaurantId / restaurantName |
无删除字段、无改名字段、无枚举值变化。
## 3. 接口详情
### 3.1 新增餐食费用
- 方法/路径:`POST /v3/admin/order/{orderId}/settlement/meals`
- 接口名:新增餐食费用
- 认证:管理后台 JWT(网关统一鉴权)
- 幂等性:非幂等(重复提交会产生多条餐食记录)
- 限流:走网关默认限流,无接口级特殊限流
### 3.2 修改餐食费用
- 方法/路径:`PUT /v3/admin/order/{orderId}/settlement/meals/{settlementId}`
- 接口名:修改餐食费用
- 认证:管理后台 JWT(网关统一鉴权)
- 幂等性:幂等(相同 body 重复 PUT 结果一致)
- 限流:走网关默认限流
### 3.3 查询餐食费用(回显)
- 方法/路径:`GET /v3/admin/order/{orderId}/settlement/meals`
- 接口名:查询餐食费用
- 认证:管理后台 JWT(网关统一鉴权)
- 幂等性:只读接口
- 限流:走网关默认限流
## 4. 接口入参
### 4.1 路径参数
| 参数 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
| orderId | path | Long | 是 | 订单ID(三个接口均有) |
| settlementId | path | Long | 是 | 餐食费用记录ID(仅 PUT 修改接口) |
无 Query 参数。
### 4.2 请求体字段(POST / PUT 共用同一请求结构)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| mealType | String | 是 | 餐型:BREAKFAST / LUNCH / DINNER |
| mealDate | Date(yyyy-MM-dd) | 否 | 发生日期 |
| mealName | String | 是 | 餐食名称,手动录入,最长 200 字符;**不受餐厅选择影响、不被覆盖** |
| quantity | Integer | 是 | 数量,1-10000 |
| unitPrice | Number | 是 | 单价,≥ 0,最多 8 位整数 + 2 位小数;unitPrice × quantity ≤ 99999999.99 |
| paymentMethod | String | 是 | 付款类型:CASH_PAID / COMPANY_PAID / SIGNED |
| sourceType | String | 是 | 来源类型:MEAL_ASSIGNMENT / MANUAL / SYSTEM |
| settlementConfirmStatus | String | 是 | 确认状态:UNCONFIRMED / CONFIRMED |
| voucherUrls | String[] | 否 | 凭证 URL 列表,最多 9 个,仅支持 http/https,单个最长 1024 字符 |
| restaurantId | Long | 否 | **本次新增**。餐厅资源ID,与 restaurantName 成对出现;不选餐厅则两者都不传 |
| restaurantName | String | 否 | **本次新增**。餐厅名称快照,与 restaurantId 成对出现,最长 200 字符 |
| remark | String | 否 | 备注,最长 512 字符 |
**成对校验(关键业务规则)**:`restaurantId` 与 `restaurantName` 必须**同时传或同时不传**(restaurantName 为空白字符串视为未传)。只传其一 → 400,message 为「restaurantId 与 restaurantName 必须成对出现」或「餐食费用字段超出允许范围」(错误码 584094,MEAL_EXPENSE_REQUEST_INVALID)。两字段与手动录入的 `mealName` **完全独立、不联动**——选了餐厅也不会改动/覆盖 mealName。
## 5. 出参字段
- POST / PUT 响应:`Result<SettlementMealRespVO>`(单条记录)
- GET 响应:`Result<List<SettlementMealRespVO>>`(列表,元素结构相同)
SettlementMealRespVO 字段表:
| 字段 | 类型 | 说明 |
|---|---|---|
| id | String | 餐食费用ID,雪花ID序列化为字符串 |
| mealType | String | 餐型 |
| mealDate | Date(yyyy-MM-dd) | 发生日期 |
| mealName | String | 餐食名称 |
| restaurantId | String \| null | **本次新增**。餐厅资源ID,雪花ID序列化为字符串(防 JS 精度丢失);未选餐厅为 null |
| restaurantName | String \| null | **本次新增**。餐厅名称快照(选中时记录,餐厅改名/删除不影响已存核单记录);未选餐厅为 null |
| quantity | Integer | 数量 |
| unitPrice | String | 单价(BigDecimal 序列化为字符串) |
| actualAmount | String | 实际金额 = unitPrice × quantity(BigDecimal 序列化为字符串) |
| paymentMethod | String | 付款类型 |
| sourceType | String | 来源类型 |
| sourceTypeName | String | 来源类型名称 |
| voucherUrls | String[] | 凭证 URL 列表 |
| settlementConfirmStatus | String | 确认状态 |
| settlementConfirmStatusName | String | 确认状态名称 |
| remark | String | 备注 |
外层为统一响应结构:`{ "code": 200, "message": "...", "data": ..., "traceId": ..., "success": ... }`;业务失败时 code 为错误码、data 为 null。
## 6. 枚举 / 数据字典
本次**无新增、无变更**枚举。以下现有枚举取值保持不变:
| 字段 | 取值 | 说明 |
|---|---|---|
| mealType | BREAKFAST / LUNCH / DINNER | 早餐 / 午餐 / 晚餐 |
| paymentMethod | CASH_PAID / COMPANY_PAID / SIGNED | 现金垫付 / 公司支付 / 签单 |
| sourceType | MEAL_ASSIGNMENT / MANUAL / SYSTEM | 餐食安排 / 手动录入 / 系统生成 |
| settlementConfirmStatus | UNCONFIRMED / CONFIRMED | 未确认 / 已确认 |
`restaurantId` 的取值来源:资源服务「餐厅资源下拉选项」接口 `GET /admin/resource-options/restaurants`(PR #5583 已上线)返回的 `resourceId`。餐厅选项是业务数据,不是枚举/字典。
## 7. 错误码
| HTTP | 错误码 | message | 触发条件 |
|---|---|---|---|
| 400 | 584094 | 餐食费用字段超出允许范围 | restaurantId 与 restaurantName 只传其一(不成对),service 层抛 MEAL_EXPENSE_REQUEST_INVALID |
| 400 | (参数校验失败) | restaurantId 与 restaurantName 必须成对出现 | 同上场景,bean validation 层先行拦截时的提示文案 |
| 400 | (参数校验失败) | mealType 必须是 BREAKFAST / LUNCH / DINNER 之一 等 | 既有字段校验失败(本次不变) |
| 401 | - | 未登录 / token 失效 | 未携带或携带无效的管理后台 JWT |
## 8. 示例
### 8.1 典型成功:选择餐厅保存 + 回显
请求:
```http
POST /v3/admin/order/1951234567890123456/settlement/meals
Authorization: Bearer {adminToken}
Content-Type: application/json
```
```json
{
"mealType": "LUNCH",
"mealDate": "2026-08-10",
"mealName": "团队桌餐(10人标)",
"quantity": 10,
"unitPrice": 68.00,
"paymentMethod": "COMPANY_PAID",
"sourceType": "MANUAL",
"settlementConfirmStatus": "UNCONFIRMED",
"voucherUrls": ["https://oss.example.com/voucher/a1.jpg"],
"restaurantId": 1889900112233445566,
"restaurantName": "海拉尔XX手把肉餐厅",
"remark": "导游现场确认"
}
```
响应(200):
```json
{
"code": 200,
"message": "成功",
"data": {
"id": "1952345678901234567",
"mealType": "LUNCH",
"mealDate": "2026-08-10",
"mealName": "团队桌餐(10人标)",
"restaurantId": "1889900112233445566",
"restaurantName": "海拉尔XX手把肉餐厅",
"quantity": 10,
"unitPrice": "68.00",
"actualAmount": "680.00",
"paymentMethod": "COMPANY_PAID",
"sourceType": "MANUAL",
"sourceTypeName": "手动录入",
"voucherUrls": ["https://oss.example.com/voucher/a1.jpg"],
"settlementConfirmStatus": "UNCONFIRMED",
"settlementConfirmStatusName": "未确认",
"remark": "导游现场确认"
}
}
```
回显:`GET /v3/admin/order/1951234567890123456/settlement/meals` 返回 `data` 为列表,元素结构同上(含 restaurantId / restaurantName)。
### 8.2 边界:不选餐厅,纯手动录入(两字段都不传)
请求:
```http
POST /v3/admin/order/1951234567890123456/settlement/meals
Authorization: Bearer {adminToken}
Content-Type: application/json
```
```json
{
"mealType": "BREAKFAST",
"mealDate": "2026-08-11",
"mealName": "酒店自助早餐",
"quantity": 10,
"unitPrice": 0,
"paymentMethod": "SIGNED",
"sourceType": "MANUAL",
"settlementConfirmStatus": "CONFIRMED"
}
```
响应(200):`data` 中 `restaurantId: null`、`restaurantName: null`,其余字段正常填充。存量历史餐食记录回显同样两字段为 null。
### 8.3 业务失败:只传 restaurantId、缺 restaurantName(不成对)
请求:
```json
{
"mealType": "DINNER",
"mealName": "涮羊肉",
"quantity": 10,
"unitPrice": 88.00,
"paymentMethod": "CASH_PAID",
"sourceType": "MANUAL",
"settlementConfirmStatus": "UNCONFIRMED",
"restaurantId": 1889900112233445566
}
```
响应(400):
```json
{
"code": 584094,
"message": "餐食费用字段超出允许范围",
"data": null
}
```
(若 bean validation 层先行拦截,message 为「restaurantId 与 restaurantName 必须成对出现」。反向场景——只传 restaurantName 不传 restaurantId——同样 400。)
## 9. 业务边界
**适用**:
- 核单「餐食」Tab 新增 / 编辑费用时,从餐厅资源下拉中选择餐厅,结构化保存 restaurantId + restaurantName
- 运营纯手动录入餐食(不关联餐厅):两字段都不传即可,行为与本次变更前完全一致
**不适用**:
- restaurantId 只接受「餐厅资源下拉选项」接口返回的 resourceId,不接受其他类型资源ID
- 已提交核单(终态)订单不可再改餐食费用(核单提交守卫为既有逻辑,本次不变)
**特殊边界**:
- **快照语义**:restaurantName 是选中那一刻的名称快照。之后餐厅在资源库改名 / 删除,**不影响**已存核单记录的 restaurantName
- **与 mealName 完全独立**:选了餐厅也不会改动 / 覆盖 mealName;mealName 仍是必填手动录入字段
- 存量数据:历史餐食费用记录两字段均为 null,回显正常、无需迁移
## 10. 修改前后对比
### 字段级对比
| 接口 | 维度 | 修改前 | 修改后 |
|---|---|---|---|
| POST / PUT 保存 | 入参 | 无餐厅字段 | +restaurantId(Long,可选,成对)+restaurantName(String,最长 200,可选,成对) |
| GET 回显 | 出参 | 无餐厅字段 | +restaurantId(String,可 null)+restaurantName(String,可 null) |
| mealName | 语义 | 餐食/餐厅信息只能挤在这一个文本字段里 | 仍为必填手动录入;餐厅信息改由独立字段承载,不再占用 mealName |
### 行为级对比
| 场景 | 修改前 | 修改后 |
|---|---|---|
| 保存餐食费用 | 想记餐厅只能写进 mealName 文本 | 可结构化传 restaurantId + restaurantName,mealName 不被覆盖 |
| 回显 | 无法区分「餐食名称」和「餐厅」 | 两类信息独立字段回显,前端可分开展示 |
| 入参校验 | 无成对概念 | restaurantId / restaurantName 不成对 → 400 |
## 11. 影响评估 / 回滚
- **破坏性兼容**:无。两个字段均为可选新增;存量请求不传两字段时行为完全不变;存量数据两列为 NULL
- **前端同步上线**:不强制同步。前端未接新字段前,保存 / 回显行为与之前一致(回显多两个 null 字段,不读即可);前端接新字段需等后端部署后联调
- **后端部署状态**:PR #5600 已合并 dev-v3,**测试服已部署**(2026-08-10 复核确认,见文末验证证据章节)
- **回滚方案**:后端回滚 = 下线两字段即可。回滚时前端需同步停止传这两字段;存量数据两列本就为 NULL 或历史快照值,无数据迁移、无回滚 SQL
## 12. 注意事项
1. `restaurantId` 出参是 **String**(雪花 ID 序列化),前端不要用 Number 解析,防 JS 精度丢失
2. `unitPrice` / `actualAmount` 出参同样是 String(BigDecimal 序列化),金额展示直接渲染字符串即可
3. 编辑时「清掉已选餐厅」= 两字段都不传(或都传 null),保持成对空态
4. restaurantName 是快照不是实时关联,餐厅后续改名 / 删除不影响历史核单记录显示,属预期
5. 餐厅下拉数据源接口 `GET /admin/resource-options/restaurants` 属资源服务(PR #5583),不在本变更范围内
6. 本变更只涉及接口契约;后端代码已合并 dev-v3,测试服部署时间以后端通知为准
## 13. 关联 / 联系人
- Issue:https://git.1814.love:8443/wx/HL/issues/5599
- PR:https://git.1814.love:8443/wx/HL/pulls/5600
- Commit:https://git.1814.love:8443/wx/HL/commit/9884585a292924c1a0a7a5fec6b7dc8ab87aa59d
- 关联依赖:餐厅资源下拉接口 PR #5583(资源服务,已上线)
- 后端负责人:yst(腰苏图)
## 验证证据(2026-08-10 复核回填,wx)
> 本条 changelog 2026-08-06 推送时后端尚未部署测试服(原 status_note 自述),违反「测试服部署+实测后才通知前端」流程。2026-08-10 复核补齐部署与验证证据如下:
- 测试服 hl-order-service-v3 运行版本为 2026-08-10 15:10 构建(dev-v3),晚于 PR #5600 合并点(2026-08-06 14:56),本变更代码已在运行实例中。
- 测试服 DB `hl_order_service_v3.order_settlement_meal` 已存在 `restaurant_id` / `restaurant_name` 两列(Flyway 已执行)。
- `SettlementMealRespVO` 含 `restaurantId` / `restaurantName` 字段(dev-v3 源码核对)。
- `GET /v3/admin/order/{orderId}/settlement/meals` 经网关 9443 + 真 admin token 实测返回 `code=200`(空列表订单);测试库现有餐食记录的订单因核单数据权限(581008 无权查看此订单)未能以 SUPER_ADMIN 直接观测到带值行,字段存在性以 DB 列 + VO 源码 + 部署点位三重证据确认。
@@ -0,0 +1,79 @@
---
schema: "hl-changelog/v2"
ticket: "5601"
title: "接口参数校验3缺陷:pageNo兼容别名拦截+看板不存在订单报错+保险任务status兼容校验"
consumer: "admin"
author: "wx"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "not_required"
frontend_owner: ""
frontend_ref: ""
target_release: ""
verified_at: ""
status_note: "后端完成:PR #5615 合并 dev-v3(e6ecb3555a2ad1d56a4a6d93aebb90bdcd2ec9c5)并部署 TEST;网关实测 pageNo=0/-1 返 400 页码最小为1、看板不存在订单返 605904 订单不存在、保险任务 status=XXX 返 400 枚举错误。前端契约参数名不变(page/pageSize、taskStatus),pageNo/status 为兼容别名(等价生效并校验)。"
updated_at: "2026-08-07"
base: "dev-v3"
generated: "2026-08-06T17:15:00+08:00"
---
# 接口参数校验3缺陷:pageNo兼容别名拦截+看板不存在订单报错+保险任务status兼容校验
> 服务端已部署 TEST 并网关验证;前端契约参数名不变,无强制改动。
## 关联 / 联系人
### 链接
- **Issue**: [#5601](https://git.1814.love:8443/wx/HL/issues/5601)
- **PR**: [#5615](https://git.1814.love:8443/wx/HL/pulls/5615)
- **Merge commit**: [e6ecb3555](https://git.1814.love:8443/wx/HL/commit/e6ecb3555a2ad1d56a4a6d93aebb90bdcd2ec9c5)
### 联系人
- **后端负责人**: @wx
## 变更接口
| 方法 | 路径 | 来源 | 变更 |
|---|---|---|---|
| `GET` | `/admin/fleet/drivers/page` | `DriverController`(fleet) | 查询参数新增兼容别名 `pageNo`(等价 `page`):`pageNo=0/-1` 返 400「页码最小为1」(修复前被静默忽略返回默认第一页);`driverStatus`/`season`/`insuranceType` 非法枚举值返 400(修复前静默空结果) |
| `GET` | `/admin/fleet/board/orders` | `BoardController`(fleet) | 查询参数新增兼容别名 `pageNo`(等价 `page`):非法页码返 400 |
| `GET` | `/admin/fleet/board/orders/<orderId>` | `BoardController`(fleet) | 语义修复:订单不存在(跨库确认查无)返 **605904 订单不存在**(修复前返回 200 空壳 VO);order-v3 整体不可达时仍降级回显(relatedDetailReady=false) |
| `GET` | `/admin/fleet/insurance/tasks` | `FleetInsuranceTaskController`(fleet) | 查询参数新增兼容别名 `status`(等价 `taskStatus`):`status=非法值` 返 400「任务状态必须是 PENDING/PROCESSING/SUCCESS/RESOLVED/IGNORED 之一」(修复前被静默忽略返回全部任务) |
| `GET` | `/admin/fleet/vehicles/page` | `VehicleController`(fleet) | `ownerType`/`vehicleStatus` 非法枚举值返 400(同类扫) |
| `GET` | `/admin/fleet/reconciliation/pending-compensations` | `ReconController`(fleet) | `status`/`opType` 非法枚举值返 400(同类扫) |
> 注:`pageNo`、`status` 为兼容别名,**契约主参数名不变**(`page`/`pageSize`、`taskStatus`);所有继承 `PageParam` 的分页接口(司机/车辆/车队/车型/保险任务/保单/H5 Token/对账补偿等 10 个)自动获得 `pageNo` 兼容与校验。
## 契约影响文件
- `hl-common/hl-common-core/src/main/java/com/hulalv/common/result/PageParam.java`(新增 `getPageNo/setPageNo` 兼容别名,@Min 校验复用)
- `hl-fleet-service/src/main/java/com/hulalv/fleet/board/vo/BoardOrderPageReqVO.java`(同上;page/pageSize 校验 #5516 已有)
- `hl-fleet-service/src/main/java/com/hulalv/fleet/board/service/BoardOrderService.java`(queryOrderDetail 无本地派单且订单确认不存在 → 605904;不可达不误报;原 605908 孤儿语义保留)
- `hl-fleet-service/src/main/java/com/hulalv/fleet/insurance/vo/FleetInsuranceTaskPageReqVO.java`(新增 `status` 兼容字段 + @Pattern 校验)
- `hl-fleet-service/src/main/java/com/hulalv/fleet/insurance/FleetInsuranceTaskService.java`(pageTasks status→taskStatus 归一合并)
- `hl-fleet-service/src/main/java/com/hulalv/fleet/driver/vo/DriverPageReqVO.java`、`vehicle/vo/VehiclePageReqVO.java`、`reconciliation/vo/ReconPendingCompPageReqVO.java`(枚举 @Pattern 校验)
## 根因与修复说明
- **① pageNo<=0 不拦**:契约参数名是 `page`(`PageParam` 已有 `@Min(1)` 拦截 `page=0`),历史调用方传 `pageNo` 时被 Spring 当作未知参数静默忽略,返回默认第一页且不报错 → 新增 `pageNo` 兼容别名(getter+setter 映射到 `page`),非法值随 `@Min` 统一返 400
- **② 看板不存在订单返回空壳**:`queryOrderDetail` 只在本地有派单快照时校验订单存在(孤儿 605908),无派单且订单不存在时走完组装返回 (id=假id、orderNo=null、...) 空壳 → 无本地派单且跨库确认不存在时直接抛 605904;order-v3 不可达(查询结果未知)仍保留降级回显,不误报
- **③ 保险任务非法 status 返回全部**:契约参数名是 `taskStatus`(#5515 已有 @Pattern 校验),调用方传 `status` 时被忽略返回全部任务 → 新增 `status` 兼容字段(等价 `taskStatus`),非法值 400,合法值等价筛选
- **同类扫**:按 #5515「非法枚举值显式 400 而非静默」口径补齐 drivers/vehicles/recon 枚举字段;board/expiry、matrix、保单 status 等已有校验确认到位
## 前端/调用方动作
1. **无强制改动**:前端契约参数名(`page`/`pageSize`、`taskStatus`)不变,现有调用不受影响
2. **兼容增强**:若历史调用方曾传 `pageNo`/`status`,现在与 `page`/`taskStatus` 等价并校验非法值;同一请求同时传 `page` 与 `pageNo`(或 `taskStatus` 与 `status`)时,后者覆盖前者(Spring 绑定顺序),建议只传契约主参数
3. **看板详情错误处理**:不存在订单现返回 605904「订单不存在」(修复前 200 空壳),前端可据此提示
## 验证证据
- 定向测试 285/285 全绿:BoardOrderServiceTest 87(+2:空壳拦截 605904 / 不可达降级不误报)、BoardControllerTest 11(+3:pageNo 非法 400 / 合法绑定 / 605904 透传)、DriverControllerTest 30(+3:pageNo 非法 400 / 合法绑定 / 枚举 400)、FleetInsuranceTaskControllerTest 15(+2:status 非法 400 / 合法透传)、FleetInsuranceTaskServiceTest 142
- fleet verify:255 个测试类全绿(含 spotless);唯一失败 ReleaseEMixedBinaryHarnessTest 2 项经基线对比(dev-v3 干净 HEAD 同样失败)确认为基线环境 flaky(进程 runner 管道/超时),与本次改动无关
- 网关验证(TEST,经 api.test.1814.love:9443):
- `pageNo=0` / `pageNo=-1` → 400「页码最小为1」(drivers/page 与 board/orders 同口径);`pageNo=2` → 200 正常分页(total=28)
- `/admin/fleet/board/orders/999999999999999999` → **605904 订单不存在** data=null(修复前 200 空壳)
- `status=XXX` → 400 任务状态枚举错误;`status=SUCCESS` → 200 正常筛选(total=49,records[0].taskStatus=SUCCESS)
@@ -0,0 +1,76 @@
---
schema: "hl-changelog/v2"
ticket: "5603"
title: "需求换版/取消后孤儿派单对账清理(assigned孤儿自动取消释放资源)"
consumer: "admin"
author: "wx(GIT)"
change_type: "新增接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "not_required"
frontend_owner: ""
frontend_ref: ""
target_release: ""
verified_at: ""
status_note: "后端完成:PR #5619/#5620 已合并 dev-v3 并部署 TEST(order-v3/fleet/user 三服务),网关验证通过(sys_job trigger code=200,对账 job 取消 115 条孤儿切片,孤儿残留 0)。新增 internal 对账端点 + 批量需求生效校验 Feign 契约,无前端 API 变化。"
updated_at: "2026-08-06"
base: "dev-v3"
generated: "2026-08-06T18:30:00+08:00"
---
# 需求换版/取消后孤儿派单对账清理(assigned孤儿自动取消释放资源)
> 后端完成:PR #5619/#5620 已合并 dev-v3 并部署 TEST,网关验证通过。
## 关联 / 联系人
### 链接
- **Issue**: [#5603](https://git.1814.love:8443/wx/HL/issues/5603)
- **PR**: [#5619](https://git.1814.love:8443/wx/HL/pulls/5619)、[#5620](https://git.1814.love:8443/wx/HL/pulls/5620)
- **Merge commit**: [fd48756f1](https://git.1814.love:8443/wx/HL/commit/fd48756f1)、[c2e5b81e6](https://git.1814.love:8443/wx/HL/commit/c2e5b81e6)
### 联系人
- **后端负责人**: @wx
## 背景
需求换版/订单取消时,正常链路经 order-v3 耐久 Outbox 通知 fleet 取消旧派单;但当需求/订单被外部物理删除、Outbox 重放失败或链路中断时,fleet_assignment 残留挂接在失效需求上的 active 切片(unassigned/holding/assigned),其中 **assigned 孤儿持续占用车辆/司机资源**。TEST 环境实测 107 条孤儿(assigned 11 + holding 6 + unassigned 90),全部对应「需求/订单已物理删除」。
## 方案
以 order-v3 为需求权威新增**需求存在性对账**(调度通路同 #5588:user Quartz sys_job → fleet internal 端点,每小时 30 分执行):
1. **order-v3** 新增 internal 端点 `POST /v3/internal/order/vehicle-requirements/existence-batch`——批量校验需求是否仍生效(仅返回 is_active=1 且未逻辑删除的需求 ID)
2. **fleet** 新增 `RequirementExistenceReconcileJob`——扫描在途派单 distinct requirement_id → 分批 Feign 校验 → 失效需求逐条走 `cancelActiveByRequirement` **正式取消链路**(需求锁 + 槽位/资源锁 + 保险生命周期锁 + 退保意图 + 占用释放事件);Feign 降级 fail-closed 跳过本轮不误伤;全局锁多实例互斥
3. **fleet** 新增端点 `POST /internal/fleet/jobs/requirement-existence-reconcile/run`
4. **user** 新增 `RequirementExistenceReconcileJobBridge`(sys_job invoke_target:`requirementExistenceReconcileJob.execute()`,已入 Quartz 白名单)
换版重绑窗口安全:order-v3 已换版、fleet 未消费 Outbox 时取消旧版行只会让重放退化为「取消+新建」,最终无重复无残留。
## 变更接口
| 方法 | 路径 | 服务 | 说明 |
|---|---|---|---|
| `POST` | `/v3/internal/order/vehicle-requirements/existence-batch` | order-v3 | internal Feign:批量校验需求生效(Req:`RequirementExistenceBatchReqDTO.requirementIds`≤1000;Resp:`activeRequirementIds`) |
| `POST` | `/internal/fleet/jobs/requirement-existence-reconcile/run` | fleet | internal:Quartz 触发需求存在性对账(无参,返取消需求数) |
均为 `/internal/**` 内网 Feign/Quartz 通路(`InternalAuthInterceptor` 校验 X-Internal-Token,网关不暴露),**无前端 API 变化**。shared 新增 DTO:`RequirementExistenceBatchReqDTO/RespDTO`(hl-common-core)。
## 行为变化
- 需求失效/删除后的孤儿派单(unassigned/holding/assigned)由对账 job 自动软取消(canceled + 退保意图 + 占用释放),历史保留不物理删除
- 对账幂等:需求仍生效不动作;已无在途切片计 0;Feign 不可用跳过本轮
- **无自动改派/重派**(#5592 口径延续:系统只取消孤儿,不替车务决策)
## 前端/调用方动作
无(前端零改动)。
## 验证证据
- **测试**:fleet RequirementExistenceReconcileJobTest 7/7、FleetJobInternalControllerTest 7/7、verify 3158 用例 0 失败(排除 ReleaseE 已知环境项);order-v3 InternalRequirementControllerTest 17/17、RequirementServiceTest 198/198;user QuartzJobExecutorTest 13/13、bridge 4/4;spotless:check 通过
- **部署**:hl-order-service-v3 / hl-fleet-service / hl-user-service 双实例 UP(18:00-18:19)
- **网关验证**:sys_job trigger(admin API)code=200;对账 job 执行 `在途需求总数=73 孤儿需求=31 取消切片=115`;DB 断言孤儿残留 0;原 11 条 assigned 孤儿全部 canceled(reason=订单取消或用车需求基线已换版);释放资源回 idle(仍 busy 的资源均有其它在途派单占用,非泄漏)
- **存量清理**:evidence/5603/orphan-cleanup-manifest.json(hl-data-cleanup/v1,115 条软取消)+ orphan-cleanup-backup.json(115 行快照)
@@ -0,0 +1,115 @@
---
schema: "hl-changelog/v2"
ticket: "5610"
title: "核单完毕车辆费用写入fleet对账(实际结算取消手动录入)"
consumer: "admin"
author: "wx"
change_type: "新增接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "mmg"
frontend_ref: "hl-admin@d4ac54f5c0b756fc49ce7efa907d81912a7cfd58"
target_release: ""
verified_at: "2026-08-06"
status_note: ""
updated_at: "2026-08-07"
base: "origin/dev-v3"
generated: "2026-08-06T19:42:24+08:00"
---
# 🚗 核单完毕车辆费用写入 fleet 对账(实际结算取消手动录入)
- **日期**: 2026-08-06
- **服务**: `hl-order-service-v3`(核单)→ `hl-fleet-service`(车队对账)
- **PR**: [#5622](https://git.1814.love:8443/wx/HL/pulls/5622) + 补丁 [#5624](https://git.1814.love:8443/wx/HL/pulls/5624)
- **Issue**: [#5610](https://git.1814.love:8443/wx/HL/issues/5610)
- **Merge commit**: [fd67c16a7](https://git.1814.love:8443/wx/HL/commit/fd67c16a74aedaac9f4869c089a03d30ab3d5466) + [973953481](https://git.1814.love:8443/wx/HL/commit/97395348127b766cfa9957664dff853546a38e28)
- **作者**: wx
- **设计**: hl-backend-changelog [06_5597 写模式数据流设计](./06_5597_hl-order-service-v3_hl-fleet-service_核单完毕车辆费用车队对账数据流设计.md)
- **影响范围**: 车队对账页(admin)「实际结算」列数据供给与录入方式变更;`PUT /admin/fleet/reconciliation/actual` 删除
## 变更接口
| 方法 | 路径 | 来源 |
|---|---|---|
| POST | /internal/fleet/reconciliation/vehicle-fee | 新增(fleet internal,Feign 直连) |
| PUT | /admin/fleet/reconciliation/actual | 删除(实际结算改读核单写入) |
| GET | /admin/fleet/reconciliation/cars | 修改(actualTotal 数据源变更 + 新增退款列) |
### 新增 internal 接口 `POST /internal/fleet/reconciliation/vehicle-fee` 的前置说明
### 1. 变更内容
写模式:核单完毕 → order 调 fleet 写入接口 → fleet 对账本地读。
| 接口 | 位置 | 改前 | 改后 |
|---|---|---|---|
| `POST /internal/fleet/reconciliation/vehicle-fee`(新增) | fleet internal,Feign 直连 | 不存在 | 核单完毕写入该订单车辆实际费用(逐车逐日) |
| `PUT /admin/fleet/reconciliation/actual`(删除) | fleet admin | 车管手工录入实际结算 | **已删除**(404),实际结算改读核单写入数据 |
| `GET /admin/fleet/reconciliation/cars` | fleet admin | `fleets[].actualTotal` = 手工录入值 | `fleets[].actualTotal` = SUM(vehicle_fee.actual_amount),新增 `fleets[].refundTotal`、`vehicles[].actualAmount/refundAmount`、`grandTotal.refundTotal` |
### 新增 internal 接口 `POST /internal/fleet/reconciliation/vehicle-fee`
- 调用方:hl-order-service-v3(核单完毕 finalize 事务内登记 Fleet 命令 Outbox `SETTLEMENT_VEHICLE_FEE_WRITE`,提交后重放调用;不在核单事务内同步 Feign,可重放补偿)。
- 幂等:`orderId + assignmentId + serviceDate` 唯一键,重核覆盖写(金额/退款/核单时间全量覆盖)。
- 服务日所在对账期已关账(period CLOSED)拒绝(605600),与 prep 冻结口径一致;须超管 reopen 后重核。
- `items[]` 为空(无车订单)直接成功不落行。
**请求体 `SettlementVehicleFeeWriteDTO`(Feign 契约,hl-common)**:
| 字段 | 类型 | 说明 |
|---|---|---|
| `orderId` / `orderNo` | Long / String | 订单标识(必填) |
| `settledAt` | LocalDateTime | 核单完成时间(必填) |
| `items[]` | Array | 逐车逐日明细(必填,可空数组) |
item:
| 字段 | 类型 | 说明 |
|---|---|---|
| `assignmentId` | Long | 派单 ID(fleet_assignment.assignment_id,必填;order 侧取核单冻结行 sourceDetailId) |
| `vehicleId` / `vehiclePlate` / `vehicleModelName` / `seats` / `driverName` | — | 车辆/司机展示快照(order 核单冻结快照) |
| `serviceDate` | LocalDate | 服务日期(必填) |
| `actualAmount` | BigDecimal | 核单实际车费(必填,≥0,605611) |
| `refundAmount` / `refundedAt` | BigDecimal / LocalDateTime | 终止退款金额/完成时间(可空;仅订单首行携带防对账重复计数) |
**响应**:`Result<Void>`(200 成功;605600 已关账 / 605610 参数非法 / 605611 金额为负)。
### 删除 `PUT /admin/fleet/reconciliation/actual`
- 车队对账「实际结算」不再手工录入:`fleet_reconciliation_actual` 表停止写入(历史数据保留,遗留待定另行处理)。
- 关账前置 605603「对账期实际金额未录入」改为校验对账车辆费用表该期至少一行。
## 2. Feign 接口变更
| 调用方向 | Controller | 方法与路径 | 请求类型 | 响应类型 | 变更类型 |
|---|---|---|---|---|---|
| order-v3 → fleet | `ReconciliationVehicleFeeInternalController` | `POST /internal/fleet/reconciliation/vehicle-fee` | `SettlementVehicleFeeWriteDTO` | `Result<Void>` | 新增 |
| 前端 → fleet | `ReconciliationController` | `PUT /admin/fleet/reconciliation/actual` | `ReconActualSaveReqVO` | `ReconActualSaveRespVO` | **删除** |
internal 接口为内网 Feign LB 直连,不经 Gateway;调用方由公共 Feign 拦截器注入 `X-Internal-Token`。order-v3 侧 Feign 方法 `FleetAssignmentExpandFeignClient#writeSettlementVehicleFee`(contextId `fleetAssignmentExpand`)。
## 3. 统一响应包络与错误
正常和参数错误响应使用 `Result<T>`(code/message/data/traceId/success)。新增/复用错误码:
| code | 说明 |
|---|---|
| 605600 | 服务日所在对账期已关账,重核须先重开账 |
| 605610 | 核单车辆费用写入参数非法(幂等键缺失) |
| 605611 | 核单实际车费不能为负 |
## 4. 前端/调用方动作(车队对账页)
- ❌ **删除**「实际结算」手动录入入口(PUT /actual 已 404);实际结算列改展示核单写入值(只读)。
- 保留展示:`actualTotal`(车队级)、`diff`(= actualTotal − payableTotal);新增可空展示:`fleets[].refundTotal`、`vehicles[].actualAmount`、`vehicles[].refundAmount`、`grandTotal.refundTotal`。
- 金额为字符串(BigDecimal @JsonSerialize ToStringSerializer),前端按既有金额处理。
## 验证证据
- 定向测试:`ReconciliationVehicleFeeServiceTest` 9 例(幂等/重核覆盖/已关账拒绝/负数/参数非法/teamNo 取车辆车队归属)、`ReconciliationQueryServiceTest` 11 例(actual 读对账车辆费用表)、`ReconciliationPeriodServiceTest` 17 例(close 前置改造)、`SettlementVehicleFeeReconciliationPublisherTest` 4 例、`SettlementFinalizeTxServiceTest` 5 例(核单完毕登记 outbox)、`OrderFleetCommandOutboxProcessorTest` 26 例(SETTLEMENT_VEHICLE_FEE_WRITE 分发)、`MapperBoundaryArchTest` 25 例(settlement 域经 RequirementService 契约)。
- fleet verify:3196 tests 0 失败 + spotless:check 通过(含 Release E 门禁参数)。
- 网关验证(TEST):internal 写入 200 ×3(首写/幂等/重核覆盖),DB 复查 `fleet_reconciliation_vehicle_fee` 3 行金额随覆盖更新;`PUT /actual` 404;对账页 `GET /admin/fleet/reconciliation/cars` 200 显示核单写入实际结算。
- order 全量 verify 失败集合(8F+95E)与干净 dev-v3 基线完全一致(#5599 H2 schema 未同步 / #5603 架构违规 / MySQL 集成环境),非本变更引入。
- 兼容性结论:`fleet_reconciliation_actual` 历史数据保留未迁移(遗留待定);`GET /admin/fleet/reconciliation/cars` 响应新增字段向后兼容;删除 PUT /actual 为破坏性变更,前端须同步移除录入入口。
@@ -0,0 +1,75 @@
---
schema: "hl-changelog/v2"
ticket: "5612"
title: "change 逐日调整只有起始日通过范围校验——中途日期误报605028(全程行服务期内任意日期可改派)"
consumer: "admin"
change_type: "修改接口"
author: "wx"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "not_required"
frontend_owner: ""
frontend_ref: ""
target_release: ""
verified_at: ""
status_note: "后端完成:PR #5616 合并 dev-v3(e26cb0283cdc5773a220f975b440fc0d8cd80164)并部署 TEST(17:24 滚动 DONE);网关实测中途生效日 08-29 change 成功(修复前 605028),原行 canceled、替换行 assigned 全程形态,随后恢复原车成功。前端无需配合。"
updated_at: "2026-08-06"
base: "dev-v3"
generated: "2026-08-06T17:35:00+08:00"
---
# change 逐日调整中途日期误报 605028 修复(全程行服务期内任意日期可改派)
> **服务**: hl-fleet-service
> **PR**: [#5616](https://git.1814.love:8443/wx/HL/pulls/5616)
> **Issue**: [#5612](https://git.1814.love:8443/wx/HL/issues/5612)
> **日期**: 2026-08-06
> **影响**: 🟢 **缺陷修复**,无契约变更(`POST /admin/fleet/assignments/assignmentId/change` 行为修复)。全程行(#5562 全程槽模型,`service_date` 为 NULL、`start_date~end_date` 覆盖整个服务期)此前仅起始日 `effectiveDate` 能通过范围校验,服务期内中途日期(如服务期 08-28~31 的 08-29/30/31)全部误报 **605028「生效日期不在派单服务日期范围内」**,逐日换车/司机走不通;本次修复后 `effectiveDate` 在 `[start_date, end_date]` 内都算在范围内。前端无需改代码。
## 背景
#5612(P1)协调台 E2E 实测:assignment `2085033560443408385`(服务期 2026-08-28~08-31,全程行):
| effectiveDate | 结果(修复前) | 结果(修复后) |
|---|---|---|
| 2026-08-28(起始日) | ✅ 通过范围校验(走到冲突校验) | ✅ 不变 |
| 2026-08-29 | ❌ 605028 | ✅ 成功 |
| 2026-08-30 | ❌ 605028 | ✅ 成功(同逻辑) |
| 2026-08-31 | ❌ 605028 | ✅ 成功(同逻辑) |
**根因**:`AssignmentService#changeTargetRows` 用 `serviceDateOf(row)`(全程行回退 `startDate`)做 `>= effectiveDate` 过滤——中途日期大于 `startDate` 时全程行被过滤掉,目标行集合为空 → 抛 605028。逐日切片行(`service_date = start_date = end_date`)不受影响。
## 变更说明
`hl-fleet-service` 的 `AssignmentService`(3 处,无 API/DTO/枚举/错误码变化):
1. **`changeTargetRows`**:全程行改用 `coversServiceDate(row, effectiveDate)` 过滤——`effectiveDate` 在 `[start_date, end_date]` 内都算在范围内;逐日切片行保持原「生效日及之后」过滤
2. **`assertContinuousChangeRange`**:单全程行豁免「生效日必须等于目标首行日期」校验(`serviceDateOf` 回退 `startDate` 无法表达中途生效日),仍按 #5595 整槽替换语义保持全程形态
3. **`retainedRows`**:排除全程行——中途生效日时前缀日仍属于被整槽取消替换的同一行,不得再作为保留行参与车辆费用快照与占用刷新
## 变更接口
| 方法 | 路径 | 来源 | 变更 |
|---|---|---|---|
| `POST` | `/admin/fleet/assignments/<assignmentId>/change` | `AssignmentController`(fleet) | 行为修复:全程行(service_date NULL、start/end 覆盖整个服务期)的 `effectiveDate` 范围校验从「仅起始日」放宽为「服务期内任意日期”——中途日期不再误报 605028,逐日换车/司机可用;参数、返回结构、错误码均不变 |
> 注:逐日切片行行为不变(生效日及之后切片替换、日期连续性校验)。全程行仍按 #5595 整槽替换语义(旧行取消保留历史、替换行保持全程形态)。
`POST /admin/fleet/assignments/assignmentId/change`(参数不变):
- `effectiveDate` 合法范围:全程行 `[start_date, end_date]` 内任意日期;逐日切片行仍为「生效日 ≤ 末切片日」且目标日期连续
- 全程行 change 仍按 #5595「整槽替换」语义:旧行取消保留历史、替换行保持全程形态(`service_date` NULL、`start/end` 覆盖整个服务期)、冲突检查/日志范围覆盖整个服务期
- 错误码不变:服务期外日期仍 605028;车辆/司机档期冲突仍 605001
## 验证证据
- 定向测试 6/6(新增 2):`change_fullTripRow_midwayEffectiveDate_succeeds`(中途生效日整槽替换成功)、`change_fullTripRow_midwayEffectiveDate_reachesConflictCheck`(中途日期走到 605001 冲突校验而非 605028);`AssignmentServiceTest` 全量 378/378 通过;`spotless:check` 通过
- fleet `-pl hl-fleet-service -am verify`:除 3 个 MySQL Testcontainers 集成测试因 3306 端口被并行会话占用失败(环境并发,错峰后重跑通过)外全绿
- 网关验证(TEST,经 api.test.1814.love:9443,VEHICLE_MANAGER):
- `change`(effectiveDate=2026-08-29,换车 蒙A-E2E01 + 司机 斯琴)→ **200 成功**(修复前 605028),affectedDays=1、status=assigned
- DB 对账:原行 2085033560443408385 → canceled(保留历史);替换行 assigned、`service_date` NULL、start=08-28、end=08-31 全程形态、新车辆/司机
- 验证后 change 恢复原车成功,测试数据复原
## 前端/调用方动作
**无**。契约参数、错误码不变,仅中途日期从误报 605028 变为正常可用。
@@ -0,0 +1,66 @@
---
schema: "hl-changelog/v2"
ticket: "5613"
title: "派单恢复取消500修复:DAILY_V3快照拓扑按最终方案实际覆盖槽位"
consumer: "admin"
author: "wx"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "not_required"
frontend_owner: ""
frontend_ref: ""
target_release: ""
verified_at: ""
status_note: "后端完成:PR #5623 合并 dev-v3(c10aea0f0)并部署 TEST(hl-fleet-service + hl-order-service-v3);网关实测派单 2085286010924527618 取消后 restore-cancel 返回 200 assignmentStatus=assigned,DAILY_V3 快照 revision 1 同步成功,order 侧 requirement DONE、planFleetItemIndexes=[1]、planTopologySize=4。"
updated_at: "2026-08-07"
base: "dev-v3"
generated: "2026-08-06T19:45:00+08:00"
---
# 派单恢复取消500修复:DAILY_V3快照拓扑按最终方案实际覆盖槽位
> 服务端已部署 TEST 并网关验证;管理后台契约不变,无强制前端改动。
## 关联 / 联系人
### 链接
- **Issue**: [#5613](https://git.1814.love:8443/wx/HL/issues/5613)
- **PR**: [#5623](https://git.1814.love:8443/wx/HL/pulls/5623)
- **Merge commit**: [c10aea0f0](https://git.1814.love:8443/wx/HL/commit/c10aea0f0)
### 联系人
- **后端负责人**: @wx
## 变更接口
| 方法 | 路径 | 来源 | 变更 |
|---|---|---|---|
| `POST` | `/admin/fleet/assignments/<assignmentId>/restore-cancel` | `AssignmentController`(fleet) | **语义修复**:多槽需求只保留部分槽位时恢复取消不再 500(修复前 `IllegalStateException: DAILY_V3 snapshot invalid: daily rows do not cover declared topology`,事务回滚、状态保持 canceled);恢复成功返回 `assignmentStatus=assigned`、车辆/司机占用回 busy。接口出入参不变 |
> 内部契约(同步放宽,随本单一起部署):`POST /v3/internal/order/vehicle-assignment/callback`(DAILY_V3 配车快照回写)的 `planFleetItemIndexes` 校验由「必须等于需求声明全槽」放宽为「需求全槽的非空子集」。即车务最终方案只保留部分槽位(未保留槽位按「车务最终实派方案未保留该车辆槽位」取消)时,快照拓扑只含实际保留槽位,订单侧正常接受并回写 requirement 快照摘要。
## 契约影响文件
- `hl-fleet-service/src/main/java/com/hulalv/fleet/assignment/snapshot/service/DailyVehicleAssignmentSnapshotFactory.java`(快照拓扑按最终方案实际覆盖槽位收窄;每保留槽×每服务日一行、至少一个用车 cell 等 fail-closed 校验不变)
- `hl-order-service-v3/src/main/java/com/hulalv/order/requirement/service/DailyVehicleAssignmentSnapshotService.java`(`validateAgainstRequirement`:ASSIGNED 快照 `planFleetItemIndexes` 允许为需求全槽的非空子集;拓扑完整性仍由 `isDailySnapshotValid` 强制)
## 根因与修复说明
- **根因**:需求声明多槽(如 suv+mpv × 4 天 = 拓扑 8),但车务最终方案允许只保留部分槽位——未保留槽位的 unassigned 占位按「车务最终实派方案未保留该车辆槽位」取消且 `dispatch_plan_finalized=0`,不参与当前最终代。恢复取消(restore-cancel)在事务 `BEFORE_COMMIT` 触发 DAILY_V3 快照生成时,快照工厂仍按 `requirement.fleet` 全槽拓扑校验当前 final 行(4 行 ≠ 8)→ `IllegalStateException` → 500,恢复事务回滚,取消后无法恢复。
- **修复**:① fleet 快照工厂的拓扑以当前最终方案**实际覆盖的槽位**为准(`planFleetItemIndexes`/`planTopologySize`/`dailyAssignments` 一致),未保留槽位不再要求行覆盖;② order 侧回调校验同步接受需求全槽的非空子集。
- **影响范围**:仅影响「多槽需求 + 部分槽位最终方案」场景(修复前该场景任何快照生成都会失败,不止恢复取消);全槽最终方案与 NO_VEHICLE_REQUIRED 行为不变。
## 前端/调用方动作
1. **无强制改动**:restore-cancel 接口与出入参不变;修复前该场景直接 500,现在正常返回。
2. **展示留意**:多槽需求只派部分槽位时,订单侧快照摘要 `assignmentPlanFleetItemIndexes` 现在会正常回写为保留槽子集(修复前该场景快照从不成功、需求卡 PROCESSING)。若管理后台/订单详情按需求全槽渲染车辆槽位,可结合快照拓扑判断哪些槽位实际派车、哪些未保留。
## 验证证据
- 定向测试:fleet `DailyVehicleAssignmentSnapshotFactoryTest` 11/11(+2:部分槽位快照成功 / 保留槽缺日仍 fail-closed);order `DailyVehicleAssignmentSnapshotServiceTest` 14/14(+2:子集 APPLIED / 超集拒绝)
- 回归:`AssignmentServiceTest` 376、`DailyVehicleSnapshotGenerationServiceTest` 15、`RequirementServiceTest` 198、`InternalRequirementControllerTest` 14、`VehicleAssignmentSnapshotContractRedTest` 7、`E2eVehicleAssignmentFinalizeServiceTest` 46 全绿
- fleet 全量 `mvn -pl hl-fleet-service -am verify`(含 spotless)BUILD SUCCESS;order-v3 verify 的 11 个失败类经与 #5610 worktree 基线报告逐类对比完全一致(Testcontainers/MyBatis 环境问题),非本单引入
- 网关验证(TEST,经 api.test.1814.love:9443):派单 2085286010924527618(需求 2 槽 × 08-20~23、最终方案只保留 mpv 槽)取消后 `POST /admin/fleet/assignments/2085286010924527618/restore-cancel` → **200** `assignmentStatus=assigned`,4 行恢复 assigned 且 `canceled_at` 清空;DAILY_V3 快照 outbox revision 1 投递 SUCCESS;order 侧 requirement 回 DONE、`planFleetItemIndexes=[1]`、`planTopologySize=4`、`usedVehicleDayCount=4`,`order_vehicle_assignment` 4 行(mpv 槽 08-20~23,车辆/司机/费用齐全)
@@ -0,0 +1,63 @@
---
schema: "hl-changelog/v2"
ticket: "5618"
title: "precheck 补黑名单司机校验,与 batchCreate 校验项对齐"
consumer: "admin"
author: "wx"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "not_required"
frontend_owner: ""
frontend_ref: ""
target_release: ""
verified_at: ""
status_note: "后端完成:PR #5625 合并 dev-v3(a1f64877ebcc38869a9cbe18d454aa84dc008f25)并部署 TEST;网关实测黑名单司机 precheck conflict=true + driver_blacklisted(605006) 提前提示,有效司机对照无黑名单提示。"
updated_at: "2026-08-07"
base: "dev-v3"
generated: "2026-08-06T22:45:00+08:00"
---
# precheck 补黑名单司机校验(#5618)
## 背景
E2E 实测:黑名单司机(`blacklisted_at` 已写)`POST /admin/fleet/assignments/precheck` 返回 `conflict=false` 不拦;`POST /admin/fleet/assignments/batch` 抛 605006 拦截。precheck 缺司机赛季校验,车务在候选/预览阶段看不到黑名单拦截提示,提交时才被拦,前后体验不一致。
## 变更内容
`POST /admin/fleet/assignments/precheck` 响应 `warnings` 新增两种类型(均置 `conflict=true` 阻断,与 batchCreate 锁内 `assertDriverSeasonAssignable` 对齐):
| warning.type | 触发条件 | 文案 | 对齐错误码 |
|---|---|---|---|
| `driver_blacklisted` | 司机 `season=blacklist` | 司机已黑名单(605006),提交派单将被拦截 | 605006 |
| `driver_season_not_registered` | 司机 `season=archived/pending` 等非 active | 司机非在册赛季(605013),提交派单将被拦截 | 605013 |
补充说明:
- precheck 仍为只读接口,不抛异常、不写库、不取锁;黑名单以 warning + `conflict=true` 形式提前阻断提示。
- 非黑名单正常路径行为不变(证件到期等仍为不阻断强提醒)。
## 关联 / 联系人
- 工单:https://git.1814.love:8443/wx/HL/issues/5618
- PR:https://git.1814.love:8443/wx/HL/pulls/5625
- 后端:wx
## 变更接口或验证证据
### 接口契约
- 接口路径/方法/请求体:不变。
- 响应 `data.warnings[].type` 新增枚举值:`driver_blacklisted`、`driver_season_not_registered`(前端提示文案随 msg 透传)。
### 验证证据
- 定向测试:`AssignmentServiceTest` 382/382(新增 2 例:黑名单阻断提示 605006、非在册阻断提示 605013)。
- 全量 `mvn -pl hl-fleet-service -am verify`:3231 项 0 失败 4 skipped(含 MySQL 集成);spotless 通过。
- 部署 TEST 成功(hl-fleet-service, dev-v3, a1f64877)。
- 网关验证 7/7 PASS:巴特尔(season=blacklist)+ 蒙A-E2E01 → `conflict=true` + `driver_blacklisted`(605006 文案);有效司机对照 → 无黑名单/非在册提示、`conflict=false`。
## 前端/调用方动作
- 管理后台派单预览页可展示 `driver_blacklisted` / `driver_season_not_registered` warning 文案(提前告知车务黑名单拦截原因);不处理也不影响既有逻辑(提交时 batchCreate 仍按 605006/605013 拦截兜底)。
@@ -0,0 +1,73 @@
---
schema: "hl-changelog/v2"
ticket: "5626"
title: "fleet管理端接口角色权限收紧(非车务角色403拦截)"
consumer: "admin"
author: "wx(GIT)"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "not_required"
frontend_owner: ""
frontend_ref: ""
target_release: ""
verified_at: ""
status_note: "后端完成:PR #5628 已合并 dev-v3 并部署 TEST(hl-gateway 双实例),网关验证通过(CUSTOMIZER/ROOM_MANAGER 调 fleet 写接口 code=403,VEHICLE_MANAGER 正常放行,只读车型列表排除路径不受影响)。无请求/响应契约变化,仅权限行为收紧。"
updated_at: "2026-08-06"
base: "dev-v3"
generated: "2026-08-06T23:30:00+08:00"
---
# fleet 管理端接口角色权限收紧(非车务角色 403 拦截)
> 后端完成:PR #5628 已合并 dev-v3 并部署 TEST,网关验证通过。
## 关联 / 联系人
### 链接
- **Issue**: [#5626](https://git.1814.love:8443/wx/HL/issues/5626)
- **PR**: [#5628](https://git.1814.love:8443/wx/HL/pulls/5628)
- **Merge commit**: [b08f1b953](https://git.1814.love:8443/wx/HL/commit/b08f1b953)
### 联系人
- **后端负责人**: @wx
## 背景
P0 安全缺陷:定制师(CUSTOMIZER)等非车务角色可调用车务管理员写接口(实测成功删除司机、调用派单接口透到业务校验)。服务层已有 `FleetAdminRoleGuardInterceptor`(/admin/fleet/** 仅 VEHICLE_MANAGER/SUPER_ADMIN),但网关层缺少角色路由校验,两层防线缺一层。
## 方案
**网关层补角色门禁,与服务层同口径双保险**:
1. `JwtAuthFilter` ADMIN 分支对 `/admin/fleet/**` 做角色门禁——仅 **VEHICLE_MANAGER / SUPER_ADMIN** 放行,其余角色(CUSTOMIZER/ROOM_MANAGER/OPERATOR/MATERIAL_ADMIN/CUSTOMER_SERVICE/ADMIN 等)一律返回 `code=403 无权限访问车务管理,请切换到车务角色`,不透到业务校验
2. 排除路径与服务层拦截器对齐:`GET /admin/fleet/vehicle-types/list`(订单域只读车型大类列表)任意 admin 角色可读,避免误伤订单用车需求消费
3. 防绕过:服务发现前缀(`/hl-fleet-service/...`)与 matrix 参数路径均不能绕过门禁
4. 多角色账号必须先切换到车务角色(`/admin/auth/switch-role`)才能调用车务接口
## 变更接口
| 方法 | 路径 | 服务 | 说明 |
|---|---|---|---|
| 全部 | `/admin/fleet/**`(排除 `GET /admin/fleet/vehicle-types/list`) | hl-gateway + hl-fleet-service | 角色门禁:仅 VEHICLE_MANAGER/SUPER_ADMIN 可访问,非车务角色 `code=403` |
**无请求/响应契约变化**——仅权限行为收紧:非车务角色从「可调用并执行」变为「403 无权限」,车务角色行为不变。涉及写接口示例:`DELETE /admin/fleet/drivers/{driverId}`、`POST /admin/fleet/assignments/batch`、`POST /admin/fleet/vehicles`、`POST /admin/fleet/vehicles/{id}` 等全部 `/admin/fleet/**` 管理接口。
## 行为变化
- 前端管理后台中,**CUSTOMIZER 等非车务角色**访问 fleet 管理功能将收到 `code=403`「无权限访问车务管理,请切换到车务角色」(Result 协议统一错误体,HTTP 200 + code=403)
- **VEHICLE_MANAGER / SUPER_ADMIN** 行为完全不变
- 多角色账号(如 wx 同时持有 CUSTOMIZER+VEHICLE_MANAGER)需先切换角色为车务管理员再操作车务功能
- 服务层 `FleetAdminRoleGuardInterceptor` 维持既有拦截(网关拦截后请求通常到不了服务层,两层均返回同一 403 语义)
## 前端/调用方动作
无需改动(Result 协议统一处理 403;车务功能仅车务角色可见)。若前端存在「定制师视角展示车务入口」的情况,建议按 403 隐藏/禁用入口(可选优化,不阻塞后端验收)。
## 验证证据
- **测试**:网关 JwtAuthFilterTest 26/26(新增多角色越权矩阵 14 例:CUSTOMIZER/ROOM_MANAGER/OPERATOR/MATERIAL_ADMIN/CUSTOMER_SERVICE/ADMIN/SALES/DESIGNER/unknown-role → 403;VEHICLE_MANAGER/SUPER_ADMIN → 放行;排除路径放行;服务发现前缀/matrix 参数防绕过)、JwtAuthFilterGrasslandGuideTest 38/38、TraceIdFilterTest 3/3;fleet FleetAdminRoleGuardInterceptorTest 16/16(新增非车务角色参数化矩阵);fleet 全量 verify 3240 例仅 ReleaseE 8033 环境基线失败(干净基线同表现);gateway 全量仅 CrossSchemaMigrationAuditTest 基线失败(#5435 引入,与本次无关);fleet spotless:check 通过
- **部署**:hl-gateway 双实例 UP(23:13-23:14 滚动部署)
- **网关验证**:CUSTOMIZER 删司机/派单/建车辆 → `code=403 无权限访问车务管理`;ROOM_MANAGER 删司机 → 403;VEHICLE_MANAGER 删司机 → 透到业务层(600205 司机不存在,不误伤);CUSTOMIZER `GET /admin/fleet/vehicle-types/list` → 200 放行
@@ -0,0 +1,86 @@
---
schema: "hl-changelog/v2"
ticket: "5550"
title: "派单车辆槽位可删除(车务可删任意未派单槽位含定制师傅建议的)"
consumer: "admin"
change_type: "新增接口"
author: "wx(GIT)"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "pi-main-session"
frontend_ref: "hl-admin@99fc5bfcc0d52aed3d3e663ca2df247583a53409"
target_release: ""
verified_at: ""
status_note: "后端完成:PR #5551 已合并 dev-v3 并部署 TEST;网关验证通过(未派单槽位删除成功+关联一致、已派槽位拒绝、不存在 605012)。前端在派单页槽位操作区增加删除入口即可。"
updated_at: "2026-08-05"
base: "dev-v3"
---
# 车务: 派单车辆槽位可删除
> **服务**: hl-fleet-service
> **PR**: #5551
> **Issue**: [#5550](https://git.1814.love:8443/wx/HL/issues/5550)
> **日期**: 2026-08-05
## 背景
派单页面车辆槽位(槽位 1/2)此前无删除入口。本次新增槽位删除能力:**车务可删除任意未派单槽位**(含定制师傅建议的),删除后日切片/Step2 canonical 快照/看板自动一致。
## 变更接口
| 方法 | 路径 | 来源 |
|---|---|---|
| `DELETE` | `/admin/fleet/assignments/slots/{slotId}` | `AssignmentController`(fleet) |
路径前缀 `/admin/fleet/**` 已由网关登录/角色校验与 `FleetAdminRoleGuardInterceptor`(VEHICLE_MANAGER / SUPER_ADMIN)收口,无需新增网关规则。
## 1. 删除车辆槽位 `DELETE /admin/fleet/assignments/slots/{slotId}`
请求参数:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `slotId` | string(Long) | 是 | PathVar,稳定槽位 ID(Step2 快照 retainedSlotIds 中的值) |
| `reason` | string | 否 | Body,删除原因(≤200 字,操作日志留痕) |
**删除规则(业务口径)**:
- **可删**:槽位全部行均为 `unassigned`(未派单),或仅含普通 `canceled` 历史行(取消流水保留不删)
- **拒绝(605007)**:槽位存在 `holding`/`assigned`/`completed` 行,或**已最终确认方案(dispatchPlanFinalized=1)的取消行**——finalized 取消行会使槽位在 Step2 reconcile 中复活且关联对账,禁止删除
- **605012**:槽位不存在
**删除动作(事务内)**:
1. 软删该槽位全部 `unassigned` 每日切片(canceled 历史行保留——对账/保险 REFUND 关联不丢失)
2. Step2 canonical 快照:`retainedSlotIds` 移除该槽位 + `snapshotVersion` 递增 + `contentDigest` 重算(与 Board 口径一致)
3. 派单操作日志追加 `slot_removed`(幂等键 `slot-remove:{slotId}`,按槽位幂等)
响应 `data`:
| 字段 | JSON 类型 | 说明 |
|---|---|---|
| `slotId` | string(Long) | 被删除槽位 ID |
| `requirementId` / `orderId` | string(Long) | 归属需求/订单 |
| `removedRowCount` | int | 软删除的未派单切片行数 |
| `retainedSlotIds` | array(string) | 删除后快照保留槽位集合 |
| `snapshotVersion` | string(Long) | 删除后快照版本(无快照为 null) |
**错误码**:**605012** 槽位不存在 / **605007** 槽位已派车或已确认,请先取消派车后再删除 / **605008** 抢锁超时 / 401 未登录。
## 前端配合
派单页面槽位操作区增加「删除槽位」入口:
- 槽位存在已派车/已确认时后端返回 605007,前端展示错误提示并引导先取消派车;
- 删除成功后可刷新候选(canonicalSnapshot.retainedSlotIds 已收敛),无需其他联动。
## 关联/联系人
### 链接
- [后端工单 #5550](https://git.1814.love:8443/wx/HL/issues/5550)
- [后端 PR #5551](https://git.1814.love:8443/wx/HL/pulls/5551)
- Merge commit: `a422c58f91`
### 联系人
- **后端负责人**: @wx
@@ -0,0 +1,65 @@
---
schema: "hl-changelog/v2"
ticket: "5629"
title: "precheck 对不存在车辆/司机返回明确 conflict 原因"
consumer: "admin"
author: "wx"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "not_required"
frontend_owner: ""
frontend_ref: ""
target_release: ""
verified_at: ""
status_note: "后端完成:PR #5637 合并 dev-v3(d621d25471a1c75652e19bd4c471bb61fb0dea95)并部署 TEST;网关实测不存在车/司机 precheck conflict=true 且 conflicts 含 vehicle_not_found(车辆不存在)/driver_not_found(司机不存在),有效资源对照 conflicts 为空不误报。"
updated_at: "2026-08-07"
base: "dev-v3"
generated: "2026-08-07T12:10:00+08:00"
---
# precheck 对不存在车辆/司机返回明确 conflict 原因(#5629)
## 背景
E2E 实测:`POST /admin/fleet/assignments/precheck` 对**不存在的车辆/司机**(如 vehicleId/driverId=999999999999999999)返回 `code=200, conflict=true`,但 **`conflicts=[]` 为空**——原因只埋在 `warnings`(`vehicle_unavailable`/`driver_unavailable`,msg=「车辆不存在或已删除」/「司机不存在或已删除」),车务预览在冲突明细区看不到"车辆不存在/司机不存在"的明确提示。
## 变更内容
`POST /admin/fleet/assignments/precheck` 响应 `conflicts` 新增两种类型(资源不存在时置 `conflict=true` 阻断,与既有 `resourceUnavailable` 行为一致,仅把原因从仅 warnings 补进 conflicts):
| conflict.type | 触发条件 | msg 文案 |
|---|---|---|
| `vehicle_not_found` | 车辆不存在(`vehicle==null`) | 车辆不存在 |
| `driver_not_found` | 司机不存在(`driver==null`) | 司机不存在 |
补充说明:
- `conflicts[].msg` 字段此前对重叠冲突(`vehicle`/`driver`)留空由前端结构化自渲染,本次对不存在类冲突填入明确文案;`PrecheckResult.ConflictItem` BO 新增 `msg` 字段并由 converter 透传。
- 车辆/司机**存在但不可用**(维保/停用、休假/待激活)仍只进 `warnings`(`vehicle_unavailable`/`driver_unavailable`),不新增 conflicts 项,行为不变。
- `warnings` 中 `vehicle_unavailable`/`driver_unavailable`(含"不存在或已删除"文案)保留,向后兼容。
- precheck 仍为只读接口,不抛异常、不写库、不取锁。
## 关联 / 联系人
- 工单:https://git.1814.love:8443/wx/HL/issues/5629
- PR:https://git.1814.love:8443/wx/HL/pulls/5637
- 后端:wx
## 变更接口或验证证据
### 接口契约
- 接口路径/方法/请求体:不变。
- 响应 `data.conflicts[].type` 新增枚举值:`vehicle_not_found`、`driver_not_found`;此两种类型 `conflictAssignmentId/conflictOrderNo/conflictDateRange` 为空,`msg` 为明确原因文案。
### 验证证据
- 定向测试:`AssignmentServiceTest#precheck_notFoundResources_returnsExplicitConflictReason`(不存在车/司机 → conflicts 含两 not_found 类型+msg)、`AssignmentConverterTest#toPrecheckRespVO_notFoundConflictMsgPassthrough`(msg 透传)。
- 全量 `mvn -pl hl-fleet-service -am verify`:3242 项 0 失败 4 skipped(含 MySQL 集成);spotless:check 通过。
- 部署 TEST 成功(hl-fleet-service, dev-v3, d621d254)。
- 网关验证 10/10 PASS:不存在车+不存在司机 → conflict=true + vehicle_not_found(车辆不存在)+driver_not_found(司机不存在);有效车+不存在司机 → 仅 driver_not_found;不存在车+存在司机 → 仅 vehicle_not_found;有效车+存在司机对照 → conflicts=[] 不误报。
## 前端/调用方动作
- 管理后台派单预览页冲突明细区可直接展示 `vehicle_not_found`/`driver_not_found` 的 `msg` 文案(车辆不存在/司机不存在);不处理也不影响既有逻辑(`conflict=true` 仍会阻断,warnings 仍含 unavailable 提示兜底)。
@@ -0,0 +1,59 @@
---
schema: "hl-changelog/v2"
ticket: "5630"
title: "房型分类入口字典白名单校验 + 存量 BIG_BED 归一,行程/配房房型恢复中文显示"
consumer: "admin"
author: "wx"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "not_required"
frontend_owner: ""
frontend_ref: ""
target_release: ""
verified_at: ""
status_note: "后端完成:PR #5634 合并 dev-v3(4f881af977be50850a78c3b05ac9912758b8b87c)并部署 TEST;网关实测创建/更新房型 roomCategory=BIG_BED 被 310210 拒绝,存量 BIG_BED 三处数据源归一 KING 后订单详情 roomCategoryLabel 显示中文「豪华大床」。"
updated_at: "2026-08-07"
base: "dev-v3"
generated: "2026-08-07T11:45:00+08:00"
---
# 房型分类字典白名单校验 + 存量 BIG_BED 归一(#5630)
## 背景
行程安排/配房的房型显示英文 `BIG_BED` 无中文。根因链(TEST 库实证):
1. 房型管理入口 `RoomTypeCreate/UpdateRequest.roomCategory` 只校验非空+长度,**无字典 `room_category` 白名单校验** → `BIG_BED` 经房型管理入口写入 `room_type`(2026-02-19);
2. 配房时 `room_type.room_category` 快照进 `house_hotel_assignment` / `house_requirement_assignment_snapshot`,需求 `order_hotel_requirement.days` JSON 亦含该 code;
3. 房型 2026-05-28 已被人工改回 `KING`,但快照停留 `BIG_BED`;字典 `room_category` 无 `BIG_BED`(有 `KING`=豪华大床)→ `roomCategoryLabel` 字典映射失败 → 原样显示英文。
## 变更内容
`POST /admin/hotel/{hotelId}/room-type` 与 `PUT /admin/hotel/room-type/{roomTypeId}` 新增房型分类字典白名单校验:
- `roomCategory` 必须在字典 `room_category` 已维护 value 集合内(STANDARD/SINGLE/TWIN/QUEEN/KING/DELUXE/SUITE/FAMILY/YURT/SPECIAL/PARENT_CHILD),否则返回业务错误 **310210**(`房型分类无效:{code},仅允许字典 room_category 已维护的值`),不落库。
- 字典服务异常/字典数据缺失时降级放行(warn 日志),不阻塞房型管理主流程。
- `updateRoomType` 未变更 `roomCategory` 字段时不触发该校验。
补充说明:
- 无 DTO 字段结构变化;非法 category 此前会静默写库,现在返回 400 业务错误码 310210,属行为收紧。
- 前端无需适配:房型分类表单一向从字典 `room_category` 下拉选择,字典内值全部放行。
## 存量数据处理(TEST 已执行,生产需按相同 SQL 归一)
`BIG_BED→KING`(跟随源房型 3002000000000000013 当前口径,字典映射 `KING→豪华大床`):
```sql
-- TEST 已执行并复核清零(4+2+2 需求 4 处)
UPDATE house_hotel_assignment SET room_category='KING' WHERE room_category='BIG_BED'; -- 4 条
UPDATE house_requirement_assignment_snapshot SET room_category='KING' WHERE room_category='BIG_BED'; -- 2 条
-- order_hotel_requirement.days JSON:读出→递归 roomCategory BIG_BED→KING→写回(2 需求 4 处)
```
## 验证
- 定向测试 `RoomTypeCategoryValidationTest` 8/8:BIG_BED 拒绝(不写库)/KING 放行/字典异常降级/空字典降级/update 不改 category 不触发/null 拒绝。
- 合并后 dev-v3(4f881af9)`mvn -pl hl-resource-service -am verify`:2596 项 0 失败(3 个 option Mapper Testcontainers 测试因 Docker Desktop 29 API≥1.40 与老 ryuk 0.7.0 不兼容排除,基线同失败已实证,与本改动无关)。
- 网关实测 9/9:创建/更新 BIG_BED → 310210 拒绝;归一前订单详情 label=BIG_BED(英文实证);三处归一复核清零;归一后两订单 label 全显示「豪华大床」。
@@ -0,0 +1,284 @@
---
schema: "hl-changelog/v2"
ticket: "5633"
title: "订单详情补核单状态字段"
consumer: "admin"
change_type: "修改接口"
author: "yst(GIT)"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "mmg"
frontend_ref: "hl-admin@18f8e23b9b2c77a81fed3de87fe9a7b94ff3b201"
target_release: "v2.1"
verified_at: ""
status_note: "PR #5635 已合并 dev-v3;2026-08-10 复核确认测试服已部署、reviewStatus/reviewStatusName 经网关实测在出参中(见文末验证证据章节)。管理后台待接入。"
updated_at: "2026-08-10"
base: "dev-v3"
---
# 🔧【修改接口·管理后台】订单详情补核单状态字段 (#5633)
> **PR**:[#5635](https://git.1814.love:8443/wx/HL/pulls/5635) | **服务**:`hl-order-service-v3` | **更新时间**:2026-08-07 | **消费端**:管理后台
## 1. 接口背景
订单详情页原有的「核单中」徽标取自 `flowStatus=REVIEWING`(订单流程状态),而核单列表页按 `review_status`(核单任务状态)分 tab,两者是**两个不同字段**:详情文案「核单中」与列表 tab 文案「核算中」字序不一致,导致用户在详情看到「核单中」后到核单列表找不到对应 tab,产生「单丢了」的误判。
本次在订单详情出参 `main` 段补齐 `reviewStatus` / `reviewStatusName` 两个字段,与核单列表 tab 使用**同一枚举、同一文案**,消除详情与列表的口径歧义。
## 2. 变更清单
| # | 接口名 | 方法 | 路径 | 变更类型 | 说明 |
|---|---|---|---|---|---|
| 1 | 订单详情 | `GET` | `/v3/admin/order/{id}` | 修改 | 出参 `data.main` 段新增 `reviewStatus`、`reviewStatusName` 两个字段;其余字段与行为不变 |
## 3. 接口详情
### 3.1 订单详情
- **接口说明**:查询单个订单的详情聚合数据(主单 + 各 Tab 数据段),本次变更只涉及 `data.main` 段。
- **使用场景**:管理后台打开订单详情页。
- **认证**:需要管理后台登录态和订单查看权限。
- **幂等性**:是,只读查询。
- **限流**:未声明接口级独立限流规则。
## 4. 接口入参
### 4.1 路径参数 / Query 参数
| 字段 | 位置 | 类型 | 必填 | 说明与校验 |
|---|---|---|---|---|
| `id` | Path | String(Long) | 是 | 订单 ID,必须为正整数;按字符串传递,避免大整数精度损失 |
无 Query 参数。
### 4.2 请求体字段
GET 请求无请求体。
## 5. 出参字段
响应类型:`Result<OrderDetailRespVO>`。本次变更集中在 `data.main`(`OrderMainVO`)段,下表只列出与本次变更相关的主单状态字段簇;`main` 段其余字段及 `tags` / `overview` 等其他数据段均不变。
### 5.1 统一响应外层
| 字段 | 类型 | 可空 | 说明 |
|---|---|---|---|
| `code` | Integer | 否 | 成功为 `200`;失败见 §7 |
| `message` | String | 否 | 结果说明 |
| `data` | Object/null | 失败时为空 | 成功时为订单详情聚合数据 |
| `traceId` | String | 是 | 链路追踪 ID |
| `success` | Boolean | 否 | `code=200` 时为 `true` |
### 5.2 `data.main` 状态字段簇
| 字段 | 类型 | 可空 | 说明 |
|---|---|---|---|
| `id` | String(Long) | 否 | 订单 ID,按字符串返回 |
| `orderNo` | String | 否 | 订单号 |
| `orderStatus` | String | 否 | 订单主状态枚举值(6 主状态) |
| `orderStatusName` | String | 否 | 订单主状态中文名 |
| `flowStatus` | String | 是 | 订单流程细状态枚举值;`REVIEWING` 表示流程处于核单环节,**不等于**核单任务状态 |
| `flowStatusName` | String | 是 | 订单流程细状态中文名(如「核单中」) |
| `reviewStatus` | String/null | 是 | **本次新增**。核单任务状态枚举值,对应 `order_main.review_status`,与核单列表 tab 同枚举;取值见 §6 |
| `reviewStatusName` | String/null | 是 | **本次新增**。核单任务状态中文名,与核单列表 tab 文案一字不差;取值见 §6 |
| `flowStep` | Integer/null | 是 | 线性 6 步当前步序号(1-6=进行中各步;null=已取消终态) |
| `flowStepTotal` | Integer | 否 | 线性步骤总数,固定 `6` |
| `flowStepName` | String/null | 是 | 当前步中文名 |
| `flowStepCode` | String/null | 是 | 当前步编码 |
| `flowStepStatus` | String/null | 是 | 当前步状态 |
> `main` 段其余字段(金额、日期、来源、合同/保险/退款状态徽标等)本次无变化,沿用既有契约。
## 6. 枚举 / 数据字典
### 6.1 `main.reviewStatus` / `main.reviewStatusName`
**所属字段**:`data.main.reviewStatus`、`data.main.reviewStatusName` | **类型**:String/null | **可空**:是
| `reviewStatus` 值 | `reviewStatusName` 值 | 说明 |
|---|---|---|
| `NONE` | `待核算` | 尚未生成核单任务;对齐核单列表归一逻辑,与 `PENDING` **同显「待核算」**,不单独显示「未核单」 |
| `PENDING` | `待核算` | 核单任务待处理 |
| `IN_PROGRESS` | `核算中` | 核单任务进行中 |
| `COMPLETED` | `已完成` | 核单任务已完成 |
| `null` | `null` | 订单尚无 `review_status` 值(如未进入核单流程的订单);此时两字段均为 JSON 空值,不是字符串 `"null"` |
**容错规则**:
- `reviewStatus` 为 `null` 时,`reviewStatusName` 也为 `null`,不报错。
- `reviewStatus` 为无法识别的值时,`reviewStatusName` **原样返回该值**,接口不抛错。
**与 `flowStatus` 的关系**:`flowStatus=REVIEWING` 表示订单流程走到核单环节(中文名「核单中」),是流程维度;`reviewStatus` 是核单任务自身的状态机维度,与核单列表 tab 同源。两者并存、语义不同,前端展示核单任务状态时以 `reviewStatus` / `reviewStatusName` 为准。
## 7. 错误码
| code | 含义 | 触发场景 |
|---|---|---|
| `200` | 查询成功 | 正常返回订单详情 |
| `400` | 请求参数错误 | `id` 不是正整数 |
| `401` | 未登录或登录态失效 | 缺少或携带无效的管理后台访问令牌 |
| `403` | 无访问权限 | 登录态、角色或权限不允许访问 |
| `581007` | 订单不存在 | `id` 对应订单不存在(含已软删除) |
## 8. 示例
### 8.1 典型成功:核单任务进行中
**请求**:
```http
GET /v3/admin/order/9223372036854775000
Authorization: Bearer <管理后台访问令牌>
```
无请求体。
**响应**(只截取 `data.main` 状态字段簇,其余字段省略):
```json
{
"code": 200,
"message": "成功",
"data": {
"main": {
"id": "9223372036854775000",
"orderNo": "HL20260801000001",
"orderStatus": "CONFIRMED",
"orderStatusName": "已确认",
"flowStatus": "REVIEWING",
"flowStatusName": "核单中",
"reviewStatus": "IN_PROGRESS",
"reviewStatusName": "核算中",
"flowStep": 5,
"flowStepTotal": 6,
"flowStepName": "核单结算",
"flowStepCode": "SETTLEMENT",
"flowStepStatus": "IN_PROGRESS"
}
},
"traceId": null,
"success": true
}
```
### 8.2 边界情况:尚无核单任务状态(reviewStatus 为 null)
**场景说明**:订单尚未进入核单流程,`order_main.review_status` 为 NULL,两字段均返回 JSON 空值;前端按「无核单任务状态」处理,不要按字符串 `"null"` 判断。
**请求**:
```http
GET /v3/admin/order/900000000002
Authorization: Bearer <管理后台访问令牌>
```
无请求体。
**响应**(只截取 `data.main` 状态字段簇):
```json
{
"code": 200,
"message": "成功",
"data": {
"main": {
"id": "900000000002",
"orderNo": "HL20260802000002",
"orderStatus": "PENDING",
"orderStatusName": "待确认",
"flowStatus": "AWAITING_CONFIRM",
"flowStatusName": "待确认",
"reviewStatus": null,
"reviewStatusName": null,
"flowStep": 2,
"flowStepTotal": 6,
"flowStepName": "待确认",
"flowStepCode": "CONFIRM",
"flowStepStatus": "IN_PROGRESS"
}
},
"traceId": null,
"success": true
}
```
另:`reviewStatus=NONE` 时 `reviewStatusName` 返回「待核算」(与 `PENDING` 同文案,对齐核单列表归一逻辑),见 §6。
### 8.3 业务失败:订单不存在
**请求**:
```http
GET /v3/admin/order/999999999999
Authorization: Bearer <管理后台访问令牌>
```
无请求体。
**响应**:
```json
{
"code": 581007,
"message": "订单不存在",
"data": null,
"traceId": null,
"success": false
}
```
## 9. 业务边界
- **适用**:所有 v3 订单的详情查询;需要展示「核单任务状态」(与核单列表 tab 口径一致)的场景。
- **不适用**:判断订单流程进度仍用 `flowStatus` / `flowStep` 等流程字段,`reviewStatus` 只表达核单任务自身状态,不能替代流程状态。
- **特殊边界**:
- 未进入核单流程的订单 `reviewStatus` 为 `null`,属正常数据,不是异常。
- `NONE` 与 `PENDING` 展示文案同为「待核算」,与核单列表 tab 完全一致;需要区分「未生成任务」与「任务待处理」时用 `reviewStatus` 枚举值判断,不要用中文名判断。
## 10. 修改前后对比
### 10.1 字段级对比(`data.main` 段)
| 字段 | 修改前 | 修改后 |
|---|---|---|
| `reviewStatus` | 不存在 | 新增,String/null,核单任务状态枚举值 |
| `reviewStatusName` | 不存在 | 新增,String/null,核单任务状态中文名(与核单列表 tab 同文案) |
| 其余字段 | 不变 | 不变 |
### 10.2 行为级对比
| 维度 | 修改前 | 修改后 |
|---|---|---|
| 详情页核单状态来源 | 只有 `flowStatus=REVIEWING`(文案「核单中」),与核单列表 tab 口径不一致 | 新增 `reviewStatus` / `reviewStatusName`,与核单列表 tab 同枚举、同文案 |
| 接口签名 | `Result<OrderDetailRespVO>` | 不变,仅出参多 2 个字段 |
| 入参 / 错误码 | 不变 | 不变 |
## 11. 影响评估 / 回滚
- **兼容性**:纯新增出参字段,向后兼容;未接入新字段的前端版本不受影响,可继续按原字段渲染。
- **破坏兼容**:无。
- **前端同步上线**:不要求同步上线;详情页核单徽标切换到 `reviewStatusName` 可在后端发布后任意时间进行。
- **回滚方案**:还原 PR #5635 对应提交即可,`main` 段不再返回这两个字段;前端读取不到时按字段缺失处理(`undefined`),不会解析报错。
## 12. 注意事项
- `reviewStatusName` 文案与核单列表 tab **一字不差**:「待核算 / 核算中 / 已完成」;不要在前端自行映射文案,直接使用该字段,避免再次出现字序不一致。
- `NONE` 与 `PENDING` 同显「待核算」是**有意对齐**核单列表的归一逻辑,不是 bug。
- `reviewStatus` 为 `null` 时 `reviewStatusName` 必为 `null`;`reviewStatus` 为非法值时 `reviewStatusName` 原样返回该值,接口不抛错。
- `main.id` 等 Long 型 ID 按字符串序列化,前端按字符串处理,避免大整数精度丢失。
## 13. 关联 / 联系人
- **Issue**:[#5633](https://git.1814.love:8443/wx/HL/issues/5633)
- **PR**:[#5635](https://git.1814.love:8443/wx/HL/pulls/5635)
- **Commit**:[c378061b08](https://git.1814.love:8443/wx/HL/commit/c378061b08e85cc7794b23c2a49691ad4f8eb01e)
- **后端负责人**:腰苏图
## 验证证据(2026-08-10 复核回填,wx)
> 本条 changelog 2026-08-07 推送时 backend_status=implemented(非法枚举且未部署),违反「测试服部署+实测后才通知前端」流程。2026-08-10 复核补齐部署与验证证据如下:
- 测试服 hl-order-service-v3 运行版本为 2026-08-10 15:10 构建(dev-v3),晚于 PR #5635 合并点(2026-08-07 14:25),本变更代码已在运行实例中。
- `GET /v3/admin/order/{orderId}` 经网关 9443 + 真 admin token 实测:`data.main` 已包含 `reviewStatus` / `reviewStatusName` 两个键(未进入核单流程的订单两键返回 JSON null,符合本文 8.2 边界示例)。
@@ -0,0 +1,89 @@
---
schema: "hl-changelog/v2"
ticket: "5636"
title: "对账vehicle-fee对齐核单重设计(补driverId必填+移除退款字段)"
consumer: "admin"
author: "wx(GIT)"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "mmg"
frontend_ref: "hl-admin@d897c3d4fc31932dd351e99f1911144314e2cc2f"
target_release: ""
verified_at: ""
status_note: "后端完成:PR #5641 已合并 dev-v3 并部署 TEST(hl-fleet-service + hl-order-service-v3 双实例)。网关验证通过(对账车辆费用查询接口正常返回,响应已不含 refund 字段)。internal Feign 契约变化:写入接口 Item 补 driverId 必填、移除 refundAmount/refundedAt;对账查询 VO 移除 refund 聚合。"
updated_at: "2026-08-07"
base: "dev-v3"
generated: "2026-08-07T14:00:00+08:00"
---
# 对账 vehicle-fee 对齐核单重设计(补 driverId 必填 + 移除退款字段)
> 后端完成:PR #5641 已合并 dev-v3 并部署 TEST,网关验证通过。
## 关联 / 联系人
### 链接
- **Issue**: [#5636](https://git.1814.love:8443/wx/HL/issues/5636)
- **PR**: [#5641](https://git.1814.love:8443/wx/HL/pulls/5641)
- **Merge commit**: [d0e976f9e](https://git.1814.love:8443/wx/HL/commit/d0e976f9e)
### 联系人
- **后端负责人**: @wx
## 背景
#5610 已实现 `POST /internal/fleet/reconciliation/vehicle-fee`(核单完毕写入对账车辆实际费用),但参数与核单重设计(hl-backend-changelog 06_5597)不一致:
| 项 | 设计要求 | 修复前实现 |
|----|---------|-----------|
| driverId | **必填**(对账按司机关联) | **缺失**(只有 driverName) |
| refundAmount/refundedAt | **不含**(核单无退款) | **多了**(核单无退款数据,字段恒空) |
| vehicleId | fleet 侧按派单(司机+日期)关联 | order 透传 |
## 口径(wx 定)
- **driverId 由核单传**(核单按司机算钱天然携带)
- **vehicleId 由 fleet 侧按派单(司机+日期)从 `fleet_assignment` 关联**(核单可不传)
- **无 refundAmount/refundedAt**(核单无退款数据;退款归支付/退款模块)
## 方案
1. **写入契约** `SettlementVehicleFeeWriteDTO.Item`:补 `driverId`(`@NotNull` 必填);移除 `refundAmount`/`refundedAt`
2. **表 `fleet_reconciliation_vehicle_fee`**:migration `V20260807_001` 加 `driver_id` 列 + `idx_driver_service_date` 索引,删 `refund_amount`/`refunded_at` 列(H2 兼容:单动作 ALTER / CREATE INDEX,不带 AFTER)
3. **写入 Service**:`driverId` 必填校验(缺失 → 605610);`vehicleId` item 未传时按派单反查 `fleet_assignment.vehicle_id` 关联填入;`driverName` 快照缺失时按派单反查补全
4. **对账查询**:移除 refund 聚合(`ReconCarsVehicleVO.refundAmount` / `ReconCarsFleetVO.refundTotal` / `ReconCarsGrandTotalVO.refundTotal` + `ReconciliationQueryService` 三处聚合)
5. **order 侧 publisher**:`buildItems` 透传核单冻结行 `line.driverId()`;移除「终止退款挂首行」逻辑
## 变更接口
| 方法 | 路径 | 服务 | 说明 |
|---|---|---|---|
| POST | `/internal/fleet/reconciliation/vehicle-fee` | hl-fleet-service | **internal Feign 契约**:Item 补 `driverId`(必填),移除 `refundAmount`/`refundedAt` |
| GET | `/admin/fleet/reconciliation/cars` | hl-fleet-service | 响应 VO 移除 `refundTotal`(车队/总计)与 `refundAmount`(车辆明细)字段 |
**契约变化**:
- internal 写入接口(order-v3 → fleet,Feign 直连不经网关):请求 Item **新增必填 `driverId`**、**删除 `refundAmount`/`refundedAt`**。order 侧 publisher 同 PR 同步改造,双侧一并部署,无跨版本兼容窗口。
- 对账查询接口(管理后台):响应**删除 refund 相关字段**(`grandTotal.refundTotal`、`fleets[].refundTotal`、`fleets[].vehicles[].refundAmount`)。核单无退款数据,这些字段恒为 0/null,删除不影响实际口径。
## 行为变化
- 核单完毕写入对账车辆费用时,每条明细必须携带 `driverId`(核单按司机算钱天然有);缺失返回 `code=605610`
- 对账「实际结算」列数据源不变(仍读 `SUM(actual_amount)`);退款相关展示字段从响应移除
- 既有 `#5610` 期间写入的历史行若无 `driver_id`,随重核覆盖写自然补全
## 前端/调用方动作
- **管理后台对账页**:若引用了对账车辆费用响应的 `refundTotal`/`refundAmount` 字段,需移除相关展示(核单无退款,这些字段恒空)。「实际结算」列数据源不变。
- internal 写入接口由 order-v3 内部 Feign 调用,双侧同 PR 同步改造并一并部署,前端无感知。
## 验证证据
- **测试**:fleet reconciliation 38/38(VehicleFeeService 10 含新增 driverId 必填/vehicleId 派单关联用例 + Query 11 + Period 17);order publisher 4/4(含 driverId 透传用例)+ outbox 26/26 + InternalRequirement 17/17;fleet spotless:check 通过
- **fleet verify**:3243 例,仅 ReleaseE 8033(需 MySQL 8.0.33 环境)+ MixedBinaryHarness 偶发——基线已知失败,与本案无关
- **order-v3 verify**:LayerEnforcement/RedLineArch 转绿(顺带修复 #5603 引入的 Controller→DO ArchUnit 违规);剩余 7 失败 + 95 errors 全为 Testcontainers/MySQL schema 基线失败(`order_settlement_summary` 缺表等),与 vehicle-fee driverId 无关
- **部署**:hl-fleet-service + hl-order-service-v3 双实例滚动部署 UP(13:53-13:55)
- **网关验证**:VEHICLE_MANAGER 调 `GET /admin/fleet/reconciliation/cars` → 200,`grandTotal` 仅含 `actual/diff/estimated/payable/totalDays/totalOrderCount`,已无 `refundTotal`;CUSTOMIZER 调 → 403(#5626 门禁生效)
@@ -0,0 +1,64 @@
---
schema: "hl-changelog/v2"
ticket: "5640"
title: "司机详情页直接投保全年保险 POST /admin/fleet/drivers/{id}/insure"
consumer: "admin"
author: "wx"
change_type: "新增接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "mmg"
frontend_ref: "845d8827"
target_release: ""
verified_at: ""
status_note: "后端完成:PR #5645/#5651/#5652 合并 dev-v3(6f7a9c19b70444395558f137e4cde6fb9524ecff)并部署 TEST;网关实证 600211 守卫+直接投保出单(INSURED)+保单可查+档案年险回填+重复投保 540032 拦截。TEST 用 4 天档降档验证(TEST 无 365 天档计划,环境限制);生产上线需配 annual-direct-plan-id 指向生产年险产品(1-无限天)。"
updated_at: "2026-08-07"
base: "dev-v3"
generated: "2026-08-07T16:20:00+08:00"
---
# 司机详情页直接投保全年保险(#5640)
## 背景
司机详情页此前只能查看保单、不能直接投保;现有投保只有按行程(PER_TRIP 派单自动投)与手动选计划/起止的 purchase 接口。本单新增「一键直接投保全年保险」端点(wx 口径:直接投保=给司机投全年保险 annual policy,保额/期限按计划默认不可选,被保人=司机档案证件)。
## 新增接口
### `POST /admin/fleet/drivers/{driverId}/insure` —— 司机直接投保全年保险
**入参**:无(仅路径 driverId)。
**行为**:
- 默认计划解析:nacos `fleet.insurance.annual-direct-plan-id`(缺省回落 `annual-gap-plan-id`)→ DRIVER/BOTH 可用计划唯一候选自动选;**多候选/无候选抛 600211**(禁止按列表顺序猜测保额)。
- 保障期:**T+1 起保**(保游硬性约束:即时生效保险起保日必须大于当前时间,540030)× `fleet.insurance.annual-direct-coverage-days` 天(**默认 365=全年**;TEST 环境无 365 天档计划,配 4 天降档验证)。
- 被保人:司机档案证件(姓名/身份证/手机/性别自动组装)。
- 受理即绑档案年险:insurance_type=annual + 保单号/保费/起止回填 + annualSource=baoyou;保游回调 INSURED 补真实保单号,FAILED/CANCELLED 自动解绑回退(沿用 #3760/#5558 Saga)。
- 幂等:同日同人幂等键 + 上游 540032(保障期重叠)双重拦截重复投保。
**响应**:`DriverInsurancePolicyDTO`(与 purchase/policies 同结构,证件号脱敏)。
**错误码**:600205 司机不存在 / **600211 未配置默认全年保险计划且候选不唯一(新增)** / 100001 司机身份证非18位 / 540031 计划未标注司机可用 / 540032 保障期已有生效保单 / 540005 计划不存在 / 540007 无匹配费率 / 540034 产品已下架不可售 / 600206 出单成功但年险绑定失败 / 605601 保险服务不可用。
## 前端交接(司机详情页【投保】按钮)
- 按钮调 `POST /admin/fleet/drivers/{driverId}/insure`(无 body)。
- 成功:返回保单 DTO,提示投保成功并刷新保单列表(`GET /{driverId}/insurance/policies`)与司机详情(insurance_type 变 annual、年险四件套已回填)。
- 600211:提示「未配置默认全年保险计划,请联系运营」;540032:提示「该保障期已有生效保单」;600206:提示「出单成功但年险绑定失败,勿重复投保,联系管理员」。
- 建议按钮在司机已有生效年险时禁用或二次确认(前端可据详情接口 insurance_type/年险起止判断)。
## 配置项(nacos `hl-fleet-service-${env}.yml` → `fleet.insurance`)
| 键 | 含义 | TEST | 生产 |
|---|---|---|---|
| `annual-direct-plan-id` | 直接投保默认计划 | 2067501078319951874(畅心游20万) | **待配:指向生产年险产品计划(1-无限天)** |
| `annual-direct-coverage-days` | 保障天数,默认 365 | 4(TEST 无 365 天档,降档验证) | 不配(默认 365) |
**遗留(不阻塞本单)**:生产 `annual-direct-plan-id` 需运营在保游维护/确认年险产品计划后配置(wx 确认生产有 1-无限天司机年险产品)。
## 验证
- DriverInsuranceServiceTest **30/30**:配置计划一年期+受理即绑 / 单候选自动选 / 多候选 600211 / 无候选 600211 / 降档天数投保。
- 6f7a9c19 全量 verify **3253 项 0F/0E**/4 skipped。
- 网关实证:未配置→600211;配置后投保出单 INSURED(8.8~8.11 4 天档);保单列表可查;档案年险回填;insurance_order 落账 DRIVER+司机;重复投保 540032 拦截。
@@ -0,0 +1,71 @@
---
schema: "hl-changelog/v2"
ticket: "5642"
title: "出行人所属地后端解析返回 nativePlace(身份证前6位→地区名)"
consumer: "admin"
author: "wx"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "verified"
frontend_owner: "mmg"
frontend_ref: "7e7085b6"
target_release: ""
verified_at: ""
status_note: "2026-08-07 协调台浏览器实测:补身份证后派单页所属地正常显示「内蒙古呼伦贝尔市」(前端 implemented ref=7e7085b6 + 后端 #5656 链路 + 数据有身份证,端到端通),标 verified。"
updated_at: "2026-08-07"
base: "dev-v3"
generated: "2026-08-07T16:15:00+08:00"
---
# 出行人所属地后端解析返回 nativePlace(#5642)
## 背景
出行人"所属地"此前由前端从身份证号前 6 位自行解析,显示乱码。改为后端解析返回。口径经协调台确认:按**权威 GB/T 2260**(现行版,省+地级粒度)解析——150784=内蒙古呼伦贝尔市(工单示例"赤峰"系笔误,1504xx 才是赤峰);不新建 district 表,沿用 `IdCardParser` 静态码表模式(与 `idProvinceName` 同源)。
## 变更内容
`GET /v3/admin/order/{id}/traveler/list` 等 admin 出行人出参(`TravelerVO`,含 traveler list / 协同单 / 结算退回详情等所有 `toAdminVO` 路径)**新增 `nativePlace` 字段**:
| 场景 | nativePlace |
|---|---|
| 大陆身份证,命中地级码 | 省短名+地市名,如 `150784…`→`内蒙古呼伦贝尔市`、`320101…`→`江苏南京市` |
| 直辖市(1101/1201/3101/5001/5002) | 市名,如 `110101…`→`北京市` |
| 省直辖县级(4190/4290/4690/6590) | 按 6 位精确映射,如 `469001…`→`海南五指山市`、`659001…`→`新疆石河子市` |
| 非身份证(PASSPORT 等) | `null` |
| 未命中(含已撤销历史码如 3712 莱芜) | `null`(不报错) |
补充说明:
- 解析基于解密后的明文 idNo(converter 层既有行为),仅 18 位结构 + 合法生日段才解析;数据源为现行 GB/T 2260 地级行政区码表,不含已撤销历史代码(历史码身份证所属地返回 null)。
- 既有字段不受影响:`idCardMasked` 仍脱敏、`idProvinceCode/idProvinceName` 逻辑不变。
- internal VO(明文 Feign 契约)未加该字段,admin 出参仅新增只读字段,无破坏性。
## 关联 / 联系人
- 工单:https://git.1814.love:8443/wx/HL/issues/5642
- PR:https://git.1814.love:8443/wx/HL/pulls/5650
- 后端:wx
## 变更接口或验证证据
### 接口契约
- 接口路径/方法/请求体:不变。
- 响应 `data[].nativePlace` 新增字段(string | null):所属地(省+地级行政区名);非身份证或未命中为 `null`。
### 验证证据
- 定向测试 274 全过:`IdCardParserTest#extractNativePlace_*`(地级码/省直辖县级/非法与未命中 3 例)、`TravelerConverterTest#toAdminVO_*nativePlace*`(2 例),覆盖 TravelerService/TravelerAdminController/OrderDetailService。
- 全量 `mvn -pl hl-order-service-v3 -am verify`:7610 测试,7F/95E 全部位于 30 个基线已坏的 Mapper/集成 IT 类(Feign loadbalancer Bean 缺失、Flyway IT schema 校验等环境问题),git stash 基线复跑同类同败,无一涉及 traveler/idcard 影响面。
- 部署 TEST 成功(hl-order-service-v3 双实例 8086/8186 UP)。
- 网关验证 10/10 PASS(自建 HLTEST 订单 2085637067265449985):150784→内蒙古呼伦贝尔市、469001→海南五指山市、110101→北京市、PASSPORT→null、371201→null 不报错;脱敏与省级字段回归通过。
## 前端/调用方动作
- 出行人"所属地"列**直接展示后端返回的 `nativePlace`**,**删除前端自行解析身份证前 6 位的逻辑**(当前乱码来源)。
- `nativePlace` 为 `null` 时展示空(如 "-"),不要 fallback 到前端解析。
- 适用接口:所有返回 `TravelerVO` 的 admin 接口(出行人列表等)。
> 2026-08-07 协调台更正:派单详情接口 travelers 缺 nativePlace 系**后端覆盖不全**(fleet 派单详情 BoardOrderDetailVO 链路未加),非前端问题。另立后端工单补 fleet-detail-context→BoardOrderDetailVO 链路。前端 traveler/list 接入无误。
@@ -0,0 +1,57 @@
---
schema: "hl-changelog/v2"
ticket: "5643"
title: "派车价按车型+日期回显价格日历价(修复空收费日期误免)+ 调价/行程链接文案优化"
consumer: "admin"
change_type: "修改接口"
author: "wx(GIT)"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "not_required"
frontend_owner: ""
frontend_ref: ""
target_release: ""
verified_at: ""
status_note: "后端完成:PR #5647 已合并 dev-v3 并部署 TEST(15:46 滚动 DONE)。网关验证 6 项全 PASS:候选传空收费日期数组回显日历价 800×4=3200(修复前 4 天 FREE ¥0.00);按日历价派车成功且快照 source=AUTO;调价与行程链接文案按新口径展示。前端无需配合。"
updated_at: "2026-08-07"
base: "dev-v3"
generated: "2026-08-07T15:50:00+08:00"
---
# 派车价按车型+日期回显价格日历价(修复空收费日期误免)+ 调价/行程链接文案优化
> **服务**: hl-fleet-service
> **PR**: [#5647](https://git.1814.love:8443/wx/HL/pulls/5647)
> **Issue**: [#5643](https://git.1814.love:8443/wx/HL/issues/5643)
> **日期**: 2026-08-07
> **影响**: 🟢 **缺陷修复 + 文案优化**,无契约结构变更(字段不变,仅返回值/报错文案修正)。前端无需改代码。
## 背景
#5643(P1)wx 实测:价格日历有数据(SUV普拉多¥1000/天、GL8¥900、帕萨特¥600、考斯特¥1500,2026-08 各日期),但派车订单 26-6457(蒙A-H7777 汉兰达 SUV 8/9-8/12)派车价 4 天都 ¥0.00。
**根因**:`POST /admin/fleet/assignments/candidates` 把请求里的 `chargeableServiceDates=[]`(空数组)按字面空集处理 → 全程误判"免费" → 逐日 `assignmentPrice=¥0.00 source=FREE`、自动总价 ¥0。需求未配置收费日期时前端回传空数组(而非 null),触发该路径。
**网关复现**:同一需求传 `[]` → 4 天 FREE ¥0.00;不传 → 正常 800×4=3200(汉兰达日历价 ¥800/天)。
## 修复内容(内部,无接口/字段结构变化)
1. **候选取价空数组归一化**:`AssignmentCandidateService` 对 `chargeableServiceDates` 做空集合→未指定(=全部服务日收费)归一化,候选车辆逐日回显日历价(`source=CALENDAR`)、自动总价正确求和。创建/改派边界的"全免需二次确认+原因"守卫语义不变(`resolveChargeableServiceDates` 未动);已落库全免组(收费日为空的合法态)的改派/保留行取价不受影响。
2. **调价报错文案可行动化**(创建与逐日方案两处):价=日历价的日期填了调价原因时,报错由「日历价日期不能填写车辆调价原因」改为「派车价与日历价一致的日期无需填写调价原因,请清空未调价日期的调价原因后重试」。校验语义与审计不变量不变(调价日必须有原因、未调价日不留原因)。
3. **行程链接文案分级**:派单通知模板渲染 `itinerary.url 预览阶段(无可定位派车组)显示「行程链接在派单成功后自动生成」;派车组可定位但无效/定位歧义仍显示「行程链接暂不可用,请联系车务确认」(失败关闭保留);HOLD 未 finalize 组签链仍按 #5461 设计失败关闭。模板渲染的收费/免费日期摘要同步空数组归一化。
## 变更接口
- `POST /admin/fleet/assignments/candidates`:`chargeableServiceDates` 传 `[]` 与不传行为一致(全部服务日按价格日历取价);候选车辆 `dailyVehicleFees[].calendarPrice/assignmentPrice`、`autoVehicleFeeTotal` 正常回显(非 ¥0)。
- `POST /admin/fleet/assignments`、`POST /admin/fleet/assignments/batch`:未调价日期携带调价原因时的报错文案变更(错误码不变,100001/参数非法族)。
- `POST /admin/fleet/message-templates/:templateId/render`:`itinerary.url` 在预览阶段的占位文案变更(见上)。
## 验证证据
- 全量 `mvn -pl hl-fleet-service -am verify`:3252 Tests,Failures=0,Errors=0(dev-v3 @ 76bc874d);新增候选空收费日期回归用例;spotless 通过。
- 部署 TEST:15:46 滚动 DONE。
- 网关(订单 26-6457,蒙A-H7777 汉兰达 8/9-8/12,日历价 ¥800/天)6 项全 PASS:①候选传 `[]` 回显 800×4=3200 ②默认入参同样 3200 ③预览文案=行程链接在派单成功后自动生成 ④价=日历价+原因报新文案 ⑤HOLD 派车成功且 DB 快照 calendar=800 全收费、total=3200.00、source=AUTO ⑥HOLD 未 finalize 组渲染按设计失败关闭。
## 前端配合
无需配合。派车弹窗/候选列表原本读取的字段不变,现在能拿到正确的日历价。
@@ -0,0 +1,80 @@
---
schema: "hl-changelog/v2"
ticket: "5644"
title: "司机手机号支持车务管理员直接修改(放开 phone 可改)"
consumer: "admin"
author: "wx"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "mmg"
frontend_ref: "hl-admin@0e8340a1ca012de0c7e965906596ccc3c37d31cd"
target_release: ""
verified_at: "2026-08-07"
status_note: "后端完成:PR #5648 已合并 dev-v3(86e319ac1)并部署 TEST(hl-fleet-service 双实例)。手机号编辑放开:明文入参正常更新(格式 600212 / 重复 600203),脱敏回传保持原值;idCard 仍不可改。网关验证 12/12 通过:改 phone 生效、重复 600203、格式 600212、脱敏保持、idCard 不变、临时司机已清理。"
updated_at: "2026-08-07"
base: "dev-v3"
generated: "2026-08-07T14:50:00+08:00"
---
# 司机手机号支持车务管理员直接修改(放开 phone 可改)
> 后端完成:PR #5648 已合并 dev-v3 并部署 TEST。
## 关联 / 联系人
### 链接
- **Issue**: [#5644](https://git.1814.love:8443/wx/HL/issues/5644)
- **PR**: [#5648](https://git.1814.love:8443/wx/HL/pulls/5648)
- **Merge commit**: [86e319ac1](https://git.1814.love:8443/wx/HL/commit/86e319ac1)
### 联系人
- **后端负责人**: @wx
## 背景
司机手机号此前被锁死:后端编辑接口注释「idCard/phone 不可改:入参 phone 忽略不更新」,前端编辑页手机号禁用(「不可编辑,如需更换请联系管理员」)。wx 要求车务管理员可直接修改司机手机号(联系方式口径,不涉及司机登录账号体系)。
## 方案
**编辑司机档案接口放开 phone**(仅车务管理员权限,接口本身已由 `/admin/fleet/**` 角色门禁保护):
1. `PUT /admin/fleet/drivers/{id}`:入参 `phone` 不再忽略——**非空明文(不含 `*`)时正常更新**,落库前校验:
- **格式**:11 位数字,非法返 `code=600212 手机号格式错误(需 11 位数字)`(新增错误码;600211 已被 #5640 占用让位)
- **唯一性**:`existsByPhone(phone, excludeSelf)` 排除自身,与其他司机重复返 `code=600203 手机号已存在`
2. **脱敏回写防护**:详情页回显的手机号是脱敏值(如 `135****5020`),前端原样回传(含 `*`)时**跳过更新保持原值**(与 license.no 同机制,防掩码串覆盖 AES 加密真值);`phone` 不传(null)同样保持原值
3. **idCard 仍不可改**:入参忽略不更新(保持不变)
4. 手机号是唯一键(uk_phone),编辑更新走既有加密列等值比对(EncryptTypeHandler),服务层预校验 + DB 唯一键兜底
## 变更接口
| 方法 | 路径 | 服务 | 说明 |
|---|---|---|---|
| PUT | `/admin/fleet/drivers/{id}` | hl-fleet-service | **修改接口**:`phone` 入参放开可改(明文 11 位数字更新;含 `*` 脱敏回传 / null 保持原值;格式非法 600212;与其他司机重复 600203);`idCard` 仍忽略不更新 |
**请求体变化**:`phone` 字段从「编辑忽略」变为「可编辑」(新增时本就必填,字段定义不变,仅编辑语义变化)。
## 行为变化
- **车务管理员**编辑司机档案时,手机号可直接修改(不再被忽略);改后立即生效(档案联系方式口径,不联动登录账号)
- 修改为**其他司机已占用**的手机号 → `code=600203 手机号已存在`,整单拒绝
- 提交非 11 位数字 → `code=600212 手机号格式错误(需 11 位数字)`
- 不传 phone / 回传脱敏值 → 保持原手机号不变
- 身份证号(idCard)任何情况下不可修改(入参忽略)
## 前端/调用方动作
**必须**:司机编辑页手机号**去禁用**(去掉「不可编辑,如需更换请联系管理员」文案),改为可编辑输入框:
- 提交前可做 11 位数字格式校验(后端 600212 兜底)
- 若用户未修改手机号,编辑表单回显的是脱敏值(含 `*`),**原样回传即可**(后端保持原值)
- 修改时提交明文 11 位号码
- 后端返回 `600203`(重复)/ `600212`(格式)时按 Result 协议展示错误提示
## 验证证据
- **测试**:DriverServiceTest 151/151(新增 4 例:明文更新生效 / 脱敏回传保持原值 / 格式非法 600212 / 重复 600203 排除自身 / null 保持原值)、DriverControllerTest 30/30;fleet 全量 verify **3251 tests 0 失败 4 skipped** + spotless:check 通过(Release E 门禁参数)——见工单评论
- **部署**:hl-fleet-service 滚动部署 TEST 双实例 UP(dev-v3=86e319ac1)
- **网关验证**:待执行(改 phone 生效 / 脱敏保持 / 600203 重复拒绝)
@@ -0,0 +1,70 @@
---
schema: "hl-changelog/v2"
ticket: "5649"
title: "holdMode=0直派兼容全程占位行拓扑校验(修复既有缺口)"
consumer: "admin"
author: "wx(GIT)"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "not_required"
frontend_owner: ""
frontend_ref: ""
target_release: ""
verified_at: ""
status_note: "后端完成:PR #5653 已合并 dev-v3 并部署 TEST(hl-fleet-service 双实例)。修复 holdMode=0 直派+全程占位行需求拓扑校验必挂(既有缺口,#5643 发现非回归)。无请求/响应契约变化,仅派单 finalize 内部拓扑校验逻辑兼容全程形态。"
updated_at: "2026-08-07"
base: "dev-v3"
generated: "2026-08-07T17:10:00+08:00"
---
# holdMode=0 直派兼容全程占位行拓扑校验(修复既有缺口)
> 后端完成:PR #5653 已合并 dev-v3 并部署 TEST,网关验证通过。
## 关联 / 联系人
### 链接
- **Issue**: [#5649](https://git.1814.love:8443/wx/HL/issues/5649)
- **PR**: [#5653](https://git.1814.love:8443/wx/HL/pulls/5653)
- **Merge commit**: [86a8a8aa9](https://git.1814.love:8443/wx/HL/commit/86a8a8aa9)
### 联系人
- **后端负责人**: @wx
## 背景
#5643 发现的既有缺口(非回归):holdMode=0 直派的 batch dailyPlan 在**全程占位行需求**上必挂——`finalizeDailyBatchDispatchPlan` 期望逐日切片(`isSingleDaySlice`),但全程占位行(#5562 全程槽模型:`service_date` NULL、`startDate~endDate` 覆盖整个服务期)被整段消费后保持全程形态,只产生 `slot:startDate` 一个拓扑 key,与逐日 items(`slot:start..slot:end`)不匹配,单行 `isSingleDaySlice` 校验也必挂,拓扑校验误报「最终实派方案写入不完整」。考古 274b03561288(#5595 前基线)同样逻辑。holdMode=1 HOLD 路径跳过 finalize 不受影响。
## 修复
`finalizeDailyBatchDispatchPlan` 拓扑校验兼容全程占位行:
1. **key 展开**:将 `isFullTripRow` 的全程行按服务期逐日展开为多个逻辑 key(`slot:start..slot:end` 全部映射到同一物理行),与逐日 items 的 key 集合对齐
2. **单行校验**:合法形态从「仅 `isSingleDaySlice`」放宽为「`isSingleDaySlice || isFullTripRow`」——整段消费的全程行不再误判为写入不完整
3. **ID 去重**:全程行跨多天展开为多个逻辑 key 但对应同一物理行,`finalizedAssignmentIds` 按物理行去重(只收一次 ID),避免 `markDispatchPlanGeneration` 的 distinct 校验误报
## 变更接口
**无请求/响应契约变化**——仅派单 finalize 内部拓扑校验逻辑修复(`POST /admin/fleet/assignments/batch` 的 dailyPlan 直派路径行为修正:全程占位行需求从「必挂报错」变为「正常冻结」)。
## 行为变化
- **holdMode=0 直派 + 全程占位行需求**:从「拓扑校验必挂、报『最终实派方案写入不完整』」修复为「正常冻结最终实派方案」
- **holdMode=1 HOLD 路径**:跳过 finalize,完全不受影响
- **逐日切片路径**:`isFullTripRow` 为 false 走原逻辑,行为不变
- **拓扑真缺失**:仍正确报「写入不完整」(key 集合不匹配时不放松校验)
## 前端/调用方动作
无需改动(仅修复了直派路径在全程占位行需求上的误报,前端调用方式不变)。
## 验证证据
- **新增 3 用例**:直派全程占位行不误报 / 直派逐日切片不受影响 / 直派拓扑缺失仍报不完整
- AssignmentServiceTest **386/386 全绿**;fleet spotless:check 通过
- fleet verify(mvn-throttle 错峰):3243 测试仅 `ReleaseEOccupancyMysql8033RecoveryTest`(需 MySQL 8.0.33 环境)基线失败,与本案无关
- **部署**:hl-fleet-service 双实例 UP(17:05)
- **网关验证**:VEHICLE_MANAGER 调 `/admin/fleet/board/summary`、`/admin/fleet/reconciliation/cars` 均 200,服务健康
@@ -0,0 +1,48 @@
---
schema: "hl-changelog/v2"
ticket: "5654"
title: "修复应用到槽位丢价:批量逐日方案未传价日期按价格日历兜底"
consumer: "admin"
author: "wx"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "not_required"
frontend_owner: ""
frontend_ref: ""
target_release: ""
verified_at: ""
status_note: "后端修复完成:PR #5659 合并 dev-v3(d39ef846e166861a836cc86308134d2da0bbca99)并部署 TEST;网关实证修复前 500 NPE、修复后应用到槽位成功且未传价日期按日历价兜底落库+排车表正常读取。前端无需改动(纯后端容错修复)。"
updated_at: "2026-08-07"
base: "dev-v3"
generated: "2026-08-07T18:10:00+08:00"
---
# 修复应用到槽位丢价(#5654)
## Bug
排车表选车弹窗候选带出本次价 ¥900(#5643 已修候选带出),但点「应用到槽位」后排车表该槽位「本次派车价」全 ¥0.00、「日历价」列"—"——价格没写入槽位。
## 根因
「应用到槽位」(统一选择车辆/司机→应用)走 `POST /admin/fleet/assignments/batch`(dailyPlan 逐日方案):
1. `DailyPlanItem.assignmentPrice` 注释「used=true 时必填」但**无校验注解**,前端统一选择应用时不带价;
2. `flushDailyPlanSegment` 把 null 价原样包进 `dailyVehicleFees`;
3. `assertDailyFeeAdjustmentReasons` 对 null price 调 `compareTo` → **500 NullPointerException**(TEST 堆栈实证 `AssignmentService.java:2919`);
4. 应用失败槽位无派车行 → 排车表读取兜底 ¥0/—。
## 修复(行为变化)
`POST /admin/fleet/assignments/batch`(dailyPlan 模式):
- **未传价(assignmentPrice=null)的用车日期不再报错**,按「所选车辆车型 + 服务日」从价格日历兜底(与单体派单 `POST /assignments` 未传 protocolPrice 的口径一致)——修复前该场景 500 NPE。
- 未传价日期附带的单日调价原因被忽略(价格来自日历无调价);显式传价且与日历价不一致的日期仍需调价原因(不变)。
- VO 注释对齐口径:`assignmentPrice` 可空=日历兜底;`used=false` 时仍必须为空。
- 防御:`assertDailyFeeAdjustmentReasons` 对 null 日价跳过(不再 NPE)。
## 验证
- AssignmentServiceTest **389/389**(新增 3:无价日不进覆盖集/全无价空覆盖集/null 价不 NPE 防御);dev-v3 全量 verify 3259 项(唯一 Failure 为 releasee 进程时序 flaky,单跑 PASS,与本改动无关)。
- 网关实证(复现单 8/13-8/16 双槽位):修复前不带价应用 → 500 NPE;修复后 → 200 成功,槽位 1(汉兰达不带价)4 天 holding `protocol_price=vehicle_fee_calendar_price=800`(日历兜底)AUTO,排车表 `dailyVehiclePlan` 返回 `calendarPrice=assignmentPrice=800、priceSource=CALENDAR`;槽位 0(GL8 带价 900)3600 AUTO 正常。
@@ -0,0 +1,432 @@
---
author: "yst(GIT)"
schema: "hl-changelog/v2"
ticket: "5655"
title: "核单导游/摄影族B嵌套接口下线,统一走族A扁平接口"
consumer: "admin"
change_type: "删除接口"
backend_status: "deployed"
gateway_status: "not_required"
frontend_status: "implemented"
frontend_owner: "mmg"
frontend_ref: "ee7a5d58"
target_release: ""
verified_at: "2026-08-07"
status_note: "后端已删除族B guides/photographers 嵌套 GET/PUT 共4个路由并部署测试服;已行为级验证族B 4端点返回404、族A guide-fees/photographer-fees 正常返回。等待前端将导游/摄影页签从族B路径切换到族A扁平接口,frontend_status=pending 表示等待前端真实领取。"
updated_at: "2026-08-08"
base: "dev-v3"
---
# ⚠️【删除接口·管理后台】核单导游/摄影族B嵌套接口下线,统一走族A扁平接口 (#5655)
> **PR**: #5658 | **服务**: order-v3 | **更新时间**: 2026-08-07
## 1. 接口背景
核单页面的导游、摄影师费用历史上存在两套接口:
- **族 A(保留)**:`/settlement/guide-fees`、`/settlement/photographer-fees`,按天扁平行结构,与住宿、餐食等页签形态一致。
- **族 B(本次删除)**:`/settlement/staff-fees/guides`、`/settlement/staff-fees/photographers`,按人嵌套 `persons[]` 结构。
一笔导游/摄影费用只对应一个人,族 B 的 `persons[]` 嵌套属于过度设计,且与其他核单页签的平铺形态不一致。本次将族 B 共 4 个路由整体删除,导游/摄影核单统一由族 A 扁平接口承载。
**旧路径已删,调用返回 HTTP 404「接口不存在」。** 前端必须把导游、摄影师页签的查询/保存调用从族 B 路径切换到族 A 路径。
## 2. 变更清单
| # | 接口名 | 方法 | 路径 | 变更类型 | 说明 |
|---|--------|------|------|----------|------|
| 1 | 查询导游人员费用(族B) | GET | `/v3/admin/order/:orderId/settlement/staff-fees/guides` | 删除 | 路由删除,调用返回 HTTP 404 |
| 2 | 全量替换导游人员费用(族B) | PUT | `/v3/admin/order/:orderId/settlement/staff-fees/guides` | 删除 | 路由删除,调用返回 HTTP 404 |
| 3 | 查询摄影师人员费用(族B) | GET | `/v3/admin/order/:orderId/settlement/staff-fees/photographers` | 删除 | 路由删除,调用返回 HTTP 404 |
| 4 | 全量替换摄影师人员费用(族B) | PUT | `/v3/admin/order/:orderId/settlement/staff-fees/photographers` | 删除 | 路由删除,调用返回 HTTP 404 |
替代接口(族 A,**本次未改动,已在线**,前端切换目标):
| Tab | 查询 | 全量保存 | 确认 |
|-----|------|----------|------|
| 导游 | `GET /v3/admin/order/:orderId/settlement/guide-fees` | `PUT /v3/admin/order/:orderId/settlement/guide-fees` | `POST /v3/admin/order/:orderId/settlement/guide-fees/confirm` |
| 摄影师 | `GET /v3/admin/order/:orderId/settlement/photographer-fees` | `PUT /v3/admin/order/:orderId/settlement/photographer-fees` | `POST /v3/admin/order/:orderId/settlement/photographer-fees/confirm` |
## 3. 接口详情
### 3.1 已删除:族B 导游人员费用查询与保存
- **原方法与路径**:
- `GET /v3/admin/order/:orderId/settlement/staff-fees/guides`
- `PUT /v3/admin/order/:orderId/settlement/staff-fees/guides`
- **使用场景**:已删除。导游核单查询/保存改用 `/settlement/guide-fees`(见 §3.3)。
- **认证**:原接口要求管理后台登录态;接口删除后,即使登录态有效也返回 HTTP 404。
- **幂等性**:不适用。
- **限流**:无。
### 3.2 已删除:族B 摄影师人员费用查询与保存
- **原方法与路径**:
- `GET /v3/admin/order/:orderId/settlement/staff-fees/photographers`
- `PUT /v3/admin/order/:orderId/settlement/staff-fees/photographers`
- **使用场景**:已删除。摄影师核单查询/保存改用 `/settlement/photographer-fees`(见 §3.4)。
- **认证**:原接口要求管理后台登录态;接口删除后,即使登录态有效也返回 HTTP 404。
- **幂等性**:不适用。
- **限流**:无。
### 3.3 替代:导游费用(族A)
- **接口名**:查询导游费用 / 全量保存导游费用 / 确认导游费用
- **方法与路径**:
- `GET /v3/admin/order/:orderId/settlement/guide-fees`
- `PUT /v3/admin/order/:orderId/settlement/guide-fees`
- `POST /v3/admin/order/:orderId/settlement/guide-fees/confirm`
- **使用场景**:核单页面导游页签的查询、全量保存、确认。
- **认证**:管理后台登录态 + 订单访问权限。
- **幂等性**:GET 只读;PUT 为全量替换语义,需携带 `expectedSourceFingerprint` 乐观锁指纹(取值为最近一次 GET 返回的 `sourceFingerprint`),指纹不匹配拒绝写入;POST confirm 重复确认不产生副作用。
- **限流**:无接口级特殊限流。
### 3.4 替代:摄影师费用(族A)
- **接口名**:查询摄影师费用 / 全量保存摄影师费用 / 确认摄影师费用
- **方法与路径**:
- `GET /v3/admin/order/:orderId/settlement/photographer-fees`
- `PUT /v3/admin/order/:orderId/settlement/photographer-fees`
- `POST /v3/admin/order/:orderId/settlement/photographer-fees/confirm`
- **使用场景**:核单页面摄影师页签的查询、全量保存、确认。
- **认证 / 幂等性 / 限流**:与 §3.3 导游一致。
## 4. 接口入参
### 4.1 路径参数(族A GET / PUT / POST 通用)
| 字段 | 类型 | 必填 | 说明 | 校验 |
|------|------|------|------|------|
| `orderId` | String(Long) | 是 | 订单 ID | 正整数 |
GET 无 Query 参数、无请求体。POST confirm 无请求体。
### 4.2 PUT 请求体(全量保存)
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `expectedSourceFingerprint` | String | 是 | 乐观锁指纹,取最近一次 GET 返回的 `sourceFingerprint`;不匹配则拒绝写入 |
| `items` | Array | 是 | 全量费用行(扁平按天,无嵌套);传 `[]` 表示清空 |
| `excludedCandidateKeys` | String[] | 否 | 被排除的候选 `candidateKey` 列表;无排除传 `[]` |
`items[]` 行字段与 GET 出参行字段一致(见 §5.2),其中 `id` 已有行需回传、新增行不传。
## 5. 出参字段
### 5.1 顶层字段(GET `data`)
| 字段 | 类型 | 可空 | 说明 |
|------|------|------|------|
| `category` | String | 否 | 类别;导游固定 `GUIDE`,摄影师固定 `PHOTOGRAPHER` |
| `sourceFingerprint` | String | 否 | 乐观锁指纹;PUT 必须通过 `expectedSourceFingerprint` 回传 |
| `totalAmount` | String(Decimal) | 否 | 费用合计金额,字符串格式如 `"590.00"` |
| `cashPaidAmount` | String(Decimal) | 否 | 现付金额合计 |
| `unconfirmedCount` | Integer | 否 | 未确认行数 |
| `pendingCandidateCount` | Integer | 否 | 待处理候选数 |
| `settlementReady` | Boolean | 否 | 是否已具备核单条件 |
| `blockReasonCode` | String | 是 | 不具备核单条件时的机器可读原因;可核单时为 `null`,如 `ITEMS_UNCONFIRMED` |
| `editable` | Boolean | 否 | 当前是否可编辑 |
| `readOnlyReasonCode` | String | 是 | 只读原因;可编辑时为 `null` |
| `items` | Array | 否 | 费用行,扁平按天,无嵌套;无明细为 `[]` |
### 5.2 `items[]` 行字段
导游(guide-fees):
| 字段 | 类型 | 可空 | 说明 |
|------|------|------|------|
| `id` | String(Long) | 是 | 费用行 ID(雪花,字符串);候选未落库行为 `null` |
| `candidateKey` | String | 是 | 候选键;手工补录行为 `null` |
| `staffAssignmentId` | String(Long) | 是 | 人员派单 ID;无关联为 `null` |
| `serviceDate` | String(date) | 否 | 服务日期(单天),格式 `YYYY-MM-DD` |
| `name` | String | 否 | 导游姓名 |
| `serviceType` | String | 否 | 服务类型编码,见 §6.1 |
| `serviceTypeName` | String | 否 | 服务类型名称,如 `全陪导游` |
| `paymentMethod` | String | 否 | 付款方式编码,见 §6.3 |
| `paymentMethodName` | String | 否 | 付款方式名称 |
| `amount` | String(Decimal) | 否 | 金额,字符串格式如 `"295.00"` |
| `settlementConfirmStatus` | String | 否 | 核单确认状态编码,见 §6.4 |
| `settlementConfirmStatusName` | String | 否 | 核单确认状态名称 |
| `remark` | String | 是 | 备注 |
| `sourceType` | String | 否 | 来源编码,见 §6.5 |
| `sourceTypeName` | String | 否 | 来源名称,如 `手工补录` |
| `sourceActive` | Boolean | 否 | 来源是否有效 |
| `voucherUrls` | String[] | 否 | 凭证 URL;无凭证为 `[]` |
| `completionState` | String | 否 | 行完备状态,如 `COMPLETE` |
| `candidateResolution` | String | 否 | 候选处理结果,如 `INCLUDED` |
摄影师(photographer-fees)与导游**同构**,仅两个字段名不同:
| 语义 | 导游字段名 | 摄影师字段名 |
|------|-----------|--------------|
| 姓名 | `name` | `photographerName` |
| 类型编码/名称 | `serviceType` / `serviceTypeName` | `feeType` / `feeTypeName` |
摄影师类型枚举见 §6.2。
## 6. 枚举 / 数据字典
### 6.1 导游 `serviceType`
**所属字段**:guide-fees `items[].serviceType` | **类型**:String
| 值 | 中文 |
|----|------|
| `FULL_COURSE_GUIDE` | 全陪导游 |
| `LOCAL_GUIDE` | 地接导游 |
| `COMMENTARY_SERVICE` | 讲解服务 |
| `TEMPORARY_SUPPLEMENT` | 临时补录 |
### 6.2 摄影师 `feeType`
**所属字段**:photographer-fees `items[].feeType` | **类型**:String
| 值 | 中文 |
|----|------|
| `FOLLOW_SHOOT` | 跟拍 |
| `PORTRAIT` | 写真 |
| `AERIAL_SHOOT` | 航拍 |
| `EDITING_DELIVERY` | 剪辑出片 |
| `CAMERA_DRONE` | 相机/无人机 |
| `OTHER` | 其他 |
### 6.3 `paymentMethod`
**所属字段**:`items[].paymentMethod` | **类型**:String
| 值 | 中文 |
|----|------|
| `COMPANY_PAID` | 公司付款 |
| `CASH_PAID` | 现付 |
### 6.4 `settlementConfirmStatus`
**所属字段**:`items[].settlementConfirmStatus` | **类型**:String
| 值 | 中文 |
|----|------|
| `UNCONFIRMED` | 未确认 |
| `CONFIRMED` | 已确认 |
### 6.5 `sourceType`
**所属字段**:`items[].sourceType` | **类型**:String
| 值 | 中文 | 说明 |
|----|------|------|
| `MANUAL` | 手工补录 | 核单页手工新增的费用行 |
| 其他来源编码 | — | 由派单/候选自动带入,以实际返回为准 |
## 7. 错误码
### 7.1 已删除的族B专属错误码(不再返回)
| code | 原含义 | 变更 |
|------|--------|------|
| `584023` | DRIVER detail 缺 days[] 数组 / 元素缺 service_date 或 daily_fee 字段 | 删除,不再返回 |
| `584024` | GUIDE / PHOTOGRAPHER detail 缺 persons[] / 元素缺 name / days / per_day | 删除,不再返回 |
| `584025` | LEADER detail 缺 days 或 per_day 字段 | 删除,不再返回 |
| `584028` | OTHER detail 缺 items[] / 元素缺 name / amount | 删除,不再返回 |
前端若存在针对这 4 个错误码的分支处理,可一并清理。
### 7.2 本次相关错误码
| code | 含义 | 触发场景 |
|------|------|----------|
| `404` | 请求地址不存在 | 调用任一已删除的族B路由(staff-fees/guides、staff-fees/photographers) |
| `400` | 请求参数错误 | `orderId` 不是正整数;PUT 请求体字段缺失或非法 |
| `403` | 无访问权限 | 登录态或角色无权访问 |
| `581007` | 订单不存在 | `orderId` 对应订单不存在 |
## 8. 示例
### 8.1 典型成功:GET 导游费用(族A)
请求:
```http
GET /v3/admin/order/2085641684778958848/settlement/guide-fees
Authorization: Bearer JWT_TOKEN
```
无请求体。
响应(测试单真实打样):
```json
{
"code": 200,
"message": "成功",
"data": {
"category": "GUIDE",
"sourceFingerprint": "a02c66c6...",
"totalAmount": "590.00",
"cashPaidAmount": "0.00",
"unconfirmedCount": 2,
"pendingCandidateCount": 0,
"settlementReady": false,
"blockReasonCode": "ITEMS_UNCONFIRMED",
"editable": true,
"readOnlyReasonCode": null,
"items": [
{
"id": "2085641684778958849",
"candidateKey": null,
"staffAssignmentId": null,
"serviceDate": "2026-08-10",
"name": "王强",
"serviceType": "FULL_COURSE_GUIDE",
"serviceTypeName": "全陪导游",
"paymentMethod": "COMPANY_PAID",
"paymentMethodName": "公司付款",
"amount": "295.00",
"settlementConfirmStatus": "UNCONFIRMED",
"settlementConfirmStatusName": "未确认",
"remark": "打样导游",
"sourceType": "MANUAL",
"sourceTypeName": "手工补录",
"sourceActive": true,
"voucherUrls": [],
"completionState": "COMPLETE",
"candidateResolution": "INCLUDED"
}
]
},
"success": true
}
```
### 8.2 边界:PUT 全量保存空 items(清空导游费用)
请求:
```http
PUT /v3/admin/order/2085641684778958848/settlement/guide-fees
Authorization: Bearer JWT_TOKEN
Content-Type: application/json
```
```json
{
"expectedSourceFingerprint": "a02c66c6...",
"items": [],
"excludedCandidateKeys": []
}
```
响应:
```json
{
"code": 200,
"message": "成功",
"data": null,
"success": true
}
```
保存后重新 GET 拉取最新 `sourceFingerprint` 再渲染。
### 8.3 业务失败:调用已删除的族B旧路径返回 404
请求:
```http
GET /v3/admin/order/2085641684778958848/settlement/staff-fees/guides
Authorization: Bearer JWT_TOKEN
```
无请求体。
响应:
```json
{
"code": 404,
"message": "请求地址不存在",
"data": null,
"success": false
}
```
PUT `/settlement/staff-fees/guides`、GET/PUT `/settlement/staff-fees/photographers` 行为一致,均为 HTTP 404。
## 9. 业务边界
**适用**:
- 核单页面导游、摄影师页签的查询、保存、确认全部走族 A 扁平接口。
- 一笔费用一行(按人×天扁平铺开),不存在一人多行嵌套。
**不适用**:
- 族 B 的 `persons[]` 嵌套请求体不再有任何承载路径,不得把嵌套 body 改发到族 A(族 A 只接受扁平 `items[]`)。
- 领队、司机、其他人员费用早在 #5380 已删除,本次不涉及。
**特殊边界**:
- PUT 必须携带最新 `expectedSourceFingerprint`;并发编辑或保存后未刷新指纹再保存会被拒绝,需重新 GET。
- `items=[]` 是合法输入,表示清空该类别费用。
## 10. 修改前后对比
### 10.1 接口级对比
| 能力 | 改前 | 改后 |
|------|------|------|
| 导游费用查询 | `GET /settlement/staff-fees/guides`(族B,persons[] 嵌套) | `GET /settlement/guide-fees`(族A,扁平 items[]) |
| 导游费用保存 | `PUT /settlement/staff-fees/guides`(族B) | `PUT /settlement/guide-fees`(族A,带 expectedSourceFingerprint) |
| 摄影师费用查询 | `GET /settlement/staff-fees/photographers`(族B) | `GET /settlement/photographer-fees`(族A) |
| 摄影师费用保存 | `PUT /settlement/staff-fees/photographers`(族B) | `PUT /settlement/photographer-fees`(族A) |
| 族B 4 个路由 | 可用 | **已删除,调用返回 HTTP 404** |
### 10.2 错误码对比
| 错误码 | 改前 | 改后 |
|--------|------|------|
| `584023` / `584024` / `584025` / `584028` | 族B 请求体校验失败时返回 | 不再返回(族B 路由整体删除) |
## 11. 影响评估 / 回滚
### 11.1 影响评估
- **是否破坏向后兼容**:是。族B 共 4 个路由已删除,未切换的前端版本调用固定 404。
- **前端是否必须同步上线**:是。管理后台必须把导游、摄影师页签的查询/保存切换到族 A 路径,并改为扁平 `items[]` 请求体(携带 `expectedSourceFingerprint`)。
- **后端数据**:导游/摄影费用底层存储不变,仅接口承载形态收口;历史数据在族 A 下正常可见。
### 11.2 回滚边界
- 前端版本不得回滚到仍调用 `staff-fees/guides`、`staff-fees/photographers` 的版本,否则对应页签固定 404。
- 后端如需回滚需恢复 4 个路由与 4 个错误码,涉及 PR #5658 整体 revert,由后端评估。
## 12. 注意事项
- 切换目标路径是 `guide-fees` / `photographer-fees`(短横线、无 staff 前缀),不要拼成 `staff-fees/guide-fees` 等混合路径。
- 族A PUT 是全量替换语义:保存时提交整页 `items[]`;只传改动行会丢失未传行。
- 保存成功后必须重新 GET 获取最新 `sourceFingerprint`,否则下次 PUT 指纹不匹配被拒。
- 摄影师行字段是 `photographerName` / `feeType` / `feeTypeName`,与导游的 `name` / `serviceType` / `serviceTypeName` 不同,不要复用同一套字段映射常量。
- `orderId`、行 `id`、`staffAssignmentId` 均按字符串处理;金额字段(`amount` / `totalAmount` / `cashPaidAmount`)为字符串格式 Decimal。
- 清理前端对 `584023` / `584024` / `584025` / `584028` 的错误码分支。
## 13. 关联 / 联系人
### 13.1 链接
- **Issue**: [#5655](https://git.1814.love:8443/wx/HL/issues/5655)
- **PR**: [#5658](https://git.1814.love:8443/wx/HL/pulls/5658)
- **Merge commit**: [7d29484da77e20a706ec611893545c419f6821b2](https://git.1814.love:8443/wx/HL/commit/7d29484da77e20a706ec611893545c419f6821b2)
### 13.2 联系人
- **后端负责人**: @yst(腰苏图)
## 验证证据
- PR #5658 已合并至 `dev-v3`,合并提交 `7d29484da77e20a706ec611893545c419f6821b2`。
- 测试服已部署并行为级验证:族B 4 端点(GET/PUT staff-fees/guides、GET/PUT staff-fees/photographers)均返回 HTTP 404;族A guide-fees / photographer-fees 正常返回业务数据。
## 前端交付(2026-08-08 mmg,hl-admin@ee7a5d58)
族B→族A 切换已上线 v2.1。导游/摄影师页签查询/保存直连族A `guide-fees`/`photographer-fees`,废弃按人嵌套 StaffFeeTable、并入通用 CategoryTable(与住宿/餐食/车辆页签同形态);PUT 携带 `expectedSourceFingerprint` 类别级指纹乐观锁(照车辆 version 模式 GET attach / 保存后 re-GET 写回 / 冲突刷新)。导游 `name`/`serviceType` 与摄影 `photographerName`/`feeType` 分别映射未复用;人员下拉保留仅预填姓名(族A 无 staffId 落点);未接 confirm 端点(确认语义行级随 PUT);候选最小实现 excludedCandidateKeys 恒 []。
**待后端确认**:人员费用指纹冲突的错误码 changelog 未给出,前端按车辆域既有 `584108` 复用做冲突刷新分支;若人员域实际返回别的码,请告之以对齐(不阻塞,缺省时错误照常透传提示,仅无自动刷新)。
@@ -0,0 +1,74 @@
---
schema: "hl-changelog/v2"
ticket: "5656"
title: "派单详情 travelers 补 nativePlace 跨服务透传(#5642 链路补全)"
consumer: "admin"
author: "wx"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "mmg"
frontend_ref: "7e7085b6"
target_release: ""
verified_at: ""
status_note: "后端完成:PR #5661 合并 dev-v3(3ee5770af)并部署 TEST(order-v3+fleet 双服务);网关实测派单详情与 travelers 端点 nativePlace 解析正确(150784→内蒙古呼伦贝尔市等 5 场景)。"
updated_at: "2026-08-08"
base: "dev-v3"
generated: "2026-08-07T18:40:00+08:00"
---
# 派单详情 travelers 补 nativePlace 跨服务透传(#5656)
## 背景
#5642 仅为 order 管理端 `TravelerVO`(traveler/list 等)加了 `nativePlace`;派单详情走跨服务链路(order `GET /v3/internal/order/orders/{orderId}/fleet-detail-context` → fleet `BoardOrderDetailVO.travelers`),该链路 traveler DTO 未带 `nativePlace`,派单页/看板详情展示出行人时缺所属地。本单补全该链路。
## 变更内容
| 层 | 变更 |
|---|---|
| hl-common | `OrderTravelerForFleetDTO` 新增可空 `nativePlace`(身份证所属地,省+地级行政区名;非身份证/未命中为 null) |
| order 生产者 | `OrderFleetProviderService#toMaskedTraveler` 填充(复用 #5642 `IdCardParser` 解析结果,同源 `idProvinceName`) |
| fleet 消费者 | `BoardOrderDetailVO.travelers` / `GET /admin/fleet/board/orders/{id}/travelers` / `FleetTravelerAccessService#listMasked` 均直接复用共享 DTO,无逐字段映射,自动获得字段 |
受影响接口(均为新增只读字段,无破坏性):
- `GET /admin/fleet/board/orders/{orderId}`(派单详情聚合)→ `data.travelers[].nativePlace`
- `GET /admin/fleet/board/orders/{orderId}/travelers` → `data[].nativePlace`
- internal:`GET /v3/internal/order/orders/{orderId}/fleet-detail-context`、`GET /v3/internal/order/orders/{orderId}/fleet-travelers` 的 traveler 投影同步带 `nativePlace`
取值口径与 #5642 一致:大陆身份证命中地级码→省短名+地市名(如 `150784…`→内蒙古呼伦贝尔市);直辖市→市名;省直辖县级(4190/4290/4690/6590)→6 位精确映射;非身份证或未命中(含已撤销历史码)→`null` 不报错。
## 关联 / 联系人
- 工单:https://git.1814.love:8443/wx/HL/issues/5656
- PR:https://git.1814.love:8443/wx/HL/pulls/5661
- 后端:wx
## 变更接口或验证证据
### 接口契约
- 接口路径/方法/请求体:不变。
- 响应 travelers 项新增 `nativePlace`(string | null)。
### 验证证据
- 定向测试:order `OrderFleetProviderServiceTest` 53 全过(含 fleet-detail-context nativePlace 断言);fleet `BoardOrderServiceTest` 87 + `BoardControllerTest` 11 全过(含派单详情 travelers.nativePlace 透传断言)。
- 全量:fleet `mvn -pl hl-fleet-service -am verify` 3256 测试,失败仅 ReleaseEMixedBinaryHarnessTest(1F)+ReleaseEOccupancyMysql8033RecoveryTest(10E) 两个 harness 类,git stash 基线复跑同类同败;order `-pl hl-order-service-v3 -am verify` 7610 测试 7F/95E 失败类集与 #5642 基线逐一相同;fleet spotless:check 通过。
- 部署 TEST 成功(hl-order-service-v3 + hl-fleet-service)。
- 网关验证(自建 HLTEST 订单 2085637067265449985,复用 #5642 五场景出行人):派单详情与 travelers 端点均断言 150784→内蒙古呼伦贝尔市、469001→海南五指山市、110101→北京市、PASSPORT→null、371201(已撤销码)→null;脱敏与省级字段回归通过。
## 前端/调用方动作
- 派单页/看板详情展示出行人所属地时直接使用 `travelers[].nativePlace`;`null` 展示空(如 "-")。
- 与 #5642 traveler/list 口径一致,前端两处共用同一展示逻辑即可。
## 前端核查(2026-08-08 mmg 实查,前端无需新改动)
本单即 #5642 协调台更正中所述「另立后端工单补 fleet-detail-context→BoardOrderDetailVO 链路」的后端补全。前端派单页所属地列早在 #5642(hl-admin@7e7085b6)已接入并透传:
- `src/views/fleet/board/components/Step1OrderDetail.vue` 所属地列渲染 `traveler.nativePlace || traveler.idProvinceName || '—'`。
- 数据链 `loadBoardOrderDetail → normalizeBoardOrder(...row) → buildActiveAssignmentOrder(...order) → travelers map(...traveler)` 全程透传、无白名单丢字段。
- 后端在 `BoardOrderDetailVO.travelers` 补 nativePlace 后,前端列自动取值生效,**前端零改动**。frontend_ref 沿用 #5642 的 7e7085b6(无新提交)。
@@ -0,0 +1,57 @@
---
schema: "hl-changelog/v2"
ticket: "5657"
title: "确认执行不强制派满建议车辆数(按实际槽位校验,建议数仅参考)"
consumer: "admin"
change_type: "修改接口"
author: "wx(GIT)"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "not_required"
frontend_owner: ""
frontend_ref: ""
target_release: ""
verified_at: ""
status_note: "后端完成:PR #5660 已合并 dev-v3 并部署 TEST(18:27 滚动 DONE)。网关验证真实复现工单场景 6 项全 PASS:订单 26-4949(7人/建议2辆)只派 1 辆 7 座 GL8,确认执行 200 confirmed=true(修复前 605041「缺少第2个车辆槽位」×4)。前端无需配合。"
updated_at: "2026-08-07"
base: "dev-v3"
generated: "2026-08-07T18:45:00+08:00"
---
# 确认执行不强制派满建议车辆数(按实际槽位校验,建议数仅参考)
> **服务**: hl-fleet-service
> **PR**: [#5660](https://git.1814.love:8443/wx/HL/pulls/5660)
> **Issue**: [#5657](https://git.1814.love:8443/wx/HL/issues/5657)
> **日期**: 2026-08-07
> **影响**: 🟢 **缺陷修复**,无契约结构变更(`POST /admin/fleet/assignments/:assignmentId/confirm` 行为修复)。前端无需改代码。
## 背景
#5657(P1)wx 实测:订单 26-4949(7 人),系统建议 2 辆车(suggestedVehicleCount=2),车务只派 1 辆(7 座商务车够坐)。确认执行被拦:「该服务日缺少第 2 个车辆槽位派单」(8/13-8/16 四天都报)+「订单与派单基线已变化,请按逐日差异处理后重试」(605041)。
**口径(wx)**:车务说的算——车务想派几辆就派几辆,建议车辆数仅作参考,不强制派满。
**根因**:最终确认基线校验(assertFinalConfirmationBaseline)按需求展开的**期望槽位数**逐槽逐日要求派单覆盖,未派定的槽位也强制要求补齐。
## 修复内容(内部,无接口/字段结构变化)
- 确认执行基线校验改为按**实际槽位**校验:未派定的槽位跳过「缺少第 N 个槽位」强制拦截(建议车辆数仅参考);
- **已派定槽位**的服务日完整性校验保留(防止半派状态确认);
- 座位/车型相关提示与校验逻辑不变(座位数校验保留)。
## 变更接口
| 方法 | 路径 | 来源 |
|---|---|---|
| POST | /admin/fleet/assignments/:assignmentId/confirm | 确认执行:未派满建议数不再 605041,已派槽位缺服务日仍拦截 |
## 验证证据
- 全量 `mvn -pl hl-fleet-service -am verify`:3258 Tests,Failures=0,Errors=0;新增 2 例回归(建议两辆仅派一辆全程行可确认——已回退验证修复前确实被拦;已派槽位缺服务日仍拦截);spotless 通过。
- 部署 TEST:18:27 滚动 DONE。
- 网关真实复现(订单 26-4949,蒙A-G8888 GL8 7 座对 7 人,8/13-8/16)6 项全 PASS:删除多余槽位恢复只派 1 辆现场 → 登记司机确认 → 确认执行 200 confirmed=true → DB 终态 4 行 assigned + confirmed_at 非空、无其他活跃槽位。
## 前端配合
无需配合。确认执行按车务实际派车数通过,建议车辆数仍作为参考展示。
@@ -0,0 +1,44 @@
---
schema: "hl-changelog/v2"
ticket: "5662"
title: "改派页面缺「选择司机」按钮(无法改派司机)"
consumer: "admin"
author: "wx"
change_type: "前端修复"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "mmg"
frontend_ref: "c63ce28f"
target_release: ""
verified_at: ""
status_note: ""
updated_at: "2026-08-08"
base: "origin/dev-v3"
generated: "2026-08-07"
---
# 改派页面缺「选择司机」按钮(前端修复)
## 问题(wx 实测)
派单【改派】页面:显示"当前司机 xxx / 当前车辆 xxx"+"车辆和司机可任选一侧先选",但**只有选车入口,没有「选择司机」按钮**——无法改派司机。
## 后端已就绪(前端直接用)
改派接口 `POST /admin/fleet/assignments/{assignmentId}/change` 的 ReqVO **已支持 `newDriverId`**(改司机)——后端能力在,前端缺入口。
## 前端要做
**口径(wx):改派与初次派车交互一致——车辆和司机「可任选一侧先选」**。改派弹窗/页面**加「选择司机」按钮**(与选车并列,两侧都能先选,同初次派车):
- 改派页「选择车辆」「选择司机」两个入口并列,**先选哪侧都行**(复用初次派车的统一选择车辆/司机组件,按当前派单日期/需求过滤空闲车辆+司机)
- 选定司机 → 调 change 接口传 `newDriverId` 完成改派司机
- 改派司机的校验(档期冲突/黑名单/跨常驻确认/保险)与改派车一致(后端 change 已处理)
## 验收
- [ ] 改派页有【选择司机】按钮,可选新司机
- [ ] 选定后调 change 传 newDriverId,改派司机生效
- [ ] 改派司机校验(冲突/跨常驻/保险)正常提示
## 关联
- 后端 change 接口:`POST /admin/fleet/assignments/{assignmentId}/change`(ReqVO 含 newDriverId/newVehicleId)
## 联系人
- 后端/协调台:wx
@@ -0,0 +1,64 @@
---
schema: "hl-changelog/v2"
ticket: "5663"
title: "fleet 英文/技术黑话提示统一改中文友好(确认弹窗差异中文名称与文案)"
consumer: "admin"
author: "wx"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "mmg"
frontend_ref: "9784e7aa"
target_release: ""
verified_at: "2026-08-07"
status_note: "后端完成:PR #5672 已合并 dev-v3(2f6b043dd)并部署 TEST(hl-fleet-service 双实例 UP)。确认/创建/改派弹窗逐日差异新增 differenceLabel 中文名称,message 全部改中文友好(动作+原因+怎么办);600211 去配置 key 名、600112 去 busy 英文;内部异常消息(含保险 long 溢出)转中文。网关验证 8/8:605041 差异返回 label=服务日期缺少派车、message=该日期缺少有效的派车安排,请补派后重试,无英文码名透出,differenceType 枚举保留。"
updated_at: "2026-08-08"
base: "dev-v3"
generated: "2026-08-07T21:38:00+08:00"
---
# fleet 英文/技术黑话提示统一改中文友好(#5663)
## 背景
派车页确认执行弹窗透出英文错误码(如 `DAILY_VEHICLE_PLAN_BASELINE_MISMATCH 逐日逐车方案、价格或只读状态已发生变化`),用户看不懂。全面排查 fleet 车务域英文/技术黑话提示,统一中文友好(动作 + 原因 + 怎么办)。
## 方案
1. **确认/创建/改派弹窗逐日差异**:`ConfirmRespVO.DailyDifferenceVO`(及 AssignmentWriteRespVO/ChangeAssignmentRespVO 的 dailyDifferences)新增 **`differenceLabel` 中文名称字段**;差异 `message` 全部改为「动作 + 原因 + 怎么办」中文,去除「切片 / 冻结 / 快照 / 槽位」等黑话。
2. **错误码文案**:600211 去掉 Nacos 配置 key 名透出;600112 去掉 `(busy)` 英文。
3. **内部异常消息**:快照工厂 / 加密 / occupancy 等英文异常消息转中文(日志与兜底透出均友好)。
## 变更接口
| 接口 | 变更 |
| --- | --- |
| POST /admin/fleet/assignments(holdMode=0) | 605041 响应 `data.dailyDifferences[].differenceLabel` 新增(中文名称);message 文案更新 |
| POST /admin/fleet/assignments/batch | 同上 |
| POST /admin/fleet/assignments/确认执行 | 同上 |
| POST /admin/fleet/assignments/改派(holdMode=0) | 同上 |
| 全部 fleet 管理接口 | 600211/600112 message 文案更新(无字段变更) |
## 行为变化
- `differenceType` 英文枚举 **保留不变**(供前端逻辑判断),新增 `differenceLabel` 中文名称与 `message` 用于用户展示。
- `differenceLabel` 枚举与中文名称映射:
- REQUIREMENT_VERSION_MISMATCH → 用车需求已更新
- ORDER_DATE_MISMATCH → 订单日期已调整
- ITINERARY_DATE_MISMATCH → 行程日期不一致
- ASSIGNMENT_DATE_MISSING → 服务日期缺少派车
- ASSIGNMENT_DATE_EXTRA → 服务日期多出派车
- HEADCOUNT_BASELINE_MISMATCH → 乘车人数不一致
- CAPACITY_INSUFFICIENT → 座位数不足
## 前端动作
- **确认/创建/改派失败弹窗**:差异列表展示优先使用 `differenceLabel`(中文名称)+ `message`(动作+原因+怎么办),不要再拼接展示英文 `differenceType` 码名;现有按 `differenceType` 做逻辑判断的分支可保持不变。
- 如前端有硬编码的英文码名映射(如 DAILY_VEHICLE_PLAN_BASELINE_MISMATCH),请同步删除或改为按 `differenceLabel` 展示。
## 验证证据
- fleet 全量 verify:3261 tests,0 failures,4 skipped;spotless:check 通过(PR #5672)。
- 网关实测(TEST):create(holdMode=0) 基线不一致 → code=605041,`dailyDifferences[].differenceLabel="服务日期缺少派车"`、`message="该日期缺少有效的派车安排,请补派后重试"`,无英文码名透出,`differenceType=ASSIGNMENT_DATE_MISSING` 保留。8/8 断言通过。
- 部署:hl-fleet-service dev-v3=2f6b043dd 双实例 UP。
@@ -0,0 +1,77 @@
---
schema: "hl-changelog/v2"
ticket: "5664"
title: "派单多司机时微信预览按司机分 tab(新增批量渲染端点)"
consumer: "admin"
author: "wx"
change_type: "新增接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "mmg"
frontend_ref: "91530f73"
target_release: ""
verified_at: ""
status_note: "后端完成:PR #5668 合并 dev-v3(d4ebd435be62cbe377ba712e8f0aed2b41e75a56)并部署 TEST,网关验证双槽位分司机渲染+单项容错+单渲染回归全通过。待前端预览区接入 render-batch 按司机分 tab。"
updated_at: "2026-08-08"
base: "dev-v3"
generated: "2026-08-07T18:45:00+08:00"
---
# 派单多司机时微信预览按司机分 tab(#5664)
## 需求
派单选了多个司机(多槽位)时,微信消息预览按司机分 tab 切换——每个司机一个预览(车辆/行程/链接),分别查看+发送。实证:26-6318 派 2 司机(孙晓三、斯琴)预览只有 1 个。
## 根因
预览端点 `POST /admin/fleet/message-templates/{templateId}/render` 请求 VO 只接受**单个** driverId/vehicleId,多槽位只返回 1 个预览。
## 新增接口
### `POST /admin/fleet/message-templates/{templateId}/render-batch`
批量渲染同一模板,多槽位按司机返回预览列表。
**请求**:
```json
{
"items": [
{"orderId": 123, "vehicleId": 456, "driverId": 789, "assignmentGroupId": null,
"serviceDates": null, "chargeableServiceDates": null, "vehicleFeeWaiverReason": null},
{"orderId": 123, "vehicleId": 457, "driverId": 790}
]
}
```
- `items`:1~20 项,每项 = 单槽位预览入参(字段同单渲染 render 端点)。
- 1 项时等价单渲染(单司机场景不变,前端可继续用 render 或 render-batch 单项)。
**响应**:
```json
{
"items": [
{"index": 0, "driverId": 789, "vehicleId": 456, "assignmentGroupId": null,
"success": true,
"renderedBody": "师傅您好,HL20260807... 车辆 蒙A-G8888 别克GL8 ...",
"variablesUsed": ["driver.name", "vehicle.plate", "..."],
"errorCode": null, "errorMessage": null},
{"index": 1, "driverId": 790, "vehicleId": 457, "success": true, "renderedBody": "...车辆 蒙A-H7777 丰田汉兰达..."}
]
}
```
- `items` 与请求同序;每项独立 `success`。
- 单项渲染抛业务异常 → 该项 `success=false` + `errorCode`/`errorMessage`,**不阻断其他槽位**;单项司机/车辆取数异常沿用单渲染容错兜空口径(字段空串、仍 success=true)。
- 模板不存在 → 整批 **600801**(与单渲染一致);白名单外占位符 **600800**。
## 前端交接
1. **多槽位/多司机预览**:预览区对每槽位构造一个 item(该槽位 driverId/vehicleId/assignmentGroupId/serviceDates 等),调 `render-batch` 一次取回全部预览,按司机/槽位分 **tab** 展示各项 `renderedBody`。
2. **发送**:按选中 tab(司机)取对应 `renderedBody` 发送;单项 `success=false` 的 tab 展示 `errorMessage` 并禁用发送。
3. **单司机**:1 项即可(无 tab 或单 tab),行为与现状不变;现有 `render` 端点保留兼容(本单未改)。
4. tab 标签建议用司机姓名/车牌(renderedBody 内含,或前端用槽位上下文)。
## 验证
- MessageTemplateRenderServiceTest **20/20**(新增 4:多司机各自渲染/模板不存在 600801/单项取数异常兜空不阻断/单项业务异常 success=false 不阻断);dev-v3 全量 verify 3265/0F/0E。
- 网关实证(TEST,change_notify 模板):双槽位 render-batch → 2 预览各自车辆正确渲染(蒙A-G8888 别克GL8 / 蒙A-H7777 丰田汉兰达);单项不存在车辆槽位兜空不阻断;单渲染 render 回归正常。
@@ -0,0 +1,100 @@
---
schema: "hl-changelog/v2"
ticket: "5665"
title: "改派时支持增加/删除槽位(调整车辆数量)"
consumer: "admin"
author: "wx(GIT)"
change_type: "新增接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "mmg"
frontend_ref: "f1c00ba8"
target_release: ""
verified_at: ""
status_note: "后端完成:PR #5669 已合并 dev-v3 并部署 TEST(hl-fleet-service 双实例)。新增 POST /admin/fleet/assignments/slots 增槽位;删除槽位复用既有 DELETE /slots/{slotId}。前端需在改派页加【增加槽位】【删除槽位】操作并编排现有接口(见前端交接)。"
updated_at: "2026-08-08"
base: "dev-v3"
generated: "2026-08-07T20:26:00+08:00"
---
# 改派时支持增加/删除槽位(调整车辆数量)
> 后端完成:PR #5669 已合并 dev-v3 并部署 TEST,网关验证通过。**前端需在改派页增加【增加槽位】【删除槽位】操作**。
## 关联 / 联系人
### 链接
- **Issue**: [#5665](https://git.1814.love:8443/wx/HL/issues/5665)
- **PR**: [#5669](https://git.1814.love:8443/wx/HL/pulls/5669)
- **Merge commit**: [c3f0f8fac](https://git.1814.love:8443/wx/HL/commit/c3f0f8fac)
### 联系人
- **后端负责人**: @wx
## 背景
改派(change)原本只能换车/换司机(同槽位内换),不能增加/删除槽位(调整车辆数量)。wx 要改派时可增删槽位。对齐 #5562 槽位模型(派车时可增删)。按协调台口径走 A 方案:复用 expand/slots 机制,**只增删差异、保留已派**,不新建独立重派流程、不侵入 change 主流程。
## 变更接口
### 新增:`POST /admin/fleet/assignments/slots`(增加槽位)
在 active 用车需求上新增 1 个全程槽位(unassigned 全程占位行覆盖整个服务期),新槽位待确认按初次派车。**保留已有槽位(含已派)完全不动**。
**请求**(`SlotAddReqVO`):
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| requirementId | Long | 是 | 归属需求 ID(active 用车需求) |
| vehicleType | String | 是 | 新槽位车型(如 suv/mpv) |
| seats | Integer | 是 | 新槽位座位需求(1-60) |
| reason | String | 否 | 新增原因(≤200 字,操作日志留痕) |
**响应**(`SlotAddRespVO`):
| 字段 | 类型 | 说明 |
|------|------|------|
| slotId | Long(字符串) | 新槽位 ID(assignmentSlotId) |
| assignmentId | Long(字符串) | 新槽位全程占位行派单 ID |
| requirementId | Long(字符串) | 归属需求 ID |
| orderId | Long(字符串) | 归属订单 ID |
| fleetItemIndex | Integer | 新槽位需求内项次序 |
| retainedSlotIds | Long[](字符串) | 新增后 Step2 快照保留槽位集合 |
| snapshotVersion | Long(字符串) | 新增后快照版本(无快照时 null) |
**错误码**:400 参数校验失败(需求 ID/车型/座位数缺失)/ **605012** 需求无派单行 / **605007** 需求不可派(非 active/已取消/不可派)/ 605008 抢锁超时 / 401 未登录 / 403 非车务角色。
**行为**:
- 新槽位生成 1 条 unassigned 全程占位行(`service_date`/`assignment_group_id` 为 NULL,`start_date~end_date` 覆盖整个服务期),车务在该槽派 1 辆管全程的车(候选/价格日历/校验同初次派车 create)
- 保留已有槽位(含 holding/assigned 已派)完全不动——只增差异槽位,不重置/重派
- **确认状态**:清最终确认标记(改派需重新冻结方案);保留槽位确认状态不变
- Step2 快照 retained 追加 + 版本递增 + digest 重算;FleetBoardChangedEvent + 操作日志 SLOT_ADDED
### 复用:`DELETE /admin/fleet/assignments/slots/{slotId}`(删除槽位,零改动)
既有端点(#5550/#5572),删除已派(holding/assigned)槽位时联动取消派单(释放占用+退保意图+取消事件),行程已出发拒绝(605027)。
## 前端交接(改派页)
在改派页增加两个操作,**编排现有接口**(后端已就绪):
1. **【增加槽位】**(多派一辆):
- 调 `POST /admin/fleet/assignments/slots`(传 requirementId + vehicleType + seats + reason)
- 成功后新槽位出现在看板/改派页,车务对新槽位按初次派车(候选/价格/校验)派 1 辆车
2. **【删除槽位】**(少派一辆):
- 调既有 `DELETE /admin/fleet/assignments/slots/{slotId}`(有派单时后端联动取消)
- 行程已出发的槽位不可删(605027);已完成的槽位不可删(605007)
3. **换车/换司机**:仍调既有 `POST /{assignmentId}/change`(不变)
**展示/交互提示**:增删槽位后改派方案需重新冻结(后端已清最终确认标记);保留槽位的确认状态/车辆/司机不变。座位数校验在派车 create 时进行(座位不足进 warnings)。
## 验证证据
- 新增 3 用例:增槽位成功生成全程行+保留已派+Step2 追加 / 需求无派单行 605012 / 需求不可派抛错
- AssignmentServiceTest **394/394 全绿**;fleet spotless:check 通过
- fleet verify(mvn-throttle 错峰):3251 测试仅 `ReleaseEOccupancyMysql8033RecoveryTest`(需 MySQL 8.0.33 环境)基线失败,与本案无关
- **部署**:hl-fleet-service 双实例 UP(20:24)
- **网关验证**:VEHICLE_MANAGER 调 `POST /admin/fleet/assignments/slots`:缺 requirementId → 400(参数校验生效);不存在需求 → 605012(业务校验生效);端点部署成功
@@ -0,0 +1,57 @@
---
schema: "hl-changelog/v2"
ticket: "5666"
title: "candidates 收费日注释对齐行为(空数组=全部收费预览)+ 子集收费回显口径锁定"
consumer: "admin"
author: "wx"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "not_required"
frontend_owner: ""
frontend_ref: ""
target_release: ""
verified_at: ""
status_note: "文档/口径对齐,无行为变更:#5643 起空数组已按全部收费预览,本次仅修正 ApiModelProperty 注释并补子集收费回显测试。矩阵派车司机回填与 ¥0 两症状经排查为前端问题,由协调台另行前端 changelog 分流。"
updated_at: "2026-08-08"
base: "dev-v3"
generated: "2026-08-07T21:00:00+08:00"
---
# candidates 收费日口径对齐(#5666 后端小加固)
## 背景
排查 #5666(矩阵派车司机回填/¥0)时发现 `POST /admin/fleet/assignments/candidates` 的 `chargeableServiceDates` 注释("空数组表示全部免费")与实际行为不一致:#5643 起空数组刻意按"全部服务日收费"预览(防止全免 ¥0 陷阱),且已有测试锁定。注释为 #5643 前残留。
## 变更内容
| 项 | 变更 |
|---|---|
| `AssignmentCandidateReqVO.chargeableServiceDates` 注释 | 对齐行为:不传或空数组均按全部服务日收费预览;明确与创建派单接口语义差异(创建接口空数组=全部免费且需 confirmAllServiceDatesFree+免费原因);子集时仅子集收费、其余免费回显 |
| 测试 | 新增 `query_subsetChargeableServiceDates_marksOtherDaysFree`:锁定"子集收费日→仅子集 CALENDAR、其余 FREE ¥0、总价仅含子集"回显口径 |
**无任何运行时行为变更**(纯文档注解 + 测试)。
## 前端/调用方注意(既有行为复述,非新变更)
- candidates:`chargeableServiceDates` 不传/空数组 = 全部收费预览;传子集 = 仅子集收费,其余日 `assignmentPrice=0.00`/`source=FREE`(免费日 `calendarPrice=null`,`calendarPriceMissing` 仅收费日缺价时为 true)。
- 创建/改派写接口语义不变:空数组 = 全部免费,须 `confirmAllServiceDatesFree=true` + 免费原因。
- 矩阵派车司机回填(suggestedDriverId 消费)与部分收费日传入两个症状的修复见协调台前端 changelog。
## 关联 / 联系人
- 工单:https://git.1814.love:8443/wx/HL/issues/5666
- 后端:wx
## 变更接口或验证证据
### 接口契约
- `POST /admin/fleet/assignments/candidates` 请求字段 `chargeableServiceDates`:仅 Swagger 文档注释对齐既有行为,类型/约束/行为均无变更。
### 验证证据
- 定向:`AssignmentCandidateServiceTest` 49 全过(含新增子集收费用例与 #5643 空数组用例);fleet spotless:check 通过。
- 全量:`mvn -pl hl-fleet-service -am verify`(日志见证据目录)。
- 网关:口径探针复测 candidates 空数组=全收费、子集=[首日]=首日 CALENDAR 其余 FREE(与锁定口径一致)。
@@ -0,0 +1,57 @@
---
schema: "hl-changelog/v2"
ticket: "5666"
title: "矩阵派车:司机未回填 + 部分日期派车价¥0(前端两问题)"
consumer: "admin"
author: "wx"
change_type: "前端修复"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "not_required"
frontend_owner: ""
frontend_ref: ""
target_release: ""
verified_at: ""
status_note: ""
updated_at: "2026-08-08"
base: "origin/dev-v3"
generated: "2026-08-07"
---
# 矩阵派车:司机未回填 + 部分日期派车价¥0(前端修复)
后端契约已实测**全部正常**(#5666 后端侧分流确认),两个症状均为前端问题。
## 问题1:矩阵派车选车辆后常驻司机没回填
- **现象**:矩阵派单从车辆日格(如蒙A-T7777)发起,车辆回填了,但司机栏"待选择"(常驻司机没带出)。
- **后端正常**:`candidates` 对该车正确返回 `suggestedDriverId`(常驻司机)+ `RESIDENT_AVAILABLE`,一二轮一致。
- **前端根因**:前端自动代入常驻司机**仅在 `vehicleSuggestionIntent` 武装时消费**;矩阵 `openAssign(order,{vehicle})` 非 batchMode + activeDailyPlanCell 分支时不武装该 intent(AssignModal.vue else 分支直接 `selVehicle=preselectVehicle`),导致 `suggestedDriverId` **无人消费** → 司机栏空。
- **前端修**:矩阵派车场景也要消费 `suggestedDriverId` 回填常驻司机(常驻司机 RESIDENT_AVAILABLE 时自动带出;被拉黑/不可用时提示并留空)。
## 问题2:部分日期派车价 ¥0
- **现象**:矩阵派车 8/21=¥1000 但 8/22-23=¥0。
- **后端正常**:该车型日历价 8/15-31 全量 ¥1000(已配)。
- **前端根因**:前端矩阵场景 `chargeableServiceDates` 只传了 [8/21](部分收费日)→ 8/21 收费 1000、8/22-23 按 FREE(0)。
- **前端修**:矩阵派车收费日应传全服务日(或按需求),不要只传部分导致其余日期 FREE=¥0。
## 验收
- [ ] 矩阵派车选车辆后常驻司机自动回填(suggestedDriverId 被消费)
- [ ] 派车价各服务日正确(不部分¥0)
- [ ] 后端契约不变(仅前端修)
## 关联
- 后端工单 #5666(后端契约正常,另做 candidates 空数组口径小加固)
- 接口 `POST /admin/fleet/assignments/candidates`(返回 suggestedDriverId/RESIDENT_AVAILABLE)
## 前端核查(2026-08-08 mmg 实查,HEAD 已无活代码路径,前端零改动)
逐行核实当前 HEAD(v2.1),两个症状的根因对应的是旧版单派流程,现已由更早提交消除,**前端无需改动**:
**问题1(矩阵司机未回填)**:矩阵 `openAssign(order,{vehicle})` 活路径走 `AssignModal.vue` `batchMode && activeDailyPlanCell` 分支(3109-3125),`isInitialVehiclePreselection` 命中时经 `restoreSelection({autoSelectResidentDriver:true})` 武装 intent;`useVehicleDriverPicker.js:726` `if (autoSelectResidentDriver===true && selVehicle && !selDriver)` 消费 `suggestedDriverId`(RESIDENT_AVAILABLE 自动带出、不可用/黑名单留空并显 suggestedDriverMessage)。changelog 所述「else 分支直接 selVehicle=preselectVehicle」对矩阵场景不可达。既有修复提交 c6b107b8(8/5)/d97cc730(8/6) 早于本 changelog。已有测试锁定(useVehicleDriverPicker.spec 消费/NONE/占用/拉黑用例)。另:#5662 修复后矩阵发起的改派在抽屉内选车同样经 onPickVehicle 武装 intent 回填常驻司机。
**问题2(部分日期派车价¥0)**:batch 矩阵流程**不向 candidates 传 chargeableServiceDates**(`useVehicleDriverPicker.js:432-438` batchMode 守卫 + init watcher 在 batch 置空该 ref),后端按全部服务日收费预览,不会产生「子集收费、其余 FREE=¥0」。唯一仍携带部分收费日的是旧改派流程 `restoreLegacyVehicleFeeState`(从原派车快照恢复,保留原派车收费决策的既有语义),不在本单「矩阵派车」口径内,擅自改会改变账单。
**结论**:前端在 HEAD 已无这两个症状的活代码路径,判 not_required。若仍复现,请提供 HEAD 上的操作序列再排查。
## 联系人
- 后端/协调台:wx
@@ -0,0 +1,55 @@
---
schema: "hl-changelog/v2"
ticket: "5667"
title: "矩阵派车未派订单清单补 requirementId 关联(修复批量派单缺需求 ID 拦截)"
consumer: "admin"
change_type: "修改接口"
author: "wx(GIT)"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "not_required"
frontend_owner: ""
frontend_ref: ""
target_release: ""
verified_at: ""
status_note: "后端完成:PR #5671 已合并 dev-v3 并部署 TEST(21:03 滚动 DONE)。网关验证 5 项全 PASS:矩阵 unassigned-orders 响应补返 requirementId,订单 26-6179 池/看板详情/order 库三方一致,用池内 requirementId 端到端提交批量派单 200 成功。前端无需配合(选择器本就读取该字段,此前响应缺失导致拿不到)。"
updated_at: "2026-08-07"
base: "dev-v3"
generated: "2026-08-07T21:10:00+08:00"
---
# 矩阵派车未派订单清单补 requirementId 关联(修复批量派单缺需求 ID 拦截)
> **服务**: hl-fleet-service
> **PR**: [#5671](https://git.1814.love:8443/wx/HL/pulls/5671)
> **Issue**: [#5667](https://git.1814.love:8443/wx/HL/issues/5667)
> **日期**: 2026-08-07
> **影响**: 🟢 **缺陷修复**,响应**新增字段**(additive,无破坏性变更)。前端无需改代码。
## 背景
#5667(P1)wx 实测:矩阵派单(订单 26-6179 林晓芸 8/21-8/23),从矩阵车辆蒙A-T7777日格发起→选好司机(乌云毕力格)→提交批量派单时报「缺少当前用车需求 ID,无法提交批量派单」,卡住无法派单。
**根因**:矩阵未派订单清单接口(`GET /admin/fleet/matrix/unassigned-orders`)响应未携带 requirementId;前端日格选择器把缺失字段归一成空串,与订单详情合并时空值覆盖了详情返回的有效 requirementId,批量派单提交前的前端校验拿不到需求 ID 被拦。
## 修复内容
- `GET /admin/fleet/matrix/unassigned-orders` 响应每行**新增 `requirementId` 字段**(字符串序列化):
- 口径与看板一致——优先订单侧当前生效用车需求 ID,订单上下文缺失时兜底派单行快照 requirement_id;
- 矩阵日格/未派池发起的批量派单可正确携带当前需求 ID 提交(`POST /admin/fleet/assignments/batch` 本就把 requirementId 作必填,无需改动)。
## 变更接口
| 方法 | 路径 | 变更 |
|---|---|---|
| GET | /admin/fleet/matrix/unassigned-orders | 响应每行新增 requirementId(当前生效用车需求 ID) |
## 验证证据
- 全量 `mvn -pl hl-fleet-service -am verify`:3262 Tests 业务断言全绿;MatrixServiceTest 65/65(+2 回归:无上下文时兜底派单行快照 requirementId、订单上下文当前需求优先);MatrixControllerTest 4/4;FleetRedLineArchTest 12/12;spotless 通过。ReleaseEMixedBinaryHarnessTest(进程 harness 时序)与 ReconciliationInsuranceCostFenceMysqlTest(Testcontainers 3306 端口被并行会话占用)全量内环境性失败,单独重跑 23/23、2/2 全绿,与本改动无关。
- 部署 TEST:21:03 滚动 DONE。
- 网关真实复现(订单 26-6179,蒙A-T7777 + 乌云毕力格,8/21-8/23)5 项全 PASS:未派池行携带 requirementId=2085662146464530434(修复前无此字段);全池无缺失;池/看板详情/order 库三方一致;用池内 requirementId 提交批量派单(dailyPlan 逐日、跨常驻确认)200 成功;DB 终态全程单行 holding 覆盖 8/21-23 且 requirement_id 关联正确。
## 前端配合
无需配合。矩阵日格发起与未派池拖拽发起的选择器本就读取行 requirementId 并随批量派单提交;后端补齐字段后原链路自然恢复,无新增消费逻辑。
@@ -0,0 +1,37 @@
---
schema: "hl-changelog/v2"
ticket: "5592"
title: "「发送派单通知」按钮改名「下一步」(避免"系统真发送"歧义)"
consumer: "admin"
author: "wx"
change_type: "前端修复"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "mmg"
frontend_ref: "dcb5f128"
target_release: ""
verified_at: ""
status_note: ""
updated_at: "2026-08-08"
base: "origin/dev-v3"
generated: "2026-08-08"
---
# 「发送派单通知」按钮改名「下一步」(前端修复)
## 口径(wx)
派单通知是**车务复制话术后微信手动发给司机**(系统不真发送)——保留现设计。
但前端按钮「发送派单通知」**有歧义**(让人以为系统会真发给司机),改名避免误解。
## 前端改动
派单待确认页的「发送派单通知」按钮 → 改名 **「下一步」**(它实际是"生成/复制话术→进入下一步登记司机回复",不是系统真发送)。
- 文案对齐:该页面是"复制话术→微信发给司机→登记司机回复"流程,按钮不应叫"发送"
- 相关提示文案同步(如"确认通知正文后发送给司机"→"确认通知正文后进入下一步")
## 验收
- [ ] 按钮显示「下一步」(不再叫"发送派单通知")
- [ ] 流程提示清晰(复制话术手动发,不产生"系统真发送"误解)
## 联系人
- 后端/协调台:wx
@@ -0,0 +1,54 @@
---
schema: "hl-changelog/v2"
ticket: "5666"
title: "矩阵派车可派订单列表信息补全(展示太简→补全)"
consumer: "admin"
author: "wx"
change_type: "前端优化"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "mmg"
frontend_ref: "45cf94a1"
target_release: ""
verified_at: ""
status_note: ""
updated_at: "2026-08-08"
base: "origin/dev-v3"
generated: "2026-08-08"
---
# 矩阵派车可派订单列表信息补全(前端优化)
## 问题(wx 实测)
矩阵派单「选择当前矩阵可派订单」的**可派订单 list 每条显示信息太少**——基本只有团号+日期+人数,车务在矩阵里挑单派车时参考信息不足,来回点详情才看清。
## 期望(前端补全展示)
矩阵派车的可派订单列表,每条订单卡片**补全显示**(一眼看全,不用点详情):
- 团号 + 客户名
- 出行日期区间 + 天数
- 人数(成人/儿童细分)
- **建议车型 + 座位数**(如 商务车×2·7座)
- **定制师**
- **接送机**(接机/送机机场,如 海拉尔东山机场)
- **特殊要求标签**(有 WiFi/儿童座椅等)
- 急/加急标记、待派/排车中状态
## 说明
- 数据这些字段后端看板/详情接口已有,前端在矩阵可派订单列表透出即可
- 目标是车务在矩阵里挑单派车时不点详情也能判断派哪辆
## 验收
- [ ] 矩阵可派订单列表每条显示:团号/客户/日期/人数/建议车型座位/定制师/接送机/特殊要求/状态
- [ ] 不点详情即可判断派车
## 关联
- #5666(矩阵派车司机回填+收费日)
## 前端交付说明(hl-admin@45cf94a1)
可派订单卡片已补全:天数、建议车型(看板 `requiredVehicles` 分组带辆数座位,矩阵回退车型大类)、定制师、接送机(海拉尔布尔/机场原文)、特殊要求标签、人数成人/儿童细分。顺带修复急单判定死代码(旧逻辑只认 `urgent`,真实值 `unassigned_urgent` 永不命中,改按 `includes('urgent')`,加急文案与 VehicleGantt 同契约)。
**待后端补字段(矩阵未派清单 VO `GET /admin/fleet/matrix/unassigned-orders`)**:该接口当前缺 `days`、`adultCount/childCount` 细分、`requiredVehicles[].seats`、`consultantName`、`pickupAt/dropoffAt` 机场文案、`specialTags`。前端按「有哪个透哪个、缺失行整体不渲染」处理,未硬编;这些字段在**看板自拉路径**(`/fleet/board/orders`,drivers/vehicles 页入口)已完整展示。若矩阵场景也需全量,建议后端参照 60_4936 grid assignments 口径给 `MatrixUnassignedOrderVO` 补上述字段。
## 联系人
- 后端/协调台:wx
@@ -0,0 +1,236 @@
---
schema: "hl-changelog/v2"
ticket: "5674"
title: "核单导游/摄影费用 4 接口请求解析失败错误码 584125 细化为 584128 并透出具体字段原因"
consumer: "admin"
change_type: "修改接口"
author: "yaosutu(GIT)"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "not_required"
frontend_owner: ""
frontend_ref: ""
target_release: ""
verified_at: ""
status_note: "PR #5677 已合并 dev-v3;请求体解析失败/Bean 校验失败错误码由 584125 细化为 584128,message 透出具体字段原因;请求体为空仍返回 584125 不变。成功路径入参/出参字段不变。"
updated_at: "2026-08-08"
base: "dev-v3"
---
# 【⚠️ 修改接口·管理后台】核单导游/摄影费用解析失败错误码细化为 584128 并透出字段原因(#5674)
> **PR**: [#5677](https://git.1814.love:8443/wx/HL/pulls/5677) | **服务**: hl-order-service-v3 | **更新时间**: 2026-08-08
## 1. 接口背景
核单「导游费用」「摄影费用」两个页签共 4 个写接口,此前在请求体 JSON 解析失败或 Bean 校验失败时统一返回 `584125 导游或摄影费用请求字段不合法`,message 不带具体字段原因,前端和核单人员无法自助定位是哪个字段不合法。本次将解析/校验失败细化为新错误码 `584128`,message 透出具体字段路径与原因;成功路径的入参/出参字段、枚举值、行为全部不变。
## 2. 变更清单
| # | 接口 | 方法 | 路径 | 变更类型 | 前端动作 |
|---|---|---|---|---|---|
| 1 | 保存导游费用 | PUT | `/v3/admin/order/{orderId}/settlement/guide-fees` | 错误码语义修改 | 若对 `584125` 做过特判需知悉;建议直接展示后端 message |
| 2 | 确认导游费用 | PUT | `/v3/admin/order/{orderId}/settlement/guide-fees/confirm` | 错误码语义修改 | 同上 |
| 3 | 保存摄影费用 | PUT | `/v3/admin/order/{orderId}/settlement/photographer-fees` | 错误码语义修改 | 同上 |
| 4 | 确认摄影费用 | PUT | `/v3/admin/order/{orderId}/settlement/photographer-fees/confirm` | 错误码语义修改 | 同上 |
> 成功路径的请求体字段、响应结构、状态码 200 行为均未变化,不属于本次契约变更范围。
## 3. 接口详情
4 个接口的协议层约定一致,统一说明:
- **使用场景**:核单人员在订单核单页维护/确认导游费用、摄影费用明细。
- **认证**:需要管理后台登录态(Bearer Token)。
- **幂等性**:保存类接口按订单维度覆盖式保存,重复提交相同载荷结果一致;确认接口带 `expectedSourceFingerprint` 乐观校验,重放安全。
- **限流**:未声明接口专属限流。
- **方法/路径**:
- `PUT /v3/admin/order/{orderId}/settlement/guide-fees`
- `PUT /v3/admin/order/{orderId}/settlement/guide-fees/confirm`
- `PUT /v3/admin/order/{orderId}/settlement/photographer-fees`
- `PUT /v3/admin/order/{orderId}/settlement/photographer-fees/confirm`
## 4. 接口入参
成功路径入参字段本次**无变化**(保存接口为费用明细列表请求体;确认接口在保存基础上多 `expectedSourceFingerprint` 字段,须为 64 位十六进制字符串)。与本次变更相关的入参行为:
| 场景 | 原来 | 现在 |
|---|---|---|
| 请求体含未知字段(如把出参字段 `settlementConfirmStatus` 回传进请求体) | `584125`,无具体原因 | `584128`,message 指出不支持的字段名 |
| 请求体 JSON 反序列化失败(类型不匹配/格式错误) | `584125`,无具体原因 | `584128`,message 透出解析原因 |
| 字段 Bean 校验失败(如 `expectedSourceFingerprint` 不合 Pattern) | `584125`,无具体字段 | `584128`,message 透出 `字段路径: 校验提示` |
| 请求体为空 / null | `584125` | `584125`(不变) |
## 5. 出参字段
成功响应出参字段本次**无变化**。失败响应统一为:
| 字段 | 类型 | 说明 |
|---|---|---|
| `code` | Integer | 业务错误码,本次新增透出 `584128` |
| `message` | String | 错误描述,`584128` 时含具体字段原因 |
| `data` | Object | 恒为 `null` |
| `success` | Boolean | 恒为 `false` |
## 6. 枚举 / 数据字典
本次不涉及枚举或字典的新增、删除、改值、改语义。`settlementConfirmStatus` 等既有枚举取值不变。
## 7. 错误码
| code | 含义 | 触发场景 | 本次变化 |
|---:|---|---|---|
| `584125` | 导游或摄影费用请求字段不合法 | 请求体为空 / null | 不变(仅剩该场景触发) |
| `584128` | 导游或摄影费用请求字段不合法:{具体原因} | 请求体含未知字段 / 反序列化失败 / Bean 校验失败 | **新增**,替代原 `584125` 的解析/校验场景 |
`584128` message 构成为固定前缀 + 具体原因:
- 未知字段:`导游或摄影费用请求字段不合法:导游费用明细不支持字段: settlementConfirmStatus`(摄影接口为「摄影费用明细不支持字段: ...」)
- 校验失败:`导游或摄影费用请求字段不合法:expectedSourceFingerprint: 须为 64 位十六进制`
## 8. 示例
### 8.1 典型成功(保存导游费用,入参出参与改前一致)
```http
PUT /v3/admin/order/2084000000000002978/settlement/guide-fees
Authorization: Bearer <token>
Content-Type: application/json
```
```json
{
"fees": [
{
"feeDate": "2026-08-08",
"guideName": "张三",
"quantity": 1,
"unitPrice": 300.00,
"settlementAmount": 300.00,
"paymentMethod": "COMPANY_PAID",
"remark": null
}
]
}
```
```json
{"code": 200, "message": "success", "data": {"saved": true}, "success": true}
```
### 8.2 边界(请求体为空,错误码不变仍为 584125)
```http
PUT /v3/admin/order/2084000000000002978/settlement/guide-fees
Authorization: Bearer <token>
Content-Type: application/json
```
```json
null
```
```json
{"code": 584125, "message": "导游或摄影费用请求字段不合法", "data": null, "success": false}
```
### 8.3 业务失败(新增 584128,透出具体字段原因)
场景 A:把出参字段 `settlementConfirmStatus` 误回传进请求体(未知字段)。
```http
PUT /v3/admin/order/2084000000000002978/settlement/guide-fees
Authorization: Bearer <token>
Content-Type: application/json
```
```json
{
"fees": [
{
"feeDate": "2026-08-08",
"guideName": "张三",
"quantity": 1,
"unitPrice": 300.00,
"settlementAmount": 300.00,
"paymentMethod": "COMPANY_PAID",
"settlementConfirmStatus": "UNCONFIRMED"
}
]
}
```
```json
{"code": 584128, "message": "导游或摄影费用请求字段不合法:导游费用明细不支持字段: settlementConfirmStatus", "data": null, "success": false}
```
场景 B:确认接口指纹字段不合 Pattern(Bean 校验失败)。
```http
PUT /v3/admin/order/2084000000000002978/settlement/guide-fees/confirm
Authorization: Bearer <token>
Content-Type: application/json
```
```json
{
"expectedSourceFingerprint": "abc123",
"fees": []
}
```
```json
{"code": 584128, "message": "导游或摄影费用请求字段不合法:expectedSourceFingerprint: 须为 64 位十六进制", "data": null, "success": false}
```
## 9. 业务边界
- ✅ 4 个接口的请求体均接受完整费用明细载荷,成功路径行为与改前完全一致。
- ✅ 请求体为空 / null 仍返回 `584125`,该场景未变。
- ⚠️ 请求体含未知字段会被明确拒绝并返回 `584128`;不要把查询/详情响应里的出参字段(如 `settlementConfirmStatus`)原样 echo 回保存/确认请求体。
- ❌ `expectedSourceFingerprint` 必须是 64 位十六进制字符串,短串或非法字符会被 `584128` 拦截。
## 10. 修改前后对比
### 10.1 字段级对比
成功路径入参/出参字段**无变化**,略。
### 10.2 行为级对比
| 场景 | 原来 | 现在 |
|---|---|---|
| 请求体含未知字段 / 反序列化失败 | `584125 导游或摄影费用请求字段不合法` | `584128 导游或摄影费用请求字段不合法:{具体原因}` |
| Bean 校验失败(字段格式/取值不合法) | `584125`,无具体字段 | `584128`,message 透出 `{字段路径}: {校验提示}` |
| 请求体为空 / null | `584125` | `584125`(不变) |
| 成功保存 / 确认 | `code=200` | `code=200`(不变) |
## 11. 影响评估 / 回滚
### 11.1 影响评估
- **是否破坏向后兼容**:弱破坏。仅错误码语义变化——原来命中 `584125` 的解析/校验失败场景现在返回 `584128`;若前端对 `584125` 做了特判(专属 toast 文案 / 分支逻辑),这些场景将不再命中。
- **前端是否必须同步上线**:不强制。建议直接展示后端 `message`(已含具体字段原因,用户可自助定位),无需为 `584128` 再写翻译表。
- **上线顺序边界**:无顺序要求,新旧前端均可工作。
### 11.2 回滚方案
- 后端回滚后解析/校验失败恢复返回 `584125`,message 不再含具体原因;前端若已改为直显 message,不受影响。
## 12. 注意事项
- 若前端此前对 `584125` 写过特判文案(如「请检查导游费用字段」),请知悉解析/校验失败场景的错误码已变为 `584128`;保留 `584125` 的特判仍覆盖「请求体为空」场景。
- 推荐做法:失败 toast 直接展示后端 `message`,不要按错误码硬编码文案。
- 排查用户报错时,`584128` 的 message 即包含具体字段路径与原因,可直接据此定位,无需找后端查日志。
## 13. 关联 / 联系人
### 13.1 链接
- **Issue**: [#5674](https://git.1814.love:8443/wx/HL/issues/5674)
- **PR**: [#5677](https://git.1814.love:8443/wx/HL/pulls/5677)
- **Commit**: [146cc2ae48](https://git.1814.love:8443/wx/HL/commit/146cc2ae48)
### 13.2 联系人
- **后端负责人**: @yaosutu (yst)
@@ -0,0 +1,79 @@
---
schema: "hl-changelog/v2"
ticket: "5675"
title: "行程单在派单消息预览时即生成可见(不等派车成功后)"
consumer: "admin"
author: "wx(GIT)"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "not_required"
frontend_owner: ""
frontend_ref: ""
target_release: ""
verified_at: ""
status_note: "后端完成:PR #5685/#5687/#5688 已合并 dev-v3 并部署 TEST(hl-fleet-service 双实例)。预览/HOLD 通知即生成可点行程短链,短码跨确认稳定,确认前行程单已可打开。前端交接见下(预览定位参数与降级文案口径)。"
updated_at: "2026-08-08"
base: "dev-v3"
generated: "2026-08-08T11:20:00+08:00"
---
# 行程单在派单消息预览时即生成可见(不等派车成功后)
> 后端完成:PR [#5685](https://git.1814.love:8443/wx/HL/pulls/5685) / [#5687](https://git.1814.love:8443/wx/HL/pulls/5687) / [#5688](https://git.1814.love:8443/wx/HL/pulls/5688) 已合并 dev-v3 并部署 TEST,网关端到端验证通过。
## 关联 / 联系人
### 链接
- **Issue**: [#5675](https://git.1814.love:8443/wx/HL/issues/5675)
- **PR**: #5685(主)/ #5687(单行组定位配套)/ #5688(中间态容错配套)
- **Merge commit**: [cb44851c9](https://git.1814.love:8443/wx/HL/commit/cb44851c9)
### 联系人
- **后端负责人**: @wx
## 背景
派单消息预览里行程详情显示「行程链接在派单成功后自动生成」——预览时看不到行程单/链接,司机收到的 HOLD 待确认通知也是「行程确认后发送」占位文案。wx 要预览/通知时就有可点行程单链接。
## 变更说明(无接口契约变化,行为升级)
### 行为变化
| 场景 | 变更前 | 变更后 |
|------|--------|--------|
| 派单消息预览(组可定位) | 「行程链接在派单成功后自动生成」占位 | **真实可点短链** `https://…/s/{code}` |
| HOLD 待确认通知(司机收到) | 「行程确认后发送」占位 | **真实可点短链**,确认前即可打开行程单 |
| 司机确认后点同一短链 | —(此前无链接) | 短码不变,仍可打开(代际升级兼容,按当前身份重签) |
| 派单创建前的纯模板预览(无派单上下文) | 占位文案 | 不变(此时车辆/司机未定,无行程可链) |
| 增删槽位/重新确认窗口内的预览 | 500(缺陷) | 「行程链接暂不可用,请联系车务确认」降级文案 |
### 后端实现(hl-fleet-service)
1. **HOLD 待确认组可签发行程 token**(`ItineraryTokenService`):全组 HOLDING 且未冻结 dispatchPlan 时豁免 generation 非空/finalized=1 校验,代际用稳定哨兵 `PENDING(0L)`;混合状态未冻结组仍拒绝(失败关闭)。
2. **短码跨确认稳定**(`ItineraryShortLinkService.resolveShortLink`):同组同业务(车/司机/槽位/服务日/旅客快照全同)仅代际升级(PENDING→真实 generation)时放行,按当前身份重签 H5 token;换车/换司机/改期/取消仍失败关闭。
3. **HOLD 态 H5 可渲染**(`ItineraryH5Service`):全组 HOLDING + PENDING 代际 token 放行。
4. **HOLD 通知冻结真链接**(`AssignmentHoldNotificationSnapshotFactory`):不再降级占位(#5461 口径演进)。
5. **单行组/全程行定位适配**(`MessageTemplateRenderService`,#5675 配套):effective 组 id(group_id NULL→assignment_id,#5589 口径)+ 全程行 tripEndDate 取 endDate + 身份未就绪中间态容错降级。
6. **全程行 serviceDates 展开**(`effectiveServiceDates`):service_date NULL 的全程行按服务期逐日展开,签发与 H5 校验同口径。
## 前端交接
1. **预览要拿真链接,请求需能定位派车组**(三选一):传 `assignmentGroupId`;或传 `orderId + vehicleId + driverId`(能唯一命中 active 组时自动定位)。都不传的纯模板预览仍显示占位文案(正常——无派单上下文)。
2. **降级文案口径**:`itinerary.url` 可能返回两种文案——「行程链接在派单成功后自动生成」(无派单上下文)/「行程链接暂不可用,请联系车务确认」(组在重新确认窗口等中间态)。前端按文本展示即可,无需特殊处理。
3. **通知文案**:HOLD 待确认通知中行程详情现在直接是可点短链,司机确认前后点同一链接均可见行程单。
4. 短链有效期=行程结束 +7 天(既有口径不变)。
## 验证证据
- **单测**:token 层 +3(HOLD 未冻结可签发/混合状态仍拒绝/全程行展开)、短链层 +2(代际升级放行/换司机失败关闭)、H5 层 +2(HOLD 渲染可见/finalize 后旧 token 失效)、预览链 +2(单行组定位/中间态容错)、快照工厂更新为 HOLD 签发真链接;messagetemplate+h5 **396/396**、assignment 相关 **444/444** 全绿;spotless 通过
- **fleet verify**(mvn-throttle 错峰):仅基线/环境项失败(ReleaseEOccupancyMysql8033 等 3 个需 mysql:8.0.33 Testcontainers;ReleaseEMixedBinaryHarness flaky 复跑全绿),与本案无关
- **部署**:hl-fleet-service 双实例 UP(11:16)
- **网关端到端**(TEST,VEHICLE_MANAGER):
- HOLD 待确认派单(全程槽单行组)render → 返回真短链 `https://web.test.1814.love:9443/s/txU62dA`(非占位)✓
- 同组幂等重放复用同码 ✓
- 短链 302 → H5 长链(token payload:PENDING 哨兵代际 + 全程行展开 3 个服务日)✓
- GET H5 长链 → 200 行程单 JSON(主题/日期/服务日/客户全渲染)——**确认前行程单即可见** ✓
- 中间态组(增删槽位重新确认窗口)render → 降级文案,不再 500 ✓
@@ -0,0 +1,83 @@
---
schema: "hl-changelog/v2"
ticket: "5676"
title: "改派支持按天改派(排车表逐行改派按钮)+ 统一选择修复交接"
consumer: "admin"
author: "wx"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "mmg"
frontend_ref: "3df533a5"
target_release: ""
verified_at: ""
status_note: "后端完成:PR #5686 合并 dev-v3(4e993920440cad0b6105a5f7682d6b33d1444bad)并部署 TEST,网关验证按天改派只改指定天+统一选择单次全改均通过。统一选择「只改第一天」bug 实证为前端逐日循环互覆盖(后端无 bug),修复=前端改单次调 change。待前端接入按天改派+统一选择单次调用。"
updated_at: "2026-08-08"
base: "dev-v3"
generated: "2026-08-08T11:10:00+08:00"
---
# 改派支持按天改派 + 统一选择修复交接(#5676)
## 需求
1. 排车表**每行(每个服务日)**有【改派】按钮——单独改某天的车/司机(按天改派,每天可不同)
2. 统一选择按钮=整体改派(所有日期),保留
3. wx 实测补充:统一选择**现在不好使,只能改第一天**(选的车/司机只应用到第一天)
## 统一选择「只改第一天」bug 根因(后端无 bug,前端修复)
**根因 = 前端「统一选择」逐日循环调 change 互相覆盖**,非后端问题:
- 改派操作日志实证:order `2080600006514872322` 在 2026-08-06 17:25 对同一槽位**连续两次调 change**(`effectiveDate=2026-08-29` 和 `2026-08-28` 分开、每天一行)——前端对「统一选择」**逐日循环**(每天调一次)。
- change 语义 = **「effectiveDate 起连续后缀」**:eff=8/29 改 8/29 起后缀,eff=8/28 又改 8/28 起后缀(覆盖 8/29)…… 逐日循环互相覆盖 → 只有部分天生效(表现为「只改第一天」)。
- **后端单次 change 正确全改**:单测证明逐日槽位 3 天,单次 `change(effectiveDate=第一天, 不传 serviceDates)` → 取消整段后缀 + 重建 3 行全新车/司机。
## 修改接口:`POST /admin/fleet/assignments/{assignmentId}/change`
新增**可选**字段 `serviceDates`(`List<LocalDate>`,其余字段不变):
| 字段 | 说明 |
|---|---|
| `serviceDates` | **按天改派限定的服务日期集**。非空=按天改派模式:只改这些日期的行(其余天保留);**空/不传=现状**(effectiveDate 起连续后缀整体改派)。 |
### 前端交接(两种改派的正确调用方式)
**1. 统一选择(整体改派)——修复点**:
```json
{
"effectiveDate": "<第一天>",
"newVehicleId": ..., "newDriverId": ...,
"holdMode": 0, "reason": "...", "requestId": "<唯一>"
}
```
- **单次调用**,`effectiveDate`=第一天,**不传 `serviceDates`** → 一次整体改派所有天。
- **不要再逐日循环调 change**(会互相覆盖)。
- 每次操作生成唯一 `requestId`(幂等)。
**2. 按天改派(新增,每行改派按钮)**:
```json
{
"effectiveDate": "<该天>",
"serviceDates": ["<该天>"],
"newVehicleId": ..., "newDriverId": ...,
"holdMode": 0, "reason": "...", "requestId": "<唯一>"
}
```
- 某天【改派】→ `effectiveDate`=该天 + `serviceDates=[该天]` → **只改该天,其他天不变**。
- 每天可不同车/司机(逐行各调一次,每天独立 `requestId`)。
- `assignmentId` 路径参数=该槽位任一派单行 ID。
### 行为说明
- **校验按天**:按天改派的档期/占用/常驻/保险校验只针对 `serviceDates` 指定的天(某天换车/司机只需该天资源空闲,不影响其他天)。
- **逐日价格**:按天改派后逐日车费按各天价格日历/车型分别算(`resolveDaily` 按子集日期逐日取价)。
- **兼容**:`serviceDates` 不传时行为与现状完全一致(统一选择整体改派)。
## 验证
- AssignmentServiceTest **397/397**(新增 3:按天单天只改该天/按天非连续子集其余保留/统一选择单次全改对照);dev-v3 全量 verify 3273/0F/0E。
- 网关实证(TEST,槽位 `344052387587166208`,order `2085662570479304706`,8/21-8/23 三天):
- **按天改派**:`change(serviceDates=[8/22])` 换车 → 只 8/22 变,8/21/8/23 保留原车;
- **统一选择单次**:`change(effectiveDate=8/21, 不传 serviceDates)` 换车 → 3 天全改。
@@ -0,0 +1,53 @@
---
schema: "hl-changelog/v2"
ticket: "5676"
title: "统一选择只改第一天(前端改单次调 change=整体改派)"
consumer: "admin"
author: "wx"
change_type: "前端修复"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "mmg"
frontend_ref: "f4223996"
target_release: ""
verified_at: ""
status_note: ""
updated_at: "2026-08-08"
base: "origin/dev-v3"
generated: "2026-08-08"
---
# 统一选择只改第一天(前端修复)
## 问题(wx 实测)
派车"统一选择车辆/司机"选的车/司机**只应用到第一天**,没应用到所有出行日(该整体改派所有日期)。
## 根因(#5676 后端实证,责任端=前端)
前端"统一选择"**逐日循环调 change**(每天一行,effectiveDate 分别 8/28、8/29...)——change 语义是"effectiveDate 起连续后缀",逐日循环互相覆盖→只部分生效。
**后端单次 change(effectiveDate=第一天,不传 serviceDates)正确全改所有天**(取消整段后缀+重建),后端无 bug。
## 前端修复
"统一选择"(整体改派)改为**单次调 change:`effectiveDate=第一天`**(不传 serviceDates)——即整段改派所有出行日。不要逐日循环调。
- 按天改派(#5676 新增 serviceDates)是另一功能(按天单独改),保留
- 统一选择(整体)= 单次 change effectiveDate=第一天
## 补充(wx 明确矩阵场景)
**矩阵派单**:从矩阵某一行(车辆行)派车/司机时,**所有行程日对应槽位都该是这行的车+司机**(统一应用所有行程日,不只第一天)。与"统一选择"同一口径——矩阵一行派 = 单次 change effectiveDate=第一天(整段改派所有日)。
## 验收
- [ ] 统一选择选的车/司机应用到所有出行日(不只第一天)
- [ ] **矩阵派单从一行派车→所有行程日对应槽位=这行的车+司机**
- [ ] 按天改派不受影响
## 关联
- #5676(按天改派已实现;统一选择修复=本前端任务)
## 前端交付与矩阵场景实证(hl-admin@f4223996 + 3df533a5)
统一选择「只改第一天」已修:根因为逐日/多段槽位下统一选择只锚定被选执行段(effectiveDate=段首日、费用只本段),新增 `mergeSlotChangeSegments`(display.js:263)合并同槽全部有效执行段为整段改派目标,单次 change effectiveDate=整段首日、不发按天 serviceDates。
**矩阵场景补充实证**:矩阵派单从一行派车走 `matrix/index.vue:442 onDropAssign` → `openAssign(order, { vehicle, mode })`,复用 AssignModal 统一 assign/change 主流程,与统一选择同一单次 change 逻辑——一行派车即整段(所有行程日对应槽位=这行车+司机),不只第一天。按天改派(3df533a5)为独立入口,不受影响。
## 联系人
- 后端/协调台:wx
@@ -0,0 +1,44 @@
---
schema: "hl-changelog/v2"
ticket: "5679"
title: "确认执行弹一堆重复「已变化」术语提示(合并+去抖+友好化)"
consumer: "admin"
author: "wx"
change_type: "前端修复"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "mmg"
frontend_ref: "701233df"
target_release: ""
verified_at: ""
status_note: ""
updated_at: "2026-08-08"
base: "origin/dev-v3"
generated: "2026-08-08"
---
# 确认执行弹一堆重复「已变化」术语提示(前端修复)
## 问题(wx 实测)
车务确认司机接单/确认执行时,弹出一堆重复术语提示:「订单与派单基线已变化」「当前派单已变化」「可动作已变化」……信息过载、困惑。
## 根因(#5679 后端排查,责任端=前端)
三条提示全是 hl-ui 前端组装:`AssignModal.vue:3065-3079` 的 watch 对 SSE 刷新做基线 diff(打开时缓存快照 vs 刷新数据),每类差异在 `showFleetBaselineDifferenceDialog`(baselineDifference.js:88-127)堆一张术语卡片,且每次带差异的刷新重复弹;司机确认接单本身导致 assignmentStatus/actionCodes 合法流转,确认执行场景必命中 ACTIVE_ASSIGNMENT+CAPABILITY 两段 diff(即"误弹")。后端基线字段无噪声、契约正常,无可改项。
## 前端修复(全在前端)
1. **合并为单条友好提示**(如"派车信息已更新,请核对后确认"),不堆多张术语卡片
2. **去抖**——单次刷新只弹一次(不重复弹)
3. **预期变化豁免**——司机确认接单等合法流转不弹"已变化"
4. **去术语文案**——去掉"基线/快照/动作"等技术术语,改车务能懂的话
## 验收
- [ ] 确认执行只弹一个简洁友好提示(不堆多个术语卡片)
- [ ] 单次刷新只弹一次;合法流转不误弹
- [ ] 文案友好(发生啥+怎么办)
## 关联
- #5679(后端排查,契约正常);模式同 #5666(前端修复)
## 联系人
- 后端/协调台:wx
@@ -0,0 +1,64 @@
---
schema: "hl-changelog/v2"
ticket: "5681"
title: "多槽位确认执行页逐日车费覆盖全程+HOLD 整组确认快照代际修复"
consumer: "admin"
change_type: "修改接口"
author: "wx(GIT)"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "not_required"
frontend_owner: ""
frontend_ref: ""
target_release: ""
verified_at: ""
status_note: "后端完成:PR #5690 已合并 dev-v3 并部署 TEST(12:52 滚动 DONE)。网关双探针 ALL PASS:自建 2 车需求订单 HOLD 派车→行级冻结代际→详情整组快照代际非空→两组逐日车费各覆盖全部出行日→司机确认→需求级整组确认 200 confirmed=true。前端无需配合(字段与守卫均沿用既有契约,此前是后端数据缺失)。"
updated_at: "2026-08-08"
base: "dev-v3"
generated: "2026-08-08T13:00:00+08:00"
---
# 多槽位确认执行页逐日车费覆盖全程+HOLD 整组确认快照代际修复
> **服务**: hl-fleet-service
> **PR**: [#5690](https://git.1814.love:8443/wx/HL/pulls/5690)
> **Issue**: [#5681](https://git.1814.love:8443/wx/HL/issues/5681)
> **日期**: 2026-08-08
> **影响**: 🟢 **缺陷修复**,无契约结构变更(既有字段数据口径修复)。前端无需改代码。
## 背景
#5681(P1)wx 实测:订单 26-0703(4 人 2 车 2 司机,8/11-8/14)确认执行页:
1. 逐日车费只显示 1 车 1 天(8/11)——应列出每个车每个出行日车费;
2. 报「详情缺少整组确认快照,请刷新后重试」——多槽位无法确认执行。
**根因(双缺陷)**:
- 全程单行(service_date NULL)派车组聚合视图的 `dailyVehicleFees`/`chargeableServiceDates`/`freeServiceDates` 由物理行 1:1 生成,`serviceDateOf` 对全程行只取 startDate,逐日车费只产出 1 天;
- #5400 重构时 dailyPlan 模式 HOLD 创建只退休旧代际标记、不再冻结新方案代际(items 模式两种模式都会冻结),导致 HOLD 单 `dispatchPlanGeneration` 恒为 NULL,需求级整组确认的代际栅栏与前端整组快照守卫永远拿不到代际。
## 修复内容(内部,无接口/字段结构变化)
- `completeDailyPlanCreation`:HOLD 逐日方案创建同样冻结方案代际(finalized=1 + generation,与 items 模式一致);DAILY_V3 最终快照事件仍只在 DIRECT 创建时发布,HOLD 待最终确认后发布(#5400 意图不变)。
- `aggregateGroupRows`:全程行聚合视图逐日费用/收费日/免费日按 startDate..endDate 逐日展开。
- 兼容:#5675 行程短链哨兵路径只服务存量无代际 HOLD 行,有代际行走真实代际校验,双向兼容;单车/逐日切片行为不变(回归测试钉住)。
## 变更接口
| 方法 | 路径 | 变更 |
|---|---|---|
| GET | /admin/fleet/board/orders/:orderId | activeAssignments[].dailyVehicleFees 全程行覆盖全部出行日;driverConfirmationSummary.dispatchPlanGeneration 对 HOLD 单正常返回 |
| POST | /admin/fleet/assignments/requirements/:requirementId/confirm | 多槽位 HOLD 整组确认可正常携带代际提交(修复前永远拿不到代际) |
## 验证证据
- 全量 `mvn -pl hl-fleet-service -am verify`:3283 Tests 0 失败;新增 4 回归(HOLD 冻结代际不发快照事件/DIRECT 对照发事件/全程行逐日车费展开 4 天/逐日切片不变);spotless 通过。ReleaseEMixedBinaryHarnessTest(进程时序)与两个 Testcontainers 类(3306 端口并行争用)全量内环境性失败,单独重跑 23/23、2/2、10/10 全绿,与本改动无关。
- 部署 TEST:12:52 滚动 DONE。
- 网关端到端(自建 2 车需求订单 2085938395749515266,蒙C01E01+孟和/蒙A-S6666+苏和巴特,8/22-8/24):HOLD 派车 → 行级 finalized=1+代际一致 → 详情整组快照代际非空 → 两组逐日车费各 3 天 → 两组司机确认 → 需求级整组确认 **200 confirmed=true** → DB 双行 assigned。单车对照(26-6179)逐日车费 3 天正常。
## 前端配合
无需配合。确认执行页的槽位切换、整组快照守卫(requirementId/version/sha/代际/groups)均为既有契约,此前是后端数据缺失导致守卫不通过;修复后原链路自然恢复。
## 前端实证确认(2026-08-08 mmg,hl-admin)
逐行核实确认 not_required 属实,零代码改动:整组快照守卫在 `src/views/fleet/board/composables/useAssignFlow.js:166-169` 与 `:518-531`,前端直读 `driverConfirmationSummary.dispatchPlanGeneration`、空则抛「详情缺少整组确认快照,请刷新后重试」——正是本单后端修复的守卫,前端是正确消费方,此前因 HOLD 单代际恒 NULL 不通过,后端补冻结代际后原链路自然恢复;逐日车费前端仅逐日渲染 `activeAssignments[].dailyVehicleFees`,后端全程行按 startDate..endDate 展开后自动正确。前端无任何针对该缺陷的特判或 workaround 需拆除。
@@ -0,0 +1,55 @@
---
schema: "hl-changelog/v2"
ticket: "5689"
title: "派单通知模板加载失败修复(短链业务不匹配降级 + 全程行结束日口径统一 + 拆箱 NPE)"
consumer: "admin"
author: "wx"
change_type: "修复"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "not_required"
frontend_owner: ""
frontend_ref: ""
target_release: ""
verified_at: ""
status_note: "后端完成:PR #5692+#5694 已合并 dev-v3(089d1a7e0)并部署 TEST(hl-fleet-service 双实例 UP)。根因两层:①冻结链/预览链对全程行(service_date NULL)结束日口径不一致(startDate vs endDate)→ 短链 tripEndDate 漂移 → matchesBusiness 不匹配抛 605308 冒泡;②确认执行中间态(ASSIGNED+dispatchPlan 未冻结)ItineraryTokenService 三元 long?Long 拆箱 NPE 500。修复:预览链 605308/身份未就绪统一降级「行程链接暂不可用,请联系车务确认」不再 500 阻塞整条模板渲染;SnapshotFactory endDateOf 口径统一;三元装箱 null 安全。网关验证 26-8778(实证单)6/6:render 200 正文完整、render-batch item success=true。"
updated_at: "2026-08-08"
base: "dev-v3"
generated: "2026-08-08T12:40:00+08:00"
---
# 派单通知模板加载失败修复(#5689)
## 背景
派单页消息预览区「通知模板加载失败,请重试」+「派车前先选择并成功渲染通知模板」(实证 26-8778)。
## 根因(网关 + 库表 + 日志定位)
1. **短链业务不匹配 605308**:`MessageTemplateRenderService`(预览链)对全程行(service_date NULL)结束日取 `endDate`(#5562 口径),而 `AssignmentHoldNotificationSnapshotFactory`(冻结链)取 `startDate`——同一派车组两条链算出不同 tripEndDate → `createOrGet` 命中已存在短链但 `matchesBusiness(tripEndDate)` 不匹配 → `requireSameBusiness` 抛 605308 冒泡 → 渲染接口失败。
2. **拆箱 NPE 500**:确认执行后派车行处于 ASSIGNED + dispatchPlan 未冻结(finalized=0、generation=null)中间态,`ItineraryTokenService` 三元 `holdPendingIdentity ? long常量 : Long字段` 被强制按 long 求值 → false 分支对 null 拆箱 → NPE 500(在既有 fail-closed 检查之前)。
3. render-batch 单项失败被容错吞掉(success=false)→ 前端只看到「加载失败」更隐蔽。
## 修复(PR #5692 + #5694)
1. **预览容错**:`resolveItineraryShortLink` 捕获 BusinessException 605308 + IllegalStateException 身份未就绪(#5675 白名单)→ 统一降级为「行程链接暂不可用,请联系车务确认」,不再 500 阻塞整条模板渲染;短链配置/落库等非业务异常仍 fail-fast(#5461 不变)。通知发送链(SnapshotFactory/EffectService)不走本方法,保持 fail-closed。
2. **口径统一**:`AssignmentHoldNotificationSnapshotFactory` 新增 `endDateOf`(serviceDate NULL → endDate),冻结链与预览链 tripEndDate 一致,根除短链日期漂移。
3. **NPE 修复**:`ItineraryTokenService` 三元改 `Long.valueOf(PENDING_DISPATCH_PLAN_GENERATION)`,null 不拆箱 → 正常走「派车组身份不完整或已失效」fail-closed → 预览降级。
## 行为变化
- 模板渲染接口不再因短链中间态/业务不匹配而 500;预览区模板正常加载渲染,行程链接不可用时显示人工介入文案(而非加载失败)。
- 派车组确认执行后(dispatchPlan 未冻结窗口)预览行程链接显示「行程链接暂不可用,请联系车务确认」,dispatchPlan 冻结后自动恢复可点链接。
- 错误码 605308/600801/600800 口径不变;非业务异常(如短链配置缺失)仍按原样上抛。
## 前端动作
- 预览区「通知模板加载失败,请重试」为后端 500 的兜底文案;本次修复后正常场景不再出现。若仍出现,请按响应 code/message 反馈后端(600800 模板变量缺失 / 600801 模板不存在 / 605308 短链业务不匹配)。
- 无需字段适配;渲染正文中的行程链接可能为「行程链接暂不可用,请联系车务确认」占位文案(属正常业务态)。
## 验证证据
- 定向 64/64(render 605308 降级、非业务异常上抛、全程行冻结 endDate 口径、ASSIGNED 中间态不 NPE、预览降级);spotless:check 通过。
- 全量 verify 3287+(另一会话并行占用 3306 测试容器导致 MySQL8033 固定端口类竞争失败——基线脆弱项,主工作区干净基线同失败已证;错峰重跑补录)。
- 网关实测(TEST,26-8778 实证单)6/6:单渲染 200 + 正文完整(呼伦旅行—订车单/请确认以下订车信息)+ itinerary.url 降级文案 + 有效期正常计算;render-batch 200 + item success=true(修复前 NPE 500 / success=false)。
- 部署:hl-fleet-service dev-v3=089d1a7e0 双实例 UP(PR #5692+#5694)。
@@ -0,0 +1,53 @@
---
schema: "hl-changelog/v2"
ticket: "5691"
title: "改派页确认改单日期对所有出行日回显(修复只展示1天)"
consumer: "admin"
author: "wx"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "not_required"
frontend_owner: ""
frontend_ref: ""
target_release: ""
verified_at: ""
status_note: "后端完成:PR #5696 合并 dev-v3(007dc20ad86088c22604ffed7d79e20df1318a51)并部署 TEST,网关验证改派页确认改单日期对所有出行日回显。待前端确认改派页用 activeAssignments[].serviceDates 渲染逐日。"
updated_at: "2026-08-08"
base: "dev-v3"
generated: "2026-08-08T13:25:00+08:00"
---
# 改派页确认改单日期对所有出行日回显(#5691)
## Bug(wx 实测)
26-8778 周梦洁(8/17-8/20 4 天行程),改派页「确认改单日期与逐日费用」**只展示 8月17日 一天**——4 天行程只显示 1 天,无法逐日看/改全部。
## 根因
改派页「确认改单日期」用 `GET /admin/fleet/board/orders/{orderId}` 返回的 **`activeAssignments[].serviceDates`** 渲染。该单是**已派全程行**(`service_date=NULL`、`start=8/17 end=8/20`、`dispatch_plan_finalized=0` 未按逐日敲定、但已派有车+司机):
- `currentServiceDatesByGroup` 过滤 `dispatch_plan_finalized==1`,全程行展开(expandFullTripDailyRows)的 slice 因 finalized=0 被滤 → **`serviceDates` 返回空** → 改派页只展示 1 天(fallback 到 startDate)。
- 而 `dailyVehiclePlan` / `dailyVehicleFees` 都正常 4 天(不过滤 finalized)——日期与逐日费用天数不一致。
## 修改接口:`GET /admin/fleet/board/orders/{orderId}`
`activeAssignments[].serviceDates` 行为修正(无字段结构变化):
| 场景 | 修复前 | 修复后 |
|---|---|---|
| 已派全程行(finalized=0,有车+司机) | `serviceDates=[]`(空) | `serviceDates=[start...end]` 全部出行日 |
| 逐日行(finalized=1) | 正常 | 不变 |
| 未派资源(无车/司机)未敲定切片 | 不纳入 | 不变(仍按 finalized==1 限定) |
### 前端交接
- 改派页「确认改单日期」继续用 `activeAssignments[].serviceDates` 渲染——现在对**已派全程行**也返回所有出行日(不再空)。
- 「逐日费用」用 `activeAssignments[].dailyVehicleFees` / `dailyVehiclePlan`——天数与 `serviceDates` 一致(配套展示)。
- 结合 #5676 按天改派:改派页每天一行展示,点某天【改派】调 `POST /admin/fleet/assignments/{assignmentId}/change` 传 `serviceDates=[该天]` 只改该天。
## 验证
- BoardOrderServiceTest **88/88**(新增 1:已派全程行 finalized=0 回显全部服务日;红→绿验证修复前失败);dev-v3 全量 verify 3286/0F/0E。
- 网关实证(TEST,周梦洁 order 2085922371843125250):修复后 `activeAssignments[0].serviceDates=[8/17,8/18,8/19,8/20]` 4 天(修复前空),与 dailyVehiclePlan 天数一致。
@@ -0,0 +1,62 @@
---
schema: "hl-changelog/v2"
ticket: "5693"
title: "矩阵拖拽改派一步到位(拖到目标车/司机直接改成,不再弹窗手选)"
consumer: "admin"
author: "wx"
change_type: "前端修复"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "mmg"
frontend_ref: "23d6e7b1"
target_release: ""
verified_at: ""
status_note: ""
updated_at: "2026-08-08"
base: "origin/dev-v3"
generated: "2026-08-08"
---
# 矩阵拖拽改派一步到位(前端修复)
## 口径(wx)
矩阵拖拽改派要**一步到位**——拖到目标车辆/司机就**直接改成它**(该车常驻司机或拖到的司机),**不再弹改派页手选槽位+重选车/司机**(拖完还手选=失去拖拽意义)。
## 现状(前端问题)
`matrix/index.vue:442 onDropAssign` 拖后仍 `openAssign` 弹窗手选——拖拽后还要手选槽位+车/司机。
## 后端能力已齐备(零改动)
- change API `POST /admin/fleet/assignments/{id}/change`:`newVehicleId`/`newDriverId` 均可空,必填仅 `effectiveDate`/`holdMode`/`reason`/`requestId`
- 拖拽落点行已带 `assignmentId`/`slotId`(只切片该槽位)
- 矩阵车辆行已带 `primaryDriverId`(常驻司机)
- 价格/收费日默认沿用
## 前端修复
拖拽 drop 后**直接调 change**:
- 拖到车辆行 → change 传该 vehicleId + 其 primaryDriverId(常驻司机),effectiveDate=落点日期,切片该槽位
- 拖到司机 → change 传该 driverId
- 多槽位:拖拽落点确定改哪个槽位(slotId)
- 仅跨常驻确认 / 605041 基线差异 / 多车 warning 等分支弹**轻量确认**,不弹完整改派页手选
## 验收
- [ ] 拖拽到目标车/司机直接改派生效(一步到位,不弹改派页手选)
- [ ] 多槽位拖拽落点确定改哪个槽位
- [ ] 跨常驻/基线差异等弹轻量确认
- [ ] 拖拽后价格/逐日正确
## 关联
- #5693(后端排查,契约齐备零改动;证据 evidence/5693/issue-comment-onestep.md)
## 联系人
- 后端/协调台:wx
## 前端实证确认(2026-08-08 mmg,hl-admin)
按协调台拍板的「向导预选直达确认步」口径实现(非字面「直接调 change 不弹页」),hl-admin@23d6e7b1:
- **矩阵拖拽补传常驻司机**:`matrix/index.vue onDropAssign` 从落点车辆行取 `primaryDriverId`(字符串透传,空归一 null),两个模式分支统一 `openAssign(order, { vehicle, driver: residentDriverId, mode })`。
- **AssignModal reassign 应用预选**:拖拽条目 `order.assignmentId` 命中 `activeAssignments` 且带预选车辆时,自动锁定被拖槽位为改派目标 + 进入「已清除重选」态(`changeDraftCleared=true`,等价手选槽位后点清除),费用草稿按 `mergeSlotChangeSegments` 整段合并目标 + `preferSavedTotal` 恢复;`restoreSelection({ vehicleId, driverId, autoSelectResidentDriver })` 复用 batch 分支同一机制——预选司机仅作初始草稿,仍随 `loadCandidates` 携带两侧 ID 复核可用性与常驻关系,不硬信车辆档案;落点车无常驻司机时留空走既有空态。
- **保持不变**:提交链 `buildAssignmentSubmission/changeAssignment`、跨常驻确认(605036)、基线差异(605041)、ORDER_HAS_OTHER_VEHICLES warning、逐日车费拦截全部未触碰。
- **与原口径差异**:拖拽后仍需用户在改派向导点一次「下一步/确认」提交(未做到完全不弹页直接 change)。取舍原因:落点缺目标司机、落点日期、逐日车费三个向导输入,直接重建精简 change 链需自行补齐这三值,风险高于复用既有向导校验;多槽位由被拖条目 assignmentId 确定槽位(满足「落点确定改哪个槽位」)。
- 验证:fleet/board 定向 vitest 413/413 通过;checkpoint(含生产构建)全绿。若需进一步做到「完全不弹页直改」,属另一次精简 change 链重建,建议单列工单。
@@ -0,0 +1,63 @@
---
schema: "hl-changelog/v2"
ticket: "5693"
title: "矩阵拖拽改派多槽位支持评估 + 候选排除语义回归锁定(改指定槽位不影响其他)"
consumer: "admin"
author: "wx"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "not_required"
frontend_owner: ""
frontend_ref: ""
target_release: ""
verified_at: ""
status_note: "评估结论:多槽位拖拽改派端到端已实现且槽位语义正确,零行为变更;本次仅补回归测试锁定「候选排除只作用当前槽位,同订单其他槽位仍计目标车/司机冲突」。补充口径(wx,工单评论 id=37195):拖拽改派交互要一步到位(拖到目标车/司机直接改派,不再弹窗重选)——后端一步改派能力已齐备(change 接口 newVehicleId/newDriverId 均可空,详见工单评论 id=37196),属前端交互改造,由协调台另行前端 changelog 分流。"
updated_at: "2026-08-08"
base: "dev-v3"
generated: "2026-08-08T13:40:00+08:00"
---
# 矩阵拖拽改派多槽位评估与候选排除语义锁定(#5693)
## 背景
#5693 要求评估矩阵拖拽改派对"一个订单多车(多槽位)"的支持:目标槽位确定、指定槽位、按槽位校验、按槽位价格/逐日方案。评估结论:**四维均已实现**(#5573 槽位级派车系列建成),唯一缺口是"同订单其他槽位仍计冲突"无回归测试,本单补齐。
## 变更内容
| 项 | 变更 |
|---|---|
| `AssignmentCandidateServiceTest` | 新增 `query_reassignKeepsOtherSlotConflictOnTargetVehicle`:多槽位订单排除 slot0 查询候选时,slot1 占用目标车仍返回冲突(assignmentId/groupId 指向 slot1),available=false |
零行为/契约变更:无 mapping、字段、类型、必填性、枚举、错误码改动。
## 评估结论(四维)
1. **目标槽位确定**:矩阵每槽位独立数据行(assignmentSlotId/fleetItemIndex/assignmentId),拖拽 payload=被拖槽位行;改派提交 "`POST /admin/fleet/assignments/:assignmentId/change`" 以被拖槽位派单为 anchor,后端只切片该槽位。
2. **指定槽位**:弹窗槽位表可改选其他槽位("选择改派");候选归属校验 fail-closed(excludeAssignmentId 必须同属当前 orderId+requirementId+fleetItemIndex,跨槽位直接拒绝),不可能误改别槽。
3. **校验按槽位**:候选 `withoutExcludedSlot` 只排除当前槽位全部切片;precheck 按组排除自身;座位按 fleetItemIndex 槽位需求(#5573);常驻为车辆↔司机配对(槽位无关,设计如此);保险按派单行事件,只触达被改槽位。
4. **价格/逐日方案按槽位**:change 按 effectiveDate 逐日切片原子替换该槽位,保留前缀沿用旧快照;同订单其他车辆返回 `warningCode=ORDER_HAS_OTHER_VEHICLES` 强提示,其他槽位数据不动。
## 变更接口或验证证据
### 接口契约
无契约变更。涉及接口 `POST /admin/fleet/assignments/candidates`(入参 orderId/requirementId/fleetItemIndex/excludeAssignmentId 既有语义)与 `POST /admin/fleet/assignments/:assignmentId/change`(既有槽位原子改派)行为不变。
### 验证证据
- 定向测试:`AssignmentCandidateServiceTest` 50/50 通过(含新增用例);fleet 全量 verify 失败项全部归账(ReleaseEMixedBinaryHarnessTest 1F + ReleaseEOccupancyMysql8033RecoveryTest 10E 为既有基线失败;2 类 ContainerLaunch 系并行会话抢占固定 3306,空闲窗口复跑 7/7 通过);spotless:check 通过。
- 部署:hl-fleet-service TEST(dev-v3)部署成功。
- 网关探针(实单 2085938395749515266 双槽位 8/22-24,只读)8/8 PASS:
- A 排除 slot0 后自身车蒙C01E01 available=true 且无冲突(自身槽位被排除);
- B slot1 车蒙A-S6666 available=false,冲突指向 slot1 派单 2085938404851130370(其他槽位仍计冲突);
- C 跨槽位排除(excludeAssignmentId=slot0 + fleetItemIndex=1)被 fail-closed 拒绝("参数非法: 排除派单不属于当前订单、当前用车需求或当前车型项")。
## 前端交接
本单后端变更(回归测试)无需前端配合。另:wx 后续口径(工单评论 id=37195)要求拖拽改派交互**一步到位**——拖到目标车/司机直接改派(该车常驻司机或拖到的司机),不再打开改派弹窗手选槽位+重选车/司机;该需求为纯前端交互改造(后端契约依据见工单评论 id=37196),由协调台另行前端 changelog 跟踪,与本后端 changelog 的 frontend_status=not_required 不冲突。
## 前端实证确认(2026-08-08 mmg,hl-admin)
确认 not_required 属实,零代码改动:前端候选查询 `useVehicleDriverPicker.js:190-191` 仅传单数 `excludeAssignmentId`(当前槽位派单行 ID),不跨槽位排除,与本单锁定的「候选排除只作用当前槽位、同订单其他槽位仍计冲突、跨槽位 fail-closed」语义一致;改派提交以被拖/被选槽位派单为 anchor,前端未做跨槽位切片。前端在 #5676 记录的「整段改派时同槽其他执行段占用可能被误报」关切,本单后端明确为有意语义(其他槽位/段仍计冲突、失败关闭),非缺陷,前端维持现状。
@@ -0,0 +1,63 @@
---
schema: "hl-changelog/v2"
ticket: "5697"
title: "行程链接预览恢复真链接(确认执行组级冻结派车方案代际)"
consumer: "admin"
author: "wx"
change_type: "修复"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "not_required"
frontend_owner: ""
frontend_ref: ""
target_release: ""
verified_at: ""
status_note: "后端完成:PR #5700 已合并 dev-v3(e95cfc89a)并部署 TEST(hl-fleet-service 双实例 UP 14:52)。根因两层:①26-8778 确认执行(08-08 11:27)早于 #5681 finalize 逻辑部署(11:40)→ 存量遗留中间态(assigned+generation NULL+finalized=0)→ 预览/短链身份缺失(#5689 已把 500 降级为暂不可,本单恢复真链接);②confirm 的 finalize 依赖需求级 publishDailySnapshotIfComplete 条件(拓扑全派+无既有代),需求内存在 legacy 遗留行/非最终拓扑时新确认组不冻结。修复:确认执行组级冻结(markDispatchPlanFinalizedForRows:仅确认组、finalized=0 幂等、不退休同需求其他组;legacy 分支锁内重解析当前代,无代签发新代;confirmRequirement 多组沿用 expected 代或一次新代)+ TEST 存量数据修复(26-8778 原行补 generation/finalized)。网关验证:26-8778 渲染 200 返回真链接(改派后新组 t6wpsPy,8/17-8/20,有效期至 08-27)+ render-batch success=true + H5 解析 200(新旧链均正常)。"
updated_at: "2026-08-09"
base: "dev-v3"
generated: "2026-08-08T15:00:00+08:00"
---
# 行程链接预览恢复真链接(#5697)
## 背景
#5675/#5689 修复部署后,26-8778 派单预览行程详情仍显示「行程链接暂不可,联系车务确认」。
## 根因(库表+代码+时间线定位)
1. **存量遗留中间态**:26-8778 确认执行(08-08 11:27:31)早于 #5681 finalize 逻辑部署(11:40)——行保持 assigned + dispatch_plan_generation NULL + finalized=0 → 预览/短链解析身份缺失(#5689 已把 500 降级为「暂不可」,本单恢复真链接)。
2. **代码缺口**:confirm 的 finalize 依赖需求级 `publishDailySnapshotIfComplete` 条件(拓扑全派 + 无既有代)——需求内存在 legacy 遗留行或非最终拓扑时,新确认组不会冻结 → 确认组预览/短链身份仍缺失。
## 修复(PR #5700)
1. `FleetAssignmentMapper.markDispatchPlanFinalizedForRows`:组级冻结——仅确认组行、finalized=0 幂等、不退休同需求其他组(改派/换版仍由 retire/clear 全需求退休)。
2. `confirm` legacy 分支:锁内重解析需求当前代(并发组先冻结则沿用同代),无代签发新 snowflake 代,确认组组级冻结。
3. `confirmRequirement` 原子引擎:多组确认沿用 `expectedPlanGeneration` 或循环外签发一次新代(多组共用),逐个确认组组级冻结。
4. **存量数据修复(TEST)**:26-8778 原行补写 generation/finalized(精确单行 UPDATE + 前后 SELECT 对比);该行后续(14:33-14:37)被测试改派流程取消,改派新组已带代际(finalized=1)。
## 行为变化
- 确认执行后的派车组(含与 legacy 遗留行共存的场景)预览返回可点行程链接,不再「暂不可」。
- 新 HOLD/DIRECT 派单创建即冻结代际(#5681 既有行为不变);本修复补充确认执行组级冻结,需求级最终快照事件语义不变。
- 短链解析侧代际升级兼容(哨兵→真实代)不变;取消派车后旧短链随身份失效(既有语义)。
## 前端动作
- 预览区「行程链接暂不可用,请联系车务确认」为业务降级文案:确认执行后(dispatchPlan 冻结前窗口)或派车组身份失效时展示;正常确认后展示可点链接(h5 行程契约页)。
- 无需字段适配;模板渲染接口行为与错误码口径不变。
## 验证证据
- 定向测试:+2(render 确认后已冻结全程行返回真实链接;legacy 遗留行共存时新组确认组级冻结且不误发需求级快照);confirm 相关 4 用例回归;保险并发确认测试补 stub 回归。
- 全量 verify 3294 tests 0 失败 4 skipped + spotless:check 通过。
- 网关实测(TEST,26-8778):渲染 200 返回真链接(https://web.test.1814.love:9443/s/t6wpsPy,8/17-8/20,有效期至 08-27);render-batch 200 + item success=true;H5 短链解析 200(行程契约 V2 全 4 天)。
- 部署:hl-fleet-service dev-v3=e95cfc89a 双实例 UP(14:52)。
## 前端实证确认(2026-08-09 mmg,hl-admin v2.1)
纯后端修复(确认执行组级冻结代际),前端无需改动:
- changelog §前端动作明确「无需字段适配;模板渲染接口行为与错误码口径不变」。
- 已 grep 实证:全 `src/` 无任何行程链接预览 / 「暂不可用」文案 / 短链解析 / `render-batch` / `dispatchPlan` 相关代码——行程链接预览为后端渲染(H5 / 网关)能力,hl-admin 不持有该预览组件或降级文案。
- 预览区「行程链接暂不可用」为后端业务降级文案,正常确认后由后端返回可点 h5 链接,前端无字段适配需求。
@@ -0,0 +1,108 @@
---
schema: "hl-changelog/v2"
ticket: "5698"
title: "改派修复:已派全程行改派生效(计费日期整段校验)+ 清除司机/车辆后槽位空态待重选"
consumer: "admin"
author: "wx(GIT)"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "mmg"
frontend_ref: "106aa658"
target_release: ""
verified_at: ""
status_note: "后端接口行为修复:POST /admin/fleet/assignments/ID/change 对已派全程行(service_date 为空、start/end 覆盖整个服务期)改派时,计费日期/费用快照/组派冲突检查按整段服务期展开——此前 serviceDateOf 只回退生效日第一天,前端按全部服务日提交计费日期即报「计费日期必须属于本派车组服务日期」,改派完全不生效(TEST 操作日志 13:59 连续 7 次 change_failed 实证)。修复后网关实证改派成功(双向往返均生效)。前端配合项见正文「前端交接」。"
updated_at: "2026-08-08"
base: "dev-v3"
generated: "2026-08-08T15:00:00+08:00"
---
# 改派修复:已派全程行改派生效 + 清除司机/车辆后槽位空态
> 后端完成:PR #5699 已合并 dev-v3(fb8945e97)并部署 TEST,网关验证通过(改派双向往返生效、现场已还原)。
## 关联 / 联系人
### 链接
- **Issue**: [#5698](https://git.1814.love:8443/wx/HL/issues/5698)
- **PR**: [#5699](https://git.1814.love:8443/wx/HL/pulls/5699)
- **关联**: [#5676](https://git.1814.love:8443/wx/HL/issues/5676)(按天改派)、[#5691](https://git.1814.love:8443/wx/HL/issues/5691)(回显全部服务日)
### 联系人
- 后端:wx(GIT)
- 前端配合:mmg / 协调台
---
## 背景(wx 实测)
改派页两个 bug:
1. **清除司机没清空**:点「清除车辆/司机」后槽位仍显示原车蒙A-E2E99+王信(已生效派车),用户以为没清空。
2. **统一改派确认后司机没变**:选新司机→确认→还是原司机,改派完全不生效("完全不懂")。
## 后端修复(#5698,已部署 TEST)
### Bug 2 根因
TEST 操作日志实证:订单 HL20260808105342627(蒙A-E2E99+王信,8/17-8/20 **全程行** service_date=NULL)13:59 连续 7 次 `change_failed`,报错均为:
> `参数非法: 计费日期必须属于本派车组服务日期`
已派全程行改派按整槽替换(#5595 语义),但 `resolveChargeableServiceDates` 用 `serviceDateOf()` 对全程行只回退到 **startDate 一天**;前端按全部服务日提交计费日期(#5691 回显全部服务日后的真实载荷)→ 校验失败 → change 抛异常回滚 → 改派不生效(前端静默失败)。
### 修复
`AssignmentService#changeTargetServiceDates`:全程行按 [startDate..endDate] **整段展开**,逐日切片行取自身 serviceDate;应用于改派 4 处——计费日期校验、对账期检查、组派冲突检查、替换行费用快照报价(quote 从只报第一天改为整段)。
**接口契约不变**(无新增/变更字段),仅修复既有行为。守卫不放宽:计费日期超出服务期仍拒绝;跨常驻组合仍要求确认(605036);无变化载荷仍拒绝(605029)。
### 验证
- 定向测试 `AssignmentServiceTest` 400 项全绿(新增 2 项:整段计费日期改派成功 + 越界日期仍拒绝);回归 210 项全绿;fleet verify 3293 项全绿;spotless 通过
- 网关实证(TEST,wx 实测现场):统一改派(effectiveDate=第一天 + 整段计费日期)到新司机/新车辆 **业务成功**(修复前 7 连败),替换行 assigned 全程形态 8/17-8/20;换回原派同样成功;现场已还原为 蒙A-E2E99+王信
## 前端交接(pending,需前端配合)
### 1. 清除司机/车辆后槽位显示空态(协调台定口径 B)
现状:改派页「清除车辆/司机」(#5662)只清**本次改派草稿**(不触发后端),槽位行继续显示已生效派车(蒙A-E2E99+王信)——用户误以为"没清空"。
期望(口径 B):清除后该槽位行显示**空态(待重选)**,用户明确"已清空",随后重新选择车/司机,提交改派生效。后端派单必须车+司机的终态不变(**改派提交前仍是原值**),清除只是前端进入"待重选"展示态。
- 相关代码:`src/views/fleet/board/components/AssignModal.vue`(`clearChangeAssignmentDraft` / `changeDraftCleared` / 槽位表「当前车辆/当前司机」列)
- 交互参考:清除后已有「已清除草稿,可重新选择」提示与「选择车辆/司机」入口,仅需将槽位表两列在 `changeDraftCleared=true` 时改为空态展示(如显示「待重新选择」)
- 验收:清除后槽位行不再显示原车/原司机;重选新司机提交后列表展示新司机
### 2. 统一改派链路
后端修复后,前端现有提交链路(`useAssignFlow.js` `buildAssignmentSubmission`:单次调 change、effectiveDate=第一天、不传 serviceDates、携带整段 chargeableServiceDates)可直接生效,无需改动。按天改派(serviceDates)不受影响。
## 变更接口
### `POST /admin/fleet/assignments/ID/change`(行为修复,接口契约不变)
- 已派全程行(`service_date` 为空、`start_date`/`end_date` 覆盖整个服务期)改派时,入参 `chargeableServiceDates` 允许携带该行覆盖的**全部服务日**(此前只认生效日第一天,其余日期报「计费日期必须属于本派车组服务日期」导致改派失败回滚)
- `chargeableServiceDates` 超出目标行服务期仍拒绝(守卫不放宽);其余入参语义不变(`effectiveDate` 必填、`serviceDates` 空=连续后缀整体改派、`newVehicleId`/`newDriverId` 可空=保留原值)
- 响应结构不变;替换行费用快照/报价按整段服务期计算(不再只算第一天)
## 前端/调用方动作
- 后端无动作:现有提交链路(单次调 change + effectiveDate=第一天 + 整段计费日期)修复后直接生效
- **前端配合项(pending)**:改派页「清除车辆/司机」后槽位行显示空态(待重选),不再显示原车/原司机——见上文「前端交接」
## 验证证据
- 定向测试:`AssignmentServiceTest` 400 项全绿(新增 2 项全程行整段计费日期改派成功/越界拒绝);回归 FleetAssignmentMapper 61 + 候选 50 + 快照 11 + 看板 88 全绿;fleet verify 3293 项全绿;spotless 通过
- 部署:TEST 滚动部署 hl-fleet-service 双实例 UP(8087/8187,dev-v3 @ fb8945e97)
- 网关实证(wx 实测现场 HL20260808105342627):统一改派到新司机/新车辆业务成功(修复前 7 连败),替换行 assigned 全程形态 8/17-8/20;换回原派同样成功;现场已还原
## 验收清单(本单)
- [x] 清除司机正常清空(司机+车辆都清)——口径 B 已定:前端清除后槽位空态待重选(**前端交接 pending**);后端终态语义不变
- [x] 统一改派确认后司机改成新选的(生效)——后端修复完成,TEST 网关实证双向往返生效
- [x] 定向测试 + PR 合并 + 部署 TEST + 网关验证——PR #5699 合并 dev-v3(fb8945e97),TEST 滚动部署双实例 UP,网关验证通过
- [x] changelog(yst 完整格式)——本文件
@@ -0,0 +1,88 @@
---
schema: "hl-changelog/v2"
ticket: "5701"
title: "登记司机确认不被「通知结果正在确认」拦截(人工确认直接成功)"
consumer: "admin"
author: "wx(GIT)"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "not_required"
frontend_owner: ""
frontend_ref: ""
target_release: ""
verified_at: ""
status_note: "后端完成:PR #5705/#5716/#5719 已合并 dev-v3 并部署 TEST(hl-fleet-service 双实例)。登记司机确认(MANUAL_CONTACT)与 confirm 确认执行均不再被 605042 拦截;已冻结 HOLD 组 confirm 不再误判 605020。全链路「登记确认→confirm assigned」网关实证走通(AMBIGUOUS+已冻结组 confirm 200 assigned)。前端交接见下(605042 场景收敛与错误提示口径)。"
updated_at: "2026-08-08"
base: "dev-v3"
generated: "2026-08-08T18:15:00+08:00"
---
# 登记司机确认不被「通知结果正在确认」拦截(人工确认直接成功)
> 后端完成:PR [#5705](https://git.1814.love:8443/wx/HL/pulls/5705) 已合并 dev-v3 并部署 TEST,网关全链路验证通过。
## 关联 / 联系人
### 链接
- **Issue**: [#5701](https://git.1814.love:8443/wx/HL/issues/5701)
- **PR**: [#5705](https://git.1814.love:8443/wx/HL/pulls/5705) / [#5716](https://git.1814.love:8443/wx/HL/pulls/5716) / [#5719](https://git.1814.love:8443/wx/HL/pulls/5719)
- **Merge commit**: [d28d2cd11](https://git.1814.love:8443/wx/HL/commit/d28d2cd11)
### 联系人
- **后端负责人**: @wx
## 背景
派单页点「登记司机已确认」报 **605042「司机通知结果正在确认,请稍后重试」**——HOLD 通知异步发送结果仍 AMBIGUOUS(短信网关未回执)时,人工登记被拦;连锁导致 confirm 确认执行报 605020(司机确认没登记上,状态未到可确认执行)。口径(wx):车务点确认就是确认——系统不知道司机线下结果,人工登记与异步通知结果应解耦。
## 变更说明(无接口契约变化,行为修正)
### `POST /admin/fleet/assignments/{assignmentId}/driver-confirmation` 行为变化
| 场景 | 变更前 | 变更后 |
|------|--------|--------|
| 通知结果确认中(AMBIGUOUS)+ **MANUAL_CONTACT** 人工联系登记 | 605042 拦截 | **直接登记成功** |
| 通知结果确认中(AMBIGUOUS)+ **NOTIFICATION** 通知回复来源 | 605042 拦截 | 400「无系统通知发送成功事实时必须显式选择人工联系来源」(更准确的引导) |
| 通知结果确认中 + 未显式指定来源 | 605042 拦截 | 400「无系统通知发送成功事实时必须显式选择人工联系来源」 |
| 通知已发送(SENT)/未发送(NOT_SENT/失败/取消) | 不变 | 不变 |
### `POST /admin/fleet/assignments/{assignmentId}/confirm` 行为变化(补修)
| 场景 | 变更前 | 变更后 |
|------|--------|--------|
| 通知结果确认中(AMBIGUOUS)+ 已登记司机确认 | 605042 拦截 | **直接推进 assigned**(同登记确认口径,与异步通知结果解耦) |
| 已冻结 HOLD 组(dispatch_plan_finalized=1,#5697 冻结方案常态) | **605020 误判**(组级冻结 CAS 对已冻结行幂等跳过,但断言要求全量更新,自相矛盾) | 正常推进 assigned(断言只覆盖未冻结行) |
### 不变的保护
- 其余 605042 保护点(expand 换版 / cancel / change / undo 等**通知代际推进与身份失效**场景)保留原拦截。
- NOTIFICATION 来源仍需通知 SENT 事实(原有校验不变)。
## 前端交接
1. **人工登记路径**:司机线下确认后,登记请求传 `driverReplySource=MANUAL_CONTACT`(+操作人)即可直接成功,不再需要等通知结果回执或重试。
2. **605042 在该端点不再出现**:前端可移除 driver-confirmation 的 605042 重试引导;通知未回执时若用户选「通知回复」来源,会收到 400 提示「请选择人工联系来源」,按文案展示即可。
3. **全链路**:登记确认成功后,`POST /{assignmentId}/confirm`(确认执行)即可走通 assigned(605020 连锁消除)。
## 验证证据
- **网关全链路(补修实证,TEST,holding 派单 2085978741208481793)**:通知 AMBIGUOUS(delivery_status=dispatching)+ 已冻结组(dispatch_plan_finalized=1)+ 已登记 MANUAL_CONTACT 司机确认 → `confirm` 确认执行 → **200 成功,confirmed=true、status=assigned**、返回行程 H5 链接(一次实证同时覆盖 AMBIGUOUS 放行与已冻结组 605020 修复)
- **单测**:新增 2 用例(AMBIGUOUS+MANUAL_CONTACT 登记成功并写凭证;AMBIGUOUS+未显式来源拒绝并提示人工联系),替换原 605042 拦截用例;AssignmentServiceTest **402/402 全绿**;spotless 通过
- **fleet verify**(mvn-throttle 错峰,Docker 原生 Testcontainers):仅 `ReleaseEOccupancyMysql8033RecoveryTest` 10 个基线失败(frozen Release E V002 SHA-256 发布产物缺失,与本案无关),其余 3286 全绿
- **部署**:hl-fleet-service 双实例 UP(15:29)
- **网关全链路**(TEST,VEHICLE_MANAGER,holding 派单 2085662146632224770):
- 构造通知 AMBIGUOUS(delivery_status=dispatching)→ `driver-confirmation` MANUAL_CONTACT 登记 → **200 直接成功**(修复前 605042)✓
- 通知恢复终态后 `confirm` 确认执行 → **200,confirmed=true、status=assigned**、返回行程 H5 链接、车辆/司机状态置 busy ✓(605020 连锁消除)
## 前端实证确认(2026-08-08 mmg,hl-admin)
确认 not_required 属实,零代码改动:
1. **前端唯一登记路径即 MANUAL_CONTACT**:`useAssignFlow.js:121 buildDriverConfirmationSubmission` 硬编码 `driverReplySource: 'MANUAL_CONTACT'`,注释明确「此入口只供后台人工电话/微信登记;必须与通知回执事实显式隔离」。后端变更后该路径在 AMBIGUOUS 时直接成功(修复前 605042 拦截),正是本修复目标,前端天然受益。
2. **无 605042 特判可移除**:grep 全 `src/` 无任何 605042 处理或「正在确认请稍后重试」重试引导;业务错误统一走 `request.js` 弹 `body.message`,后端返回文案原样展示(交接项 2 的「可移除重试引导」前端本就不存在)。
3. **不会触发新 400**:新 400「请选择人工联系来源」仅在 NOTIFICATION 来源或未显式指定来源时出现;前端永远显式 MANUAL_CONTACT,不会命中。
4. **confirm 确认执行**(2026-08-08 补修后更新):后端补修(PR #5716/#5719)已让 confirm 在 AMBIGUOUS + 已登记司机确认时**也不再被 605042 拦截**(与登记确认同口径解耦),并修复已冻结 HOLD 组(dispatch_plan_finalized=1)confirm 误判 605020。前端实证:全 `src/` 无任何 605042 业务处理;唯一 605020 引用是 `baselineDifference.spec.js:47` 断言它**不是**基线差异错误(即不特殊处理);confirm 提交链 `useAssignFlow.js:1095 confirmAssignment` 无错误码特判,错误统一走 `request.js` 弹后端 message。补修属后端行为放宽,前端天然受益,零改动——not_required 维持不变。
@@ -0,0 +1,334 @@
---
schema: "hl-changelog/v2"
ticket: "5704"
title: "核单域下线数据指纹乐观锁:6 个端点删除指纹/版本号入参与出参字段"
consumer: "admin"
change_type: "修改接口"
author: "yaosutu(GIT)"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "mmg"
frontend_ref: "d32e14b9"
target_release: ""
verified_at: ""
status_note: "PR #5709 已合并 dev-v3;核单域 6 个端点删除 expectedSourceFingerprint/version 入参与 sourceFingerprint/version 出参,错误码 584108/584110/584325 同步下线。字段删除属硬破坏契约,前端必须先停传这些字段再与后端同批发布。"
updated_at: "2026-08-08"
base: "dev-v3"
---
# 【⚠️ 修改接口·管理后台】核单域下线数据指纹乐观锁,6 个端点删除指纹/版本号字段(#5704)
> **PR**: [#5709](https://git.1814.love:8443/wx/HL/pulls/5709) | **服务**: hl-order-service-v3 | **更新时间**: 2026-08-08
## 1. 接口背景
核单为单人负责场景,不存在多人并发同时修改同一订单核单数据的情况。此前引入的数据指纹(sha256)/版本号乐观锁机制(前端 GET 拿到指纹,保存/确认/提交时回传,数据被他人改动则拒存)对单人操作无实际保护价值,且强制前端每次保存前 GET 并回传 64 位十六进制指纹,增加对接负担。本次将核单域内该机制整体下线:**删除 6 个端点的指纹/版本号入参字段与对应出参字段,3 个相关错误码不再触发**。
> ⚠️ 本次为**字段删除类硬破坏契约**:其中 5 个端点的请求体带未知字段白名单校验,前端若继续传已删除的字段会被拒绝(详见 §11)。**前端必须先删除这些字段的传参,再与后端同批发布。**
## 2. 变更清单
| # | 接口 | 方法 | 路径 | 变更类型 | 前端动作 |
|---|---|---|---|---|---|
| 1 | 保存导游费用 | PUT | `/v3/admin/order/{orderId}/settlement/guide-fees` | 删除入参 `expectedSourceFingerprint`、删除出参 `sourceFingerprint` | 停止传参/读字段 |
| 2 | 确认导游费用 | POST | `/v3/admin/order/{orderId}/settlement/guide-fees/confirm` | 删除入参 `expectedSourceFingerprint` | 停止传参 |
| 3 | 保存摄影费用 | PUT | `/v3/admin/order/{orderId}/settlement/photographer-fees` | 删除入参 `expectedSourceFingerprint`、删除出参 `sourceFingerprint` | 停止传参/读字段 |
| 4 | 确认摄影费用 | POST | `/v3/admin/order/{orderId}/settlement/photographer-fees/confirm` | 删除入参 `expectedSourceFingerprint` | 停止传参 |
| 5 | 保存车辆核单草稿 | PUT | `/v3/admin/order/{orderId}/settlement/step3/vehicles` | 删除入参 `version`、删除出参 `version` | 停止传参/读字段 |
| 6 | 完成核单 | POST | `/v3/admin/order/{orderId}/settlement/finalize` | 删除入参 `reimbursementExpectedSourceFingerprint`、`groupExpectedSourceFingerprint` | 停止传参 |
同时下线的错误码:`584108`、`584110`、`584325`(详见 §7)。
## 3. 接口详情
- **使用场景**:核单人员在订单核单页维护导游费用、摄影费用、车辆核单草稿,并在全部分类就绪后完成核单提交。
- **认证**:需要管理后台登录态(Bearer Token)。
- **幂等性**:保存类接口按订单维度覆盖式保存,重复提交相同载荷结果一致;确认/提交接口重放安全(不再有指纹前置校验)。
- **限流**:未声明接口专属限流。
- **方法/路径**:见 §2 变更清单(共 6 个端点;对应的 GET 查询端点出参同步删除指纹/版本号字段,见 §5)。
## 4. 接口入参
### 4.1 路径参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `orderId` | Long | 是 | 订单 ID,路径参数,6 个端点一致 |
### 4.2 请求体字段(变更后现状)
**PUT /settlement/guide-fees(保存导游费用)**
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `items` | Array | 是 | 导游费用明细全量集合,最多 200 条;每项含 `id`/`candidateKey`/`staffAssignmentId`/`serviceDate`/`name`/`serviceType`/`paymentMethod`/`amount`/`remark`/`voucherUrls`/`sourceResolution`/`candidateStatus` |
| `excludedCandidateKeys` | Array of String | 否 | 明确排除的候选 key;空数组表示本次不新增排除项 |
| ~~`expectedSourceFingerprint`~~ | - | - | **已删除,禁止再传**(传了会被 584128 白名单拒绝) |
**POST /settlement/guide-fees/confirm(确认导游费用)**
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `itemIds` | Array of Long | 是 | 待确认 INCLUDED 费用明细 ID 列表(JSON 中每项为字符串),1~200 条 |
| ~~`expectedSourceFingerprint`~~ | - | - | **已删除,禁止再传** |
**PUT /settlement/photographer-fees、POST /settlement/photographer-fees/confirm**:字段结构同导游两个端点,仅业务对象为摄影费用,删除字段同为 `expectedSourceFingerprint`。
**PUT /settlement/step3/vehicles(保存车辆核单草稿)**
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `items` | Array | 是 | 车辆核单全量明细 |
| ~~`version`~~ | - | - | **已删除,禁止再传**(传了会被白名单拒绝,返回 400) |
**POST /settlement/finalize(完成核单)**
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `remark` | String | 否 | 提交备注 |
| `reimbursementConfirmation` | Object | 条件必填 | 主报账确认凭据;含 `transferDate`(转账日期)、`transferRef`(转账流水号,主报账净额非 0 时必填,trim 后最长 128 字符)、`advanceSettledFlag`(预支是否已处理,必填布尔)、`signedVoucher`(签字凭证,至少 1 个 URL 非空文件:`files[{name,url}]` + `note`) |
| ~~`reimbursementExpectedSourceFingerprint`~~ | - | - | **已删除,禁止再传** |
| ~~`groupExpectedSourceFingerprint`~~ | - | - | **已删除,禁止再传** |
> 注:finalize 请求体未启用未知字段白名单,误传旧指纹字段会被**静默忽略**(不报 400),但前端仍应停止传参,避免依赖「传了也没事」的行为。
## 5. 出参字段
成功路径出参结构不变,仅删除指纹/版本号字段:
| 端点 | 删除的出参字段 | 原作用 |
|---|---|---|
| GET/PUT `/settlement/guide-fees`、POST `/settlement/guide-fees/confirm` 响应 | ~~`sourceFingerprint`~~ | 导游费用来源数据 sha256 指纹 |
| GET/PUT `/settlement/photographer-fees`、POST `/settlement/photographer-fees/confirm` 响应 | ~~`sourceFingerprint`~~ | 摄影费用来源数据指纹 |
| GET/PUT `/settlement/step3/vehicles` 响应 | ~~`version`~~ | 车辆核单草稿版本号 |
其余出参字段(如导游/摄影的 `category`/`totalAmount`/`cashPaidAmount`/`unconfirmedCount`/`pendingCandidateCount`/`settlementReady`/`blockReasonCode`/`items`/`editable`/`readOnlyReasonCode`,车辆的 `orderId`/`totalAmount`/`allConfirmed`/`settlementReady`/`blockReasonCode`/`items`/`frozen` 等)均无变化。前端不要再读取 `sourceFingerprint` / `version`,读取结果恒为 undefined。
## 6. 枚举 / 数据字典
本次不涉及枚举或字典的新增、删除、改值、改语义。`serviceType`(FULL_COURSE_GUIDE/LOCAL_GUIDE/COMMENTARY_SERVICE/TEMPORARY_SUPPLEMENT)、`paymentMethod`(COMPANY_PAID/CASH_PAID/SIGNED)、`blockReasonCode` 等既有取值不变。
## 7. 错误码
| code | 含义 | 本次变化 |
|---:|---|---|
| `584108` | 车辆核单明细已变化,请刷新 | **已删除,不再触发** |
| `584110` | 导游或摄影费用数据已变化,请刷新 | **已删除,不再触发** |
| `584325` | 核单提交指纹缺失(FINALIZE_FINGERPRINT_REQUIRED) | **已删除,不再触发** |
| `584315` | 核单来源数据已变化,请刷新后重新确认 | **仍在用**:车辆保存的来源数据漂移门禁改抛此码(承接原 584108 场景) |
| `584128` | 导游或摄影费用请求字段不合法:{具体原因} | 不变;前端误传已删除字段时由该码拒绝(见 §8.3) |
> 前端如曾对 `584108`/`584110`/`584325` 写过特判(专属提示/自动刷新分支),这些分支不会再命中,应移除;车辆来源漂移场景改判 `584315`。
## 8. 示例
### 8.1 典型成功(保存导游费用,不再回传指纹)
```http
PUT /v3/admin/order/2084000000000002978/settlement/guide-fees
Authorization: Bearer <token>
Content-Type: application/json
```
```json
{
"items": [
{
"id": "9001",
"candidateKey": null,
"staffAssignmentId": "11",
"serviceDate": "2026-08-08",
"name": "导游甲",
"serviceType": "FULL_COURSE_GUIDE",
"paymentMethod": "COMPANY_PAID",
"amount": "500.00",
"remark": null,
"voucherUrls": [],
"sourceResolution": null,
"candidateStatus": "COMPLETE"
}
],
"excludedCandidateKeys": []
}
```
```json
{
"code": 200,
"message": "success",
"data": {
"category": "GUIDE",
"totalAmount": "500.00",
"cashPaidAmount": "0.00",
"unconfirmedCount": 1,
"pendingCandidateCount": 0,
"settlementReady": false,
"blockReasonCode": "UNCONFIRMED_ITEMS",
"items": [],
"editable": true,
"readOnlyReasonCode": null
},
"success": true
}
```
> 注意:响应中已无 `sourceFingerprint` 字段。
### 8.2 边界(完成核单,不再传双指纹)
```http
POST /v3/admin/order/2084000000000002978/settlement/finalize
Authorization: Bearer <token>
Content-Type: application/json
```
```json
{
"remark": "核单完成",
"reimbursementConfirmation": {
"transferDate": "2026-08-08",
"transferRef": "TX20260808001",
"advanceSettledFlag": true,
"signedVoucher": {
"files": [{"name": "voucher.jpg", "url": "https://oss.example.com/voucher/1.jpg"}],
"note": null
}
}
}
```
```json
{"code": 200, "message": "success", "data": {"submitted": true}, "success": true}
```
### 8.3 业务失败(旧前端仍传已删除字段,被白名单拒绝)
场景 A:保存导游费用仍传 `expectedSourceFingerprint`。
```http
PUT /v3/admin/order/2084000000000002978/settlement/guide-fees
Authorization: Bearer <token>
Content-Type: application/json
```
```json
{
"expectedSourceFingerprint": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
"items": []
}
```
```json
{"code": 584128, "message": "导游或摄影费用请求字段不合法:导游费用请求不支持字段: expectedSourceFingerprint", "data": null, "success": false}
```
场景 B:保存车辆核单草稿仍传 `version`。
```http
PUT /v3/admin/order/2084000000000002978/settlement/step3/vehicles
Authorization: Bearer <token>
Content-Type: application/json
```
```json
{
"version": 3,
"items": []
}
```
```json
{"code": 400, "message": "请求数据格式错误:车辆核单请求不支持字段: version", "data": null, "success": false}
```
## 9. 业务边界
- ✅ 保存/确认/提交不再要求前端先 GET 取指纹,可直接操作;单人负责场景下后写覆盖先写,与既有使用方式一致。
- ✅ 车辆保存仍保留「来源数据漂移」业务门禁:草稿加载后若派单/用车来源数据已变化,保存时返回 `584315`,提示刷新后重新确认——这不是乐观锁,是业务一致性校验。
- ❌ 导游/摄影 4 个端点与车辆保存端点对请求体做字段白名单校验,**任何未知字段都会被拒**(含本次删除的指纹/版本号字段),不要把查询响应整个 echo 回请求体。
- ❌ 已终态(冻结)的核单数据仍不可编辑,该约束与本次变更无关,保持不变。
### 9.1 保存时必须剥掉的只读派生字段(导游/摄影)
导游/摄影保存接口(PUT guide-fees / photographer-fees)的 GET 响应 items[] 里含有后端计算的只读派生字段,**保存回传时必须剥掉**,否则触发白名单 400(错误码 584128「不支持字段: xxx」)。
必须剥掉的字段:
| 字段 | 含义 |
|---|---|
| `sourceType` / `sourceTypeName` | 来源类型及中文名 |
| `sourceActive` | 来源是否仍有效 |
| `serviceTypeName` | 导游服务类型中文名 |
| `feeTypeName` | 摄影费用类型中文名 |
| `paymentMethodName` | 付款方式中文名 |
| `settlementConfirmStatus` / `settlementConfirmStatusName` | 核算确认状态及中文名 |
| `candidateResolution` | 候选处理结果 |
通则:**所有 `*Name` 中文字段 + `sourceType`/`sourceActive` + 确认状态 + 候选处理结果,都是后端算的,保存一律不回传。** 推荐前端保存前按允许字段重建 payload(维护 toSaveItem 映射),不要把 GET 响应对象整个 echo 回去。
## 10. 修改前后对比
### 10.1 字段级对比
| 端点 | 字段 | 原来 | 现在 |
|---|---|---|---|
| PUT guide-fees / photographer-fees | `expectedSourceFingerprint` | 入参,回传 GET 拿到的指纹 | **已删除** |
| POST guide-fees/confirm、photographer-fees/confirm | `expectedSourceFingerprint` | 入参 | **已删除** |
| GET/PUT guide-fees、photographer-fees 响应 | `sourceFingerprint` | 出参,64 位十六进制 | **已删除** |
| PUT step3/vehicles | `version` | 入参,草稿版本号 | **已删除** |
| GET/PUT step3/vehicles 响应 | `version` | 出参,整数版本号 | **已删除** |
| POST finalize | `reimbursementExpectedSourceFingerprint`、`groupExpectedSourceFingerprint` | 入参,双指纹 | **已删除** |
### 10.2 行为级对比
| 场景 | 原来 | 现在 |
|---|---|---|
| 保存导游/摄影费用 | 必须先 GET 取 `sourceFingerprint` 回传,指纹不匹配返回 584110 | 直接保存,无指纹校验 |
| 保存车辆核单草稿 | 必须回传 `version`,不匹配返回 584108 | 直接保存;来源数据漂移改返回 584315 |
| 完成核单提交 | 必须传主报账+单团核算双指纹,缺失返回 584325 | 直接提交,无指纹校验 |
| 请求体含已删除字段 | 正常受理 | 导游/摄影返回 584128、车辆返回 400;finalize 静默忽略 |
## 11. 影响评估 / 回滚
### 11.1 影响评估
- **是否破坏向后兼容**:**是,硬破坏**。导游/摄影 4 个端点 + 车辆保存端点带请求体字段白名单,旧前端继续传 `expectedSourceFingerprint` / `version` 会被拒绝(584128 / 400),核单保存、确认链路直接不可用。
- **前端是否必须同步上线**:**必须同批**。前端需先删除上述字段的传参与读取,再与后端同批发布;旧前端 + 新后端 = 核单保存/确认全部报错。
- **上线顺序边界**:前后端同批发布;若必须分先后,**先上前端(停传字段),再上后端**。
- **前端特判清理**:移除对 `584108`/`584110`/`584325` 的特判;车辆来源漂移提示改挂 `584315`。
### 11.2 回滚方案
- 后端回滚即恢复原指纹契约;但已改造的新前端(不传指纹)在旧后端上会触发指纹校验失败——**回滚必须前后端同批回滚**。
- 数据侧无迁移:指纹/版本号不持久化在业务表,回滚无数据修复成本。
## 12. 注意事项
- 本次只下线核单域内上述 6 个端点的指纹机制;应收总览/逐条优惠确认的指纹错误码 `584300`/`584302`(OVERVIEW_FINGERPRINT_EXPIRED / DISCOUNT_FINGERPRINT_EXPIRED)**不在本次范围,仍在用**,相关确认接口的指纹传参保持不变。
- 保存类接口幂等语义不变:按订单维度覆盖式全量保存,重复提交相同载荷结果一致。
- 排查用户报错时,`584128` / 400 的 message 已含具体不支持的字段名,可直接据此定位前端是否还在传旧字段。
- 小程序端(/v3/mp/*)不涉及本次变更,无需任何改动。
## 13. 关联 / 联系人
### 13.1 链接
- **Issue**: [#5704](https://git.1814.love:8443/wx/HL/issues/5704)
- **代码 PR**: [#5709](https://git.1814.love:8443/wx/HL/pulls/5709)
- **文档 PR**: [#5711](https://git.1814.love:8443/wx/HL/pulls/5711)
### 13.2 联系人
- **后端负责人**: @yaosutu (yst)
## 前端实证确认(2026-08-08 mmg,hl-admin@d32e14b9)
已按契约停传/停读全部指纹/版本号字段,清理下线错误码特判:
- **入参删除**:保存导游/摄影 `buildStaffFeeTabSaveRequest` 不再传 `expectedSourceFingerprint`(含回退 #5674 给导游强制传指纹的逻辑——该 changelog 已撤回并入本单);保存车辆 `buildVehicleSaveRequest` 删 `version`;finalize 删 `reimbursementExpectedSourceFingerprint`/`groupExpectedSourceFingerprint`。人员/车辆保存 items 白名单重建(不回传 sourceType/settlementConfirmStatus 等只读字段)保留不动。
- **出参停读**:报告适配不再投影 `sourceFingerprint`;GET 回读不再持久化车辆 version / 人员指纹。
- **错误码特判**:车辆来源漂移恢复分支 584108 改挂 **584315**(恢复语义不变:丢弃过期草稿+GET 回读权威明细+提示重新核对);人员 584110/584108 指纹冲突分支删除(下线后不再命中);584325 下线清理。584300/584302(应收总览/优惠确认指纹)不在范围,未触碰;`attachRefreshedDetailForReportError` 报告侧 584312/584314/584315 刷新逻辑保留。
- **UI 门禁**:`detail.vue canComplete` 由「持有双报告指纹」放宽为「双报告已生成」(finalize 前 service 层双报告 GET 的 584311/584313 保护仍在,指纹门禁本是 UI 冗余);`ReportModal` 凭据表单重置改用报告快照引用触发(语义等价)。
- **前端未接 confirm 端点**:grep 确认无 `guide-fees/confirm`、`photographer-fees/confirm` 调用,6 端点中实际涉及 4 个。
- 验证:settlement + orderV2 定向 vitest 105/105 通过;checkpoint(含 Vitest 全量 + 生产构建)全绿。
@@ -0,0 +1,256 @@
---
schema: "hl-changelog/v2"
ticket: "5708"
title: "核单车辆下拉新增车型当日牌价 dayPrice(参考价,非最终核算价)"
consumer: "admin"
change_type: "修改接口"
author: "yaosutu(GIT)"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "mmg"
frontend_ref: "a9ddbd48"
target_release: ""
verified_at: ""
status_note: "PR #5713 已合并 dev-v3;GET /v3/admin/order/{orderId}/settlement/vehicle-options 出参 data[] 新增 dayPrice 字段(车型当日牌价,元/车天)。dayPrice 是参考价非最终核算价,最终核算价以派单后车辆快照 dailyPrice / 核单行 amount 为准。"
updated_at: "2026-08-08"
base: "dev-v3"
---
# 【修改接口·管理后台】核单车辆下拉新增车型当日牌价 dayPrice(#5708)
> **PR**: [#5713](https://git.1814.love:8443/wx/HL/pulls/5713) | **服务**: hl-order-service-v3 | **更新时间**: 2026-08-08
## 1. 接口背景
核单 Step3 车辆 Tab 的车辆下拉选项接口,此前只返回车牌 / 车型 / 司机等基础信息,核单人员看不到该车型当日的参考牌价,选车时无法预估金额。本次在出参 `data[]` 新增 `dayPrice` 字段,按订单出发日期取该车型当日定价,**仅供前端展示参考,不是最终核算价**。
## 2. 变更清单
| # | 接口 | 方法 | 路径 | 变更类型 | 前端动作 |
|---|---|---|---|---|---|
| 1 | 查询核单车辆异步下拉 | GET | `/v3/admin/order/{orderId}/settlement/vehicle-options` | 出参新增字段 | 读取 `data[].dayPrice`,建议标注"参考价" |
## 3. 接口详情
- **使用场景**:核单人员在订单核单 Step3 车辆 Tab 选择车辆时,通过关键字异步搜索候选车辆。
- **认证**:需要管理后台登录态(Bearer Token)。
- **幂等性**:是,只读查询。
- **限流**:未声明接口专属限流。
## 4. 接口入参
### 4.1 路径参数 / Query 参数
| 字段 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
| `orderId` | Path | Long | 是 | 订单 ID |
| `keyword` | Query | String | 否 | 可匹配车牌、品牌型号、车型大类和常驻司机姓名 |
| `limit` | Query | Integer | 否 | 由 Fleet 按默认 10、最大 20 处理 |
### 4.2 请求体字段
GET 请求无请求体。
## 5. 出参字段
响应类型:`Result<List<SettlementVehicleOptionRespVO>>`。
### 5.1 统一响应外层
| 字段 | 类型 | 可空 | 说明 |
|---|---|---|---|
| `code` | Integer | 否 | 成功为 `200`;失败见 §7 |
| `message` | String | 否 | 结果说明 |
| `data` | Array | 失败时为空 | 成功时为车辆下拉选项数组 |
| `success` | Boolean | 否 | `code=200` 时为 `true` |
### 5.2 `data[]` 字段(共 8 个)
| 字段 | 类型 | 可空 | 说明 |
|---|---|---|---|
| `vehicleId` | String(Long) | 否 | 车辆 ID |
| `plate` | String | 否 | 车牌号 |
| `modelName` | String | 否 | 车型名称 |
| `typeName` | String | 否 | 车型大类 |
| `primaryDriverId` | String(Long) | 是 | 常驻司机 ID |
| `primaryDriverName` | String | 是 | 常驻司机姓名 |
| `label` | String | 否 | 下拉展示文案(车牌/车型/大类/司机拼接) |
| **`dayPrice`** | **Decimal** | **是** | **车型当日牌价(元/车天),本次新增**;语义见下 |
### 5.3 `dayPrice` 语义(**重点,前端必读**)
- **是参考价,不是最终核算价**:`dayPrice` 来自 fleet 车型定价日历(按订单出发日 `departDate` 取当日牌价,未定价日回退车型 `basePrice`)。
- **最终核算价以派单后车辆快照 `dailyPrice` / 核单行 `amount` 为准**。前端展示 `dayPrice` 时应标注"参考价",避免误导核单人员把它当成结算价。
- **fleet 未上线该字段前 `dayPrice` 为 `null`**(向前兼容);fleet 侧现已上线(配套 Issue #5706),正常出值。
## 6. 枚举 / 数据字典
本次不涉及枚举新增或改值。
## 7. 错误码
| code | 含义 | 触发场景 |
|---:|---|---|
| `400` | 请求参数错误 | `orderId` 非法(如 0、负数、非数字) |
| `581007` | 订单不存在 | `orderId` 对应订单不存在 |
| `584071` | 无权访问该订单 | 当前账号不在订单可访问范围内 |
## 8. 示例
### 8.1 典型成功 —— 返回含 dayPrice
**请求**:
```http
GET /v3/admin/order/2084000000000002978/settlement/vehicle-options?keyword=汉兰达&limit=10
Authorization: Bearer <token>
```
无请求体。
**响应**:
```json
{
"code": 200,
"message": "success",
"data": [
{
"vehicleId": "301",
"plate": "蒙A88888",
"modelName": "丰田汉兰达",
"typeName": "SUV",
"primaryDriverId": "45",
"primaryDriverName": "张师傅",
"label": "蒙A88888 丰田汉兰达 SUV 张师傅",
"dayPrice": "1000.00"
},
{
"vehicleId": "302",
"plate": "蒙A66666",
"modelName": "丰田汉兰达",
"typeName": "SUV",
"primaryDriverId": "46",
"primaryDriverName": "李师傅",
"label": "蒙A66666 丰田汉兰达 SUV 李师傅",
"dayPrice": "1000.00"
}
],
"success": true
}
```
### 8.2 边界情况 —— 车型当日未定价时 dayPrice 回退 basePrice 或为 null
**场景说明**:某车型在订单出发日未配置定价日历时,后端回退取车型 `basePrice`;若 fleet 侧未上线该字段则返回 `null`。
**请求**:
```http
GET /v3/admin/order/2084000000000002978/settlement/vehicle-options?keyword=别克&limit=10
Authorization: Bearer <token>
```
无请求体。
**响应**:
```json
{
"code": 200,
"message": "success",
"data": [
{
"vehicleId": "305",
"plate": "蒙A11111",
"modelName": "别克GL8",
"typeName": "MPV",
"primaryDriverId": "47",
"primaryDriverName": "王师傅",
"label": "蒙A11111 别克GL8 MPV 王师傅",
"dayPrice": null
}
],
"success": true
}
```
前端拿到 `dayPrice: null` 时应展示为 "—" 或不显示该行参考价,**不要展示为 `0`**。
### 8.3 业务失败 —— orderId 非法返 400
**请求**:
```http
GET /v3/admin/order/0/settlement/vehicle-options?keyword=汉兰达
Authorization: Bearer <token>
```
无请求体。
**响应**:
```json
{"code": 400, "message": "请求参数错误", "data": null, "success": false}
```
## 9. 业务边界
- **适用场景**:核单车辆下拉展示参考牌价,辅助核单人员选车预估金额。
- **不适用场景**:**不要把 `dayPrice` 当作最终核算价**展示在结算明细里;最终价以派单后快照 `dailyPrice` / 核单行 `amount` 为准。
- **特殊边界**:`dayPrice` 为 `null` 时表示 fleet 侧暂无该车型当日定价数据,不等于"免费";展示时应与 `0.00` 区分。
## 10. 修改前后对比
### 10.1 字段级对比
| 字段 | 原来 | 现在 |
|---|---|---|
| `data[].dayPrice` | 不存在 | **新增**;Decimal,可空 |
其余 7 个字段(`vehicleId`/`plate`/`modelName`/`typeName`/`primaryDriverId`/`primaryDriverName`/`label`)无变化。
### 10.2 行为级对比
| 行为 | 原来 | 现在 |
|---|---|---|
| 车辆下拉展示 | 只有车牌/车型/司机 | 新增当日参考牌价 |
## 11. 影响评估 / 回滚
### 11.1 影响评估
- **是否破坏向后兼容**:否。仅出参新增字段,旧前端不读 `dayPrice` 即可继续工作。
- **前端是否必须同步上线**:否。字段为增强信息,前端可择机上线展示。
### 11.2 回滚方案
- 回滚即出参不再返回 `dayPrice`;已上线的新前端应把 `dayPrice` 作为可选字段处理(读到就展示、读不到就不展示),天然兼容回滚。
## 12. 注意事项
- **`dayPrice` 是参考价**,前端展示建议加"参考价"标注,避免与最终核算价混淆。
- fleet 侧配套改动见 Issue #5706;fleet 未上线前 `dayPrice` 恒为 `null`,前端需做 null 兜底展示。
- `dayPrice` 单位为元/车天(整段行程 1 天的价格),不是整段总价。
## 13. 关联 / 联系人
### 13.1 链接
- **Issue**: [#5708](https://git.1814.love:8443/wx/HL/issues/5708)
- **PR**: [#5713](https://git.1814.love:8443/wx/HL/pulls/5713)
- **Merge commit**: [10ba85d65](https://git.1814.love:8443/wx/HL/commit/10ba85d65eca08fa5b1f9da60a4e8c9cfd318938)
- **配套 fleet 侧 Issue**: [#5706](https://git.1814.love:8443/wx/HL/issues/5706)
### 13.2 联系人
- **后端负责人**: @yaosutu (yst)
- **fleet 侧对接**: @wx
## 前端实证确认(2026-08-08 mmg,hl-admin@a9ddbd48)
- 前端已接该下拉接口:`use-settlement-vehicle-options.js` 此前 `OPTION_FIELDS` 只投影 7 个契约字段(不含 dayPrice)。
- 修复:OPTION_FIELDS 与候选 option 增加 `dayPrice`(null 归一为 null);CategoryTable `renderVehicleSelect` 新增 `renderLabel(option, selected)`——**下拉项**追加「参考价 ¥x/车天」角标(teleport 弹层用内联样式,scoped 选不中),**选中态**只显示车牌文案不带参考价;`dayPrice` 为 null 时显「—」,不当作 0 也不当最终核算价。
- 保存契约安全:`select()` 写回 source 的字段显式列出(vehicleId/vehicleModelId/vehicleModelName/driverId/driverName),dayPrice 不进 source、不进 step3/vehicles 保存 payload。
- 验证:settlement 全量定向 vitest 93/93 通过(含候选 option 携带 dayPrice 断言);checkpoint 全绿。
@@ -0,0 +1,273 @@
---
schema: "hl-changelog/v2"
ticket: "5712"
title: "车辆核单 FLEET 行核算金额放开可编辑(amount 不再撞 584109)"
consumer: "admin"
change_type: "修改接口"
author: "yaosutu(GIT)"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "mmg"
frontend_ref: "a9ddbd48"
target_release: ""
verified_at: ""
status_note: "PR #5715 已合并 dev-v3;PUT /v3/admin/order/{orderId}/settlement/step3/vehicles 对 FLEET 来源行的 amount 字段从只读放开为可编辑,结构字段仍受 584109 保护。前端若把 amount 渲染为只读输入框,应放开为可编辑。"
updated_at: "2026-08-08"
base: "dev-v3"
---
# 【修改接口·管理后台】车辆核单 FLEET 行核算金额放开可编辑(#5712)
> **PR**: [#5715](https://git.1814.love:8443/wx/HL/pulls/5715) | **服务**: hl-order-service-v3 | **更新时间**: 2026-08-08
## 1. 接口背景
核单 Step3 车辆 Tab 的全量保存接口此前对 **FLEET(车务)来源行** 的 `amount`(核算金额)做只读保护:前端把 GET 回显的金额改大/改小后回传,会被错误码 `584109`「车务来源字段不可直接修改或删除」拦截,接口虽然返回 200 但 message 提示、金额实际不变。
业务诉求:核单人员需要能对车务来源的核算金额做手工修正(实际结算价与车务快照价不一致的场景,与住宿/门票核单的人工调价口径一致)。本次放开 FLEET 行 `amount` 可编辑,**改完即生效、不留审计痕**。
## 2. 变更清单
| # | 接口 | 方法 | 路径 | 变更类型 | 前端动作 |
|---|---|---|---|---|---|
| 1 | 全量保存车辆核单草稿 | PUT | `/v3/admin/order/{orderId}/settlement/step3/vehicles` | 行为放开(字段零变化) | FLEET 行 `amount` 输入框由只读改可编辑 |
| 2 | 查询车辆核单草稿 | GET | `/v3/admin/order/{orderId}/settlement/step3/vehicles` | 出参语义变化 | `items[].amount` 现返回覆盖层修正后金额 |
## 3. 接口详情
- **使用场景**:核单人员在订单核单 Step3 车辆 Tab 维护车辆核单明细(全量覆盖式保存)。
- **认证**:需要管理后台登录态(Bearer Token)。
- **幂等性**:是,按订单维度全量覆盖式保存,重复提交相同载荷结果一致。
- **限流**:未声明接口专属限流。
## 4. 接口入参
### 4.1 路径参数
| 字段 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
| `orderId` | Path | Long | 是 | 订单 ID |
### 4.2 请求体字段
| 字段 | 类型 | 必填 | 校验规则 | 本次是否放开 |
|---|---|---|---|---|
| `items` | Array | 是 | 全量明细 | — |
| `items[].id` | Long | 条件必填 | 既有行必传;新增手工行为 null | 否(仍受 584109 保护) |
| `items[].sourceType` | String | 是 | `FLEET` / `MANUAL` | 否 |
| `items[].serviceDate` | String(date) | 是 | `yyyy-MM-dd` | 否(仍受 584109 保护) |
| `items[].vehicleId` | Long | 条件必填 | FLEET 行必传 | 否(仍受 584109 保护) |
| `items[].vehiclePlate` | String | 否 | 最长 64 | 否(仍受 584109 保护) |
| `items[].vehicleModelId` | Long | 否 | — | 否(仍受 584109 保护) |
| `items[].vehicleModelName` | String | 否 | 最长 128 | 否(仍受 584109 保护) |
| `items[].driverId` | Long | 否 | — | 否(仍受 584109 保护) |
| `items[].driverName` | String | 否 | 最长 64 | 否(仍受 584109 保护) |
| `items[].amount` | Decimal | 是 | 非负、最多 2 位小数 | **本次放开为可编辑** |
| `items[].paymentMethod` | String | 是 | `CASH_PAID` / `SIGNED` / `COMPANY_PAID` | 否(仍受 584109 保护) |
| `items[].settlementConfirmStatus` | String | 是 | `UNCONFIRMED` / `CONFIRMED` | 否(本就可改) |
| `items[].remark` | String | 否 | 最长 500 | 否(本就可改) |
| `items[].voucherUrls` | String[] | 否 | 最多 9 个 URL | 否(本就可改) |
> **FLEET 行编辑约定**:`vehicleFeeLineId`(即 GET 回显的 `items[].id`)、`serviceDate`、`vehicleId`、`vehiclePlate`、`vehicleModelId`、`vehicleModelName`、`driverId`、`driverName`、`paymentMethod` 这 9 个**车务来源结构字段不允许改**,前端应把这些字段**原样回传**(来自 GET step3/vehicles 的回显值),只允许改 `amount`(以及 `remark` / `voucherUrls` / `settlementConfirmStatus`)。改了结构字段仍撞 `584109`。
## 5. 出参字段
成功响应为统一 `Result` 结构,`code=200`。`data` 出参字段(`orderId` / `totalAmount` / `allConfirmed` / `settlementReady` / `blockReasonCode` / `items` / `frozen`)结构无变化。
**唯一语义变化**:GET `items[].amount` 现在返回**覆盖层修正后的金额**(改完再查就是新值),不再被 fleet 快照价覆盖。
## 6. 枚举 / 数据字典
本次不涉及枚举新增或改值。`paymentMethod`(CASH_PAID/SIGNED/COMPANY_PAID)、`settlementConfirmStatus`(UNCONFIRMED/CONFIRMED)、`sourceType`(FLEET/MANUAL)取值不变。
## 7. 错误码
| code | 含义 | 触发场景 |
|---:|---|---|
| `584109` | 车务来源字段不可直接修改或删除 | 改了 FLEET 行的结构字段(serviceDate/vehicleId/vehiclePlate/vehicleModelId/vehicleModelName/driverId/driverName/paymentMethod/vehicleFeeLineId)或试图删除 FLEET 行 |
| `400` | 请求数据格式错误 | `amount` 为负数 / 小数位超过 2 位 / 数值超出范围 / 其他 Bean 校验失败 |
## 8. 示例
### 8.1 典型成功 —— FLEET 行 amount 由 800 改为 950
**请求**:
```http
PUT /v3/admin/order/2084000000000002978/settlement/step3/vehicles
Authorization: Bearer <token>
Content-Type: application/json
```
```json
{
"items": [
{
"id": "9001",
"sourceType": "FLEET",
"serviceDate": "2026-08-08",
"vehicleId": "301",
"vehiclePlate": "蒙A88888",
"vehicleModelId": "21",
"vehicleModelName": "丰田汉兰达",
"driverId": "45",
"driverName": "张师傅",
"amount": "950.00",
"paymentMethod": "COMPANY_PAID",
"settlementConfirmStatus": "UNCONFIRMED",
"remark": "实际结算价高于快照",
"voucherUrls": []
}
]
}
```
**响应**:
```json
{"code": 200, "message": "success", "data": {"saved": true}, "success": true}
```
随后 GET 同一订单 step3/vehicles,`items[].amount` 返回 `"950.00"`。
### 8.2 边界情况 —— amount 改为 0.00 仍合法
**场景说明**:金额下限为 `0.00`,0 元合法(不是"未填")。
**请求**:
```http
PUT /v3/admin/order/2084000000000002978/settlement/step3/vehicles
Authorization: Bearer <token>
Content-Type: application/json
```
```json
{
"items": [
{
"id": "9001",
"sourceType": "FLEET",
"serviceDate": "2026-08-08",
"vehicleId": "301",
"vehiclePlate": "蒙A88888",
"vehicleModelId": "21",
"vehicleModelName": "丰田汉兰达",
"driverId": "45",
"driverName": "张师傅",
"amount": "0.00",
"paymentMethod": "COMPANY_PAID",
"settlementConfirmStatus": "UNCONFIRMED",
"remark": null,
"voucherUrls": []
}
]
}
```
**响应**:
```json
{"code": 200, "message": "success", "data": {"saved": true}, "success": true}
```
### 8.3 业务失败 —— 改了 FLEET 行结构字段 vehiclePlate 撞 584109
**场景说明**:仅放开 `amount`;结构字段(如车牌)仍受保护。
**请求**:
```http
PUT /v3/admin/order/2084000000000002978/settlement/step3/vehicles
Authorization: Bearer <token>
Content-Type: application/json
```
```json
{
"items": [
{
"id": "9001",
"sourceType": "FLEET",
"serviceDate": "2026-08-08",
"vehicleId": "301",
"vehiclePlate": "蒙A99999",
"vehicleModelId": "21",
"vehicleModelName": "丰田汉兰达",
"driverId": "45",
"driverName": "张师傅",
"amount": "950.00",
"paymentMethod": "COMPANY_PAID",
"settlementConfirmStatus": "UNCONFIRMED",
"remark": null,
"voucherUrls": []
}
]
}
```
**响应**:
```json
{"code": 584109, "message": "车务来源字段不可直接修改或删除", "data": null, "success": false}
```
## 9. 业务边界
- **适用场景**:FLEET 行 `amount` 可任意改(非负、最多 2 位小数);改完即生效,**不留审计痕**,与住宿/门票核单人工调价口径一致。
- **不适用场景**:FLEET 行的结构字段(车牌 / 司机 / 服务日期 / 车型 / 付款方式 / 行 id)仍不允许改;如需换车换司机请走车务派单链路,不要在核单页改。
- **特殊边界**:`amount` 改为 `0.00` 是合法值,不是"清空";MANUAL 行的所有字段本就可改,本次无变化。
## 10. 修改前后对比
### 10.1 字段级对比
| 字段 | 原来 | 现在 |
|---|---|---|
| FLEET 行 `amount` | 只读;改值撞 `584109`(PUT 返回 200 但 message 提示、金额不变) | **可编辑**;值合法即落库 |
| FLEET 行结构字段(车牌/司机/日期/车型/付款方式) | 只读,撞 `584109` | 仍只读,撞 `584109`(不变) |
| GET `items[].amount` | 返回 fleet 快照价 | 返回**覆盖层修正后**金额 |
### 10.2 行为级对比
| 行为 | 原来 | 现在 |
|---|---|---|
| 前端把 FLEET 行 amount 改大/改小回传 | 被 `584109` 拦截,金额不变 | 正常保存,GET 回读新值 |
| 前端改 FLEET 行 vehiclePlate | `584109` | `584109`(不变) |
## 11. 影响评估 / 回滚
### 11.1 影响评估
- **是否破坏向后兼容**:否。接口签名、字段、错误码零变化;仅放开一个字段的编辑限制。
- **前端是否必须同步上线**:否。旧前端继续把 amount 渲染为只读输入框不影响功能;但建议尽快放开为可编辑以匹配新口径。
### 11.2 回滚方案
- 回滚即恢复 amount 只读保护,旧前端(amount 只读)天然兼容;已改为可编辑的新前端在旧后端上保存会重新撞 `584109`,需前后端同批回滚。
## 12. 注意事项
- 本次仅放开 `amount`;**不要把 FLEET 行其他结构字段也放开为可编辑**。
- 前端在 FLEET 行编辑表单里,`amount` 用 number input 即可,提交前按"非负、最多 2 位小数"做一次本地校验可减少 400。
- 若前端历史上有"FLEET 行 amount 改了被静默回滚"的 workaround(如改完强刷 GET 重新渲染),本次后可保留也可简化,无破坏性。
## 13. 关联 / 联系人
### 13.1 链接
- **Issue**: [#5712](https://git.1814.love:8443/wx/HL/issues/5712)
- **PR**: [#5715](https://git.1814.love:8443/wx/HL/pulls/5715)
- **Merge commit**: [d4fce1230](https://git.1814.love:8443/wx/HL/commit/d4fce12309dd3c2ad040ee5d71e9734cb1b8ad5b)
### 13.2 联系人
- **后端负责人**: @yaosutu (yst)
## 前端实证确认(2026-08-08 mmg,hl-admin@a9ddbd48)
- 前端 FLEET 行 amount 此前确为只读:`returnDetailAdapter.js adaptVehicleRows` 对 FLEET 行 `editableFields=['confirmStatus','note']`(缺 amount),CategoryTable `rowFieldEditable` 据此把 amount 渲染为只读。
- 修复:FLEET 行 editableFields 改为 `['amount','confirmStatus','note']`,amount 输入框放开可编辑;结构字段(车牌/司机/日期/车型/付款方式/id)仍不在 editableFields,保持只读(与后端 584109 保护一致)。凭证列由 `canEditRowVoucher` 独立判定(不看 editableFields),本就开放,无需改。
- 保存链路 `buildVehicleSaveRequest` 本就把 `row.amount` 透传进 `items[].amount`、结构字段从 `source.*` 原样回传,无需改——金额改完随全量保存生效。
- 验证:settlement 全量定向 vitest 93/93 通过(含更新 `editableFields` 断言);checkpoint 全绿。
@@ -0,0 +1,79 @@
---
schema: "hl-changelog/v2"
ticket: "5725"
title: "confirm 确认执行两路径一致解除「通知结果确认中」拦截(含原子引擎整组路径)"
consumer: "admin"
author: "wx(GIT)"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "not_required"
frontend_owner: ""
frontend_ref: ""
target_release: ""
verified_at: ""
status_note: "后端完成:PR #5726 已合并 dev-v3 并部署 TEST(hl-fleet-service 双实例)。confirm 单段与整组(需求级原子引擎)两路径一致解除 AMBIGUOUS 605042 拦截;实证 26-5484(修复前 605042)与回归 26-8917 均 confirm 200 assigned。接口响应结构不变,无前端消费变化。"
updated_at: "2026-08-08"
base: "dev-v3"
generated: "2026-08-08T21:45:00+08:00"
---
# confirm 确认执行两路径一致解除「通知结果确认中」拦截(含原子引擎整组路径)
> 后端完成:PR [#5726](https://git.1814.love:8443/wx/HL/pulls/5726) 已合并 dev-v3 并部署 TEST,网关全链路验证通过。
## 关联 / 联系人
### 链接
- **Issue**: [#5725](https://git.1814.love:8443/wx/HL/issues/5725)
- **PR**: [#5726](https://git.1814.love:8443/wx/HL/pulls/5726)
- **Merge commit**: [483cfd1ba](https://git.1814.love:8443/wx/HL/commit/483cfd1ba)
### 联系人
- **后端负责人**: @wx
## 背景
#5716 修复时只移除了单段 confirm **legacy 路径**(无派车方案代际)的「通知结果确认中」校验;**有代际的确认走需求级原子引擎路径**(`confirmSingletonThroughRequirementEngine` → `confirmRequirement`),其中 `isRequiredHoldingGroup` 分支残留同类校验,AMBIGUOUS 仍 605042。
实证对照(TEST):26-5484(单代 finalized=1 → 原子路径)confirm 被 605042 拦;26-8917(成功时刻为旧行 finalized=0/orphaned 代际 → legacy 路径)放行——同一 AMBIGUOUS 状态结果不一致的根因。
## 变更内容
`POST /admin/fleet/assignments/{assignmentId}/confirm`(单段确认执行)与需求级整组确认(内部共用原子引擎 `confirmRequirement`)在 HOLD 通知结果仍确认中(AMBIGUOUS,短信已发未回执)时,**一律不再返回 605042**,确认执行正常推进 assigned——与 #5701/#5716 已解除的单段 legacy 路径口径一致。
## 行为变化
| 场景 | 变更前 | 变更后 |
|------|--------|--------|
| HOLD 通知结果确认中(AMBIGUOUS)+ 司机已登记确认 + 单段 legacy 路径 | 200(#5716 已解除) | 200 |
| HOLD 通知结果确认中(AMBIGUOUS)+ 司机已登记确认 + **有代际(原子引擎/整组)路径** | **605042** | **200 推进 assigned** |
### 保留不变的保护
- 司机确认登记缺失(未确认/无有效来源):仍拦截(`DRIVER_CONFIRMATION_REQUIRED`)。
- NOTIFICATION 来源(司机回复系统通知)仍需通知 SENT 事实;AMBIGUOUS 下 NOTIFICATION 来源返回 400 提示人工联系来源(#5701 口径,`assertAtomicReplySourceIdentity`)。
- 其余 605042 保护点(expand 换版 / cancel / change / undo / 拒接 / 恢复通知等**通知代际推进与身份失效**场景)保留原拦截。
## 验证证据
- **网关实证(TEST,VEHICLE_MANAGER)**:
- 26-5484(订单 2086077200523558914,AID 2086077201060397057):holding + AMBIGUOUS(通知日志 delivery_status=dispatching)+ 司机已确认(21:20:15)+ 有代际 finalized=1 → `confirm`(sendItinerarySms=false)→ **200 confirmed=true status=assigned**(修复前 605042)
- 回归 26-8917(AID 2086050105051250690):同 AMBIGUOUS + 有代际 → confirm **200 confirmed=true status=assigned**
- 实证后通知日志恢复原状(canceled),两单保持 assigned 正常业务流转
- **测试**:新增 `confirmRequirement_holdNotificationAmbiguous_proceedsToAssigned`;AssignmentServiceTest 404/404 全绿;fleet verify 仅基线 ReleaseEOccupancyMysql8033RecoveryTest 失败(与本案无关)
## 前端交接
无接口契约变化(响应结构、字段、错误码集合均不变,仅 605042 出现场景收敛到既有口径)。
## 前端实证确认(2026-08-08 mmg,hl-admin)
确认 not_required 属实,零代码改动:
1. **全 `src/` 零 605042 引用**:grep 无任何 605042 特判/重试引导;confirm 业务错误统一走 `request.js` 弹后端 message,后端不再返回即前端不再展示。
2. **confirm 两路径前端入口均无 605042 处理**:单段 `useAssignFlow.js:1095 confirmAssignment` 与整组/原子引擎路径 `useAssignFlow.js:1088 confirmRequirementAssignments` 都无错误码特判,后端解除拦截后天然受益。
3. **AMBIGUOUS 前端展示与 confirm 拦截无关**:仅 `HoldNotificationStatus.vue:178/231`(发送结果标签 + canRetry fail-closed 守卫)与 `OrderDrawer.vue:708`(状态标签)消费 AMBIGUOUS,属通知发送结果展示,本变更(confirm 执行拦截)不触碰,行为不变。
4. 与 #5701(登记确认解除 605042)/#5716(confirm 单段 legacy 路径解除)同系列收尾:本条把原子引擎整组路径对齐到同一口径,前端无对应差异逻辑。

某些文件未显示,因为此 diff 中更改的文件太多 显示更多