文件
hl-api-changelog/changelogs-v2/2026-09/20_7443_调整订单车辆安排页同页提交行程与接送机两类用车需求-修改接口-管理后台.md
T
Mimingguang 830b8109e0
changelog-filename-gate / validate (push) Failing after 2s
docs(changelog): #7443 A+B 订单侧已交付 verified(hl-admin v2.1 6c091ef24)
调整弹窗双槽+显式 kind 写口+结算 step3 requirementKind 归属;C 车务侧属 18_7443 另起交付
2026-09-21 17:23:09 +08:00

34 KiB
原始文件 Blame 文件历史

schema, ticket, title, consumer, author, change_type, backend_status, gateway_status, frontend_status, frontend_owner, frontend_ref, target_release, verified_at, status_note, updated_at, base
schema ticket title consumer author change_type backend_status gateway_status frontend_status frontend_owner frontend_ref target_release verified_at status_note updated_at base
hl-changelog/v2 7443 调整订单「车辆安排」页同页提交 行程用车(TRAVEL) + 接送机用车(TRANSFER) 两类需求 admin wx(GIT) 修改接口 deployed verified verified mmg 6c091ef2486e0844d5bf1e39c705e43bec875e4f v2.1 2026-09-21 后端已合入 dev-v3(PR #8024,squash 提交 920f29d76)并部署测试服:deploy-status.sh 回读 hl-order-service-v3 = dev-v3 @ 920f29d76、BEHIND=0/N、STATE=ok,两实例滚动重启均 UP,判据 git merge-base --is-ancestor 920f29d76 920f29d76 = true。gateway_status=verified 的依据是四条真实网关调用而非源码推断:①读口双槽(含阳性对照:未提交需求的订单两个字段都是 null,证明不是恒有值)②一次 submit 同时提交两份 → HTTP 200,落库两条 active 行,fleet 分别为 bus/19座/1台 与 mpv/7座/2台 ③调整记录两条 label 原文不同 ④无大交通时 809002。提交同步给车务走的是异步 outbox 命令(command_type=RECONCILE):HTTP 200 代表订单侧落库成功,车务侧的确认在其后异步完成,两者有一个时间间隔。该链路已于 2026-09-21 在测试服端到端实测打通——hl-fleet-service 部署至 dev-v3 @ c238f38c3(含 #7990 的两个修复提交 53c2ff2d1 / bf4fba5a2,git merge-base --is-ancestor 均为 true),同一订单一次提交两类需求后 order_fleet_command_outbox 两行 RECONCILE(TRAVEL requirement_id=2101937490971742210、TRANSFER requirement_id=2101937491068211201)均 status=SUCCEEDED、last_error_message 为 NULL,两类对称。前端调用时会遇到的限定另见正文「2026-09-21 补充」小节:环境开关 hl.order.requirement.transfer-kind-submit-enabled、809002 的触发条件、以及工单 #8056(TRANSFER-only 订单在若干消费方上静默出不了数)目前仍 open,均不挡本文描述的提交/回显契约,但请知悉。前端已于 2026-09-21 交付 A+B 订单侧(hl-admin v2.1 6c091ef24):调整弹窗双槽(snapshot transferRequirement 回显独立槽、hasPickupTime!==true 置灰引导防 809002、单槽走 putVehicleRequirement 显式 kind、双槽走 submitAdjustment 同事务两键)、既有写口补显式 kind(reject 走 query 不进 body)、结算 step3 手录车行 requirementKind 归属(FLEET 省略/MANUAL 手选+回显带回/双需求缺归属前置拦截防 809008)。C 车务侧 TRANSFER 派车属 18_7443 范围另起交付。 2026-09-21 dev-v3

order-v3: 调整订单「车辆安排」页同页提交 行程用车 + 接送机用车 两类需求

服务: hl-order-service-v3(adjustment 层,唯一变化点) PR: #8024 | Issue: #7443 | 合并提交: 920f29d76 日期: 2026-09-20 影响范围: 管理后台「调整订单 → 车辆安排」页。此前该页结构上只能提交行程用车,本次补上接送机用车的读口与写口。


⚠️ 关键变化

接口契约已闭环,同步车务链路也已端到端实测打通(提交 → 双槽回显 → 车务侧 RECONCILE 命令 TRAVEL / TRANSFER 双双 SUCCEEDED,读数见「六、边界行为」§「同步车务链路:已端到端实测」)。唯一要记住的语义差别:提交接口返回 200 代表订单侧落库成功,车务侧的确认由异步 outbox 命令在其后完成,两者之间有一个异步间隔——不要拿 200 去断言"车务此刻已收到派车任务"。三条调用时会实际撞上的限定(单槽写口 kind 默认值、809002 触发条件、环境开关状态)与已知的下游消费方缺口见「六、边界行为」及其后的「2026-09-21 补充」。


一、背景

「车辆安排」页此前只有一个用车需求槽。页面上那张接送机卡片(航班号、抵离时间、接送备注)来自 vehicleTransportSummary,它是只读的大交通摘要——没有车型、座位数、数量输入,也没有对应的提交字段。于是业务上「接机用什么车、用几辆」没有任何录入通道。

后端的用车需求模型本身早就支持两类并存:表 order_vehicle_requirement 的 requirement_kind 取 TRAVEL(行程用车,服务日=行程日)/ TRANSFER(接送机,服务日=航班日),唯一键 (order_id, active_kind) ⇒ 同一订单两类 active 需求合法并存,各有自己的 fleet 与 service_dates。缺口只在 adjustment 这一层把 kind 焊死成了 TRAVEL。本次把它透出来。


二、变更接口清单

# 接口 方法 路径 变更类型 说明
1 调整订单预填快照查询 GET /v3/admin/order/{id}/adjustment/snapshot 修改接口 新增响应字段 transferRequirement(结构与既有 vehicleRequirement 完全相同)
2 调整订单统一提交 POST /v3/admin/order/{id}/adjustment/submit 修改接口 updates 新增 transferRequirement,支持一次提交同时落 TRAVEL + TRANSFER 两类用车需求

三、接口详情

1. 调整订单预填快照查询 GET /v3/admin/order/{id}/adjustment/snapshot

VO: AdjustmentSnapshotRespVO(无独立 ReqVO;入参为 path 变量 id + query 参数 scope)

使用场景

「车辆安排」弹窗打开时调用,一次性拉取行程用车(TRAVEL)与接送机用车(TRANSFER)两类需求的当前 active 版本、以及大交通摘要,用于双卡片回显。scope 传 VEHICLE_REQ(或不传,不传返全部子领域)时本组字段有值;basic 恒返回不受 scope 限制。

入参

字段 位置 类型 必填 约束 说明
id Path Long ✅ 订单雪花 ID 订单 ID
scope Query String ❌ 逗号分隔枚举:BASIC/PEOPLE/SCHEDULE/ITINERARY/HOTEL_REQ/VEHICLE_REQ;任一 token 非法返 587003 限定返回子领域;不传返全部。scope 传了但不含 VEHICLE_REQ 时,vehicleRequirement/transferRequirement/vehicleTransportSummary 三个字段均不返回

出参 Result<AdjustmentSnapshotRespVO>

字段 类型 说明
vehicleRequirement VehicleRequirementVO 行程用车需求(requirement_kind=TRAVEL)。字段名/类型均未变动;该类别无活跃需求时为 null
transferRequirement VehicleRequirementVO 新增。接送机用车需求(requirement_kind=TRANSFER)。该类别无活跃需求时为 null
vehicleTransportSummary VehicleTransportSummaryVO 大交通接送时间摘要,结构与行为原样不变,仍是只读展示
basic/travelers/schedule/itinerary/hotelRequirement/hotelDayDefaults/lockedDays/editableTabLocksHint - 其余子领域字段,本次未改动,按各自既有 scope 规则返回

VehicleRequirementVO 结构(vehicleRequirement 与 transferRequirement 复用同一 VO):

字段 类型 说明
id String 需求 ID(雪花,序列化为字符串)
version Integer 版本号
status String 需求状态,枚举见「六.5、枚举 / 数据字典」
fleet Array 车辆组合,元素 {vehicleType, seats, count} —— 即「用什么车、几座、几辆」
specialTags Array<String> 特殊诉求标签(字典 vehicle_special_demand)
pickupRequired Boolean 兼容回显字段;接机/接站以大交通摘要为准
dropoffRequired Boolean 兼容回显字段;送机/送站以大交通摘要为准
remark String 备注
claimerId / claimerName / claimedAt - 车控人信息(已认领时有值)
vehicleType / requiredSeats - ⚠️ 旧兼容字段,恒为 null。车型与座位已迁入 fleet,不要再读这两个

VehicleTransportSummaryVO 结构(本次未改动,供接送机门控逻辑参考):

字段 类型 说明
hasPickupTime Boolean 是否有可展示的接送机/站时间——前端据此判断能否提交接送机需求
displayText String 汇总展示文案;无时间时为 null
emptyText String 空态提示;hasPickupTime=false 时返回,当前文案「暂无接送机时间」
arrivals / departures Array 到达/离开接送时间明细

请求示例

GET /v3/admin/order/2101219133700952066/adjustment/snapshot?scope=VEHICLE_REQ

响应示例

实测节选(订单 2101219133700952066,摘自「八、测试环境已验证」①第二行,仅保留 data 内 vehicleRequirement/transferRequirement 两字段用于结构对照):

{
  "vehicleRequirement": {
    "id": "2101219223517659138",
    "fleet": [{"vehicleType": "mpv", "seats": 7, "count": 1}]
  },
  "transferRequirement": {
    "id": "2101219393722634242",
    "fleet": [{"vehicleType": "mpv", "seats": 7, "count": 1}]
  }
}

⚠️ 以上两者 fleet 恰好相同是该样本单本身如此,不能拿来证明按 kind 取数生效;真正证明它的是下面「空数据 / 降级响应」的阳性对照,以及两者 id 不同。

空数据 / 降级响应

该订单没有接送机需求时 transferRequirement 为 null(不是空对象,也不是省略字段)。实测阳性对照:订单 2101566624467419137(提交前)两个字段均为 null——用于证明 transferRequirement 不是恒有值、按 kind 派生是真实生效的(若恒有值就无法与 vehicleRequirement 区分开)。

{ "code": 200, "data": { "vehicleRequirement": null, "transferRequirement": null }, "success": true }

错误响应

{ "code": 581007, "message": "订单不存在", "success": false, "data": null }
{ "code": 587003, "message": "调整范围取值非法", "success": false, "data": null }

业务边界

  • 未登录/网关未透传 X-Admin-Role → 401(网关拦截),不进入本接口逻辑
  • 订单不存在 → 581007
  • scope 含非法枚举值 → 587003,不会静默只返 basic
  • vehicleRequirement/transferRequirement 为 null 是正常态(该类别当前无活跃需求),前端不应把 null 当异常处理
  • 两个字段结构完全对称,读取代码不应区分对待,唯一差异是各自的 id/fleet/version 等业务数据
  • vehicleType/requiredSeats 两个旧兼容字段恒为 null,车型信息一律读 fleet

2. 调整订单统一提交 POST /v3/admin/order/{id}/adjustment/submit

VO: AdjustmentSubmitReqVO → AdjustmentSubmitRespVO

使用场景

「车辆安排」弹窗点击保存时调用。前端在内存中收集本次改动的 vehicleRequirement(行程用车)与/或 transferRequirement(接送机用车),一次性提交;后端在单一事务内原子应用,任一子域校验失败则整体回滚(含已提交的另一半)。这是「调整订单」弹窗统一提交入口的一部分,本次只新增 updates.transferRequirement 这一个子字段,其余子域(people/schedule/itinerary/hotelRequirement)行为不变。

入参

字段 位置 类型 必填 约束 说明
id Path Long ✅ 订单雪花 ID 订单 ID
updates Body Object ✅ 至少一个子字段非 null,否则 587012 各子域修改内容容器
updates.vehicleRequirement Body VehicleRequirementBodyVO ❌ 未改子领域置 null 行程用车需求完整新版本;只传它时行为与改动前逐字节一致
updates.vehicleRequirement.fleet Body Array 提交该需求时必填 元素 {vehicleType, seats, count};vehicleType 取值见「六.5、枚举 / 数据字典」 车型组合
updates.vehicleRequirement.specialTags Body Array<String> ❌ 字典 vehicle_special_demand 通用特殊诉求标签
updates.vehicleRequirement.pickupRequired / .dropoffRequired Body Boolean ❌ - 兼容字段
updates.vehicleRequirement.remark Body String ❌ - 备注
updates.transferRequirement Body VehicleRequirementBodyVO ❌ 新增;子字段与 updates.vehicleRequirement 完全相同(fleet/specialTags/pickupRequired/dropoffRequired/remark) 接送机用车需求完整新版本;🔴 不含 serviceDates——服务日由后端从大交通派生;该订单没有大交通时返 809002;开关未开时返 809009

出参 Result<AdjustmentSubmitRespVO>

字段 类型 说明
success Boolean 提交是否成功。响应体极简,不含业务数据;失败统一由全局异常处理器返回 Result{code, message}

请求示例

与「八、测试环境已验证」②实测一致,补上 updates 外层包裹以符合 AdjustmentSubmitReqVO 结构:

{
  "updates": {
    "vehicleRequirement": {
      "fleet": [{"vehicleType": "bus", "seats": 19, "count": 1}]
    },
    "transferRequirement": {
      "fleet": [{"vehicleType": "mpv", "seats": 7, "count": 2}]
    }
  }
}

响应示例

实测原文(HTTP 200,未展开顶层 message/success 字段):

{"code":200,"data":{"success":true}}

空数据 / 降级响应

若 updates 整体所有子字段均为 null(既未改行程用车也未改接送机,也未改其它子域),后端判定为无实际修改,返回 587012(不落库、不产生调整记录)。只传 vehicleRequirement 或只传 transferRequirement 都是合法的部分提交,另一半保持不变——不是"全有全无"。

错误响应

实测原文(订单无大交通时提交 transferRequirement):

{"code":809002,"message":"接送机需求缺少服务日期,请先补齐大交通信息"}

源码定义、未在本次实测中主动触发(测试服开关已开),按 VehicleRequirementKindErrorCode/AdjustmentErrorCode 源码消息模板给出:

{ "code": 809009, "message": "接送机用车需求尚未开放提交,请联系管理员确认开放时间(订单 2101566624467419137)", "success": false, "data": null }
{ "code": 587012, "message": "变更内容为空,无实际修改", "success": false, "data": null }
{ "code": 587002, "message": "订单已是终态,不可调整", "success": false, "data": null }

业务边界

  • 事务边界:updates.vehicleRequirement 与 updates.transferRequirement 在同一个 @Transactional 事务内应用;任一半失败(如接送机因缺大交通抛 809002)整笔回滚,已提交的另一半也不落库
  • serviceDates 前端不传;服务日由后端派生:TRAVEL 取行程日,TRANSFER 取大交通航班/车次日期(详见「四、契约约束与正确调用方式」)
  • 开关 hl.order.requirement.transfer-kind-submit-enabled 关闭时提交 transferRequirement 返 809009;开关无 @RefreshScope,Nacos 热推不生效,需重启实例
  • 只传 vehicleRequirement → 行为与改动前逐字节一致;改动前的请求体不含 transferRequirement 字段,旧前端请求不受影响(向后兼容)
  • fleet[].vehicleType 只接受 suv/mpv/bus/sedan 四个大类 key,后端兼容历史别名并归一
  • 调整记录 adjustment-record 会为两类需求各产出一条可区分的 VEHICLE_REQ 条目(行程用车需求已调整 / 接送机用车需求已调整),见「八、测试环境已验证」③
  • 提交成功代表订单侧需求已落库,车务侧由异步 outbox 命令(command_type=RECONCILE)在其后确认;该链路 TRAVEL / TRANSFER 两类已于 2026-09-21 在测试服实测双双 SUCCEEDED,前端无需为它写任何补偿逻辑,只是不要拿提交接口的 200 去断言车务此刻已确认(读数见「六、边界行为」§「同步车务链路:已端到端实测」)

四、契约约束与正确调用方式

本节只写后端接受/拒绝 payload 的规则,不写 UI 渲染建议。

serviceDates 由后端派生,前端禁止传

TRANSFER 的服务日来自大交通,空集合不会兜底成行程日(那样会把航班日写错,派车日期落到需求单声明范围之外):

  • TRAVEL:服务日 = 行程日(order_itinerary_day 派生)
  • TRANSFER:服务日 = 大交通的航班/车次日期(客人可能提前一天到、返程后一天走,所以允许落在行程日窗口之外)

✅ 正确 / ❌ 错误 payload 对照

场景 payload 结果
✅ 只提交行程用车 {"updates":{"vehicleRequirement":{"fleet":[...]}}} 200,行为与改动前一致
✅ 只提交接送机用车(订单已录大交通) {"updates":{"transferRequirement":{"fleet":[...]}}} 200,落 1 条 TRANSFER 需求
✅ 同页两类都提交 {"updates":{"vehicleRequirement":{...},"transferRequirement":{...}}} 200,落 2 条 active 需求(见「八」②实测)
❌ 提交接送机用车但订单未录大交通 {"updates":{"transferRequirement":{"fleet":[...]}}} 809002,整笔回滚(见「八」④实测)
❌ 提交接送机用车但开关未开(默认关闭) 同上 809009
❌ 期望通过入参指定 serviceDates {"updates":{"transferRequirement":{"serviceDates":[...]}}} 无效——该字段不在 VehicleRequirementBodyVO 定义内,传了也会被忽略,服务日仍按后端派生规则计算

前端必须处理的前置:没有大交通时提交接送机需求会失败

因此该订单没有录入大交通行程时,提交 transferRequirement 会返回 809002。

⇒ 建议前端在没有大交通时把接送机那一段的输入置灰,并提示「请先录入大交通行程」,不要让用户填完再吃一个错误码。判断依据用同一份快照里的 vehicleTransportSummary.hasPickupTime(为 false 时它还会给出 emptyText,当前文案是「暂无接送机时间」)。

⚠️ 两份同时提交而接送机这半抛 809002 时,整笔调整回滚(一次 submit = 一笔原子调整),行程用车那半也不会落库。所以置灰比事后补救重要。

错误码处置对照(🔴 两码分开处理,别混)

错误码 触发条件 前端应做的下一步
809002 该订单尚未录入大交通行程,却提交了 transferRequirement 去补大交通——引导用户先在大交通模块录入行程,而不是重试提交
809009 当前环境的 hl.order.requirement.transfer-kind-submit-enabled 开关未开启 找后端确认该环境的开关——这不是数据问题,重试/补数据都无效,需要后端改配置并重启实例

环境开关

hl.order.requirement.transfer-kind-submit-enabled

  • 代码默认 false:未显式置 true 的环境上,提交 kind=TRANSFER 返 809009
  • 测试服已置 true(随 order-v3 重启生效)
  • ⚠️ 该配置无 @RefreshScope(源码 RequirementService 注释确认),改完必须重启服务才生效,Nacos 热推不生效

五、数据库行为

写接口 POST .../adjustment/submit 落库表 order_vehicle_requirement(INSERT-only 版本化模型,唯一键 (order_id, active_kind),同订单同 kind 仅 1 行 is_active=1)。

实测②落库结果(订单 2101566624467419137):

active_kind fleet service_dates
TRAVEL [{"count":1,"seats":19,"vehicleType":"bus"}] ["2026-10-20","2026-10-21","2026-10-22"](行程三天)
TRANSFER [{"count":2,"seats":7,"vehicleType":"mpv"}] ["2026-10-20","2026-10-23"](接机日 + 送机日)

🔴 两个 service_dates 一个都不是前端传的,全部由后端按 kind 派生——这是「前端不传日期」这条约定的硬证据。

同订单两类需求各占一行、互不覆盖:TRAVEL 与 TRANSFER 各自维护自己的 version/fleet/service_dates,提交一类不影响另一类已落库的行(除非同次 submit 一起提交)。

写入原子性:updates.vehicleRequirement 与 updates.transferRequirement 在同一个 @Transactional 事务内落库;任一半失败(如 809002)整笔回滚,DB 层零写入(不是"先落一半再补")。


六、边界行为

  • 未登录/网关未透传角色 → 401(网关拦截)
  • 订单不存在 → 581007
  • scope 非法枚举值 → 587003
  • 订单已是终态(已结算/已取消)→ 提交返 587002,拒绝任何调整(含车辆需求)
  • updates 全部子字段为空 → 587012
  • 老数据兼容:改动前落库的旧行仍被正确识别为 requirement_kind=TRAVEL 并映射进 vehicleRequirement,不会因为响应新增字段而出现兼容异常

同步车务链路:已端到端实测(2026-09-21)

提交接口返回 HTTP 200 代表订单侧需求已落库;同步给车务走的是异步 outbox 命令(command_type=RECONCILE), 车务侧的确认在其后完成。这条链路 TRAVEL / TRANSFER 两类已实测打通,前端按本文接入即可,不必为它写补偿逻辑。

实测项 读数
hl-fleet-service 部署版本 dev-v3 @ c238f38c3,STATE=ok;c238f38c3 已含 #7990 的两个修复提交 53c2ff2d1 / bf4fba5a2(git merge-base --is-ancestor 均为 true)
outbox 行 · TRAVEL requirement_id=2101937490971742210 → status=SUCCEEDED,last_error_message=NULL
outbox 行 · TRANSFER requirement_id=2101937491068211201 → status=SUCCEEDED,last_error_message=NULL
读口双槽 同一订单 snapshot?scope=VEHICLE_REQ 的 vehicleRequirement 与 transferRequirement 均非 null;阳性对照单 2087157633055064066(未提交过接送机需求)的 transferRequirement 为 null,证明该字段不是恒有值

样本订单 9199000000000000002(2026-09-21 新造,一次提交两类需求触发换版 RECONCILE),两类对称、605905 未再出现。

唯一需要前端记住的语义差别仍是:200 ≠ 车务此刻已确认,中间隔着一次异步投递,不要拿前者断言后者。 下面「2026-09-21 补充」的三条限定是契约自带的,请一并读完再接入。

2026-09-21 补充:前端调用时会遇到的三个限定

这三条都是契约本身自带的限定(不是内部进度),无论后端那条同步链路处于什么状态都成立,前端接入前务必确认:

  1. 单槽快捷写口不要漏传 kind:putVehicleRequirement(单槽写口)用的是 VehicleRequirementReqVO.kind,@Pattern 限定取值 TRAVEL|TRANSFER,不传时默认 TRAVEL。走这条快捷写口提交接送机需求,必须显式传 kind=TRANSFER,否则会被当成行程用车落库。
  2. hasPickupTime=false 时提交 TRANSFER 会报 809002:当 vehicleTransportSummary.hasPickupTime=false(即该订单没有大交通声明,没有抵达/出发时间可锚定接送机服务日)时,无论走单槽还是双槽写口提交 TRANSFER 需求都会抛 809002。前端应在没有大交通数据时禁用或提示「接送机用车」入口,而不是让用户提交后才看到报错。
  3. 环境开关是独立配置项:接送机需求提交受开关 hl.order.requirement.transfer-kind-submit-enabled 控制,代码默认 false,关闭时提交 kind=TRANSFER 一律返 809009(写口直接拒绝,一行都不落库)。测试服已开启,本文所有实测读数都是在开关打开的前提下取得的。收到 809009 即表示所在环境的开关没开,属配置问题,重试与补数据均无效。

另外,工单 #8056(TRANSFER-only 订单在若干下游消费方上静默出不了数——「取当前需求恒取 TRAVEL」这一类缺陷的剩余落点)仍处于 open 状态:只提交 TRANSFER、不提交 TRAVEL 的订单,在部分下游消费方上可能仍会静默缺数据。这条不影响本文描述的提交/回显契约,但请知悉,遇到"只提了接送机、下游看不到数据"的反馈时可以先对号排查这条。

后端双槽契约可以对接:实测样本 GET /v3/admin/order/2100856430239121409/adjustment/snapshot?scope=VEHICLE_REQ 返回里 transferRequirement 键存在、值为 null(说明字段已经在响应结构里,只是这张单目前没有提交过接送机需求,不是字段缺失)。提交时按「二、变更接口清单」里的写口,在 updates.transferRequirement 放一份与 updates.vehicleRequirement 完全相同的结构即可写入第二行(requirement_kind=TRANSFER 的那一行)。


六.5、枚举 / 数据字典

status(VehicleRequirementVO.status,源码 RequirementStatus 枚举,房/车需求共用单源)

所属字段: vehicleRequirement.status / transferRequirement.status | 类型: String

值 中文 label 说明
PENDING 待房务配 已提交,等待车控接单(核心+团期共用,进入抢单池)
PROCESSING 配房中 已接单,处理中
DONE 配房完成 配车完成
PENDING_REVIEW 待审核 仅团期:定制师提交后等团期管理员审核
REJECTED_TO_CONSULTANT 驳回 已驳回定制师
REJECTED_TO_ADMIN 驳回 已驳回团期管理员(仅团期)

⚠️ label 是房务侧视角措辞(该枚举被房、车两域共用),车需求场景下前端应另行映射展示文案,不要直接渲染 label 原文。AdjustmentSnapshotRespVO 内嵌 VehicleRequirementVO 的 Swagger 注释写的是「PENDING / CLAIMED / DONE」——该注释与源码枚举 RequirementStatus 不一致,CLAIMED 不是合法取值,请以本表(源码枚举)为准。

fleet[].vehicleType(FleetItem.vehicleType)

所属字段: vehicleRequirement.fleet[].vehicleType / transferRequirement.fleet[].vehicleType / 提交体同路径 | 类型: String

值 说明
suv SUV
mpv MPV(本文实测样本使用值)
bus 大巴/中巴(本文实测样本使用值)
sedan 轿车

只选大类,不选具体车型;后端兼容历史别名并归一。

requirement_kind(DB 列 order_vehicle_requirement.requirement_kind;不直接出现在 JSON 字段名中,通过 vehicleRequirement/transferRequirement 两个槽位体现)

值 对应响应/提交字段 服务日口径
TRAVEL vehicleRequirement 行程日(order_itinerary_day 派生)
TRANSFER transferRequirement 大交通航班/车次日期(允许落在行程日窗口之外)

六.6、修改前后对比

字段级对比

字段 改前 改后
GET .../snapshot 响应 vehicleRequirement 唯一的用车需求槽 语义收窄为「行程用车」,字段名/类型/取值规则不变
GET .../snapshot 响应 transferRequirement 不存在 新增,接送机用车需求,无该需求时为 null
POST .../submit 请求体 updates.vehicleRequirement 唯一的用车需求提交槽 字段名/类型/校验规则不变
POST .../submit 请求体 updates.transferRequirement 不存在 新增,接送机用车需求提交槽
adjustment-record 车辆需求变更项 label 恒为「车辆需求已调整」 按类别区分为「行程用车需求已调整」/「接送机用车需求已调整」

行为级对比

行为 改前 改后
接送机用车的录入通道 无——vehicleTransportSummary 只读展示,没有对应提交字段 有——updates.transferRequirement 可提交车型/座位/数量
一次提交能覆盖的用车类别 仅 TRAVEL TRAVEL、TRANSFER,或两者同页一次提交(同一原子事务)
调整记录中车辆需求变更的可辨识度 无法区分改的是哪一类 两条独立可辨识条目
TRANSFER 服务日来源 N/A(无此提交路径) 后端从大交通派生,前端不传;无大交通时拒绝(809002)

六.7、影响评估

  • 是否破坏向后兼容: 否——vehicleRequirement 字段名/类型/语义零变更,旧前端请求体(不含 transferRequirement)行为与改动前逐字节一致
  • 前端是否必须同步上线: 否,本次是纯新增字段/新增可选提交槽,前端可延后接入;接入前不会影响现网「行程用车」链路
  • 前端 workaround 清理点: 无——此前接送机用车没有任何前端录入通道,不存在需要撤下的旧 workaround
  • 提交与车务确认之间隔着一次异步投递:接口契约已闭环(提交 + 回显),"提交成功"代表订单侧已落库,车务侧由异步 outbox 命令在其后确认——该链路两类需求已于 2026-09-21 实测双双 SUCCEEDED;读数见「六、边界行为」§「同步车务链路:已端到端实测」,调用限定见其后的「2026-09-21 补充」

七、不影响范围

  • 仅影响: 管理后台「调整订单 → 车辆安排」弹窗的读口(GET .../adjustment/snapshot)与写口(POST .../adjustment/submit)
  • 零影响:
    • vehicleRequirement 字段名/类型/语义零变更,现网只读行程用车那部分代码无需调整
    • vehicleTransportSummary(大交通摘要)结构与语义原样不变,仍只读展示
    • 用车需求生命周期写口 VehicleRequirementAdminController(dispatch/reject/supplier-reject/submit/urgent/urgent/cancel/candidates/assign)均未改动——本次 PR 只动了 AdjustmentSnapshotRespVO/AdjustmentSubmitReqVO/AdjustmentService 三个源文件(git show --stat 920f29d76 核实)
    • Fleet 侧确认/重开内部写口(OrderInternalForFleetController 的 .../vehicle/final-confirmation-reservations、.../release、.../vehicle/reopen-after-assignment-cancel)响应结构未动
    • 团期用车需求 reopen(GroupBatchRequirementController 的 .../vehicle-requirement/reopen)未动
    • 「调整订单」弹窗其余子域(出行人/改期/行程/房需求)的接口与行为完全不受影响
    • C 端接口、订单创建/详情读取接口零影响
    • 历史数据无需迁移:存量订单的 TRAVEL 需求行结构不变;本次不产生任何 TRANSFER 迁移行

八、测试环境已验证

真实网关调用(2026-09-20,测试服),后端版本 hl-order-service-v3 @ 920f29d76(PR #8024 squash 合入 dev-v3):

① 读口双槽 —— 带阳性对照

订单 vehicleRequirement transferRequirement
2101566624467419137(提交前) null null
2101219133700952066(两类都有) {id:2101219223517659138, fleet:[{mpv,7,1}]} {id:2101219393722634242, fleet:[{mpv,7,1}]}

⚠️ 第二行两者的 fleet 恰好相同(样本单本身如此),所以"两个字段不同"这件事不能拿来证明按 kind 取数生效;真正证明它的是第一行那个全 null 的阳性对照,以及两者 requirementId 不同。 ✓

② 同页提交(本文的核心)

POST /v3/admin/order/2101566624467419137/adjustment/submit
updates.vehicleRequirement  = {fleet:[{vehicleType:"bus", seats:19, count:1}]}
updates.transferRequirement = {fleet:[{vehicleType:"mpv", seats:7,  count:2}]}
→ HTTP 200  {"code":200,"data":{"success":true}}

落库 order_vehicle_requirement 两条 active 行:

active_kind fleet service_dates
TRAVEL [{"count":1,"seats":19,"vehicleType":"bus"}] ["2026-10-20","2026-10-21","2026-10-22"](行程三天)
TRANSFER [{"count":2,"seats":7,"vehicleType":"mpv"}] ["2026-10-20","2026-10-23"](接机日 + 送机日)

🔴 两个 service_dates 一个都不是前端传的,全部由后端按 kind 派生——这是「前端不传日期」这条约定的硬证据。 ✓

③ 调整记录可区分

GET /v3/admin/order/{id}/adjustment-record → 本次 changeCount:2,两条 type=VEHICLE_REQ, label 分别是 行程用车需求已调整 / 接送机用车需求已调整。改动前两条 label 完全相同、事后分不出改的是哪一份。 ✓

④ 无大交通的失败形态

订单 2101567681155207169(同产品、已付款、无大交通),只提交 transferRequirement: → HTTP 200 + {"code":809002,"message":"接送机需求缺少服务日期,请先补齐大交通信息"}

(提交前已确认测试服 Nacos hl.order.requirement.transfer-kind-submit-enabled: true, 所以这个 809002 不是被开关挡住的假象。) ✓

联调样本:订单 2101219133700952066(订单号 HL20260919155734730,散客单),已录大交通 2 条,TRAVEL 与 TRANSFER 两类需求均已存在,可直接用来验双槽回显。


十、相关文档

  • 关联 Issue: wx/HL#7443
  • 关联 PR: wx/HL#8024(squash 合并至 dev-v3 @920f29d76)
  • 关联 Issue(仍 open): wx/HL#8056(TRANSFER-only 订单在若干下游消费方上静默出不了数,详见「2026-09-21 补充」)
  • 关联 Issue: wx/HL#7990(接送机需求同步车务曾恒返 605905)——修复提交 53c2ff2d1 / bf4fba5a2 已随 hl-fleet-service c238f38c3 部署测试服,2026-09-21 实测 TRANSFER 侧 RECONCILE SUCCEEDED,605905 未再出现

关联 / 联系人

链接

联系人

  • 后端负责人: wx(GIT)
  • 前端负责人: mmg