文件
hl-api-changelog/changelogs-v2/2026-09/12_7535_团期接口返回值整改非破坏批-修改接口-管理后台.md
Mimingguang 10502ccdd3
changelog-filename-gate / validate (push) Failing after 2s
chore(changelog): 补回写漏网 8 条(7510×2/7511/7512 verified+not_required;7513/7530/7531/7535 not_required)
7510/7511/7512 代码早已随供应商关系系列交付(a17a2c2a/4bedc8be),实证后回写 verified 挂 a17a2c2a;
11_7510 为正本 12_7510 的重复副本(canonical_path),标 not_required 消除 pending;
7513/7530/7531/7535 实证前端零改动 not_required。
2026-09-13 09:51:52 +08:00

1983 行
88 KiB
Markdown

此文件含有模棱两可的 Unicode 字符
此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。
---
schema: "hl-changelog/v2"
ticket: "7535"
title: "团期接口返回值整改·非破坏批(opsStage / 负责人 / 报账人 / 审批行补全 / 枚举中文配对 / 命名统一)"
consumer: "admin"
author: "jw(GIT)"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "not_required"
frontend_status: "not_required"
frontend_owner: "mmg"
frontend_ref: ""
target_release: ""
verified_at: "2026-09-12"
status_note: "19 个团期读端点纯加响应字段,既有 key 的名称/类型/取值/null 语义一行未动,前端零改动即可继续运行。零 DDL、零错误码、零网关改动。四组旧字段已标 @Deprecated 但本批不删,请新代码逐步切到新名。 前端 2026-09-13 闭环 not_required:前端无严格 schema 校验多余 key 静默忽略,五组 @Deprecated 旧字段本批仍返回不 break,改读新名为非强制改进项本批不动。零业务代码改动。"
updated_at: "2026-09-13"
base: "dev-v3"
---
# order-v3: 团期接口返回值整改·非破坏批
**服务**: hl-order-service-v3
**PR**: #7583
**Issue**: #7535
---
## ⚠️ 关键变化
🟢 **本批纯加字段,前端零改动即可继续运行。** 19 个端点只多出响应 key,**既有 key 的名称、类型、取值与 null 语义一行没动**。新字段按需取用。
🔴 **`opsStage` 以后端八桶为准,原型侧的 stage 取值需要改**(wx 2026-09-11 定案)。后端八值:
`RECRUIT` 招募中 / `FORMED` 已成团 / `PENDING_TRIP` 待出行 / `TRAVELLING` 出行中 /
`TRIP_FINISHED` 出行完毕 / `AUDITING` 核团中 / `CHECKED` 已验团 / `DISBANDED` 已流团。
**`FORMED` 是复合桶**(`RESOURCE_PREPARING` + `MATERIAL_PREPARING` 两个九态都落它)。
**前端不要再自己复刻九态 → 八桶的折叠逻辑,直接读 `opsStage`。**
🔴 **四个 `Text` / `Label` 后缀字段已标 `@Deprecated`**,本批**不删**、值不变,请新代码改用同值的 `Name` 字段,删除时间另行通知:
| 旧字段(仍返回) | 新字段(同值) | 所在响应 |
|---|---|---|
| `batchStatusLabel` | `batchStatusName` | 团期看板行 |
| `productBatchStatusLabel` | `productBatchStatusName` | 团期分页项 |
| `statusText` | `statusName` | 芯片逐户行 |
| `bizTypeText` | `bizTypeName` | 审批中心统一列表行 |
🔴 **审批中心统一列表的 `orderNo` / `customerName` / `departDate` 只在 `bizType=WITHDRAW` 行有值**,`DISBAND` 行恒 `null`(与已有的 `orderId` 同一条规则)。前端**按行类型判断再渲染**,否则 DISBAND 行会出现三个空列。
🔴 **`checkedResourceTypes` 恒 `["HOTEL"]`**:需求确认预检**只检查住宿、不检查用车**,`ready=true` **不代表**用车需求齐备。
🔴 **联系人 key 统一为 `customerName`**:芯片逐户 / 合同逐户 / 行程汇总预警行 / 行程下钻逐户**四处**新增 `customerName`,与既有 `contactName` **逐字同值**;`contactName` 已标 `@Deprecated`,本期仍返回、**计划下一期删除**。
报名清单「联系人」列显示 `—` 是**前端读错 key**(后端一直给的是客户姓名),请改读 `customerName`。
🔴 **团期主键 key 统一为 `groupBatchId`**:名额调整 / 芯片详情 / 合同面板三处响应新增 `groupBatchId`,与既有 `batchId` **逐字同值、同为字符串形态**;`batchId` 已标 `@Deprecated`。
staff 的 `PUT .../staff` 与 `GET .../staff/candidates` 响应新增 `productBatchId` + `groupBatchId`——
⚠️ **候选端点的 `groupBatchId` 在团期尚未创建时为 `null`**(staff 允许在成团前先配,该端点**不报错**),前端**不得**把它当必有主键去拼请求,否则会打出 `/group-batch/null/...`。
`GET .../staff` 返回**裸数组、没有顶层信封**,因此**不带**这两个 ID。
🔴 **芯片逐户行与合同逐户行新增 `teamNo`**(纯加)。⚠️ **逐行各不相同**,不是页头那一个团期编号的重复;⚠️ **订金支付成功后才生成,未付订金的户是 `null`**(与是不是团期订单无关)。后端**不做任何兜底**——不返空串、不回退成订单号、不拿团期编号顶替,前端请按 `null` 渲染「—」。
另:「报名清单 / 财务 / 预支」三张表的同名字段由**破坏批那张单(#7536)**交付,两批的字段名、类型与 null 语义完全一致,前端可按同一套逻辑渲染。
🔴 **应收 / 已收 / 待收命名统一**:团期详情新增 `receivableAmount` / `receivedAmount`(与既有 `totalReceivable` / `totalReceived` 同值,旧名已 `@Deprecated`、计划下一期删除);团期分页项新增 `unpaidAmount` = `max(0, 应收 − 已收)`,**恒非负、恒非 null**。⚠️ 与财务 tab 的同名字段**同名不同源**,权威待收值仍以财务 tab 为准。财务 tab 那 12 个金额字段的 JSON 形态**本批不变**,其变更由另一张单交接。
🔴 **芯片逐户新增房务负责人三件套** `claimerId` / `claimerName` / `claimerSource`,**六个芯片端点统一给**。
`claimerSource` 取值 `BATCH`(团级指针)/ `LEGACY`(历史旧户的户级归属)/ `null`(真实无人认领,此时另两个字段也为 `null`)——让前端不必猜这个名字是团级还是户级。
🔴 **十个裸 code 字段补齐了中文配对**,统一兜底口径:**code 为 `null` → `Name` 为 `null`;code 翻不出 → `Name` 回落原 code**(不抛异常、不返空串)。
---
## 一、背景
团期模块的响应体长期存在四类不一致,都是前端一眼能看见、但后端没人系统清过的:
1. **八桶只能筛、不能读**:`GET /v3/admin/order/group-batch` 的**入参**早就支持按八桶 `opsStage` 筛选,**出参却没有这个字段**——前端只能拿九态 `batchStatus` 自己再折一遍桶,折叠规则一分叉就和服务端筛选结果对不上。
2. **中文名后缀三套并存**:同一个 `batchStatus` 在分页项叫 `batchStatusName`、在看板行叫 `batchStatusLabel`;芯片叫 `statusText`、审批叫 `bizTypeText`。同时还有 10 个裸 code 字段根本没有中文配对,前端只能自己维护映射表。
3. **同义字段各叫各的**:联系人在团期域 4 个 VO 里叫 `contactName`、在其余 8 个 VO 里叫 `customerName`;团期主键在 3 个 VO 里叫 `batchId`、其余一律 `groupBatchId`;整团应收/已收在三个端点有三套名字。
4. **该有的字段缺位**:芯片逐户看不到房务负责人、逐户行看不到团号、审批中心统一列表的退单户行看不到订单号与客户姓名、staff 名册看不到报账人等级、预检响应不告诉前端它到底检查了什么。
本单**只加不改**:19 个端点新增 47 个响应 key,旧字段一律同值保留并打 `@Deprecated`(本批不删)。
**路径、方法、请求参数、既有字段的名称/类型/取值/null 语义一律不变**,向后兼容纯增。
---
## 二、变更接口清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|------|------|------|----------|------|
| 1 | 团期分页列表(A1) | GET | `/v3/admin/order/group-batch` | 修改 | 响应行新增 `opsStage` / `opsStageName` / `unpaidAmount` / `productBatchStatusName` |
| 2 | 团期看板 | GET | `/v3/admin/order/group-batch/board` | 修改 | 响应行新增 `opsStage` / `opsStageName` / `batchStatusName` |
| 3 | 团期详情(A2) | GET | `/v3/admin/order/group-batch/{groupBatchId}` | 修改 | 新增 `opsStage` / `opsStageName` / `receivableAmount` / `receivedAmount` / `thresholdSourceName` |
| 4 | 团期配房逐户明细 | GET | `/v3/admin/order/group-batch/{groupBatchId}/chips/hotel` | 修改 | 信封 +2、逐户 +6 |
| 5 | 团期配车逐户明细 | GET | `/v3/admin/order/group-batch/{groupBatchId}/chips/vehicle` | 修改 | 同上 |
| 6 | 团期配导游逐户明细 | GET | `/v3/admin/order/group-batch/{groupBatchId}/chips/guide` | 修改 | 同上 |
| 7 | 团期配摄影逐户明细 | GET | `/v3/admin/order/group-batch/{groupBatchId}/chips/photo` | 修改 | 同上 |
| 8 | 团期合同逐户明细 | GET | `/v3/admin/order/group-batch/{groupBatchId}/chips/contract` | 修改 | 同上 |
| 9 | 团期保险逐户明细 | GET | `/v3/admin/order/group-batch/{groupBatchId}/chips/insurance` | 修改 | 同上 |
| 10 | 团期「合同保险」面板 | GET | `/v3/admin/order/group-batch/{groupBatchId}/contracts` | 修改 | 信封 +1、逐户 +2 |
| 11 | 团期行程逐日汇总 | GET | `/v3/admin/order/group-batch/{groupBatchId}/itinerary` | 修改 | 天数预警行新增 `customerName` |
| 12 | 团期行程某项逐户下钻 | GET | `/v3/admin/order/group-batch/{groupBatchId}/itinerary/nodes/{nodeKey}` | 修改 | 逐户行新增 `customerName` |
| 13 | 审批中心统一列表 | GET | `/v3/admin/order/group-batch/approvals/page` | 修改 | 新增 `orderNo` / `customerName` / `departDate` / `approvalStatusName` / `bizTypeName` |
| 14 | 退单审批列表 | GET | `/v3/admin/order/group-batch/withdraw/page` | 修改 | 新增 `refundModeName` / `approvalStatusName` |
| 15 | 整团确认需求缺失预检 | GET | `/v3/admin/order/group-batch/{groupBatchId}/requirement/confirm-check` | 修改 | 外层 +2、缺失项 +2 |
| 16 | 调整团期满团名额 | PUT | `/v3/admin/order/group-batch/{groupBatchId}/capacity` | 修改 | 新增 `groupBatchId` |
| 17 | 团期人员配置列表 | GET | `/v3/admin/group-batch/{productBatchId}/staff` | 修改 | 每行新增 `staffRoleName` / `reporterRank` / `reporterRankName` |
| 18 | 团期人员配置全量保存 | PUT | `/v3/admin/group-batch/{productBatchId}/staff` | 修改 | 顶层 +2、每行 +3 |
| 19 | 团期人员配置候选列表 | GET | `/v3/admin/group-batch/{productBatchId}/staff/candidates` | 修改 | 每项新增 6 个 key |
---
## 三、接口详情
### 1. 团期分页列表(A1) `GET /v3/admin/order/group-batch`
**VO**: `PageResult<GroupBatchPageItemRespVO>`
#### 使用场景
团期看板的分页列表。**本单起每行多出 4 个 key**:运营八桶 `opsStage`/`opsStageName`、整团待收 `unpaidAmount`、以及与 `productBatchStatusLabel` 同值的 `productBatchStatusName`。
#### 入参字段表
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|------|------|------|------|------|------|
| pageNo / pageSize / productId / scope / batchStatus / opsStage / month / keyword / deadlineFrom / deadlineTo | Query | — | — | 本单**一个入参都没改** | 含同名的**入参筛选** `opsStage`,取值集与新出参 `opsStage` 完全一致 |
#### 出参字段表
| 字段 | 类型 | 说明 |
|------|------|------|
| opsStage | String | **本单新增**。运营八桶:`RECRUIT` 招募中 / `FORMED` 已成团 / `PENDING_TRIP` 待出行 / `TRAVELLING` 出行中 / `TRIP_FINISHED` 出行完毕 / `AUDITING` 核团中 / `CHECKED` 已验团 / `DISBANDED` 已流团。由 `batchStatus` 九态折叠(`FORMED` 是复合桶 = `RESOURCE_PREPARING` + `MATERIAL_PREPARING`)。⚠️ `batchStatus` 为 `null` 或不在九态内(历史脏数据)时本字段为 `null` |
| opsStageName | String | **本单新增**。八桶中文名;与 `opsStage` **同生同灭**(一起为 `null`) |
| unpaidAmount | String | **本单新增**。整团待收 = `max(0, receivableAmount − receivedAmount)`,**恒非负、恒非 `null`**(两个被减数任一为 `null` 按 0 计;已收多于应收的历史脏数据返 `0`,不透负数)。JSON **字符串**形态。⚠️ 与财务 tab 的同名字段**同名不同源**,权威待收以财务 tab 为准 |
| productBatchStatusName | String | **本单新增**。与 `productBatchStatusLabel` **逐字同值同源**(产品域 Feign 给出,order 域不再映射一次) |
| productBatchStatusLabel | String | **值不变**,本单起标 `@Deprecated`,本批**不删**;新代码请改读 `productBatchStatusName` |
| (其余字段) | — | **全部不变**,本单不改动任何既有字段的名称、类型、取值与 null 语义 |
#### 请求示例
```http
GET /v3/admin/order/group-batch?pageNo=1&pageSize=20
Authorization: Bearer <admin token>
```
#### 响应示例
```json
{
"code": 200,
"message": "成功",
"data": {
"records": [
{
"groupBatchId": "2096412454643802114",
"batchStatus": "RESOURCE_PREPARING",
"batchStatusName": "资源准备中",
"opsStage": "FORMED",
"opsStageName": "已成团",
"productBatchStatus": "FINISHED",
"productBatchStatusLabel": "已结束",
"productBatchStatusName": "已结束",
"receivableAmount": "321750.00",
"receivedAmount": "55000.00",
"unpaidAmount": "266750.00"
}
],
"total": 28,
"page": 1,
"pageSize": 20
},
"success": true
}
```
#### 空数据 / 降级响应
库里存在九态之外的脏 `batch_status` 时,**只影响那一行**:该行 `opsStage` 与 `opsStageName` 同为 `null`,`batchStatus`/`batchStatusName` 照旧(后者回落原 code),整页**不会 500**。未建团行 `opsStage=RECRUIT`。
#### 错误响应
| 码 | 符号 | 触发 |
|----|------|------|
| 不变 | 400 | `pageNo` / `pageSize` 非法 |
| 不变 | `GROUP_BATCH_PRODUCT_FETCH_FAILED`(589515) | `productId` 场景拉产品域班期失败 |
```json
{
"code": 589515,
"message": "产品域班期获取失败",
"data": null,
"traceId": null,
"success": false
}
```
#### 业务边界
- **前端不要再自己复刻九态 → 八桶的折叠逻辑**,直接读 `opsStage`。后端八桶是唯一真源(`GroupBatchStageBuckets`)。
- `unpaidAmount` 是本行应收/已收的**现算值**,与财务 tab 的同名字段算法不同,某些历史脏数据下可能差一点。
- `productBatchStatusName` / `productBatchStatusLabel` 在 `productId` 缺省的老调用里**都是 `null`**(不拉产品域),这一条与改前一致。
### 2. 团期看板 `GET /v3/admin/order/group-batch/board`
**VO**: `List<GroupBatchBoardItemRespVO>`
#### 使用场景
团期看板的行列表。**本单起每行多出 3 个 key**:`opsStage`/`opsStageName`,以及与 `batchStatusLabel` 同值的 `batchStatusName`。
#### 入参字段表
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|------|------|------|------|------|------|
| productId | Query | Long | ✅ | 产品 ID | 本单不变 |
| scope | Query | String | ❌ | 班期范围 | 本单不变 |
#### 出参字段表
| 字段 | 类型 | 说明 |
|------|------|------|
| opsStage | String | **本单新增**。运营八桶:`RECRUIT` 招募中 / `FORMED` 已成团 / `PENDING_TRIP` 待出行 / `TRAVELLING` 出行中 / `TRIP_FINISHED` 出行完毕 / `AUDITING` 核团中 / `CHECKED` 已验团 / `DISBANDED` 已流团。由 `batchStatus` 九态折叠(`FORMED` 是复合桶 = `RESOURCE_PREPARING` + `MATERIAL_PREPARING`)。⚠️ `batchStatus` 为 `null` 或不在九态内(历史脏数据)时本字段为 `null` |
| opsStageName | String | **本单新增**。八桶中文名;与 `opsStage` **同生同灭**(一起为 `null`) |
| batchStatusName | String | **本单新增**。与 `batchStatusLabel` **逐字同值**(同一次装配取同一个变量,不会分叉) |
| batchStatusLabel | String | **值不变**,本单起标 `@Deprecated`,本批**不删**;新代码请改读 `batchStatusName` |
| (其余字段) | — | **全部不变**,本单不改动任何既有字段的名称、类型、取值与 null 语义 |
#### 请求示例
```http
GET /v3/admin/order/group-batch/board?productId=2044306857534636034
Authorization: Bearer <admin token>
```
#### 响应示例
```json
{
"code": 200,
"message": "成功",
"data": [
{
"groupBatchId": "2096412454643802114",
"batchStatus": "RESOURCE_PREPARING",
"batchStatusLabel": "资源准备中",
"batchStatusName": "资源准备中",
"opsStage": "FORMED",
"opsStageName": "已成团"
}
],
"success": true
}
```
#### 空数据 / 降级响应
未命中行(产品有班期、订单侧未建团)固定 `batchStatus=RECRUITING`,走同一条折桶得 `opsStage=RECRUIT`/招募中,**不特判**。脏状态行两个 opsStage 字段同为 `null`。
#### 错误响应
| 码 | 符号 | 触发 |
|----|------|------|
| 不变 | 400 | `productId` 缺失 |
```json
{
"code": 400,
"message": "productId 不能为空",
"data": null,
"traceId": null,
"success": false
}
```
#### 业务边界
- 同一团期在 A1 分页、本端点、A2 详情三处的 `opsStage` **必然相同**(同一个 resolve)。
- `batchStatusLabel` 与 `batchStatusName` 永远同值,前端二选一即可。
### 3. 团期详情(A2) `GET /v3/admin/order/group-batch/{groupBatchId}`
**VO**: `GroupBatchDetailRespVO`
#### 使用场景
团期详情。**本单起多出 5 个 key**:`opsStage`/`opsStageName`、与旧名同值的 `receivableAmount`/`receivedAmount`、以及 `thresholdSource` 的中文名 `thresholdSourceName`。
#### 入参字段表
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|------|------|------|------|------|------|
| groupBatchId | Path | Long | ✅ | 团期聚合主键 | 本单不变 |
#### 出参字段表
| 字段 | 类型 | 说明 |
|------|------|------|
| opsStage | String | **本单新增**。运营八桶:`RECRUIT` 招募中 / `FORMED` 已成团 / `PENDING_TRIP` 待出行 / `TRAVELLING` 出行中 / `TRIP_FINISHED` 出行完毕 / `AUDITING` 核团中 / `CHECKED` 已验团 / `DISBANDED` 已流团。由 `batchStatus` 九态折叠(`FORMED` 是复合桶 = `RESOURCE_PREPARING` + `MATERIAL_PREPARING`)。⚠️ `batchStatus` 为 `null` 或不在九态内(历史脏数据)时本字段为 `null` |
| opsStageName | String | **本单新增**。八桶中文名;与 `opsStage` **同生同灭**(一起为 `null`) |
| receivableAmount | String | **本单新增**。与 `totalReceivable` **逐字同值、同一来源不重算**,字段名与 A1 分页项 / 财务端点统一。JSON **字符串**形态 |
| receivedAmount | String | **本单新增**。与 `totalReceived` **逐字同值、同一来源不重算**。JSON **字符串**形态 |
| totalReceivable / totalReceived | BigDecimal | **值不变**,本单起标 `@Deprecated`,本批**不删**;新代码请改读 `receivableAmount` / `receivedAmount` |
| thresholdSourceName | String | **本单新增**。`PRODUCT_REALTIME` → 产品域实时值;`SNAPSHOT_FALLBACK` → 建团快照回退。`thresholdSource` 为 `null` 时为 `null`,取值不在枚举内时**回落原 code** |
| (其余字段) | — | **全部不变**,本单不改动任何既有字段的名称、类型、取值与 null 语义 |
#### 请求示例
```http
GET /v3/admin/order/group-batch/2096412454643802114
Authorization: Bearer <admin token>
```
#### 响应示例
```json
{
"code": 200,
"message": "成功",
"data": {
"groupBatchId": "2096412454643802114",
"batchStatus": "RESOURCE_PREPARING",
"batchStatusName": "资源准备中",
"opsStage": "FORMED",
"opsStageName": "已成团",
"totalReceivable": "321750.00",
"totalReceived": "55000.00",
"receivableAmount": "321750.00",
"receivedAmount": "55000.00",
"thresholdSource": "PRODUCT_REALTIME",
"thresholdSourceName": "产品域实时值"
},
"success": true
}
```
#### 空数据 / 降级响应
`thresholdSource` 为 `null` 时 `thresholdSourceName` 也为 `null`;脏 `batch_status` 时两个 opsStage 字段同为 `null`。均不报错。
#### 错误响应
| 码 | 符号 | 触发 |
|----|------|------|
| 不变 | `GROUP_BATCH_NOT_FOUND`(589500) | 团期不存在 / 非团期 / 已软删 |
| 不变 | `GROUP_BATCH_PERMISSION_DENIED`(589507) | 无 `group-batch:view` 权限 |
```json
{
"code": 589500,
"message": "团期不存在",
"data": null,
"traceId": null,
"success": false
}
```
#### 业务边界
- `thresholdSourceName` 是**派生只读字段**(由 `thresholdSource` 现算),因此与它**不可能分叉**。
- 新旧两对金额字段永远同值,前端二选一即可;旧名下一期删除。
### 4. 团期配房逐户明细 `GET /v3/admin/order/group-batch/{groupBatchId}/chips/hotel`
**VO**: `GroupBatchChipDetailVO`
#### 使用场景
团期看板「配房」芯片下钻的逐户明细(**六个芯片端点同构**)。本单起信封多出 `groupBatchId`/`aggregateStatusName`,逐户行多出 `teamNo`/`customerName`/`statusName` 与三个负责人字段。
#### 入参字段表
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|------|------|------|------|------|------|
| groupBatchId | Path | Long | ✅ | 团期聚合主键 | 本单不变 |
#### 出参字段表
| 字段 | 类型 | 说明 |
|------|------|------|
| teamNo | String | **本单新增**。团号(`order_main.team_no`,形如 `26-0001`)。⚠️ **逐户各不相同**,不是页头那一个团期编号的重复;⚠️ **订金支付成功后才生成,未付订金的户为 `null`**(与是不是团期订单无关)。后端**不做任何兜底**——不返空串、不回退成 `orderNo`、不拿团期编号顶替 |
| customerName | String | **本单新增**。与 `contactName` **逐字同值**(同一来源 `order_main.customer_name`) |
| contactName | String | **值不变**,本单起标 `@Deprecated`,本批**不删**;新代码请改读 `customerName` |
| statusName | String | **本单新增**。与 `statusText` **逐字同值**(同一次装配直接对拷) |
| statusText | String | **值不变**,本单起标 `@Deprecated`,本批**不删**;新代码请改读 `statusName` |
| claimerId | String | **本单新增**。该户房务负责人 adminId(字符串形态);整团与该户均无人认领时为 `null` |
| claimerName | String | **本单新增**。负责人姓名;与 `claimerId` 同生同灭 |
| claimerSource | String | **本单新增**。`BATCH` 取自团级指针 `order_group_batch.house_claimer_id`(绝大多数情况)/ `LEGACY` 该户在历史旧户冻结名单内、取自该户 `order_hotel_requirement.claimer_id` / `null` 真实无人认领(此时另两个字段也为 `null`) |
| aggregateStatusName | String | **本单新增**(信封层)。整团聚合态中文名:待开始 / 进行中 / 已完成 / 异常。`aggregateStatus` 为 `null` 时为 `null` |
| groupBatchId | String | **本单新增**(信封层)。与 `batchId` **逐字同值**,同为字符串形态 |
| batchId | String | **值不变**,本单起标 `@Deprecated`,本批**不删**;新代码请改读 `groupBatchId` |
| (其余字段) | — | **全部不变**,本单不改动任何既有字段的名称、类型、取值与 null 语义 |
#### 请求示例
```http
GET /v3/admin/order/group-batch/2097498512387104770/chips/hotel
Authorization: Bearer <admin token>
```
#### 响应示例
```json
{
"code": 200,
"message": "成功",
"data": {
"batchId": "2097498512387104770",
"groupBatchId": "2097498512387104770",
"chipLabel": "配房",
"aggregateStatus": "TODO",
"aggregateStatusName": "待开始",
"totalCount": 4,
"doneCount": 0,
"items": [
{
"orderId": "2098372769329598466",
"orderNo": "HL20260911192708661",
"teamNo": "26-9069",
"contactName": "何书禾",
"customerName": "何书禾",
"peopleCount": 2,
"status": "PENDING",
"statusText": "待房务配",
"statusName": "待房务配",
"needsIt": true,
"updateTime": null,
"claimerId": "30001",
"claimerName": "张三",
"claimerSource": "BATCH"
}
]
},
"success": true
}
```
#### 空数据 / 降级响应
团期无活跃子订单时 `items` 为空数组、三格计数为 0,新增字段**不出现在任何行里**(没有行)。整团未认领时逐户三个负责人字段全为 `null`。
#### 错误响应
| 码 | 符号 | 触发 |
|----|------|------|
| 不变 | `GROUP_BATCH_NOT_FOUND`(589500) | 团期不存在 / 非团期 / 已软删 |
| 不变 | `GROUP_BATCH_PERMISSION_DENIED`(589507) | 无 `group-batch:view` 权限 |
```json
{
"code": 589500,
"message": "团期不存在",
"data": null,
"traceId": null,
"success": false
}
```
#### 业务边界
- **六个芯片端点的响应结构完全一致**,本单 6 处一起加,不因芯片类型特判——「这个团归谁」与看哪张芯片无关。
- **负责人默认读团级指针**:整团认领只写团级、不回写户级,只读户级会让「已被正常认领并配房的新团」全团显示空负责人。
- 超管接管后 CAS 落空的残留户级归属属**待清理脏数据**,本字段仍如实给 `BATCH`——`claimerSource` 就是给前端/运营分辨用的。
- 一个团里有的户有 `teamNo`、有的户是 `null` 是**正常态**,不是后端漏填。
### 5. 团期配车逐户明细 `GET /v3/admin/order/group-batch/{groupBatchId}/chips/vehicle`
**VO**: `GroupBatchChipDetailVO`
#### 使用场景
团期看板「配车」芯片下钻的逐户明细(**六个芯片端点同构**)。本单起信封多出 `groupBatchId`/`aggregateStatusName`,逐户行多出 `teamNo`/`customerName`/`statusName` 与三个负责人字段。
#### 入参字段表
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|------|------|------|------|------|------|
| groupBatchId | Path | Long | ✅ | 团期聚合主键 | 本单不变 |
#### 出参字段表
| 字段 | 类型 | 说明 |
|------|------|------|
| teamNo | String | **本单新增**。团号(`order_main.team_no`,形如 `26-0001`)。⚠️ **逐户各不相同**,不是页头那一个团期编号的重复;⚠️ **订金支付成功后才生成,未付订金的户为 `null`**(与是不是团期订单无关)。后端**不做任何兜底**——不返空串、不回退成 `orderNo`、不拿团期编号顶替 |
| customerName | String | **本单新增**。与 `contactName` **逐字同值**(同一来源 `order_main.customer_name`) |
| contactName | String | **值不变**,本单起标 `@Deprecated`,本批**不删**;新代码请改读 `customerName` |
| statusName | String | **本单新增**。与 `statusText` **逐字同值**(同一次装配直接对拷) |
| statusText | String | **值不变**,本单起标 `@Deprecated`,本批**不删**;新代码请改读 `statusName` |
| claimerId | String | **本单新增**。该户房务负责人 adminId(字符串形态);整团与该户均无人认领时为 `null` |
| claimerName | String | **本单新增**。负责人姓名;与 `claimerId` 同生同灭 |
| claimerSource | String | **本单新增**。`BATCH` 取自团级指针 `order_group_batch.house_claimer_id`(绝大多数情况)/ `LEGACY` 该户在历史旧户冻结名单内、取自该户 `order_hotel_requirement.claimer_id` / `null` 真实无人认领(此时另两个字段也为 `null`) |
| aggregateStatusName | String | **本单新增**(信封层)。整团聚合态中文名:待开始 / 进行中 / 已完成 / 异常。`aggregateStatus` 为 `null` 时为 `null` |
| groupBatchId | String | **本单新增**(信封层)。与 `batchId` **逐字同值**,同为字符串形态 |
| batchId | String | **值不变**,本单起标 `@Deprecated`,本批**不删**;新代码请改读 `groupBatchId` |
| (其余字段) | — | **全部不变**,本单不改动任何既有字段的名称、类型、取值与 null 语义 |
#### 请求示例
```http
GET /v3/admin/order/group-batch/2097498512387104770/chips/vehicle
Authorization: Bearer <admin token>
```
#### 响应示例
```json
{
"code": 200,
"message": "成功",
"data": {
"batchId": "2097498512387104770",
"groupBatchId": "2097498512387104770",
"chipLabel": "配房",
"aggregateStatus": "TODO",
"aggregateStatusName": "待开始",
"totalCount": 4,
"doneCount": 0,
"items": [
{
"orderId": "2098372769329598466",
"orderNo": "HL20260911192708661",
"teamNo": "26-9069",
"contactName": "何书禾",
"customerName": "何书禾",
"peopleCount": 2,
"status": "PENDING",
"statusText": "待房务配",
"statusName": "待房务配",
"needsIt": true,
"updateTime": null,
"claimerId": "30001",
"claimerName": "张三",
"claimerSource": "BATCH"
}
]
},
"success": true
}
```
#### 空数据 / 降级响应
团期无活跃子订单时 `items` 为空数组、三格计数为 0,新增字段**不出现在任何行里**(没有行)。整团未认领时逐户三个负责人字段全为 `null`。
#### 错误响应
| 码 | 符号 | 触发 |
|----|------|------|
| 不变 | `GROUP_BATCH_NOT_FOUND`(589500) | 团期不存在 / 非团期 / 已软删 |
| 不变 | `GROUP_BATCH_PERMISSION_DENIED`(589507) | 无 `group-batch:view` 权限 |
```json
{
"code": 589500,
"message": "团期不存在",
"data": null,
"traceId": null,
"success": false
}
```
#### 业务边界
- **六个芯片端点的响应结构完全一致**,本单 6 处一起加,不因芯片类型特判——「这个团归谁」与看哪张芯片无关。
- **负责人默认读团级指针**:整团认领只写团级、不回写户级,只读户级会让「已被正常认领并配房的新团」全团显示空负责人。
- 超管接管后 CAS 落空的残留户级归属属**待清理脏数据**,本字段仍如实给 `BATCH`——`claimerSource` 就是给前端/运营分辨用的。
- 一个团里有的户有 `teamNo`、有的户是 `null` 是**正常态**,不是后端漏填。
### 6. 团期配导游逐户明细 `GET /v3/admin/order/group-batch/{groupBatchId}/chips/guide`
**VO**: `GroupBatchChipDetailVO`
#### 使用场景
团期看板「配导游」芯片下钻的逐户明细(**六个芯片端点同构**)。本单起信封多出 `groupBatchId`/`aggregateStatusName`,逐户行多出 `teamNo`/`customerName`/`statusName` 与三个负责人字段。
#### 入参字段表
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|------|------|------|------|------|------|
| groupBatchId | Path | Long | ✅ | 团期聚合主键 | 本单不变 |
#### 出参字段表
| 字段 | 类型 | 说明 |
|------|------|------|
| teamNo | String | **本单新增**。团号(`order_main.team_no`,形如 `26-0001`)。⚠️ **逐户各不相同**,不是页头那一个团期编号的重复;⚠️ **订金支付成功后才生成,未付订金的户为 `null`**(与是不是团期订单无关)。后端**不做任何兜底**——不返空串、不回退成 `orderNo`、不拿团期编号顶替 |
| customerName | String | **本单新增**。与 `contactName` **逐字同值**(同一来源 `order_main.customer_name`) |
| contactName | String | **值不变**,本单起标 `@Deprecated`,本批**不删**;新代码请改读 `customerName` |
| statusName | String | **本单新增**。与 `statusText` **逐字同值**(同一次装配直接对拷) |
| statusText | String | **值不变**,本单起标 `@Deprecated`,本批**不删**;新代码请改读 `statusName` |
| claimerId | String | **本单新增**。该户房务负责人 adminId(字符串形态);整团与该户均无人认领时为 `null` |
| claimerName | String | **本单新增**。负责人姓名;与 `claimerId` 同生同灭 |
| claimerSource | String | **本单新增**。`BATCH` 取自团级指针 `order_group_batch.house_claimer_id`(绝大多数情况)/ `LEGACY` 该户在历史旧户冻结名单内、取自该户 `order_hotel_requirement.claimer_id` / `null` 真实无人认领(此时另两个字段也为 `null`) |
| aggregateStatusName | String | **本单新增**(信封层)。整团聚合态中文名:待开始 / 进行中 / 已完成 / 异常。`aggregateStatus` 为 `null` 时为 `null` |
| groupBatchId | String | **本单新增**(信封层)。与 `batchId` **逐字同值**,同为字符串形态 |
| batchId | String | **值不变**,本单起标 `@Deprecated`,本批**不删**;新代码请改读 `groupBatchId` |
| (其余字段) | — | **全部不变**,本单不改动任何既有字段的名称、类型、取值与 null 语义 |
#### 请求示例
```http
GET /v3/admin/order/group-batch/2097498512387104770/chips/guide
Authorization: Bearer <admin token>
```
#### 响应示例
```json
{
"code": 200,
"message": "成功",
"data": {
"batchId": "2097498512387104770",
"groupBatchId": "2097498512387104770",
"chipLabel": "配房",
"aggregateStatus": "TODO",
"aggregateStatusName": "待开始",
"totalCount": 4,
"doneCount": 0,
"items": [
{
"orderId": "2098372769329598466",
"orderNo": "HL20260911192708661",
"teamNo": "26-9069",
"contactName": "何书禾",
"customerName": "何书禾",
"peopleCount": 2,
"status": "PENDING",
"statusText": "待房务配",
"statusName": "待房务配",
"needsIt": true,
"updateTime": null,
"claimerId": "30001",
"claimerName": "张三",
"claimerSource": "BATCH"
}
]
},
"success": true
}
```
#### 空数据 / 降级响应
团期无活跃子订单时 `items` 为空数组、三格计数为 0,新增字段**不出现在任何行里**(没有行)。整团未认领时逐户三个负责人字段全为 `null`。
#### 错误响应
| 码 | 符号 | 触发 |
|----|------|------|
| 不变 | `GROUP_BATCH_NOT_FOUND`(589500) | 团期不存在 / 非团期 / 已软删 |
| 不变 | `GROUP_BATCH_PERMISSION_DENIED`(589507) | 无 `group-batch:view` 权限 |
```json
{
"code": 589500,
"message": "团期不存在",
"data": null,
"traceId": null,
"success": false
}
```
#### 业务边界
- **六个芯片端点的响应结构完全一致**,本单 6 处一起加,不因芯片类型特判——「这个团归谁」与看哪张芯片无关。
- **负责人默认读团级指针**:整团认领只写团级、不回写户级,只读户级会让「已被正常认领并配房的新团」全团显示空负责人。
- 超管接管后 CAS 落空的残留户级归属属**待清理脏数据**,本字段仍如实给 `BATCH`——`claimerSource` 就是给前端/运营分辨用的。
- 一个团里有的户有 `teamNo`、有的户是 `null` 是**正常态**,不是后端漏填。
### 7. 团期配摄影逐户明细 `GET /v3/admin/order/group-batch/{groupBatchId}/chips/photo`
**VO**: `GroupBatchChipDetailVO`
#### 使用场景
团期看板「配摄影」芯片下钻的逐户明细(**六个芯片端点同构**)。本单起信封多出 `groupBatchId`/`aggregateStatusName`,逐户行多出 `teamNo`/`customerName`/`statusName` 与三个负责人字段。
#### 入参字段表
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|------|------|------|------|------|------|
| groupBatchId | Path | Long | ✅ | 团期聚合主键 | 本单不变 |
#### 出参字段表
| 字段 | 类型 | 说明 |
|------|------|------|
| teamNo | String | **本单新增**。团号(`order_main.team_no`,形如 `26-0001`)。⚠️ **逐户各不相同**,不是页头那一个团期编号的重复;⚠️ **订金支付成功后才生成,未付订金的户为 `null`**(与是不是团期订单无关)。后端**不做任何兜底**——不返空串、不回退成 `orderNo`、不拿团期编号顶替 |
| customerName | String | **本单新增**。与 `contactName` **逐字同值**(同一来源 `order_main.customer_name`) |
| contactName | String | **值不变**,本单起标 `@Deprecated`,本批**不删**;新代码请改读 `customerName` |
| statusName | String | **本单新增**。与 `statusText` **逐字同值**(同一次装配直接对拷) |
| statusText | String | **值不变**,本单起标 `@Deprecated`,本批**不删**;新代码请改读 `statusName` |
| claimerId | String | **本单新增**。该户房务负责人 adminId(字符串形态);整团与该户均无人认领时为 `null` |
| claimerName | String | **本单新增**。负责人姓名;与 `claimerId` 同生同灭 |
| claimerSource | String | **本单新增**。`BATCH` 取自团级指针 `order_group_batch.house_claimer_id`(绝大多数情况)/ `LEGACY` 该户在历史旧户冻结名单内、取自该户 `order_hotel_requirement.claimer_id` / `null` 真实无人认领(此时另两个字段也为 `null`) |
| aggregateStatusName | String | **本单新增**(信封层)。整团聚合态中文名:待开始 / 进行中 / 已完成 / 异常。`aggregateStatus` 为 `null` 时为 `null` |
| groupBatchId | String | **本单新增**(信封层)。与 `batchId` **逐字同值**,同为字符串形态 |
| batchId | String | **值不变**,本单起标 `@Deprecated`,本批**不删**;新代码请改读 `groupBatchId` |
| (其余字段) | — | **全部不变**,本单不改动任何既有字段的名称、类型、取值与 null 语义 |
#### 请求示例
```http
GET /v3/admin/order/group-batch/2097498512387104770/chips/photo
Authorization: Bearer <admin token>
```
#### 响应示例
```json
{
"code": 200,
"message": "成功",
"data": {
"batchId": "2097498512387104770",
"groupBatchId": "2097498512387104770",
"chipLabel": "配房",
"aggregateStatus": "TODO",
"aggregateStatusName": "待开始",
"totalCount": 4,
"doneCount": 0,
"items": [
{
"orderId": "2098372769329598466",
"orderNo": "HL20260911192708661",
"teamNo": "26-9069",
"contactName": "何书禾",
"customerName": "何书禾",
"peopleCount": 2,
"status": "PENDING",
"statusText": "待房务配",
"statusName": "待房务配",
"needsIt": true,
"updateTime": null,
"claimerId": "30001",
"claimerName": "张三",
"claimerSource": "BATCH"
}
]
},
"success": true
}
```
#### 空数据 / 降级响应
团期无活跃子订单时 `items` 为空数组、三格计数为 0,新增字段**不出现在任何行里**(没有行)。整团未认领时逐户三个负责人字段全为 `null`。
#### 错误响应
| 码 | 符号 | 触发 |
|----|------|------|
| 不变 | `GROUP_BATCH_NOT_FOUND`(589500) | 团期不存在 / 非团期 / 已软删 |
| 不变 | `GROUP_BATCH_PERMISSION_DENIED`(589507) | 无 `group-batch:view` 权限 |
```json
{
"code": 589500,
"message": "团期不存在",
"data": null,
"traceId": null,
"success": false
}
```
#### 业务边界
- **六个芯片端点的响应结构完全一致**,本单 6 处一起加,不因芯片类型特判——「这个团归谁」与看哪张芯片无关。
- **负责人默认读团级指针**:整团认领只写团级、不回写户级,只读户级会让「已被正常认领并配房的新团」全团显示空负责人。
- 超管接管后 CAS 落空的残留户级归属属**待清理脏数据**,本字段仍如实给 `BATCH`——`claimerSource` 就是给前端/运营分辨用的。
- 一个团里有的户有 `teamNo`、有的户是 `null` 是**正常态**,不是后端漏填。
### 8. 团期合同逐户明细 `GET /v3/admin/order/group-batch/{groupBatchId}/chips/contract`
**VO**: `GroupBatchChipDetailVO`
#### 使用场景
团期看板「合同」芯片下钻的逐户明细(**六个芯片端点同构**)。本单起信封多出 `groupBatchId`/`aggregateStatusName`,逐户行多出 `teamNo`/`customerName`/`statusName` 与三个负责人字段。
#### 入参字段表
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|------|------|------|------|------|------|
| groupBatchId | Path | Long | ✅ | 团期聚合主键 | 本单不变 |
#### 出参字段表
| 字段 | 类型 | 说明 |
|------|------|------|
| teamNo | String | **本单新增**。团号(`order_main.team_no`,形如 `26-0001`)。⚠️ **逐户各不相同**,不是页头那一个团期编号的重复;⚠️ **订金支付成功后才生成,未付订金的户为 `null`**(与是不是团期订单无关)。后端**不做任何兜底**——不返空串、不回退成 `orderNo`、不拿团期编号顶替 |
| customerName | String | **本单新增**。与 `contactName` **逐字同值**(同一来源 `order_main.customer_name`) |
| contactName | String | **值不变**,本单起标 `@Deprecated`,本批**不删**;新代码请改读 `customerName` |
| statusName | String | **本单新增**。与 `statusText` **逐字同值**(同一次装配直接对拷) |
| statusText | String | **值不变**,本单起标 `@Deprecated`,本批**不删**;新代码请改读 `statusName` |
| claimerId | String | **本单新增**。该户房务负责人 adminId(字符串形态);整团与该户均无人认领时为 `null` |
| claimerName | String | **本单新增**。负责人姓名;与 `claimerId` 同生同灭 |
| claimerSource | String | **本单新增**。`BATCH` 取自团级指针 `order_group_batch.house_claimer_id`(绝大多数情况)/ `LEGACY` 该户在历史旧户冻结名单内、取自该户 `order_hotel_requirement.claimer_id` / `null` 真实无人认领(此时另两个字段也为 `null`) |
| aggregateStatusName | String | **本单新增**(信封层)。整团聚合态中文名:待开始 / 进行中 / 已完成 / 异常。`aggregateStatus` 为 `null` 时为 `null` |
| groupBatchId | String | **本单新增**(信封层)。与 `batchId` **逐字同值**,同为字符串形态 |
| batchId | String | **值不变**,本单起标 `@Deprecated`,本批**不删**;新代码请改读 `groupBatchId` |
| (其余字段) | — | **全部不变**,本单不改动任何既有字段的名称、类型、取值与 null 语义 |
#### 请求示例
```http
GET /v3/admin/order/group-batch/2097498512387104770/chips/contract
Authorization: Bearer <admin token>
```
#### 响应示例
```json
{
"code": 200,
"message": "成功",
"data": {
"batchId": "2097498512387104770",
"groupBatchId": "2097498512387104770",
"chipLabel": "配房",
"aggregateStatus": "TODO",
"aggregateStatusName": "待开始",
"totalCount": 4,
"doneCount": 0,
"items": [
{
"orderId": "2098372769329598466",
"orderNo": "HL20260911192708661",
"teamNo": "26-9069",
"contactName": "何书禾",
"customerName": "何书禾",
"peopleCount": 2,
"status": "PENDING",
"statusText": "待房务配",
"statusName": "待房务配",
"needsIt": true,
"updateTime": null,
"claimerId": "30001",
"claimerName": "张三",
"claimerSource": "BATCH"
}
]
},
"success": true
}
```
#### 空数据 / 降级响应
团期无活跃子订单时 `items` 为空数组、三格计数为 0,新增字段**不出现在任何行里**(没有行)。整团未认领时逐户三个负责人字段全为 `null`。
#### 错误响应
| 码 | 符号 | 触发 |
|----|------|------|
| 不变 | `GROUP_BATCH_NOT_FOUND`(589500) | 团期不存在 / 非团期 / 已软删 |
| 不变 | `GROUP_BATCH_PERMISSION_DENIED`(589507) | 无 `group-batch:view` 权限 |
```json
{
"code": 589500,
"message": "团期不存在",
"data": null,
"traceId": null,
"success": false
}
```
#### 业务边界
- **六个芯片端点的响应结构完全一致**,本单 6 处一起加,不因芯片类型特判——「这个团归谁」与看哪张芯片无关。
- **负责人默认读团级指针**:整团认领只写团级、不回写户级,只读户级会让「已被正常认领并配房的新团」全团显示空负责人。
- 超管接管后 CAS 落空的残留户级归属属**待清理脏数据**,本字段仍如实给 `BATCH`——`claimerSource` 就是给前端/运营分辨用的。
- 一个团里有的户有 `teamNo`、有的户是 `null` 是**正常态**,不是后端漏填。
### 9. 团期保险逐户明细 `GET /v3/admin/order/group-batch/{groupBatchId}/chips/insurance`
**VO**: `GroupBatchChipDetailVO`
#### 使用场景
团期看板「保险」芯片下钻的逐户明细(**六个芯片端点同构**)。本单起信封多出 `groupBatchId`/`aggregateStatusName`,逐户行多出 `teamNo`/`customerName`/`statusName` 与三个负责人字段。
#### 入参字段表
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|------|------|------|------|------|------|
| groupBatchId | Path | Long | ✅ | 团期聚合主键 | 本单不变 |
#### 出参字段表
| 字段 | 类型 | 说明 |
|------|------|------|
| teamNo | String | **本单新增**。团号(`order_main.team_no`,形如 `26-0001`)。⚠️ **逐户各不相同**,不是页头那一个团期编号的重复;⚠️ **订金支付成功后才生成,未付订金的户为 `null`**(与是不是团期订单无关)。后端**不做任何兜底**——不返空串、不回退成 `orderNo`、不拿团期编号顶替 |
| customerName | String | **本单新增**。与 `contactName` **逐字同值**(同一来源 `order_main.customer_name`) |
| contactName | String | **值不变**,本单起标 `@Deprecated`,本批**不删**;新代码请改读 `customerName` |
| statusName | String | **本单新增**。与 `statusText` **逐字同值**(同一次装配直接对拷) |
| statusText | String | **值不变**,本单起标 `@Deprecated`,本批**不删**;新代码请改读 `statusName` |
| claimerId | String | **本单新增**。该户房务负责人 adminId(字符串形态);整团与该户均无人认领时为 `null` |
| claimerName | String | **本单新增**。负责人姓名;与 `claimerId` 同生同灭 |
| claimerSource | String | **本单新增**。`BATCH` 取自团级指针 `order_group_batch.house_claimer_id`(绝大多数情况)/ `LEGACY` 该户在历史旧户冻结名单内、取自该户 `order_hotel_requirement.claimer_id` / `null` 真实无人认领(此时另两个字段也为 `null`) |
| aggregateStatusName | String | **本单新增**(信封层)。整团聚合态中文名:待开始 / 进行中 / 已完成 / 异常。`aggregateStatus` 为 `null` 时为 `null` |
| groupBatchId | String | **本单新增**(信封层)。与 `batchId` **逐字同值**,同为字符串形态 |
| batchId | String | **值不变**,本单起标 `@Deprecated`,本批**不删**;新代码请改读 `groupBatchId` |
| (其余字段) | — | **全部不变**,本单不改动任何既有字段的名称、类型、取值与 null 语义 |
#### 请求示例
```http
GET /v3/admin/order/group-batch/2097498512387104770/chips/insurance
Authorization: Bearer <admin token>
```
#### 响应示例
```json
{
"code": 200,
"message": "成功",
"data": {
"batchId": "2097498512387104770",
"groupBatchId": "2097498512387104770",
"chipLabel": "配房",
"aggregateStatus": "TODO",
"aggregateStatusName": "待开始",
"totalCount": 4,
"doneCount": 0,
"items": [
{
"orderId": "2098372769329598466",
"orderNo": "HL20260911192708661",
"teamNo": "26-9069",
"contactName": "何书禾",
"customerName": "何书禾",
"peopleCount": 2,
"status": "PENDING",
"statusText": "待房务配",
"statusName": "待房务配",
"needsIt": true,
"updateTime": null,
"claimerId": "30001",
"claimerName": "张三",
"claimerSource": "BATCH"
}
]
},
"success": true
}
```
#### 空数据 / 降级响应
团期无活跃子订单时 `items` 为空数组、三格计数为 0,新增字段**不出现在任何行里**(没有行)。整团未认领时逐户三个负责人字段全为 `null`。
#### 错误响应
| 码 | 符号 | 触发 |
|----|------|------|
| 不变 | `GROUP_BATCH_NOT_FOUND`(589500) | 团期不存在 / 非团期 / 已软删 |
| 不变 | `GROUP_BATCH_PERMISSION_DENIED`(589507) | 无 `group-batch:view` 权限 |
```json
{
"code": 589500,
"message": "团期不存在",
"data": null,
"traceId": null,
"success": false
}
```
#### 业务边界
- **六个芯片端点的响应结构完全一致**,本单 6 处一起加,不因芯片类型特判——「这个团归谁」与看哪张芯片无关。
- **负责人默认读团级指针**:整团认领只写团级、不回写户级,只读户级会让「已被正常认领并配房的新团」全团显示空负责人。
- 超管接管后 CAS 落空的残留户级归属属**待清理脏数据**,本字段仍如实给 `BATCH`——`claimerSource` 就是给前端/运营分辨用的。
- 一个团里有的户有 `teamNo`、有的户是 `null` 是**正常态**,不是后端漏填。
### 10. 团期「合同保险」面板 `GET /v3/admin/order/group-batch/{groupBatchId}/contracts`
**VO**: `GroupBatchContractBoardVO`
#### 使用场景
合同保险面板一屏读。本单起信封多出 `groupBatchId`,逐户卡片多出 `teamNo` 与 `customerName`。
#### 入参字段表
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|------|------|------|------|------|------|
| groupBatchId | Path | Long | ✅ | 团期聚合主键 | 本单不变 |
#### 出参字段表
| 字段 | 类型 | 说明 |
|------|------|------|
| groupBatchId | String | **本单新增**(信封层)。与 `batchId` **逐字同值**,同为字符串形态 |
| batchId | String | **值不变**,本单起标 `@Deprecated`,本批**不删**;新代码请改读 `groupBatchId` |
| teamNo | String | **本单新增**(逐户)。口径与芯片逐户行**完全一致**:`order_main.team_no`,逐户各不相同,未付订金为 `null`,无任何兜底 |
| customerName | String | **本单新增**(逐户)。与 `contactName` **逐字同值** |
| contactName | String | **值不变**,本单起标 `@Deprecated`,本批**不删**;新代码请改读 `customerName` |
| (其余字段) | — | **全部不变**,本单不改动任何既有字段的名称、类型、取值与 null 语义 |
#### 请求示例
```http
GET /v3/admin/order/group-batch/2097498512387104770/contracts
Authorization: Bearer <admin token>
```
#### 响应示例
```json
{
"code": 200,
"message": "成功",
"data": {
"batchId": "2097498512387104770",
"groupBatchId": "2097498512387104770",
"issuable": false,
"totalCount": 4,
"items": [
{
"orderId": "2098372769329598466",
"orderNo": "HL20260911192708661",
"teamNo": "26-9069",
"contactName": "何书禾",
"customerName": "何书禾",
"contractState": "NOT_ISSUED",
"contractStateText": "未出"
}
]
},
"success": true
}
```
#### 空数据 / 降级响应
本期无活跃子订单时 `items` 为空数组、三格分子分母均 0。
#### 错误响应
| 码 | 符号 | 触发 |
|----|------|------|
| 不变 | `GROUP_BATCH_NOT_FOUND`(589500) | 团期不存在 / 非团期 / 已软删 |
| 不变 | `GROUP_BATCH_PERMISSION_DENIED`(589507) | 无 `group-batch:view` 权限 |
```json
{
"code": 589500,
"message": "团期不存在",
"data": null,
"traceId": null,
"success": false
}
```
#### 业务边界
- 本端点与芯片 `contract` 端点的 `teamNo` **同一取值来源、同一 null 语义**,两处必然一致。
- 面板三格计数由 `items` 自算,本单**未改一行**计数逻辑。
### 11. 团期行程逐日汇总 `GET /v3/admin/order/group-batch/{groupBatchId}/itinerary`
**VO**: `GroupBatchItineraryRespVO`
#### 使用场景
团期行程汇总。本单起「天数不一致户」预警行多出 `customerName`。
#### 入参字段表
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|------|------|------|------|------|------|
| groupBatchId | Path | Long | ✅ | 团期聚合主键 | 本单不变 |
#### 出参字段表
| 字段 | 类型 | 说明 |
|------|------|------|
| dayCountOutliers[].customerName | String | **本单新增**。与同一项的 `contactName` **逐字同值** |
| dayCountOutliers[].contactName | String | **值不变**,本单起标 `@Deprecated`,本批**不删**;新代码请改读 `customerName` |
| (其余字段) | — | **全部不变**,本单不改动任何既有字段的名称、类型、取值与 null 语义 |
#### 请求示例
```http
GET /v3/admin/order/group-batch/2096412454643802114/itinerary
Authorization: Bearer <admin token>
```
#### 响应示例
```json
{
"code": 200,
"message": "成功",
"data": {
"dayCount": 3,
"dayCountConsistent": false,
"dayCountOutliers": [
{
"orderId": "2096655509804187650",
"orderNo": "HL20260907014322086",
"contactName": "沈怀妍",
"customerName": "沈怀妍",
"dayCount": 1
}
]
},
"success": true
}
```
#### 空数据 / 降级响应
各户天数一致时 `dayCountOutliers` 为空数组,新增字段不出现(没有行)。
#### 错误响应
| 码 | 符号 | 触发 |
|----|------|------|
| 不变 | `GROUP_BATCH_NOT_FOUND`(589500) | 团期不存在 / 非团期 / 已软删 |
| 不变 | `GROUP_BATCH_PERMISSION_DENIED`(589507) | 无 `group-batch:view` 权限 |
```json
{
"code": 589500,
"message": "团期不存在",
"data": null,
"traceId": null,
"success": false
}
```
#### 业务边界
- 本单只加字段,**行程一致性判定逻辑一行未改**。
### 12. 团期行程某项逐户下钻 `GET /v3/admin/order/group-batch/{groupBatchId}/itinerary/nodes/{nodeKey}`
**VO**: `GroupBatchItineraryNodeDetailVO`
#### 使用场景
行程某个节点的逐户下钻。本单起逐户行多出 `customerName`。
#### 入参字段表
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|------|------|------|------|------|------|
| groupBatchId | Path | Long | ✅ | 团期聚合主键 | 本单不变 |
| nodeKey | Path | String | ✅ | 节点键(由汇总端点给出) | 本单不变 |
#### 出参字段表
| 字段 | 类型 | 说明 |
|------|------|------|
| items[].customerName | String | **本单新增**。与同一项的 `contactName` **逐字同值** |
| items[].contactName | String | **值不变**,本单起标 `@Deprecated`,本批**不删**;新代码请改读 `customerName` |
| (其余字段) | — | **全部不变**,本单不改动任何既有字段的名称、类型、取值与 null 语义 |
#### 请求示例
```http
GET /v3/admin/order/group-batch/2096412454643802114/itinerary/nodes/<nodeKey>
Authorization: Bearer <admin token>
```
#### 响应示例
```json
{
"code": 200,
"message": "成功",
"data": {
"nodeName": "礼仪接机",
"householdCount": 55,
"items": [
{
"orderId": "2096655509804187650",
"orderNo": "HL20260907001741975",
"contactName": "蒋岚妍",
"customerName": "蒋岚妍",
"has": true
}
]
},
"success": true
}
```
#### 空数据 / 降级响应
`nodeKey` 无人命中时 `items` 仍返回全部活跃户(`has=false`),新增字段照常有值。
#### 错误响应
| 码 | 符号 | 触发 |
|----|------|------|
| 不变 | `GROUP_BATCH_NOT_FOUND`(589500) | 团期不存在 / 非团期 / 已软删 |
| 不变 | `GROUP_BATCH_PERMISSION_DENIED`(589507) | 无 `group-batch:view` 权限 |
```json
{
"code": 589500,
"message": "团期不存在",
"data": null,
"traceId": null,
"success": false
}
```
#### 业务边界
- 未命中该节点的户 `has=false`,但 `customerName` 与 `contactName` 照常有值。
### 13. 审批中心统一列表 `GET /v3/admin/order/group-batch/approvals/page`
**VO**: `PageResult<GroupBatchApprovalItemRespVO>`
#### 使用场景
流团与退单户共用的审批中心列表。本单起每行多出 5 个 key:退单户三件套 `orderNo`/`customerName`/`departDate`,以及 `approvalStatusName` 与 `bizTypeName`。
#### 入参字段表
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|------|------|------|------|------|------|
| pageNum / pageSize / bizType / approvalStatus / groupBatchId | Query | — | — | 本单**一个入参都没改** | — |
#### 出参字段表
| 字段 | 类型 | 说明 |
|------|------|------|
| orderNo | String | **本单新增**。⚠️ **只在 `bizType=WITHDRAW` 行有值,`DISBAND` 行恒 `null`**(与已有的 `orderId` 同一条规则);订单查不到(已软删)时也为 `null` |
| customerName | String | **本单新增**。同上规则 |
| departDate | String | **本单新增**。团期出发日 `yyyy-MM-dd`,与退单专用列表 `GET .../withdraw/page` **同源同格式、逐字相同**。同上规则 |
| approvalStatusName | String | **本单新增**。待审批 / 已通过 / 已取消退单。`approvalStatus` 为 `null` 时为 `null`,取值不在枚举内时**回落原 code** |
| bizTypeName | String | **本单新增**。与 `bizTypeText` **逐字同值**(流团 / 退单户) |
| bizTypeText | String | **值不变**,本单起标 `@Deprecated`,本批**不删**;新代码请改读 `bizTypeName` |
| (其余字段) | — | **全部不变**,本单不改动任何既有字段的名称、类型、取值与 null 语义 |
#### 请求示例
```http
GET /v3/admin/order/group-batch/approvals/page?pageNum=1&pageSize=20
Authorization: Bearer <admin token>
```
#### 响应示例
```json
{
"code": 200,
"message": "成功",
"data": {
"records": [
{
"approvalId": "2096029515502243842",
"bizType": "WITHDRAW",
"bizTypeText": "退单户",
"bizTypeName": "退单户",
"approvalStatus": "APPROVED",
"approvalStatusName": "已通过",
"orderId": "2096029450184347649",
"orderNo": "HL20260905081537435",
"customerName": "退单复测-7100",
"departDate": "2026-10-31"
},
{
"approvalId": "2097963098638876674",
"bizType": "DISBAND",
"bizTypeText": "流团",
"bizTypeName": "流团",
"approvalStatus": "APPROVED",
"approvalStatusName": "已通过",
"orderId": null,
"orderNo": null,
"customerName": null,
"departDate": null
}
],
"total": 38
},
"success": true
}
```
#### 空数据 / 降级响应
页内**一行 WITHDRAW 都没有**时,后端**一次订单查询都不发**(空集合短路)。订单或团期已软删的 WITHDRAW 行三个新字段为 `null`,**该行照常返回、不漏行、不报错**。
#### 错误响应
| 码 | 符号 | 触发 |
|----|------|------|
| 不变 | `GROUP_BATCH_PERMISSION_DENIED`(589507) | 无 `group-batch:view` 权限 |
```json
{
"code": 589507,
"message": "无操作权限",
"data": null,
"traceId": null,
"success": false
}
```
#### 业务边界
- 🔴 **前端必须按行类型判断再渲染**:三个新字段只在 `bizType=WITHDRAW` 行有值,`DISBAND` 行恒 `null`。按「字段存在即渲染」写会出现空列。
- 整页**一次**批量取单(防 N+1),不是每行一次。
### 14. 退单审批列表 `GET /v3/admin/order/group-batch/withdraw/page`
**VO**: `PageResult<WithdrawApprovalItemRespVO>`
#### 使用场景
退单户专用审批列表。本单起每行多出 `refundModeName` 与 `approvalStatusName` 两个中文名。
#### 入参字段表
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|------|------|------|------|------|------|
| pageNum / pageSize / approvalStatus / … | Query | — | — | 本单**一个入参都没改** | — |
#### 出参字段表
| 字段 | 类型 | 说明 |
|------|------|------|
| refundModeName | String | **本单新增**。按政策退 / 订金全额退 / 已付全额退 / 部分退。`refundMode` 为 `null` 时为 `null`,取值不在枚举内时**回落原 code** |
| approvalStatusName | String | **本单新增**。待审批 / 已通过 / 已取消退单。同上兜底口径 |
| (其余字段) | — | **全部不变**,本单不改动任何既有字段的名称、类型、取值与 null 语义 |
#### 请求示例
```http
GET /v3/admin/order/group-batch/withdraw/page?pageNum=1&pageSize=20
Authorization: Bearer <admin token>
```
#### 响应示例
```json
{
"code": 200,
"message": "成功",
"data": {
"records": [
{
"approvalId": "2096029515502243842",
"orderNo": "HL20260905081537435",
"customerName": "退单复测-7100",
"departDate": "2026-10-31",
"refundMode": "FULL_DEPOSIT",
"refundModeName": "订金全额退",
"approvalStatus": "APPROVED",
"approvalStatusName": "已通过"
}
],
"total": 2
},
"success": true
}
```
#### 空数据 / 降级响应
无数据时 `records` 为空数组。两个 code 为 `null` 时对应的 `Name` 也为 `null`。
#### 错误响应
| 码 | 符号 | 触发 |
|----|------|------|
| 不变 | `GROUP_BATCH_PERMISSION_DENIED`(589507) | 无权限 |
```json
{
"code": 589507,
"message": "无操作权限",
"data": null,
"traceId": null,
"success": false
}
```
#### 业务边界
- 退单详情 `GET .../withdraw/{approvalId}` 的响应体继承自本 VO,**同样多出这两个字段**(向后兼容纯增)。
- 本端点与审批中心统一列表对同一张审批单的 `orderNo`/`customerName`/`departDate` **逐字相同**。
### 15. 整团确认需求缺失预检 `GET /v3/admin/order/group-batch/{groupBatchId}/requirement/confirm-check`
**VO**: `GroupBatchRequirementCheckRespVO`
#### 使用场景
点「整体确认需求」之前的预检。本单起外层多出 `checkedResourceTypes` 与 `batchStatusName`,缺失项多出 `customerName` 与 `reasonName`。
#### 入参字段表
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|------|------|------|------|------|------|
| groupBatchId | Path | Long | ✅ | 团期聚合主键 | 本单不变 |
#### 出参字段表
| 字段 | 类型 | 说明 |
|------|------|------|
| checkedResourceTypes | String[] | **本单新增**。本期**恒 `["HOTEL"]`**,由服务端常量给出。🔴 预检**只检查住宿、不检查用车**——`ready=true` **不代表**用车需求齐备 |
| batchStatusName | String | **本单新增**。团期状态中文名;`batchStatus` 为 `null` 时为 `null`,不在九态内时回落原 code |
| missing[].customerName | String | **本单新增**。客户姓名(`order_main.customer_name`),运营据此直接认出是哪一户 |
| missing[].reasonName | String | **本单新增**。未提报 / 缺房型或房数 / 需求结构异常 / 住宿晚数对不上 / 晚序号异常。`reason` 为 `null` 时为 `null`,不在五值内时回落原 code |
| (其余字段) | — | **全部不变**,本单不改动任何既有字段的名称、类型、取值与 null 语义 |
#### 请求示例
```http
GET /v3/admin/order/group-batch/2096412454643802114/requirement/confirm-check
Authorization: Bearer <admin token>
```
#### 响应示例
```json
{
"code": 200,
"message": "成功",
"data": {
"groupBatchId": "2096412454643802114",
"batchStatus": "RESOURCE_PREPARING",
"batchStatusName": "资源准备中",
"ready": false,
"checkedResourceTypes": ["HOTEL"],
"missing": [
{
"orderId": "2096655509804187650",
"orderNo": "HL20260907014322086",
"customerName": "沈怀妍",
"consultantId": "1001",
"consultantName": "admin",
"reason": "NOT_SUBMITTED",
"reasonName": "未提报"
}
]
},
"success": true
}
```
#### 空数据 / 降级响应
无缺失户时 `missing` 为空数组、`ready` 由阶段判定;`checkedResourceTypes` **无论如何都是 `["HOTEL"]`**(不随团期配置变化)。
#### 错误响应
| 码 | 符号 | 触发 |
|----|------|------|
| 不变 | `GROUP_BATCH_NOT_FOUND`(589500) | 团期不存在 / 非团期 / 已软删 |
| 不变 | `GROUP_BATCH_PERMISSION_DENIED`(589507) | 无 `group-batch:view` 权限 |
```json
{
"code": 589500,
"message": "团期不存在",
"data": null,
"traceId": null,
"success": false
}
```
#### 业务边界
- 🔴 `checkedResourceTypes` 存在的**全部理由**就是让前端知道「`ready=true` 只说明住宿齐了」。扩到用车是另一张单,届时本字段变成 `["HOTEL","VEHICLE"]`。
- 本单**不扩大检查范围**,预检行为一行未改。
### 16. 调整团期满团名额 `PUT /v3/admin/order/group-batch/{groupBatchId}/capacity`
**VO**: `GroupBatchCapacityRespVO`
#### 使用场景
调整满团户数。本单起响应多出 `groupBatchId`。
#### 入参字段表
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|------|------|------|------|------|------|
| groupBatchId | Path | Long | ✅ | 团期聚合主键 | 本单不变 |
| capacityDelta | Body | Integer | ✅ | 净增量(户),不得为 0 | 本单不变 |
#### 出参字段表
| 字段 | 类型 | 说明 |
|------|------|------|
| groupBatchId | String | **本单新增**。与 `batchId` **逐字同值**,同为字符串形态。⚠️ 它是**派生只读字段**(由 `batchId` 现算),因此两者**不可能分叉** |
| batchId | String | **值不变**,本单起标 `@Deprecated`,本批**不删**;新代码请改读 `groupBatchId` |
| (其余字段) | — | **全部不变**,本单不改动任何既有字段的名称、类型、取值与 null 语义 |
#### 请求示例
```http
PUT /v3/admin/order/group-batch/2097498512387104770/capacity
Content-Type: application/json
{"capacityDelta": 1}
Authorization: Bearer <admin token>
```
#### 响应示例
```json
{
"code": 200,
"message": "成功",
"data": {
"batchId": "2097498512387104770",
"groupBatchId": "2097498512387104770",
"beforeMaxRooms": 4,
"maxRooms": 5,
"capacityDelta": 1,
"enrolledRooms": 4,
"remainRooms": 1
},
"success": true
}
```
#### 空数据 / 降级响应
失败时 `data` 为 `null`(与改前一致),新增字段随之不出现。
#### 错误响应
| 码 | 符号 | 触发 |
|----|------|------|
| 不变 | 589538 | 非招募中阶段不可调 |
| 不变 | 589539 | 名额调整量不能为 0 |
| 不变 | 589509 | 新满团户数低于已报名户数或为负 |
| 不变 | 589540 | 产品域库存同步失败 |
```json
{
"code": 589539,
"message": "名额调整量不能为 0",
"data": null,
"traceId": null,
"success": false
}
```
#### 业务边界
- 本单**只加返回字段**,名额调整的权限门、阶段门、库存同步逻辑一行未改。
### 17. 团期人员配置列表 `GET /v3/admin/group-batch/{productBatchId}/staff`
**VO**: `List<BatchStaffConfigRespVO.BatchStaffItemVO>`
#### 使用场景
团期已配人员名册(**裸数组、无顶层信封**,本单不改其形态)。本单起每行多出 `staffRoleName` 与报账人两字段。
#### 入参字段表
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|------|------|------|------|------|------|
| productBatchId | Path | Long | ✅ | 产品侧班期 ID | 本单不变 |
#### 出参字段表
| 字段 | 类型 | 说明 |
|------|------|------|
| staffRoleName | String | **本单新增**。角色中文名(领队/司机/导游/摄影/其他/导游助理/研学老师/生活老师);`staffRole` 为 `null` 时为 `null`,不在枚举内时回落原 code |
| reporterRank | String | **本单新增**。报账人等级 `PRIMARY` 主 / `SECONDARY` 次 / `NONE` 非报账人。**本端点恒非 `null`**(历史空值归一为 `NONE`) |
| reporterRankName | String | **本单新增**。主报账人 / 次报账人 / 非报账人;与 `reporterRank` 同生同灭 |
| (其余字段) | — | **全部不变**,本单不改动任何既有字段的名称、类型、取值与 null 语义 |
#### 请求示例
```http
GET /v3/admin/group-batch/2052935476557328386/staff
Authorization: Bearer <admin token>
```
#### 响应示例
```json
{
"code": 200,
"message": "成功",
"data": [
{
"id": "2098667039013941249",
"staffId": 1002,
"staffRole": "GUIDE",
"staffRoleName": "导游",
"staffName": "李雪梅",
"staffPhone": "138****1002",
"sortOrder": 0,
"reporterRank": "PRIMARY",
"reporterRankName": "主报账人"
}
],
"success": true
}
```
#### 空数据 / 降级响应
未配置任何人员时返回空数组 `[]`(与改前一致)。
#### 错误响应
| 码 | 符号 | 触发 |
|----|------|------|
| 不变 | 400 | `productBatchId` 非法 |
```json
{
"code": 400,
"message": "参数校验失败",
"data": null,
"traceId": null,
"success": false
}
```
#### 业务边界
- 🔴 本端点返回**裸数组、没有顶层信封**,因此**不带** `productBatchId` / `groupBatchId`。包信封是结构变更(破坏性),另有工单跟进。
- `reporterRank` 由 `PUT .../staff/{staffId}/reporter-rank` 设置,本单未改那个写端点一行。
### 18. 团期人员配置全量保存 `PUT /v3/admin/group-batch/{productBatchId}/staff`
**VO**: `BatchStaffConfigRespVO`
#### 使用场景
全量保存团期人员配置。本单起响应顶层多出 `productBatchId`/`groupBatchId`,`staffList[]` 每项多出 `staffRoleName` 与报账人两字段。
#### 入参字段表
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|------|------|------|------|------|------|
| productBatchId | Path | Long | ✅ | 产品侧班期 ID | 本单不变 |
| staffList | Body | Array | ✅ | 全量配置(传空数组 = 清空) | 本单不变 |
#### 出参字段表
| 字段 | 类型 | 说明 |
|------|------|------|
| productBatchId | String | **本单新增**(顶层)。直接回显路径参数,**恒非 `null`** |
| groupBatchId | String | **本单新增**(顶层)。由 `productBatchId` 反查得到。⚠️ **本端点的 200 响应中恒非 `null`**——入口第一道守卫就是成团校验(未建团 589553 / 未成团或已流团 589552),团期不存在时根本返不到这里 |
| staffList[].staffRoleName / reporterRank / reporterRankName | String | **本单新增**,口径同上一个端点;新配的人 `reporterRank` 为 `NONE` |
| (其余字段) | — | **全部不变**,本单不改动任何既有字段的名称、类型、取值与 null 语义 |
#### 请求示例
```http
PUT /v3/admin/group-batch/2052935476557328386/staff
Content-Type: application/json
{"staffList": [{"staffId": 1002, "staffRole": "GUIDE", "sortOrder": 0}]}
Authorization: Bearer <admin token>
```
#### 响应示例
```json
{
"code": 200,
"message": "成功",
"data": {
"productBatchId": "2052935476557328386",
"groupBatchId": "2096412454643802114",
"staffList": [
{
"id": "2098667039013941249",
"staffId": 1002,
"staffRole": "GUIDE",
"staffRoleName": "导游",
"staffName": "李雪梅",
"reporterRank": "NONE",
"reporterRankName": "非报账人"
}
],
"affectedOrderCount": 55
},
"success": true
}
```
#### 空数据 / 降级响应
传空数组 = 清空配置,`staffList` 返回空数组,两个顶层 ID 照常有值。
#### 错误响应
| 码 | 符号 | 触发 |
|----|------|------|
| 不变 | 589553 | 团期尚未创建(该班期还没有任何订单) |
| 不变 | 589552 | 团期未成团或已流团 |
| 不变 | 589582 | 请求体内 `staffId` 重复 |
| 不变 | 582114 | 角色与人员类型不符 |
```json
{
"code": 589553,
"message": "团期尚未创建(该班期还没有任何订单),请先建团并完成成团后再操作",
"data": null,
"traceId": null,
"success": false
}
```
#### 业务边界
- 🔴 **未建团时本端点返 589553,不是 200**——这是工单 #7287 T5 定的**既有守卫**,本单未改。想在成团前拿团期 ID,用候选端点。
- 反查团期用的是**入口守卫已经查过的那一次**结果,**新增查询数为 0**。
### 19. 团期人员配置候选列表 `GET /v3/admin/group-batch/{productBatchId}/staff/candidates`
**VO**: `List<StaffCandidateRespVO>`
#### 使用场景
「配置导游 / 配置摄影」弹窗的人员资源库。本单起每项多出 6 个 key。
#### 入参字段表
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|------|------|------|------|------|------|
| productBatchId | Path | Long | ✅ | 产品侧班期 ID | 本单不变 |
| role | Query | String | ✅ | `GUIDE` 导游位 / `PHOTOGRAPHER` 摄影位 | 本单不变 |
#### 出参字段表
| 字段 | 类型 | 说明 |
|------|------|------|
| productBatchId | String | **本单新增**。直接回显路径参数,**恒非 `null`** |
| groupBatchId | String | **本单新增**。由 `productBatchId` 反查。🔴 **团期尚未创建时为 `null`**(staff 允许在成团前先配,本端点**不报错**、返 200)。**前端不得把它当必有主键去拼后续请求**,否则会打出 `/group-batch/null/...` |
| staffTypeName | String | **本单新增**。人员类型中文名;`staffType` 为 `null` 时为 `null`,不在枚举内时回落原 code |
| assignedRoleName | String | **本单新增**。已选角色中文名;`assignedRole` 为 `null` 时为 `null` |
| reporterRank | String | **本单新增**。⚠️ **未进入本团期名册的候选为 `null`,不是 `NONE`**——`NONE` 的语义是「已在名册里、但不是报账人」,两者必须能区分 |
| reporterRankName | String | **本单新增**。与 `reporterRank` 同生同灭 |
| (其余字段) | — | **全部不变**,本单不改动任何既有字段的名称、类型、取值与 null 语义 |
#### 请求示例
```http
GET /v3/admin/group-batch/2052935476557328386/staff/candidates?role=GUIDE
Authorization: Bearer <admin token>
```
#### 响应示例
```json
{
"code": 200,
"message": "成功",
"data": [
{
"productBatchId": "2052935476557328386",
"groupBatchId": "2096412454643802114",
"staffId": 1002,
"staffName": "李雪梅",
"staffPhone": "138****1002",
"staffType": "GUIDE",
"staffTypeName": "导游",
"assigned": true,
"assignedRole": "GUIDE",
"assignedRoleName": "导游",
"reporterRank": "PRIMARY",
"reporterRankName": "主报账人"
},
{
"productBatchId": "2052935476557328386",
"groupBatchId": "2096412454643802114",
"staffId": 1010,
"staffType": "LEADER",
"staffTypeName": "领队",
"assigned": false,
"assignedRole": null,
"assignedRoleName": null,
"reporterRank": null,
"reporterRankName": null
}
],
"success": true
}
```
#### 空数据 / 降级响应
资源域无可用人员时返回空数组。团期尚未创建时 `groupBatchId` 为 `null`、HTTP 200、`code=200`(**不返 589500**)。
#### 错误响应
| 码 | 符号 | 触发 |
|----|------|------|
| 不变 | 582116 | `role` 不是 `GUIDE` / `PHOTOGRAPHER` |
| 不变 | `STAFF_INFO_FETCH_FAILED` | 资源域不可达 |
```json
{
"code": 582116,
"message": "候选角色非法",
"data": null,
"traceId": null,
"success": false
}
```
#### 业务边界
- 🔴 **`reporterRank` / `assignedRole` 是【本团期名册】维度,`assigned` 是【本配置位】维度,两者口径不同。** 一个被配到**另一个位**上的人,在本位会是 `assigned=false` 但 `reporterRank` 非 `null`——这是对的,不是 bug。
- 整批**只反查一次**团期,不是每个候选一次。
---
## 四、契约约束与正确调用方式
1. **不需要改任何调用代码即可继续工作**。本批是纯增,未消费新字段的页面行为完全不变。
2. **`opsStage` 直接读,不要自己折桶**。服务端八桶的唯一真源是 `GroupBatchStageBuckets`;前端复刻一份,规则一改就和**入参筛选** `opsStage` 的结果对不上。
3. **同值字段对二选一即可**,不要两个都渲染:
`batchStatusLabel`↔`batchStatusName`、`productBatchStatusLabel`↔`productBatchStatusName`、
`statusText`↔`statusName`、`bizTypeText`↔`bizTypeName`、`contactName`↔`customerName`、
`batchId`↔`groupBatchId`、`totalReceivable`↔`receivableAmount`、`totalReceived`↔`receivedAmount`。
服务端保证每一对**在同一次响应里逐字相同**(同一表达式/同一变量赋值,或派生只读字段)。
4. **`teamNo` 按 `null` 判空即可**,不必区分 `""`——后端永远不返空串。也**不要**用 `teamNo != null` 判断是不是团期单,那会两个方向都判错。
5. **审批中心统一列表按 `bizType` 分支渲染**:`DISBAND` 行的 `orderId` / `orderNo` / `customerName` / `departDate` 恒 `null`。
6. **staff 候选端点的 `groupBatchId` 可能为 `null`**,拿它拼后续请求前必须判空。
---
## 五、数据库行为
**本单零数据库变更**:无新增 / 修改表、无新增列、无新增索引、**无 Flyway 迁移脚本**、无新增 Mapper 方法。
清单里的两个写端点(16 `PUT .../capacity`、18 `PUT .../staff`)**写库行为一行未改**,本单只是在它们返回前多填了展示字段:
- `PUT .../capacity` 的 `groupBatchId` 是**派生只读字段**,由已有的 `batchId` 现算,不读库;
- `PUT .../staff` 的两个顶层 ID 复用**入口成团守卫已经查过的那一次** `getByProductBatchId` 结果,**新增查询数为 0**。
唯一的 Mapper 改动是给**两条既有列受限投影**各加一个已有列:
`OrderInfoMapper.selectChipProjectionByProductBatchIds` 与 `selectContractPanelProjectionByProductBatchIds`
各加一个 `OrderInfo::getTeamNo`(映射 `order_main.team_no`,**非加密列**,不触发逐行解密)。
`git diff` 上该文件**只有两行新增、无第三个 hunk**。
新增字段的取数全部**零新增查询**:
- 团号来自上述两条**已有**的批量投影;
- 芯片负责人的团级指针来自 `chipDetail` 里**已在手**的团期实体;
- 冻结名单每次请求读 1 次(按 `groupBatchId` 单表命中),**名单为空时短路掉**户级需求那次查询;
- 审批列表整页**一次**批量取单,页内无 `WITHDRAW` 行时**一次都不取**;
- staff 报账人来自**已有**的名册查询。
---
## 六、边界行为
| 场景 | 行为 |
|---|---|
| `batch_status` 是九态之外的脏值 / 为 `null` | 该行 `opsStage` 与 `opsStageName` **同为 `null`**,`batchStatus` / `batchStatusName` 照旧;**整页不会 500** |
| 未建团行(产品有班期、订单侧无团期) | `batchStatus=RECRUITING` → `opsStage=RECRUIT`/招募中,走同一条折桶、不特判 |
| 整团未认领(`house_claimer_id IS NULL`) | 芯片逐户 `claimerId`/`claimerName`/`claimerSource` **三者全为 `null`**,不是空串、不是 0 |
| 该户在历史旧户冻结名单内 | 读该户 `order_hotel_requirement.claimer_id`,`claimerSource=LEGACY`;户级也为空则三者整体 `null`(**不回落团级**) |
| 超管接管后 CAS 落空、户级残留旧人 | 该户不在冻结名单里,按定案显示**团级新接管人** + `claimerSource=BATCH`。这是对的:团级指针是唯一真源,户级残留是待清理脏数据 |
| 订金未支付成功 | `teamNo` 为 `null`(**不是空串、不回退成 `orderNo`**);同团其他已付订金的户照常有值 |
| 审批行是 `DISBAND` | `orderNo` / `customerName` / `departDate` 恒 `null`,该行**照常返回、不漏行、不报错** |
| 审批行是 `WITHDRAW` 但订单/团期已软删 | 三个字段为 `null`,该行照常返回;**统一列表与退单专用列表给出相同的 `null`** |
| 页内一条 `WITHDRAW` 都没有 | 后端**一次订单查询都不发** |
| 任一 code 为 `null` | 对应的 `Name` 为 `null`(**不造空串**) |
| 任一 code 不在枚举内 | 对应的 `Name` **回落原 code**(不抛异常、不返空串);`opsStage` 是唯一例外——它回落 `null`,因为八桶取值集是前端页签,透一个不存在的值出去会渲染出不存在的页签 |
| 应收 / 已收任一为 `null` | 按 `0` 参与计算,`unpaidAmount` 恒非 `null` |
| 已收 > 应收(退款/多收的历史脏数据) | `unpaidAmount` 返回 `0`,**不透负数** |
| staff 候选:团期尚未创建 | `groupBatchId` 为 `null`,HTTP 200 + `code=200`(**不返 589500**) |
| staff 候选:人已被配到**另一个位** | `assigned=false`(本配置位口径)但 `assignedRole` / `reporterRank` **非 `null`**(本团期名册口径)——两者口径不同,不是 bug |
| staff 候选:人还没进本团期名册 | `reporterRank` 为 `null`(**不是 `NONE`**) |
| staff 名册:`reporter_rank` 历史空值 | 归一为 `NONE` / 非报账人(名册端点**恒非 `null`**) |
## 六.6、修改前后对比
| 维度 | 改前 | 改后 |
|---|---|---|
| 团期分页项 `GroupBatchPageItemRespVO` | 27 个 key | **31 个 key**(+`opsStage`/`opsStageName`/`unpaidAmount`/`productBatchStatusName`) |
| 团期看板行 `GroupBatchBoardItemRespVO` | 27 | **30**(+`opsStage`/`opsStageName`/`batchStatusName`) |
| 团期详情 `GroupBatchDetailRespVO` | 43 | **48**(+`opsStage`/`opsStageName`/`receivableAmount`/`receivedAmount`/`thresholdSourceName`) |
| 芯片信封 `GroupBatchChipDetailVO` | 6 | **8**(+`aggregateStatusName`/`groupBatchId`) |
| 芯片逐户 `GroupBatchChipItemRespVO` | 8 | **14**(+`teamNo`/`customerName`/`statusName`/`claimerId`/`claimerName`/`claimerSource`) |
| 合同面板 `GroupBatchContractBoardVO` | 10 | **11**(+`groupBatchId`) |
| 合同逐户 `GroupBatchContractItemVO` | 15 | **17**(+`teamNo`/`customerName`) |
| 预检 `GroupBatchRequirementCheckRespVO` | 4 | **6**(+`checkedResourceTypes`/`batchStatusName`;`missing[]` 另 +2) |
| 统一审批行 `GroupBatchApprovalItemRespVO` | 14 | **19**(+`orderNo`/`customerName`/`departDate`/`approvalStatusName`/`bizTypeName`) |
| 退单行 `WithdrawApprovalItemRespVO` | 16 | **18**(+`refundModeName`/`approvalStatusName`) |
| staff 候选 `StaffCandidateRespVO` | 7 | **13**(+6) |
| **团期子订单项 `GroupBatchOrderItemRespVO`(A3)** | 29 | **29 —— 零变化** |
| 路径 / 方法 / 请求参数 | — | **完全不变** |
| 既有字段的名称 / 类型 / 取值 / null 语义 | — | **完全不变**(源码 diff 中零条字段删除或改名) |
| 错误码 | — | **无新增、无调整** |
| 数据库 / Flyway / 网关路由 | — | **零改动** |
## 六.7、影响评估
- **兼容性**:响应体**纯增**字段,未消费新 key 的前端页面**无需任何改动即可继续工作**。
- **需要前端动的**:
1. 团期列表 / 看板的「阶段」页签改读 `opsStage`,**删掉自己那套九态→八桶折叠**;
2. 报名清单「联系人」列改读 `customerName`(此前显示 `—` 是读错 key);
3. 芯片下钻逐户行可加「负责人」与「团号」两列;
4. 审批中心统一列表可加订单号 / 客户姓名 / 出发日三列(**按 `bizType` 分支渲染**);
5. 新代码逐步把四组 `Text`/`Label`/`batchId`/`total*` 旧名切到新名(**本批不强制,删除时间另行通知**)。
- **性能**:新增开销只有「每次芯片请求多读一次冻结名单(按 `groupBatchId` 单表命中,名单为空时到此为止)」与「审批列表整页一次批量取单(页内无 WITHDRAW 行则零次)」。
团号与负责人全部复用**已有**的批量投影与已在手的团期实体,**零新增查询**。
- **响应体积**:团期分页每行多 4 个 key、芯片逐户每户多 6 个 key。芯片明细端点返回全量逐户、没有分页,**几百户的团会多出上千个字段**,仍在 KB 量级、不触任何网关限制。
- **连带生效(无需单独对接)**:退单审批详情 `GET .../withdraw/{approvalId}` 的响应体继承自 `WithdrawApprovalItemRespVO`,**同样多出** `refundModeName` / `approvalStatusName`。
- **两个只读派生字段**:`GroupBatchCapacityRespVO.groupBatchId` 与 `GroupBatchDetailRespVO.thresholdSourceName` 是**只读派生 getter**(分别由 `batchId` 与 `thresholdSource` 现算)。对前端没有任何差别;对后端的意义是这两对 key **在结构上不可能分叉**。
---
## 七、不影响范围
- **团期子订单列表(A3)`GroupBatchOrderItemRespVO` 一个字段都没加**,改前改后 29 个 key 完全一致——它的 5 个裸 code 与 `roomTypeName` 归 #7536。
- **财务 tab 的 12 个金额字段 JSON 形态本批不变**(`GroupBatchFinanceRespVO` / `GroupBatchFinanceItemVO` 零改动),其变更由 #7536 交接。
- **「报名清单 / 财务 / 预支」三张表逐行的 `teamNo` 不在本批**,归 #7536;两批的字段名、类型与 null 语义完全一致。
- **`GET /v3/admin/group-batch/{productBatchId}/staff` 仍返回裸数组、不包顶层信封**(包信封属结构变更,另有工单)。
- **预检不扩到用车**:本批只是把「只检查住宿」这个事实透出成 `checkedResourceTypes`,检查行为一行未改。
- **小程序端(mp 域)全部 VO 不动**;**`/v3/internal/` 端点不动**。
- **零改动**:Controller 方法体、Entity、Flyway、错误码、hl-gateway 配置、其他微服务。
---
## 八、测试环境已验证
**部署**:`hl-order-service-v3` @ `dev-v3` / `bb68be409`(PR #7583 合并提交),双实例滚动重启完成。
**全部实测经真实网关 `api.test.1814.love:9443` + Bearer 鉴权。**
本单**零新增 Controller、零网关路由改动**,网关无需重滚。
| 验证点 | 结果 |
|---|---|
| 八桶三端点一致 | 团期 `2096412454643802114`(`RESOURCE_PREPARING`)在 A1 分页 / A2 详情 / 看板三处均 `opsStage=FORMED`、`opsStageName=已成团` |
| `FORMED` 复合桶 | `RESOURCE_PREPARING` 与 `MATERIAL_PREPARING` 两个团期同为 `FORMED`/已成团 |
| 芯片负责人(已认领) | 六个芯片端点逐户全部 `claimerId=30001` / `claimerName=验收房务甲` / `claimerSource=BATCH` |
| 芯片负责人(未认领) | 三个字段全为 `null` |
| 报账人 | 置 `PRIMARY` 前名册读到 `NONE`/非报账人,置后读到 `PRIMARY`/主报账人 |
| 候选 `reporterRank` | 未被本团期选中的 5 人全部 `null`(**不是 `NONE`**);已选未任报账人的返 `NONE`/非报账人 |
| 审批统一列表 vs 退单列表 | 同一审批单 `orderNo`/`customerName`/`departDate` **三项逐字相同**(2 条正向 + 1 条降级态同为 `null`) |
| DISBAND 行 | 一页 38 行(34 DISBAND / 4 WITHDRAW),**34 行三字段全 `null`、零漏行、零报错** |
| 预检 | 4 个团期均返 `checkedResourceTypes=["HOTEL"]`,`missing[]` 每项带 `customerName` 与 `reasonName` |
| 后缀四处同值 | 芯片 55 户 `statusText==statusName`;A1 17 行 `productBatchStatusLabel==productBatchStatusName`;看板与审批同理 |
| 联系人四处同值 | 芯片 / 合同 / 行程下钻实测逐户 `customerName==contactName` |
| 团期 ID 三处同值 | 名额调整 / 芯片详情 / 合同面板 `groupBatchId==batchId`,**均为字符串形态** |
| 金额 | 详情两对逐字同值;A1 全 28 行 `unpaidAmount == max(0, 应收−已收)` **零例外** |
| `teamNo` 正负 | 同一团期一户 `26-9069`、三户 `null`,芯片与合同两端点一致;`orderNo` 同一对象里照常非空 |
| staff 候选未建团 | `groupBatchId=null`,HTTP 200 + `code=200`(**不返 589500**) |
| **零破坏(真·双部署对拍)** | 同一台 TEST 上先后部署 `93bd823b4`(合入前)与 `bb68be409`(合入后),逐端点抓取响应并摊平成规范化字段路径做集合对拍:**20 个端点删除字段路径 = 0**,新增 +90;另用同 commit 重跑一趟作对照组,键集漂移 = 0。A3 `GET .../{groupBatchId}/orders` **新增 0 / 删除 0 / 值变 0** |
**本地全量**:
- 第一遍(排除 `*IT` / `*IntegrationTest` / `*MysqlTest` / `*MysqlMigrationTest`):`Tests 9800 / Failures 0 / Errors 52 / Skipped 8`
- 第二遍(只跑上面排除的类,每类独立 JVM):`Tests 308 / Failures 0 / Errors 9 / Skipped 41`
- 两遍 61 个 Errors **全部既存或环境所致**(`SignVoucherServiceTest` 48 例是 `dev-v3` 上既存的测试间污染;其余 13 例全是 `Could not find a valid Docker environment`)。与 `dev-v3` 基线逐类一致,**本单净增 249 例、零新增失败**。
- ArchUnit 全绿:`HouseModuleBoundaryArchTest` 4/0(本单新引入中立包依赖的专项)、`RedLineArchTest` 12/0、`MapperBoundaryArchTest` 26/0、`LayerEnforcementTest` 5/0。
---
## 十、相关文档
- Issue:https://git.1814.love:8443/wx/HL/issues/7535
- PR:https://git.1814.love:8443/wx/HL/pulls/7583
- API-SPEC §17.1 / §17.2 字段清单已同步:`docs/order-v3/api/API-SPEC.html`
- 团期接口文档「已落地清单」已登记:`docs/group/团期模块接口文档-v2.0.html` §0A.10
- 八桶唯一真源:`hl-order-service-v3/src/main/java/com/hulalv/order/groupbatch/helper/GroupBatchStageBuckets.java`
- 团号生成器:`hl-order-service-v3/src/main/java/com/hulalv/order/core/service/GroupCodeService.java`
---
## 关联 / 联系人
- 后端:jw
- 前端(hl-ui 管理后台):mmg
- 需求定案:wx(2026-09-11:「原型上有的必须有;可以多给;不能加离谱的字段」「后缀统一为 Name」「opsStage 以后端八桶为准,原型侧改」)
- ⚠️ **待 mmg 确认**:原型侧的 8 个 stage 取值与后端八桶的重合度是 wx 口述、撰写工单时未核对原型文件。本批以后端八桶为准,原型侧需按上表 8 个取值调整。