文件
hl-api-changelog/changelogs-v2/2026-09/22_8152_团期用车需求补车辆规格与接送机汇总-修改接口-管理后台.md
T

54 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 8152 团期用车需求补车辆规格(座位/车辆数/特殊诉求/备注),新增子订单用车需求记录端点,汇总与预检补接送机口径 admin wx(GIT) 修改接口 deployed not_required verified mmg 14cb7110ab6072af1dc3ee767951771be9972436 v2.1 2026-09-22 一次提交覆盖三张工单:#8152 团级乘车分组补车辆规格四字段 + 三个新错误码(809116/809117/809118);#8151 新增 GET .../requirement/vehicle-households 并给 requirement-summary 补 transferSummary;#8153 给 requirement/confirm-check 补 transferSubmitEnabled 与 transferDeclaredWithoutRequirement。gateway_status: not_required —— 本批零网关改动,/v3/admin/** 通配已配在 hl-gateway application.yml 的 order-service-v3 路由上,无新增 /admin/ 前缀。frontend_status: pending —— 新增端点与新增字段均需前端渲染,后端不代填。 前端已交付(hl-admin v2.1 @ 14cb7110):用车板块全链路——编辑弹窗规格四字段+paired rule 前置 809118、余座负值直显不 clamp 不拦提交;新建 VehicleSummarySection(两套字段名分开映射)与 VehicleHouseholdsSection(户数≠行数);confirm-check 接送机缺口提示不随免车/未开放短路。 订正残留已清(0b65814a06):VehicleHouseholdsSection 注释与 spec 夹具换车务口径真值,渲染面本就纯透传无行为变更。 2026-09-22 dev-v3

order-v3 团期需求: 团级用车需求补车辆规格,新增子订单用车需求记录端点,汇总/预检补接送机口径

存放目录: 二期(v3) → changelogs-v2/2026-09/

服务: hl-order-service-v3(团期需求域)、hl-fleet-service(配车覆盖度基线,无对外接口变化) PR: 见文末「关联 / 联系人」 Issue: #8152 / #8151 / #8153 日期: 2026-09-22 影响范围: 管理后台「团期详情 → 查看需求」Tab 的用车板块(团级正式用车需求编辑弹窗、子订单用车需求记录、全团需求汇总、整体确认预检)


⚠️ 关键变化(非必须,本版与上版行为不同 / 纠错 / 撤销时必写)

一条口径不一致必须在页面上原样透出,不要自行抹平:

  • 拦截口径不扣司机位:PUT .../vehicle-requirement 的座位充足性校验判的是 seats × count < 该组最大单日乘车人数,总座位里含驾驶位。
  • 回显口径扣司机位:响应里的 remainingPassengerSeats = max(0, seats × count − count) − 该组最大单日乘车人数,每辆车扣 1 个司机位。
  • 于是 20 座 × 1 辆 / 20 人能保存成功,而返回的 remainingPassengerSeats 是 -1。

展示侧:remainingPassengerSeats 必须允许负数,不能 clamp 到 0。负值就是缺口,clamp 之后「刚好坐不下 1 人」与「刚好坐满」在页面上完全同形,运营拿不到补车信号。

🔴 提交侧(更要紧的一条):保存成功的分组,其 remainingPassengerSeats 可以为负数。这是「余座缺口」的展示值,不是校验失败信号,前端不得据此拦截提交。是否允许保存由后端 809116 判定(口径:seats × count 与该组最大乘车人数比较,不扣司机位);前端只需把负数如实显示为缺口,用于提示运营补车。

响应体里没有任何字段表示「这一单已经过了后端闸门」——remainingPassengerSeats 是唯一的座位信号。若前端按「负数 = 不合法」做提交拦截,20 座 × 1 辆 / 20 人这类组合在 UI 上就永远提交不了,而后端 API 是放行的:严口径事实上变成了闸门,且后端全绿、日志无异常、无人会发现。


一、背景(选填)

团级正式用车需求原先只填车型文本,车务拿到的是「35座大巴」这种字符串,排车时「几座 × 几辆」只能靠人问;同时团期管理员在「查看需求」Tab 里看不到定制师逐户报了什么(用房侧早有「汇总 + 子订单订房记录」上下两块,用车只有团级那一块),等于对着一个汇总数字签字。本批补齐三件事:团级分组的车辆规格、子订单用车需求记录端点、接送机(TRANSFER)在汇总与预检里的口径。

维度 本批之前 本批之后
团级乘车分组可填规格 仅车型文本 车型 + 座位数 + 车辆数 + 特殊诉求标签 + 备注
团期「查看需求」用车板块 只有团级正式需求一块 团级正式需求 + 子订单用车需求记录(新端点)
requirement-summary 车侧口径 只统计行程用车(TRAVEL) 车侧字段口径不变,接送机另挂 transferSummary
整体确认预检的接送机信息 无 transferSubmitEnabled + transferDeclaredWithoutRequirement 缺口名单

二、变更接口清单

# 接口 方法 路径 变更类型 说明
1 保存团期正式用车需求 PUT /v3/admin/order/group-batch/{groupBatchId}/vehicle-requirement 请求体新增 4 字段 + 响应新增 8 字段 + 3 个新错误码 分组元素补 seats/count/specialTags/remark
2 读团期正式用车需求 GET /v3/admin/order/group-batch/{groupBatchId}/vehicle-requirement 响应新增 8 字段 与 1 共用同一响应体,原样回显
3 团期子订单用车需求记录 GET /v3/admin/order/group-batch/{groupBatchId}/requirement/vehicle-households 新增接口 形态对齐既有 hotel-households
4 全团需求汇总 GET /v3/admin/order/group-batch/{groupBatchId}/requirement-summary 响应新增 transferSummary 既有车侧字段零改动
5 整体确认需求缺失预检 GET /v3/admin/order/group-batch/{groupBatchId}/requirement/confirm-check 响应新增 2 字段 接送机开关 + 缺口名单

三、接口详情

1. 保存团期正式用车需求 PUT /v3/admin/order/group-batch/{groupBatchId}/vehicle-requirement

VO: GroupVehicleRequirementSaveReqVO → GroupVehicleRequirementRespVO

使用场景

团期详情「查看需求 → 团级正式用车需求」编辑弹窗点保存。语义是整份全量替换:未出现在本次提交里的分组会被移出当前版本。本批在分组元素里新增了 4 个可填字段,其余字段与提交语义均不变。

入参

字段 位置 类型 必填 约束 说明
groupBatchId Path Long ✅ - 团期聚合主键
version Body Integer ❌ 首次保存传 null,其后回传上次拿到的值 乐观锁;不一致抛 809102
remark Body String ❌ ≤500 整份需求备注
groups Body Array ✅ 可以是空数组(@NotNull 非 @NotEmpty) 全部乘车分组;有在团需车户却零分组抛 809103
groups[].groupId Body Long ❌ 新增分组传 null 带上它即声明「这就是库里那一组」,此时 groupCode 不得变更(否则 809104)
groups[].groupCode Body String ✅ ≤32,同一份内不得重复 直接作为车费 alloc_group
groups[].vehicleType Body String ✅ ≤64 车型文本/字典值,不设档位枚举
groups[].serviceStartDate Body LocalDate ✅ yyyy-MM-dd 本组服务开始日
groups[].serviceEndDate Body LocalDate ✅ 不早于开始日 本组服务结束日
groups[].seats Body Integer ❌ @Min(1);与 count 同填或同空 本批新增 该组单车座位数;存量分组可不传
groups[].count Body Integer ❌ @Min(1);与 seats 同填或同空 本批新增 该组车辆数量;只填一半抛 809118
groups[].specialTags Body Array<String> ❌ 取值须在字典 vehicle_special_demand 内 本批新增 特殊诉求标签编码数组;含字典外编码整份拒绝(809117)
groups[].remark Body String ❌ ≤500 本批新增 该组备注 / 其他诉求
groups[].days Body Array ✅ 非空,且正好铺满本组服务日范围 逐日用车人数与成员
groups[].days[].tripDate Body LocalDate ✅ 落在本组服务日范围内、不重复、不缺日 越界或重复抛 809105,缺日抛 809106
groups[].days[].headcount Body Integer ✅ @Min(1),且 ≥ 当日成员户数 该组该日乘车人数(不是户数)
groups[].days[].memberOrderIds Body Array<Long> ✅ 非空,须全属本团在团户 该组该日实际乘车的子订单集合

出参 Result<GroupVehicleRequirementRespVO>

字段 类型 说明
requirementId String 正式需求主键(Long 序列化为字符串)
groupBatchId String 团期聚合主键(Long 序列化为字符串)
status String DRAFT / CONFIRMED / DISPATCHED / DONE / PENDING_RECONFIRM / CANCELLED;PUT 后为 DRAFT
version Integer 版本号,下次提交须回传
remark String 整份备注(撤回/免车会追加,不覆盖)
confirmedBy String 整份确认人;DRAFT 时为 null
confirmedAt LocalDateTime 整份确认时间;DRAFT 时为 null
planRefreshState String 配车刷新状态原值;null = 从未登记过刷新
planRefreshReplayCount Integer 人工受控重投累计次数,上限 5
blockedStage String 团期被阻断阶段快照;null = 未阻断
planRefreshStalled Boolean 刷新是否已停滞、不会自愈(恒非 null),判「要不要现在找人」看它
planRefreshStalledReason String STATE_FAILED / COMMAND_FAILED / TIMEOUT;未停滞为 null
planRefreshTimeoutAt LocalDateTime 本轮刷新超时时刻;非 PENDING 为 null
planRefreshReplayExhausted Boolean 人工重投额度是否耗尽(恒非 null)
groups Array 全部乘车分组;整团免车态为空数组
groups[].groupId String 分组主键(Long 序列化为字符串),下次提交同一组必须回传
groups[].groupCode String 分组键 = 车费 alloc_group
groups[].vehicleType String 车型文本/字典值
groups[].vehicleTypeName String 本批新增 车型中文名,后端下发,前端不自己映射编码
groups[].serviceStartDate / serviceEndDate LocalDate 本组服务日范围
groups[].seats Integer 本批新增 单车座位数;存量分组为 null(表示待填),不是 0
groups[].count Integer 本批新增 车辆数量;存量分组为 null
groups[].specialTags Array<SpecialTagItem> 本批新增 特殊诉求标签(code + name);存量分组为空数组
groups[].remark String 本批新增 该组备注;存量分组为 null
groups[].totalSeatCount Integer 本批新增 总座位数 = seats × count(含驾驶位);座位或数量缺一即为 null
groups[].maxHeadcount Integer 本批新增 该组 days 里的最大用车人数
groups[].remainingPassengerSeats Integer 本批新增 余座 = 扣司机位后的可乘座位 − maxHeadcount;可为负;座位或数量缺一即为 null
groups[].specialTags[].code / name String 字典编码 / 中文名;字典查不到该编码时 name 为 null(不回落成编码)
groups[].days[].tripDate LocalDate 团期行程日
groups[].days[].headcount Integer 该组该日用车人数
groups[].days[].memberOrderIds Array<String> 成员子订单集合(Long 序列化为字符串)
groups[].days[].memberOrderCount Integer 当日成员户数 = memberOrderIds.size(),供填人数时对照

请求示例

{
  "version": 3,
  "remark": "9/13 起换大巴",
  "groups": [
    {
      "groupId": "1867000000009",
      "groupCode": "BUS",
      "vehicleType": "35座大巴",
      "serviceStartDate": "2026-09-12",
      "serviceEndDate": "2026-09-13",
      "seats": 19,
      "count": 2,
      "specialTags": ["child_seat"],
      "remark": "含高速费",
      "days": [
        { "tripDate": "2026-09-12", "headcount": 9, "memberOrderIds": [2101506167043985410] },
        { "tripDate": "2026-09-13", "headcount": 9, "memberOrderIds": [2101506167043985410] }
      ]
    }
  ]
}

响应示例

{
  "code": 200,
  "message": "成功",
  "data": {
    "requirementId": "1867000000101",
    "groupBatchId": "2101506167098511362",
    "status": "DRAFT",
    "version": 4,
    "remark": "9/13 起换大巴",
    "confirmedBy": null,
    "confirmedAt": null,
    "planRefreshState": null,
    "planRefreshReplayCount": null,
    "blockedStage": null,
    "planRefreshStalled": false,
    "planRefreshStalledReason": null,
    "planRefreshTimeoutAt": null,
    "planRefreshReplayExhausted": false,
    "groups": [
      {
        "groupId": "1867000000009",
        "groupCode": "BUS",
        "vehicleType": "35座大巴",
        "vehicleTypeName": "大巴",
        "serviceStartDate": "2026-09-12",
        "serviceEndDate": "2026-09-13",
        "seats": 19,
        "count": 2,
        "specialTags": [{ "code": "child_seat", "name": "儿童安全座椅" }],
        "remark": "含高速费",
        "totalSeatCount": 38,
        "maxHeadcount": 9,
        "remainingPassengerSeats": 27,
        "days": [
          {
            "tripDate": "2026-09-12",
            "headcount": 9,
            "memberOrderIds": ["2101506167043985410"],
            "memberOrderCount": 1
          },
          {
            "tripDate": "2026-09-13",
            "headcount": 9,
            "memberOrderIds": ["2101506167043985410"],
            "memberOrderCount": 1
          }
        ]
      }
    ]
  },
  "success": true
}

空数据 / 降级响应

  • 整团没有在团需车户时,groups: [] 是合法提交,响应 groups 为空数组。
  • 存量分组(本批之前建的)回显时 seats/count/remark 为 null、specialTags 为 []、totalSeatCount/remainingPassengerSeats 为 null。null 表示「这一组还没填过车辆规格」,与填了 0 是两件事(0 通不过 @Min(1)),前端不要把 null 兜成 0。
  • 车型中文名依赖车队侧车型库:查不到编码或车队不可用时 vehicleTypeName 为 null,接口仍 200,不阻断页面。
{ "code": 200, "message": "成功", "data": { "groups": [] }, "success": true }

错误响应

{
  "code": 809116,
  "message": "第 BUS 组座位数不足:19 座 × 1 辆 = 19 座,少于该组最大乘车人数 20 人",
  "success": false,
  "data": null
}
{
  "code": 809118,
  "message": "第 BUS 组的座位数与车辆数必须同时填写,或同时留空",
  "success": false,
  "data": null
}
{
  "code": 809117,
  "message": "第 BUS 组特殊诉求标签 wheelchair_lift 不在字典内,请从下拉项中选择",
  "success": false,
  "data": null
}

业务边界

  • 报文里「第 {0} 组」的 {0} 填的是 groupCode,不是序号。809116/809117/809118 三条均如此,报文渲染出来形如「第 BUS 组…」,前端可直接展示、也可据此定位是哪一组填错。
  • 一次只抛一条:整份提交的多条违规按校验遍历顺序收集,只抛第一条。前端改完一处再保存可能撞上下一条。
  • 座位充足性判据 = seats × count < 该组最大单日乘车人数,不扣司机位(拦截口径),与响应里扣司机位的 remainingPassengerSeats(回显口径)刻意差一个司机位。这样「刚好坐满、司机另开一辆」的既有排法不会被一刀拦死。
  • seats 与 count 同生同死:只填一个抛 809118;两个都不填 = 存量形态,座位校验整体跳过。
  • 标签校验在事务外先做:specialTags 要调字典服务,校验不过时零写入。字典按 ACTIVE 项放行,运营新增字典项后立即可用(后端未硬编码枚举)。
  • 标签编码会被 trim、丢空白、按首次出现去重保序后落库,前端重复提交同一编码不会报错,但回显只有一条。
  • 整份审核粒度是「整份」,不支持增量补丁;整团不需要用车请走 POST .../vehicle-requirement/waive,不要提交空 groups 代替(有需车户时会撞 809103)。
  • 乐观锁:version 不一致抛 809102,其报文第二个占位符不保证是数字(CAS 落空分支传的是说明文本),前端不要按数字解析。

2. 读团期正式用车需求 GET /v3/admin/order/group-batch/{groupBatchId}/vehicle-requirement

VO: GroupVehicleRequirementSaveReqVO → GroupVehicleRequirementRespVO

使用场景

打开团期「查看需求 → 团级正式用车需求」时读取回显,与保存端点共用同一个响应体(PUT / GET / withdraw / waive 四端点同体)。本批新增的 8 个字段在这里原样可读。

入参

字段 位置 类型 必填 约束 说明
groupBatchId Path Long ✅ - 团期聚合主键

无请求体。

出参 Result<GroupVehicleRequirementRespVO>

字段 类型 说明
data Object 结构与第 1 节「出参」逐字段相同;该团尚未形成正式用车需求时为 null
data.groups[].seats / count Integer 本批新增;存量分组为 null
data.groups[].specialTags Array<SpecialTagItem> 本批新增;存量分组为空数组
data.groups[].vehicleTypeName String 本批新增;车队不可用或无此编码时为 null
data.groups[].totalSeatCount / maxHeadcount / remainingPassengerSeats Integer 本批新增;座位或数量缺一时前者与后者为 null

请求示例

GET /v3/admin/order/group-batch/2101506167098511362/vehicle-requirement HTTP/1.1
Host: <网关域名>
Authorization: Bearer <token>

无请求体。

响应示例

{
  "code": 200,
  "message": "成功",
  "data": {
    "requirementId": "1867000000101",
    "groupBatchId": "2101506167098511362",
    "status": "CONFIRMED",
    "version": 4,
    "groups": [
      {
        "groupId": "1867000000010",
        "groupCode": "SUV",
        "vehicleType": "suv",
        "vehicleTypeName": "SUV系列",
        "serviceStartDate": "2026-09-12",
        "serviceEndDate": "2026-09-12",
        "seats": 20,
        "count": 1,
        "specialTags": [],
        "remark": null,
        "totalSeatCount": 20,
        "maxHeadcount": 20,
        "remainingPassengerSeats": -1,
        "days": [
          {
            "tripDate": "2026-09-12",
            "headcount": 20,
            "memberOrderIds": ["2101506167043985410"],
            "memberOrderCount": 1
          }
        ]
      }
    ]
  },
  "success": true
}

上面就是「关键变化」那条口径不一致的真实形态:20 座 × 1 辆载 20 人保存成功,余座 -1。

空数据 / 降级响应

该团尚未形成正式用车需求时 data 为 null(不是空对象),前端按「尚未创建」渲染:

{ "code": 200, "message": "成功", "data": null, "success": true }

错误响应

{
  "code": 403,
  "message": "无权限访问",
  "success": false,
  "data": null
}

业务边界

  • 判权码 group-batch:view,与 requirement-summary / hotel-households 同码。
  • status 不是恒定值,不要按「读到即 CONFIRMED」渲染。
  • 配车刷新观测块七个字段是只读投影,不接受回传、不参与任何提交;判「要不要现在找人」看 planRefreshStalled,别看 planRefreshState。
  • 存量团期读出来的分组 seats/count 为 null 是正常形态(绝大多数历史团期都是),不要当异常画红。

3. 团期子订单用车需求记录 GET /v3/admin/order/group-batch/{groupBatchId}/requirement/vehicle-households

VO: GroupVehicleRequirementSaveReqVO → GroupVehicleHouseholdsRespVO

使用场景

本批新增端点。 团期详情「查看需求」Tab 的用车板块下半块:上面是团级正式需求,下面就是本端点——定制师逐户报了什么。形态刻意对齐既有 .../requirement/hotel-households,前端可复用用房需求那套「每户一张卡」的展示组件。

入参

字段 位置 类型 必填 约束 说明
groupBatchId Path Long ✅ - 团期聚合主键
kind Query String ❌ TRAVEL / TRANSFER 需求类别过滤;不传则两类都返(前端默认不传)

无请求体。

出参 Result<GroupVehicleHouseholdsRespVO>

字段 类型 说明
groupBatchId String 团期 ID(Long 序列化为字符串)
departDate LocalDate 团期出发日期;未定出发日时为 null
householdCount int 本列表户数,按 orderId 去重(一户同时报了两类只算 1 户)
vehicleRowCount int 需求行数(一户可能 TRAVEL + TRANSFER 两行),与 householdCount 刻意不等价
countedHouseholdCount int 计入 requirement-summary 车侧汇总的户数(= 有活跃 TRAVEL 行的户数)
households Array 逐户明细,按 orderNo 升序
households[].orderId String 子订单 ID(Long 序列化为字符串)
households[].orderNo String 子订单团号
households[].customerName String 主联系人姓名
households[].participantCount int 出行人数(成人 + 儿童 + 小童 + 婴儿)
households[].consultantId String 定制师 ID(Long 序列化为字符串);未指派为 null
households[].consultantName String 定制师姓名;未指派为 null
households[].countedInSummary boolean 该户是否计入车侧汇总(= 有活跃 TRAVEL 行);只报接送机的户为 false
households[].requirements Array 该户的用车需求行,0~2 条(TRAVEL / TRANSFER 各至多一条活跃行)
requirements[].requirementId String 需求行 ID(Long 序列化为字符串)
requirements[].kind String TRAVEL = 行程用车 / TRANSFER = 接送机
requirements[].kindName String 类别中文名,后端下发,前端不自己映射
requirements[].status String PENDING_REVIEW / PENDING / PROCESSING / DONE
requirements[].statusName String 状态中文名(车务口径);status 为空时为 null,遇未知状态码时原样回落该 code 字符串
requirements[].fleet Array<FleetItem> 车队明细,定制师所报原貌,不做合并
requirements[].specialTags Array<SpecialTagItem> 特殊诉求标签;未填为空列表
requirements[].remark String 备注 / 其他诉求,≤500;未填为 null
requirements[].serviceDates Array<LocalDate> 本需求冻结的服务日期;未冻结时为空列表
requirements[].headcount Integer 乘车人数(不含司机)
requirements[].totalSeatCount Integer 总座位数 = Σ(seats × count);fleet 为空时为 0
requirements[].remainingPassengerSeats Integer 余座 = 可载客座位(已按每车扣 1 个司机位)− 乘车人数
requirements[].pickupRequired Boolean 是否需要平台接机/接站;仅 TRANSFER 有意义
requirements[].dropoffRequired Boolean 是否需要平台送机/送站;仅 TRANSFER 有意义
requirements[].returnRemark String 打回原因;未被打回过为 null
requirements[].returnedAt LocalDateTime 打回时间;未被打回过为 null
fleet[].vehicleType String 车型编码(suv / mpv / bus / sedan);缺失为 null
fleet[].vehicleTypeName String 车型中文名;车队不可用或无此编码时为 null
fleet[].seats / count Integer 单车座位数 / 车辆数
specialTags[].code / name String 标签编码(字典 vehicle_special_demand 的 value)/ 中文名;字典不可用或无此编码时 name 为 null

请求示例

GET /v3/admin/order/group-batch/2101506167098511362/requirement/vehicle-households?kind=TRANSFER HTTP/1.1
Host: <网关域名>
Authorization: Bearer <token>

无请求体。不传 kind 时 URL 为 .../requirement/vehicle-households,两类都返。

响应示例

{
  "code": 200,
  "message": "成功",
  "data": {
    "groupBatchId": "2101506167098511362",
    "departDate": "2026-09-12",
    "householdCount": 1,
    "vehicleRowCount": 2,
    "countedHouseholdCount": 1,
    "households": [
      {
        "orderId": "2101506167043985410",
        "orderNo": "GT-26-0081",
        "customerName": "陈昊",
        "participantCount": 4,
        "consultantId": "10001",
        "consultantName": "李四",
        "countedInSummary": true,
        "requirements": [
          {
            "requirementId": "2101506167043985411",
            "kind": "TRAVEL",
            "kindName": "行程用车",
            "status": "DONE",
            "statusName": "配车完成",
            "fleet": [
              { "vehicleType": "suv", "vehicleTypeName": "SUV系列", "seats": 7, "count": 1 }
            ],
            "specialTags": [{ "code": "child_seat", "name": "儿童安全座椅" }],
            "remark": "含高速费",
            "serviceDates": ["2026-09-12", "2026-09-13"],
            "headcount": 4,
            "totalSeatCount": 7,
            "remainingPassengerSeats": 2,
            "pickupRequired": null,
            "dropoffRequired": null,
            "returnRemark": null,
            "returnedAt": null
          },
          {
            "requirementId": "2101506167043985412",
            "kind": "TRANSFER",
            "kindName": "接送机",
            "status": "PENDING",
            "statusName": "待车队配",
            "fleet": [
              { "vehicleType": "mpv", "vehicleTypeName": "商务车", "seats": 7, "count": 1 }
            ],
            "specialTags": [],
            "remark": null,
            "serviceDates": ["2026-09-12"],
            "headcount": 4,
            "totalSeatCount": 7,
            "remainingPassengerSeats": 2,
            "pickupRequired": true,
            "dropoffRequired": false,
            "returnRemark": null,
            "returnedAt": null
          }
        ]
      }
    ]
  },
  "success": true
}

注意这一例里 householdCount=1 而 vehicleRowCount=2——表头「共 N 户」必须取 householdCount,不能取 households.length 之外的行数。

空数据 / 降级响应

团里没有任何活跃用车需求(或按 kind 过滤后为空)时,三个计数为 0、households 为空数组,接口仍 200:

{
  "code": 200,
  "message": "成功",
  "data": {
    "groupBatchId": "2101506167098511362",
    "departDate": "2026-09-12",
    "householdCount": 0,
    "vehicleRowCount": 0,
    "countedHouseholdCount": 0,
    "households": []
  },
  "success": true
}

车型中文名与标签中文名依赖车队侧与字典:不可用时对应 vehicleTypeName / name 为 null,其余字段照常返回,不 500、不阻断页面。

错误响应

{
  "code": 403,
  "message": "无权限访问",
  "success": false,
  "data": null
}

业务边界

  • 判权码与既有 hotel-households / requirement-summary 一致(group-batch:view)。
  • 户数与行数是两个数:householdCount 按 orderId 去重,vehicleRowCount 数行。照抄用房侧的写法在「一户两类」时会把表头写错。
  • 被打回的需求行不在本列表内(打回 = 原地置 REJECTED_* 并失活)。这与用房侧「列出打回户并灰显」刻意不同,前端不要按用房那套去找 countedInSummary=false 的打回户。
  • countedInSummary=false 在本端点的含义是「该户没有活跃 TRAVEL 行」——典型就是只报了接送机的户。车侧汇总只统计行程用车。
  • pickupRequired / dropoffRequired 仅 TRANSFER 行有意义,TRAVEL 行上为 null。
  • 不传 kind = 两类都返,这与提交侧「不传按 TRAVEL」的缺省相反:只读筛选若沿用提交侧缺省,接送机会整类从页面消失且无提示。
  • 🔴 statusName 口径订正说明(曾误用房务枚举 label):本端点的 statusName 原实现直接取 RequirementStatus 枚举自带的 label——该枚举被房、车两域共用,label 是房务侧视角文案(PENDING 的 label 字面量就是「待房务配」),枚举类自己的 javadoc 已写明「车需求场景下的展示文案由前端另行映射」。已由 45adfd7ed(PR #8173,fix(order-v3): 用车逐户需求读口 statusName 改用车务文案,不再吐枚举的房务 label (#8151))修正为改调 GroupBatchConverter.resolveRequirementStatusName(code, true),与团期其它用车读口(团级正式需求的 vehicleRequirementStatusName 等)同一口径。完整取值:
status statusName(车务口径)
PENDING 待车队配
PROCESSING 配车中
DONE 配车完成
PENDING_REVIEW 待审核
REJECTED_TO_CONSULTANT 已驳回定制师
REJECTED_TO_ADMIN 已驳回管理员
其它未知码 原样回落该 code 字符串
空 / null null

后两个驳回态在映射范围内,但被打回的需求行已失活、不出现在本端点的列表里(见前一条),故本列表实际只会出现前 4 行。

🔎 同源残留(写给后续做 grep 的人,两处均不影响运行):上述被订正的四个错误取值(待处理 / 处理中 / 已完成 / 待审核)在本文件之外还有两个落点,hl-admin 14cb7110 实读结果:

  • VehicleHouseholdsSection.vue:191 的注释写着「四枚举:待审核/待处理/处理中/已完成」。不影响渲染:同文件 :78 是 req.statusName 为空则回落 req.status 再回落破折号的纯透传表达式,无任何字面分支;:65 注释已明写「kindName/statusName 后端下发,禁自建编码→中文映射」。后端文案变了,页面显示跟着变。
  • __tests__/VehicleHouseholdsSection.spec.js:39,57,111,113 的夹具是 statusName: '已完成' / '待处理'。不会变红:用例断言的是透传行为(输入什么就渲染什么),夹具换成任何字符串都绿。

两处都只是文本,改与不改都不影响功能。列在这里是因为下一个人 grep「待处理」时会同时撞上它们,得能分清哪些是错的、哪些是它们本该的样子。

▶ 责任归属写在明处:这四个取值是后端先写错在本交接件里、前端照着抄的。契约文档错与实现错同等有害,已由 e011960 订正。


4. 全团需求汇总 GET /v3/admin/order/group-batch/{groupBatchId}/requirement-summary

VO: GroupVehicleRequirementSaveReqVO → GroupRequirementSummaryRespVO

使用场景

团期「查看需求」Tab 顶部汇总块。本批只做一件事:新增 transferSummary(接送机汇总)。既有车侧字段(vehicleRequirementCount、vehicleSeatSummary)口径零改动,仍只统计行程用车。

入参

字段 位置 类型 必填 约束 说明
groupBatchId Path Long ✅ - 团期聚合主键

无请求体。

出参 Result<GroupRequirementSummaryRespVO>

字段 类型 说明
activeOrderCount 等既有字段 int / Array 本批不改,口径不变
vehicleRequirementCount int 已提交用车需求的子订单数(既有,仍是行程用车口径)
vehicleSeatSummary Array 大巴座位汇总(既有,仍是行程用车口径)
transferSummary Object 本批新增 接送机汇总;恒非 null(空团也给空壳)
transferSummary.householdCount int 有活跃接送机需求的户数(按 orderId 去重)
transferSummary.pickupHouseholdCount int 其中需要平台接机/接站的户数(pickupRequired=true)
transferSummary.dropoffHouseholdCount int 其中需要平台送机/送站的户数(dropoffRequired=true)
transferSummary.headcount int 接送机总人数(各户 headcount 之和;未填人数的户按 0 计)
transferSummary.vehicleSeatSummary Array<TransferSeatItem> 按车型聚合的接送机座位/台数
transferSummary.serviceDates Array<LocalDate> 接送机涉及的服务日期去重集合(升序);未冻结服务日的需求不贡献日期
TransferSeatItem.vehicleType String 车型大类编码(suv / mpv / bus / sedan;需求里缺失时为「未知」)
TransferSeatItem.vehicleTypeName String 车型大类中文名;查不到或车队不可用时为 null
TransferSeatItem.seats int 合计座位数 = Σ(单车座位 × 台数)
TransferSeatItem.count int 合计车辆台数

请求示例

GET /v3/admin/order/group-batch/2101506167098511362/requirement-summary HTTP/1.1
Host: <网关域名>
Authorization: Bearer <token>

无请求体。

响应示例

{
  "code": 200,
  "message": "成功",
  "data": {
    "activeOrderCount": 6,
    "vehicleRequirementCount": 5,
    "vehicleSeatSummary": [
      { "vehicleType": "bus", "vehicleTypeName": "大巴", "totalSeats": 38, "totalCount": 2 }
    ],
    "transferSummary": {
      "householdCount": 2,
      "pickupHouseholdCount": 2,
      "dropoffHouseholdCount": 1,
      "headcount": 7,
      "vehicleSeatSummary": [
        { "vehicleType": "mpv", "vehicleTypeName": "商务车", "seats": 14, "count": 2 }
      ],
      "serviceDates": ["2026-09-12", "2026-09-16"]
    }
  },
  "success": true
}

空数据 / 降级响应

团里没有接送机需求(含空团)时 transferSummary 仍是对象、不是 null,计数为 0、数组为空——前端可以无条件 v-for,不必做 null 判断:

{
  "code": 200,
  "data": {
    "transferSummary": {
      "householdCount": 0,
      "pickupHouseholdCount": 0,
      "dropoffHouseholdCount": 0,
      "headcount": 0,
      "vehicleSeatSummary": [],
      "serviceDates": []
    }
  },
  "success": true
}

错误响应

{
  "code": 403,
  "message": "无权限访问",
  "success": false,
  "data": null
}

业务边界

  • 判权码 group-batch:view(本端点暴露客户特殊需求)。
  • transferSummary 与既有车侧字段是两套数:既有 vehicleSeatSummary 只含行程用车,接送机的座位/台数只在 transferSummary.vehicleSeatSummary 里。两者不要相加当「全团用车」展示,除非页面明确要合计。
  • 🔴 两组同域字段名不一致,必须写两套映射:接送机侧与行程车侧都是「按车型聚合的座位/台数」,字段含义完全相同,但名字不同(按工单接口表刻意为之,本批不改)。照既有字段名去取新对象会拿到 undefined:
含义 行程车侧 vehicleSeatSummary[](既有 VehicleSeatItem) 接送机侧 transferSummary.vehicleSeatSummary[](新增 TransferSeatItem)
车型编码 vehicleType vehicleType(同名)
车型中文名 vehicleTypeName vehicleTypeName(同名)
合计座位数 totalSeats seats
合计车辆台数 totalCount count

前端不要复用同一个渲染/取数函数,需要两套映射。

  • 车型编码在需求里缺失时归到 "未知" 一条,台数不丢。
  • headcount 把未填人数的户按 0 计,所以它可能小于 householdCount × 实际人数,只作汇总参考。

5. 整体确认需求缺失预检 GET /v3/admin/order/group-batch/{groupBatchId}/requirement/confirm-check

VO: GroupVehicleRequirementSaveReqVO → GroupBatchRequirementCheckRespVO

使用场景

「查看需求」Tab 进入时、以及点「整体确认」前调用,据 ready 置灰按钮、据 missing / vehicleMissing 展示缺哪几户。本批新增两个接送机相关字段。

入参

字段 位置 类型 必填 约束 说明
groupBatchId Path Long ✅ - 团期聚合主键

无请求体。

出参 Result<GroupBatchRequirementCheckRespVO>

字段 类型 说明
ready / missing / vehicleMissing / vehicleWaived 等既有字段 - 本批不改
transferSubmitEnabled Boolean 本批新增 当前环境是否开放接送机需求提交(配置 hl.order.requirement.transfer-kind-submit-enabled)
transferDeclaredWithoutRequirement Array 本批新增 在大交通声明了接送机、却没有活跃 TRANSFER 用车需求行的户;提示性,不进 ready、不阻断确认
该数组项 .orderId String 子订单 ID(Long 序列化为字符串)
该数组项 .orderNo String 子订单号
该数组项 .customerName String 客户姓名
该数组项 .consultantId String 定制师 adminId(Long 序列化为字符串);未指派为 null
该数组项 .consultantName String 定制师姓名快照;未指派为 null
该数组项 .pickupRequired Boolean 大交通里声明了接机/接站
该数组项 .dropoffRequired Boolean 大交通里声明了送机/送站
该数组项 .pickupRemark String 已声明批次上的文字备注(多条去重后以「;」连接);无备注为 null

请求示例

GET /v3/admin/order/group-batch/2101506167098511362/requirement/confirm-check HTTP/1.1
Host: <网关域名>
Authorization: Bearer <token>

无请求体。

响应示例

{
  "code": 200,
  "message": "成功",
  "data": {
    "groupBatchId": "2101506167098511362",
    "batchStatus": "RESOURCE_PREPARING",
    "batchStatusName": "资源准备中",
    "ready": true,
    "missing": [],
    "checkedResourceTypes": ["HOTEL", "VEHICLE"],
    "vehicleWaived": true,
    "vehicleMissing": [],
    "groupVehicleRequirementId": "1867000000101",
    "groupVehicleRequirementStatus": "CONFIRMED",
    "groupVehicleRequirementVersion": 4,
    "transferSubmitEnabled": false,
    "transferDeclaredWithoutRequirement": [
      {
        "orderId": "60123456789001",
        "orderNo": "HL2606010001",
        "customerName": "陈昊",
        "consultantId": "10001",
        "consultantName": "李四",
        "pickupRequired": true,
        "dropoffRequired": false,
        "pickupRemark": "航班 CA1234,落地 14:20"
      }
    ]
  },
  "success": true
}

上面这一例同时演示了两条边界:vehicleWaived=true(整团免车)不清空缺口名单;transferSubmitEnabled=false 时名单也照报。

空数据 / 降级响应

无此类户时 transferDeclaredWithoutRequirement 是空数组、不是 null(null 与「一条都没有」在前端是两种渲染):

{
  "code": 200,
  "data": { "transferSubmitEnabled": true, "transferDeclaredWithoutRequirement": [] },
  "success": true
}

错误响应

{
  "code": 403,
  "message": "无权限访问",
  "success": false,
  "data": null
}

业务边界

  • 🔴 transferDeclaredWithoutRequirement 不跟随 vehicleWaived 短路:整团免车豁免的是团级行程用车,与「某户自己声明了要接送机」无关。所以团期标了免车,这个名单照样可能非空——前端不要据 vehicleWaived 隐藏它。
  • 🔴 transferSubmitEnabled=false 时名单同样照报:缺口是事实,与能不能立刻补是两件事。此时前端应提示「当前环境未开放接送机需求提交」(定制师提交 kind=TRANSFER 会被 809004 拒),但不要因此隐藏名单——否则管理员会照着名单去催定制师,定制师撞一堵不会变的墙。
  • 该名单是提示不是缺失:不进 ready、不阻断整团确认、也不并进 vehicleMissing(后者语义严格是「TRANSFER 行已存在但服务日未补录」)。混在一起的代价是一个误填会把整团确认卡死,而运营没有手段标记「确认过了、不用管」。
  • 本字段只在 confirm-check 读口上有值;整团确认写口共用同一 VO,那条路径上它恒为空数组。
  • 车侧新增的两个预检原因码会出现在 vehicleMissing[].reason 里:GROUP_SPEC_INCOMPLETE(对应 809118)与 GROUP_SEATS_INSUFFICIENT(对应 809116),detail 字段与整团确认时抛出的报文逐字相同,可直接展示。

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

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

✅ 正确 / ❌ 错误 payload 对照(PUT .../vehicle-requirement 的分组元素)

场景 payload 片段
✅ 存量分组不填规格(两个都不传) { "groupCode": "BUS", "seats": null, "count": null } → 座位校验整体跳过
✅ 规格填全且坐得下 { "groupCode": "BUS", "seats": 19, "count": 2 },该组最大单日人数 36 → 38 ≥ 36 通过
✅ 刚好坐满(含驾驶位) { "groupCode": "SUV", "seats": 20, "count": 1 },最大单日人数 20 → 20 < 20 不成立,通过,回显 remainingPassengerSeats: -1
❌ 只填座位数 { "groupCode": "BUS", "seats": 19, "count": null } → 809118
❌ 只填车辆数 { "groupCode": "BUS", "seats": null, "count": 2 } → 809118
❌ 座位不足 { "groupCode": "BUS", "seats": 19, "count": 1 },最大单日人数 20 → 809116
❌ 座位数为 0 { "groupCode": "BUS", "seats": 0, "count": 1 } → 400(@Min(1)),不是 809116
❌ 字典外标签 { "groupCode": "BUS", "specialTags": ["wheelchair_lift"] }(字典无此项)→ 809117,整份零写入

切换状态时的必要动作

  • 想把某组从「已填规格」改回「未填」,必须把 seats 与 count 同时显式传 null,只清一个会撞 809118。
  • 想清空某组特殊诉求,传 "specialTags": [] 或 null 均可(后端归一处理);不要传 [""](空白项会被丢弃,但不要依赖这个)。
  • 编辑存量团期时,把 GET 拿到的 seats / count(可能是 null)原样回传即可,后端不会因为它们是 null 而拒绝。

五、数据库行为

只写外部可观察行为:

前端提交(分组元素) 再次 GET 读到
seats=19, count=2 seats: 19, count: 2, totalSeatCount: 38, remainingPassengerSeats: 38 − 2 − maxHeadcount
seats=null, count=null seats: null, count: null, totalSeatCount: null, remainingPassengerSeats: null
specialTags=["child_seat","child_seat"," "] specialTags: [{ "code": "child_seat", "name": "儿童安全座椅" }](trim + 丢空白 + 去重保序)
remark="含高速费" remark: "含高速费"

存量分组的四个新字段没有默认值:本批之前建的分组行读出来是 seats: null / count: null / specialTags: [] / remark: null,不是 0、不是空串。前端渲染必须区分「未填」与「填了值」。

整份替换语义不变:保存成功后未出现在本次提交里的分组被移出当前版本,其规格字段随之不可见。


六、边界行为

  • 未登录 → 401(网关拦截)。
  • 无 group-batch:view 权限 → 403。
  • 团期不存在 → 对应团期错误码,不 500。
  • 车队服务 / 字典服务降级 → vehicleTypeName、specialTags[].name 为 null,其余字段照常返回,不 500 不阻断页面(只读端点降级不回落成编码,避免前端把编码当中文展示)。
  • 老数据兼容 → 存量分组无规格字段 → seats / count / remark 为 null、specialTags 为 [],不异常;存量团期打开编辑弹窗后原样保存不会被新校验拒绝。
  • 生产环境:二期(order-v3 / fleet)尚未上线生产,本批路径在生产环境为 404。这是既有事实,不是本批引入的。

六.5、枚举 / 数据字典

kind(用车需求类别)

所属字段: GroupVehicleHouseholdsRespVO.households[].requirements[].kind、以及 vehicle-households 的 query 参数 kind | 类型: String

值 中文 说明
TRAVEL 行程用车 团期行程期间的用车需求;计入 requirement-summary 既有车侧字段
TRANSFER 接送机 接送机/接送站需求;计入 transferSummary,不进既有车侧字段

query 参数不传 = 两类都返。

status(子订单用车需求行状态)

所属字段: GroupVehicleHouseholdsRespVO.households[].requirements[].status | 类型: String

值 中文 说明
PENDING_REVIEW 待审核 定制师已提交,等团期侧核对
PENDING 待车队配 已进入处理队列
PROCESSING 配车中 车务作业中
DONE 配车完成 本需求行已闭环

被打回的需求行已失活,不出现在本端点的列表里;statusName 是车务口径中文名(见上表),status 为空时为 null,遇未知状态码时原样回落该 code 字符串。

specialTags(字典 vehicle_special_demand)

所属字段: GroupVehicleRequirementSaveReqVO.groups[].specialTags(提交,List<String> 编码)/ GroupVehicleRequirementRespVO.groups[].specialTags(回显,{code,name}) | 类型: String 编码

取值由运营在字典里维护、后端按字典实际内容校验,代码里不硬编码枚举——前端必须从字典下拉取值,不要自己写死一份列表。只放行字典里 ACTIVE 的项,含字典外编码整份拒绝(809117)。回显时 name 为 null 表示字典里查不到该编码(不回落成编码)。

vehicleType(车型大类编码)

所属字段: transferSummary.vehicleSeatSummary[].vehicleType、vehicle-households 的 fleet[].vehicleType | 类型: String

值 中文 说明
suv SUV系列 中文名取自车型管理库,后端下发
mpv 商务车 同上
bus 大巴 同上
sedan 轿车 同上
未知 未知 需求里车型编码缺失时的归并项(仅汇总类字段出现,台数不丢)

注意团级 GroupVehicleRequirementSaveReqVO.groups[].vehicleType 是自由文本/字典值、不设档位枚举(例:35座大巴),与上表的大类编码不是同一个取值空间。


六.6、修改前后对比

字段级对比

字段 改前 改后
PUT .../vehicle-requirement 请求 groups[] groupId / groupCode / vehicleType / serviceStartDate / serviceEndDate / days 额外接受 seats、count、specialTags、remark(均非必填)
响应 groups[] groupId / groupCode / vehicleType / 服务日 / days 额外返回 vehicleTypeName、seats、count、specialTags、remark、totalSeatCount、maxHeadcount、remainingPassengerSeats
requirement-summary 无接送机信息 新增 transferSummary(恒非 null),既有车侧字段口径不变
requirement/confirm-check 无接送机信息 新增 transferSubmitEnabled、transferDeclaredWithoutRequirement(空时为 [])
vehicleMissing[].reason 取值 不含规格相关原因 新增 GROUP_SPEC_INCOMPLETE、GROUP_SEATS_INSUFFICIENT
新端点 无 GET .../requirement/vehicle-households

行为级对比

行为 改前 改后
提交只填座位数或只填车辆数 接受(无此字段) 809118 拒绝,整份零写入
提交坐不下的规格 接受(无此字段) 809116 拒绝(判据不扣司机位)
提交字典外特殊诉求标签 接受(无此字段) 809117 拒绝,事务外先校验,零写入
存量团期原样保存 通过 仍通过(四个新字段非必填,null 时校验整体跳过)
整团免车(vehicleWaived=true)时的接送机缺口 无此名单 名单照报,不随免车短路

六.7、影响评估

  • 是否破坏向后兼容: 否。四个新请求字段全部非必填,不传即维持原行为;新增响应字段是增量。
  • 前端是否必须同步上线: 是——新增端点与新增字段需要前端渲染;不改前端时页面仍可用,但团级分组无法填写车辆规格、看不到子订单用车记录与接送机汇总。
  • 前端 workaround 清理点:
    • 若此前在前端自行维护过一份 vehicle_special_demand 标签中文映射表,可撤掉,改用后端下发的 specialTags[].name。
    • 若此前在前端自行维护过车型编码→中文的映射,可撤掉,改用 vehicleTypeName。
    • 若此前把 remainingPassengerSeats 之类余座数做过 Math.max(0, x) 处理,必须撤掉——负值是有效信号。
    • 同理,不要新增「余座为负则禁止保存」的前端校验:那会把后端放行的组合在 UI 上锁死(见「关键变化」提交侧那条)。

七、不影响范围(显式声明, 帮前端/QA 缩小排查面)

  • 仅影响: 管理后台「团期详情 → 查看需求」Tab 的用车板块(团级正式用车需求、子订单用车需求记录、全团汇总、整体确认预检)。
  • 零影响:
    • requirement-summary 的用房侧全部字段(dailyRoomBreakdown、hotelNeededOrderCount 等)与 hotel-households 端点。
    • requirement-summary 既有车侧字段 vehicleRequirementCount / vehicleSeatSummary 的口径(仍只统计行程用车)。
    • 子订单侧用车需求提交端点的字段与校验(本批不改定制师提交侧)。
    • POST .../requirement/confirm(整团确认写口)的判决逻辑:新增的接送机缺口名单不进 ready、不阻断确认。
    • POST .../vehicle-requirement/withdraw / waive / reopen 三个写端点的语义(它们与 PUT/GET 共用响应体,因此同样多出 8 个字段,但行为不变)。
    • 历史数据:存量分组不迁移,四个新字段保持 null,下次编辑保存时才可能写入。

八、测试环境已验证

网关路由:本批零网关改动。/v3/admin/** 通配已配在 hl-gateway 的 order-service-v3 路由上,新增的 .../requirement/vehicle-households 落在既有通配内,无新增 /admin/ 前缀需要配路由(故 gateway_status: not_required)。

自动化回归(分支 feat/8152-group-vehicle-structured,本批新增/改写的用例类):

GroupVehicleRequirementSaveTest              保存链路(含四个新字段落库与回显)      ✓
GroupVehicleRequirementValidateTest          809116 / 809117 / 809118 三条校验        ✓
VehicleSeatCalculatorTest                    余座口径(扣司机位、允许为负)           ✓
GroupBatchVehicleHouseholdServiceTest        vehicle-households 户数/行数/kind 过滤   ✓
GroupBatchRequirementSummaryTest             transferSummary 聚合与空团空壳           ✓
GroupVehicleRequirementConfirmCheckTest      transferSubmitEnabled / 缺口名单不短路   ✓
TransferDeclarationSupportTest               大交通声明 → 缺口名单推导                ✓
RequirementServiceVehicleKindsQueryTest      TRAVEL / TRANSFER 分类取数               ✓
GroupDispatchCoverageCalculatorTest(fleet) 团级规格进配车覆盖度基线                 ✓
RedLineArchTest                              架构红线门禁                             ✓

数据库变更:V20260922_401__order_group_vehicle_group_add_fleet_fields.sql,四列全部可空无默认值(存量行保持 null,见「五、数据库行为」)。

活体实测(测试服网关 https://api.test.1814.love:9443,2026-09-22 13:0x–13:1x;hl-order-service-v3 @ f1986f996,hl-fleet-service @ c4321f961)。取一个带真实接送机需求的团期(3 户,其中 pickup 2 户、dropoff 1 户,合计 6 人,车型汇总 suv / 15 座 / 3 辆)逐个请求:

端点 HTTP 业务 code 实测要点
GET .../vehicle-requirement 200 200 分组元素 8 个新字段全部出现:vehicleTypeName seats count specialTags remark totalSeatCount maxHeadcount remainingPassengerSeats。该团期分组属存量数据,除 maxHeadcount = 6 外新字段为 null / 空数组——存量行的 GET 侧兼容已实证
GET .../requirement/vehicle-households 200 200 householdCount = 3、vehicleRowCount = 3、countedHouseholdCount = 0、households[] 返回 3 条真实行(含 kind / status / fleet / serviceDates)
同端点 ?kind=TRANSFER 200 200 过滤参数被接受,返回同 3 条(均为 TRANSFER),无报错
GET .../requirement-summary 200 200 transferSummary 节点出现,6 个子字段全部有值:householdCount = 3 / pickupHouseholdCount = 2 / dropoffHouseholdCount = 1 / headcount = 6 / vehicleSeatSummary[] = 1 条 / serviceDates = ["2026-10-30"]
GET .../requirement/confirm-check 200 200 transferSubmitEnabled = true(Boolean)、transferDeclaredWithoutRequirement = [](数组)

⚠️ 上表最后一行的空数组是阴性对照,不是「该字段恒为空」:该团期的 3 户全都有 TRANSFER 需求行,本就不该进缺口名单。字段的类型与位置已固定,按契约对接即可;名单非空时的元素结构见本篇「三、接口详情」第 5 节的字段表。


十、相关文档

  • 关联 Issue: wx/HL#8152、wx/HL#8151、wx/HL#8153
  • 同批交接件: changelogs-v2/2026-09/22_8154_团期管理员只读查看子订单与金额面端点收回-修复-管理后台.md(团期管理员权限行为变更)
  • 既有对位端点(形态参考): changelogs-v2/2026-09/20_8046_团期用房新增子订单订房记录接口-新增接口-管理后台.md

关联 / 联系人

链接

联系人

  • 后端负责人: @wx