docs(8478): 团期详情新增分叉进度条 progressStepper,附前端交接清单
changelog-filename-gate / validate (push) Failing after 1s

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
这个提交包含在:
jw
2026-09-28 16:33:03 +08:00
共同撰写人 Claude Opus 5.5
父节点 8cf973dcb0
当前提交 deb65b63ec
@@ -0,0 +1,401 @@
---
schema: "hl-changelog/v2"
ticket: "8478"
title: "团期详情新增分叉进度条 progressStepper,配置段拆配房、配车、配导游、配摄影、配物资五条分支"
consumer: "admin"
author: "jw(GIT)"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "pending"
frontend_owner: ""
frontend_ref: ""
target_release: ""
verified_at: ""
status_note: "PR #8480 已合入 dev-v3(49777861b),TEST 的 hl-order-service-v3 运行 dev-v3 49777861b;经网关 api.test.1814.love 用真实 admin token 实测招募、配置、确认、出行三态、核单、结算、已流团各状态,以及整团免车与无需导摄,全部通过。前端需接:详情页头用 progressStepper 画分叉进度条替换直线步骤条,页头加「未设置主报账人」标签,去掉「团期尚不满足确认条件」横幅、查看需求「仍有子订单需求缺失」提示块、总览「资源与单据」卡片(见第四节前端交接清单),故 frontend_status 记 pending。"
updated_at: "2026-09-28"
base: "dev-v3"
---
# 团期详情:新增分叉进度条 progressStepper(管理后台)
> **服务**: hl-order-service-v3(端口 8086)
> **PR**: #8480(合入 dev-v3 为 `49777861b`)
> **Issue**: #8478
> **日期**: 2026-09-28
> **影响范围**: 团期详情页页头进度条、确认缺项提示、查看需求提示块、总览「资源与单据」卡片
---
## ⚠️ 关键变化
1. **团期详情新增 `progressStepper`**:6 个主节点(招募 / 配置 / 确认 / 出行 / 核单 / 结算),「配置」节点下带 5 条分支(配房 / 配车 / 配导游 / 配摄影 / 配物资),字段名与订单详情的 `progressStepper` 一致,订单详情的分叉图组件可以直接复用。
2. **分支有四种状态**:`WAITING` 待开始 / `UNMET` 未配齐(物资为「未确认」)/ `WAIVED` 无需或整团免车 / `DONE` 已完成(物资为「已确认」)。「无需」「整团免车」由后端判定,前端**不要**再用 `hotelReady` 等五个布尔自己拼。
3. **已流团时 `progressStepper` 是空数组 `[]`**(不是 null),前端照旧显示「已流团」标签。
4. **主报账人两个字段只改了说明**:`primaryReporterId` / `primaryReporterName` 早已有值(团期人员配置里 `reporter_rank=PRIMARY` 的人,未设置为 null)。原 swagger 写的「P10 未落,暂返 null」已过时,取值没有变化。
5. **前端要配合的改造**见第四节「前端交接清单」:用进度条替换页头的「团期尚不满足确认条件」横幅,页头加「未设置主报账人」标签,去掉查看需求的「仍有子订单需求缺失」提示块和总览「资源与单据」卡片。
---
## 一、背景
团期详情页现有两块缺项提示内容重复且很长:
- 页头「团期尚不满足确认条件」横幅(#8410):12 户的团就逐户列 12 行。
- 「查看需求」页签的「仍有子订单需求缺失,暂不能整团确认」提示块。
逐户缺项在「查看需求」表格的「需求审核」「需求状态」两列里已经有了。jw 2026-09-28 定案:
- 两块提示都去掉;
- 团级五项改成和订单详情一样的分叉进度条;
- 导游 / 摄影不需要、或整团免车时,要显示「无需」「整团免车」;
- 「未设置主报账人」放在页头状态标签左侧,主报账人**不**作为分支。
「无需」的来源散在三处,前端只靠现有字段判不准,所以由后端统一派生:
| 分支 | 「无需」怎么来 | 前端自己判会踩的坑 |
|------|--------|--------|
| 导游 / 摄影 | 团期 `needs_guide` / `needs_photographer` | 这两列**只在成团时写入,招募阶段恒为 0**,直接用会把招募团显示成「无需」 |
| 车 | 团级用车需求上的「整团免车」声明(成团后声明,可撤销) | 团期详情原本没有这个信息 |
| 房、物资 | 没有免除 | — |
另外,总览「资源与单据」卡片读的是 `detail.chips`,但团期详情从来没有返回过 `chips`,那 6 张卡一直显示灰色「待办」,本次一并让前端去掉。
---
## 二、变更接口清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|------|------|------|----------|------|
| 1 | 团期详情 | GET | `/v3/admin/order/group-batch/{groupBatchId}` | 出参新增字段 | 新增 `progressStepper`;更正 `primaryReporterId` / `primaryReporterName` 的说明(取值不变) |
---
## 三、接口详情
### 1. 团期详情 `GET /v3/admin/order/group-batch/{groupBatchId}`
**VO**: `GroupBatchDetailRespVO`(新增嵌套 `GroupBatchProgressNodeVO`、`GroupBatchProgressSubFlowVO`)
#### 使用场景
团期详情页进入时调用(A2,GB-ADM-002),已有调用点不变。本次新增的 `progressStepper` 供页头画分叉进度条,替换现在的直线步骤条和「团期尚不满足确认条件」横幅。
#### 入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|------|------|------|------|------|------|
| groupBatchId | Path | String | ✅ | 团期主键(雪花 ID,按字符串传) | 团期 ID |
#### 出参 `Result<GroupBatchDetailRespVO>`
以下只列本次新增或改了说明的字段,其余字段与改前完全一致。
| 字段 | 类型 | 说明 |
|------|------|------|
| progressStepper | Array<Object> | 团期进度条。非流团时恒为 6 个主节点,按 `step` 1~6 排列;已流团、或 `batchStatus` 为空 / 认不出时为空数组 `[]` |
| progressStepper[].step | Integer | 节点序号 1~6 |
| progressStepper[].code | String | 节点编码:`RECRUIT` / `CONFIGURE` / `CONFIRM` / `TRIP` / `REVIEW` / `SETTLE`,与详情已有的 `stage` 是同一套取值 |
| progressStepper[].name | String | 节点名称:招募 / 配置 / 确认 / 出行 / 核单 / 结算 |
| progressStepper[].status | String | 节点状态:`DONE` 已过 / `PROCESSING` 进行中 / `WAITING` 未到。已结算团的结算节点是 `DONE` |
| progressStepper[].label | String | 当前节点的标签:招募中 / 配置中 / 已确认 / 待出发、出行中、已返团(出行节点取出行子状态)/ 核单中 / 已结算;非当前节点为 null |
| progressStepper[].isCurrent | Boolean | 是否当前节点,恰有一个为 true,其 `code` 等于同一响应的 `stage` |
| progressStepper[].subFlows | Array<Object> | 分支列表。只有 `CONFIGURE` 节点有值(固定 5 条),其余节点为 null |
| progressStepper[].subFlows[].code | String | 分支编码,固定顺序:`HOTEL` / `VEHICLE` / `GUIDE` / `PHOTOGRAPHER` / `MATERIAL` |
| progressStepper[].subFlows[].name | String | 分支名称:配房 / 配车 / 配导游 / 配摄影 / 配物资 |
| progressStepper[].subFlows[].status | String | 分支状态:`WAITING` / `UNMET` / `WAIVED` / `DONE`,判定规则见第六.5 节 |
| progressStepper[].subFlows[].statusName | String | 状态名:待开始 / 未配齐(物资为未确认)/ 无需、整团免车 / 已完成(物资为已确认) |
| progressStepper[].subFlows[].displayText | String | 可直接展示的文案,「名称·状态名」,如 `配车·整团免车` |
| primaryReporterId | String | **说明更正,取值不变**:团期人员配置里 `reporter_rank=PRIMARY` 那个人的 staffId;团期未设置主报账人时为 null |
| primaryReporterName | String | **说明更正,取值不变**:同一个人的姓名(配置时的快照);未设置时为 null |
#### 请求示例
```http
GET /v3/admin/order/group-batch/2104327837991518210
Authorization: Bearer <admin token>
```
#### 响应示例
TEST 实测:整团免车团,配置阶段。其余字段省略。
```json
{
"code": 200,
"message": "成功",
"success": true,
"data": {
"groupBatchId": "2104327837991518210",
"batchStatus": "RESOURCE_PREPARING",
"stage": "CONFIGURE",
"hotelReady": false,
"vehicleReady": true,
"guideReady": true,
"photographerReady": true,
"materialConfirmed": false,
"primaryReporterId": null,
"primaryReporterName": null,
"progressStepper": [
{ "step": 1, "code": "RECRUIT", "name": "招募", "status": "DONE", "label": null, "isCurrent": false, "subFlows": null },
{
"step": 2, "code": "CONFIGURE", "name": "配置", "status": "PROCESSING", "label": "配置中", "isCurrent": true,
"subFlows": [
{ "code": "HOTEL", "name": "配房", "status": "UNMET", "statusName": "未配齐", "displayText": "配房·未配齐" },
{ "code": "VEHICLE", "name": "配车", "status": "WAIVED", "statusName": "整团免车", "displayText": "配车·整团免车" },
{ "code": "GUIDE", "name": "配导游", "status": "WAIVED", "statusName": "无需", "displayText": "配导游·无需" },
{ "code": "PHOTOGRAPHER", "name": "配摄影", "status": "WAIVED", "statusName": "无需", "displayText": "配摄影·无需" },
{ "code": "MATERIAL", "name": "配物资", "status": "UNMET", "statusName": "未确认", "displayText": "配物资·未确认" }
]
},
{ "step": 3, "code": "CONFIRM", "name": "确认", "status": "WAITING", "label": null, "isCurrent": false, "subFlows": null },
{ "step": 4, "code": "TRIP", "name": "出行", "status": "WAITING", "label": null, "isCurrent": false, "subFlows": null },
{ "step": 5, "code": "REVIEW", "name": "核单", "status": "WAITING", "label": null, "isCurrent": false, "subFlows": null },
{ "step": 6, "code": "SETTLE", "name": "结算", "status": "WAITING", "label": null, "isCurrent": false, "subFlows": null }
]
}
}
```
招募阶段的团,5 条分支都是 `{"status": "WAITING", "statusName": "待开始"}`,`RECRUIT` 为当前节点,label「招募中」。
#### 空数据 / 降级响应
已流团(`batchStatus=CANCELLED`),或 `batchStatus` 为空 / 认不出时,`progressStepper` 为空数组,详情其余字段照常返回:
```json
{
"code": 200,
"success": true,
"data": { "batchStatus": "CANCELLED", "stage": "DISBANDED", "stageName": "已流团", "progressStepper": [] }
}
```
#### 错误响应
与改前一致,本次没有新增错误码。
```json
{ "code": 589500, "message": "团期不存在", "data": null, "success": false }
```
```json
{ "code": 401, "message": "缺少有效的 Authorization 头", "data": null }
```
| 场景 | 返回 |
|------|------|
| 团期不存在 / 已删除 | `589500 团期不存在` |
| 未带或带了无效 token | 网关约定:HTTP 200,响应体 `code: 401` |
#### 业务边界
- 判权、入参、其余出参都与改前一致;本次只加了一个字段。
- `progressStepper` **只供展示**。确认按钮能不能点,仍以确认预检 `GET .../confirm-check` 的 `ready` 为准;阶段判断仍以 `batchStatus` 为准。
- 配置阶段(`RESOURCE_PREPARING`)里,分支为 `UNMET` 的项,就是确认预检 `batchItems` 里同一项 `passed=false`(两边读同一组标记,TEST 上 9 个配置阶段团逐项核对一致)。招募阶段分支一律显示「待开始」,预检这时 `statusConfirmable=false`,两者不做一一对应。
- 分支状态是实时派生的:管理员确认物资、配齐房车、声明或撤销整团免车后,重新拉一次详情就会变。
- 只读:接口不写库。只有「非招募、非流团、车已就绪」时才多查一次本库,判断整团免车声明。
---
## 四、契约约束与正确调用方式
本接口是 GET,没有请求体。下表是消费出参的正确方式。
### ✅ 正确 / ❌ 错误用法对照
| 场景 | 做法 |
|------|------|
| ✅ 画进度条 | 按数组顺序(即 `step`)画 6 个节点,带 `subFlows` 的节点画成分叉 |
| ✅ 分支文案 | 直接用 `displayText`,或 `name + "·" + statusName` |
| ✅ 分支颜色 | 按 `status` 四值分:`DONE` 完成色、`WAIVED` 完成色的弱化版(建议灰色勾)、`UNMET` 警示色(橙)、`WAITING` 灰 |
| ✅ 已流团 | `progressStepper` 为 `[]` 时不画进度条,显示「已流团」标签 |
| ❌ 用 `hotelReady` 等五个布尔自己拼分支 | 判不出「无需」「整团免车」,招募团还会被误判 |
| ❌ 写死订单进度条的节点编码(`PROFILE` / `RESOURCE` / `DEPART`) | 团期节点编码是 `RECRUIT` / `CONFIGURE` / `CONFIRM` / `TRIP` / `REVIEW` / `SETTLE` |
| ❌ 用 `progressStepper` 判断能否确认 | 能否确认只看 `confirm-check` 的 `ready` |
### 前端交接清单
行号按 hl-ui `origin/v2.1@501c4258`。
1. **分叉进度条**:通用化 `src/views/order-v2/detail/components/ForkStepBar.vue`,只加可选参数,订单页行为不变。
- 节点从传入数组读:首节点、带 `subFlows` 的分叉节点、其后各节点,不再写死订单的节点编码;首节点文字可配(团期为「招募」)。
- 支持 5 条分支的高度。现在 3 条及以上是 132px,5 条时间隔约 23px 会重叠,建议约 200px。
- 新增 `UNMET` 橙色样式和 `WAIVED` 样式;补 `MATERIAL` 图标。
- 用它替换 `batch/detail/components/BatchHero.vue` 的直线步骤条 `batch-hero__steps`,数据直接取 `detail.progressStepper`;为 `[]` 时照旧显示「已流团」标签。
- 点击分支跳到对应页签(配房 / 配车 / 配导游 / 配摄影 / 物资),用 `index.vue` 现有的 `onGotoChip`。
2. **页头主报账人提示**:`BatchHero.vue` 右上 `batch-hero__stat` 里、状态标签左边,`!detail.primaryReporterId && detail.batchStatus !== 'CANCELLED'` 时显示橙色标签「未设置主报账人」,点击打开现有的 `ReporterRankModal`(`index.vue` 的 `reporterShow`)。主报账人**不**作为分支。
3. **删掉页头横幅**:`batch/detail/index.vue:94-126` 的「团期尚不满足确认条件」`n-alert` 与 `showConfirmCheckBanner`。**保留** `loadConfirmCheck` 预检(确认按钮置灰靠它);`index.vue:951` 的提示「请核对下方缺项清单」改为不指向已删除的清单。
4. **删掉查看需求提示块**:`RequirementTab.vue:97-133`「仍有子订单需求缺失,暂不能整团确认」。「豁免户」「接送机缺口」两块提示、头部「预检:缺失 x 户」小字、表格「需求审核」「需求状态」两列都保留。
5. **删掉总览「资源与单据」卡片**:`batch/detail/components/OverviewTab.vue:56-79`。详情从未返回 `chips`,这 6 张卡一直是灰色「待办」。
6. **设完主报账人后重新预检**:`index.vue:842` 的 `onReporterSaved` 目前只重拉详情,要补调 `loadConfirmCheck()`;否则设完主报账人,确认按钮仍按旧预检结果置灰,要刷新页面才恢复。
7. **单测同步**:`batch/detail/__tests__/index.spec.js:271-355` 里对横幅的断言,以及 `RequirementTab` / `OverviewTab` 相关断言。
8. **可选**:去掉横幅后,逐户的「未付订金」「合同模板未设置」在「查看需求」里看不到(前者在财务页签能看到)。如果想在确认按钮置灰时告诉用户原因,可以给按钮加悬停提示,内容直接用预检的 `gateMessage`,不需要新接口。
---
## 五、数据库行为
本接口只读,零写入、零 DDL。数据来源都是既有列:
| 读什么 | 来源 |
|--------|------|
| 节点 | `order_group_batch.batch_status` |
| 分支标记 | `order_group_batch` 的 `hotel_ready` / `vehicle_ready` / `guide_ready` / `photographer_ready` / `material_confirmed` |
| 导摄是否需要 | `order_group_batch.needs_guide` / `needs_photographer` |
| 整团免车 | `order_group_vehicle_requirement`(活跃且已确认)+ `order_group_vehicle_group`(零分组) |
---
## 六、边界行为
- 未登录 / 无效 token → 网关返回 `code: 401`(HTTP 200)。
- 团期不存在 → `589500`。
- 已流团、`batchStatus` 为空或认不出 → `progressStepper=[]`,详情其余字段照常返回,不报 500。
- 招募阶段 → 5 条分支都是「待开始」。`needs_*` 这时恒为 0,但不会显示「无需」。
- 标记为 false 时,即使该项不需要(`needs_*=0`),也显示 `UNMET`,与确认门判定一致。
- 已结算 → 6 个节点全是 `DONE`,结算节点 `isCurrent=true`、label「已结算」。
---
## 六.5、枚举 / 数据字典
### progressStepper[].code(`GroupBatchStageBuckets.Bucket`)
**所属字段**: `GroupBatchProgressNodeVO.code` | **类型**: `String`
| 值 | 中文 | 对应九态 `batchStatus` |
|----|------|------|
| `RECRUIT` | 招募 | RECRUITING |
| `CONFIGURE` | 配置 | RESOURCE_PREPARING |
| `CONFIRM` | 确认 | MATERIAL_PREPARING |
| `TRIP` | 出行 | PENDING_DEPARTURE / TRAVELLING / TRIP_FINISHED |
| `REVIEW` | 核单 | REVIEWING |
| `SETTLE` | 结算 | SETTLED |
### progressStepper[].status(`GroupBatchProgressStepper` 常量)
**所属字段**: `GroupBatchProgressNodeVO.status` | **类型**: `String`
| 值 | 中文 | 说明 |
|----|------|------|
| `DONE` | 已过 | 当前节点之前的节点;已结算团的结算节点 |
| `PROCESSING` | 进行中 | 当前节点(已结算除外) |
| `WAITING` | 未到 | 当前节点之后的节点 |
### progressStepper[].subFlows[].code(`GroupBatchProgressStepper.Branch`)
**所属字段**: `GroupBatchProgressSubFlowVO.code` | **类型**: `String`
| 值 | 中文 | 读哪个标记 | 能否免除 |
|----|------|------|------|
| `HOTEL` | 配房 | `hotelReady` | 否 |
| `VEHICLE` | 配车 | `vehicleReady` | 整团免车 |
| `GUIDE` | 配导游 | `guideReady` | 团期不需要导游 |
| `PHOTOGRAPHER` | 配摄影 | `photographerReady` | 团期不需要摄影 |
| `MATERIAL` | 配物资 | `materialConfirmed` | 否 |
### progressStepper[].subFlows[].status(`GroupBatchProgressStepper` 常量)
**所属字段**: `GroupBatchProgressSubFlowVO.status` | **类型**: `String`
按优先级从上往下判:
| 值 | 中文(statusName) | 条件 |
|----|------|------|
| `WAITING` | 待开始 | 团期在招募阶段 |
| `UNMET` | 未配齐(物资:未确认) | 对应标记不为 true |
| `WAIVED` | 无需 / 整团免车 | 导游、摄影:标记为 true 且团期不需要;车:标记为 true 且整团免车声明成立 |
| `DONE` | 已完成(物资:已确认) | 其余标记为 true 的情况 |
---
## 六.6、修改前后对比
### 字段级对比
| 字段 | 改前 | 改后 |
|------|------|------|
| `progressStepper` | 无 | 新增,见第三节 |
| `primaryReporterId` 的 swagger 说明 | 主报账人 staffId(P10 未落,暂返 null) | 取团期人员配置里 reporter_rank=PRIMARY 的人;未设置为 null(取值与改前相同) |
| `primaryReporterName` 的 swagger 说明 | 主报账人姓名(P10 未落,暂返 null) | 同一个人的姓名快照;未设置为 null(取值与改前相同) |
### 行为级对比
| 行为 | 改前 | 改后 |
|------|------|------|
| 团级五项的展示依据 | 前端读 5 个布尔,或读 confirm-check 的 batchItems | 读 `progressStepper` 的分支,含「无需」「整团免车」 |
| 已流团 | 无进度条字段 | `progressStepper=[]` |
| 其余字段 | — | 不变 |
---
## 六.7、影响评估
- **是否破坏向后兼容**: 否。纯新增字段,其余字段取值不变。
- **前端是否必须同步上线**: 否。不接新字段时页面行为与改前一致;按第四节清单改造后生效。
- **前端 workaround 清理点**: 页头「团期尚不满足确认条件」横幅、查看需求「仍有子订单需求缺失」提示块、总览「资源与单据」卡片(该卡依赖从未返回过的 `chips`),按第四节清单去掉。
---
## 七、不影响范围
- **仅影响**: 团期详情接口出参(新增一个字段)。
- **零影响**:
- 确认预检 `GET /v3/admin/order/group-batch/{groupBatchId}/confirm-check` 与确认 `POST .../confirm` 的判定和出参
- 团期列表、看板(`chips` 与统计口径不变)
- 订单详情的 `progressStepper`(团期用独立的 VO,字段名一致,互不影响)
- 数据库表结构与存量数据
---
## 八、测试环境已验证
TEST 的 hl-order-service-v3 运行 dev-v3 `49777861b`,部署后连调 6 次都返回 `progressStepper`,两个实例都已生效。经网关用真实 admin token 实测:
```
GET /v3/admin/order/group-batch/2101506167098511362 → 200,6 节点,CONFIGURE 当前「配置中」,5 条分支 ✓
GET /v3/admin/order/group-batch/2104327837991518210 → 200,配车「整团免车」,导摄「无需」 ✓
GET /v3/admin/order/group-batch/2101014943498219522 → 200,配车有分组,DONE「已完成」 ✓
GET .../{9 个配置阶段团}/confirm-check 与详情逐项比对 → 分支 UNMET ⇔ passed=false,全部一致 ✓
自造团 招募 → 5 条「待开始」(needs 为 0 也不显示无需)✓
自造团 成团后 → 房车未配齐、导摄无需、物资未确认 ✓
自造团 确认 / 待出发 / 出行中 / 已返团 / 核单 / 已结算 → 当前节点与 label 正确,code = stage ✓
自造团 已流团 → progressStepper = [] ✓
自造团 guide_ready=0 且 needs_guide=0 → UNMET(未配齐优先于无需)✓
不带 Authorization → code 401 ✓
团期不存在 1999999999999999999 → 589500 ✓
```
自造团(团期 `2104485658041147393`、订单 `2104485657902735361`、班期 `2104485617050230787`)验完已取消并清理。
---
## 九、相关历史 PR
| PR | Issue | 说明 | 是否仍有效 |
|----|-------|------|------------|
| — | #8410 | 团期确认只读预检 confirm-check,前端据此加了页头「团期尚不满足确认条件」横幅 | ✅ 接口有效;横幅按本单第四节去掉 |
| — | #8271 | 团期六节点定案,详情 `stage` 字段 | ✅ 有效,`progressStepper[].code` 与之同源 |
| — | #7441 | 整团免车声明 | ✅ 有效,配车分支「整团免车」据此判定 |
| **本 PR #8480** | **#8478** | 新增 `progressStepper` | ✅ 最新 |
---
## 十、相关文档
- 关联 Issue: [wx/HL#8478](https://git.1814.love/wx/HL/issues/8478)(正文「前端范围」与本文第四节一致)
- 关联 PR: [wx/HL#8480](https://git.1814.love/wx/HL/pulls/8480)
- 订单详情分叉进度条组件:hl-ui `src/views/order-v2/detail/components/ForkStepBar.vue`
## 关联 / 联系人
### 链接
- **Issue**: [#8478](https://git.1814.love/wx/HL/issues/8478)
- **PR**: [#8480](https://git.1814.love/wx/HL/pulls/8480)
- **Merge commit**: [49777861b](https://git.1814.love/wx/HL/commit/49777861bd967a9a50b7372351b585cff5da0c58)
### 联系人
- **后端负责人**: @jw