104 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 | frontend | 团期详情「查看需求」页签重做为一键审核弹窗:页签改只读总览加唯一主按钮,审核打回确认收进三步弹窗,全部调用既有接口,后端零改动 | admin | wx(GIT) | 前端优化 | not_required | not_required | implemented | hl-admin | 80d7ad8872b2938e4849d71f32007ff07c6f465d | v2.1 | 2026-09-30 | 后端零改动,17 个既有接口;三种提交模式的调用顺序、确认后接送机对账补放行、已确认态只可通过不可打回见正文四;4 项字段缺口本期不展示;前端已交付:页签只读总览+三步审核弹窗+对账补放行+审核变更只通过 | 2026-09-30 | dev-v3 |
团期需求: 「查看需求」页签重做为一键审核弹窗
服务: hl-order-service-v3(本条后端零改动,涉及接口全部为既有接口) PR: 无(纯前端改造) Issue: 无(ticket=frontend) 日期: 2026-09-29 影响范围: 管理后台 → 订单管理 → 团期列表 → 出团详情 →「查看需求」页签(
src/views/order-v2/batch/detail/components/RequirementTab.vue及其子组件) 设计稿: 「设计稿」https://claude.ai/artifact/R2b6RsiUvykdF9kBUdaQcC 源码基线: 后端origin/dev-v3@7b702f5c;前端 hl-uiorigin/v2.1@cdfaf793
⚠️ 关键变化(非必须,本版与上版行为不同 / 纠错 / 撤销时必写)
- 页面结构变了:原来是「汇总块 + 逐户块 + 正式用车需求块」平铺,顶部四个按钮;新设计是只读总览(状态条 + 三张汇总卡 + 逐晚用房 + 用车安排 + 逐户需求)加唯一主按钮「审核并确认需求」,点开是三步审核弹窗(①住房 ②接送机 ③行程用车)。
- 取消的按钮:「打回选中户」「新增正式行程用车需求」「更多」「整团确认需求」(
RequirementTab.vue:53 / :68 / :77 / :86)。取消的只是按钮,能力不取消:整团免车(waive)进弹窗③「整团不用车」;撤回(withdraw)与受控重开(reopen)仍须保留入口,位置前端自定(见四)。 - 四处以前容易想错的地方(均已对源码核实):
- 确认后不能逐户打回。需求已确认之后还能出现「待审核」行的,只有团期过了资源准备阶段后的接送机变更;这时团期阶段不是
RESOURCE_PREPARING,逐户打回报 589501。所以已确认态的「审核变更」只有「通过」没有「打回」。 - 整团确认不一定放行全部接送机。整团免车时一条车需求都不放行(含待审接送机);
needs_vehicle≠1的户报了接送机也不在放行集合里。确认成功后必须用响应里的transferDispatchedOrderIds对账,没放行的另调transfer/batch-confirm。 - 批量打回端点不覆盖接送机。
POST …/requirement/reject的VEHICLE只打回行程用车,且整批只收一条原因;新设计每户各有原因、要分 kind 打回,不用它,改逐户打回。 - 逐户打回(任何 kind)都会清团级确认标记。所以同一次提交里,打回必须排在
requirement/confirm之前调;顺序反了,刚写上的确认标记会被打回清掉。
- 确认后不能逐户打回。需求已确认之后还能出现「待审核」行的,只有团期过了资源准备阶段后的接送机变更;这时团期阶段不是
一、背景(选填)
运营反馈原页签按钮多、确认前要在四个板块之间来回切,确认失败时不知道卡在哪一户。新设计把「看」和「审」分开:页签只读,所有写操作收进一个弹窗,底部按打回情况自动切换三种提交模式。
本条与今天两条既有条目的关系(两条都已由前端交付,与本条不冲突):
| 既有条目 | 前端提交 | 与本条的关系 |
|---|---|---|
changelogs-v2/2026-09/29_frontend_团期详情用车汇总行程用车与接送机改逐条列出-前端优化-管理后台.md |
a73ef932 |
它定的数据口径(按 kind 拆行程用车与接送机、statusName 原文直显、不按 countedInSummary 过滤)继续有效;它改的「用车汇总」块在本条被新设计 A 的「用车安排」吸收。布局以本条为准,字段口径以原条为准。 |
changelogs-v2/2026-09/29_frontend_团期详情用车需求确认弹窗点确认不发请求-前端缺陷-管理后台.md |
01acf773 |
它修的三处调用点(VehicleHouseholdsSection.vue:334 / :387、RequirementTab.vue:588)在新设计里随原组件一起删除;新写的所有确认对话框同样必须用 onPositiveClick,不要用 onPositive。 |
涉及文件(hl-ui origin/v2.1@cdfaf793,目录 src/views/order-v2/batch/detail/components/):本节与下文引用的前端行号、行数都取自这个快照,它早于上表两个前端提交 a73ef932 / 01acf773,按上表第二条,:334 / :387 / :588 三处在你们当前分支上应已改成 onPositiveClick,各文件行数也可能有出入;按函数名与按钮文案定位即可。
| 旧组件 | 行数 | 现调接口 | 去向 |
|---|---|---|---|
RequirementTab.vue |
1055 | confirm-check / confirm / requirement-summary | 保留并重写为新设计 A;emit('contact', orderId) 事件保留(index.vue:163 → :705 onContactCustomizer 打开会话抽屉) |
RoomSummarySection.vue |
174 | (父级传入 summary) | 并入 A 的住房卡与「逐晚用房」表 |
VehicleSummarySection.vue |
160 | (父级传入 summary) | 并入 A 的「用车安排」 |
RoomHouseholdsSection.vue |
362 | hotel-households | 并入弹窗①,同时给 A 的逐户表供住房列数据 |
VehicleHouseholdsSection.vue |
571 | vehicle-households / batch-confirm / 逐户 vehicle dispatch | 并入弹窗②③ 与已确认态「审核变更」 |
RequirementRejectModal.vue |
213 | 批量 reject | 删除(新设计不用批量打回) |
GroupVehicleRequirementSection.vue |
800 | GET vehicle-requirement / reopen / waive / withdraw | 并入弹窗③;reopen / withdraw 入口位置前端自定 |
GroupVehicleRequirementEditModal.vue |
1048 | aggregate-draft / PUT vehicle-requirement / 车型字典 | 并入弹窗③ |
HouseholdRequirementModal.vue |
589 | room-plans | 保留,由逐户表「详情」打开 |
__tests__/*.spec.js |
— | — | 随组件增删调整 |
API 封装全部已存在,不需要新增:src/api/orderV2GroupBatch.js(:115 详情、:279 状态流水、:629 预检、:656 确认、:716 汇总、:748 住房逐户、:790 用车逐户、:819 接送机批量放行、:865 取正式需求、:889 重开、:929 保存正式需求、:963 自动汇总、:979 撤回、:997 免车);src/api/orderV2.js(:1543 住房逐户打回、:1561 用车逐户打回、:1577 住房逐户下发、:1597 用车逐户下发)。
二、变更接口清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|---|---|---|---|---|
| 1 | 团期详情 | GET | /v3/admin/order/group-batch/{groupBatchId} |
调用方式变更(后端零改动) | 页签头部户数人数、阶段、确认标记 |
| 2 | 团期状态流水 | GET | /v3/admin/order/group-batch/{groupBatchId}/status-logs |
调用方式变更(后端零改动) | 已确认态「时间 由 某人 确认」 |
| 3 | 全团需求汇总 | GET | /v3/admin/order/group-batch/{groupBatchId}/requirement-summary |
调用方式变更(后端零改动) | 三张汇总卡、逐晚用房、接送机汇总 |
| 4 | 住房逐户记录 | GET | /v3/admin/order/group-batch/{groupBatchId}/requirement/hotel-households |
调用方式变更(后端零改动) | 逐户表住房列、弹窗① |
| 5 | 用车逐户记录 | GET | /v3/admin/order/group-batch/{groupBatchId}/requirement/vehicle-households |
调用方式变更(后端零改动) | 逐户表车侧两列、弹窗②③、审核变更 |
| 6 | 整团确认预检 | GET | /v3/admin/order/group-batch/{groupBatchId}/requirement/confirm-check |
调用方式变更(后端零改动) | 状态条预检、弹窗底部缺失提示、大交通声明提示 |
| 7 | 取正式用车需求 | GET | /v3/admin/order/group-batch/{groupBatchId}/vehicle-requirement |
调用方式变更(后端零改动) | 行程用车卡、用车安排矩阵、弹窗③ |
| 8 | 正式用车需求自动汇总 | GET | /v3/admin/order/group-batch/{groupBatchId}/vehicle-requirement/aggregate-draft |
调用方式变更(后端零改动) | 弹窗③「按户需求重新汇总」 |
| 9 | 保存正式用车需求 | PUT | /v3/admin/order/group-batch/{groupBatchId}/vehicle-requirement |
调用方式变更(后端零改动) | 弹窗③「仅保存草稿」及确认前落草稿 |
| 10 | 整团免车 | POST | /v3/admin/order/group-batch/{groupBatchId}/vehicle-requirement/waive |
调用方式变更(后端零改动) | 弹窗③「整团不用车」 |
| 11 | 撤回正式用车需求 | POST | /v3/admin/order/group-batch/{groupBatchId}/vehicle-requirement/withdraw |
调用方式变更(后端零改动) | 已免车或已确认后改分组的前置动作 |
| 12 | 整团确认需求 | POST | /v3/admin/order/group-batch/{groupBatchId}/requirement/confirm |
调用方式变更(后端零改动) | 模式一、模式二的核心提交 |
| 13 | 住房逐户打回 | POST | /v3/admin/order/{id}/hotel-requirement/reject |
调用方式变更(后端零改动) | 弹窗①打回 |
| 14 | 用车逐户打回 | POST | /v3/admin/order/{id}/vehicle-requirement/reject |
调用方式变更(后端零改动) | 弹窗②打回(kind=TRANSFER)、弹窗③打回(kind=TRAVEL) |
| 15 | 住房逐户下发 | POST | /v3/admin/order/{id}/hotel-requirement/dispatch |
调用方式变更(后端零改动) | 已确认态「审核变更」住房通过 |
| 16 | 用车逐户下发 | POST | /v3/admin/order/{id}/vehicle-requirement/dispatch |
调用方式变更(后端零改动) | 已确认态「审核变更」车侧通过 |
| 17 | 接送机批量放行 | POST | /v3/admin/order/group-batch/{groupBatchId}/requirement/transfer/batch-confirm |
调用方式变更(后端零改动) | 确认后补放行接送机、已确认态接送机批量通过 |
三、接口详情
1. 团期详情 GET /v3/admin/order/group-batch/{groupBatchId}
VO: (无请求体) → GroupBatchDetailRespVO
使用场景
页签头部的户数、人数、阶段,以及「待确认态 / 已确认态」的判定。出团详情页 index.vue 已经在拉这个接口(封装 getGroupBatchDetail,orderV2GroupBatch.js:115),由父组件把结果传进页签即可,不必重复请求。弹窗提交成功后要重拉一次,因为 requirementConfirmed 会变。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| groupBatchId | Path | Long | ✅ | 团期 ID | 路径参数 |
出参 Result<GroupBatchDetailRespVO>
| 字段 | 类型 | 说明 |
|---|---|---|
| groupBatchId | Long(JSON 字符串) | 团期 ID(GroupBatchDetailRespVO.java:34) |
| batchNo | String | 班期编号(:48) |
| batchStatus | String | 团期阶段码,枚举见六.5(:58) |
| batchStatusName | String | 阶段中文名(:61) |
| enrolledPeople | Integer | 活跃子订单人数合计,页头「N 人」与用车矩阵「在团人数」用它(:130) |
| subOrderCount | Integer | 活跃子订单户数,页头「N 户」用它(:152) |
| vehicleReady | Boolean | 配车完成或整团免车成立(:164)。不是「已下发车务」,别用它渲染已确认态的「用车已下发车务」 |
| requirementConfirmed | Boolean | 需求整体确认标志(:176)。false=待确认态,true=已确认态 |
| departDate | LocalDate | 出发日(:248) |
| endDate | LocalDate | 结束日(:251) |
本页只用上表字段,其余字段不在本条范围。
请求示例
GET /v3/admin/order/group-batch/2100856430494973953
响应示例
按 VO 结构组装,取值为示意,不是测试服读数(只列本页用到的字段):
{
"code": 200,
"message": "成功",
"data": {
"groupBatchId": "2100856430494973953",
"batchNo": "T26-8867",
"batchStatus": "RESOURCE_PREPARING",
"batchStatusName": "资源准备中",
"enrolledPeople": 7,
"subOrderCount": 2,
"vehicleReady": false,
"requirementConfirmed": false,
"departDate": "2026-10-08",
"endDate": "2026-10-10"
},
"traceId": null,
"success": true
}
空数据 / 降级响应
无空数据形态:团期不存在直接报 589500(requireById)。enrolledPeople / subOrderCount 在没有活跃子订单时为 0。
错误响应
{
"code": 589507,
"message": "无操作权限(当前角色未授予团期权限,或该团期不在您名下)",
"data": null,
"traceId": null,
"success": false
}
业务边界
- 判权
group-batch:view(GroupBatchQueryController.java:113),另有数据级归属校验:定制师角色只能看自己名下的团期,否则 589507。 - 团期不存在报 589500「团期不存在」。
requirementConfirmed会被后端自动清回 false:资源准备阶段有户改住房或用车需求、有户转团时都会清(GroupBatchService.java:2629reopenRequirementConfirmation)。页面不要缓存这个值做判断,每次进入页签与每次弹窗提交后都以最新详情为准。
2. 团期状态流水 GET /v3/admin/order/group-batch/{groupBatchId}/status-logs
VO: (无请求体) → List<GroupBatchStatusLogItemVO>
使用场景
已确认态状态条的「{时间} 由 {人} 确认」。取法:列表按时间升序、不分页,取 eventType = BATCH_REQUIREMENT_CONFIRM 的最后一条,用它的 changedAt 与 operatorName。封装 getGroupBatchStatusLogs(orderV2GroupBatch.js:279)。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| groupBatchId | Path | Long | ✅ | 团期 ID | 路径参数 |
出参 Result<List<GroupBatchStatusLogItemVO>>
| 字段 | 类型 | 说明 |
|---|---|---|
| logId | Long(JSON 字符串) | 流水 ID |
| groupBatchId | Long(JSON 字符串) | 团期 ID |
| changeType | String | 变更大类 |
| eventType | String | 事件类型,本页只认三个值,见六.5 |
| eventTypeName | String | 事件中文名 |
| fromStatus / fromStatusName | String | 变更前团期阶段(数据类事件可能为空) |
| toStatus / toStatusName | String | 变更后团期阶段 |
| content | String | 事件描述 |
| reason | String | 原因(打回类事件为打回原因) |
| operatorType | String | 操作人类型 |
| operatorId | Long | 操作人 ID |
| operatorName | String | 操作人姓名,状态条「由 某人 确认」用它 |
| extra | Object | 扩展信息;逐户打回写入的 extra 只含本户 orderId |
| changedAt | LocalDateTime | 事件时间,状态条时间用它 |
请求示例
GET /v3/admin/order/group-batch/2100856430494973953/status-logs
响应示例
按 VO 结构组装,取值为示意,不是测试服读数:
{
"code": 200,
"message": "成功",
"data": [
{
"logId": "2105000000000000001",
"groupBatchId": "2100856430494973953",
"changeType": "DATA",
"eventType": "BATCH_REQUIREMENT_CONFIRM",
"eventTypeName": "需求整体确认",
"fromStatus": null,
"fromStatusName": null,
"toStatus": null,
"toStatusName": null,
"content": "需求整体确认",
"reason": null,
"operatorType": "ADMIN",
"operatorId": "2021059720172838914",
"operatorName": "王骁",
"extra": null,
"changedAt": "2026-09-29 16:20:00"
}
],
"traceId": null,
"success": true
}
空数据 / 降级响应
{ "code": 200, "message": "成功", "data": [], "traceId": null, "success": true }
团期不存在或没有任何流水时返回空数组。已确认但列表里找不到 BATCH_REQUIREMENT_CONFIRM 时,状态条不展示「时间 由 某人 确认」这一行,其余照常。
错误响应
{
"code": 589507,
"message": "无操作权限(当前角色未授予团期权限,或该团期不在您名下)",
"data": null,
"traceId": null,
"success": false
}
业务边界
- 判权
group-batch:view,在 Service 入口校验(GroupBatchStatusLogService.java:203)。 - 时间线写入失败只记日志、不回滚业务,所以「已确认但没有确认流水」是可能出现的形态,前端必须容忍(见上节降级)。
- 取「最后一条」而不是「第一条」:确认 → 被打回或自动清标记 → 再确认,会留下多条
BATCH_REQUIREMENT_CONFIRM。 - 本条对「确认人取自状态流水」这一推导未在测试服实测。
3. 全团需求汇总 GET /v3/admin/order/group-batch/{groupBatchId}/requirement-summary
VO: (无请求体) → GroupRequirementSummaryRespVO
使用场景
新设计 A 的住房卡、接送机卡、逐晚用房表、特殊需求户数。进入页签调用一次,弹窗提交成功后重拉。封装 getGroupRequirementSummary(orderV2GroupBatch.js:716)。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| groupBatchId | Path | Long | ✅ | 团期 ID | 路径参数 |
出参 Result<GroupRequirementSummaryRespVO>
| 字段 | 类型 | 说明 |
|---|---|---|
| activeOrderCount | Integer | 在团子订单数 |
| hotelRequirementCount | Integer | 住房需求条数 |
| hotelNeededOrderCount | Integer | 需要住房的户数,住房卡「N/N 户已提交」的分母 |
| hotelFlagMismatchOrderCount | Integer | 住房标记与需求不一致的户数 |
| hotelSubmittedOrderCount | Integer | 已提交住房需求的户数,「N/N 户已提交」的分子 |
| vehicleRequirementCount | Integer | 用车需求条数 |
| dailyRoomBreakdown[] | Array | 逐晚用房,只计已提交且未被打回的户,不含客户自订的晚;全团都自订的晚没有条目 |
| dailyRoomBreakdown[].dayNumber | Integer | 第几晚 |
| dailyRoomBreakdown[].stayDate | LocalDate | 入住日 |
| dailyRoomBreakdown[].rooms[] | Array | 该晚按房型大类合计:roomCategory / roomCategoryName / totalRoomCount |
| dailyRoomBreakdown[].hotels[] | Array | 该晚按酒店拆:hotelId / hotelName / totalRoomCount / rooms[](同上三字段) |
| vehicleSeatSummary[] | Array | 行程用车按车型合计(只算 TRAVEL):vehicleType / vehicleTypeName / totalSeats / totalCount |
| orderSpecialTags[] | Array | 各户特殊需求:orderId / teamNo / requirementType(HOTEL / VEHICLE)/ specialTags(String 数组) |
| transferSummary | Object | 接送机汇总,恒不为 null |
| transferSummary.householdCount | Integer | 报了接送机的户数 |
| transferSummary.pickupHouseholdCount | Integer | 要接机的户数 |
| transferSummary.dropoffHouseholdCount | Integer | 要送机的户数 |
| transferSummary.headcount | Integer | 接送机总人数 |
| transferSummary.vehicleSeatSummary[] | Array | 接送机按车型:vehicleType / vehicleTypeName / seats / count |
| transferSummary.serviceDates[] | LocalDate[] | 接送机涉及日期的并集(不带方向) |
请求示例
GET /v3/admin/order/group-batch/2100856430494973953/requirement-summary
响应示例
测试服实测原文(2026-09-29 16:38,经网关,格式化排版,内容未改):
{
"code": 200,
"message": "成功",
"data": {
"activeOrderCount": 2,
"hotelRequirementCount": 2,
"hotelNeededOrderCount": 2,
"hotelFlagMismatchOrderCount": 0,
"hotelSubmittedOrderCount": 2,
"vehicleRequirementCount": 2,
"dailyRoomBreakdown": [
{
"dayNumber": 1,
"stayDate": "2026-10-08",
"rooms": [
{ "roomCategory": "DELUXE", "roomCategoryName": "豪华房", "totalRoomCount": 1 },
{ "roomCategory": "KING", "roomCategoryName": "豪华大床", "totalRoomCount": 1 },
{ "roomCategory": "STANDARD", "roomCategoryName": "标间", "totalRoomCount": 1 }
],
"hotels": [
{
"hotelId": "2023714929877450753",
"hotelName": "呼伦贝尔香格里拉大酒店",
"totalRoomCount": 3,
"rooms": [
{ "roomCategory": "DELUXE", "roomCategoryName": "豪华房", "totalRoomCount": 1 },
{ "roomCategory": "KING", "roomCategoryName": "豪华大床", "totalRoomCount": 1 },
{ "roomCategory": "STANDARD", "roomCategoryName": "标间", "totalRoomCount": 1 }
]
}
]
},
{
"dayNumber": 2,
"stayDate": "2026-10-09",
"rooms": [
{ "roomCategory": "STANDARD", "roomCategoryName": "标间", "totalRoomCount": 3 }
],
"hotels": [
{
"hotelId": "3001000000000000002",
"hotelName": "海拉尔海棠酒店",
"totalRoomCount": 3,
"rooms": [
{ "roomCategory": "STANDARD", "roomCategoryName": "标间", "totalRoomCount": 3 }
]
}
]
}
],
"vehicleSeatSummary": [
{ "vehicleType": "bus", "vehicleTypeName": "大巴系列", "totalSeats": 38, "totalCount": 2 }
],
"orderSpecialTags": [
{ "orderId": "2100856430239121409", "teamNo": "26-7060", "requirementType": "HOTEL", "specialTags": ["禁烟"] },
{ "orderId": "2102309919002943489", "teamNo": "26-2355", "requirementType": "HOTEL", "specialTags": ["含早餐", "景观房", "高楼层"] },
{ "orderId": "2102309919002943489", "teamNo": "26-2355", "requirementType": "VEHICLE", "specialTags": ["儿童安全座椅"] }
],
"transferSummary": {
"householdCount": 2,
"pickupHouseholdCount": 2,
"dropoffHouseholdCount": 2,
"headcount": 7,
"vehicleSeatSummary": [
{ "vehicleType": "suv", "vehicleTypeName": "SUV系列", "seats": 5, "count": 1 },
{ "vehicleType": "mpv", "vehicleTypeName": "商务车", "seats": 7, "count": 1 }
],
"serviceDates": ["2026-10-08", "2026-10-10", "2026-10-11"]
}
},
"traceId": null,
"success": true
}
按这份实测数据,住房卡应显示:峰值 3 间/晚(两晚各 3 间取最大)、间夜 6、酒店 2 家;接送机卡应显示:2 户 · 7 人,接机 2 户、送机 2 户,SUV系列 5座 ×1 · 商务车 7座 ×1。
空数据 / 降级响应
没有任何户提交时:dailyRoomBreakdown、vehicleSeatSummary、orderSpecialTags 为空数组;transferSummary 仍是对象,计数为 0、数组为空。
{
"code": 200,
"message": "成功",
"data": {
"activeOrderCount": 2,
"hotelRequirementCount": 0,
"hotelNeededOrderCount": 2,
"hotelFlagMismatchOrderCount": 0,
"hotelSubmittedOrderCount": 0,
"vehicleRequirementCount": 0,
"dailyRoomBreakdown": [],
"vehicleSeatSummary": [],
"orderSpecialTags": [],
"transferSummary": { "householdCount": 0, "pickupHouseholdCount": 0, "dropoffHouseholdCount": 0, "headcount": 0, "vehicleSeatSummary": [], "serviceDates": [] }
},
"traceId": null,
"success": true
}
(按 VO 结构组装,取值为示意。)
错误响应
{
"code": 589500,
"message": "团期不存在",
"data": null,
"traceId": null,
"success": false
}
业务边界
- 判权
group-batch:view(GroupBatchRequirementController.java:91);无权 589507。团期不存在 589500。 - 汇总口径是「在团」子订单(只排除已取消),被打回的户不计入逐晚用房。
- 逐晚用房没有全团自订晚的条目:晚数不能用
dailyRoomBreakdown.length算,要用endDate − departDate(见四「字段来源」)。 vehicleSeatSummary只含行程用车;接送机车型看transferSummary.vehicleSeatSummary,两者不要相加。
4. 住房逐户记录 GET /v3/admin/order/group-batch/{groupBatchId}/requirement/hotel-households
VO: (无请求体) → GroupHotelHouseholdsRespVO
使用场景
逐户表的住房列、弹窗①的逐户审核列表、逐晚用房表的「城市」和「客户自订」备注。封装 getGroupHotelHouseholds(orderV2GroupBatch.js:748)。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| groupBatchId | Path | Long | ✅ | 团期 ID | 路径参数 |
出参 Result<GroupHotelHouseholdsRespVO>
| 字段 | 类型 | 说明 |
|---|---|---|
| groupBatchId | Long(JSON 字符串) | 团期 ID |
| departDate / endDate | LocalDate | 出发日 / 结束日 |
| householdCount | Integer | 需要住房的户数(与汇总 hotelNeededOrderCount 同口径) |
| countedHouseholdCount | Integer | 计入汇总的户数 |
| households[] | Array | 逐户,按 orderNo 升序 |
| households[].orderId | Long(JSON 字符串) | 子订单 ID,逐户打回 / 下发的路径参数 {id} 用它 |
| households[].orderNo | String | 订单号 |
| households[].teamNo | String | 团号,可能为 null |
| households[].customerName | String | 客户名 |
| households[].participantCount | Integer | 该户人数 |
| households[].consultantId / consultantName | Long / String | 定制师 |
| households[].status | String | 住房需求状态,见六.5;未提交为 null;打回为 REJECTED_* |
| households[].statusName | String | 状态中文名,直接显示 |
| households[].countedInSummary | Boolean | 是否计入汇总;打回态为 false |
| households[].remark | String | 备注 |
| households[].specialTags | String[] | 特殊需求 |
| households[].returnRemark / returnedAt | String / LocalDateTime | 最近一次打回原因与时间 |
| households[].days[] | Array | 逐晚:dayNumber / stayDate / customerSelfBooked / hotels[] |
| households[].days[].hotels[] | Array | hotelId / hotelName / city / district / totalRoomCount / rooms[] |
| households[].days[].hotels[].rooms[] | Array | roomTypeId / roomTypeName / roomCategory / roomCategoryName / roomCount |
请求示例
GET /v3/admin/order/group-batch/2101506167098511362/requirement/hotel-households
响应示例
按 VO 结构组装,ID 取 VO 自带示例值,其余取值为示意,不是测试服读数:
{
"code": 200,
"message": "成功",
"data": {
"groupBatchId": "2101506167098511362",
"departDate": "2026-10-08",
"endDate": "2026-10-10",
"householdCount": 1,
"countedHouseholdCount": 1,
"households": [
{
"orderId": "2101506167043985410",
"orderNo": "HL20260920101530112",
"teamNo": "26-0480",
"customerName": "张丽",
"participantCount": 3,
"consultantId": "2021059720172838914",
"consultantName": "王骁",
"status": "PENDING_REVIEW",
"statusName": "待审核",
"countedInSummary": true,
"remark": "老人同行,尽量安排低楼层",
"specialTags": ["禁烟"],
"returnRemark": null,
"returnedAt": null,
"days": [
{
"dayNumber": 1,
"stayDate": "2026-10-08",
"customerSelfBooked": false,
"hotels": [
{
"hotelId": "2023714929877450753",
"hotelName": "呼伦贝尔香格里拉大酒店",
"city": "呼伦贝尔",
"district": "海拉尔区",
"totalRoomCount": 2,
"rooms": [
{ "roomTypeId": "2023714929877450801", "roomTypeName": "高级双床房", "roomCategory": "STANDARD", "roomCategoryName": "标间", "roomCount": 2 }
]
}
]
}
]
}
]
},
"traceId": null,
"success": true
}
空数据 / 降级响应
{
"code": 200,
"message": "成功",
"data": { "groupBatchId": "2101506167098511362", "departDate": "2026-10-08", "endDate": "2026-10-10", "householdCount": 0, "countedHouseholdCount": 0, "households": [] },
"traceId": null,
"success": true
}
(按 VO 结构组装。)需要住房但一次都没提交的户也会列出,status 为 null、days 为空。
错误响应
{
"code": 589507,
"message": "无操作权限(当前角色未授予团期权限,或该团期不在您名下)",
"data": null,
"traceId": null,
"success": false
}
业务边界
- 判权
group-batch:view;团期不存在 589500。 - 被打回的户照样列出(
countedInSummary=false、status为REJECTED_TO_CONSULTANT),用于「已打回」筛选;它不计入逐晚用房。 - 本列表的「计入汇总的户」逐晚加总 = 汇总接口的
dailyRoomBreakdown,两处数字应一致。 city只在这里有,汇总接口的hotels[]没有城市;逐晚用房表的城市按hotelId关联本接口取。
5. 用车逐户记录 GET /v3/admin/order/group-batch/{groupBatchId}/requirement/vehicle-households
VO: (无请求体) → GroupVehicleHouseholdsRespVO
使用场景
逐户表的「接送机」「行程用车」两列,弹窗②(接送机)与弹窗③下半「各户行程用车需求」,已确认态「审核变更」的车侧待审行。封装 getGroupVehicleHouseholds(groupBatchId, kind)(orderV2GroupBatch.js:790)。不传 kind 一次返回两类,前端按 requirements[].kind 拆;沿用既有条目按 kind 分两次取也可以。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| groupBatchId | Path | Long | ✅ | 团期 ID | 路径参数 |
| kind | Query | String | ❌ | TRAVEL / TRANSFER,其他值报 809000 |
不传返回两类 |
出参 Result<GroupVehicleHouseholdsRespVO>
| 字段 | 类型 | 说明 |
|---|---|---|
| groupBatchId | Long(JSON 字符串) | 团期 ID |
| departDate / endDate | LocalDate | 出发日 / 结束日 |
| householdCount | Integer | 应报车的户数(含一条都没提交的户),行程用车卡「N/N 户已报」的分母 |
| vehicleRowCount | Integer | 返回的需求行条数 |
| countedHouseholdCount | Integer | 有活跃行程用车行的户数,「N/N 户已报」的分子 |
| households[].orderId | Long(JSON 字符串) | 子订单 ID |
| households[].orderNo / teamNo / customerName | String | 订单号 / 团号 / 客户名 |
| households[].participantCount | Integer | 该户人数 |
| households[].consultantId / consultantName | Long / String | 定制师 |
| households[].countedInSummary | Boolean | 是否计入汇总 |
| households[].status / statusName | String | 户级状态:null=该户一条都没提交;非 null 时取展示顺序首条(TRAVEL 优先)的状态 |
| households[].requirements[] | Array | 0~2 条(每个 kind 至多一条);被打回的行已失活,不在这里 |
| requirements[].requirementId | Long(JSON 字符串) | 需求行 ID |
| requirements[].kind / kindName | String | TRAVEL 行程用车 / TRANSFER 接送机 |
| requirements[].status / statusName | String | PENDING_REVIEW / PENDING / PROCESSING / DONE;statusName 原文直显(TRAVEL 待审显示「待提交车务」) |
| requirements[].fleet[] | Array | vehicleType / vehicleTypeName / seats / count |
| requirements[].specialTags[] | Array | code / name |
| requirements[].remark | String | 备注 |
| requirements[].serviceDates | LocalDate[] | 服务日期;接送机的日期不带方向 |
| requirements[].headcount | Integer | 人数 |
| requirements[].totalSeatCount | Integer | 总座位数 |
| requirements[].remainingPassengerSeats | Integer | 扣司机座与人数后的剩余座位 |
| requirements[].pickupRequired / dropoffRequired | Boolean | 是否接机 / 送机,仅 TRANSFER 有值,TRAVEL 为 null |
| requirements[].returnRemark / returnedAt | String / LocalDateTime | 最近一次打回原因与时间 |
请求示例
GET /v3/admin/order/group-batch/2100856430494973953/requirement/vehicle-households
响应示例
测试服实测原文(2026-09-29 16:38,经网关,未传 kind;备注字段为测试数据原样保留):
{"code":200,"message":"成功","data":{"groupBatchId":"2100856430494973953","departDate":"2026-10-08","endDate":"2026-10-10","householdCount":2,"vehicleRowCount":4,"countedHouseholdCount":2,"households":[{"orderId":"2100856430239121409","orderNo":"HL20260918155619496","teamNo":"26-7060","customerName":"王有亿","participantCount":3,"consultantId":"2021059720172838914","consultantName":"王骁","countedInSummary":true,"status":"PENDING_REVIEW","statusName":"待提交车务","requirements":[{"requirementId":"2100883541330944002","kind":"TRAVEL","kindName":"行程用车","status":"PENDING_REVIEW","statusName":"待提交车务","fleet":[{"vehicleType":"bus","vehicleTypeName":"大巴系列","seats":19,"count":1}],"specialTags":[],"remark":"#7949 AC-2 定制师提交","serviceDates":["2026-10-08","2026-10-09","2026-10-10"],"headcount":3,"totalSeatCount":19,"remainingPassengerSeats":15,"pickupRequired":null,"dropoffRequired":null,"returnRemark":null,"returnedAt":null},{"requirementId":"2102202475291549698","kind":"TRANSFER","kindName":"接送机","status":"PENDING_REVIEW","statusName":"待审核","fleet":[{"vehicleType":"suv","vehicleTypeName":"SUV系列","seats":5,"count":1}],"specialTags":[{"code":"儿童安全座椅","name":"儿童安全座椅"}],"remark":"444444","serviceDates":["2026-10-08","2026-10-11"],"headcount":3,"totalSeatCount":5,"remainingPassengerSeats":1,"pickupRequired":true,"dropoffRequired":true,"returnRemark":null,"returnedAt":null}]},{"orderId":"2102309919002943489","orderNo":"HL20260922161158291","teamNo":"26-2355","customerName":"王二麻子","participantCount":4,"consultantId":"2083111674486693889","consultantName":"刘畅","countedInSummary":true,"status":"PENDING_REVIEW","statusName":"待提交车务","requirements":[{"requirementId":"2104838140441280514","kind":"TRAVEL","kindName":"行程用车","status":"PENDING_REVIEW","statusName":"待提交车务","fleet":[{"vehicleType":"bus","vehicleTypeName":"大巴系列","seats":19,"count":1}],"specialTags":[{"code":"儿童安全座椅","name":"儿童安全座椅"}],"remark":"12121221","serviceDates":["2026-10-08","2026-10-09","2026-10-10"],"headcount":4,"totalSeatCount":19,"remainingPassengerSeats":14,"pickupRequired":null,"dropoffRequired":null,"returnRemark":null,"returnedAt":null},{"requirementId":"2104838140579692545","kind":"TRANSFER","kindName":"接送机","status":"PENDING_REVIEW","statusName":"待审核","fleet":[{"vehicleType":"mpv","vehicleTypeName":"商务车","seats":7,"count":1}],"specialTags":[{"code":"儿童安全座椅","name":"儿童安全座椅"}],"remark":"32","serviceDates":["2026-10-08","2026-10-10"],"headcount":4,"totalSeatCount":7,"remainingPassengerSeats":2,"pickupRequired":true,"dropoffRequired":true,"returnRemark":null,"returnedAt":null}]}]},"traceId":null,"success":true}
注意同一户 TRAVEL 待审的 statusName 是「待提交车务」、TRANSFER 待审是「待审核」,两者 status 都是 PENDING_REVIEW。判断用 status,显示用 statusName。
空数据 / 降级响应
{
"code": 200,
"message": "成功",
"data": { "groupBatchId": "2100856430494973953", "departDate": "2026-10-08", "endDate": "2026-10-10", "householdCount": 0, "vehicleRowCount": 0, "countedHouseholdCount": 0, "households": [] },
"traceId": null,
"success": true
}
(按 VO 结构组装。)应报车但一条都没提交的户会列出,status 为 null、requirements 为空数组。
错误响应
{
"code": 809000,
"message": "用车需求类别非法:BUS",
"data": null,
"traceId": null,
"success": false
}
(按错误码模板 用车需求类别非法:{0} 组装。)
业务边界
- 判权
group-batch:view;团期不存在 589500;kind非法 809000。 - 车侧没有「已打回」可读:打回后该行失活、从
requirements里消失,读数与「未提交」相同。逐户表「已打回」筛选只能覆盖住房侧(见四「字段缺口」)。 - 列表范围 = 在团户里
needs_vehicle=1的户,并上有活跃用车需求行的户。下单时needs_vehicle恒写 true,所以实际上就是全部在团户;没报任何用车的户也在列表里,status为 null、requirements为[]。 - 最多 500 户(超出截断),按
orderNo升序(空值排最后),同值再按orderId。 - 一户最多一条 TRAVEL、一条 TRANSFER。
6. 整团确认预检 GET /v3/admin/order/group-batch/{groupBatchId}/requirement/confirm-check
VO: (无请求体) → GroupBatchRequirementCheckRespVO
使用场景
状态条「预检通过,可以确认 / 还有 N 项未就绪」、弹窗底部 missingText、大交通声明提示条。进入页签调用一次;弹窗打开时、弹窗③保存草稿或免车后各重拉一次。封装 confirmGroupBatchRequirementCheck(orderV2GroupBatch.js:629)。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| groupBatchId | Path | Long | ✅ | 团期 ID | 路径参数 |
出参 Result<GroupBatchRequirementCheckRespVO>
| 字段 | 类型 | 说明 |
|---|---|---|
| groupBatchId | Long(JSON 字符串) | 团期 ID |
| batchStatus / batchStatusName | String | 团期阶段 |
| ready | Boolean | missing 为空 且 vehicleMissing 为空 且 阶段为 RESOURCE_PREPARING 时为 true |
| missing[] | Array | 住房侧缺失:orderId / teamNo / orderNo / customerName / consultantId / consultantName / reason / reasonName / dayNumber / segmentIndex / expectedNights / actualNights;reason 见六.5 |
| checkedResourceTypes | String[] | 本次检查了哪些资源类型 |
| vehicleWaived | Boolean | 是否已声明整团免车 |
| vehicleMissing[] | Array | 车侧违规:reason / groupCode / tripDate / orderId / teamNo / orderNo / detail;reason 见六.5。免车时恒为空 |
| vehicleExemptHouseholds | Array | 豁免用车的户 |
| groupVehicleRequirementId / Status / Version | Long / String / Integer | 当前活跃正式用车需求;没有时为 null |
| transferSubmitEnabled | Boolean | 接送机提交开关状态 |
| transferDeclaredWithoutRequirement[] | Array | 大交通里声明了接送、但没报接送机需求的户:orderId / teamNo / orderNo / customerName / consultantId / consultantName / pickupRequired / dropoffRequired / pickupRemark。只是提示,不进 ready、不阻断确认 |
请求示例
GET /v3/admin/order/group-batch/2104327837991518210/requirement/confirm-check
响应示例
测试服实测原文(2026-09-27,整团免车的团期):
{"code":200,"message":"成功","data":{"groupBatchId":"2104327837991518210","batchStatus":"RESOURCE_PREPARING","batchStatusName":"资源准备中","ready":true,"missing":[],"checkedResourceTypes":["HOTEL","VEHICLE"],"vehicleWaived":true,"vehicleMissing":[],"vehicleExemptHouseholds":[],"groupVehicleRequirementId":"2104331168285671426","groupVehicleRequirementStatus":"CONFIRMED","groupVehicleRequirementVersion":1,"transferSubmitEnabled":true,"transferDeclaredWithoutRequirement":[]},"traceId":null,"success":true}
空数据 / 降级响应
没有降级形态。团期阶段不对时照常返回 200,ready=false,missing 与 vehicleMissing 可能都为空——此时 ready=false 的原因就是阶段,按 batchStatusName 提示。
错误响应
{
"code": 589507,
"message": "无操作权限(当前角色未授予团期权限,或该团期不在您名下)",
"data": null,
"traceId": null,
"success": false
}
业务边界
- 判权
group-batch:demand:confirm(GroupBatchRequirementController.java:160)。只有 view 权限的角色调它会 589507,页签要能在拿不到预检时照常渲染只读部分,并隐藏主按钮。 - 车侧检查顺序:团级六条(809100 / 809101 / 809103~809110 对应的原因)→ 户级未提交行程用车(
HOUSEHOLD_REQUIREMENT_NOT_SUBMITTED)→ 待放行接送机未回填服务日(TRANSFER_SERVICE_DATES_NOT_BACKFILLED)→ 接送机窗不全(TRANSFER_WINDOW_INCOMPLETE)→ 户车型与分组车型不符(MEMBER_GROUP_MISMATCH)。 - 整团免车时车侧检查整段跳过(
vehicleMissing恒空,809007 也不查),transferDeclaredWithoutRequirement不受免车影响照常给。 - 确认时后端按同一套规则再算一遍,预检通过不等于确认一定成功(中间可能有户改了需求),确认失败按错误码处理。
7. 取正式用车需求 GET /v3/admin/order/group-batch/{groupBatchId}/vehicle-requirement
VO: (无请求体) → GroupVehicleRequirementRespVO
使用场景
行程用车卡(状态、组数、逐日覆盖、车型)、「用车安排」的分组×日期矩阵、弹窗③打开时的初始草稿。封装 getGroupVehicleRequirement(orderV2GroupBatch.js:865)。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| groupBatchId | Path | Long | ✅ | 团期 ID | 路径参数 |
出参 Result<GroupVehicleRequirementRespVO>
| 字段 | 类型 | 说明 |
|---|---|---|
| requirementId | Long(JSON 字符串) | 正式需求 ID |
| groupBatchId | Long(JSON 字符串) | 团期 ID |
| status | String | 见六.5 GroupVehicleRequirementStatus |
| version | Integer | 版本号,PUT 时原样带回 |
| remark | String | 整份备注 |
| confirmedBy / confirmedAt | String / LocalDateTime | 确认人 / 确认时间 |
| planRefreshState / planRefreshReplayCount / blockedStage / planRefreshStalled / planRefreshStalledReason / planRefreshTimeoutAt / planRefreshReplayExhausted | — | 受控重开链路专用,普通流程为空,本页不展示 |
| groups[] | Array | 乘车分组;status=CONFIRMED 且 groups 为空 = 整团免车 |
| groups[].groupId / groupCode | Long / String | 分组 ID / 分组编码(如 BUS、BUS2) |
| groups[].vehicleType / vehicleTypeName | String | 车型 |
| groups[].seats / count | Integer | 单车座位 / 车辆数 |
| groups[].serviceStartDate / serviceEndDate | LocalDate | 本组服务起止 |
| groups[].specialTags[] | Array | code / name |
| groups[].remark | String | 组备注 |
| groups[].totalSeatCount / maxHeadcount / remainingPassengerSeats | Integer | 总座位 / 最大单日人数 / 剩余座位 |
| groups[].days[] | Array | 逐日:tripDate / headcount / memberOrderIds / memberOrderCount |
| exemptHouseholds | Array | 豁免用车的户 |
请求示例
GET /v3/admin/order/group-batch/2100856430494973953/vehicle-requirement
响应示例
按 VO 结构组装,取值为示意,不是测试服读数:
{
"code": 200,
"message": "成功",
"data": {
"requirementId": "2104900000000000001",
"groupBatchId": "2100856430494973953",
"status": "DRAFT",
"version": 1,
"remark": null,
"confirmedBy": null,
"confirmedAt": null,
"planRefreshState": null,
"planRefreshReplayCount": null,
"blockedStage": null,
"planRefreshStalled": null,
"planRefreshStalledReason": null,
"planRefreshTimeoutAt": null,
"planRefreshReplayExhausted": null,
"groups": [
{
"groupId": "2104900000000000011",
"groupCode": "BUS",
"vehicleType": "bus",
"serviceStartDate": "2026-10-08",
"serviceEndDate": "2026-10-10",
"vehicleTypeName": "大巴系列",
"seats": 19,
"count": 1,
"specialTags": [{ "code": "儿童安全座椅", "name": "儿童安全座椅" }],
"remark": null,
"totalSeatCount": 19,
"maxHeadcount": 7,
"remainingPassengerSeats": 11,
"days": [
{ "tripDate": "2026-10-08", "headcount": 7, "memberOrderIds": ["2100856430239121409", "2102309919002943489"], "memberOrderCount": 2 },
{ "tripDate": "2026-10-09", "headcount": 7, "memberOrderIds": ["2100856430239121409", "2102309919002943489"], "memberOrderCount": 2 },
{ "tripDate": "2026-10-10", "headcount": 7, "memberOrderIds": ["2100856430239121409", "2102309919002943489"], "memberOrderCount": 2 }
]
}
],
"exemptHouseholds": []
},
"traceId": null,
"success": true
}
空数据 / 降级响应
{ "code": 200, "message": "成功", "data": null, "traceId": null, "success": true }
还没形成正式需求时 data=null:行程用车卡显示「未形成正式需求」,矩阵不画。
错误响应
{
"code": 589507,
"message": "无操作权限(当前角色未授予团期权限,或该团期不在您名下)",
"data": null,
"traceId": null,
"success": false
}
业务边界
- 判权
group-batch:demand:confirm(不是 view)。只有 view 权限的角色看页签时这里会 589507,行程用车卡与用车矩阵要降级为「无权查看」而不是整页报错。 - 整团免车的判定只能用「
status=CONFIRMED且groups为空」,没有单独的布尔字段;预检接口的vehicleWaived可以作为交叉核对。 version是乐观锁,编辑前取、保存时带回,页面停留期间被别人改过会 809102。
8. 正式用车需求自动汇总 GET /v3/admin/order/group-batch/{groupBatchId}/vehicle-requirement/aggregate-draft
VO: (无请求体) → GroupVehicleAggregateDraftRespVO
使用场景
弹窗③「按户需求重新汇总」,以及还没有正式需求时打开弹窗③的首次自动汇总。只计算、不落库;返回的 draft 可以原样作为 PUT 的请求体。封装 getGroupVehicleAggregateDraft(orderV2GroupBatch.js:963)。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| groupBatchId | Path | Long | ✅ | 团期 ID | 路径参数 |
出参 Result<GroupVehicleAggregateDraftRespVO>
| 字段 | 类型 | 说明 |
|---|---|---|
| groupBatchId | Long(JSON 字符串) | 团期 ID |
| currentStatus | String | 当前活跃正式需求状态,没有时为 null |
| draft | GroupVehicleRequirementSaveReqVO | 汇总出的草稿,结构同第 9 节请求体,可原样 PUT |
| droppedFleetItems[] | Array | 汇总时被舍弃的车型:orderId / teamNo / orderNo / vehicleType / seats / count / keptVehicleType / reason |
| staleHeadcountOrders[] | Array | 人数已变的户:orderId / teamNo / orderNo / frozenHeadcount / liveHeadcount |
| paddedOrderDays[] | Array | 被补齐日期的户:orderId / teamNo / orderNo / dates |
| seatOptionAdjusted[] | Array | 座位档位被调整的组:groupCode / orderId / teamNo / orderNo / vehicleType / originalSeats / adoptedSeats / seatOptions / reason |
| violations[] | Array | 草稿仍违反的规则:code(Integer,809 段码)/ reason / detail / groupCode / tripDate / orderId / teamNo |
| exemptHouseholds | Array | 豁免用车的户 |
请求示例
GET /v3/admin/order/group-batch/2100856430494973953/vehicle-requirement/aggregate-draft
响应示例
按 VO 结构组装,取值为示意,不是测试服读数:
{
"code": 200,
"message": "成功",
"data": {
"groupBatchId": "2100856430494973953",
"currentStatus": null,
"draft": {
"version": null,
"remark": null,
"groups": [
{
"groupId": null,
"groupCode": "BUS",
"vehicleType": "bus",
"serviceStartDate": "2026-10-08",
"serviceEndDate": "2026-10-10",
"seats": 19,
"count": 1,
"specialTags": ["儿童安全座椅"],
"remark": null,
"days": [
{ "tripDate": "2026-10-08", "headcount": 7, "memberOrderIds": ["2100856430239121409", "2102309919002943489"] },
{ "tripDate": "2026-10-09", "headcount": 7, "memberOrderIds": ["2100856430239121409", "2102309919002943489"] },
{ "tripDate": "2026-10-10", "headcount": 7, "memberOrderIds": ["2100856430239121409", "2102309919002943489"] }
]
}
]
},
"droppedFleetItems": [],
"staleHeadcountOrders": [],
"paddedOrderDays": [],
"seatOptionAdjusted": [],
"violations": [],
"exemptHouseholds": []
},
"traceId": null,
"success": true
}
空数据 / 降级响应
没有降级形态:车型字典读取失败时直接报 809120(见下),有户还没提交行程用车时报 809121,都不会返回半份草稿。
错误响应
{
"code": 809121,
"message": "团期 「第3期 10月8日出发团」 有 1 户缺少可汇总的行程用车需求,暂不能自动汇总:26-2355:未提交行程用车需求",
"data": null,
"traceId": null,
"success": false
}
(按错误码模板 团期 {0} 有 {1} 户缺少可汇总的行程用车需求,暂不能自动汇总:{2} 组装。{0} 是「第N期 班期名」外加一对直角引号,两者都缺时为「(未命名)」;{2} 是逐户「团号(缺则订单号):原因」,多户用顿号分隔。)
业务边界
- 判权
group-batch:demand:confirm。 - 809120:车型字典读取失败,提示用户重试即可。
- 809121:有户的行程用车汇总不出来,不能汇总。原因有四种:未提交行程用车需求、车型均不在车型字典内、推不出用车日期、订单人数为 0。弹窗③下半的逐户列表会显示是哪几户,message 里也逐户点名。
violations非空时照样可以 PUT 成草稿,但确认会被同样的规则挡住;弹窗③要把violations逐条显示在对应分组 / 日期旁。- 只读、无副作用,可以反复调用。
9. 保存正式用车需求 PUT /v3/admin/order/group-batch/{groupBatchId}/vehicle-requirement
VO: GroupVehicleRequirementSaveReqVO → GroupVehicleRequirementRespVO
使用场景
弹窗③「仅保存草稿」;模式一 / 模式二确认前,如果弹窗③里改过分组或还没有正式需求,先 PUT 落成草稿再调 confirm。封装 saveGroupVehicleRequirement(orderV2GroupBatch.js:929)。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| groupBatchId | Path | Long | ✅ | 团期 ID | 路径参数 |
| version | Body | Integer | ❌ | 首次保存传 null;之后必须等于当前版本 | 乐观锁 |
| remark | Body | String | ❌ | ≤500 | 整份备注 |
| groups | Body | Array | ✅ | @NotNull,空数组合法 |
乘车分组 |
| groups[].groupId | Body | Long | ❌ | 新组为 null | 已有组带回原 ID |
| groups[].groupCode | Body | String | ✅ | ≤32,不可改名(改名 = 删旧组加新组) | 分组编码 |
| groups[].vehicleType | Body | String | ✅ | ≤64,须在车型字典内 | 车型 |
| groups[].serviceStartDate / serviceEndDate | Body | LocalDate | ✅ | @NotNull |
本组服务起止 |
| groups[].seats | Body | Integer | ❌ | @Min(1),须在该车型可选档位内;与 count 同填或同空 |
单车座位 |
| groups[].count | Body | Integer | ❌ | @Min(1);与 seats 同填或同空 |
车辆数 |
| groups[].specialTags | Body | String[] | ❌ | 须在字典内 | 特殊诉求 |
| groups[].remark | Body | String | ❌ | ≤500 | 组备注 |
| groups[].days | Body | Array | ✅ | @NotEmpty |
逐日 |
| groups[].days[].tripDate | Body | LocalDate | ✅ | 在本组服务日范围内、不重复 | 日期 |
| groups[].days[].headcount | Body | Integer | ✅ | @Min(1),不小于当日成员户数 |
当日人数 |
| groups[].days[].memberOrderIds | Body | Long[] | ✅ | @NotEmpty;须属本团;同户同日只能在一个组 |
当日成员子订单 |
出参 Result<GroupVehicleRequirementRespVO>
| 字段 | 类型 | 说明 |
|---|---|---|
| status | String | 保存后恒为 DRAFT |
| version | Integer | 已 +1,下次保存用它 |
| groups / 其余字段 | — | 同第 7 节 |
请求示例
{
"version": 1,
"remark": null,
"groups": [
{
"groupId": "2104900000000000011",
"groupCode": "BUS",
"vehicleType": "bus",
"serviceStartDate": "2026-10-08",
"serviceEndDate": "2026-10-10",
"seats": 19,
"count": 1,
"specialTags": ["儿童安全座椅"],
"remark": null,
"days": [
{ "tripDate": "2026-10-08", "headcount": 7, "memberOrderIds": ["2100856430239121409", "2102309919002943489"] },
{ "tripDate": "2026-10-09", "headcount": 7, "memberOrderIds": ["2100856430239121409", "2102309919002943489"] },
{ "tripDate": "2026-10-10", "headcount": 7, "memberOrderIds": ["2100856430239121409", "2102309919002943489"] }
]
}
]
}
响应示例
按 VO 结构组装,取值为示意:结构同第 7 节响应示例,status 为 DRAFT、version 为 2。
{
"code": 200,
"message": "成功",
"data": {
"requirementId": "2104900000000000001",
"groupBatchId": "2100856430494973953",
"status": "DRAFT",
"version": 2,
"remark": null,
"confirmedBy": null,
"confirmedAt": null,
"groups": [
{
"groupId": "2104900000000000011",
"groupCode": "BUS",
"vehicleType": "bus",
"vehicleTypeName": "大巴系列",
"serviceStartDate": "2026-10-08",
"serviceEndDate": "2026-10-10",
"seats": 19,
"count": 1,
"totalSeatCount": 19,
"maxHeadcount": 7,
"remainingPassengerSeats": 11,
"days": [
{ "tripDate": "2026-10-08", "headcount": 7, "memberOrderIds": ["2100856430239121409", "2102309919002943489"], "memberOrderCount": 2 }
]
}
],
"exemptHouseholds": []
},
"traceId": null,
"success": true
}
空数据 / 降级响应
groups: [] 是合法请求,但本团有需要用车的户时报 809103;整团不用车应走第 10 节免车,不要 PUT 空分组。
错误响应
{
"code": 809102,
"message": "正式用车需求已被他人修改(提交版本 1,当前版本 2),请刷新后重试",
"data": null,
"traceId": null,
"success": false
}
(按错误码模板组装。)
业务边界
- 判权
group-batch:demand:confirm;阶段须为RESOURCE_PREPARING,否则 589501。 - 错误按后端校验顺序:先在事务外做字典校验 809117(特殊标签)/ 809120(车型字典读不到)/ 809119(车型不在字典内),这三个排在阶段守卫之前 → 团期不存在 589500 → 阶段 589501 → 809115(已免车,须先撤回)→ 809101(当前不是 DRAFT,比如已 CONFIRMED,须先撤回)→ 809102(版本不对)→ 809104(分组重复或改名)→ 809123(有户还没提交行程用车)→ 分组 / 座位 / 档位类只抛第一条(809103、809105~809110、809116、809118、809124)→ 写入时版本被并发推进,仍报 809102。
- 入参校验失败返回
code=400,message为注解原文(如「提交备注不能超过 500 字」这类),HTTP 仍是 200。 - 幂等 5 秒,同团重复提交返回
code=100502「正式用车需求保存中,请勿重复提交」。 - 保存只落草稿,不下发车务;下发由第 12 节确认完成。
10. 整团免车 POST /v3/admin/order/group-batch/{groupBatchId}/vehicle-requirement/waive
VO: GroupVehicleRequirementWaiveReqVO → GroupVehicleRequirementRespVO
使用场景
弹窗③「整团不用车」。整团不需要平台用车的团期,不免车就确认不了(没有正式需求时 confirm 报 809100)。封装 waiveGroupVehicleRequirement(orderV2GroupBatch.js:997)。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| groupBatchId | Path | Long | ✅ | 团期 ID | 路径参数 |
| reason | Body | String | ✅ | @NotBlank「免车原因不能为空」;≤200「免车原因不能超过 200 字」 |
免车原因 |
出参 Result<GroupVehicleRequirementRespVO>
| 字段 | 类型 | 说明 |
|---|---|---|
| status | String | 恒为 CONFIRMED |
| groups | Array | 恒为空数组 |
| 其余字段 | — | 同第 7 节 |
请求示例
{ "reason": "客户自行包车,全程不需要平台用车" }
响应示例
按 VO 结构组装,取值为示意:
{
"code": 200,
"message": "成功",
"data": {
"requirementId": "2104331168285671426",
"groupBatchId": "2104327837991518210",
"status": "CONFIRMED",
"version": 1,
"remark": "客户自行包车,全程不需要平台用车",
"confirmedBy": "2021059720172838914",
"confirmedAt": "2026-09-27 10:12:00",
"groups": [],
"exemptHouseholds": []
},
"traceId": null,
"success": true
}
空数据 / 降级响应
已经免车的团期再调一次按幂等成功处理,返回同样的免车态。
错误响应
{
"code": 809114,
"message": "车务已开工(2026-10-08:BUS),不能再声明整团免车",
"data": null,
"traceId": null,
"success": false
}
(按错误码模板 车务已开工({0}:{1}),不能再声明整团免车 组装。)
业务边界
- 判权
group-batch:demand:confirm;阶段须为RESOURCE_PREPARING / TRIP_FINISHED / REVIEWING之一(GroupBatchService.java:2468),否则 589501。 - 带分组的活跃正式需求须为
DRAFT或CONFIRMED,否则 809101(零写入);带分组时失活旧版本、换一份零分组的免车版本;零分组且已是确认态时按幂等成功返回;车务已开工 809114(在写入之前)。 - 免车只是把正式需求置成「已确认且无分组」,不会整团确认需求;弹窗仍要走第 12 节 confirm 才算确认。
- 免车后 confirm 不放行任何车需求(含待审接送机),见四「对账补放行」。
- 免车后要改回有车:先第 11 节撤回,再 PUT 分组,否则 PUT 报 809115。
- 幂等 5 秒,重复提交返回
code=100502「整团免车声明处理中,请勿重复提交」。
11. 撤回正式用车需求 POST /v3/admin/order/group-batch/{groupBatchId}/vehicle-requirement/withdraw
VO: GroupVehicleRequirementWithdrawReqVO → GroupVehicleRequirementRespVO
使用场景
两种情况必须先撤回:①已免车,想改成有车;②正式需求已确认(CONFIRMED / DISPATCHED),想改分组。原来挂在「更多」菜单里,按钮取消后入口位置前端自定(建议放弹窗③分组区右上角,仅在 status ∈ {CONFIRMED, DISPATCHED} 时出现)。封装 withdrawGroupVehicleRequirement(orderV2GroupBatch.js:979)。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| groupBatchId | Path | Long | ✅ | 团期 ID | 路径参数 |
| reason | Body | String | ✅ | @NotBlank「撤回原因不能为空」;≤200「撤回原因不能超过 200 字」 |
撤回原因 |
出参 Result<GroupVehicleRequirementRespVO>
| 字段 | 类型 | 说明 |
|---|---|---|
| status | String | 恒为 DRAFT |
| version | Integer | 已 +1 |
| confirmedBy / confirmedAt | String / LocalDateTime | 已清空 |
| 其余字段 | — | 同第 7 节 |
请求示例
{ "reason": "客户临时增加一天包车,需要重新分组" }
响应示例
按 VO 结构组装,取值为示意:
{
"code": 200,
"message": "成功",
"data": {
"requirementId": "2104331168285671426",
"groupBatchId": "2104327837991518210",
"status": "DRAFT",
"version": 2,
"remark": "客户临时增加一天包车,需要重新分组",
"confirmedBy": null,
"confirmedAt": null,
"groups": [],
"exemptHouseholds": []
},
"traceId": null,
"success": true
}
空数据 / 降级响应
没有正式需求时不是空数据,而是报 809100。
错误响应
{
"code": 809101,
"message": "正式用车需求当前状态 DRAFT 不允许本次操作,期望 [CONFIRMED, DISPATCHED]",
"data": null,
"traceId": null,
"success": false
}
(按错误码模板 正式用车需求当前状态 {0} 不允许本次操作,期望 {1} 组装。{1} 是后端集合的 toString(),方括号里两个值的先后顺序不固定,前端原样显示 message,不要解析它。)
业务边界
- 判权
group-batch:demand:confirm;无团期阶段守卫。 - 撤回本身不受团期阶段限制,但撤回之后的第 9 节 PUT 与第 12 节 confirm 只在
RESOURCE_PREPARING可用,其他阶段报 589501。团期已过RESOURCE_PREPARING时,撤回入口要提示这一点。 - 状态须为
CONFIRMED或DISPATCHED,否则 809101;没有正式需求 809100。 - 撤回后:回到
DRAFT、version+1、原因追加进remark、清确认人与确认时间、复位团期vehicleReady。 - 撤回不清团级
requirementConfirmed;改完分组后要再走一次第 12 节 confirm,正式需求才会回到CONFIRMED。 - 幂等 5 秒,重复提交返回
code=100502「正式用车需求撤回中,请勿重复提交」。
12. 整团确认需求 POST /v3/admin/order/group-batch/{groupBatchId}/requirement/confirm
VO: (无请求体) → GroupBatchRequirementConfirmRespVO
使用场景
弹窗底部模式一「确认需求并下发」、模式二「打回 N 户并确认其余」的核心一步。一次调用把住房、行程用车、接送机的待审行一起放行,并把正式用车需求推到已确认。封装 confirmGroupBatchRequirement(orderV2GroupBatch.js:656)。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| groupBatchId | Path | Long | ✅ | 团期 ID | 路径参数;无请求体 |
出参 Result<GroupBatchRequirementConfirmRespVO>
| 字段 | 类型 | 说明 |
|---|---|---|
| groupBatchId | Long(JSON 字符串) | 团期 ID |
| requirementConfirmed | Boolean | 恒为 true |
| dispatchedOrderIds | Long[] | 住房侧本次由待审放行的户 |
| skippedOrderIds | Long[] | 住房侧本次未动的户(已是 PENDING / PROCESSING / DONE) |
| dispatchedCount | Integer | = dispatchedOrderIds 长度 |
| vehicleDispatchedOrderIds | Long[] | 行程用车(TRAVEL)本次放行的户 |
| transferDispatchedOrderIds | Long[] | 接送机(TRANSFER)本次放行的户,对账补放行就用它 |
| vehicleSkippedOrderIds | Long[] | 车侧本次未动的户(两类合并去重);免车时为空数组 |
| vehicleDispatchedCount | Integer | 车侧放行的条数(不是户数)= 上面两个列表长度之和 |
| groupVehicleRequirementId | Long | 正式需求 ID;整团免车且无正式需求时为 null |
| groupVehicleRequirementStatus | String | 确认后正式需求的实际状态:DRAFT / PENDING_RECONFIRM → CONFIRMED;DISPATCHED / DONE 原样返回 |
| groupVehicleRequirementVersion | Integer | 确认后版本号 |
| planRefreshState / planRefreshOutboxId / planRefreshReplayKind / planRefreshReplayCount / blockedStage | — | 受控重开链路专用,普通确认为 null |
| advanceUnblocked | Boolean | 恒为 false |
请求示例
POST /v3/admin/order/group-batch/2100856430494973953/requirement/confirm
响应示例
按 VO 结构组装,取值为示意,不是测试服读数:
{
"code": 200,
"message": "成功",
"data": {
"groupBatchId": "2100856430494973953",
"requirementConfirmed": true,
"dispatchedOrderIds": ["2100856430239121409", "2102309919002943489"],
"skippedOrderIds": [],
"dispatchedCount": 2,
"vehicleDispatchedOrderIds": ["2100856430239121409", "2102309919002943489"],
"transferDispatchedOrderIds": ["2100856430239121409", "2102309919002943489"],
"vehicleSkippedOrderIds": [],
"vehicleDispatchedCount": 4,
"groupVehicleRequirementId": "2104900000000000001",
"groupVehicleRequirementStatus": "CONFIRMED",
"groupVehicleRequirementVersion": 3,
"planRefreshState": null,
"planRefreshOutboxId": null,
"planRefreshReplayKind": null,
"planRefreshReplayCount": null,
"blockedStage": null,
"advanceUnblocked": false
},
"traceId": null,
"success": true
}
空数据 / 降级响应
没有降级形态:要么整体成功,要么报错且零写入。
错误响应
{
"code": 589533,
"message": "仍有 1 户未提交需求或需求不完整,无法整体确认,请先查看缺失清单",
"data": null,
"traceId": null,
"success": false
}
(按错误码模板 仍有 {0} 户未提交需求或需求不完整,无法整体确认,请先查看缺失清单 组装。)
业务边界
- 判权
group-batch:demand:confirm。 - 后端执行顺序(
GroupBatchRequirementService.java:505-584,同一事务,任一步失败整团零写入):①阶段守卫 589501 → ②住房缺失 589533 → ③车侧违规,抛第一条对应的 809 段码(809100 / 809101 / 809103~809110 / 809122 / 809007 / 809126 / 809125 等)→ ④写确认标记与时间线 → ⑤住房待审户放行 → ⑥正式用车需求推到已确认 → ⑦行程用车与接送机待审行放行 → 提交后通知房务。 - 整团免车时 ⑥⑦ 都不做:待审的行程用车与接送机一条都不放行(
:518-520、:564)。 - 放行集合只含在团、
needs_vehicle=1、未退团的户(:1206-1211):needs_vehicle≠1的户报了接送机,这里也不放行。 - 上两条的后果:确认成功后前端必须用
transferDispatchedOrderIds对账,见四「对账补放行」。 - 同一团期的确认与逐户打回共用一把团级锁。
- 幂等 5 秒,重复提交返回
code=100502「需求确认处理中,请勿重复提交」。 - 受控重开链路(正式需求处于
PENDING_RECONFIRM)下还可能报 809204(车务配车尚未覆盖完整)、809210(刷新重试次数已达上限);普通确认不会遇到。
13. 住房逐户打回 POST /v3/admin/order/{id}/hotel-requirement/reject
VO: RejectReqVO → Void
使用场景
弹窗①某户选「打回」并填了原因,提交时逐户调用。封装 rejectHotelRequirement(orderId, payload)(orderV2.js:1543)。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| id | Path | Long | ✅ | 子订单 ID(取 hotel-households 的 orderId) |
路径参数 |
| returnRemark | Body | String | ✅ | @NotBlank「打回/驳回备注不能为空」;≤500「打回/驳回备注不能超过 500 字」 |
打回原因,定制师可见 |
出参 Result<Void>
| 字段 | 类型 | 说明 |
|---|---|---|
| data | null | 成功无返回体 |
请求示例
{ "returnRemark": "第 2 晚房型与人数对不上,3 人只订了 1 间大床,请核对后重新提交" }
响应示例
{ "code": 200, "message": "成功", "data": null, "traceId": null, "success": true }
空数据 / 降级响应
无返回体,成功即 data=null。
错误响应
{
"code": 589535,
"message": "子订单 26-2355 已分房,请先由房务调整配房后再打回",
"data": null,
"traceId": null,
"success": false
}
(按错误码模板 子订单 {0} 已分房,请先由房务调整配房后再打回 组装。)
业务边界
- 判权
group-batch:demand:confirm;团期阶段须为RESOURCE_PREPARING,否则 589501(零写入)。 - 错误按后端校验顺序:订单不存在 581007 → 非团单 582083 → 阶段 589501 → 该户已有配房 589535(要房务先调整配房)→ 订单无有效需求行 582031 → 源状态不是
PENDING_REVIEW/PENDING582083 → 并发改动 582083。 - 成功后:该户住房需求退回定制师(
REJECTED_TO_CONSULTANT),清团级确认标记,写时间线BATCH_REQUIREMENT_REJECT,给定制师生成返工待办并发站内信。 - 与整团确认共用团级锁;每户一次调用,各自独立提交,已成功的打回不会因为后面某户失败而回滚。
14. 用车逐户打回 POST /v3/admin/order/{id}/vehicle-requirement/reject
VO: RejectReqVO → Void
使用场景
弹窗②接送机打回(kind=TRANSFER)、弹窗③下半各户行程用车打回(kind=TRAVEL)。封装 rejectVehicleRequirement(orderId, payload, kind)(orderV2.js:1561)。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| id | Path | Long | ✅ | 子订单 ID | 路径参数 |
| kind | Query | String | ❌ | TRAVEL / TRANSFER,不传按 TRAVEL;其他值 809000 |
打回哪一类;接送机必须显式传 TRANSFER |
| returnRemark | Body | String | ✅ | @NotBlank「打回/驳回备注不能为空」;≤500「打回/驳回备注不能超过 500 字」 |
打回原因 |
出参 Result<Void>
| 字段 | 类型 | 说明 |
|---|---|---|
| data | null | 成功无返回体 |
请求示例
POST /v3/admin/order/2102309919002943489/vehicle-requirement/reject?kind=TRANSFER
Content-Type: application/json
{ "returnRemark": "送机日期与大交通返程不一致,请按返程航班重新提交" }
响应示例
{ "code": 200, "message": "成功", "data": null, "traceId": null, "success": true }
空数据 / 降级响应
无返回体,成功即 data=null。
错误响应
{
"code": 589501,
"message": "团期状态不允许当前操作",
"data": null,
"traceId": null,
"success": false
}
业务边界
- 判权
group-batch:demand:confirm;团期阶段须为RESOURCE_PREPARING,否则 589501(零写入)。已确认态「审核变更」出现时团期已过这个阶段,所以那里不能打回。 - 错误按后端校验顺序:订单不存在 581007 → 非团单 582083 → 阶段 589501 → 该户用车需求正在最终确认 582092 → 订单无有效需求行 582031 → 源状态不是
PENDING_REVIEW/PENDING582083 → 并发改动 582083。车侧没有 589535。 kind只打回指定的那一类:打回接送机不影响该户行程用车,反之亦然。- 成功后:该行退回定制师并失活(从 vehicle-households 里消失),不论 kind 都会清团级确认标记,写时间线
BATCH_REQUIREMENT_REJECT。 - 打回 TRAVEL 后该户缺行程用车,整团确认会被 809122 挡住;打回 TRANSFER 不挡确认(推理成立,未在测试服实测),该户可能出现在预检的
transferDeclaredWithoutRequirement提示里。
15. 住房逐户下发 POST /v3/admin/order/{id}/hotel-requirement/dispatch
VO: DispatchReqVO → Void
使用场景
已确认态「审核变更」里住房行点「通过」。首次确认不用它(confirm 已一并放行住房)。封装 dispatchHotelRequirement(orderId, payload)(orderV2.js:1577)。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| id | Path | Long | ✅ | 子订单 ID | 路径参数 |
| dispatchRemark | Body | String | ❌ | ≤500「提交备注不能超过 500 字」 | 下发备注;请求体必须有,可传 {} |
出参 Result<Void>
| 字段 | 类型 | 说明 |
|---|---|---|
| data | null | 成功无返回体 |
请求示例
{ "dispatchRemark": "" }
响应示例
{ "code": 200, "message": "成功", "data": null, "traceId": null, "success": true }
空数据 / 降级响应
无返回体,成功即 data=null。
错误响应
{
"code": 582083,
"message": "需求状态不允许此操作,请检查当前状态",
"data": null,
"traceId": null,
"success": false
}
业务边界
- 判权
group-batch:demand:confirm;无团期阶段守卫。 - 守卫顺序:订单不存在 581007 → 非团单 582083 → 团期未成团 589552 / 未建团 589553 → 无有效需求行 582031 → 当前不是
PENDING_REVIEW582083 → 并发更新失败 582083。 - 成功后:
PENDING_REVIEW → PENDING,写下发备注,房控状态置待处理,写时间线,该团配房完成标记失效。 - 按源码,资源准备阶段有户改住房会把整团打回「需求待确认」,所以已确认态下住房待审行正常不会出现;页面按数据渲染即可,出现就按本接口处理。
16. 用车逐户下发 POST /v3/admin/order/{id}/vehicle-requirement/dispatch
VO: DispatchReqVO → Void
使用场景
已确认态「审核变更」里车侧行点「通过」:接送机传 kind=TRANSFER,行程用车传 kind=TRAVEL。多户接送机一起通过时可以改用第 17 节批量放行。封装 dispatchVehicleRequirement(orderId, payload, kind)(orderV2.js:1597)。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| id | Path | Long | ✅ | 子订单 ID | 路径参数 |
| kind | Query | String | ❌ | TRAVEL / TRANSFER,不传按 TRAVEL;其他值 809000 |
下发哪一类;接送机必须显式传 TRANSFER |
| dispatchRemark | Body | String | ❌ | ≤500「提交备注不能超过 500 字」 | 下发备注;请求体必须有,可传 {} |
出参 Result<Void>
| 字段 | 类型 | 说明 |
|---|---|---|
| data | null | 成功无返回体 |
请求示例
POST /v3/admin/order/2102309919002943489/vehicle-requirement/dispatch?kind=TRANSFER
Content-Type: application/json
{ "dispatchRemark": "" }
响应示例
{ "code": 200, "message": "成功", "data": null, "traceId": null, "success": true }
空数据 / 降级响应
无返回体,成功即 data=null。
错误响应
测试服实测原文(2026-09-29 16:38,经网关,用不存在的订单 ID 探错误信封):
{"code":581007,"message":"订单不存在","data":null,"traceId":null,"success":false}
业务边界
- 判权
group-batch:demand:confirm;无团期阶段守卫,已确认态也能调。 - 守卫顺序:该户用车需求正在最终确认 582092「用车需求正在最终确认,请稍后重试」(最先)→ 订单不存在 581007 → 非团单 582083 → 团期未成团 589552 / 未建团 589553 → 无有效需求行 582031 → 当前不是
PENDING_REVIEW582083 → 接送机服务日期未回填 809007(在状态更新之前)→ 并发更新失败 582083。 - 成功后:
PENDING_REVIEW → PENDING,写下发备注,车控状态置待处理,软删该行旧的实配记录,写时间线。 kind传错类别会动错行:接送机不传kind会按 TRAVEL 去找行程用车行。
17. 接送机批量放行 POST /v3/admin/order/group-batch/{groupBatchId}/requirement/transfer/batch-confirm
VO: TransferBatchConfirmReqVO → TransferBatchConfirmRespVO
使用场景
两处:①模式一 / 模式二 confirm 成功后,把弹窗②判为通过、但不在 transferDispatchedOrderIds 里的户补放行;②已确认态「审核变更」里接送机多户一起通过。封装 batchConfirmTransferRequirements(orderV2GroupBatch.js:819)。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| groupBatchId | Path | Long | ✅ | 团期 ID | 路径参数 |
| orderIds | Body | Long[] | ✅ | @NotEmpty「请至少选择一个要确认的子订单」;≤200「单次确认不超过 200 户」 |
要放行接送机的子订单 |
| dispatchRemark | Body | String | ❌ | ≤500「确认备注不能超过 500 字」 | 放行备注 |
出参 Result<TransferBatchConfirmRespVO>
| 字段 | 类型 | 说明 |
|---|---|---|
| groupBatchId | Long(JSON 字符串) | 团期 ID |
| requestedCount | int | 请求户数 |
| successCount | int | 成功户数 |
| failedCount | int | 失败户数 |
| succeededOrderIds | Long[] | 成功的户 |
| failed[] | Array | 失败明细:orderId / teamNo / errorCode(Integer)/ reason |
请求示例
{ "orderIds": ["2100856430239121409", "2102309919002943489"], "dispatchRemark": "" }
响应示例
按 VO 结构组装,取值为示意:
{
"code": 200,
"message": "成功",
"data": {
"groupBatchId": "2100856430494973953",
"requestedCount": 2,
"successCount": 1,
"failedCount": 1,
"succeededOrderIds": ["2100856430239121409"],
"failed": [
{ "orderId": "2102309919002943489", "teamNo": "26-2355", "errorCode": 582083, "reason": "需求状态不允许此操作,请检查当前状态" }
]
},
"traceId": null,
"success": true
}
空数据 / 降级响应
允许部分成功:code=200 不代表全部成功,必须看 failedCount,大于 0 时把 failed[] 逐户列给用户。
错误响应
{
"code": 589597,
"message": "子订单 26-2355 不属于本团期",
"data": null,
"traceId": null,
"success": false
}
(按错误码模板 子订单 {0} 不属于本团期 组装。)
业务边界
- 判权
group-batch:demand:confirm;团期不存在 589500;团期已取消 589501;其他阶段都允许。 - 有任一户不属于本团期,整批拒绝报 589597,一户都不放行。
- 逐户失败(状态不对、服务日期未回填等)进
failed[],不影响其他户。 - 幂等 120 秒,按「团期 + 这批 orderIds」判重,重复提交返回
code=100502「接送机需求确认处理中,请勿重复提交」。
四、契约约束与正确调用方式(接口类必写)
本节只写后端接受 / 拒绝的规则与前端必须遵守的调用顺序。
✅ 正确 / ❌ 错误 payload 对照
| 场景 | payload |
|---|---|
| ✅ 接送机逐户打回 | POST /v3/admin/order/{id}/vehicle-requirement/reject?kind=TRANSFER + { "returnRemark": "原因" } |
| ❌ 接送机打回不带 kind | POST /v3/admin/order/{id}/vehicle-requirement/reject → 按 TRAVEL 打回了该户的行程用车 |
| ❌ 打回不带原因 | { "returnRemark": "" } → code=400「打回/驳回备注不能为空」 |
| ✅ 逐户下发无备注 | {} 或 { "dispatchRemark": "" } |
| ❌ 逐户下发不带请求体 | 无 body → 请求体缺失,接口不受理 |
| ✅ 首次保存正式需求 | { "version": null, "groups": [ … ] } |
| ❌ 改完不带版本 | 已有版本时传 version: null 或旧版本 → 809102 |
| ✅ 整团不用车 | POST …/vehicle-requirement/waive + { "reason": "原因" } |
| ❌ 整团不用车走空分组 | PUT …/vehicle-requirement + { "groups": [] }(本团有需要用车的户)→ 809103 |
| ✅ 整团确认 | POST …/requirement/confirm,无请求体 |
| ❌ 用批量打回处理接送机 | POST …/requirement/reject 的 VEHICLE 只覆盖 TRAVEL,只有接送机的户报 589534 |
切换状态时的必要动作
弹窗底部三种提交模式与调用顺序(按顺序串行调用,任一步失败就停下、提示错误、重拉页签数据;已成功的逐户打回不回滚):
| 模式 | 触发条件 | 按钮文案 | 调用顺序 |
|---|---|---|---|
| 一 | 三步里没有任何「打回」 | 确认需求并下发 | ① 弹窗③改过分组或还没有正式需求 → PUT vehicle-requirement;选了整团不用车 → waive(二选一,都不需要就跳过)→ ② POST requirement/confirm → ③ 对账补放行(见下) |
| 二 | 只有弹窗②(接送机)有打回 | 打回 N 户并确认其余 | ① 逐户 vehicle-requirement/reject?kind=TRANSFER → ② 同模式一的 PUT / waive → ③ POST requirement/confirm → ④ 对账补放行 |
| 三 | 弹窗①(住房)或弹窗③(行程用车)有任一打回 | 打回 N 项 | 逐户 hotel-requirement/reject、vehicle-requirement/reject?kind=TRAVEL,弹窗②的接送机打回(kind=TRANSFER)一并提交;不调 confirm |
- 打回一律排在 confirm 之前:逐户打回会清团级确认标记,排在后面会把刚写上的确认清掉。
- 模式三不调 confirm 的原因:住房打回后该户算缺失(589533),行程用车打回后该户缺行程用车(809122),确认必失败。
- 模式三不提交弹窗③的分组编辑:打回行程用车后 PUT 会被 809123 挡住。要保留分组编辑,让用户先点「仅保存草稿」(PUT)再提交打回;弹窗里要提示这一点。
- 有打回项没填原因时禁用提交按钮(
returnRemark必填、≤500)。免车原因同理(必填、≤200)。 - N 的口径:模式二的 N = 接送机打回户数;模式三的 N = 三步打回行数合计(同一户打了住房和行程用车算 2 项)。
对账补放行(模式一、模式二 confirm 成功后必做):
- 取弹窗②里判为「通过」、且该行
status = PENDING_REVIEW的户,记为 A。 - 从 A 里去掉
confirm响应transferDispatchedOrderIds里已有的户,剩下的记为 B。 - B 非空 →
POST requirement/transfer/batch-confirm,orderIds = B;看failedCount,失败户逐条提示。 - 会出现 B 非空的两种情况:整团免车(confirm 一条车需求都不放行);该户
needs_vehicle≠1(不在放行集合)。
已确认态(requirementConfirmed=true)的「审核变更(N)」:
- N = 住房与车侧所有
status = PENDING_REVIEW的行数。 - 只提供「通过」:住房 → 第 15 节逐户下发;接送机 → 第 16 节
kind=TRANSFER或第 17 节批量;行程用车 → 第 16 节kind=TRAVEL。 - 「打回」只在
batchStatus = RESOURCE_PREPARING时显示;按源码,这个阶段有户改需求会自动清确认标记、页签回到待确认态,所以已确认态下「打回」实际不会出现。
主按钮可用性:
batchStatus ≠ RESOURCE_PREPARING且未确认:确认与打回都会 589501,主按钮置灰并显示batchStatusName。- 预检 589507(无 demand:confirm 权限):隐藏主按钮、只读展示。
- 预检
ready=false但阶段正确:主按钮仍可点(用户要进弹窗去打回),弹窗里模式一 / 模式二的提交按钮按missing + vehicleMissing条数给出missingText并禁用。
原「更多」菜单里三项能力的去处:
- 整团免车(waive)→ 弹窗③「整团不用车」。
- 撤回(withdraw)→ 前端自定入口,仅
status ∈ {CONFIRMED, DISPATCHED}时显示;已免车改有车、已确认改分组都必须先撤回。 - 受控重开(
POST …/vehicle-requirement/reopen,封装reopenGroupVehicleRequirement,orderV2GroupBatch.js:889)→ 前端自定入口,契约不变。
字段来源与前端算法(设计 A 页签主体):
| 展示元素 | 来源 / 算法 |
|---|---|
| 页头 N 户 N 人 | 详情 subOrderCount / enrolledPeople |
| 状态条「需求待确认 / 需求已确认」 | 详情 requirementConfirmed |
| 状态条「N 户已全部提交」 | 汇总 hotelSubmittedOrderCount == hotelNeededOrderCount 且 用车逐户 countedHouseholdCount == householdCount |
| 状态条「预检通过,可以确认」 | 预检 ready;为 false 时显示 missing.length + vehicleMissing.length 条未就绪 |
| 已确认态「时间 由 某人 确认」 | 状态流水最后一条 BATCH_REQUIREMENT_CONFIRM 的 changedAt / operatorName(未实测) |
| 已确认态「审核变更(N)」列表 | 状态条下方逐行列出 status = PENDING_REVIEW 的行:customerName + 行的 kindName(住房行写「住房」)+ 该行内容;每行一个「通过」,右上「全部通过(N)」。接口不区分新报与修改,界面不写「新报 / 改了」 |
| 已确认态「N 户已下发房务」 | 住房逐户 status ∈ {PENDING, PROCESSING, DONE} 的户数 |
| 已确认态「N 户已下发车务」(接送机) | 用车逐户 TRANSFER 行 status ∈ {PENDING, PROCESSING, DONE} 的户数 |
| 已确认态「正式需求已确认 N 组」 | 正式需求 status + groups.length |
| 住房卡「待审核 N」 | 住房逐户 status = PENDING_REVIEW 的户数 |
| 住房卡「间/晚(峰值)」 | 每晚 dailyRoomBreakdown[].rooms[].totalRoomCount 求和,取各晚最大值 |
| 住房卡「N 晚」 | endDate − departDate(天数差),不用 dailyRoomBreakdown.length |
| 住房卡「间夜」 | 全部晚的 totalRoomCount 总和 |
| 住房卡「N 家酒店」 | dailyRoomBreakdown[].hotels[].hotelId 去重计数 |
| 住房卡「N 晚有 N 户客户自订」 | 住房逐户 days[].customerSelfBooked=true:按 stayDate 去重得晚数,按 orderId 去重得户数 |
| 住房卡「N/N 户已提交」 | 汇总 hotelSubmittedOrderCount / hotelNeededOrderCount |
| 住房卡「N 户有特殊需求」 | 汇总 orderSpecialTags 中 requirementType=HOTEL 的 orderId 去重计数 |
| 接送机卡「待审核 N」 | 用车逐户 TRANSFER 行 status = PENDING_REVIEW 的户数 |
| 接送机卡「N 户 · N 人」 | transferSummary.householdCount / headcount |
| 接送机卡「接机 N 户 N 人 · 送机 N 户 N 人」 | 户数用 pickupHouseholdCount / dropoffHouseholdCount;人数 = 用车逐户 TRANSFER 行按 pickupRequired=true / dropoffRequired=true 分别对 headcount 求和;日期不配方向(见缺口) |
| 接送机卡车型 | transferSummary.vehicleSeatSummary[] → {vehicleTypeName} {seats}座 ×{count} |
| 行程用车卡「正式需求 · 草稿」 | 正式需求 status 映射中文(六.5);data=null 显示「未形成正式需求」;CONFIRMED 且 groups 为空显示「整团不用车」 |
| 行程用车卡「N 组 · 逐日覆盖 x/y 天」 | N = groups.length;x = groups[].days[].tripDate 去重后落在 departDate..endDate 内的天数;y = endDate − departDate + 1 |
| 行程用车卡车型(日期) | groups[] → {vehicleTypeName} {seats}座 ×{count}({serviceStartDate}–{serviceEndDate}) |
| 行程用车卡「N/N 户已报」 | 用车逐户 countedHouseholdCount / householdCount |
| 大交通声明提示 | 预检 transferDeclaredWithoutRequirement[]:customerName + 声明了接机(pickupRequired)/ 送机(dropoffRequired)+ 定制师 consultantName;「联系定制师」→ emit('contact', orderId) |
| 逐晚用房表 晚次 / 日期 | 以 departDate..endDate−1 逐晚生成行,按 stayDate 关联 dailyRoomBreakdown;没有条目的晚在备注列标「全团客户自订」或「无已提交需求」(用住房逐户 customerSelfBooked 区分) |
| 逐晚用房表 城市 · 酒店 | hotels[].hotelName;城市按 hotelId 关联住房逐户 days[].hotels[].city |
| 逐晚用房表 房型列 | 按数据里出现的 roomCategory 动态生成列,列头用 roomCategoryName;设计稿里的「标间 / 大床 / 亲子 / 家庭」四列只是示意,实测数据里出现的是 DELUXE / KING / STANDARD |
| 逐晚用房表 合计 / 间夜合计 | 行合计 = 该晚 rooms[].totalRoomCount 之和;末行按列求和 |
| 用车安排 行程用车矩阵 | 行 = groups[](groupCode + 车型);列 = departDate..endDate;格 = 该组该日 days[].headcount,无则空 |
| 用车安排「在团人数」 | 详情 enrolledPeople |
| 用车安排 接送机 | 按方向分两行:接机行取用车逐户 TRANSFER 行里 pickupRequired=true 的户,送机行取 dropoffRequired=true 的户;每行列客户名、人数(headcount 求和)、车型(按 fleet 计数)。标题旁单列服务日期 transferSummary.serviceDates,不与方向配对 |
| 逐户表 数据集 | 住房逐户 ∪ 用车逐户,按 orderId 合并 |
| 逐户表 筛选「全部」 | 合并后户数 |
| 逐户表 筛选「待审核」 | 住房 status 或任一车侧行 status 为 PENDING_REVIEW 的户 |
| 逐户表 筛选「已打回」 | 住房 status 为 REJECTED_TO_CONSULTANT / REJECTED_TO_ADMIN 的户(车侧见缺口) |
| 逐户表 筛选「未提交」 | 住房 status=null 或 用车逐户户级 status=null 的户 |
| 逐户表 筛选「有特殊需求」 | 住房 specialTags 非空 或 任一车侧行 specialTags 非空 |
| 逐户表 搜索 | 前端本地过滤 customerName / teamNo / orderNo / consultantName |
| 逐户表 户 / 人数 / 定制师 | customerName(副行 teamNo,null 显示 —)/ participantCount / consultantName |
| 逐户表 住房 | days[].hotels[].hotelName 去重拼接;副行 晚数与房数合计 |
| 逐户表 接送机 | TRANSFER 行:接 / 送标记 + serviceDates + fleet;无 TRANSFER 行且在 transferDeclaredWithoutRequirement 里 →「未报 · 大交通声明了接机 / 送机」;不在用车逐户列表里 →「不需要」;其余 → — |
| 逐户表 行程用车 | TRAVEL 行 fleet + serviceDates;不在用车逐户列表里 →「不需要」 |
| 逐户表 特殊需求 | 住房 specialTags ∪ 车侧 specialTags[].name |
| 逐户表 备注 | 住房 remark 与车侧 remark 分行显示 |
| 逐户表 状态 | 住房与车侧各显示 statusName 原文;户级徽标按「已打回 > 待审核 > 未提交 > 已下发」取最高 |
| 逐户表 详情 | 打开保留的 HouseholdRequirementModal |
| 逐户表 联系定制师 | emit('contact', orderId) → index.vue:705 |
字段来源与前端算法(设计 B 审核弹窗):
| 弹窗元素 | 来源 / 算法 |
|---|---|
| 步骤条 ①住房 ②接送机 ③行程用车 | 各步待审行数与已打回数由前端统计 |
| ① 逐户列表 | 住房逐户 households[];status ∈ {PENDING_REVIEW, PENDING} 的户可选「通过 / 打回」,其余只读 |
| ①「全部重置为通过」 | 前端清空本步所有打回标记与原因 |
| ①「本次下发」 | 本步判为通过且 status=PENDING_REVIEW 的户,按 days[].hotels[].rooms[].roomCount 求和得间夜 |
| ② 逐户列表 | 用车逐户 TRANSFER 行:接机 pickupRequired / 送机 dropoffRequired / 人数 headcount / 车型 fleet / specialTags / remark |
| ② 大交通声明提示 | 预检 transferDeclaredWithoutRequirement[] |
| ③ 正式需求编辑区 | 有正式需求用第 7 节 groups;没有或点「按户需求重新汇总」用第 8 节 draft;violations 逐条标在对应组 / 日期旁 |
| ③「添加分组」 | 前端在 groups 里新增一组(groupId=null,groupCode 不可与已有组重复) |
③ 逐日覆盖 coverText |
同设计 A「逐日覆盖 x/y 天」 |
| ③「整团不用车」 | 第 10 节 waive(需填原因) |
| ③「仅保存草稿」 | 第 9 节 PUT,成功后用返回的 version 覆盖本地 |
| ③ 各户行程用车需求 | 用车逐户 TRAVEL 行;打回走第 14 节 kind=TRAVEL |
底部 missingText |
预检 missing[] 与 vehicleMissing[] 条数;reasonName / detail 逐条可展开 |
底部 submitLabel |
按上面三种模式切换 |
字段缺口(本期不展示):
| 设计稿元素 | 为什么没有 | 本期处理 |
|---|---|---|
| 户级变更前后差异(「第 4 晚加 1 间大床」)与「新报 / 修改」的区分 | 所有接口只返回当前版本,不返回上一版或差异 | 本期不展示,只列「某户 住房 / 接送机 / 行程用车 待审核」 |
| 接送机按日期拆方向(「10/03 接机 5 户 16 人 · 10/08 送机 5 户 16 人」) | serviceDates 不带方向,接口没有「哪一天是接机」 |
本期不展示日期与方向的配对;按方向显示户数与人数,日期单列 |
| 大交通声明的接送日期 | transferDeclaredWithoutRequirement 只有方向标记与 pickupRemark |
本期不展示日期 |
| 车侧「已打回」 | 车侧打回后该行失活,不再返回,与「未提交」读数相同 | 本期「已打回」筛选只覆盖住房侧 |
五、数据库行为(涉及写操作时必写)
本条后端零改动,下表只列前端各提交动作在后端产生的既有写入,供前端判断「失败时有没有部分写入」。
| 前端动作 | 后端写入 | 失败时 |
|---|---|---|
PUT vehicle-requirement |
正式用车需求新版本落为 DRAFT,version+1 |
零写入 |
waive |
正式用车需求置为 CONFIRMED 且无分组,记免车原因 |
零写入 |
withdraw |
正式用车需求回 DRAFT、version+1、原因追加进备注、清确认人与时间、复位团期 vehicleReady |
零写入 |
requirement/confirm |
团期 requirementConfirmed=true + 时间线 BATCH_REQUIREMENT_CONFIRM;住房待审行 → PENDING;正式需求 → CONFIRMED;车侧待审行 → PENDING(免车时后两项不做) |
同一事务,整团零写入 |
逐户 reject(住房 / 用车) |
该户该类需求行 → REJECTED_TO_CONSULTANT 并写打回原因;清团级 requirementConfirmed;时间线 BATCH_REQUIREMENT_REJECT |
该户零写入;此前已成功的其他户不回滚 |
逐户 dispatch(住房 / 用车) |
该户该类需求行 PENDING_REVIEW → PENDING,写下发备注,房控 / 车控置待处理 |
该户零写入 |
transfer/batch-confirm |
成功户的接送机行 → PENDING |
逐户独立,部分成功 |
六、边界行为
- 未登录 → 网关拦截,返回信封
code=401。 - 无团期权限 → 589507;只有
group-batch:view的角色能看汇总、逐户、详情、流水,看不了预检与正式用车需求(这两个要group-batch:demand:confirm),页签要能部分降级。 - 团期不存在 → 589500(状态流水除外,它返回空数组)。
- 团期阶段不是
RESOURCE_PREPARING→ 确认、逐户打回、保存正式需求都是 589501;逐户下发、接送机批量放行、撤回不受阶段限制。 - 同一团期两个人同时操作:确认与逐户打回共用团级锁;正式需求靠
version乐观锁(809102);各写接口有 5 秒(接送机批量 120 秒)幂等窗口,重复点击返回code=100502,前端提交期间锁按钮即可。 - 入参校验失败 → HTTP 200、
code=400,message为注解原文,多条用「; 」连接。 - 所有 ID(
groupBatchId、orderId、requirementId等)在 JSON 里是字符串,前端不要转 Number。
六.5、枚举 / 数据字典(接口出现枚举时必写)
batchStatus(com.hulalv.order.groupbatch.enums.GroupBatchStatus)
所属字段: GroupBatchDetailRespVO.batchStatus、GroupBatchRequirementCheckRespVO.batchStatus | 类型: String
| 值 | 中文 | 说明 |
|---|---|---|
RECRUITING |
招募中 | 确认 / 打回 589501 |
RESOURCE_PREPARING |
资源准备中 | 唯一可整团确认、可打回、可保存正式用车需求的阶段 |
MATERIAL_PREPARING |
物料准备中 | 确认 / 打回 589501 |
PENDING_DEPARTURE |
待出发 | 同上 |
TRAVELLING |
出行中 | 同上 |
TRIP_FINISHED |
出行完毕 | 同上;可免车 |
REVIEWING |
核单中 | 同上;可免车 |
SETTLED |
已结算 | 同上 |
CANCELLED |
已取消 | 同上;接送机批量放行也拒 |
status(com.hulalv.order.requirement.enums.RequirementStatus)
所属字段: 住房逐户 households[].status、用车逐户 households[].status 与 requirements[].status | 类型: String
| 值 | 中文 | 说明 |
|---|---|---|
PENDING_REVIEW |
待审核 | 定制师已提交、团期管理员未放行;车侧 TRAVEL 的 statusName 显示「待提交车务」 |
PENDING |
待房务配 | 已放行;车侧 statusName 以接口返回为准 |
PROCESSING |
配房中 | 房务 / 车务处理中 |
DONE |
配房完成 | 处理完成 |
REJECTED_TO_CONSULTANT |
驳回 | 已打回定制师;只在住房逐户出现,车侧打回行不返回 |
REJECTED_TO_ADMIN |
驳回 | 被下游驳回到团期管理员 |
null |
— | 该户一条都没提交 |
显示一律用接口返回的 statusName,不要用本表中文自行翻译(车侧与住房侧同一状态的中文不同)。
kind(com.hulalv.order.requirement.enums.VehicleRequirementKind)
所属字段: 用车逐户 requirements[].kind;逐户打回 / 下发的 Query kind | 类型: String
| 值 | 中文 | 说明 |
|---|---|---|
TRAVEL |
行程用车 | Query 不传时的默认值 |
TRANSFER |
接送机 | 必须显式传 |
status(com.hulalv.order.groupbatch.enums.GroupVehicleRequirementStatus)
所属字段: GroupVehicleRequirementRespVO.status、预检 groupVehicleRequirementStatus、确认响应 groupVehicleRequirementStatus | 类型: String
| 值 | 中文 | 说明 |
|---|---|---|
DRAFT |
草稿 | 可 PUT;确认时推到 CONFIRMED |
CONFIRMED |
已确认 | groups 为空即整团免车;改分组须先撤回 |
DISPATCHED |
已发车务 | 改分组须先撤回 |
DONE |
配车完成 | — |
PENDING_RECONFIRM |
待重新确认 | 受控重开链路;确认时推到 CONFIRMED |
CANCELLED |
已取消 | 流团时关闭并失活,之后取正式用车需求读不到(data 为 null) |
missing[].reason(GroupBatchRequirementCheckRespVO.MissingItem)
所属字段: 预检 missing[].reason(中文见同行 reasonName) | 类型: String
| 值 | 中文 | 说明 |
|---|---|---|
NOT_SUBMITTED |
未提报 | 该户需要住房但没有有效住房需求(含被打回后未重提) |
ROOM_CATEGORY_MISSING |
缺房型或房数 | 某晚某段缺房型大类或房数小于 1,附 dayNumber / segmentIndex |
INVALID_REQUIREMENT |
需求结构异常 | 逐晚数据为空或结构不完整 |
NIGHTS_MISMATCH |
住宿晚数对不上 | 附 expectedNights / actualNights |
DAY_NUMBER_INVALID |
晚序号异常 | 晚序号跳号、重复或越界,附 expectedNights / actualNights |
vehicleMissing[].reason(GroupBatchRequirementCheckRespVO)
所属字段: 预检 vehicleMissing[].reason(无中文名字段,展示用 detail) | 类型: String
| 值 | 中文 | 说明 |
|---|---|---|
GROUP_REQUIREMENT_NOT_FOUND |
未形成正式需求 | 对应 809100;处置:弹窗③汇总后保存,或整团不用车 |
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,处置是催定制师提交 |
MEMBER_GROUP_MISMATCH |
户车型与分组车型不符 | 对应 809125,处置是重新汇总并保存 |
TRANSFER_SERVICE_DATES_NOT_BACKFILLED |
接送机服务日期未回填 | 对应 809007,只带 orderId |
TRANSFER_WINDOW_INCOMPLETE |
接送机窗没盖住大交通日期 | 对应 809126,带 tripDate,处置是让定制师重新提交接送机需求 |
GROUP_SPEC_INCOMPLETE |
座位数与车辆数没同填 | 对应 809118(源码常量 GroupVehicleRequirementService.java:229,VO 注释未列) |
GROUP_SEATS_INSUFFICIENT |
座位不够 | 对应 809116(同上 :232) |
GROUP_SEATS_NOT_IN_OPTIONS |
座位不在可选档位 | 对应 809124(同上 :235) |
GROUP_SEAT_OPTIONS_UNAVAILABLE |
档位读取失败 | 复用 809120 语义(同上 :238) |
上表「中文」列是本条给的说明性译名,接口不返回;遇到表外的值按 detail 原文展示。
eventType(com.hulalv.order.groupbatch.enums.GroupBatchLogEventType,本页只用三个)
所属字段: GroupBatchStatusLogItemVO.eventType | 类型: String
| 值 | 中文 | 说明 |
|---|---|---|
BATCH_REQUIREMENT_CONFIRM |
需求整体确认 | 已确认态「时间 由 某人 确认」取最后一条 |
BATCH_REQUIREMENT_REJECT |
需求打回 | 批量或逐户打回;逐户时 extra 只含本户 orderId |
BATCH_REQUIREMENT_REOPENED |
需求重开待确认 | 有户改需求或转团,后端自动清确认标记 |
六.6、修改前后对比(修改/删除类接口必写,新增跳过)
字段级对比
| 字段 | 改前 | 改后 |
|---|---|---|
| 所有接口的请求与响应字段 | 不变 | 不变(后端零改动) |
vehicle-households 的 kind 调法 |
父组件按 TRAVEL / TRANSFER 分两次取 |
可不传 kind 一次取两类,按 requirements[].kind 拆;分两次取仍然有效 |
行为级对比
| 行为 | 改前 | 改后 |
|---|---|---|
| 打回 | 顶部「打回选中户」→ 批量打回端点,整批一条原因,接送机打不了 | 弹窗内逐户逐类打回,每户各自原因,接送机 kind=TRANSFER |
| 整团确认 | 顶部「整团确认需求」直接 confirm | 弹窗底部按三种模式串行调用,确认后对账补放行接送机 |
| 正式行程用车需求 | 「新增正式行程用车需求」按钮 + 独立编辑弹窗 | 收进弹窗③,确认前按需 PUT |
| 免车 / 撤回 / 重开 | 「更多」菜单 | 免车进弹窗③;撤回与重开入口前端自定 |
| 接送机放行 | 用车逐户块勾选 + 批量放行按钮 | 首次确认随 confirm 放行并对账补放行;已确认态走「审核变更」 |
| 已确认后的待审行 | 可在逐户块逐条下发 | 「审核变更(N)」只提供通过 |
六.7、影响评估(修改/删除类必写)
- 是否破坏向后兼容: 否(后端零改动,旧页签照常可用)
- 前端是否必须同步发版: 否
- 前端 workaround 清理点:
RequirementRejectModal.vue及批量打回封装rejectGroupBatchRequirement的调用点(orderV2GroupBatch.js:679,封装本身可留);RequirementTab.vue:53 / :68 / :77 / :86四个按钮与:588整团确认对话框;VehicleHouseholdsSection.vue的勾选与批量放行按钮(并入弹窗②与审核变更)
七、不影响范围(显式声明, 帮前端/QA 缩小排查面)
- 仅影响: 出团详情「查看需求」页签及其子组件
- 零影响:
- 后端全部接口与数据(零改动)
- 出团详情其他页签(整团总览、子订单、配房明细、行程、用餐、操作记录等)
- 定制师侧提交住房 / 用车 / 接送机需求的页面
- 房务、车务侧的工作台
HouseholdRequirementModal(保留原样,只是改由逐户表「详情」打开)
八、测试环境已验证
测试服网关实测,带 ✓ 的为本条示例所用原文:
GET /v3/admin/order/group-batch/2100856430494973953/requirement-summary → 200 + 两晚逐晚用房 + 接送机汇总 ✓(2026-09-29 16:38)
GET /v3/admin/order/group-batch/2100856430494973953/requirement/vehicle-households → 200 + 2 户 4 行(不传 kind 两类同返)✓(2026-09-29 16:38)
POST /v3/admin/order/1/vehicle-requirement/dispatch?kind=TRANSFER → 581007 订单不存在(错误信封形态)✓(2026-09-29 16:38)
GET /v3/admin/order/group-batch/2104327837991518210/requirement/confirm-check → 200 + vehicleWaived=true + ready=true ✓(2026-09-27)
验证团期: groupBatchId=2100856430494973953(2 户,出发 2026-10-08,资源准备中);免车团期 groupBatchId=2104327837991518210。
其余接口的示例按 VO 结构组装、取值为示意,已在各节示例上方逐一标注;「确认人取自状态流水」「打回接送机不挡确认」两条是按源码推理,未在测试服实测,同样已在对应小节标注。
十、相关文档
- 设计稿: 「设计稿」https://claude.ai/artifact/R2b6RsiUvykdF9kBUdaQcC
- 同日既有条目:
changelogs-v2/2026-09/29_frontend_团期详情用车汇总行程用车与接送机改逐条列出-前端优化-管理后台.md - 同日既有条目:
changelogs-v2/2026-09/29_frontend_团期详情用车需求确认弹窗点确认不发请求-前端缺陷-管理后台.md - 后端源码(
origin/dev-v3@7b702f5c,hl-order-service-v3):GroupBatchRequirementController.java、GroupBatchQueryController.java、HotelRequirementAdminController.java、VehicleRequirementAdminController.java、GroupBatchRequirementService.java、GroupVehicleRequirementService.java、GroupBatchService.java - 前端源码(hl-ui
origin/v2.1@cdfaf793):src/views/order-v2/batch/detail/components/、src/api/orderV2GroupBatch.js、src/api/orderV2.js
关联 / 联系人
链接
- Issue: 无(ticket=frontend)
- PR: 无(后端零改动)
- 前端提交: 前端完成后填入 frontmatter
frontend_ref