feat(发票模块): 新增发票详情接口 + 发票列表 page 结构升级(管理后台·#4258/#4265)
- 新增 GET /v3/admin/order/invoice/{id} 发票详情接口(全量字段含专票四项/开票痕迹/推送痕迹)
- GET /v3/admin/order/invoice/page 列表行新增 9 个订单冗余字段
- tab 入参新增 NONE(未申请,代客申请候选)
- tabCounts 和 stats 从扁平对象改为数组(破坏性)
这个提交包含在:
父节点
7907e2aaa6
当前提交
2a24c42ba5
@ -0,0 +1,313 @@
|
||||
# 发票详情接口(财务开票弹窗 / 详情页)
|
||||
|
||||
> 变更类型:新增接口
|
||||
> 端类型:管理后台
|
||||
> 日期:2026-06-23 | Issue:#4258 | PR:#4262 | 服务:hl-order-service-v3
|
||||
|
||||
---
|
||||
|
||||
## 接口背景
|
||||
|
||||
财务在「上传发票 PDF」弹窗或发票详情页中,需要读取完整的开票申请明细:抬头信息、开票金额、专票四项(银行账号、注册地址、注册电话)、开票后的发票号 / PDF / 推送记录。本接口返回单张发票的全量字段,供弹窗回显和详情页展示使用。
|
||||
|
||||
---
|
||||
|
||||
## 变更清单
|
||||
|
||||
| # | 变更类型 | 说明 |
|
||||
|---|---------|------|
|
||||
| 1 | 新增接口 | `GET /v3/admin/order/invoice/{id}` 发票详情 |
|
||||
|
||||
---
|
||||
|
||||
## 接口详情
|
||||
|
||||
| 项 | 说明 |
|
||||
|---|------|
|
||||
| **方法 + 路径** | `GET /v3/admin/order/invoice/{id}` |
|
||||
| **接口名** | 发票详情(财务开票弹窗 / 详情页) |
|
||||
| **描述** | 返回单张发票的完整申请明细、状态、开票痕迹、推送痕迹及订单冗余信息 |
|
||||
| **认证** | 管理后台 JWT(Bearer Token) |
|
||||
| **幂等性** | 只读,天然幂等 |
|
||||
| **限流** | 无特殊限流 |
|
||||
|
||||
---
|
||||
|
||||
## 接口入参
|
||||
|
||||
### 路径参数
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| `id` | string(Long 雪花 ID) | 是 | 发票 ID,前端以字符串传输防精度丢失 |
|
||||
|
||||
### 请求体
|
||||
|
||||
无。
|
||||
|
||||
---
|
||||
|
||||
## 出参字段
|
||||
|
||||
返回结构:`Result<AdminInvoiceDetailRespVO>`
|
||||
|
||||
### 标识字段
|
||||
|
||||
| 字段名 | 类型 | 说明 |
|
||||
|--------|------|------|
|
||||
| `id` | string | 发票 ID(雪花 ID,字符串) |
|
||||
| `orderId` | string | 所属订单 ID |
|
||||
| `orderNo` | string | 订单编号,如 `ORD2026062300001` |
|
||||
|
||||
### 开票申请明细
|
||||
|
||||
| 字段名 | 类型 | 说明 |
|
||||
|--------|------|------|
|
||||
| `invoiceType` | string | 发票类型枚举值,见枚举节 |
|
||||
| `invoiceTypeText` | string | 发票类型中文名,如「增值税普通发票」 |
|
||||
| `titleType` | string | 抬头类型,`COMPANY` 或 `PERSONAL` |
|
||||
| `titleName` | string | 发票抬头(企业名称或个人姓名) |
|
||||
| `taxNo` | string / null | 税号,个人抬头为 null |
|
||||
| `bankName` | string / null | 开户银行,**仅专票**有值,其余 null |
|
||||
| `bankAccount` | string / null | 银行账号,**仅专票**有值,其余 null |
|
||||
| `registAddress` | string / null | 注册地址,**仅专票**有值,其余 null |
|
||||
| `registPhone` | string / null | 注册电话,**仅专票**有值,其余 null |
|
||||
| `amount` | string | 开票金额,单位**分**,字符串防精度丢失,如 `"98600"` |
|
||||
| `email` | string / null | 电子发票接收邮箱 |
|
||||
| `mailAddress` | string / null | 纸质发票邮寄地址,电子发票为 null |
|
||||
| `applyReason` | string / null | 备注(申请原因) |
|
||||
|
||||
### 状态字段
|
||||
|
||||
| 字段名 | 类型 | 说明 |
|
||||
|--------|------|------|
|
||||
| `status` | string | 发票状态枚举值,见枚举节 |
|
||||
| `statusText` | string | 发票状态中文名,如「待开票」 |
|
||||
| `requestedBy` | string / null | 申请人姓名 |
|
||||
| `requestedAt` | string / null | 申请时间,ISO 8601,如 `"2026-06-20T14:30:00"` |
|
||||
|
||||
### 开票痕迹(ISSUED 后有值)
|
||||
|
||||
| 字段名 | 类型 | 说明 |
|
||||
|--------|------|------|
|
||||
| `invoiceNo` | string / null | 发票号码,开票后回填 |
|
||||
| `fileUrl` | string / null | 发票 PDF 下载 URL(OSS 直链),开票后回填 |
|
||||
| `pdfName` | string / null | PDF 文件名,如 `"invoice_202606230001.pdf"` |
|
||||
| `pdfSize` | string / null | PDF 大小(字节数),字符串,如 `"204800"` |
|
||||
| `issuedBy` | string / null | 开票操作人姓名 |
|
||||
| `issuedAt` | string / null | 开票时间,ISO 8601 |
|
||||
|
||||
### 推送痕迹(PUSHED 后有值)
|
||||
|
||||
| 字段名 | 类型 | 说明 |
|
||||
|--------|------|------|
|
||||
| `pushedAt` | string / null | 推送时间,ISO 8601 |
|
||||
| `pushedChannels` | array(string) / null | 推送渠道列表,如 `["EMAIL","WECHAT"]`;未推送为 null |
|
||||
|
||||
### 订单冗余字段
|
||||
|
||||
| 字段名 | 类型 | 说明 |
|
||||
|--------|------|------|
|
||||
| `productName` | string | 产品名称 |
|
||||
| `tierName` | string / null | 产品档次名称 |
|
||||
| `contactName` | string | 客户联系人姓名 |
|
||||
| `customizerName` | string / null | 定制师姓名 |
|
||||
| `departureDate` | string | 出发日期,格式 `YYYY-MM-DD` |
|
||||
|
||||
---
|
||||
|
||||
## 枚举 / 数据字典
|
||||
|
||||
### 发票类型(invoiceType)
|
||||
|
||||
| 枚举值 | 中文名 | 说明 |
|
||||
|--------|--------|------|
|
||||
| `VAT_NORMAL` | 增值税普通发票 | 普票,专票四项字段均为 null |
|
||||
| `VAT_SPECIAL` | 增值税专用发票 | 专票,bankName / bankAccount / registAddress / registPhone 有值 |
|
||||
| `ELECTRONIC` | 电子发票 | 电子普票,mailAddress 为 null,仅 email 有值 |
|
||||
|
||||
### 抬头类型(titleType)
|
||||
|
||||
| 枚举值 | 中文名 |
|
||||
|--------|--------|
|
||||
| `COMPANY` | 企业 |
|
||||
| `PERSONAL` | 个人 |
|
||||
|
||||
### 发票状态(status)
|
||||
|
||||
| 枚举值 | 中文名 | 说明 |
|
||||
|--------|--------|------|
|
||||
| `REQUESTED` | 待开票 | 申请已提交,财务未处理 |
|
||||
| `ISSUED` | 已开票(待推送) | 财务已上传 PDF,尚未推送给客户 |
|
||||
| `PUSHED` | 已推送 | 已推送给客户 |
|
||||
| `VOIDED` | 已作废 | 该发票已作废 |
|
||||
|
||||
---
|
||||
|
||||
## 错误码
|
||||
|
||||
| 错误码 | 含义 | 触发场景 |
|
||||
|--------|------|---------|
|
||||
| `581500` | 发票不存在 | 传入的 `id` 在库中不存在或已软删除 |
|
||||
| `401` | 未授权 | 未携带有效 JWT |
|
||||
| `403` | 无权限 | 当前账号无发票管理权限 |
|
||||
|
||||
---
|
||||
|
||||
## 示例
|
||||
|
||||
### 典型成功(REQUESTED 状态,普票,全字段)
|
||||
|
||||
请求:
|
||||
```
|
||||
GET /v3/admin/order/invoice/1934567890123456789
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
响应:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"id": "1934567890123456789",
|
||||
"orderId": "1920000000000000001",
|
||||
"orderNo": "ORD2026062300001",
|
||||
"invoiceType": "VAT_NORMAL",
|
||||
"invoiceTypeText": "增值税普通发票",
|
||||
"titleType": "COMPANY",
|
||||
"titleName": "呼籁科技有限公司",
|
||||
"taxNo": "91310000XXXXXXXXXX",
|
||||
"bankName": null,
|
||||
"bankAccount": null,
|
||||
"registAddress": null,
|
||||
"registPhone": null,
|
||||
"amount": "98600",
|
||||
"email": "finance@hulalv.com",
|
||||
"mailAddress": null,
|
||||
"applyReason": "报销使用",
|
||||
"status": "REQUESTED",
|
||||
"statusText": "待开票",
|
||||
"requestedBy": "张三",
|
||||
"requestedAt": "2026-06-20T14:30:00",
|
||||
"invoiceNo": null,
|
||||
"fileUrl": null,
|
||||
"pdfName": null,
|
||||
"pdfSize": null,
|
||||
"issuedBy": null,
|
||||
"issuedAt": null,
|
||||
"pushedAt": null,
|
||||
"pushedChannels": null,
|
||||
"productName": "云南香格里拉深度游5日",
|
||||
"tierName": "标准档",
|
||||
"contactName": "李四",
|
||||
"customizerName": "王五",
|
||||
"departureDate": "2026-07-10"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 边界情况(ISSUED 状态,含 fileUrl / invoiceNo,专票四项有值)
|
||||
|
||||
请求:
|
||||
```
|
||||
GET /v3/admin/order/invoice/1934567890123456790
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
响应:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"id": "1934567890123456790",
|
||||
"orderId": "1920000000000000002",
|
||||
"orderNo": "ORD2026062200001",
|
||||
"invoiceType": "VAT_SPECIAL",
|
||||
"invoiceTypeText": "增值税专用发票",
|
||||
"titleType": "COMPANY",
|
||||
"titleName": "某某贸易有限公司",
|
||||
"taxNo": "91310000YYYYYYYYYY",
|
||||
"bankName": "工商银行上海支行",
|
||||
"bankAccount": "6222 0000 0000 0001",
|
||||
"registAddress": "上海市浦东新区XX路XX号",
|
||||
"registPhone": "021-12345678",
|
||||
"amount": "150000",
|
||||
"email": null,
|
||||
"mailAddress": "上海市浦东新区财务部",
|
||||
"applyReason": null,
|
||||
"status": "ISSUED",
|
||||
"statusText": "已开票(待推送)",
|
||||
"requestedBy": "赵六",
|
||||
"requestedAt": "2026-06-21T09:00:00",
|
||||
"invoiceNo": "20260623000001",
|
||||
"fileUrl": "https://oss.hulalv.com/invoice/202606/invoice_20260623000001.pdf",
|
||||
"pdfName": "invoice_20260623000001.pdf",
|
||||
"pdfSize": "204800",
|
||||
"issuedBy": "财务小陈",
|
||||
"issuedAt": "2026-06-22T16:00:00",
|
||||
"pushedAt": null,
|
||||
"pushedChannels": null,
|
||||
"productName": "西藏拉萨朝圣7日",
|
||||
"tierName": "尊享档",
|
||||
"contactName": "赵六",
|
||||
"customizerName": "孙七",
|
||||
"departureDate": "2026-08-01"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 业务失败(发票不存在)
|
||||
|
||||
请求:
|
||||
```
|
||||
GET /v3/admin/order/invoice/9999999999999999999
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
响应:
|
||||
```json
|
||||
{
|
||||
"code": 581500,
|
||||
"msg": "发票不存在",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 业务边界
|
||||
|
||||
**适用场景**
|
||||
- 财务在「上传发票 PDF」弹窗打开时调用,回显完整申请明细
|
||||
- 发票详情页查看全量开票及推送信息
|
||||
|
||||
**不适用场景**
|
||||
- 批量查询多张发票(用列表接口 `GET /v3/admin/order/invoice/page`)
|
||||
- 小程序端查询发票(本接口仅管理后台)
|
||||
|
||||
**特殊边界**
|
||||
- 专票四项字段(`bankName` / `bankAccount` / `registAddress` / `registPhone`):仅 `invoiceType=VAT_SPECIAL` 时有值,前端按 invoiceType 决定是否展示这四项
|
||||
- 开票痕迹字段(`invoiceNo` / `fileUrl` / `pdfName` / `pdfSize` / `issuedBy` / `issuedAt`):状态为 `ISSUED` 或 `PUSHED` 时有值,`REQUESTED` 和 `VOIDED` 时为 null
|
||||
- 推送痕迹字段(`pushedAt` / `pushedChannels`):仅 `PUSHED` 时有值
|
||||
- `amount` 单位为**分**,前端展示时除以 100 转为元
|
||||
|
||||
---
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. `id` / `orderId` 为 Long 雪花 ID,前端必须以**字符串**接收,不可用 JS number 类型(会丢失精度)
|
||||
2. `amount` 单位为**分**,字符串格式,展示时除以 100 转为元
|
||||
3. `pdfSize` 单位为**字节**,字符串格式,展示时自行换算为 KB / MB
|
||||
4. `pushedChannels` 未推送时为 null,不是空数组 `[]`,前端判断时注意区分
|
||||
|
||||
---
|
||||
|
||||
## 关联 / 联系人
|
||||
|
||||
| 项 | 内容 |
|
||||
|----|------|
|
||||
| **Issue** | [#4258 发票详情接口](https://git.1814.love:8443/wx/HL/issues/4258) |
|
||||
| **PR** | [#4262](https://git.1814.love:8443/wx/HL/pulls/4262) |
|
||||
| **后端负责人** | yst |
|
||||
@ -0,0 +1,444 @@
|
||||
# 发票列表 page 结构调整(破坏性变更)
|
||||
|
||||
> 变更类型:修改接口(破坏性)
|
||||
> 端类型:管理后台
|
||||
> 日期:2026-06-23 | Issue:#4265 / #4271 | PR:#4267 / #4271 / #4272 | 服务:hl-order-service-v3
|
||||
|
||||
> **破坏性变更**:`tabCounts` 和 `stats` 两个字段的数据结构均已从扁平对象改为数组,前端 tab 角标读取、统计卡渲染、列表行新增字段**全部需要改动**,上线时前后端需同步发布。
|
||||
|
||||
---
|
||||
|
||||
## 接口背景
|
||||
|
||||
财务发票管理列表本轮进行了三项结构升级:
|
||||
|
||||
1. **列表行**新增订单冗余字段(产品、出行人数、定制师等),让财务在列表页即可看到关键订单信息
|
||||
2. **新增 NONE tab**(未申请),支持代客申请场景——展示已完成但尚未申请发票的订单
|
||||
3. **`tabCounts` 和 `stats` 从扁平对象改为数组**,便于前端遍历渲染、后端动态扩展 tab 和统计维度
|
||||
|
||||
---
|
||||
|
||||
## 变更清单
|
||||
|
||||
| # | 变更类型 | 具体内容 |
|
||||
|---|---------|---------|
|
||||
| 1 | 出参新增字段 | `records[]` 行新增 `orderNo`(补回填)、`productName`、`tierName`、`contactName`、`customizerName`、`departureDate`、`adultCount`、`childCount`、`youngChildCount` 共 9 个字段 |
|
||||
| 2 | 入参新增枚举值 | `tab` 参数新增 `NONE`(未申请),返回「已完成且无有效发票」的订单行 |
|
||||
| 3 | 出参结构破坏性变更 | `tabCounts` 从扁平对象改为数组 TabCountItem[] |
|
||||
| 4 | 出参结构破坏性变更 | `stats` 从扁平对象改为数组 StatItem[] |
|
||||
|
||||
---
|
||||
|
||||
## 接口详情
|
||||
|
||||
| 项 | 说明 |
|
||||
|---|------|
|
||||
| **方法 + 路径** | `GET /v3/admin/order/invoice/page` |
|
||||
| **接口名** | 财务发票管理列表(分页) |
|
||||
| **描述** | 分页查询发票列表,支持多 tab 过滤、统计卡汇总、tab 计数角标 |
|
||||
| **认证** | 管理后台 JWT(Bearer Token) |
|
||||
| **幂等性** | 只读,天然幂等 |
|
||||
| **限流** | 无特殊限流 |
|
||||
|
||||
---
|
||||
|
||||
## 接口入参
|
||||
|
||||
### Query 参数
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| `tab` | string | 否 | Tab 过滤,见枚举节;默认 `ALL`;**本次新增 `NONE`** |
|
||||
| `pageNo` | integer | 否 | 页码,默认 1 |
|
||||
| `pageSize` | integer | 否 | 每页条数,默认 20,最大 100 |
|
||||
| `keyword` | string | 否 | 关键词搜索(订单号、客户名、定制师名) |
|
||||
| `invoiceType` | string | 否 | 发票类型过滤,见枚举 |
|
||||
| `startDate` | string | 否 | 申请日期起,格式 `YYYY-MM-DD` |
|
||||
| `endDate` | string | 否 | 申请日期止,格式 `YYYY-MM-DD` |
|
||||
|
||||
### 请求体
|
||||
|
||||
无。
|
||||
|
||||
---
|
||||
|
||||
## 出参字段
|
||||
|
||||
返回结构:`Result<PageResult<AdminInvoicePageRespVO>>`,分页对象顶层附带 `tabCounts`(数组)和 `stats`(数组)。
|
||||
|
||||
### 分页包装层
|
||||
|
||||
| 字段名 | 类型 | 说明 |
|
||||
|--------|------|------|
|
||||
| `total` | integer | 总条数 |
|
||||
| `pageNo` | integer | 当前页码 |
|
||||
| `pageSize` | integer | 每页大小 |
|
||||
| `records` | array | 当前页数据行,见下表 |
|
||||
| `tabCounts` | array | 各 tab 计数数组(**已改为数组**),见 TabCountItem |
|
||||
| `stats` | array | 统计卡汇总数组(**已改为数组**),见 StatItem |
|
||||
|
||||
### records[] 行字段
|
||||
|
||||
| 字段名 | 类型 | 说明 |
|
||||
|--------|------|------|
|
||||
| `id` | string / null | 发票 ID;**NONE tab 行为 null** |
|
||||
| `orderId` | string | 订单 ID |
|
||||
| `orderNo` | string | 订单编号(本次补充回填,原定义但无值) |
|
||||
| `invoiceType` | string / null | 发票类型;NONE tab 行为 null |
|
||||
| `invoiceTypeText` | string / null | 发票类型中文名;NONE tab 行为 null |
|
||||
| `titleName` | string / null | 发票抬头;NONE tab 行为 null |
|
||||
| `amount` | string / null | 开票金额(分),字符串;NONE tab 行为 null |
|
||||
| `status` | string | 发票状态;NONE tab 行固定为 `"NONE"` |
|
||||
| `statusText` | string | 发票状态中文名;NONE tab 行固定为 `"未申请"` |
|
||||
| `requestedAt` | string / null | 申请时间;NONE tab 行为 null |
|
||||
| `productName` | string | 产品名称(新增) |
|
||||
| `tierName` | string / null | 产品档次名称(新增) |
|
||||
| `contactName` | string | 客户联系人姓名(新增) |
|
||||
| `customizerName` | string / null | 定制师姓名(新增) |
|
||||
| `departureDate` | string | 出发日期,格式 `YYYY-MM-DD`(新增) |
|
||||
| `adultCount` | integer | 成人数(新增) |
|
||||
| `childCount` | integer | 儿童数(新增) |
|
||||
| `youngChildCount` | integer | 婴儿数(新增) |
|
||||
|
||||
> 出行人数展示:将 `adultCount` / `childCount` / `youngChildCount` 三值组合为「2成人1儿童」等文案,数量为 0 的维度可省略。
|
||||
|
||||
### TabCountItem 字段
|
||||
|
||||
| 字段名 | 类型 | 说明 |
|
||||
|--------|------|------|
|
||||
| `code` | string | Tab 枚举值 |
|
||||
| `name` | string | Tab 中文名 |
|
||||
| `count` | integer | 该 tab 下的条数 |
|
||||
|
||||
### StatItem 字段
|
||||
|
||||
| 字段名 | 类型 | 说明 |
|
||||
|--------|------|------|
|
||||
| `code` | string | 统计维度枚举值 |
|
||||
| `name` | string | 统计维度中文名(直接渲染,无需前端自行拼接) |
|
||||
| `count` | integer | 该维度数量 |
|
||||
| `amount` | string | 该维度金额,单位分,字符串,保留两位小数,如 `"98600.00"` |
|
||||
|
||||
---
|
||||
## 枚举 / 数据字典
|
||||
|
||||
### tab 入参枚举(含新增 NONE)
|
||||
|
||||
| 枚举值 | 说明 | records 行特征 |
|
||||
|--------|------|--------------|
|
||||
| `REQUESTED` | 待开票 | 正常发票行,发票字段有值 |
|
||||
| `ISSUED` | 待推送(已开票) | 正常发票行,fileUrl 有值 |
|
||||
| `PUSHED` | 已推送 | 正常发票行,pushedAt 有值 |
|
||||
| `NONE` | 未申请(新增) | 订单行,id / invoiceType 等发票字段均为 null,status="NONE" |
|
||||
| `ALL` | 全部 | 混合行,包含 NONE 行和发票行 |
|
||||
|
||||
### tabCounts 数组 code 枚举
|
||||
|
||||
| code | name |
|
||||
|------|------|
|
||||
| `REQUESTED` | 待开票 |
|
||||
| `ISSUED` | 待推送 |
|
||||
| `PUSHED` | 已推送 |
|
||||
| `NONE` | 未申请 |
|
||||
| `ALL` | 全部 |
|
||||
|
||||
### stats 数组 code 枚举
|
||||
|
||||
| code | name | 备注 |
|
||||
|------|------|------|
|
||||
| `REQUESTED` | 待开票 | 待处理发票的金额汇总 |
|
||||
| `ISSUED` | 已开票·待推送 | 含义与 tabCounts 中 ISSUED 相同,语境不同 |
|
||||
| `PUSHED` | 已推送 | 已推送给客户的金额汇总 |
|
||||
| `CURRENT_MONTH_ISSUED` | 本月已开票 | 当月开票汇总(跨 ISSUED + PUSHED) |
|
||||
|
||||
> `ISSUED` 在 tabCounts 中文名是「待推送」,在 stats 中文名是「已开票·待推送」,含义相同但语境不同。后端按语境在 `name` 字段直接返回正确文案,前端**直接渲染 `name`,不要按 code 自行拼文案**。
|
||||
|
||||
### 发票类型(invoiceType)
|
||||
|
||||
| 枚举值 | 中文名 |
|
||||
|--------|--------|
|
||||
| `VAT_NORMAL` | 增值税普通发票 |
|
||||
| `VAT_SPECIAL` | 增值税专用发票 |
|
||||
| `ELECTRONIC` | 电子发票 |
|
||||
|
||||
---
|
||||
|
||||
## 错误码
|
||||
|
||||
| 错误码 | 含义 | 触发场景 |
|
||||
|--------|------|---------|
|
||||
| `401` | 未授权 | 未携带有效 JWT |
|
||||
| `403` | 无权限 | 当前账号无发票管理权限 |
|
||||
| `400` | 参数错误 | `tab` 传入不存在的枚举值 |
|
||||
|
||||
---
|
||||
## 示例
|
||||
|
||||
### 典型成功(ALL tab,返回数组结构)
|
||||
|
||||
请求:
|
||||
```
|
||||
GET /v3/admin/order/invoice/page?tab=ALL&pageNo=1&pageSize=20
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
响应:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"total": 12,
|
||||
"pageNo": 1,
|
||||
"pageSize": 20,
|
||||
"records": [
|
||||
{
|
||||
"id": "1934567890123456789",
|
||||
"orderId": "1920000000000000001",
|
||||
"orderNo": "ORD2026062300001",
|
||||
"invoiceType": "VAT_NORMAL",
|
||||
"invoiceTypeText": "增值税普通发票",
|
||||
"titleName": "呼籁科技有限公司",
|
||||
"amount": "98600",
|
||||
"status": "REQUESTED",
|
||||
"statusText": "待开票",
|
||||
"requestedAt": "2026-06-20T14:30:00",
|
||||
"productName": "云南香格里拉深度游5日",
|
||||
"tierName": "标准档",
|
||||
"contactName": "李四",
|
||||
"customizerName": "王五",
|
||||
"departureDate": "2026-07-10",
|
||||
"adultCount": 2,
|
||||
"childCount": 1,
|
||||
"youngChildCount": 0
|
||||
}
|
||||
],
|
||||
"tabCounts": [
|
||||
{ "code": "REQUESTED", "name": "待开票", "count": 3 },
|
||||
{ "code": "ISSUED", "name": "待推送", "count": 2 },
|
||||
{ "code": "PUSHED", "name": "已推送", "count": 2 },
|
||||
{ "code": "NONE", "name": "未申请", "count": 5 },
|
||||
{ "code": "ALL", "name": "全部", "count": 12 }
|
||||
],
|
||||
"stats": [
|
||||
{ "code": "REQUESTED", "name": "待开票", "count": 3, "amount": "1000.00" },
|
||||
{ "code": "ISSUED", "name": "已开票·待推送", "count": 2, "amount": "98600.00" },
|
||||
{ "code": "PUSHED", "name": "已推送", "count": 2, "amount": "50000.00" },
|
||||
{ "code": "CURRENT_MONTH_ISSUED", "name": "本月已开票", "count": 4, "amount": "148600.00" }
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 边界情况(NONE tab,发票字段为 null 的订单行)
|
||||
|
||||
请求:
|
||||
```
|
||||
GET /v3/admin/order/invoice/page?tab=NONE&pageNo=1&pageSize=20
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
响应:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"total": 5,
|
||||
"pageNo": 1,
|
||||
"pageSize": 20,
|
||||
"records": [
|
||||
{
|
||||
"id": null,
|
||||
"orderId": "1920000000000000099",
|
||||
"orderNo": "ORD2026062200099",
|
||||
"invoiceType": null,
|
||||
"invoiceTypeText": null,
|
||||
"titleName": null,
|
||||
"amount": null,
|
||||
"status": "NONE",
|
||||
"statusText": "未申请",
|
||||
"requestedAt": null,
|
||||
"productName": "西藏拉萨朝圣7日",
|
||||
"tierName": null,
|
||||
"contactName": "钱八",
|
||||
"customizerName": "孙九",
|
||||
"departureDate": "2026-06-15",
|
||||
"adultCount": 4,
|
||||
"childCount": 0,
|
||||
"youngChildCount": 1
|
||||
}
|
||||
],
|
||||
"tabCounts": [
|
||||
{ "code": "REQUESTED", "name": "待开票", "count": 3 },
|
||||
{ "code": "ISSUED", "name": "待推送", "count": 2 },
|
||||
{ "code": "PUSHED", "name": "已推送", "count": 2 },
|
||||
{ "code": "NONE", "name": "未申请", "count": 5 },
|
||||
{ "code": "ALL", "name": "全部", "count": 12 }
|
||||
],
|
||||
"stats": [
|
||||
{ "code": "REQUESTED", "name": "待开票", "count": 3, "amount": "1000.00" },
|
||||
{ "code": "ISSUED", "name": "已开票·待推送", "count": 2, "amount": "98600.00" },
|
||||
{ "code": "PUSHED", "name": "已推送", "count": 2, "amount": "50000.00" },
|
||||
{ "code": "CURRENT_MONTH_ISSUED", "name": "本月已开票", "count": 4, "amount": "148600.00" }
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 业务失败(tab 枚举值不存在)
|
||||
|
||||
请求:
|
||||
```
|
||||
GET /v3/admin/order/invoice/page?tab=INVALID
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
响应:
|
||||
```json
|
||||
{
|
||||
"code": 400,
|
||||
"msg": "参数错误:tab 枚举值不合法",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
## 业务边界
|
||||
|
||||
**适用场景**
|
||||
- 财务管理后台「发票管理」列表页
|
||||
- 代客申请场景:切换到 NONE tab 查看「已完成但未申请发票」的订单,点击进入代客申请流程
|
||||
|
||||
**不适用场景**
|
||||
- 小程序端查看发票状态(走小程序端专属接口)
|
||||
- 查询单张发票全量明细(走 `GET /v3/admin/order/invoice/{id}` 详情接口)
|
||||
|
||||
**特殊边界**
|
||||
- NONE tab 行是订单行,不是发票行:`id` 为 null,发票字段均为 null,`status` 固定为字符串 `"NONE"`,前端需按 status 判断是否展示发票操作按钮
|
||||
- ALL tab 混合 NONE 行和发票行:遍历 records 时需按 `status === "NONE"` 区分行类型
|
||||
- `amount` 单位为分,字符串格式,前端展示时除以 100 转为元
|
||||
|
||||
---
|
||||
|
||||
## 修改前后对比
|
||||
|
||||
### tabCounts 字段
|
||||
|
||||
旧(扁平对象):
|
||||
```json
|
||||
{
|
||||
"tabCounts": {
|
||||
"requestedCount": 3,
|
||||
"issuedCount": 2,
|
||||
"pushedCount": 2,
|
||||
"allCount": 12,
|
||||
"noneCount": 5
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
新(数组,现行):
|
||||
```json
|
||||
{
|
||||
"tabCounts": [
|
||||
{ "code": "REQUESTED", "name": "待开票", "count": 3 },
|
||||
{ "code": "ISSUED", "name": "待推送", "count": 2 },
|
||||
{ "code": "PUSHED", "name": "已推送", "count": 2 },
|
||||
{ "code": "NONE", "name": "未申请", "count": 5 },
|
||||
{ "code": "ALL", "name": "全部", "count": 12 }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### stats 字段
|
||||
|
||||
旧(扁平对象):
|
||||
```json
|
||||
{
|
||||
"stats": {
|
||||
"requestedCount": 3,
|
||||
"requestedAmount": 1000,
|
||||
"issuedCount": 2,
|
||||
"issuedAmount": 98600,
|
||||
"pushedCount": 2,
|
||||
"pushedAmount": 50000,
|
||||
"currentMonthIssuedCount": 4,
|
||||
"currentMonthIssuedAmount": 148600
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
新(数组,现行):
|
||||
```json
|
||||
{
|
||||
"stats": [
|
||||
{ "code": "REQUESTED", "name": "待开票", "count": 3, "amount": "1000.00" },
|
||||
{ "code": "ISSUED", "name": "已开票·待推送", "count": 2, "amount": "98600.00" },
|
||||
{ "code": "PUSHED", "name": "已推送", "count": 2, "amount": "50000.00" },
|
||||
{ "code": "CURRENT_MONTH_ISSUED", "name": "本月已开票", "count": 4, "amount": "148600.00" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### tab 入参新增值
|
||||
|
||||
| 旧可选值 | 新增值 |
|
||||
|---------|--------|
|
||||
| REQUESTED / ISSUED / PUSHED / ALL | 新增 `NONE`(未申请) |
|
||||
|
||||
### records[] 行新增字段
|
||||
|
||||
| 字段 | 变化 |
|
||||
|------|------|
|
||||
| `orderNo` | 原已定义,本次补充回填(实际有值) |
|
||||
| `productName` | 新增 |
|
||||
| `tierName` | 新增 |
|
||||
| `contactName` | 新增 |
|
||||
| `customizerName` | 新增 |
|
||||
| `departureDate` | 新增 |
|
||||
| `adultCount` | 新增 |
|
||||
| `childCount` | 新增 |
|
||||
| `youngChildCount` | 新增 |
|
||||
|
||||
---
|
||||
|
||||
## 影响评估 / 回滚
|
||||
|
||||
### 破坏兼容性评估
|
||||
|
||||
| 模块 | 是否影响 | 必须改动 |
|
||||
|------|---------|---------|
|
||||
| Tab 角标数字渲染 | 是 | 旧代码读 `tabCounts.requestedCount` 等扁平字段会 undefined,需改为遍历数组按 `code` 取值 |
|
||||
| 统计卡渲染 | 是 | 旧代码读 `stats.requestedCount` / `stats.requestedAmount` 等扁平字段会 undefined,需改为遍历数组按 `code` 取 `count` / `amount` |
|
||||
| 列表行渲染 | 需新增 | 新增 9 个字段需接线渲染(产品名、出行人数组合、定制师、出发日期等) |
|
||||
| NONE tab 处理 | 需新增 | NONE tab 下行无发票 `id`,代客申请按钮需按 `status==="NONE"` 判断 |
|
||||
| ALL tab 混合行 | 需新增 | ALL tab 下需区分 NONE 行和正常发票行 |
|
||||
|
||||
### 前端同步上线要求
|
||||
|
||||
本次变更前后端需同步发布。旧前端读新后端的数组结构,tab 角标和统计卡均会渲染为空。
|
||||
|
||||
### 回滚方案
|
||||
|
||||
如需回滚后端,通知前端同步回滚对应代码;两端数据结构不匹配会导致 tab 角标消失和统计卡白屏。
|
||||
|
||||
---
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. `tabCounts` 和 `stats` **均已变为数组**,旧的扁平对象键名已全部废弃,前端读取方式必须更新
|
||||
2. NONE tab 行中 `status` 是字符串 `"NONE"`,而不是 null,前端用 `status === "NONE"` 判断行类型
|
||||
3. `stats` 中的 `amount` 单位为**分**,字符串格式,保留两位小数,前端展示时除以 100 转为元
|
||||
4. `ISSUED` 在 tabCounts 和 stats 中 `name` 不同,直接渲染 `name` 字段即可,不要自行拼接
|
||||
5. `adultCount` / `childCount` / `youngChildCount` 为整数,0 的维度建议展示时省略
|
||||
|
||||
---
|
||||
|
||||
## 关联 / 联系人
|
||||
|
||||
| 项 | 内容 |
|
||||
|----|------|
|
||||
| **Issue** | [#4265 发票列表 NONE tab](https://git.1814.love:8443/wx/HL/issues/4265) / [#4271 列表订单冗余字段](https://git.1814.love:8443/wx/HL/issues/4271) |
|
||||
| **PR** | [#4267](https://git.1814.love:8443/wx/HL/pulls/4267) / [#4271](https://git.1814.love:8443/wx/HL/pulls/4271) / [#4272 stats 拍平](https://git.1814.love:8443/wx/HL/pulls/4272) |
|
||||
| **后端负责人** | yst |
|
||||
正在加载...
x
在新工单中引用
屏蔽一个用户