成团接口新增可选请求体 formedNote、新增 group-batch:manage 权限校验、 重复成团改为语义化 589537;团期详情与产品班期两侧新增最低成团户数 minToForm。 后端已部署 TEST 并实测:带理由成团成功、重复成团 589537、 不传 body 兼容路径均通过;网关链路已验证。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
这个提交包含在:
@@ -0,0 +1,424 @@
|
||||
---
|
||||
schema: "hl-changelog/v2"
|
||||
ticket: "7158"
|
||||
title: "团期手动成团门槛与提前成团留痕"
|
||||
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: "后端已部署 TEST 并实测:成团带理由成功、重复成团 589537、不传 body 兼容路径均通过。前端待接:成团弹窗三格读 minToForm、产品排期表单加最低成团户数输入框。"
|
||||
updated_at: "2026-09-06"
|
||||
base: "dev-v3"
|
||||
---
|
||||
|
||||
# 团期手动成团:成团门槛 min_to_form 与提前成团留痕
|
||||
|
||||
> **影响范围**:管理后台「团期详情 → 整团总览 → 成团」弹窗,以及产品「Step4 班期」维护表单。
|
||||
> 当前状态:后端已部署 TEST 并实测;前端待接入。
|
||||
|
||||
## ⚠️ 关键变化
|
||||
|
||||
1. **成团接口新增可选请求体**。`POST .../group` 原来无请求体,现在可传 `formedNote`(提前成团理由)。
|
||||
**不传 body 时行为与之前完全一致**,前端不改也不会坏。
|
||||
2. **成团新增权限校验** `group-batch:manage`。此前该接口无任何权限校验。
|
||||
3. **重复成团改为语义化错误码 589537**,此前返回笼统的 589501「团期状态不允许当前操作」。
|
||||
4. **新增成团门槛字段 `minToForm`**(最低成团**户数**,户 = 订单 = 房)。
|
||||
团期详情与产品班期两侧都新增该字段,供成团弹窗三格渲染。
|
||||
|
||||
## 一、背景
|
||||
|
||||
招募中的团期需管理员手动点「成团」才进入成团状态,进入后才能开始需求审核 / 配置资源。
|
||||
成团弹窗顶部要显示三格「已售 5/9 户 · 成团标准 满 6 户 · 距标准差 1 户」,
|
||||
但此前**成团标准没有任何数据源**:团期侧的 `minGroupPeople` 是「人数」口径且全局无写入方恒为 null,
|
||||
产品侧只有按人数的最低成团人数。本次新增按**户数**的 `minToForm` 补齐这条链路。
|
||||
|
||||
**门槛只提示不拦截**:未达标也可提前成团,这是业务要求。系统在任何情况下都不自动成团。
|
||||
|
||||
## 二、变更接口清单
|
||||
|
||||
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 1 | 团期手动成团 | POST | `/v3/admin/order/group-batch/{groupBatchId}/group` | 修改接口 | 新增可选请求体 formedNote;新增权限校验;重复成团改 589537 |
|
||||
| 2 | 团期详情 | GET | `/v3/admin/order/group-batch/{groupBatchId}` | 修改接口 | 出参新增 minToForm(成团门槛户数) |
|
||||
| 3 | 产品班期修改 | PUT | `/admin/product/item/{id}/schedule` | 修改接口 | 入参新增 minToForm(最低成团户数) |
|
||||
| 4 | 产品班期列表 | GET | `/admin/product/item/{id}/schedule/list` | 修改接口 | 出参新增 minToForm |
|
||||
|
||||
## 三、接口详情
|
||||
|
||||
### 1. 团期手动成团 `POST /v3/admin/order/group-batch/{groupBatchId}/group`
|
||||
|
||||
**VO**: `GroupBatchFormReqVO`
|
||||
|
||||
#### 使用场景
|
||||
|
||||
管理员在「团期详情 → 整团总览」底部操作条点「成团」,弹窗确认后调用。
|
||||
仅招募中(`RECRUITING`)的团期可成团;成团后团期进入资源准备中,才能开始需求审核与配置资源。
|
||||
已售户数未达成团门槛时也可以成团(提前成团),此时建议在弹窗里填写理由。
|
||||
|
||||
#### 入参
|
||||
|
||||
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| groupBatchId | path | Long | 是 | 正整数 | 团期 ID |
|
||||
| formedNote | body | String | 否 | 最长 256 字 | 提前成团理由。整个 body 可以不传;不传等同于不带理由,行为与本次改动前一致 |
|
||||
|
||||
#### 出参
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| code | Integer | 200 表示成团成功 |
|
||||
| message | String | 提示文案 |
|
||||
| data | Object | 固定为 null,本接口无返回体 |
|
||||
| success | Boolean | true 表示成功 |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```json
|
||||
{
|
||||
"formedNote": "客户催促,线下已谈妥另外 1 户"
|
||||
}
|
||||
```
|
||||
|
||||
#### 响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "成功",
|
||||
"data": null,
|
||||
"traceId": null,
|
||||
"success": true
|
||||
}
|
||||
```
|
||||
|
||||
#### 空数据 / 降级响应
|
||||
|
||||
本接口成功时 `data` 恒为 null,不存在空数据形态。
|
||||
成团流水文案里的「已售 N/M 户」依赖实时聚合,聚合失败时降级为不带户数的文案,
|
||||
**不影响成团本身成功**,前端无需为此做特殊处理。
|
||||
|
||||
#### 错误响应
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 589537,
|
||||
"message": "团期已成团,不可重复成团",
|
||||
"data": null,
|
||||
"traceId": null,
|
||||
"success": false
|
||||
}
|
||||
```
|
||||
|
||||
#### 业务边界
|
||||
|
||||
- 仅 `RECRUITING` 状态可成团;已成团(含之后各状态)返回 589537,已流团返回 589501。
|
||||
- 重复成团**零副作用**:不写状态、不写流水、不触发任何下游动作。
|
||||
- 未达成团门槛**不拦截**,照常成团,仅在成团流水里标注未达标与理由。
|
||||
- 需要 `group-batch:manage` 权限,无权限返回 589507。
|
||||
- 系统在任何情况下都不自动成团;达标只代表「允许成团」。
|
||||
|
||||
### 2. 团期详情 `GET /v3/admin/order/group-batch/{groupBatchId}`
|
||||
|
||||
**VO**: `GroupBatchDetailRespVO`
|
||||
|
||||
#### 使用场景
|
||||
|
||||
打开团期详情页时调用。本次新增的 `minToForm` 与既有 `enrolledRooms` / `maxRooms`
|
||||
一起,足以渲染成团弹窗顶部三格,前端不需要再调其他接口。
|
||||
|
||||
#### 入参
|
||||
|
||||
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| groupBatchId | path | Long | 是 | 正整数 | 团期 ID |
|
||||
|
||||
#### 出参
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| minToForm | Integer | **本次新增**。最低成团户数,户 = 订单 = 房。null 或 0 表示未设门槛 |
|
||||
| enrolledRooms | Integer | 已售户数(成团弹窗第一格分子) |
|
||||
| maxRooms | Integer | 满团户数(第一格分母),0 表示不限 |
|
||||
| remainRooms | Integer | 剩余户数,不限时为 null |
|
||||
| minGroupPeople | Integer | 历史字段,最低成团**人数**,全局无写入方恒为 null。成团门槛请改用 minToForm |
|
||||
| batchStatus | String | 团期状态码 |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```http
|
||||
GET /v3/admin/order/group-batch/2096412454643802114
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
#### 响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "成功",
|
||||
"data": {
|
||||
"groupBatchId": "2096412454643802114",
|
||||
"batchStatus": "RECRUITING",
|
||||
"enrolledRooms": 1,
|
||||
"maxRooms": 8,
|
||||
"remainRooms": 7,
|
||||
"minToForm": 6,
|
||||
"minGroupPeople": null
|
||||
},
|
||||
"success": true
|
||||
}
|
||||
```
|
||||
|
||||
#### 空数据 / 降级响应
|
||||
|
||||
`minToForm` 为 null 或 0 表示该团期未设成团门槛。
|
||||
此时前端**只显示第一格「已售 X/Y 户」**,不显示「成团标准」与「距标准差」两格。
|
||||
本次上线前建出的存量团期一律是这种情况,不做数据回填。
|
||||
|
||||
#### 错误响应
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 589500,
|
||||
"message": "团期不存在",
|
||||
"data": null,
|
||||
"success": false
|
||||
}
|
||||
```
|
||||
|
||||
#### 业务边界
|
||||
|
||||
- 三格渲染口径:已售 `enrolledRooms`/`maxRooms` 户;成团标准 满 `minToForm` 户;距标准差 `max(0, minToForm - enrolledRooms)` 户。
|
||||
- `minToForm` 是**建团时从产品班期快照**下来的,之后改产品班期不会回改已建出的团期。
|
||||
- `minGroupPeople` 与 `minToForm` 是两个不同口径的字段,并存且互不换算,不要混用。
|
||||
|
||||
### 3. 产品班期修改 `PUT /admin/product/item/{id}/schedule`
|
||||
|
||||
**VO**: `ScheduleSaveReqVO`
|
||||
|
||||
#### 使用场景
|
||||
|
||||
产品维护 Step4「班期」表单保存时调用。本次新增 `minToForm`,
|
||||
即该班期的最低成团户数,与既有 `maxRooms`(满团户数)成对维护。
|
||||
|
||||
#### 入参
|
||||
|
||||
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | Long | 是 | 正整数 | 产品 ID |
|
||||
| batchId | body | Long | 是 | 修改时必传 | 班期 ID |
|
||||
| minToForm | body | Integer | 否 | 非负整数 | **本次新增**。最低成团户数,空或 0 表示不限 |
|
||||
| maxRooms | body | Integer | 否 | 非负整数 | 满团户数,0 表示不限 |
|
||||
|
||||
#### 出参
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| data | Long | 班期 ID |
|
||||
| success | Boolean | 是否成功 |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```json
|
||||
{
|
||||
"batchId": 2052935476557328386,
|
||||
"departureDate": "2026-10-01",
|
||||
"adultPrice": 2925.00,
|
||||
"childPrice": 2425.00,
|
||||
"singleRoomDiff": 500.00,
|
||||
"maxRooms": 8,
|
||||
"minToForm": 6
|
||||
}
|
||||
```
|
||||
|
||||
#### 响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "成功",
|
||||
"data": 2052935476557328386,
|
||||
"success": true
|
||||
}
|
||||
```
|
||||
|
||||
#### 空数据 / 降级响应
|
||||
|
||||
`minToForm` 不传时服务端兜底为 0(不限),与 `maxRooms` / `maxParticipants` 的兜底口径一致。
|
||||
存量班期在本次 DDL 后取默认值 0,不做回填。
|
||||
|
||||
#### 错误响应
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 403,
|
||||
"message": "无操作权限",
|
||||
"data": null,
|
||||
"success": false
|
||||
}
|
||||
```
|
||||
|
||||
#### 业务边界
|
||||
|
||||
- `minToForm` **只服务团期运营台的成团弹窗与成团留痕**,不参与任何下单与库存判定。
|
||||
- 库存与满团判定仍然只看 `maxRooms` / `maxParticipants`,本次不受影响。
|
||||
- 与既有的按人数的最低成团人数字段并存、互不覆盖、互不换算。
|
||||
- 改这里**不会**回改已经建出的团期,团期侧是建团时的快照。
|
||||
|
||||
### 4. 产品班期列表 `GET /admin/product/item/{id}/schedule/list`
|
||||
|
||||
**VO**: `ScheduleRespVO`
|
||||
|
||||
#### 使用场景
|
||||
|
||||
产品维护 Step4「班期」列表回显,以及班期编辑弹窗打开时取当前值。
|
||||
|
||||
#### 入参
|
||||
|
||||
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| id | path | Long | 是 | 正整数 | 产品 ID |
|
||||
|
||||
#### 出参
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| minToForm | Integer | **本次新增**。最低成团户数,0 表示不限 |
|
||||
| maxRooms | Integer | 满团户数,0 表示不限 |
|
||||
| batchId | Long | 班期 ID |
|
||||
| departureDate | String | 出发日期 |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```http
|
||||
GET /admin/product/item/2044306857534636034/schedule/list
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
#### 响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "成功",
|
||||
"data": [
|
||||
{
|
||||
"batchId": 2052935476557328386,
|
||||
"batchNo": "Q202610012052935476548939777",
|
||||
"departureDate": "2026-10-01",
|
||||
"maxRooms": 8,
|
||||
"minToForm": 0
|
||||
}
|
||||
],
|
||||
"success": true
|
||||
}
|
||||
```
|
||||
|
||||
#### 空数据 / 降级响应
|
||||
|
||||
产品下无班期时 `data` 为空数组。
|
||||
存量班期的 `minToForm` 一律回显 0,表示尚未设置成团门槛,属正常值而非异常。
|
||||
|
||||
#### 错误响应
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 404,
|
||||
"message": "产品不存在",
|
||||
"data": null,
|
||||
"success": false
|
||||
}
|
||||
```
|
||||
|
||||
#### 业务边界
|
||||
|
||||
- 列表回显的 `minToForm` 是产品侧权威值;团期侧显示的是建团时的快照,两者可能不同,属预期。
|
||||
- 该字段不影响列表排序与筛选。
|
||||
|
||||
## 四、契约约束与正确调用方式
|
||||
|
||||
- **成团请求体整体可选**。前端可以继续用无 body 的旧调用,也可以传 `{"formedNote": "..."}`。
|
||||
建议:已售户数未达 `minToForm` 时在弹窗里出现理由输入框并把值传上来。
|
||||
- **理由本期不强制必填**。服务端不会因为没填理由而拒绝成团,前端可自行决定是否做前端必填。
|
||||
- **成团弹窗三格全部来自团期详情接口**,不需要额外接口。`minToForm` 为 null 或 0 时只显示第一格。
|
||||
- **同一份 `ScheduleSaveReqVO` 也被新建班期 `POST /admin/product/item/{id}/schedule` 使用**,
|
||||
该接口同样接受 `minToForm`,语义与修改班期完全一致;批量创建
|
||||
`POST /admin/product/item/{id}/schedule/batch-create` 使用 `ScheduleBatchCreateReqVO`,
|
||||
同样新增了 `minToForm` 并逐个透传给每个新建班期。这三个入口共用一套口径,前端按同一字段接入即可。
|
||||
- **权限**:成团需要 `group-batch:manage`。该权限已随本次发布授予 `ADMIN` 与 `SUPER_ADMIN`。
|
||||
若线上还有其他角色需要点成团,需要单独补授,否则会被拦为 589507。
|
||||
|
||||
## 五、数据库行为
|
||||
|
||||
- 成团成功时推进团期状态,并写入一条**成团操作流水**,内容形如
|
||||
「手动成团 · 已售 1/8 户 · 未达标(满6户) · 理由:客户催促」,含操作人与时间。
|
||||
未设门槛时省略达标判定段,未填理由时省略理由段。
|
||||
- 重复成团、无权限、团期不存在三种情况**均不产生任何写入**。
|
||||
- 成团门槛在产品侧维护、在建团时快照到团期侧,之后两侧独立,不做双向同步。
|
||||
- 存量数据不回填:本次上线前已存在的班期与团期,成团门槛一律为默认值(0 或空)。
|
||||
|
||||
## 六、边界行为
|
||||
|
||||
- 未达成团门槛照常可以成团,门槛只影响提示与流水文案。
|
||||
- 系统在任何情况下都不自动成团,达标只代表「允许成团」。
|
||||
- 成团后的既有下游行为不变:派生导游 / 摄影需求标志、免闸置位、尝试推进物料准备、驱动子订单进需求态并派发配房配车待办。
|
||||
- 成团流水文案里的已售户数与团期详情同源(实时聚合),不读持久计数列,两处显示不会打架。
|
||||
|
||||
## 六.6、修改前后对比
|
||||
|
||||
| 项 | 修改前 | 修改后 |
|
||||
| --- | --- | --- |
|
||||
| 成团请求体 | 无请求体 | 可选 body,含 `formedNote`;不传时行为不变 |
|
||||
| 成团权限 | **无任何权限校验** | 需要 `group-batch:manage`,无权限 589507 |
|
||||
| 重复成团 | 589501「团期状态不允许当前操作」 | 589537「团期已成团,不可重复成团」 |
|
||||
| 成团流水 | 固定文案「成团」 | 带已售 / 满团 / 达标情况 / 提前成团理由 |
|
||||
| 团期详情成团门槛 | 只有恒为 null 的 `minGroupPeople`(人数口径) | 新增 `minToForm`(户数口径),弹窗三格可渲染 |
|
||||
| 产品班期成团门槛 | 只有按人数的最低成团人数 | 新增按户数的 `minToForm`,可在班期表单维护 |
|
||||
|
||||
## 六.7、影响评估
|
||||
|
||||
- **对现有前端调用零破坏**:成团请求体可选,不传 body 的老调用行为与改动前完全一致,已在 TEST 实测确认。
|
||||
- **权限是行为变更**:`group-batch:manage` 已随发布授予 `ADMIN` / `SUPER_ADMIN`;
|
||||
若还有其他角色在点成团,上线后会被拦住,需要补授权限。这是本次唯一需要运维配合的点。
|
||||
- **错误码语义变更**:重复成团由 589501 变为 589537。若前端对 589501 做过特殊处理,需要同步识别 589537。
|
||||
- **新增字段均为增量**,不改动任何既有字段的类型与含义;`minGroupPeople` 保持原样不动。
|
||||
- 团期成团的下游链路(子订单推进、待办派发)本次未做任何改动。
|
||||
|
||||
## 七、不影响范围
|
||||
|
||||
- 取消成团、流团两个接口本次未改动,仍然没有权限校验,将另行统一处理。
|
||||
- 下单、库存扣减、满团判定完全不受影响,仍只看 `maxRooms` / `maxParticipants`。
|
||||
- 小程序端不受影响,本次改动全部在管理后台侧。
|
||||
- 成团通知(公众号 / 短信)本期不做,弹窗上的通知勾选框暂无后端对应入参,成团后仍需人工通知客户。
|
||||
|
||||
## 八、测试环境已验证
|
||||
|
||||
TEST 环境已部署 product-v2、user-service、order-v3 三个服务并实测通过:
|
||||
|
||||
- 团期详情返回 `minToForm` / `maxRooms` / `enrolledRooms` / `remainRooms`,`minGroupPeople` 保持并存。
|
||||
- 带 `formedNote` 成团成功,团期由招募中进入资源准备中。
|
||||
- 重复成团返回 589537「团期已成团,不可重复成团」。
|
||||
- 不传请求体再次调用同样走到业务校验而非参数错误,确认请求体确实可选。
|
||||
- 产品班期列表返回 `minToForm`,存量班期回显 0。
|
||||
|
||||
未在测试环境覆盖的三项:成团流水文案(团期流水目前无对外查询接口,由单元测试保证)、
|
||||
产品班期写入 `minToForm`(受产品模块数据权限限制未能实调)、
|
||||
建团快照(需在设置门槛后新建团期订单才能观察)。
|
||||
|
||||
## 十、相关文档
|
||||
|
||||
- 工单:HL#7158
|
||||
- 合并:HL PR#7168(已合入 dev-v3)
|
||||
- 前置工单:HL#7104(成团驱动子订单流程推进),本次改成团入口,与其下游改动互不冲突
|
||||
|
||||
## 关联 / 联系人
|
||||
|
||||
- 后端:jw
|
||||
- 前端待接两项:成团弹窗三格读取 `minToForm` 并在未达标时出现提前成团理由输入框;
|
||||
产品 Step4 班期表单新增「最低成团户数」输入框。
|
||||
在新工单中引用
屏蔽一个用户