文件
hl-api-changelog/changelogs-v2/2026-09/30_8559_团期用车户数计入汇总读数不随kind筛选变化-修改接口-管理后台.md

20 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 8559 团期子订单用车需求记录:countedHouseholdCount / countedInSummary 不再随 kind 筛选归零 admin wx(GIT) 修改接口 deployed verified not_required PR #8612 已 squash 合并 dev-v3(3ecf387979),hl-order-service-v3 dev-v3 分支已滚测试服。本条只改取值语义,字段名、字段个数、HTTP 形态全部不变。 2026-09-30 dev-v3

hl-order-service-v3: 团期子订单用车需求记录的「计入汇总」读数不再随 kind 筛选归零

存放目录: changelogs-v2/2026-09/ 服务: hl-order-service-v3 (端口 8086) PR: #8612 Issue: #8559 日期: 2026-09-30 影响范围: 团期「查看需求」Tab 用车板块逐户明细端点 GET /v3/admin/order/group-batch/{groupBatchId}/requirement/vehicle-households 的两个取值(顶层 countedHouseholdCount、每户 households[].countedInSummary)


⚠️ 关键变化

  • 🔴 这是取值语义纠错,不是字段变更:countedHouseholdCount 和 households[].countedInSummary 的字段名、类型、位置全部没动,变的是它们在带 kind 筛选时返回的值。
  • 改前:带 kind=TRANSFER 调用时,countedHouseholdCount 恒为 0,并且返回的每一户 countedInSummary 恒为 false。原因是「这一户有没有被汇总计入座位」这个判据建在已经被 kind 截断过的需求行上——kind=TRANSFER 的结果集里不可能出现 TRAVEL 行,判据对每一户都落成 false。而团级汇总里那些户的座位是实实在在加进去的,同一页面两块数据互相矛盾。
  • 改后:判据改成「这一户在全部活跃需求行里有没有 TRAVEL 行」,与本次 kind 筛选无关。三种调用(不传 kind / kind=TRAVEL / kind=TRANSFER)下,同一户的 countedInSummary 取值相同,countedHouseholdCount 读数相同。
  • 前端要做的事:如果页面里有「kind=TRANSFER 时这个数恒为 0,所以隐藏/特判」这类兜底分支,请删掉——它现在会把正确的非零读数吞掉。另外不要再用「countedInSummary 全 false」去推断当前处于接送机筛选态。
  • 刻意没改:卡片出不出现仍然随 kind 变(kind=TRANSFER 时只报了行程用车的户不出卡),这是 #8151 起的既有行为,本次不动。
  • 刻意没改:householdCount(应报车户数)与 vehicleRowCount(需求行数)的口径,本次一个字都没动。

一、背景

团期「查看需求」Tab 的用车板块是上下两块:上面是团级汇总,下面是逐户明细。逐户明细支持按 kind 切换筛选(行程用车 / 接送机 / 全部)。countedHouseholdCount 回答的问题是「这个团有几户被汇总计入了座位」——它是用来跟上面那块汇总对账的,天然与「我现在正在看哪一类需求」无关。

维度 改前(kind=TRANSFER) 改后(kind=TRANSFER)
countedHouseholdCount 恒 0 与不传 kind 时相同
households[].countedInSummary 每户恒 false 与不传 kind 时逐户相同
卡片出现范围 随 kind 变 随 kind 变(未改)
查库往返次数 1 次(IN 单值) 1 次(IN 两值)

二、变更接口清单

# 接口 方法 路径 变更类型 说明
1 团期子订单用车需求记录 GET /v3/admin/order/group-batch/{groupBatchId}/requirement/vehicle-households 取值语义修正 countedHouseholdCount 与 households[].countedInSummary 不再随 kind 筛选归零

三、接口详情

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

VO: GroupVehicleHouseholdsRespVO

使用场景

团期详情「查看需求」Tab 的用车板块下半部分(逐户明细列表)。进入 Tab 时前端默认不传 kind(两类都返);用户点「行程用车 / 接送机」切页签时带上 kind。本端点只读,无副作用。权限点 group-batch:view。

入参

字段 位置 类型 必填 约束 说明
groupBatchId Path Long ✅ 团期主订单 ID 团期不存在时抛团期未找到错误
kind Query String ❌ TRAVEL / TRANSFER,不传或空白 = 两类都返 其它取值抛 809000「用车需求类别非法」。注意与提交侧「不传按 TRAVEL」的缺省刻意相反

出参 Result<GroupVehicleHouseholdsRespVO>

字段 类型 说明
groupBatchId String 团期主订单 ID(雪花,序列化为字符串)
departDate String(yyyy-MM-dd) 团期出发日,可为 null
endDate String(yyyy-MM-dd) 团期结束日,与团期详情同源,可为 null
householdCount Integer 应报车户数 = households 数组长度(含一份需求都没提交的空卡)
vehicleRowCount Integer 需求行数 = 各户 requirements 长度之和;可以小于 householdCount,不要当不变式用
countedHouseholdCount Integer 🔴 被汇总计入座位的户数 = households 中 countedInSummary=true 的条数。不随 kind 筛选变化,三种筛选读数相同。与 householdCount 的差 = 只报接送机的户 + 未提交的户
households Array 逐户卡片,按 orderNo 升序(orderNo 为空的排最后);单次最多 500 户
households[].orderId String 子订单 ID(雪花,序列化为字符串)
households[].orderNo String 子订单号
households[].teamNo String 团号,可为 null(不用订单号顶替)
households[].customerName String 客户姓名
households[].participantCount Integer 出行人数
households[].consultantId String 定制师 adminId,未指派为 null
households[].consultantName String 定制师姓名,未指派为 null
households[].countedInSummary Boolean 🔴 该户是否被团级汇总计入座位。不随 kind 筛选变化,同一户三种筛选下取值相同
households[].status String 展示用需求状态;该户一份需求都没提交时为 null
households[].statusName String 状态中文名,status 为 null 时为 null
households[].requirements Array 该户活跃需求行,0~2 条;无行时为空数组不是 null
households[].requirements[].requirementId String 需求行 ID(雪花,序列化为字符串)
households[].requirements[].kind String TRAVEL / TRANSFER
households[].requirements[].kindName String 类别中文名
households[].requirements[].status String PENDING_REVIEW / PENDING / PROCESSING / DONE
households[].requirements[].statusName String 状态中文名
households[].requirements[].fleet Array 车型项:vehicleType / vehicleTypeName / seats / count
households[].requirements[].specialTags Array 特殊诉求标签:code / name
households[].requirements[].remark String 备注,≤500,可为 null
households[].requirements[].serviceDates Array<String> 服务日期(yyyy-MM-dd)
households[].requirements[].headcount Integer 用车人数
households[].requirements[].totalSeatCount Integer 总座位数
households[].requirements[].remainingPassengerSeats Integer 余座(扣司机位后)
households[].requirements[].pickupRequired Boolean 仅 TRANSFER 行有值,TRAVEL 行为 null
households[].requirements[].dropoffRequired Boolean 仅 TRANSFER 行有值,TRAVEL 行为 null
households[].requirements[].returnRemark String 打回备注,可为 null
households[].requirements[].returnedAt String(date-time) 打回时刻,可为 null

请求示例

GET /v3/admin/order/group-batch/2101690789438570497/requirement/vehicle-households?kind=TRANSFER HTTP/1.1
Host: <admin-gateway>
Authorization: Bearer <admin-token>

响应示例

{
  "code": 200,
  "message": "成功",
  "success": true,
  "data": {
    "groupBatchId": "2101690789438570497",
    "departDate": "2026-09-12",
    "endDate": "2026-09-16",
    "householdCount": 3,
    "vehicleRowCount": 1,
    "countedHouseholdCount": 2,
    "households": [
      {
        "orderId": "2102000000000000001",
        "orderNo": "HL20260912100000001",
        "teamNo": "26-0480",
        "customerName": "陈昊",
        "participantCount": 4,
        "consultantId": "10001",
        "consultantName": "李四",
        "countedInSummary": true,
        "status": "PENDING",
        "statusName": "待车队配",
        "requirements": [
          {
            "requirementId": "2103000000000000011",
            "kind": "TRANSFER",
            "kindName": "接送机",
            "status": "PENDING",
            "statusName": "待车队配",
            "fleet": [
              { "vehicleType": "suv", "vehicleTypeName": "SUV", "seats": 7, "count": 1 }
            ],
            "specialTags": [
              { "code": "child_seat", "name": "儿童安全座椅" }
            ],
            "remark": null,
            "serviceDates": ["2026-09-12"],
            "headcount": 4,
            "totalSeatCount": 7,
            "remainingPassengerSeats": 2,
            "pickupRequired": true,
            "dropoffRequired": false,
            "returnRemark": null,
            "returnedAt": null
          }
        ]
      },
      {
        "orderId": "2102000000000000002",
        "orderNo": "HL20260912100000002",
        "teamNo": "26-0480",
        "customerName": "王琳",
        "participantCount": 2,
        "consultantId": "10001",
        "consultantName": "李四",
        "countedInSummary": true,
        "status": null,
        "statusName": null,
        "requirements": []
      },
      {
        "orderId": "2102000000000000003",
        "orderNo": "HL20260912100000003",
        "teamNo": null,
        "customerName": "赵敏",
        "participantCount": 3,
        "consultantId": null,
        "consultantName": null,
        "countedInSummary": false,
        "status": null,
        "statusName": null,
        "requirements": []
      }
    ]
  }
}

上例即改后行为:kind=TRANSFER 筛选下仍然有 countedHouseholdCount=2(前两户各有一条活跃 TRAVEL 行,被团级汇总计入了座位),只有第三户没报行程用车所以是 false。改前这三户的 countedInSummary 会全是 false、countedHouseholdCount 会是 0。

空数据 / 降级响应

团期下没有在团子订单(全部退团 / 取消)时,三个计数全 0、households 为空数组(不是 null):

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

单次返回的户数上限为 500 户,超过时截断返回前 500 条并在服务端留 warn,不报错——页面仍可用。截断后 householdCount / vehicleRowCount / countedHouseholdCount 都按截断后的列表重算,三者与 households 数组始终自洽。

错误响应

kind 传了 TRAVEL / TRANSFER 以外的值:

{
  "code": 809000,
  "message": "用车需求类别非法:BUS",
  "success": false,
  "data": null
}

业务边界

  • 鉴权:需要权限点 group-batch:view;未登录由网关拦截返 401。
  • 只读:本端点零写入,重复调用无副作用,可安全轮询。
  • 户范围:在团 = 仅排除 CANCELLED。退团 / 取消的户不出现在列表里。
  • 只取活跃行:被打回的需求行已失活,不在本列表内(与用房侧「列出打回户」的行为刻意不同)。因此一户被打回后在这里表现为 requirements: [] 的空卡,而不是灰条。
  • 卡片范围仍随 kind 变:卡片集合 = 「应报车的户」∪「本次筛选命中需求行的户」。这一条本次未改。
  • countedInSummary 不随 kind 变:它读的是该户在全部活跃行里有没有 TRAVEL 行。
  • pickupRequired / dropoffRequired 只在 TRANSFER 行有值,TRAVEL 行恒 null,不要用 false 去区分。
  • 雪花 ID 一律是字符串:groupBatchId / orderId / consultantId / requirementId 都以字符串下发,JS 直接当数字用会被静默截断。

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

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

✅ 正确 / ❌ 错误调用对照

场景 请求
✅ 进 Tab 默认拉全部 GET .../vehicle-households(不带 kind)
✅ 切到行程用车页签 GET .../vehicle-households?kind=TRAVEL
✅ 切到接送机页签 GET .../vehicle-households?kind=TRANSFER
✅ 显式传空值 GET .../vehicle-households?kind=(空白按「两类都返」处理)
❌ 传车型当类别 GET .../vehicle-households?kind=bus → 809000
❌ 传小写类别 GET .../vehicle-households?kind=transfer → 809000

切换筛选时的必要动作

切换 kind 时,顶部「计入汇总 N 户」这类读数不需要跟着置灰或隐藏——它在三种筛选下是同一个数。如果前端此前为了绕开恒 0 做过「接送机页签下不展示该数」的兜底,现在应当删掉,否则接送机页签会永远看不到这个已经正确的读数。


五、数据库行为

本端点是 GET 只读,零写入:不建行、不改行、不软删、不产生任何 outbox / MQ 事件。

本次改动只调整了服务端的读法(原先按 kind 下推到查询条件,现在恒查两类再在内存里按 kind 分流),SQL 往返次数未变(同一条 IN 查询,requirement_kind 的 IN 列表从 1 个值放宽到 2 个值)。


六、边界行为

  • 未登录 → 401(网关拦截)。
  • 权限点缺失 → 权限校验失败,不返回数据。
  • 团期 ID 不存在 → 抛团期未找到业务错误,HTTP 200 + 业务错误码。
  • 团期下无在团子订单 → 三个计数 0 + households: [],不报错。
  • 户数超 500 → 截断到前 500 条,三个计数按截断后重算,HTTP 200。
  • 在团订单 ID 存在但订单行缺失(脏数据)→ 跳过该户并在服务端留 warn,整页仍可打开。
  • 需求行 requirement_kind 为空的脏行 → 显式跳过,不进任何计数。
  • 老数据兼容:历史需求行缺 seats / count 等字段时对应位为 null,不异常。

六.5、枚举 / 数据字典

kind(用车需求类别,VehicleRequirementKind)

所属字段: 请求 Query kind、响应 households[].requirements[].kind | 类型: String

值 中文 说明
TRAVEL 行程用车 团期行程期间的用车需求;countedInSummary 的判据只认这一类
TRANSFER 接送机 接送机 / 接送站需求;pickupRequired / dropoffRequired 只在这一类上有值

请求侧不传或传空白 = 两类都返(不是「默认 TRAVEL」)。

status(需求行状态)

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

值 中文 说明
PENDING_REVIEW 待审核 定制师已提交,等团期管理员下发车务
PENDING 待车队配 已下发车务,等车队配车
PROCESSING 配车中 车务处理中
DONE 配车完成 已完成

户级 status 为 null 表示该户一份活跃需求都没有(空卡)。


六.6、修改前后对比

字段级对比

字段 改前 改后
countedHouseholdCount 字段存在,类型 Integer;kind=TRANSFER 时恒 0 字段、类型不变;三种筛选读数相同
households[].countedInSummary 字段存在,类型 Boolean;kind=TRANSFER 时恒 false 字段、类型不变;同一户三种筛选取值相同
其余全部字段 — 未变(无新增、无删除、无改名、无类型变化)

行为级对比

行为 改前 改后
不传 kind 时的两个读数 正确 正确(未变)
kind=TRAVEL 时的两个读数 正确 正确(未变)
kind=TRANSFER 时的两个读数 countedHouseholdCount=0、每户 countedInSummary=false 与不传 kind 时一致
「计入汇总」的判据数据源 已被 kind 截断的需求行 该户的全部活跃需求行
卡片是否随 kind 变 变 变(未改)
householdCount / vehicleRowCount — 未变

六.7、影响评估

  • 是否破坏向后兼容: 否(无字段增删改名;只是 kind=TRANSFER 时的取值由恒 0 / 恒 false 变为真实值)
  • 前端是否必须同步上线: 否(不改也能正常渲染,只是接送机页签下该数从「永远 0」变成真实值)
  • 前端 workaround 清理点: 若页面里有「kind=TRANSFER 时 countedHouseholdCount 恒 0,所以隐藏该数 / 走另一套算法 / 用 countedInSummary 全 false 判断当前筛选态」这类兜底分支,删掉它们——保留会吞掉正确读数或做出错误的筛选态判断。

七、不影响范围

  • 仅影响: GET /v3/admin/order/group-batch/{groupBatchId}/requirement/vehicle-households 的 countedHouseholdCount 与 households[].countedInSummary 两个取值。
  • 零影响:
    • 团级用车汇总端点(本次改的是明细侧读法,汇总侧一个字没动)
    • 团期正式用车需求的存 / 读 / 撤回 / 免车四个端点
    • 用房侧 requirement/hotel-households
    • 单户用车需求的提交、下发、打回链路
    • 团期配车(fleet 侧)任何端点
    • 历史数据:本次只改读法,不做任何数据迁移

八、测试环境已验证

  • 代码事实(对 origin/dev-v3 逐一查证):
    • 合并提交 3ecf387979(PR #8612 squash 合并进 dev-v3)。
    • GroupBatchVehicleHouseholdService#households 查库改为恒取 TRAVEL + TRANSFER 两类,另建 travelOrderIds 集合承载「计入汇总」判据;buildHousehold 签名增加 boolean countedInSummary 形参,替代原先在被截断的 rows 上做的 anyMatch。
    • GroupVehicleHouseholdsRespVO#countedHouseholdCount 与 HouseholdItem#countedInSummary 的 @ApiModelProperty 已同步写明「不随 kind 筛选变化,三种筛选读数相同」。
    • 卡片集合仍取自按 kind 过滤后的 rowsByOrder(既有行为,未改)。
  • 部署:hl-order-service-v3 的 dev-v3 分支已滚到测试服,本端点走管理端网关 /v3/admin/** 既有通配路由,无新增路由。
GET /v3/admin/order/group-batch/{groupBatchId}/requirement/vehicle-households            → 200 ✓
GET /v3/admin/order/group-batch/{groupBatchId}/requirement/vehicle-households?kind=TRAVEL → 200 ✓
GET /v3/admin/order/group-batch/{groupBatchId}/requirement/vehicle-households?kind=TRANSFER → 200 + countedHouseholdCount 与前两次一致 ✓

九、相关历史 PR

PR Issue 说明 是否仍有效
— #8151 首次提供本端点(逐户明细 + kind 筛选) ✅ 有效
— #8195 缺陷 2:householdCount 改为「应报车户数」含空卡;缺陷 5:endDate 与团期详情同源 ✅ 有效
本 PR #8612 #8559 「计入汇总」判据改为不受 kind 截断 ✅ 最新

十、相关文档

关联 / 联系人

链接

联系人

  • 后端负责人: @wx