docs(changelog): 8796 发票管理列表出参移除 stats 统计块(顶部4张统计卡片下线,tabCounts 保留)
changelog-filename-gate / validate (push) Failing after 3s

这个提交包含在:
yaosutu
2026-10-05 22:45:55 +08:00
父节点 86da96e23e
当前提交 053276cfdd
@@ -0,0 +1,340 @@
---
schema: "hl-changelog/v2"
ticket: "8796"
title: "发票管理列表出参移除顶部 stats 统计块(records / tabCounts 不变)"
consumer: "admin"
author: "yst"
change_type: "修改接口"
backend_status: "merged"
gateway_status: "not_required"
frontend_status: "pending"
frontend_owner: ""
frontend_ref: ""
target_release: ""
verified_at: ""
status_note: "产品决定下线发票管理列表顶部 4 张统计卡片;出参根级 stats 字段已删,tabCounts 角标计数保留。已合 dev-v3。前端需删除顶部统计卡片渲染逻辑。"
updated_at: "2026-10-05"
base: "dev-v3"
---
# order-v3 invoice:发票管理列表出参移除 stats 统计块(管理后台)
> 注意:**破坏性变更(删字段)**:`GET /v3/admin/order/invoice/page` 出参根级 `stats` 字段已删除。前端若仍引用 `stats` 渲染顶部统计卡片,取到的将是 `undefined`,卡片会空白或异常,**必须同步下线该卡片渲染**。
## 1. 接口背景
管理后台「财务 → 发票管理」列表页顶部原有 4 张统计卡片:待开票 / 已开票·待推送 / 已推送 / 本月已开票,数据来自列表接口出参根级的 `stats` 数组。
产品决定不要这 4 张卡片了(#8796)。后端随之把 `stats` 统计块从列表接口出参整体移除,并清掉后端只为它服务的统计查询逻辑。列表行数据、tab 角标计数均不受影响。
## 2. 变更清单
| # | 接口 | 变更点 | 类型 |
|---|------|--------|------|
| 1 | `GET /v3/admin/order/invoice/page` | 出参根级删除 `stats` 字段(原 InvoiceStatItemVO 数组:4 项统计卡片数据) | 出参字段删除 |
入参、路径、`records` 列表行结构、`tabCounts` 角标计数**全部不变**。
## 3. 接口详情
| 项 | 说明 |
|---|---|
| 服务 | hl-order-service-v3(端口 8086) |
| 路径 | `GET /v3/admin/order/invoice/page` |
| 使用场景 | 管理后台 → 财务 → 发票管理列表(分页 + tab 过滤 + 搜索) |
| 认证 | 管理后台登录态(JWT);网关既有路由 `/v3/admin/**`,无新增网关配置 |
| 幂等性 | 纯查询,天然幂等 |
| 限流 | 无特殊限流 |
## 4. 接口入参
**入参零变化**(Query 参数):
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| pageNo | int | 否 | 页码,默认 1 |
| pageSize | int | 否 | 每页条数,默认 10 |
| tab | string | 否 | tab 过滤:REQUESTED(待开票)/ ISSUED(待推送)/ PUSHED(已推送)/ NONE(未申请)/ ALL(全部),默认 ALL |
| orderNo | string | 否 | 订单号模糊搜索 |
| contactName | string | 否 | 客户名(主联系人)模糊搜索 |
| titleName | string | 否 | 开票抬头模糊搜索(NONE tab 传此参数结果置空) |
| requestedBy | string | 否 | 申请人(定制师/用户姓名)模糊搜索 |
## 5. 出参字段
响应统一包装 `Result<InvoicePageRespVO>`,`data` 结构如下。
### 5.1 顶层结构(变更后现状)
| 字段 | 类型 | 说明 |
|------|------|------|
| records | array | 发票列表行(结构见 5.2) |
| total | long | 总条数 |
| page | int | 当前页码 |
| pageSize | int | 每页条数 |
| tabCounts | array | 各 tab 计数(**保留不变**,见 5.3) |
| ~~stats~~ | ~~array~~ | **已删除**,不再返回 |
部署后实测出参顶层 keys = `["records", "total", "page", "pageSize", "tabCounts"]`,已无 `stats`。
### 5.2 records 列表行(InvoicePageItemRespVO,本次未动)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | string | 发票 ID(字符串防 JS 精度丢失) |
| orderId | string | 订单 ID(字符串) |
| orderNo | string | 订单号 |
| productName | string | 产品名 |
| productCoverImg | string | 产品封面图 URL |
| tierName | string | 档位名 |
| contactName | string | 客户名(主联系人) |
| customizerName | string | 定制师名 |
| departureDate | string(yyyy-MM-dd) | 出发日期 |
| adultCount | int | 成人数 |
| childCount | int | 儿童数 |
| youngChildCount | int | 婴儿/小童数 |
| invoiceType | string | 发票类型(VAT_NORMAL / VAT_SPECIAL) |
| invoiceTypeText | string | 发票类型文案 |
| titleType | string | 抬头类型(COMPANY / PERSONAL) |
| titleName | string | 开票抬头 |
| taxNo | string | 税号 |
| amount | number | 开票金额(元) |
| email | string | 收件邮箱 |
| status | string | 发票状态(REQUESTED / ISSUED / PUSHED / VOIDED) |
| statusText | string | 状态文案(待开票 / 已开票 / 已推送 / 已作废) |
| requestedBy | string | 申请人(定制师名或用户名) |
| requestedAt | string | 申请时间 |
| issuedAt | string | 开票时间(ISSUED 后有值) |
| issuedBy | string | 开票人(财务员工名) |
| invoiceNo | string | 发票号(财务登记) |
| fileUrl | string | 发票文件 URL(ISSUED/PUSHED 后有值) |
| pdfName | string | 发票 PDF 文件名 |
| pdfSize | long | 文件大小(字节) |
| teamNo | string | 团号 |
| createTime | string | 订单创建时间 |
| orderStatus | string | 订单状态 |
| orderStatusText | string | 订单状态文案 |
| flowStatus | string | 流程状态 |
| flowStatusText | string | 流程状态文案 |
| orderAmount | number | 订单应收总额(元) |
| paidAmount | number | 累计已收(元) |
| refundedAmount | number | 累计已退(元) |
| settlementAmount | number | 核单金额(元) |
### 5.3 tabCounts 项(InvoiceTabCountVO,保留不变)
固定 5 项,顺序:REQUESTED / ISSUED / PUSHED / NONE / ALL:
| 字段 | 类型 | 说明 |
|------|------|------|
| code | string | 状态编码(REQUESTED / ISSUED / PUSHED / NONE / ALL) |
| name | string | 中文名(待开票 / 待推送 / 已推送 / 未申请 / 全部) |
| count | int | 计数 |
tabCounts 为全局全量计数,**不受搜索条件影响**(此行为未变)。
## 6. 枚举 / 数据字典
本次无枚举变化。涉及枚举均为既有值:
| 枚举 | 取值 |
|------|------|
| tab | REQUESTED / ISSUED / PUSHED / NONE / ALL |
| status(发票) | REQUESTED(待开票)/ ISSUED(已开票)/ PUSHED(已推送)/ VOIDED(已作废) |
| invoiceType | VAT_NORMAL / VAT_SPECIAL |
| titleType | COMPANY / PERSONAL |
原 `stats[].code` 的 4 个取值(REQUESTED / ISSUED / PUSHED / CURRENT_MONTH_ISSUED)随字段一并废弃,不再有消费方。
## 7. 错误码
本接口为查询接口,正常情况无业务错误码。公共错误(未登录 / 无权限)走网关与全局异常处理。发票域业务错误码(5815xx 段,如 581500 发票不存在等)本次无变化,且本列表接口不抛出。
## 8. 示例
### 8.1 典型成功(REQUESTED tab,第一页)
请求:
```
GET /v3/admin/order/invoice/page?tab=REQUESTED&pageNo=1&pageSize=10
```
响应(注意顶层已无 stats):
```json
{
"code": 0,
"data": {
"records": [
{
"id": "1975812345678901234",
"orderId": "1960123456789012345",
"orderNo": "2026092800001",
"productName": "呼伦贝尔草原 5 日定制游",
"productCoverImg": "https://oss.example.com/cover/abc.jpg",
"tierName": "舒适档",
"contactName": "张三",
"customizerName": "李定制",
"departureDate": "2026-10-15",
"adultCount": 2,
"childCount": 1,
"youngChildCount": 0,
"invoiceType": "VAT_NORMAL",
"invoiceTypeText": "增值税普通发票",
"titleType": "COMPANY",
"titleName": "北京某某科技有限公司",
"taxNo": "91110108MA01C8XH3B",
"amount": 12800.00,
"email": "zhangsan@example.com",
"status": "REQUESTED",
"statusText": "待开票",
"requestedBy": "李定制",
"requestedAt": "2026-10-01 10:23:45",
"issuedAt": null,
"issuedBy": null,
"invoiceNo": null,
"fileUrl": null,
"pdfName": null,
"pdfSize": null,
"teamNo": "T2026101501",
"createTime": "2026-09-28 14:02:11",
"orderStatus": "COMPLETED",
"orderStatusText": "已完成",
"flowStatus": "SETTLED",
"flowStatusText": "已核单",
"orderAmount": 12800.00,
"paidAmount": 12800.00,
"refundedAmount": 0.00,
"settlementAmount": 12800.00
}
],
"total": 1,
"page": 1,
"pageSize": 10,
"tabCounts": [
{ "code": "REQUESTED", "name": "待开票", "count": 1 },
{ "code": "ISSUED", "name": "待推送", "count": 3 },
{ "code": "PUSHED", "name": "已推送", "count": 12 },
{ "code": "NONE", "name": "未申请", "count": 45 },
{ "code": "ALL", "name": "全部", "count": 61 }
]
},
"msg": ""
}
```
### 8.2 边界情况(搜索无命中,空列表)
请求:
```
GET /v3/admin/order/invoice/page?tab=ALL&titleName=不存在的公司名&pageNo=1&pageSize=10
```
响应(records 空数组、total=0,**tabCounts 仍为全局计数**,无 stats):
```json
{
"code": 0,
"data": {
"records": [],
"total": 0,
"page": 1,
"pageSize": 10,
"tabCounts": [
{ "code": "REQUESTED", "name": "待开票", "count": 1 },
{ "code": "ISSUED", "name": "待推送", "count": 3 },
{ "code": "PUSHED", "name": "已推送", "count": 12 },
{ "code": "NONE", "name": "未申请", "count": 45 },
{ "code": "ALL", "name": "全部", "count": 61 }
]
},
"msg": ""
}
```
### 8.3 业务失败(未登录 / token 失效)
请求:
```
GET /v3/admin/order/invoice/page?tab=ALL
(不带 Authorization 头)
```
响应:
```json
{
"code": 401,
"data": null,
"msg": "未登录或登录已过期"
}
```
## 9. 业务边界
- **适用**:财务在管理后台发票管理列表做分页浏览、tab 切换、按订单号/客户名/抬头/申请人搜索;tab 角标计数展示。
- **不适用**:任何需要「待开票 / 已开票 / 已推送 / 本月已开票」汇总卡片数据的场景 —— 后端已不再提供该汇总,前端**不要**自行用 tabCounts 拼凑原 stats 语义(原 stats 含金额合计与「本月已开票」口径,tabCounts 只有张数且无金额维度,CURRENT_MONTH_ISSUED 当月维度无任何替代数据源)。
- **特殊边界**:VOIDED(已作废)发票不进任何 tab,也不计入 tabCounts;NONE tab 传 titleName / requestedBy 搜索时结果强制为空(既有行为,未变)。
## 10. 修改前后对比
### 10.1 出参顶层结构对比
| 顶层字段 | 修改前 | 修改后 |
|---------|--------|--------|
| records | 有 | 有(不变) |
| total | 有 | 有(不变) |
| page | 有 | 有(不变) |
| pageSize | 有 | 有(不变) |
| tabCounts | 有 | 有(不变) |
| stats | 有(4 项统计数组) | **已删除** |
### 10.2 被删除的 stats 项结构(原 InvoiceStatItemVO,仅作存档)
原 `stats` 为固定 4 项数组,顺序 REQUESTED / ISSUED / PUSHED / CURRENT_MONTH_ISSUED:
| 字段 | 类型 | 说明 |
|------|------|------|
| code | string | 状态编码(REQUESTED / ISSUED / PUSHED / CURRENT_MONTH_ISSUED) |
| name | string | 中文名(待开票 / 已开票·待推送 / 已推送 / 本月已开票) |
| count | int | 张数 |
| amount | number | 合计金额(元) |
### 10.3 行为级对比
| 场景 | 修改前 | 修改后 |
|------|--------|--------|
| 列表查询性能 | 每次查询额外执行统计聚合(按状态计数 + 金额合计、本月口径) | 不再执行统计聚合,查询更轻 |
| tabCounts 值 | 全量计数不受搜索影响 | 同左(不变) |
| 前端顶部卡片 | 可用 stats 渲染 4 张卡片 | 数据源消失,卡片必须下线 |
## 11. 影响评估 / 回滚
### 11.1 影响评估
- **破坏兼容**:是(删出参字段)。
- 前端若仍引用 `data.stats` → 取到 `undefined`,顶部卡片空白或渲染异常(接口本身正常返回,不会报错)。
- **需要前端同步上线**:是。发票管理页须删除顶部统计卡片渲染逻辑。上线顺序建议:前端先删卡片上线(安全,后端 stats 仍在但无人消费),后端版本随后生效;反向顺序则会出现卡片空白窗口。
- tab 角标、列表行、搜索、分页逻辑零改动。
### 11.2 回滚方案
- 后端回滚 = revert PR #8797(恢复 stats 字段与统计查询)。
- 前端如已删卡片渲染,回滚后端后卡片无数据渲染,需同步回滚前端或保持卡片下线(产品决定下线,原则上不回滚)。
## 12. 注意事项
1. **前端必做**:删除发票管理列表页顶部 4 张统计卡片(待开票 / 已开票·待推送 / 已推送 / 本月已开票)的全部渲染逻辑与相关样式,清理对 `data.stats` / `stats[]` 的所有引用与类型定义。
2. 不要试图用 `tabCounts` 还原原统计卡片:原 stats 含金额合计(amount)与「本月已开票」(CURRENT_MONTH_ISSUED)口径,tabCounts 无此数据。
3. 若产品后续需要恢复统计卡片,属新需求,需重新走 Issue 排期,不是回滚本变更。
4. 本变更只影响 `GET /v3/admin/order/invoice/page` 一个接口;发票详情(`GET /v3/admin/order/invoice/{id}`)、开票 / 重传 / 推送等接口均未动。
## 13. 关联 / 联系人
- Issue:https://git.1814.love/wx/HL/issues/8796
- PR:https://git.1814.love/wx/HL/pulls/8797
- Commit:https://git.1814.love/wx/HL/commit/ba01a0719a
- 后端负责人:@yst