17 KiB
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 | 8530 | 团期用车需求换组时把旧版已排车行整槽平移,响应新增 migratedAssignmentCount 平移下界字段 | admin | wx(GIT) | 修改接口 | deployed | verified | implemented | hl-admin(claude-opus-4-8) | 38bcab548c5d71317d0f56c6d0051c7fe7a0d4fd | 2026-09-30 | PR #8563 合并 dev-v3(cb876bf780);hl-order-service-v3 + hl-fleet-service 已随该提交部署测试网关;order-v3 新增单测 6 条(RequirementServiceTest)+ fleet 新增单测 6 条(AssignmentServiceTest)+ mapper 层 2 条 + 跨服务常量 1 条,共 15 条,均为换组迁移/无配车迁移/同内容重放不迁移/非团期恒 0/订单终态不迁移等场景的定向用例。;前端已交付:FunItemAdjustModal 成功提示附换组平移基数(>0 显「旧版 N 行配车将平移至新需求」,0/统一提交路径原提示),spec 3 例,checkpoint 全绿(hl-admin 38bcab54) | 2026-09-29 | dev-v3 |
团期用车需求换组:响应新增 migratedAssignmentCount 平移下界字段
存放目录:
changelogs-v2/2026-09/服务: hl-order-service-v3(响应端点所在服务)+ hl-fleet-service(旧版配车整槽平移的执行方,经 Outbox/Feign 异步处理,前端不直接调用它) PR: #8563 Issue: #8530 日期: 2026-09-29 影响范围: 管理后台订单详情页「提交/修改/调整用车需求」接口的响应体(仅团期子订单换组场景新增字段值有意义)
⚠️ 关键变化
- 团期子订单在「改提/换组」用车需求时,旧版本名下已经排好的车行,此前会原地留在已失活的旧
requirementId下,车务侧对这些行的任何后续推进都会撞错误码 605905/605913 且没有任何提示;现在后端会在换组的同一时刻把这些行整槽平移到新需求。 - 响应 VO
VehicleRequirementRespVO新增字段migratedAssignmentCount(Integer,恒非null):本次换版交给车务平移的配车基数(下界),不是真实迁移行数。它在所有分支(首提/改提/完成后调整/幂等重放)都会回填,取 0 或正整数,从不为null。
二、变更接口清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|---|---|---|---|---|
| 1 | 提交/修改/调整用车需求 | PUT | /v3/admin/order/{id}/vehicle-requirement |
响应新增字段 | data.migratedAssignmentCount |
三、接口详情
1. 提交/修改/调整用车需求 PUT /v3/admin/order/{id}/vehicle-requirement
VO: VehicleRequirementReqVO → VehicleRequirementRespVO
使用场景
定制师/团期管理员在订单详情页提交、修改或调整用车需求。后端按 order_vehicle_requirement 表当前 active 行是否存在及其状态自动判三分支:无 active → INIT_SUBMIT 首提;PENDING → PENDING_EDIT 改提;DONE → DONE_ADJUST 完成后调整。同内容重放(与当前生效版本完全一致)额外命中 IDEMPOTENT_NOOP,不换版。consultantId 由后端从 JWT 解析,不接受前端传入。
团期子订单每次「改提/换组」(即 PENDING_EDIT 分支且确实发生换版)都会触发本次改动:旧版本名下已经排好的车行会被整槽平移到新需求,响应回填 migratedAssignmentCount 说明本次交给车务平移的基数。非团期(核心)订单、首次提交、同内容重放三种情况都不触发平移,字段恒为 0。
入参字段表
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
id |
Path | Long | 是 | 正整数 ID | 订单 ID |
kind |
Body | String | 否 | TRAVEL/TRANSFER,不传按 TRAVEL |
需求类别:TRAVEL=团期行程用车(服务日冻结为行程日),TRANSFER=接送机(服务日由大交通派生) |
fleet |
Body | List<FleetItem> | 是 | 至少 1 项 | 车型组合 |
fleet[].vehicleType |
Body | String | 是 | suv/mpv/bus/sedan |
车型大类 key(只选大类,不选具体车型) |
fleet[].seats |
Body | Integer | 是 | 需在该大类座位选项内 | 座位数 |
fleet[].count |
Body | Integer | 是 | >0 | 辆数 |
specialTags |
Body | List<String> | 否 | 需在字典 vehicle_special_demand 内 |
通用特殊诉求标签,应用到全部车辆 |
pickupRequired |
Body | Boolean | 否 | - | 兼容字段,接机/接站以实时大交通批次为准 |
dropoffRequired |
Body | Boolean | 否 | - | 兼容字段,送机/送站以实时大交通批次为准 |
remark |
Body | String | 否 | ≤500 字符 | 备注 |
本次改动未新增或修改任何入参字段,上表为该端点既有契约,供本节自包含阅读。
出参字段表
| 字段 | 类型 | 说明 |
|---|---|---|
data.id |
Long | 需求行 ID |
data.kind |
String | 需求类别:TRAVEL/TRANSFER |
data.serviceDates |
List<LocalDate> | 本版冻结的服务日期,升序去重 |
data.version |
Integer | 版本号 |
data.isActive |
Boolean | 是否为当前生效版本 |
data.status |
String | 需求状态(PENDING/PENDING_REVIEW/PROCESSING/DONE 等) |
data.branchTaken |
String | 实际走的分支:INIT_SUBMIT/PENDING_EDIT/DONE_ADJUST/IDEMPOTENT_NOOP |
data.previousVersion |
Integer/null | DONE_ADJUST 分支回填上一版本号;其余分支为 null |
data.assignmentDeletedCount |
Integer/null | DONE_ADJUST 分支回填软删旧配车行数;其余分支为 null |
data.migratedAssignmentCount |
Integer | 【新增】 本次换版交给车务平移的配车基数(下界),恒非 null;语义见下方业务边界 |
data.passengerCount |
Integer | 订单乘车人数(成人+儿童+幼童+婴儿),结构不变 |
data.vehicleCount |
Integer | 车辆总数,结构不变 |
data.totalSeatCount |
Integer | 车辆座位总数(含司机座),结构不变 |
data.driverSeatCount |
Integer | 司机占用座位数,结构不变 |
data.passengerSeatCapacity |
Integer | 可载客座位数,结构不变 |
data.remainingPassengerSeats |
Integer | 剩余可载客座位数,结构不变 |
data.pickupRequired / data.dropoffRequired |
Boolean | 兼容回显字段,结构不变 |
data.submittedAt / data.claimerId / data.claimerName / data.claimedAt |
- | 结构不变 |
请求示例
{
"kind": "TRAVEL",
"fleet": [
{ "vehicleType": "mpv", "seats": 7, "count": 1 }
],
"specialTags": ["中文司机"],
"remark": "客户要求中文司机"
}
响应示例
团期子订单换组,旧版名下有 3 行在途配车镜像(branchTaken=PENDING_EDIT 且触发平移):
{
"code": 200,
"message": "成功",
"success": true,
"data": {
"id": "2810002",
"kind": "TRAVEL",
"serviceDates": ["2026-07-19", "2026-07-23"],
"version": 2,
"isActive": true,
"status": "PENDING_REVIEW",
"branchTaken": "PENDING_EDIT",
"previousVersion": null,
"assignmentDeletedCount": null,
"migratedAssignmentCount": 3,
"passengerCount": 2,
"vehicleCount": 1,
"totalSeatCount": 7,
"driverSeatCount": 1,
"passengerSeatCapacity": 6,
"remainingPassengerSeats": 4,
"pickupRequired": true,
"dropoffRequired": true
}
}
首次提交 / 同内容重放(IDEMPOTENT_NOOP),没有旧版可迁移:
{
"code": 200,
"message": "成功",
"success": true,
"data": {
"id": "2812001",
"branchTaken": "IDEMPOTENT_NOOP",
"migratedAssignmentCount": 0
}
}
空数据 / 降级响应
本接口不存在空数据形态:请求参数合法时恒返回单条需求行;下游依赖(车队字典等)不可用时走错误响应,不降级为空对象。
错误响应
{
"code": 582021,
"message": "用车需求数组不能为空",
"success": false,
"data": null
}
{
"code": 582030,
"message": "当前需求状态不可修改(处理中)",
"success": false,
"data": null
}
本次改动未新增任何错误码,以上两例是该端点既有校验错误码,供本节自包含阅读。
业务边界
migratedAssignmentCount是「下界」不是真实迁移行数:取值 = 换组前那一版 requirement 上挂着的已排车行数(按上一版requirementId统计order_vehicle_assignment);真实平移由车务侧异步幂等执行,只搬活跃非取消行,可能小于等于该下界。- 连续换组(A→B 再 B→C)第二次读到的恒为 0,但迁移确实发生了:A→B 那一次已经把行迁到 B 名下,B→C 这一次按「上一版」(B)统计,B 名下此时还没有新快照(新快照要等车务重新确认后才按新需求落),统计结果恒为 0。前端不能把 0 解读成"这条链路从未发生过迁移",只能解读成"本次调用没有新的迁移基数"。
- 首次提交(
INIT_SUBMIT)与同内容重放的幂等分支(IDEMPOTENT_NOOP):字段恒为 0,且不触发平移信号。 - 非团期(核心)订单:字段恒为 0,且不额外查询配车镜像表(不新增一次 DB 往返),行为与本次改动之前完全一致。
- 订单处于终态(
COMPLETED/CANCELLED)时不触发平移信号,字段为 0——即使是经由"订单调整"入口提交(该入口本身绕过普通提交闸),终态订单同样不发平移。 - 该字段在全部四个分支(
INIT_SUBMIT/PENDING_EDIT/DONE_ADJUST/IDEMPOTENT_NOOP)都会回填,恒非null。
四、契约约束与正确调用方式
本节只写后端字段语义与正确/错误解读,不写 UI 渲染建议。
✅ 正确 / ❌ 错误解读对照
| 场景 | 解读 |
|---|---|
✅ migratedAssignmentCount > 0 |
本次换版确有旧版配车行被交给车务侧平移 |
✅ migratedAssignmentCount = 0 且 branchTaken = INIT_SUBMIT / IDEMPOTENT_NOOP |
本来就没有触发换版,字段恒为 0,属正常值 |
✅ migratedAssignmentCount = 0 且 branchTaken = PENDING_EDIT |
旧版名下当时没有在途配车镜像,或本次读到的是连续换组链路中的中间一跳 |
❌ 用单次 = 0 断言"这条订单从未发生过配车平移" |
连续换组 A→B→C 时,B→C 这一次恒读 0,但 A→B 时已经迁移过;单次响应不是整条历史的累计值 |
不需要的前置动作
该字段只出现在响应里,不改变入参契约:请求体字段零变化,无需为这个字段额外传参或做请求前置。
五、数据库行为
migratedAssignmentCount 不落库、不是新增列:它是响应组装时的即时统计结果,等价于:
SELECT COUNT(*) FROM order_vehicle_assignment
WHERE requirement_id = <换组前的旧 requirementId> AND deleted = 0
需求行本身仍按既有逻辑落库(旧版 deactivate + 新版 insert),本次未新增、未变更任何表结构或列。真实的配车行迁移(把 order_vehicle_assignment.requirement_id 从旧值改写为新值)发生在车务侧(hl-fleet-service),经异步 Outbox/Feign 通道执行,与本端点的同步响应解耦。
六、边界行为
- 未登录 → 401(网关拦截)。
- 入参校验失败(
fleet为空、车型非法等)→ 既有错误码,HTTP 200,data=null。 - 非团期(核心)订单:
migratedAssignmentCount恒为 0,且不额外查询order_vehicle_assignment,行为与本次改动之前一字不变。 - 订单终态(
COMPLETED/CANCELLED):不触发平移信号,migratedAssignmentCount=0。 - 业务失败仍可能是 HTTP 200,需同时检查
code、success和message。
六.5、枚举 / 数据字典
本次未新增或变更任何枚举取值。branchTaken 沿用既有四个取值,未变化:
branchTaken(响应字段)
所属字段: data.branchTaken | 类型: String
| 值 | 中文 | 说明 |
|---|---|---|
INIT_SUBMIT |
首次提交 | 订单无 active 需求行时的分支 |
PENDING_EDIT |
改提/换组 | 当前 active 需求为 PENDING 时的分支;团期订单在此分支触发配车平移 |
DONE_ADJUST |
完成后调整 | 当前 active 需求为 DONE 时的分支 |
IDEMPOTENT_NOOP |
幂等重放 | 提交内容与当前生效版本完全一致,不换版、不触发平移 |
六.6、修改前后对比
字段级对比
| 字段 | 改前 | 改后 |
|---|---|---|
data.migratedAssignmentCount |
不存在 | 新增,Integer,恒非 null,团期换组场景回填平移基数,其余场景为 0 |
行为级对比
| 行为 | 改前 | 改后 |
|---|---|---|
| 团期子订单改提/换组时,旧版名下已排的车行 | 留在已失活的旧 requirementId 下,车务对其任何后续推进都会撞 605905/605913,且没有任何信号 |
换组的同一时刻整槽平移到新需求,响应回填平移基数 |
| 团期换组是否发布逐日配车快照 | 不适用(旧版本就是孤儿状态,不发快照) | 平移这一档只做整槽平移,仍不发布逐日快照(新需求停在 PENDING_REVIEW,须经管理员审核 + C2 提交车务后才放行) |
六.7、影响评估
- 是否破坏向后兼容: 否。新增响应字段,旧前端忽略它不受影响;入参契约与既有错误码零变化。
- 前端是否必须同步上线: 否。字段是可选适配;若前端不读取该字段,端点行为(换组成功、旧配车被平移)照常生效,只是前端看不到"本次平移了几行"这个信息。
- 前端 workaround 清理点: 无。此前该场景下前端没有任何字段可用于感知"旧配车是否被平移",因此没有需要清理的旧逻辑。
七、不影响范围
- 仅影响: 团期子订单在订单详情页「改提/换组」用车需求后的响应体,以及旧版已排车行是否被后端平移这一行为。
- 零影响:
- 请求参数(
VehicleRequirementReqVO零变化) - 首次提交(
INIT_SUBMIT)与完成后调整(DONE_ADJUST)两个分支的既有字段语义(previousVersion/assignmentDeletedCount等) - 非团期(核心)订单提交用车需求的行为——该路径
migratedAssignmentCount恒 0 且不新增 DB 查询,与改动前完全一致 - 该端点既有错误码(零新增)
- 派单看板、逐日配车快照发布等下游读接口的响应结构(本次不改写它们)
- 请求参数(
八、测试环境已验证
服务:hl-order-service-v3 + hl-fleet-service,合并提交 cb876bf780(PR #8563)已合入 dev-v3 并部署测试网关。
新增单测(均为源码可核实的真实用例,覆盖以下场景):
hl-order-service-v3 RequirementServiceTest(6 条):
upsertVehicle_groupOrderPendingEdit_migratesPreviousRequirement:团期改提换版 → 登记平移信号,migratedAssignmentCount=3(按旧需求 ID 精确统计,非按新需求 ID 误统计)upsertVehicle_groupOrderPendingEditNoAssignment_migratedCountZero:旧需求名下无在途配车 → 仍登记平移信号,migratedAssignmentCount=0upsertVehicle_groupOrderSameContent_idempotentNoopNoMigrate:同内容重放(IDEMPOTENT_NOOP)→ 不登记平移信号,不查询镜像表,migratedAssignmentCount=0upsertVehicle_coreOrderPendingEdit_migratedCountZero:非团期订单改提 →migratedAssignmentCount恒 0,不新增 DB 查询upsertVehicleForOrderAdjustment_groupOrderCompleted_noMigrate:订单已完成(COMPLETED)→ 不发平移信号upsertVehicleForOrderAdjustment_groupOrderNotTerminal_stillMigrates:同订单调整入口、订单非终态 → 照常发平移信号(上一条的阳性对照)
hl-fleet-service AssignmentServiceTest(6 条,验证可派性闸放宽范围不外溢):
expand_团期改提新需求待审核_放行整槽平移expand_非待审核需求换版平移_仍按既有出口发布逐日快照(阳性对照)expand_不可派且非待审核需求_仍然拒绝expand_待审核需求但无前序需求_仍然拒绝create_当前需求待审核_仍抛605906(放宽不外溢到一步派定)restoreCancel_当前需求待审核_仍拒绝恢复(放宽不外溢到撤销取消)
另有 mapper 层 OrderVehicleAssignmentMapperTest 新增 2 条、跨服务状态字面量对齐 RequirementStatusTest 新增 1 条。
十、相关文档
- 关联 Issue: wx/HL#8530
- 关联 PR: wx/HL#8563
关联 / 联系人
链接
- Issue: #8530
- PR: #8563
- Merge commit: cb876bf780
联系人
- 后端负责人: @wx