文件
hl-api-changelog/changelogs-v2/2026-09/29_frontend_团期详情查看需求页签重做为一键审核弹窗-前端优化-管理后台.md
T
API Changelog Bot和Claude Opus 5.5 14a332f2cb
changelog-filename-gate / validate (push) Failing after 2s
docs(changelog-v2): 团期详情查看需求页签重做为一键审核弹窗 前端交接(frontend)
查看需求页签改为「状态条 + 三张卡 + 一键审核弹窗」,弹窗一次完成住房审批、
接送机审批、正式行程用车需求提交;后端零改动,列出 17 个既有接口的调用方式、
三种提交模式的调用顺序、确认后接送机对账补放行、已确认态只可通过,以及 4 项
本期不展示的字段缺口。

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-29 22:33:46 +08:00

104 KiB
原始文件 Blame 文件历史

schema, ticket, title, consumer, author, change_type, backend_status, gateway_status, frontend_status, frontend_owner, frontend_ref, target_release, verified_at, status_note, updated_at, base
schema ticket title consumer author change_type backend_status gateway_status frontend_status frontend_owner frontend_ref target_release verified_at status_note updated_at base
hl-changelog/v2 frontend 团期详情「查看需求」页签重做为一键审核弹窗:页签改只读总览加唯一主按钮,审核打回确认收进三步弹窗,全部调用既有接口,后端零改动 admin wx(GIT) 前端优化 not_required not_required pending 后端零改动,17 个既有接口;三种提交模式的调用顺序、确认后接送机对账补放行、已确认态只可通过不可打回见正文四;4 项字段缺口本期不展示 2026-09-29 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-ui origin/v2.1@cdfaf793


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

  • 页面结构变了:原来是「汇总块 + 逐户块 + 正式用车需求块」平铺,顶部四个按钮;新设计是只读总览(状态条 + 三张汇总卡 + 逐晚用房 + 用车安排 + 逐户需求)加唯一主按钮「审核并确认需求」,点开是三步审核弹窗(①住房 ②接送机 ③行程用车)。
  • 取消的按钮:「打回选中户」「新增正式行程用车需求」「更多」「整团确认需求」(RequirementTab.vue:53 / :68 / :77 / :86)。取消的只是按钮,能力不取消:整团免车(waive)进弹窗③「整团不用车」;撤回(withdraw)与受控重开(reopen)仍须保留入口,位置前端自定(见四)。
  • 四处以前容易想错的地方(均已对源码核实):
    1. 确认后不能逐户打回。需求已确认之后还能出现「待审核」行的,只有团期过了资源准备阶段后的接送机变更;这时团期阶段不是 RESOURCE_PREPARING,逐户打回报 589501。所以已确认态的「审核变更」只有「通过」没有「打回」。
    2. 整团确认不一定放行全部接送机。整团免车时一条车需求都不放行(含待审接送机);needs_vehicle≠1 的户报了接送机也不在放行集合里。确认成功后必须用响应里的 transferDispatchedOrderIds 对账,没放行的另调 transfer/batch-confirm。
    3. 批量打回端点不覆盖接送机。POST …/requirement/reject 的 VEHICLE 只打回行程用车,且整批只收一条原因;新设计每户各有原因、要分 kind 打回,不用它,改逐户打回。
    4. 逐户打回(任何 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:2629 reopenRequirementConfirmation)。页面不要缓存这个值做判断,每次进入页签与每次弹窗提交后都以最新详情为准。

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 / PENDING 582083 → 并发改动 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 / PENDING 582083 → 并发改动 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_REVIEW 582083 → 并发更新失败 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_REVIEW 582083 → 接送机服务日期未回填 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 成功后必做):

  1. 取弹窗②里判为「通过」、且该行 status = PENDING_REVIEW 的户,记为 A。
  2. 从 A 里去掉 confirm 响应 transferDispatchedOrderIds 里已有的户,剩下的记为 B。
  3. B 非空 → POST requirement/transfer/batch-confirm,orderIds = B;看 failedCount,失败户逐条提示。
  4. 会出现 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

联系人

  • 后端负责人: @wx
  • 前端负责人: @mmg