36 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 | 8249 | 团期「查看需求」:无需求行的户不再报 PENDING、户级未提交用车需求进预检清单、六条车务报文改写为可读名称 | admin | wx(GIT) | 修改接口 | deployed | verified | not_required | 前端判 not_required:状态列 statusName||status||— 三级兜底 null 安全;PENDING 判等 12 处全无关;vehicleMissing 按 orderNo 结构化分流即契约推荐判据;809 报文零文本匹配分支(拦截器透 toast/detail 直显) | 2026-09-23 | dev-v3 |
order-v3: 团期「查看需求」页三处契约变更(含报文变更)
存放目录:
changelogs-v2/{YYYY-MM}/服务: hl-order-service-v3 (端口 8007) PR: #8286 Issue: #8249 日期: 2026-09-23 影响范围: 管理后台「团期详情 → 查看需求」tab 的子订单列表状态列、整团确认预检横幅、车务相关弹窗文案
⚠️ 关键变化
- 状态字段会返
null了:hotelRequirementStatus/vehicleRequirementStatus在「该户一条 active 需求行都没有」时返回null。改前恒回落字符串"PENDING",页面把一个根本没提交的户显示成「待房务配 / 待车队配」,与同屏预检横幅里的NOT_SUBMITTED自相矛盾。配对的*StatusName此时按该户是否需要该资源分叉:需要 →"未提交",不需要 →null。 - 预检清单多一类条目:
confirm-check的vehicleMissing[]新增reason = "HOUSEHOLD_REQUIREMENT_NOT_SUBMITTED"(错误码 809122),表示「该户在团需车、却一条行程用车需求都没提交」。它与团级的GROUP_REQUIREMENT_NOT_FOUND并列出现,不互斥、不被团级缺席短路——改前车侧只查团级正式需求,「某户一行都没提交」在预检里没有任何位置能表达。 - 🔴 报文变更:六个 809 段错误码的渲染文本被改写(雪花 ID → 可读名称 / 直接删掉标识符),见「六.6、修改前后对比」。因为
GroupVehicleViolation.detail()就是toException().getMessage(),预检横幅上的detail与确认/保存/免车弹窗里的message是同一份字符串,两处同时改变。凡是对vehicleMissing[].detail或错误message做文本匹配 / 正则解析 / 截取订单号的前端逻辑,这次会失效;纯展示(原样渲染这段人话)不需要改。订单号已经由vehicleMissing[].orderNo结构化下发,不要再从detail里抠。
一、背景
「查看需求」页上同一个团期的同一户,三处读数互相矛盾:子订单列表说「待房务配」(=已提交、等资源侧接),预检横幅说「未提报」,而整团确认点下去报的是团级的「尚未形成正式用车需求」——运营据此去催车务,实际该催的是定制师。
| 维度 | 改前 | 改后 |
|---|---|---|
无 active 需求行时 *Status |
"PENDING"(借用了真实状态之一) |
null |
无 active 需求行时 *StatusName |
「待房务配」/「待车队配」 | 「未提交」(该户需要该资源时)/ null |
| 车侧预检覆盖粒度 | 只有团级正式需求的六条校验 | 团级六条 + 逐户查行程用车需求是否提交 + 待放行接送机需求服务日回填 |
| 车务报文里的标识符 | 雪花 ID(团期 2100856430494973953、子订单 2102309919002943489) |
可读名称(团期「第3期 10月8日出发团」、子订单 HL20260922161158291)或直接省略 |
二、变更接口清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|---|---|---|---|---|
| 1 | A3 团期下子订单列表 | GET | /v3/admin/order/group-batch/{groupBatchId}/orders |
出参取值变更 | 四个需求状态字段在无 active 行时改为 null + 「未提交」 |
| 2 | GB-ADM-012 整团确认需求缺失预检 | GET | /v3/admin/order/group-batch/{groupBatchId}/requirement/confirm-check |
出参枚举扩充 + 报文变更 | vehicleMissing[].reason 新增 HOUSEHOLD_REQUIREMENT_NOT_SUBMITTED;detail 文案改写 |
三、接口详情
1. A3 团期下子订单列表 GET /v3/admin/order/group-batch/{groupBatchId}/orders
VO: Query 参数 → PageResult<GroupBatchOrderItemRespVO>
使用场景
管理后台「团期详情 → 查看需求 / 子订单」tab 打开时调用,渲染该团期下每一户的一行摘要(团号、客户、金额、房需求状态、车需求状态、定制师、出行人)。本次改动只影响其中四个需求状态字段的取值,分页与其余字段的契约不变。鉴权走团期权限码 group-batch:view,未登录由网关拦截。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| groupBatchId | Path | Long | ✅ | 雪花 ID,团期聚合主键 | 团期 ID |
| page | Query | Integer | ❌ | 缺省 1;小于 1 归一为 1 | 页码,从 1 起 |
| pageSize | Query | Integer | ❌ | 缺省 20;小于 1 归一为 20;大于 200 截断为 200 | 每页条数 |
| includeTravelers | Query | Boolean | ❌ | 缺省 true | 是否附 travelers[];证件号/手机号一律不返回 |
| includeNeeds | Query | Boolean | ❌ | 缺省 true | 是否附 roomCount / roomType / specialNeeds |
| includeCancelled | Query | Boolean | ❌ | 缺省 false | 是否含已取消子订单;缺省只返活跃集 |
出参 Result<PageResult<GroupBatchOrderItemRespVO>>
| 字段 | 类型 | 说明 |
|---|---|---|
| data.total | Long | 总条数 |
| data.page | Integer | 当前页码 |
| data.pageSize | Integer | 每页条数 |
| data.records[].orderId | String | 子订单 ID(雪花,JSON 里是字符串) |
| data.records[].orderNo | String | 订单编号 |
| data.records[].teamNo | String | 团号;订金支付成功后生成,未付订金为 null |
| data.records[].customerName | String | 客户姓名 |
| data.records[].participantCount | Integer | 出行人总数 |
| data.records[].orderStatus | String | 订单状态码 |
| data.records[].orderStatusName | String | 订单状态中文名 |
| data.records[].payStatus | String | 支付状态(UNPAID / DEPOSIT_PAID / FULLY_PAID) |
| data.records[].payStatusName | String | 支付状态中文名 |
| data.records[].contractStatus | String | 合同状态;无合同时 null |
| data.records[].contractStatusName | String | 合同状态中文名;无合同时 null |
| data.records[].insuranceStatus | String | 保险状态;无保险时 null |
| data.records[].insuranceStatusName | String | 保险状态中文名;无保险时 null |
| data.records[].paidAmount | String | 已支付金额(订金 + 尾款),两位小数字符串 |
| data.records[].balanceAmount | String | 待支付尾款金额,两位小数字符串 |
| data.records[].hotelRequirementStatus | String | 本次变更:房需求状态码;无 active 房需求行时为 null(改前回落 "PENDING") |
| data.records[].hotelRequirementStatusName | String | 本次变更:房需求状态中文名;hotelRequirementStatus 为 null 时该户需房则为 "未提交"、不需房则为 null |
| data.records[].vehicleRequirementStatus | String | 本次变更:车需求状态码;无 active 行时为 null(改前回落 "PENDING") |
| data.records[].vehicleRequirementStatusName | String | 本次变更:车需求状态中文名;vehicleRequirementStatus 为 null 时该户需车则为 "未提交"、不需车则为 null |
| data.records[].consultantName | String | 定制师姓名(创单时固化) |
| data.records[].totalPrice | String | 本户应收,两位小数字符串;取消单为 "0.00" |
| data.records[].tierCode | String | 档位码(形如 2A1C) |
| data.records[].tierName | String | 档位名(形如 2成人1儿童) |
| data.records[].travelerInfoComplete | Boolean | 出行人资料是否齐全 |
| data.records[].roomCount | Integer | 房数;includeNeeds=true 时返回 |
| data.records[].roomType | String | 房型文本;includeNeeds=true 时返回,无需求行时 null |
| data.records[].roomTypeName | String | 房型中文名;字典不可达时回落原值 |
| data.records[].specialNeeds | String | 特殊需求;缺需求行时回落订单备注 |
| data.records[].contactPhone | String | 联系人手机号(脱敏,前 3 后 4) |
| data.records[].groupChatUnreadCount | Integer | 「联系定制师」按钮未读角标 |
| data.records[].travelers[].name | String | 出行人姓名 |
| data.records[].travelers[].type | String | 出行人类型(ADULT / CHILD / YOUNG_CHILD / BABY) |
| data.records[].travelers[].age | Integer | 出团日时的周岁;缺出生日期时 null |
| data.records[].travelers[].birthdayInTrip | Boolean | 是否行程期间过生日 |
请求示例
GET /v3/admin/order/group-batch/2100856430494973953/orders HTTP/1.1
Host: <网关地址>
Authorization: Bearer <admin token>
响应示例
{
"code": 200,
"message": "成功",
"data": {
"records": [
{
"orderId": "2100856430239121409",
"orderNo": "HL20260918155619496",
"teamNo": "26-7060",
"customerName": "王有亿",
"participantCount": 3,
"orderStatus": "CUSTOMIZING",
"orderStatusName": "定制中",
"payStatus": "DEPOSIT_PAID",
"payStatusName": "已付定金",
"contractStatus": null,
"contractStatusName": null,
"insuranceStatus": null,
"insuranceStatusName": null,
"paidAmount": "1500.00",
"balanceAmount": "9440.00",
"hotelRequirementStatus": "PENDING_REVIEW",
"hotelRequirementStatusName": "待审核",
"vehicleRequirementStatus": "PENDING_REVIEW",
"vehicleRequirementStatusName": "待提交车务",
"consultantName": "王骁",
"totalPrice": "10940.00",
"tierCode": "2A1C",
"tierName": "2成人1儿童",
"travelerInfoComplete": true,
"roomCount": 1,
"roomType": "DELUXE",
"roomTypeName": "豪华房",
"specialNeeds": "禁烟",
"contactPhone": "137****1407",
"groupChatUnreadCount": 0,
"travelers": [
{ "name": "王有亿", "type": "ADULT", "age": 41, "birthdayInTrip": false },
{ "name": "李美丽", "type": "ADULT", "age": 36, "birthdayInTrip": false },
{ "name": "王小明", "type": "CHILD", "age": 8, "birthdayInTrip": false }
]
},
{
"orderId": "2102309919002943489",
"orderNo": "HL20260922161158291",
"teamNo": "26-2355",
"customerName": "王二麻子",
"participantCount": 4,
"orderStatus": "CUSTOMIZING",
"orderStatusName": "定制中",
"payStatus": "DEPOSIT_PAID",
"payStatusName": "已付定金",
"contractStatus": null,
"contractStatusName": null,
"insuranceStatus": null,
"insuranceStatusName": null,
"paidAmount": "2000.00",
"balanceAmount": "13920.00",
"hotelRequirementStatus": null,
"hotelRequirementStatusName": "未提交",
"vehicleRequirementStatus": null,
"vehicleRequirementStatusName": "未提交",
"consultantName": "刘畅",
"totalPrice": "15920.00",
"tierCode": "4A",
"tierName": "4成人",
"travelerInfoComplete": false,
"roomCount": 2,
"roomType": null,
"roomTypeName": null,
"specialNeeds": "干",
"contactPhone": "185****0000",
"groupChatUnreadCount": 0,
"travelers": []
}
],
"total": 2,
"page": 1,
"pageSize": 20
},
"traceId": null,
"success": true
}
空数据 / 降级响应
团期下没有活跃子订单(或 page 超出范围)时返回空页,信封与分页字段结构同上,records 为空数组,不返 404、不 500:
{
"code": 200,
"message": "成功",
"data": { "records": [], "total": 0, "page": 1, "pageSize": 20 },
"traceId": null,
"success": true
}
错误响应
{
"code": 589500,
"message": "团期不存在",
"data": null,
"traceId": null,
"success": false
}
无团期权限或该团期不在本人名下:
{
"code": 589507,
"message": "无操作权限(当前角色未授予团期权限,或该团期不在您名下)",
"data": null,
"traceId": null,
"success": false
}
业务边界
- 业务失败走 HTTP 200 +
success:false的信封;未登录由网关返 401,不在本接口的码集里。 hotelRequirementStatus/vehicleRequirementStatus与各自的*StatusName必须成对读:Status为null且StatusName为"未提交",表示该户需要这项资源但一条需求行都没提交;两者都为null表示该户本来就不需要这项资源,页面渲染「—」。- 不要再用
status === 'PENDING'判断「没提交」——PENDING现在唯一含义是「已提交、等资源侧接单」。判「没提交」的唯一判据是status == null。 *StatusName在遇到枚举外的未知码时回落原 code,前端渲染保持statusName || status || '—'的三级兜底即可,不会拿到空串。- 本接口只读,不写库;重复调用无副作用。
includeCancelled=false(缺省)时已取消子订单不出现在结果里,total同口径。
2. GB-ADM-012 整团确认需求缺失预检 GET /v3/admin/order/group-batch/{groupBatchId}/requirement/confirm-check
VO: Path 参数 → GroupBatchRequirementCheckRespVO
使用场景
管理后台在点「整体确认需求」之前调用,用于把按钮置灰并把缺失清单摊开给运营看。它与 POST .../requirement/confirm 共用同一套校验:预检里出现的每一条,都会在确认时以对应错误码抛出且零写入。鉴权走 group-batch:demand:confirm。本次改动新增了车侧的户级校验,并改写了车侧 detail 的文案。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| groupBatchId | Path | Long | ✅ | 雪花 ID,团期聚合主键 | 团期 ID;无 Query、无 Body |
出参 Result<GroupBatchRequirementCheckRespVO>
| 字段 | 类型 | 说明 |
|---|---|---|
| data.groupBatchId | String | 团期聚合主键 |
| data.batchStatus | String | 团期当前状态码 |
| data.batchStatusName | String | 团期状态中文名;batchStatus 为 null 时为 null |
| data.ready | Boolean | 是否可整体确认:missing 空 且 vehicleMissing 空 且阶段可确认。missing 空而 ready=false 时原因在 vehicleMissing |
| data.missing[] | Array | 住宿缺失清单,按 orderId 升序,每户至多一条 |
| data.missing[].orderId | String | 子订单 ID |
| data.missing[].orderNo | String | 子订单号 |
| data.missing[].customerName | String | 客户姓名 |
| data.missing[].consultantId | String | 定制师 adminId(字符串,便于拼跳转) |
| data.missing[].consultantName | String | 定制师姓名快照 |
| data.missing[].reason | String | 住宿缺失原因码,见六.5 |
| data.missing[].reasonName | String | 住宿缺失原因中文名 |
| data.missing[].dayNumber | Integer | 第几天;无该维度时 null |
| data.missing[].segmentIndex | Integer | 段序;无该维度时 null |
| data.missing[].expectedNights | Integer | 期望晚数;无该维度时 null |
| data.missing[].actualNights | Integer | 实际晚数;无该维度时 null |
| data.checkedResourceTypes | Array | 本次预检覆盖的资源类型,恒为 ["HOTEL","VEHICLE"];两类均已覆盖到逐户粒度 |
| data.vehicleWaived | Boolean | 整团免车时为 true,此时车侧校验整体跳过、vehicleMissing 恒为空数组 |
| data.vehicleMissing[] | Array | 车侧缺失清单,按校验顺序全部列出、不按户合并;vehicleWaived=true 时为空数组 |
| data.vehicleMissing[].reason | String | 本次扩充:车侧缺失原因码,新增 HOUSEHOLD_REQUIREMENT_NOT_SUBMITTED,见六.5 |
| data.vehicleMissing[].groupCode | String | 涉及的乘车分组编码;无分组维度时 null |
| data.vehicleMissing[].tripDate | String | 涉及日期(yyyy-MM-dd);无日期维度时 null |
| data.vehicleMissing[].orderId | String | 涉及的子订单 ID;无订单维度时 null |
| data.vehicleMissing[].orderNo | String | 子订单号快照;订单不属于本团期时 null |
| data.vehicleMissing[].detail | String | 本次报文变更:人话描述,与整团确认抛出的错误报文逐字相同,可直接展示;户级条目不再带雪花 orderId |
| data.groupVehicleRequirementId | String | 当前活跃正式用车需求主键;无则 null |
| data.groupVehicleRequirementStatus | String | 活跃正式用车需求状态;无则 null。DISPATCHED / DONE 同属预检可通过的正常状态 |
| data.groupVehicleRequirementVersion | Integer | 活跃正式用车需求版本号;无则 null |
| data.transferSubmitEnabled | Boolean | 当前环境是否开放接送机需求提交;false 时提交 kind=TRANSFER 会被 809004 拒 |
| data.transferDeclaredWithoutRequirement[] | Array | 声明了接送机却没报 TRANSFER 需求的户(提示性,不进 ready、不阻断确认);无此类户时为空数组、不是 null |
请求示例
GET /v3/admin/order/group-batch/2100856430494973953/requirement/confirm-check HTTP/1.1
Host: <网关地址>
Authorization: Bearer <admin token>
响应示例
{
"code": 200,
"message": "成功",
"data": {
"groupBatchId": "2100856430494973953",
"batchStatus": "RESOURCE_PREPARING",
"batchStatusName": "资源准备中",
"ready": false,
"missing": [
{
"orderId": "2102309919002943489",
"orderNo": "HL20260922161158291",
"customerName": "王二麻子",
"consultantId": "2083111674486693889",
"consultantName": "刘畅",
"reason": "NOT_SUBMITTED",
"reasonName": "未提报",
"dayNumber": null,
"segmentIndex": null,
"expectedNights": null,
"actualNights": null
}
],
"checkedResourceTypes": ["HOTEL", "VEHICLE"],
"vehicleWaived": false,
"vehicleMissing": [
{
"reason": "GROUP_REQUIREMENT_NOT_FOUND",
"groupCode": null,
"tripDate": null,
"orderId": null,
"orderNo": null,
"detail": "团期「第3期 10月8日出发团」尚未形成正式用车需求"
},
{
"reason": "HOUSEHOLD_REQUIREMENT_NOT_SUBMITTED",
"groupCode": null,
"tripDate": null,
"orderId": "2102309919002943489",
"orderNo": "HL20260922161158291",
"detail": "该户尚未提交行程用车需求,请先让定制师提交后再整团提交车务"
}
],
"groupVehicleRequirementId": null,
"groupVehicleRequirementStatus": null,
"groupVehicleRequirementVersion": null,
"transferSubmitEnabled": true,
"transferDeclaredWithoutRequirement": []
},
"traceId": null,
"success": true
}
空数据 / 降级响应
需求齐备、可以整体确认时,两份清单都是空数组(不是 null),ready 为 true;字段集与上例完全相同:
{
"code": 200,
"message": "成功",
"data": {
"groupBatchId": "2100856430494973953",
"batchStatus": "RESOURCE_PREPARING",
"batchStatusName": "资源准备中",
"ready": true,
"missing": [],
"checkedResourceTypes": ["HOTEL", "VEHICLE"],
"vehicleWaived": false,
"vehicleMissing": [],
"transferDeclaredWithoutRequirement": []
},
"traceId": null,
"success": true
}
错误响应
{
"code": 589500,
"message": "团期不存在",
"data": null,
"traceId": null,
"success": false
}
无需求确认权限:
{
"code": 589507,
"message": "无操作权限(当前角色未授予团期权限,或该团期不在您名下)",
"data": null,
"traceId": null,
"success": false
}
业务边界
- 本接口只读,任何情况下不写库,可安全重复调用。
vehicleMissing不按户合并、不短路:团级的GROUP_REQUIREMENT_NOT_FOUND与户级的HOUSEHOLD_REQUIREMENT_NOT_SUBMITTED会同时出现(实测响应即如此)。前者说「团级需求没形成」,后者说「是谁挡着它形成」,两条的处置对象不同,都要渲染出来。- 区分条目是团级还是户级的唯一结构化判据是
orderId/orderNo是否为null,不要靠解析detail文本。户级条目恒带orderId与orderNo。 missing为空但ready=false时,原因一定在vehicleMissing;vehicleWaived=true时车侧整体跳过,vehicleMissing恒为空数组,这是合法逃生口不是异常。transferDeclaredWithoutRequirement是提示性名单,不进ready、不阻断确认,也不并进vehicleMissing;transferSubmitEnabled=false时这份名单照报,此时该提示「当前环境未开放接送机需求提交」而不是隐藏名单。- 预检通过不等于确认一定成功:确认时的 CAS 冲突(809101 / 809112)只在写入阶段才可能发生,整团回滚、零写入。
四、契约约束与正确调用方式
本节只写后端返回什么、前端据什么判定,不写 UI 渲染建议。
✅ 正确 / ❌ 错误的判定写法
| 场景 | 判定写法 |
|---|---|
| ✅ 判「该户没提交房需求」 | hotelRequirementStatus === null && hotelRequirementStatusName === '未提交',或直接 hotelRequirementStatus == null |
| ✅ 判「该户不需要房」 | hotelRequirementStatus == null && hotelRequirementStatusName == null |
| ✅ 渲染状态列 | statusName ?? status ?? '—'(三级兜底,null 安全) |
❌ 判「没提交」用 status === 'PENDING' |
PENDING 现在唯一含义是「已提交、等资源侧接单」,这样写会把真正在排队的户也算成未提交 |
❌ 从 vehicleMissing[].detail 里正则抠订单号 |
报文已改写,户级条目的 detail 里不再有 ID;订单号读 vehicleMissing[].orderNo |
| ✅ 判车侧缺失条目是团级还是户级 | item.orderId == null → 团级(跳去团级用车需求编辑);否则户级(跳到该子订单) |
❌ 假设 vehicleMissing 至多一条 |
团级与户级条目会并列出现,数组长度可以大于 1 |
报文变更涉及的调用口
下列写口在失败时抛出的 message 与预检 detail 同源,本次一起改变;它们的请求契约、字段名、错误码码值都没有变,变的只是给人看的那段文本:
| 方法 | 路径 | 涉及错误码 | 弹窗场景 |
|---|---|---|---|
| POST | /v3/admin/order/group-batch/{groupBatchId}/requirement/confirm |
809100 / 809103-809110 / 809122 / 809007 | 点「整体确认需求」,车侧不过时弹第一条违规的报文(零写入) |
| PUT | /v3/admin/order/group-batch/{groupBatchId}/vehicle-requirement |
809107 / 809108 / 809109 / 809115 | 保存/提交乘车分组被校验拒绝 |
| POST | /v3/admin/order/group-batch/{groupBatchId}/vehicle-requirement/waive |
809114 | 声明整团免车时车务已开工被拒 |
| GET | /v3/admin/order/group-batch/{groupBatchId}/requirement/confirm-check |
同上全部 | 预检横幅里的 vehicleMissing[].detail |
五、数据库行为
本次两个变更接口都是只读端点,零写入。
| 前端动作 | 写库行为 |
|---|---|
调 GET .../orders |
无 |
调 GET .../requirement/confirm-check |
无 |
调 POST .../requirement/confirm 且车侧校验不过(含新增的 809122) |
无:阶段守卫 → 住宿缺失(589533)→ 车侧校验的顺序全部排在任何写入之前,抛出即整笔事务零写入 |
新增的 809122 不引入任何新表、新列、新状态值;它是对既有「该户有没有 active 行程用车需求行」的一次查询结果的表达。
六、边界行为
- 未登录 → 401(网关拦截,不进业务码集)。
- 团期不存在 → HTTP 200 +
code=589500。 - 无权限 / 团期不在本人名下 → HTTP 200 +
code=589507。 - 老数据兼容:历史上没有 active 需求行的户,改前读出
"PENDING"、改后读出null,存量数据不迁移,同一条记录在两个版本上读数不同,差异来自读取时的回落逻辑而非库里的值。 - 枚举外未知状态码:
*StatusName回落原 code,不抛异常、不返空串。 - 该户不需要房 / 不需要车时,对应的
*Status与*StatusName都是null,前端渲染「—」。 vehicleMissing与transferDeclaredWithoutRequirement在「一条都没有」时是空数组,不是null。
六.5、枚举 / 数据字典
hotelRequirementStatus / vehicleRequirementStatus(RequirementStatus)
所属字段: GroupBatchOrderItemRespVO.hotelRequirementStatus / .vehicleRequirementStatus | 类型: String
| 值 | 中文(房 / 车) | 说明 |
|---|---|---|
null |
未提交 / null |
本次新增取值:该户没有 active 需求行。该户需要这项资源 → *StatusName 为「未提交」;不需要 → *StatusName 也是 null |
PENDING |
待房务配 / 待车队配 | 已提交并放行,等资源侧接单 |
PROCESSING |
配房中 / 配车中 | 资源侧处理中 |
DONE |
配房完成 / 配车完成 | 资源侧完成 |
PENDING_REVIEW |
待审核 / 待提交车务 | 定制师已报、等管理员动作;车侧本列恒为行程用车(TRAVEL),故用「待提交车务」(#8218) |
REJECTED_TO_CONSULTANT |
已驳回定制师 | 打回定制师重提 |
REJECTED_TO_ADMIN |
已驳回管理员 | 打回管理员 |
vehicleMissing[].reason(车侧缺失原因)
所属字段: GroupBatchRequirementCheckRespVO.VehicleMissingItem.reason | 类型: String
| 值 | 中文 | 说明 |
|---|---|---|
GROUP_REQUIREMENT_NOT_FOUND |
团级正式用车需求未形成 | 809100;团级维度,orderId / orderNo 为 null |
GROUP_REQUIREMENT_STATUS_INVALID |
团级需求状态不允许确认 | 809101 |
NO_GROUP |
至少要提交一个乘车分组 | 809103 |
GROUP_CODE_INVALID |
乘车分组编码重复或改名 | 809104 |
DAY_OUT_OF_GROUP_RANGE |
逐日行不在本组服务日范围内 | 809105 |
DAY_GAP_IN_GROUP_RANGE |
缺某日的逐日用车人数 | 809106 |
MEMBER_FOREIGN_ORDER |
成员子订单不属于本团期 | 809107 |
MEMBER_DUPLICATE_DAY |
同一户同一日落在两个分组 | 809108 |
ORDER_DAY_UNCOVERED |
某子订单某日没有被任何分组覆盖 | 809109 |
HEADCOUNT_LESS_THAN_MEMBERS |
逐日用车人数小于当日成员户数 | 809110 |
HOUSEHOLD_REQUIREMENT_NOT_SUBMITTED |
该户尚未提交行程用车需求 | 本次新增,809122;户级维度,恒带 orderId / orderNo;处置是催该户定制师提交 |
TRANSFER_SERVICE_DATES_NOT_BACKFILLED |
待放行接送机需求未回填服务日 | 809007;只带 orderId |
missing[].reason(住宿缺失原因)
所属字段: GroupBatchRequirementCheckRespVO.MissingItem.reason | 类型: String
| 值 | 中文 | 说明 |
|---|---|---|
NOT_SUBMITTED |
未提报 | 该户需房但没有 active 房需求行(含被打回后未重提) |
ROOM_CATEGORY_MISSING |
缺房型 | 需求行存在但房型行缺失 |
INVALID_REQUIREMENT |
需求结构不合法 | days 结构不可用 |
NIGHTS_MISMATCH |
晚数不符 | 实际晚数与期望晚数不一致 |
DAY_NUMBER_INVALID |
天序不合法 | dayNumber 越界或重复 |
六.6、修改前后对比
字段级对比
| 字段 | 改前 | 改后 |
|---|---|---|
GroupBatchOrderItemRespVO.hotelRequirementStatus |
无 active 房需求行时回落 "PENDING" |
无 active 行时为 null |
GroupBatchOrderItemRespVO.hotelRequirementStatusName |
相应显示「待房务配」 | code 为 null 时:该户需房 → "未提交";不需房 → null |
GroupBatchOrderItemRespVO.vehicleRequirementStatus |
无 active 车需求行时回落 "PENDING" |
无 active 行时为 null |
GroupBatchOrderItemRespVO.vehicleRequirementStatusName |
相应显示「待车队配」 | code 为 null 时:该户需车 → "未提交";不需车 → null |
GroupBatchRequirementCheckRespVO.vehicleMissing[].reason |
11 个取值 | 追加 HOUSEHOLD_REQUIREMENT_NOT_SUBMITTED,共 12 个 |
GroupBatchRequirementCheckRespVO.checkedResourceTypes |
值仍是 ["HOTEL","VEHICLE"],但车侧只覆盖团级 |
值不变;车侧实际覆盖扩到逐户(这是把字段宣称的覆盖补齐,不是取值变化) |
报文变更(六个错误码的渲染文本)
| 错误码 | 改前渲染 | 改后渲染 |
|---|---|---|
| 809100 | 团期 2100856430494973953 尚未形成正式用车需求 |
团期「第3期 10月8日出发团」尚未形成正式用车需求;团期名与期号快照都缺时为 该团期尚未形成正式用车需求 |
| 809107 | 子订单 2102309919002943489 不属于本团期,不能作为乘车成员 |
该子订单不属于本团期,不能作为乘车成员 |
| 809108 | 子订单 2102309919002943489 在 2026-10-09 同时属于分组 BUS、SUV,同一户同一日只能属于一个分组 |
该子订单在 2026-10-09 同时属于分组 BUS、SUV,同一户同一日只能属于一个分组 |
| 809109 | 子订单 2102309919002943489 的 2026-09-13 没有被任何乘车分组覆盖 |
该子订单的 2026-09-13 没有被任何乘车分组覆盖 |
| 809114 | 车务已开工(团期 2100856430494973953:团级配车已就绪) / 车务已开工(子订单 2102309919002943489:用车需求已到 DISPATCHED) |
车务已开工(团期「第3期 10月8日出发团」:团级配车已就绪) / 车务已开工(子订单 HL20260922161158291:用车需求已到 DISPATCHED);取不到订单号时为 某子订单 |
| 809115 | 团期 2100856430494973953 已声明整团免车,提交乘车分组前请先整份撤回(withdraw)回草稿 |
团期「第3期 10月8日出发团」已声明整团免车,提交乘车分组前请先整份撤回(withdraw)回草稿 |
码值一个都没变,变的只是 message / detail 的文本。809107 / 809108 / 809109 是直接删掉标识符:这三条只出现在预检清单上,而清单行已经由 orderNo 字段结构化带了订单号,文本里再带一个雪花 ID 就是同一行上的第二个标识符。809114 保留标识符只把 ID 换成订单号:它只落在免车声明弹窗上,弹窗外没有第二处说明是哪一户。
行为级对比
| 行为 | 改前 | 改后 |
|---|---|---|
| 团里有户一条需求都没提交时的列表显示 | 「待房务配 / 待车队配」(与同屏预检横幅的「未提报」矛盾) | 「未提交」 |
| 车侧预检对「某户一行行程用车需求都没提交」 | 无任何表达位置,整团确认只报团级的 809100 | vehicleMissing 里多一条 809122,带 orderId / orderNo |
| 团级缺席时是否还检查户级 | 团级缺席即返回,不再往下查 | 两层并列输出,团级缺席不短路户级 |
| 整团确认在户级未提交时的结果 | 报 809100(运营据此去催车务,方向错了) | 报 809122(催该户定制师提交),零写入 |
| 车务报文里的标识符 | 雪花 ID | 团期可读名称 / 订单号 / 直接省略 |
六.7、影响评估
- 是否破坏向后兼容: 是(部分)。
*Status新增null取值;对detail/message做文本匹配或抠 ID 的逻辑会失效。字段名、字段数量、错误码码值、请求契约均未变。 - 前端是否必须同步上线: 否。已核对
hl-ui origin/v2.1的src/views/order-v2/batch/detail/components/RequirementTab.vue:状态列渲染为r.hotelRequirementStatusName || r.hotelRequirementStatus || '—'(:812-814),对null安全;车侧缺失清单按item.orderNo是否存在分流(:654vehicleReqMissing、:708-714onVehicleMissingClick),809122 条目带orderNo,会被正确归为户级并跳到该子订单。当前前端不改也能正确工作。 - 前端 workaround 清理点: 若页面上有「把
PENDING当作未提交」的本地兜底判断,可以撤掉——后端现在用null表达「未提交」,语义是唯一的。 - 风险面: 唯一需要人工确认的是「是否存在对
vehicleMissing[].detail做字符串解析的代码」。上述两个消费点都只做原样展示,未发现解析逻辑。
七、不影响范围
- 仅影响: 管理后台「团期详情 → 查看需求」tab 的子订单状态列、整团确认预检横幅、车务相关弹窗文案。
- 零影响:
- 小程序端(mp)全部接口:本次改动只落在
/v3/admin/前缀下。 GET /v3/admin/order/group-batch/{groupBatchId}/requirement-summary(用房·汇总 / 用车·汇总):字段与取值一个没动。该页此前的「汇总加载失败」已定位为前端同 tick 重复请求被去重拦截器 abort 所致,mmg 已在hl-ui 4b33ccbd9修复并已在测试环境前端 dist 里(2026-09-23 18:06构建),与本次后端改动无关。- 房需求的提交 / 打回 / 放行链路:
missing[]的口径、589533 的触发条件与报文一律不变。 - 接送机(TRANSFER)相关:
transferSubmitEnabled、transferDeclaredWithoutRequirement、809007 的语义与取值不变。 - 订单列表 / 订单详情 / 金额相关接口:未触及。
- 历史数据:存量不迁移;差异只来自读取时的回落逻辑。
- 数据库:无 DDL、无 Flyway 脚本、无新列。
- 小程序端(mp)全部接口:本次改动只落在
八、测试环境已验证
部署:hl-order-service-v3 @ dev-v3 fc81fff1f,jar 构建时间 2026-09-23 18:36:51,两个实例(8086 / 8186)均 UP。以下读数经网关实测:
GET /v3/admin/order/group-batch/2100856430494973953/orders
→ 200;26-2355(HL20260922161158291)hotelRequirementStatus=null / StatusName=未提交,
vehicleRequirementStatus=null / StatusName=未提交 ✓
→ 200;26-7060(HL20260918155619496)hotelRequirementStatus=PENDING_REVIEW / 待审核,
vehicleRequirementStatus=PENDING_REVIEW / 待提交车务(无回归)✓
GET /v3/admin/order/group-batch/2100856430494973953/requirement/confirm-check
→ 200;vehicleMissing 里 GROUP_REQUIREMENT_NOT_FOUND 与
HOUSEHOLD_REQUIREMENT_NOT_SUBMITTED 两条同时出现(未被团级缺席短路)✓
→ 809100 的 detail 已是「团期「第3期 10月8日出发团」尚未形成正式用车需求」(无雪花 ID)✓
→ 809122 的条目带 orderId=2102309919002943489 / orderNo=HL20260922161158291 ✓
→ checkedResourceTypes=["HOTEL","VEHICLE"]、vehicleWaived=false、ready=false ✓
GET /v3/admin/order/group-batch/2100856430494973953/requirement-summary
→ 200 × 3 次(3.56s / 2.11s / 2.55s),服务端日志零 ERROR / Exception ✓
验证团期: groupBatchId=2100856430494973953(第3期 10月8日出发团,2 户活跃子订单)
十、相关文档
- 关联 Issue: wx/HL#8249
- 关联 PR: wx/HL#8286
- 同页状态文案的上一次分叉(
PENDING_REVIEW车侧按 kind 分叉):changelogs-v2/2026-09/23_8218_行程用车状态文案按kind分叉-修改接口-管理后台.md
关联 / 联系人
链接
联系人
- 后端负责人: @wx