docs(changelog): #8413 团期看板导出与统计条补齐列表新筛选(导出看到什么导什么)+ 截止日非法值忽略
changelog-filename-gate / validate (push) Failing after 1s
changelog-filename-gate / validate (push) Failing after 1s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
这个提交包含在:
@@ -0,0 +1,381 @@
|
||||
---
|
||||
schema: "hl-changelog/v2"
|
||||
ticket: "8413"
|
||||
title: "团期看板导出与统计条补齐列表新筛选:导出接收团期状态 / 截止日 / 出发区间 / 排序(看到什么导什么),统计条接收截止日 / 出发区间;三接口截止日非法值改为忽略"
|
||||
consumer: "admin"
|
||||
author: "jw(GIT)"
|
||||
change_type: "修改接口"
|
||||
backend_status: "deployed"
|
||||
gateway_status: "verified"
|
||||
frontend_status: "pending"
|
||||
frontend_owner: "mmg"
|
||||
frontend_ref: ""
|
||||
target_release: ""
|
||||
verified_at: ""
|
||||
status_note: "jw 2026-09-27 定:统计条只跟截止日、出发区间(不跟团期状态 / 看板桶 / 排序);导出看到什么导什么(传排序同列表,不传与列表各自默认一致:按产品 = 出发日升序、不按产品 = 建团时间倒序);导出不带分页、保持 2000 行上限。PR #8417(主体)+ #8432(截止日宽容解析)已合 dev-v3(dada3a8f4)并部署 TEST。2026-09-27 11:54~15:12 经真实网关实测:按产品与全局两种基底、团期状态 / 截止日 / 出发区间组合与三个排序字段 × 升降序、不传排序,导出行集与顺序均与列表已建团行逐一致;产品侧改期(快照 12-10 / 实时 12-15)后按实时日期筛,列表与导出同时命中、按快照日期同时不命中;统计条 total = 列表 total = 七桶之和,filteredOutCount 非零场景(8 / 15)与「ALL − ONGOING」一致;统计条多传团期状态 / 看板桶 / 排序结果不变;非法截止日期三接口均 200 且等同不传该条件(改前列表与导出 500)。TEST 全库团期仅 298 条,2000 行上限由单测覆盖。前端需把列表当前筛选同步传给统计条与导出,故 frontend_status 记 pending。"
|
||||
updated_at: "2026-09-27"
|
||||
base: "dev-v3"
|
||||
---
|
||||
|
||||
# 团期看板:导出与统计条跟上列表筛选(管理后台)
|
||||
|
||||
> **服务**: hl-order-service-v3(端口 8086/8186)
|
||||
> **PR**: #8417、#8432
|
||||
> **Issue**: #8413
|
||||
> **日期**: 2026-09-27
|
||||
> **影响范围**: 管理后台「团期订单」看板的统计条与「导出」按钮;列表接口仅截止日非法值的处理变化
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ 关键变化
|
||||
|
||||
1. **导出新增入参**:`batchStatus`、`deadlineFrom` / `deadlineTo`、`departFrom` / `departTo`、`sortBy` / `sortOrder`,与列表同名同义。前端把列表**当前的全部筛选和排序**原样传给导出,导出的行和顺序就与列表一致(导出不含未建团行,这一点不变)。
|
||||
2. **导出不传排序时的默认顺序变了(仅不按产品时)**:以前一律按出发日升序;现在与列表一致——**按产品看 = 出发日升序,不按产品看 = 建团时间倒序**。
|
||||
3. **统计条新增入参**:`deadlineFrom` / `deadlineTo`、`departFrom` / `departTo`。**不接收**团期状态、看板桶、排序——统计条是按桶分组的计数,前端传了也会被忽略。
|
||||
4. **报名截止日非法值不再报 500**:列表、导出、统计条传非法截止日期(如 `bad-date`、`2026-02-30`)时忽略该条件,与出发区间一致。以前列表和导出会整页返回 500。
|
||||
|
||||
---
|
||||
|
||||
## 一、背景
|
||||
|
||||
列表先后加了团期状态、报名截止日、出发区间(#7770)和排序(#7770),导出和统计条没跟上:运营在列表上筛完,顶部统计条数字对不上,导出拿到的也是没筛的全量、顺序也不同。
|
||||
|
||||
---
|
||||
|
||||
## 二、变更接口清单
|
||||
|
||||
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|
||||
|---|---|---|---|---|---|
|
||||
| 1 | 导出团期列表 | GET | `/v3/admin/order/group-batch/export` | 修改 | 新增团期状态 / 截止日 / 出发区间 / 排序入参;不按产品时默认顺序改为建团时间倒序 |
|
||||
| 2 | 团期看板统计条 | GET | `/v3/admin/order/group-batch/summary` | 修改 | 新增截止日 / 出发区间入参 |
|
||||
| 3 | 团期分页列表 | GET | `/v3/admin/order/group-batch` | 修改 | 截止日非法值由 500 改为忽略该条件 |
|
||||
|
||||
---
|
||||
|
||||
## 三、接口详情
|
||||
|
||||
### 1. 导出团期列表 `GET /v3/admin/order/group-batch/export`
|
||||
|
||||
**VO**: `GroupBatchListReqVO`(入参,与列表同一个)→ CSV 附件(固定 10 列,不变)
|
||||
|
||||
#### 使用场景
|
||||
|
||||
看板点「导出」,导出当前筛选下的全部已建团团期(不分页,单次上限 2000 行)。
|
||||
|
||||
#### 入参
|
||||
|
||||
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|
||||
|---|---|---|---|---|---|
|
||||
| productId | query | Long | 否 | — | 原有 |
|
||||
| month | query | String | 否 | yyyy-MM | 原有,决定文件名 |
|
||||
| keyword | query | String | 否 | — | 原有 |
|
||||
| opsStage | query | String | 否 | 七桶 code | 原有 |
|
||||
| scope | query | String | 否 | ONGOING / FINISHED / ALL | 原有 |
|
||||
| batchStatus | query | String | 否 | 九态 code | **新增**,精确匹配 |
|
||||
| deadlineFrom / deadlineTo | query | String | 否 | yyyy-MM-dd,非法值忽略 | **新增**,报名截止日区间 |
|
||||
| departFrom / departTo | query | String | 否 | yyyy-MM-dd,非法值忽略 | **新增**,出团日期区间 |
|
||||
| sortBy | query | String | 否 | departDate / enrollDeadline / createTime,非法值忽略 | **新增** |
|
||||
| sortOrder | query | String | 否 | asc / desc,缺省或非法 asc | **新增** |
|
||||
|
||||
`pageNo` / `pageSize` 即使传了也不生效(导出不分页)。
|
||||
|
||||
#### 出参
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|---|---|---|
|
||||
| (CSV 附件) | text/csv | 列:团期号、期号、日期、出团日、满团名额、已售、剩余、状态、子订单数、整团应收;不变 |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```http
|
||||
GET /v3/admin/order/group-batch/export?productId=2056944943066132481&scope=ALL&batchStatus=RECRUITING&deadlineFrom=2026-10-01&deadlineTo=2026-12-31&departFrom=2026-10-01&departTo=2027-01-31&sortBy=departDate&sortOrder=desc
|
||||
Authorization: Bearer <admin token>
|
||||
```
|
||||
|
||||
#### 响应示例
|
||||
|
||||
成功时直接返回 CSV 文件流(`Content-Disposition: attachment`),不套 Result 信封。
|
||||
|
||||
```json
|
||||
{
|
||||
"说明": "成功响应为 CSV 附件,此处仅示意首行表头",
|
||||
"header": "团期号,期号,日期,出团日,满团名额,已售,剩余,状态,子订单数,整团应收"
|
||||
}
|
||||
```
|
||||
|
||||
#### 空数据 / 降级响应
|
||||
|
||||
无命中时返回只含表头的 CSV。按产品导出时要调产品服务取实时日期,产品服务不可用返回 589515(与列表、统计条一致):
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 589515,
|
||||
"message": "获取团期产品列表失败,请稍后重试",
|
||||
"data": null,
|
||||
"success": false
|
||||
}
|
||||
```
|
||||
|
||||
#### 错误响应
|
||||
|
||||
| code | 触发条件 |
|
||||
|---|---|
|
||||
| `589517` | 全部筛选后命中超过 2000 行 |
|
||||
| `589515` | 按产品导出时产品服务不可用 |
|
||||
| `589507` | 无导出权限(`group-batch:export`,未改) |
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 589517,
|
||||
"message": "导出数据量超过单次上限,请缩小筛选范围后重试",
|
||||
"data": null,
|
||||
"success": false
|
||||
}
|
||||
```
|
||||
|
||||
#### 业务边界
|
||||
|
||||
- **看到什么导什么**:同一组参数下,导出行 = 列表里已建团的行,顺序一致(未建团行本来就不导出)。
|
||||
- **不传排序**:按产品看 = 出发日升序;不按产品看 = 建团时间倒序(**以前一律出发日升序**)。
|
||||
- **按产品导出**时,班期范围、截止日、出发区间按**产品侧实时日期**筛选和排序,与列表一致;产品改期后不会再出现「列表里有、导出里没有」。
|
||||
- 2000 行上限在全部筛选之后判断。
|
||||
|
||||
### 2. 团期看板统计条 `GET /v3/admin/order/group-batch/summary`
|
||||
|
||||
**VO**: `GroupBatchSummaryVO`(不变)
|
||||
|
||||
#### 使用场景
|
||||
|
||||
看板顶部统计条(总数 + 七桶计数 + 被过滤条数),随列表的截止日、出发区间一起刷新。
|
||||
|
||||
#### 入参
|
||||
|
||||
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|
||||
|---|---|---|---|---|---|
|
||||
| productId / month / keyword / scope | query | — | 否 | — | 原有 |
|
||||
| deadlineFrom / deadlineTo | query | String | 否 | yyyy-MM-dd,非法值忽略 | **新增** |
|
||||
| departFrom / departTo | query | String | 否 | yyyy-MM-dd,非法值忽略 | **新增** |
|
||||
|
||||
#### 出参
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|---|---|---|
|
||||
| total | Integer | 命中团期数(与列表同条件、不筛团期状态和看板桶时的 total 相等) |
|
||||
| buckets | Map | 七桶计数(之和 = total)+ 旧八桶别名键(#8271 过渡期兼容,不变) |
|
||||
| subOrderCount / minToForm / maxRooms | Integer | 不变 |
|
||||
| effectiveScope | String | 生效的班期范围,不变 |
|
||||
| filteredOutCount | Integer | 因班期范围被过滤掉的条数,**现在带上截止日与出发区间计算** |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```http
|
||||
GET /v3/admin/order/group-batch/summary?productId=2056944943066132481&scope=ONGOING&departFrom=2026-05-01&departTo=2026-12-31
|
||||
Authorization: Bearer <admin token>
|
||||
```
|
||||
|
||||
#### 响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "成功",
|
||||
"data": {
|
||||
"total": 22,
|
||||
"buckets": {
|
||||
"RECRUIT": 4, "CONFIGURE": 7, "CONFIRM": 0, "TRIP": 0, "REVIEW": 7, "SETTLE": 1, "DISBANDED": 3,
|
||||
"FORMED": 7, "PENDING_TRIP": 0, "TRAVELLING": 0, "TRIP_FINISHED": 0, "AUDITING": 7, "CHECKED": 1
|
||||
},
|
||||
"subOrderCount": 42,
|
||||
"minToForm": null,
|
||||
"maxRooms": null,
|
||||
"effectiveScope": "ONGOING",
|
||||
"filteredOutCount": 8
|
||||
},
|
||||
"success": true
|
||||
}
|
||||
```
|
||||
|
||||
#### 空数据 / 降级响应
|
||||
|
||||
无命中时 `total=0`、各桶为 0:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "成功",
|
||||
"data": { "total": 0, "buckets": { "RECRUIT": 0 }, "filteredOutCount": 0 },
|
||||
"success": true
|
||||
}
|
||||
```
|
||||
|
||||
#### 错误响应
|
||||
|
||||
判权未改(`group-batch:list`)。
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 589507,
|
||||
"message": "无操作权限(当前角色未授予团期权限,或该团期不在您名下)",
|
||||
"data": null,
|
||||
"success": false
|
||||
}
|
||||
```
|
||||
|
||||
#### 业务边界
|
||||
|
||||
- 不接收 `batchStatus`、`opsStage`、`sortBy`、`sortOrder`,传了也忽略(统计条要给出全部桶的计数)。
|
||||
- 不传新参数时结果与改前一致。
|
||||
|
||||
### 3. 团期分页列表 `GET /v3/admin/order/group-batch`
|
||||
|
||||
**VO**: `GroupBatchListReqVO` → `PageResult<GroupBatchPageItemRespVO>`(均不变)
|
||||
|
||||
#### 使用场景
|
||||
|
||||
看板列表。本次只改报名截止日非法值的处理。
|
||||
|
||||
#### 入参
|
||||
|
||||
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|
||||
|---|---|---|---|---|---|
|
||||
| deadlineFrom / deadlineTo | query | String | 否 | yyyy-MM-dd | **非法值改为忽略该条件**(以前 500) |
|
||||
| 其余 | query | — | 否 | — | 不变 |
|
||||
|
||||
#### 出参
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|---|---|---|
|
||||
| (全部) | — | 不变 |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```http
|
||||
GET /v3/admin/order/group-batch?deadlineFrom=bad-date&pageNo=1&pageSize=20
|
||||
Authorization: Bearer <admin token>
|
||||
```
|
||||
|
||||
#### 响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "成功",
|
||||
"data": { "records": [], "total": 298, "page": 1, "pageSize": 20 },
|
||||
"success": true
|
||||
}
|
||||
```
|
||||
|
||||
#### 空数据 / 降级响应
|
||||
|
||||
不变。
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "成功",
|
||||
"data": { "records": [], "total": 0, "page": 1, "pageSize": 20 },
|
||||
"success": true
|
||||
}
|
||||
```
|
||||
|
||||
#### 错误响应
|
||||
|
||||
判权未改。
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 589507,
|
||||
"message": "无操作权限(当前角色未授予团期权限,或该团期不在您名下)",
|
||||
"data": null,
|
||||
"success": false
|
||||
}
|
||||
```
|
||||
|
||||
#### 业务边界
|
||||
|
||||
- 非法截止日期等同不传该条件,服务端记 warn 日志。
|
||||
|
||||
---
|
||||
|
||||
## 四、契约约束与正确调用方式
|
||||
|
||||
- 前端把列表当前的筛选参数**同一份**传给统计条和导出:
|
||||
- 导出:`productId / month / keyword / opsStage / scope / batchStatus / deadlineFrom / deadlineTo / departFrom / departTo / sortBy / sortOrder`;
|
||||
- 统计条:`productId / month / keyword / scope / deadlineFrom / deadlineTo / departFrom / departTo`。
|
||||
- 统计条不要传团期状态和看板桶;传了会被忽略,但不要依赖这一点做业务判断。
|
||||
|
||||
---
|
||||
|
||||
## 五、数据库行为
|
||||
|
||||
- 零表结构变更、零迁移脚本;三个接口均只读(导出成功后照旧写导出留痕,逻辑未改)。
|
||||
- 三个接口的筛选条件由同一段代码生成,不按产品时下推数据库,按产品时日期类条件按产品侧实时日期在内存筛选。
|
||||
|
||||
---
|
||||
|
||||
## 六、边界行为
|
||||
|
||||
- 导出单次上限 2000 行不变,判断在全部筛选之后。
|
||||
- 按产品导出时,`month` 与 `keyword` 按订单侧快照匹配、CSV「日期 / 出团日」列打印订单侧快照:产品侧改过期或改过名的班期,这两处可能与列表显示不同。
|
||||
|
||||
---
|
||||
|
||||
## 六.6、修改前后对比
|
||||
|
||||
| 项 | 改前 | 改后 |
|
||||
|---|---|---|
|
||||
| 导出可用筛选 | productId / month / keyword / opsStage / scope | 另加 batchStatus / 截止日 / 出发区间 / 排序 |
|
||||
| 导出默认顺序(不按产品) | 出发日升序 | 建团时间倒序(与列表一致) |
|
||||
| 导出默认顺序(按产品) | 出发日升序(订单快照) | 出发日升序(产品侧实时) |
|
||||
| 统计条可用筛选 | productId / month / keyword / scope | 另加截止日 / 出发区间 |
|
||||
| 非法截止日期 | 列表、导出 500 | 三接口忽略该条件 |
|
||||
|
||||
---
|
||||
|
||||
## 六.7、影响评估
|
||||
|
||||
- 前端:统计条与导出要补传参数才生效;不补传时统计条结果不变,导出仅「不按产品」时默认顺序变化。
|
||||
- 列表:只有非法截止日期的处理变化,合法请求不受影响。
|
||||
|
||||
---
|
||||
|
||||
## 七、不影响范围
|
||||
|
||||
- 导出 CSV 的列与格式、导出留痕、判权码。
|
||||
- 看板列表 `GET /v3/admin/order/group-batch/board`、产品选择器、团期详情。
|
||||
|
||||
---
|
||||
|
||||
## 八、测试环境已验证
|
||||
|
||||
部署 dev-v3 @ `7c69e8227`(主体)与 `dada3a8f4`(截止日宽容解析)后,经真实网关 `https://api.test.1814.love` 实测:
|
||||
|
||||
| 用例 | 期望 | 实测 |
|
||||
|---|---|---|
|
||||
| 构建身份:统计条 departFrom=2099-01-01 | total 由 33 变 0 | 通过 |
|
||||
| 按产品:scope=ALL 不传排序 / 团期状态+截止日+出发区间 / 3 排序字段 × 升降序 | 导出行集与顺序 = 列表已建团行 | 8 组全部一致(列表 34 条含 5 条未建团,导出 29 行) |
|
||||
| 全局:出发区间不传排序 / 团期状态+截止日 / 3 排序字段 × 升降序 | 同上 | 8 组全部一致(169 / 165 / 260 行) |
|
||||
| 产品侧改期(快照 12-10、实时 12-15) | 按实时日期命中、按快照不命中,列表与导出一致 | 出发区间与截止日各两组,通过 |
|
||||
| 统计条 截止日+出发区间(按产品 / 全局,ALL / ONGOING) | total = 列表 total = 七桶之和 | 通过(21 / 23 / 229 / 260) |
|
||||
| 统计条 filteredOutCount 非零场景 | = ALL − ONGOING | 8 / 15,通过 |
|
||||
| 统计条多传团期状态 / 看板桶 / 排序 | 结果不变 | 通过 |
|
||||
| 非法截止日期 `bad-date` / `2026-02-30` | 三接口 200,等同不传 | 通过(改前列表与导出 500) |
|
||||
| 非法出发日期 / 非法排序 | 忽略 | 通过 |
|
||||
| 不带 token | 401 | 通过 |
|
||||
|
||||
TEST 全库团期 298 条,2000 行上限(589517)由单测覆盖。造数已清理(产品侧日期已改回、班期已取消)。
|
||||
|
||||
---
|
||||
|
||||
## 十、相关文档
|
||||
|
||||
- Issue #8413、PR #8417、PR #8432
|
||||
- 列表出团区间与排序:Issue #7770
|
||||
- 统计条被过滤条数:Issue #7939
|
||||
|
||||
---
|
||||
|
||||
## 关联 / 联系人
|
||||
|
||||
- 后端:jw
|
||||
- 前端:mmg
|
||||
在新工单中引用
屏蔽一个用户