32 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 | 8562 | 团期逐户用车列表区分「从未提交」与「已被打回待重提」,打回明细走新字段下发 | admin | wx(GIT) | 修改接口 | deployed | not_required | implemented | hl-admin(claude-opus-4-8) | e3f3d55265bf7f017d795e6e049601cee700dbfc | v2.1 | 2026-09-30 | GET /v3/admin/order/group-batch/{groupBatchId}/requirement/vehicle-households 的 households[] 新增三个字段:submitState(户级提交态,恒非 null,三取值 NEVER_SUBMITTED 从未提交 / SUBMITTED 已提交 / REJECTED_PENDING_RESUBMIT 已被打回待重提)、submitStateName(其中文名,后端下发)、rejectedRequirements(该户当前处于打回待重提的类别明细,恒非 null,无打回时为空数组,按展示序 TRAVEL 在前)。背景:用车的打回是「原地置 REJECTED_* + is_active=0」,被打回的户因此没有任何活跃需求行,与从未提交的户在 status 上完全同形(都是 null),车务照 status 催办会把「已交过、只是被驳回」和「压根没动过」混成一堆。四条必须照做的限定:(1) status 字段的取值规则一字未改、仍只由活跃行决定,判「有没有提交过」一律读 submitState,不要读 status 是否为 null;(2) requirements 列表内容零变化,被打回的行仍然不在里面,打回信息只在 rejectedRequirements;(3) rejectedRequirements 的元素刻意不与需求行同构(只有类别/打回状态/打回意见/打回时刻/版本号,没有车队明细、服务日期、座位数),不可当作需求行渲染,否则同一户会出现与活跃行自相矛盾的一条;(4) householdCount 口径再放宽一项,不再恒等于 needs_vehicle=true 的户数——一个 needs_vehicle 为假、没有活跃行、但有一类被打回的户现在也会进列表,判「这户为什么在列表里」看 submitState,不要拿 needsVehicle 反推。另两个数一字不动:vehicleRowCount(被打回的户贡献 0 行)与 countedHouseholdCount(只认活跃 TRAVEL 行),座位汇总口径不会因为有人被驳回而跳变。submitState 与 requirements 同受 kind 筛选影响:传 kind=TRAVEL 时,一个只有接送机被打回的户读成 NEVER_SUBMITTED;要看全貌就不传 kind(不传 = 两类都返)。已知边界(定案、非缺陷):TRANSFER 需求被「不再需要接送」失活(#8435)且没有新版时,既无活跃行也非打回,读成 NEVER_SUBMITTED,与从未提交对催办动作的要求一致,故不另立一态。入参、分页、排序、错误码(589500 / 589507 / 809000 / 401)与其余响应字段均未变化。;前端已交付:逐户表车侧判提交/判打回改读 submitState,「已打回」筛选与徽标覆盖车侧打回户,无活跃行户级文案用后端 submitStateName,rejectedRequirements 单独提示行不当需求行渲染,4 例定向测试全绿(hl-admin e3f3d552) | 2026-09-30 | dev-v3 |
团期用车逐户列表:区分「从未提交」与「已被打回待重提」
存放目录: 二期(order-v3/fleet)→
changelogs-v2/2026-09/
⚠️ 关键变化
households[]新增三个字段:submitState(户级提交态,恒非 null)、submitStateName(其中文名)、rejectedRequirements(该户当前处于打回待重提的类别明细,恒非 null,无打回时为空数组)。- 🔴 判「这户有没有提交过」一律读
submitState,不要读status是否为null。用车的打回是「原地置REJECTED_*+is_active=0」⇒ 被打回的户没有任何活跃需求行,status同样是null,与从未提交的户完全同形。照status催办会去催一个已经交过、只是被驳回的人,而真正该催的「按意见重提」在页面上看不出来。 status的取值规则一字未改(仍是活跃行展示序首条),statusName同理。本次只新增旁路字段,既有映射与读数不受影响。requirements列表内容零变化:被打回的行仍然不在里面(它已失活)。打回信息只在新字段rejectedRequirements里。- 🔴
rejectedRequirements的元素不是需求行,不可当作需求行渲染:它刻意与requirements[]不同构——只带类别 / 打回状态 / 打回意见 / 打回时刻 / 版本号,没有车队明细、服务日期、座位数。把它拼进需求表会让同一户出现一条与活跃行自相矛盾的需求。 - 🔴
householdCount口径再放宽一项,不再恒等于「needs_vehicle=true的户数」:一个needs_vehicle为假、又没有活跃行、但有一类被打回的户现在也会进列表(它正是要催重提的人)。判「这户为什么在列表里」看submitState,不要拿needsVehicle反推。 - 另两个数一字不动:
vehicleRowCount(被打回的户贡献 0 行)与countedHouseholdCount(只认活跃 TRAVEL 行)。座位汇总口径不会因为「有人被驳回」而跳变。 submitState随kind筛选变化(与requirements同一口径):传kind=TRAVEL时,一个只有接送机被打回的户读成NEVER_SUBMITTED。要看全貌就不传kind(不传 = 两类都返)。
一、背景(选填)
团期「查看需求」Tab 的用车逐户明细是车务与团期管理员的催办页:谁还没报、谁报了在等审、谁被驳回要改。但用车的打回实现是「把那一版原地置成 REJECTED_* 并把 is_active 置 0」,于是被打回的户在这个只读活跃行的端点里表现为「0 条需求行 + status 为 null」——与「从未提交」一模一样。更糟的是:needs_vehicle 为假、又没有活跃行的户改前压根不出卡,而被打回的户恰恰可能是这个形状,催办页上会整户消失。本次补的就是「这户到底是没交过,还是交过被驳回」这一维,以及「被驳回的是哪一类、意见是什么、什么时候驳的」这几个催办必需值。
二、变更接口清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|---|---|---|---|---|
| 1 | 团期子订单用车需求记录 | GET | /v3/admin/order/group-batch/{groupBatchId}/requirement/vehicle-households |
修改 | households[] 新增 submitState / submitStateName / rejectedRequirements;householdCount 口径放宽含打回户 |
三、接口详情
1. 团期子订单用车需求记录 GET /v3/admin/order/group-batch/{groupBatchId}/requirement/vehicle-households
VO: Long groupBatchId + String kind(query)→ GroupVehicleHouseholdsRespVO
使用场景
团期「查看需求」Tab 的用车逐户明细(汇总块下面那一块)。用于回答「这个团还差谁的用车需求」:本次起可以把「催首次提交」和「催按意见重提」分成两组,并在被驳回的户上直接展示驳回意见与时刻。
入参
入参本次零变化。
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| groupBatchId | path | Long | 是 | 雪花 ID;团期不存在返 589500 | 团期 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 | 本列表户数(按 orderId 去重),恒等于 households 长度。口径放宽:= 应报车户 ∪ 有活跃需求行的户 ∪ 处于打回待重提的户;不再恒等于 needs_vehicle=true 的户数 |
| vehicleRowCount | Integer | 需求行数 = Σ 各户 requirements 长度。未提交与被打回的户贡献 0 行,故可能小于 householdCount(别当「行数 ≥ 户数」不变量) |
| countedHouseholdCount | Integer | 计入车侧汇总的户数(= 有活跃 TRAVEL 行的户数)。判据一字未改,不随 kind 筛选变化,也不因有人被驳回而变 |
| households | Array | 逐户明细,按 orderNo 升序(orderNo 为空的排最后,按 orderId 兜底稳定) |
| households[].orderId | String | 子订单 ID |
| households[].orderNo | String | 子订单编号(非团号,形如 HL + yyyyMMddHHmmssSSS) |
| households[].teamNo | String | 子订单团号;未付订金尚未分配时为 null(不兜底、不回退成订单号) |
| households[].customerName | String | 主联系人姓名 |
| households[].participantCount | Integer | 出行人数(成人 + 儿童 + 小童 + 婴儿) |
| households[].consultantId | String | 定制师 ID;未指派为 null |
| households[].consultantName | String | 定制师姓名;未指派为 null |
| households[].countedInSummary | Boolean | 该户是否计入车侧汇总(= 有活跃 TRAVEL 行);未变 |
| households[].status | String | 户级用车需求状态:仅由活跃行决定。null = 该户当前没有活跃需求行(从未提交与已被打回失活两种情况都是 null,要分辨读 submitState);非 null 时取展示序首条(TRAVEL 优先)的状态。取值规则一字未改 |
| households[].statusName | String | 户级状态中文名;status 为 null 时同为 null。PENDING_REVIEW 按 kind 分两套文案(TRAVEL=待提交车务 / TRANSFER=待审核,#8218);未变 |
| households[].requirements | Array | 该户的活跃用车需求行,0~2 条(TRAVEL / TRANSFER 各至多一条)。被打回的行已失活、不在本列表内;该户没有活跃行时为空数组(不是 null)。本列表内容零变化 |
| households[].submitState | String | 🆕 户级提交态,恒非 null:NEVER_SUBMITTED / SUBMITTED / REJECTED_PENDING_RESUBMIT。status 为 null 时靠它分辨两种空态;一户两类不同时按展示序首条(TRAVEL 优先)取;随 kind 筛选变化 |
| households[].submitStateName | String | 🆕 户级提交态中文名,与 submitState 一一对应:从未提交 / 已提交 / 已被打回待重提。后端下发,前端不自己映射 |
| households[].rejectedRequirements | Array | 🆕 该户当前处于打回待重提的类别明细,按展示序(TRAVEL 在前)。恒非 null,无打回时为空数组。不是需求行,不可当作需求行渲染 |
| households[].rejectedRequirements[].kind | String | 需求类别:TRAVEL 行程用车 / TRANSFER 接送机 |
| households[].rejectedRequirements[].kindName | String | 类别中文名,后端下发 |
| households[].rejectedRequirements[].status | String | 打回状态编码:REJECTED_TO_CONSULTANT = 团期管理员打回定制师 / REJECTED_TO_ADMIN = 车务退回团期管理员 |
| households[].rejectedRequirements[].statusName | String | 打回状态中文名,与 requirements[].statusName 同一套车务文案:已驳回定制师 / 已驳回管理员 |
| households[].rejectedRequirements[].returnRemark | String | 打回意见;历史数据可能为 null |
| households[].rejectedRequirements[].returnedAt | String | 打回时刻 yyyy-MM-dd HH:mm:ss;历史数据可能为 null |
| households[].rejectedRequirements[].version | Integer | 被打回的那一版版本号。TRAVEL 与 TRANSFER 各自独立递增,不可跨类比大小 |
请求示例
GET /v3/admin/order/group-batch/2104839654727618562/requirement/vehicle-households
Authorization: Bearer {token}
按类别筛选(只看行程用车):
GET /v3/admin/order/group-batch/2104839654727618562/requirement/vehicle-households?kind=TRAVEL
Authorization: Bearer {token}
响应示例
三户分别落在三个提交态上。requirements[] 行内字段与本次改动前完全一致,这里只保留几个便于对读的字段,未列出的行内字段(fleet / serviceDates / specialTags / 座位数等)照旧下发。
{
"code": 200,
"message": "成功",
"data": {
"groupBatchId": "2104839654727618562",
"departDate": "2026-10-06",
"endDate": "2026-10-10",
"householdCount": 3,
"vehicleRowCount": 1,
"countedHouseholdCount": 1,
"households": [
{
"orderId": "2104839654727618570",
"orderNo": "HL20261006103015001",
"teamNo": "T26-3963",
"customerName": "周雅",
"participantCount": 4,
"consultantId": "1901233114509312088",
"consultantName": "苏晴",
"countedInSummary": true,
"status": "PENDING_REVIEW",
"statusName": "待提交车务",
"requirements": [
{
"requirementId": "2104839777884160001",
"kind": "TRAVEL",
"kindName": "行程用车",
"status": "PENDING_REVIEW",
"statusName": "待提交车务",
"headcount": 4,
"returnRemark": null,
"returnedAt": null
}
],
"submitState": "SUBMITTED",
"submitStateName": "已提交",
"rejectedRequirements": []
},
{
"orderId": "2104839654727618571",
"orderNo": "HL20261006103015002",
"teamNo": "T26-3964",
"customerName": "郑文博",
"participantCount": 2,
"consultantId": "1901233114509312088",
"consultantName": "苏晴",
"countedInSummary": false,
"status": null,
"statusName": null,
"requirements": [],
"submitState": "REJECTED_PENDING_RESUBMIT",
"submitStateName": "已被打回待重提",
"rejectedRequirements": [
{
"kind": "TRAVEL",
"kindName": "行程用车",
"status": "REJECTED_TO_CONSULTANT",
"statusName": "已驳回定制师",
"returnRemark": "第三天上午的用车时间与行程冲突,请改后重提",
"returnedAt": "2026-09-29 16:42:11",
"version": 2
}
]
},
{
"orderId": "2104839654727618572",
"orderNo": "HL20261006103015003",
"teamNo": null,
"customerName": "何嘉宁",
"participantCount": 3,
"consultantId": null,
"consultantName": null,
"countedInSummary": false,
"status": null,
"statusName": null,
"requirements": [],
"submitState": "NEVER_SUBMITTED",
"submitStateName": "从未提交",
"rejectedRequirements": []
}
]
},
"success": true
}
空数据 / 降级响应
- 团期下没有在团子订单:
households为空数组[],三个计数均为0,departDate/endDate照常回显,不报错。 - 某户没有活跃需求行:
requirements为空数组(不是null),status与statusName为null,而submitState仍然有确定取值(NEVER_SUBMITTED或REJECTED_PENDING_RESUBMIT)——前端不必对submitState判空。 - 某户没有被打回的类别:
rejectedRequirements为空数组(不是null)。 - 在团订单 ID 存在但订单行缺失(跨团挂单 / 订单被物理删这类数据异常):该户被跳过并在服务端留痕,整页照常返回;三个计数都按最终列表重算,不会出现「表头 42 户、列表里只有 30 户」这种自相矛盾的响应。
- 单次返回上限 500 户,超出按
orderNo升序截断并在服务端留痕;截断后三个计数同样按截断后的列表重算。
错误响应
{
"code": 809000,
"message": "用车需求类别非法:BOTH",
"data": null,
"success": false
}
809000 用车需求类别非法:{0}:kind传了TRAVEL/TRANSFER之外的非空值(例如ALL、BOTH、小写拼错)。要「两类都返」请不传该参数或传空串。589500 团期不存在:groupBatchId查不到。589507 无操作权限(当前角色未授予团期权限,或该团期不在您名下):缺团期查看权限,或该团期不在当前账号名下。401:未登录或令牌失效(网关返 HTTP 200 + 信封code: 401,请按信封code判定)。
业务边界
- 🔴 判「有没有提交过」读
submitState,不读status是否为null。打回 = 原地置REJECTED_*+is_active=0⇒ 打回户与从未提交户的status都是null,在status这一维上不可分辨。status的取值规则本次一字未改。 - 🔴
requirements列表内容零变化:被打回的行不在里面,打回信息只在rejectedRequirements。不要为了展示驳回意见去翻requirements[].returnRemark——那一格记的是该活跃行历史上被打回过的痕迹(已重提后仍可能有值),不是「当前处于打回态」。 - 🔴
rejectedRequirements不可当作需求行渲染:它与requirements[]刻意不同构,没有车队明细 / 服务日期 / 座位数。需要看需求内容时读该户的活跃行,或走需求版本历史端点。 - 🔴
householdCount不再恒等于needs_vehicle=true的户数:一个needs_vehicle为假、没有活跃行、但有一类被打回的户也会进列表。判「这户为什么在列表里」看submitState,不要拿needsVehicle反推。 rejectedRequirements只列「当前」处于打回待重提的类别,不是历史打回记录:打回后已重新提交的类别不出现在这里(那一类的现状在requirements里),否则页面会永远挂着一条早已处理完的驳回。- 一户两类状态不同时,
submitState按展示序首条取(TRAVEL 优先),与status同一条规则。例:TRAVEL 有活跃行、TRANSFER 被打回 ⇒submitState是SUBMITTED,而rejectedRequirements里有 TRANSFER 那一条。要逐类判断一律读requirements[].status与rejectedRequirements[].kind,不要用户级的submitState推单类。 submitState随kind筛选变化:传kind=TRAVEL时,一个只有接送机被打回的户读成NEVER_SUBMITTED(该类别不在筛选范围内)。要看全貌不传kind。- 已知边界(定案,非缺陷):TRANSFER 需求被「不再需要接送」失活(#8435)且之后没有新版本时,该户既无活跃行也不处于打回态,会读成
NEVER_SUBMITTED。它与「从未提交」对催办动作的要求一致(要么提,要么整团免车),故不另立一态。 version不可跨类比较:TRAVEL 的 v3 与 TRANSFER 的 v3 之间没有先后关系,两类版本号各自独立递增。vehicleRowCount可能小于householdCount:未提交与被打回的户贡献 0 行。不要再把「行数 ≥ 户数」当不变量写断言。countedHouseholdCount不随kind筛选变化(#8559),也不因驳回动作变化——座位汇总口径必须稳定。- Swagger 上该端点的
notes仍按本次改动前的口径写着「被打回的需求行已失活,不在本列表内」:这句对需求行依然成立(打回行确实不进requirements),但对户不再成立——打回户现在会出现在households里。字段级语义以本交接件与各字段的@ApiModelProperty为准。
四、契约约束与正确调用方式(接口类必写)
- 两个新字段恒非 null,直接读不用判空:
submitState与rejectedRequirements对每一户都有确定取值(后者无打回时是空数组)。需要判空的仍是status/statusName/teamNo/consultantId/consultantName这些既有字段。 - 催办分组按
submitState做:NEVER_SUBMITTED→ 催首次提交;REJECTED_PENDING_RESUBMIT→ 催按意见重提(意见与时刻在rejectedRequirements里);SUBMITTED→ 具体到哪一步看status/requirements[].status。 - 不要用
status == null当「未提交」的判据:这是本次要解决的那个缺陷本身。前端若已有这段逻辑,请改为submitState === 'NEVER_SUBMITTED'。 - 不要把
rejectedRequirements并进需求行列表:两者结构刻意不同构。驳回信息建议单独渲染成一条提示条(类别 + 状态中文名 + 意见 + 时刻),与需求行区分开。 - 不要拿
needsVehicle反推「这户为什么在列表里」:列表的并集口径已变,判据是submitState。 - 中文名一律用后端下发的:
submitStateName/kindName/statusName都由后端给出,前端不要再本地维护映射表(PENDING_REVIEW的文案还会按 kind 分叉成两种,本地表必然对不上,#8218)。 - 要看全貌不传
kind:不传 = 两类都返。传了kind则requirements、rejectedRequirements、submitState、householdCount、vehicleRowCount全部随之收窄(只有countedHouseholdCount三种筛选读数相同)。 kind只接受TRAVEL/TRANSFER:想表达「全部」请不传,传ALL/BOTH会返 809000。- 错误信封按
code判:业务失败与入参校验一律 HTTP 200 + 信封code;测试环境网关对失效令牌也返回 HTTP 200 +code: 401。
五、数据库行为
本端点为只读查询,本次改动不涉及任何 DDL 与 DML:没有新增表、没有新增列、没有 Flyway 脚本、没有写入。
submitState不是数据库列,不落表、不参与任何 SQL 过滤或分组,纯粹是响应字段——所以既有的按status筛选 / 统计的扫描路径不会把它重新捡起来,也不会误计。- 打回明细取自用车需求的版本历史行(打回行已
is_active=0)。取数用一次按子订单 ID 批量的查询(与既有的活跃行查询同一形状,requirement_kind的IN列表从 1 个值放宽到 2 个值),不是逐户 N+1;整页固定若干次查询,与户数无关。 - 判「某类是否处于打回待重提」复用的是定制师提交侧闸门的同一套算法(取最高版本组、看最后一次动作是否为打回),不新造判定规则。
六、边界行为
| 场景 | status |
requirements |
submitState |
rejectedRequirements |
是否出现在列表 |
|---|---|---|---|---|---|
| 有活跃行(TRAVEL 或 TRANSFER) | 首条行的状态 | 1~2 条 | SUBMITTED |
[] |
是 |
| 从未提交过任何版本 | null |
[] |
NEVER_SUBMITTED |
[] |
是(needs_vehicle 为真即出卡) |
| 被打回、尚未重提 | null |
[] |
REJECTED_PENDING_RESUBMIT |
1~2 条 | 是(本次新增的入列路径) |
| 被打回后已重新提交 | 新行的状态 | 1~2 条 | SUBMITTED |
[](不挂已处理完的驳回) |
是 |
| TRAVEL 有活跃行 + TRANSFER 被打回 | TRAVEL 行的状态 | 1 条(TRAVEL) | SUBMITTED(按展示序首条) |
1 条(TRANSFER) | 是 |
| TRAVEL 被打回 + TRANSFER 有活跃行 | TRANSFER 行的状态 | 1 条(TRANSFER) | REJECTED_PENDING_RESUBMIT(TRAVEL 展示序在前) |
1 条(TRAVEL) | 是 |
只有 TRANSFER 被打回,且传了 kind=TRAVEL |
null |
[] |
NEVER_SUBMITTED(该类别不在筛选内) |
[] |
取决于 needs_vehicle |
| TRANSFER 被「不再需要接送」失活且无新版(#8435) | null |
[] |
NEVER_SUBMITTED(定案) |
[] |
是 |
| 在团订单行缺失(数据异常) | — | — | — | — | 跳过该户并留痕,整页照常返回 |
| 户数超过 500 | — | — | — | — | 按 orderNo 升序截断,计数按截断后重算 |
六.5、枚举 / 数据字典
户级提交态(submitState → submitStateName,新增枚举,恒非 null)
| 码 | 中文名 | 语义 | 催办动作 |
|---|---|---|---|
| NEVER_SUBMITTED | 从未提交 | 在本次筛选的类别范围内既没有活跃需求行、也不处于打回态 | 催首次提交 |
| SUBMITTED | 已提交 | 至少一类存在活跃需求行(具体到哪一步看 status) |
按 status 跟进 |
| REJECTED_PENDING_RESUBMIT | 已被打回待重提 | 没有活跃行,但最高版本组的最后一次动作是打回 | 催「按意见改完再提」 |
展示名刻意与团期子订单列表那块的「未提交」用不同的词:那块只判「有没有活跃行」,被打回的户在那里也显示「未提交」;两处若同字,本次分开的这一步在页面上就白做了。
打回状态(rejectedRequirements[].status → statusName)
| 码 | 中文名 | 谁打回的 |
|---|---|---|
| REJECTED_TO_CONSULTANT | 已驳回定制师 | 团期管理员打回定制师 |
| REJECTED_TO_ADMIN | 已驳回管理员 | 车务退回团期管理员 |
需求类别(kind → kindName,未变)
| 码 | 中文名 |
|---|---|
| TRAVEL | 行程用车 |
| TRANSFER | 接送机 |
展示序固定 TRAVEL 在前、TRANSFER 在后;requirements 与 rejectedRequirements 共用这个序。
活跃需求行状态(requirements[].status,未变):PENDING_REVIEW / PENDING / PROCESSING / DONE。REJECTED_* 不会出现在活跃行上。PENDING_REVIEW 的中文名按 kind 分叉:TRAVEL = 待提交车务、TRANSFER = 待审核(#8218)。
六.6、修改前后对比
| 字段 / 口径 | 改动前 | 改动后 |
|---|---|---|
households[].submitState |
不存在 | 🆕 恒非 null 的三态字段,是 status 为 null 时唯一能分辨「从未提交 / 已被打回」的字段 |
households[].submitStateName |
不存在 | 🆕 三态中文名,后端下发 |
households[].rejectedRequirements |
不存在(打回信息在本端点完全取不到) | 🆕 恒非 null 的数组,列当前处于打回待重提的类别 + 意见 + 时刻 + 版本号 |
households[].status / statusName |
只由活跃行决定 | 取值规则一字未改(仍只由活跃行决定)。变的只是文档:不能再拿它判「有没有提交过」 |
households[].requirements |
只含活跃行,打回行不在其中 | 内容零变化 |
householdCount |
= 应报车户 ∪ 有活跃需求行的户;恒等于 needs_vehicle=true 的户数(needs_vehicle 创单恒真) |
并集多一项「处于打回待重提的户」⇒ 不再恒等于 needs_vehicle=true 的户数;needs_vehicle 为假但有一类被打回的户会进来 |
vehicleRowCount |
Σ 各户活跃行数 | 口径未变(打回户贡献 0 行);与 householdCount 的差额多了「打回户」这一类 |
countedHouseholdCount |
有活跃 TRAVEL 行的户数 | 一字未变,不因驳回动作跳变 |
| 被打回户是否出现在列表 | needs_vehicle 为假时不出卡(催办页上整户消失) |
出卡,submitState = REJECTED_PENDING_RESUBMIT |
| 入参 / 分页 / 排序 / 错误码 | — | 全部未变 |
六.7、影响评估
- 前端必须改的:如果页面上有「
status == null⇒ 显示未提交」这段逻辑,必须改成读submitState——不改的话打回户会继续被标成「未提交」,本次改动在页面上等于没做。 - 前端应当改的:催办清单按
submitState分两组;被驳回的户上渲染rejectedRequirements里的类别 + 状态中文名 + 意见 + 时刻。 - 前端不要做的:把
rejectedRequirements拼进需求行表格(会出现与活跃行矛盾的一条);拿needsVehicle反推入列原因;跨类比较version。 - 可能被读错的一处:
requirements[].returnRemark/returnedAt记的是该活跃行历史上被打回过的痕迹,已重提后仍可能有值;「当前处于打回态」只看rejectedRequirements是否非空。 - 列表条数会变多:
needs_vehicle为假、无活跃行、但有一类被打回的户从本次起入列。如果前端有基于户数的断言或埋点基线,会看到这一类团期的户数上升——这是预期,不是数据错误。 - 兼容性:JSON 新增字段对已有前端反序列化无影响。既有字段一个没删、没改名、没改类型。
- 无副作用面:只读端点,不涉及写入、事务、消息、权限判定变化;座位与汇总口径不变。
七、不影响范围
- 入参:
groupBatchId、kind的取值域、缺省语义(不传 = 两类)、校验规则全部未变。 - 排序与上限:
orderNo升序 +orderId兜底、单次 500 户上限未变。 - 既有响应字段:
groupBatchId/departDate/endDate/vehicleRowCount/countedHouseholdCount/households[]的既有字段(含status/statusName/requirements及行内所有字段)名称、类型、取值域、语义全部未变。 - 错误码:未新增、未删除、未改文案(589500 / 589507 / 809000 / 401)。
- 权限码:仍是团期查看权限,未收紧未放宽。
- 用房侧
hotel-households端点:本次一行未改。 - 写路径:逐户提交车务、打回、整体确认需求等写接口本次一行未改。
- 团级汇总
requirement-summary:口径与读数未变(countedHouseholdCount是它的对账口,本次刻意保持不动)。 - 网关路由:既有路由,本次无新增。
- 数据库:无 DDL、无 DML、无 Flyway 脚本。
- 小程序端:零影响。
八、测试环境已验证
本次改动的核心可验证面是「打回户与从未提交户在 status 上同形、在 submitState 上可分辨」,以及「既有三个计数与 requirements 内容不受影响」。已由下列自动化用例覆盖(hl-order-service-v3):
| 覆盖点 | 用例 |
|---|---|
打回户与从未提交户 status 相同(都是 null)、submitState 不同 |
GroupBatchVehicleHousehold8562Test#households_rejectedAndNeverSubmitted_sameStatusDifferentSubmitState |
| 打回户带出打回意见与打回状态中文名 | #households_rejectedHousehold_carriesRemarkAndStatusName |
存在打回时 requirements 仍然只含活跃行(内容零变化) |
#households_rejectionPresent_requirementsStillOnlyActiveRows |
TRAVEL 有活跃行 + TRANSFER 被打回 ⇒ submitState 按展示序首条(TRAVEL)取 |
#households_travelActiveTransferRejected_submitStateFollowsTravel |
TRAVEL 被打回 + TRANSFER 有活跃行 ⇒ submitState 同样按 TRAVEL 取 |
#households_travelRejectedTransferActive_submitStateFollowsTravel |
传 kind=TRANSFER 时 TRAVEL 的打回被筛掉 |
#households_kindTransfer_travelRejectionFilteredOut |
needs_vehicle 为假但有一类被打回的户仍然入列 |
#households_rejectedButNeedsVehicleFalse_stillListed |
完全没有打回时 submitState 为 SUBMITTED、rejectedRequirements 为空数组 |
#households_noRejectionAtAll_submitStateSubmitted |
| 打回明细按子订单 ID 批量取数(固定次数,不随户数增长) | RequirementServiceVehicleRejectionBatchTest |
九、相关历史 PR
- PR #8623(本次):
feat(order-v3): 团期逐户用车区分「从未提交」与「已被打回待重提」(#8562)。 - #8195:
householdCount改为「应报车户数」并开始包含未提交户,status/statusName两个户级字段在那一单新增。 - #8559:
countedHouseholdCount不随kind筛选变化。 - #8577:只提交接送机的户不再被判「未提交用车需求」。
- #8601:逐户提交车务与打回的
kind参数取消默认值。 - #8218:
PENDING_REVIEW的中文名按 kind 分叉(TRAVEL 待提交车务 / TRANSFER 待审核)。 - #8435:「不再需要接送」失活 TRANSFER 需求(本单已知边界的来源)。
十、相关文档
docs/CODE_RULES.md§3:VO 命名、@ApiModelProperty约定、禁 Entity 跨层(打回明细用独立 DTO 而非直接传需求行的依据)。docs/CODE_RULES.md§15.7:字典字面量单源——submitStateName/kindName/statusName由后端下发的依据。- Swagger:
hl-order-service-v3→团期需求分组。字段级语义以各字段@ApiModelProperty为准;该端点notes的那句「被打回的需求行不在本列表内」只对需求行成立、对户不成立(见「业务边界」最后一条)。
关联 / 联系人
链接
- 工单 #8562
- PR #8623
联系人
- 后端:wx
- 前端:mmg(管理后台 hl-ui)