文件
hl-api-changelog/changelogs-v2/2026-09/30_8619_团期子订单列表接送机户不再判未提交-修改接口-管理后台.md
2026-10-01 00:31:15 +08:00

24 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 8619 团期子订单列表:只报接送机的户不再判未提交,新增逐类用车需求清单字段 admin wx(GIT) 修改接口 deployed verified implemented hl-admin(claude-opus-4-8) bc9c13aaa39bab96e132a3a42515c821fa74a269 v2.1 2026-10-01 PR #8624 已 squash 合并 dev-v3(ce7cd238e9355bdc17c45f90ace02827c7db60f5),hl-order-service-v3 dev-v3 分支已滚测试服。GET /v3/admin/order/group-batch/{groupBatchId}/orders 对真实团期 2104839654727618562 实测:同户 TRAVEL+TRANSFER 两类需求状态互不覆盖、vehicleRequirements[] 按 TRAVEL 在前 TRANSFER 在后下发,589500 团期不存在错误码实测通过。所有既有字段未删改,只放宽了车需求那组字段的取值范围并新增 vehicleRequirements。;前端已交付:报名清单车需求列改逐类清单(vehicleRequirements[] 非空逐类各显一行,空数组/旧响应回落单值字段),「未提交」误报修复直显自动生效,9 例定向测试全绿(hl-admin bc9c13aa) 2026-09-30 dev-v3

存放目录: changelogs-v2/2026-09/ 服务: hl-order-service-v3 (端口 8086) PR: #8624 Issue: #8619 日期: 2026-09-30 影响范围: 管理后台团期详情页「子订单列表」/ A3 接口消费方

⚠️ 关键变化

  • 改前:GET /v3/admin/order/group-batch/{groupBatchId}/orders 的车需求四个单值字段(vehicleRequirementStatus/StatusName/Kind/KindName)只从该户 TRAVEL(行程用车) 类需求行取值。若一个户只提交了 TRANSFER(接送机) 需求、没有 TRAVEL 需求,这四个字段恒被渲染成「未提交」,即使接送机需求已经在流转甚至已完成。
  • 改后:改为按展示序(TRAVEL 优先于 TRANSFER)取该户当前活跃需求行中的首条,只提交接送机的户会如实报出接送机自己的状态,不再被误判未提交。
  • 新增字段 vehicleRequirements:GroupBatchOrderItemRespVO 新增该数组字段,逐类列出该户全部活跃车需求行(TRAVEL 在前、TRANSFER 在后),每类各自独立的 kind/kindName/status/statusName,不再只能看到"展示序首条"这一个值。该户没有任何活跃车需求行时数组是 [](空数组),不是 null。
  • vehicleRequirementKind 不再恒为 "TRAVEL":只提交接送机的户,该字段与 vehicleRequirementKindName 现在会如实报出 "TRANSFER"/"接送机"。前端如果曾经硬编码假设这两个字段只会是 TRAVEL/行程用车,需要一并放开。
  • 其余约 25 个既有字段(订单状态、支付状态、酒店需求、出行人等)取值逻辑未变。

一、背景(选填)

本单与已发布的 changelogs-v2/2026-09/30_8577_...-修改接口-管理后台.md(#8577)修的是同一症状家族(只提交接送机被误判"未提交"),但改动的是完全不同的接口/代码路径,请勿混淆:

#8577 #8619(本单)
涉及接口 PUT 保存车需求、GET 聚合草稿、GET 提交前校验(均在 GroupVehicleRequirementService) GET /v3/admin/order/group-batch/{groupBatchId}/orders(团期子订单列表,GroupBatchQueryService/GroupBatchConverter)
涉及错误码 809121/809122/809123 不涉及新增/变更错误码,沿用既有 589500
根因层 提交/校验链路 列表查询的取值范围(原只查 TRAVEL 类活跃行)

两单互不覆盖,#8577 的改动对本接口没有影响;本接口过去存在的误判问题,#8577 也没有修到。

二、变更接口清单

# 接口 方法 路径 变更类型 说明
1 团期下子订单列表(A3) GET /v3/admin/order/group-batch/{groupBatchId}/orders 响应字段语义收窄 + 新增字段 vehicleRequirementKind 不再恒为 TRAVEL;新增 vehicleRequirements[] 逐类需求清单

三、接口详情

1. 团期下子订单列表 GET /v3/admin/order/group-batch/{groupBatchId}/orders

VO: GroupBatchOrderItemRespVO

使用场景

管理后台团期详情页展示该团期下全部子订单(一个订单=一个"户")的汇总信息,含车需求配车状态一栏。前端据此渲染列表行的车需求状态标签,并可能据 vehicleRequirementKind 决定展示"行程用车"或"接送机"图标。

入参

字段 位置 类型 必填 约束 说明
groupBatchId path Long 是 团期需存在 团期ID
page query Integer 否 缺省 1,<1 归一为 1 页码,从 1 起
pageSize query Integer 否 缺省 20,<1 归一为 20,>200 截断为 200 每页条数
includeTravelers query Boolean 否 缺省 true 是否附出行人明细(证件号/手机号一律不返回)
includeNeeds query Boolean 否 缺省 true 是否附 roomCount/roomType/specialNeeds
includeCancelled query Boolean 否 缺省 false 是否含已取消子订单(缺省只返活跃集)

出参 Result<PageResult<GroupBatchOrderItemRespVO>>

字段 类型 说明
orderId String 订单ID(Long 序列化为字符串)
orderNo String 订单号
teamNo String 团号;订金支付成功后生成,未付订金为 null
customerName String 客户姓名
participantCount Integer 出行人数
orderStatus / orderStatusName String / String 订单状态/名称
flowStatus / flowStatusName String / String 流程状态/名称(12 值枚举)
reviewStatus / reviewStatusName String / String 复核状态/名称;⚠️ 与团期核单 GroupSettlementRespVO 同名字段含义相反
settlementStatus / settlementStatusName String / String 结算状态/名称;⚠️ 同样与团期核单含义相反,也不是财务 tab 的 settleStatus
payStatus / payStatusName String / String 支付状态/名称
contractStatus / contractStatusName String / String 合同状态/名称
insuranceStatus / insuranceStatusName String / String 投保状态/名称
paidAmount / balanceAmount String / String 已付金额/待付余额(BigDecimal 序列化为字符串)
hotelRequirementStatus / hotelRequirementStatusName String / String 酒店需求状态/名称;#8249 起无活跃行时为 null,不回落 PENDING
vehicleRequirementStatus String 车需求状态;本单起取该户展示序(TRAVEL 优先)首条活跃需求行的状态,不再恒来自 TRAVEL
vehicleRequirementStatusName String 车需求状态名;PENDING_REVIEW 按 kind 分叉:TRAVEL="待提交车务",TRANSFER="待审核";"未提交"现在只在该户两类需求行都不存在时才出现
vehicleRequirementKind String 车需求类别;本单起不再恒为 "TRAVEL",只提交接送机的户会报 "TRANSFER"
vehicleRequirementKindName String 车需求类别名;未知类别给 null,不回落编码
vehicleRequirements Array 本单新增。该户全部活跃车需求行,TRAVEL 在前、TRANSFER 在后;一条都没有时为 [](非 null)
consultantName String 顾问姓名
totalPrice String 订单总价
tierCode / tierName String / String 价格档位编码/名称
travelerInfoComplete Boolean 出行人信息是否完整
roomCount Integer 房间数;includeNeeds=true 时返回
roomType / roomTypeName String / String 房型编码/名称;includeNeeds=true 时返回
specialNeeds String 特殊需求;includeNeeds=true 时返回
contactPhone String 联系电话(脱敏,如 138****3046)
groupChatUnreadCount Integer 群聊未读数;user-service 不可达/Feign 超时/未登录时降级为 0
travelers Array 出行人明细;includeTravelers=true 时返回

VehicleRequirementItem(vehicleRequirements 数组元素):

字段 类型 说明
kind String 需求类别,TRAVEL / TRANSFER
kindName String 类别名,"行程用车" / "接送机"
status String 该类需求自己的状态(见六.5 枚举)
statusName String 状态名(PENDING_REVIEW 按 kind 分叉,见上)

请求示例

GET /v3/admin/order/group-batch/2104839654727618562/orders?page=1&pageSize=5&includeTravelers=false&includeNeeds=false
Authorization: Bearer {token}

响应示例

测试服真实返回(团期 2104839654727618562,3 个子订单,覆盖"两类需求并存且状态不同""仅 TRAVEL"两种场景):

{
  "code": 200,
  "message": "成功",
  "data": {
    "records": [
      {
        "orderId": "2104839654652121090",
        "orderNo": "HL20260929154414207",
        "teamNo": "26-2313",
        "customerName": "李文博",
        "participantCount": 2,
        "orderStatus": "CUSTOMIZING",
        "orderStatusName": "定制中",
        "flowStatus": "RESOURCE_PREPARING",
        "flowStatusName": "资源准备",
        "reviewStatus": null,
        "reviewStatusName": null,
        "settlementStatus": "NONE",
        "settlementStatusName": "未结算",
        "payStatus": "FULLY_PAID",
        "payStatusName": "已付全款",
        "contractStatus": null,
        "contractStatusName": null,
        "insuranceStatus": null,
        "insuranceStatusName": null,
        "paidAmount": "7360.00",
        "balanceAmount": "0.00",
        "hotelRequirementStatus": null,
        "hotelRequirementStatusName": null,
        "vehicleRequirementStatus": "DONE",
        "vehicleRequirementStatusName": "配车完成",
        "vehicleRequirementKind": "TRAVEL",
        "vehicleRequirementKindName": "行程用车",
        "vehicleRequirements": [
          {"kind": "TRAVEL", "kindName": "行程用车", "status": "DONE", "statusName": "配车完成"},
          {"kind": "TRANSFER", "kindName": "接送机", "status": "PENDING", "statusName": "待车队配"}
        ],
        "consultantName": "cw_test_7443",
        "totalPrice": "7360.00",
        "tierCode": "2A",
        "tierName": "2成人",
        "travelerInfoComplete": true,
        "roomCount": null,
        "roomType": null,
        "roomTypeName": null,
        "specialNeeds": null,
        "contactPhone": "138****3046",
        "groupChatUnreadCount": 0,
        "travelers": null
      },
      {
        "orderId": "2104839686486888449",
        "orderNo": "HL20260929154421828",
        "teamNo": "26-9436",
        "customerName": "张丽娟",
        "participantCount": 2,
        "orderStatus": "CUSTOMIZING",
        "orderStatusName": "定制中",
        "flowStatus": "PENDING_CONFIRM",
        "flowStatusName": "待确认",
        "payStatus": "FULLY_PAID",
        "payStatusName": "已付全款",
        "paidAmount": "7360.00",
        "balanceAmount": "0.00",
        "vehicleRequirementStatus": "DONE",
        "vehicleRequirementStatusName": "配车完成",
        "vehicleRequirementKind": "TRAVEL",
        "vehicleRequirementKindName": "行程用车",
        "vehicleRequirements": [
          {"kind": "TRAVEL", "kindName": "行程用车", "status": "DONE", "statusName": "配车完成"}
        ],
        "totalPrice": "7360.00",
        "tierCode": "2A",
        "tierName": "2成人",
        "contactPhone": "138****3047",
        "groupChatUnreadCount": 0
      },
      {
        "orderId": "2104839729176514562",
        "orderNo": "HL20260929154432061",
        "teamNo": "26-6559",
        "customerName": "那顺",
        "participantCount": 3,
        "orderStatus": "CUSTOMIZING",
        "orderStatusName": "定制中",
        "flowStatus": "PENDING_CONFIRM",
        "flowStatusName": "待确认",
        "payStatus": "FULLY_PAID",
        "payStatusName": "已付全款",
        "paidAmount": "11620.00",
        "balanceAmount": "0.00",
        "vehicleRequirementStatus": "DONE",
        "vehicleRequirementStatusName": "配车完成",
        "vehicleRequirementKind": "TRAVEL",
        "vehicleRequirementKindName": "行程用车",
        "vehicleRequirements": [
          {"kind": "TRAVEL", "kindName": "行程用车", "status": "DONE", "statusName": "配车完成"},
          {"kind": "TRANSFER", "kindName": "接送机", "status": "PENDING_REVIEW", "statusName": "待审核"}
        ],
        "totalPrice": "11620.00",
        "tierCode": "3A",
        "tierName": "3成人",
        "contactPhone": "138****3048",
        "groupChatUnreadCount": 0
      }
    ],
    "total": 3,
    "page": 1,
    "pageSize": 5
  },
  "traceId": null,
  "success": true
}

以上三条均取自 TRAVEL+TRANSFER 两类需求并存的户,展示了两类需求各自独立取值(第三条 TRANSFER 处于 PENDING_REVIEW 显示为"待审核",TRAVEL 处于 DONE 不受影响)。只提交接送机、完全没有 TRAVEL 需求的户是本次修复要解决的核心场景,测试服当前团期数据中暂无这类现成样本(该形态的订单目前都不挂团期),该场景由自动化回归覆盖,见"八、测试环境已验证"。

空数据 / 降级响应

分页越界的真实返回(page=999 超出总页数):

{
  "code": 200,
  "message": "成功",
  "data": {
    "records": [],
    "total": 3,
    "page": 999,
    "pageSize": 5
  },
  "traceId": null,
  "success": true
}

groupChatUnreadCount 在 user-service 不可达、Feign 调用超时或当前登录态失效时降级返回 0,不抛错、不影响本接口其余字段。

错误响应

团期不存在的真实返回:

{
  "code": 589500,
  "message": "团期不存在",
  "data": null,
  "traceId": null,
  "success": false
}

无操作权限时返回错误码 589507("无操作权限(当前角色未授予团期权限,或该团期不在您名下)",源自 GroupBatchErrorCode,本轮测试账号为 admin 全权角色未触发,未做活体验证)。

业务边界

  • groupBatchId 对应团期不存在返回 589500,data 为 null。
  • pageSize 超过 200 会被后端静默截断为 200,不报错。
  • includeCancelled 缺省 false,不传时列表不含已取消子订单。
  • vehicleRequirements 为空数组 [] 表示该户当前没有任何活跃车需求行,不是接口异常;不要用 null 判空。
  • vehicleRequirementKind/KindName 在该户尚无任何车需求行时为 null,不回落成某个默认编码。
  • 两类需求同时存在时,单值字段(vehicleRequirementStatus/Kind 等)取的是展示序(TRAVEL 优先)首条,并非"最近更新"或"按查询顺序";需要拿到每一类各自的真实状态必须读 vehicleRequirements[],不能只读单值字段。

四、契约约束与正确调用方式(接口类必写)

✅ 正确 / ❌ 错误 payload 对照

  • ✅ 正确:判断某个户是否已提交任意车需求,遍历 vehicleRequirements(长度 > 0 即已提交),或分别读取 vehicleRequirements 中 kind=TRAVEL/kind=TRANSFER 各自的 status。
  • ❌ 错误:继续假设 vehicleRequirementKind 恒为 "TRAVEL" 并据此做条件分支——只提交接送机的户会被分支判空/判错。
  • ❌ 错误:把 vehicleRequirementStatusName === "未提交" 当作"该户任意一类车需求都未提交"的充分条件——本单之后它只代表"两类都未提交",不能再用它反推"TRAVEL 未提交"或"TRANSFER 未提交"这类更细的判断,要细分请读 vehicleRequirements[]。

切换状态时的必要动作

无需前端触发任何状态切换动作;本次是纯读接口的响应字段语义调整,不涉及写操作。

五、数据库行为(涉及写操作时必写)

本接口是纯查询接口,本单未新增/变更任何表结构,也未变更任何写路径。改动仅收窄/放宽了查询车需求行时的过滤条件(原实现只按 requirement_kind = 'TRAVEL' 取活跃行,现改为按展示序取该户全部活跃行的首条,并额外把全部活跃行一并下发到 vehicleRequirements)。

六、边界行为

  • 团期不存在 → 589500,data: null。
  • 当前登录角色对该团期无权限 → 589507(源码定义,未做活体验证)。
  • page/pageSize 非法值(<1 或超范围)由后端静默归一/截断,不报参数校验错误。
  • 分页越界 → 返回 records: [],total 仍是真实总数,不报错。
  • hotelRequirementStatus/vehicleRequirementKind 等状态类字段在对应需求不存在时给 null,均不回落到某个默认状态码。
  • groupChatUnreadCount 在下游不可达时静默降级为 0。

六.5、枚举 / 数据字典(接口出现枚举时必写)

vehicleRequirementKind / vehicleRequirements[].kind(VehicleRequirementKind)

值 中文名
TRAVEL 行程用车
TRANSFER 接送机

vehicleRequirementStatus / vehicleRequirements[].status(RequirementStatus)

值 中文名(车需求语境) 备注
PENDING 待车队配
PROCESSING 配车中
DONE 配车完成
PENDING_REVIEW TRAVEL="待提交车务";TRANSFER="待审核" 同一状态码按 kind 分叉出不同中文名
REJECTED_TO_CONSULTANT 驳回顾问
REJECTED_TO_ADMIN 驳回管理员
(该户无对应需求行) 未提交 vehicleRequirementStatus/StatusName 单值字段专属,vehicleRequirements[] 数组元素不会出现这个取值——没有对应行就不会出现在数组里

六.6、修改前后对比(修改/删除类接口必写,新增跳过)

字段级对比

字段 改前 改后
vehicleRequirementStatus / StatusName 只取该户 TRAVEL 类需求行的值;无 TRAVEL 行则恒为 "未提交" 取展示序(TRAVEL 优先)首条活跃需求行的值;只要该户存在任意一类需求行就不再是"未提交"
vehicleRequirementKind / KindName 恒为 "TRAVEL"/"行程用车"(或该户无 TRAVEL 行时为 null) 如实反映展示序首条需求行的真实类别,可能是 "TRANSFER"/"接送机"
vehicleRequirements 不存在该字段 新增,数组,逐类列出该户全部活跃需求行,空时为 []

行为级对比

场景 改前 改后
只提交接送机(TRANSFER),无 TRAVEL 需求 单值字段恒报"未提交",即便接送机已在流转甚至完成 单值字段如实报接送机自己的状态;vehicleRequirements 含 1 条 TRANSFER 记录
只提交行程用车(TRAVEL) 与改后一致(回归测试覆盖,行为未变) 行为不变
两类需求都提交 单值字段只能看到 TRAVEL 一类的状态,无法从列表接口直接得知 TRANSFER 的独立状态 单值字段仍取 TRAVEL(展示序优先),但 vehicleRequirements 同时给出两类各自独立的真实状态
两类需求都未提交 "未提交"(#8249 起已是该行为) 行为不变,vehicleRequirements 为 []

六.7、影响评估(修改/删除类必写)

  • 破坏兼容:否。既有字段名称、类型、语义边界(null 代表无对应需求行)均未变,改动只是放宽了 vehicleRequirementKind 的实际取值范围、扩大了 vehicleRequirementStatus/StatusName 能反映的真实状态覆盖面。
  • 前端是否必须同步上线:若前端曾经硬编码假设 vehicleRequirementKind 恒为 "TRAVEL"(例如据此固定展示"行程用车"图标、或对非 TRAVEL 值做兜底成空白),需要同步放开,否则只提交接送机的户在前端会展示错误的类别图标/文案,但不会报错或崩溃。
  • 若前端此前为规避"接送机被误判未提交"这个已知问题,在自己代码里做过特判/兜底逻辑,本单上线后该特判可以删除。

七、不影响范围

  • hotelRequirementStatus/hotelRequirementStatusName 及其判空逻辑(#8249 行为)未变。
  • 订单状态、支付状态、合同状态、投保状态、复核/结算状态、价格档位、出行人相关字段等约 25 个既有字段未变。
  • 分页参数默认值与归一/截断规则未变。
  • includeCancelled/includeNeeds/includeTravelers 三个开关的既有行为未变。
  • #8577 修复的三个车需求提交/校验接口(PUT 保存、GET 聚合草稿、GET 提交前校验)及其错误码 809121/809122/809123,与本接口是不同代码路径,互不影响。
  • 团期详情页的"车队"chips 维度接口(/chips/vehicle)已支持 TRANSFER 类别展示,本次改动前后行为一致,不受影响。

八、测试环境已验证

活体实测(本会话,2026-09-30,测试服 dev-v3):

  1. GET /v3/admin/order/group-batch/2104839654727618562/orders?page=1&pageSize=5&includeTravelers=false&includeNeeds=false → HTTP 200,返回 3 条真实子订单记录,其中 2 条同时具有 TRAVEL+TRANSFER 两类活跃需求行,单值字段与 vehicleRequirements[] 均按预期独立报出各自状态(含 PENDING_REVIEW 在 TRANSFER 语境下正确显示为"待审核")。原文见上「响应示例」。
  2. GET /v3/admin/order/group-batch/999999999999999999/orders → HTTP 200,code:589500, message:"团期不存在"。
  3. GET /v3/admin/order/group-batch/2104839654727618562/orders?page=999&pageSize=5 → HTTP 200,records:[],total:3 保留真实总数。

自动化回归(ce7cd238e9355bdc17c45f90ace02827c7db60f5,已随 PR #8624 合入 dev-v3,覆盖测试服当前暂无现成样本的场景):

  • GroupBatchConverterTest#toOrderItemVO_transferOnly_reportsRealStatusNotNotSubmitted:该户只有一条 TRANSFER/PENDING_REVIEW 活跃行 → vehicleRequirementStatusName 报"待审核"(不是"未提交"),vehicleRequirementKind="TRANSFER",vehicleRequirements 含 1 条对应记录。这正是本单要修复的核心场景。
  • GroupBatchConverterTest#toOrderItemVO_travelOnly_legacyFieldsUnchanged:只有 TRAVEL 行时行为与改前一致(回归保护)。
  • GroupBatchConverterTest#toOrderItemVO_bothKinds_statusesStayIndependent:TRAVEL 与 TRANSFER 两类状态互不覆盖,且与查询返回顺序无关(用 TRANSFER 先于 TRAVEL 的输入顺序验证展示序不受取数顺序影响)。
  • GroupBatchConverterTest#toOrderItemVO_neitherKind_stillNotSubmitted:两类都无活跃行时仍报"未提交",vehicleRequirements 为空数组而非 null(#8249 行为回归保护)。
  • GroupBatchConverterTest#toOrderItemVO_nullVehicleRows_emptyListNotNull:上游传入 null 行集合时 vehicleRequirements 仍是空列表,不会是 null。
  • GroupBatchConverterTest#toOrderItemVO_anyExistingRow_neverRendersNotSubmitted(参数化,覆盖 TRAVEL/TRANSFER × 6 种状态共 12 种组合):只要该户存在任意一条需求行,statusName 永不为"未提交"或空白。
  • GroupVehicleStatusNameCrossOutletTest(#8218 既有门禁):同一 (状态码, kind) 对在本接口与其他读口的中文名保持一致,本次改动未破坏该跨口一致性。

十、相关文档

  • 工单:#8619
  • PR:#8624(squash 合并 ce7cd238e9355bdc17c45f90ace02827c7db60f5)
  • 关联但独立的历史修复:changelogs-v2/2026-09/30_8577_只提交接送机的户不再被判未提交用车需求-修改接口-管理后台.md(#8577,见本文「一、背景」的区分说明)

关联 / 联系人

链接

联系人

  • 后端负责人:@wx