feat(changelog): 退款明细Tab懒加载出参重构——新增退款原因+申请时间,删除预计到账和逐项明细,修正退款渠道语义 (#4418)

这个提交包含在:
yaosutu 2026-06-26 09:59:26 +08:00
父节点 b9f588737e
当前提交 23d659a74b

查看文件

@ -0,0 +1,324 @@
# 退款明细 Tab 懒加载——出参契约重构
- **接口**`GET /v3/admin/order/{id}/refund`
- **变更类型**:修改接口(出参字段调整)
- **日期**2026-06-26
- **Issue**[#4417](https://git.1814.love:8443/wx/HL/issues/4417)
- **PR**[#4418](https://git.1814.love:8443/wx/HL/pulls/4418)
- **后端负责人**yst
---
## ① 接口背景
订单详情页「退款明细」Tab 采用懒加载模式,前端单独调用此接口获取退款数据。
本次重构对出参 VO 结构进行语义修正:补充「退款原因」和「申请时间」两个展示字段,删除不展示的 `estimatedArriveDate`(预计到账日期)和 `items`(逐项明细)块,同时修正 `refundChannel` 字段的语义(此前误返回退款类型枚举值,现在统一返回真实渠道文案)。
---
## ② 变更清单
| 类型 | 字段 | 说明 |
|------|------|------|
| ✨ 新增 | `applications[].reason` | 退款原因文字 |
| ✨ 新增 | `applications[].appliedAt` | 退款申请时间 |
| ⚠️ 删除 | `applications[].estimatedArriveDate` | 预计到账日期,不再返回 |
| ⚠️ 删除 | `applications[].items[]` | 退款逐项明细块,不再返回 |
| 🔧 语义修正 | `applications[].refundChannel` | 固定返回 `"原路退回(微信)"` 字符串,不再返回退款类型枚举值 |
---
## ③ 接口详情
| 项目 | 值 |
|------|-----|
| **方法** | GET |
| **路径** | `/v3/admin/order/{id}/refund` |
| **描述** | 获取订单退款明细Tab 懒加载) |
| **认证** | 需要管理后台 JWTBearer Token |
| **幂等性** | 只读接口,天然幂等 |
| **限流** | 无特殊限流 |
---
## ④ 入参
### 4.1 路径参数
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `id` | Long字符串传输 | 是 | 订单 ID |
### 4.2 请求体
无请求体。
---
## ⑤ 出参字段
**顶层结构RefundDetailVO**
| 字段 | 类型 | 说明 |
|------|------|------|
| `totalRefundAmount` | StringBigDecimal 序列化) | 合计退款金额,单位:元 |
| `applications` | Array\<RefundApplicationVO\> | 退款申请列表(全部历史申请) |
> 当订单无任何退款申请时,整个 `refund` 节点返回 `null`,前端据此隐藏 Tab。
**applications[] 元素RefundApplicationVO——完整字段**
| 字段 | 类型 | 说明 |
|------|------|------|
| `applicationId` | Long字符串序列化 | 退款申请 ID |
| `status` | String | 退款进度状态码(见 §⑥ 枚举) |
| `statusText` | String | 状态文案,如 `"待审批"` |
| `refundAmount` | StringBigDecimal 序列化) | 退款金额(实退额为空时回退计算额),单位:元 |
| `refundChannel` | String | 退款渠道,固定返回 `"原路退回(微信)"` |
| `reason` | String | **【新增】** 退款原因,如 `"同行儿童突发感冒,不参与本次出行"` |
| `appliedAt` | StringISO 8601 LocalDateTime | **【新增】** 申请时间,如 `"2026-04-25T11:30:00"` |
| `approverName` | String | 审批人姓名,未审批时为 `null` |
| `approvedAt` | StringISO 8601 LocalDateTime | 审批时间,未审批时为 `null` |
| `actualArriveDate` | StringISO 8601 LocalDate | 实际到账日期,未到账时为 `null` |
| `progress` | Array\<ProgressStepVO\> | 4 步时间线APPLY / APPROVE / PAYOUT / ARRIVED |
**progress[] 元素ProgressStepVO**
| 字段 | 类型 | 说明 |
|------|------|------|
| `step` | String | 步骤码:`APPLY` / `APPROVE` / `PAYOUT` / `ARRIVED` |
| `label` | String | 步骤中文标签,如 `"已申请"` |
| `status` | String | 步骤状态:`DONE`(已完成)/ `ACTIVE`(进行中)/ `PENDING`(待进行) |
| `occurredAt` | StringISO 8601 | 该步骤发生时间,未到达时为 `null` |
---
## ⑥ 枚举 / 数据字典
### refundChannel退款渠道
| 值 | 含义 |
|----|------|
| `"原路退回(微信)"` | 系统当前唯一退款渠道,所有退款均原路退至微信支付 |
> 注意:此前误将退款类型枚举值(如 `PARTIAL` / `FULL`)回填到该字段,本次已修正为真实渠道文案。
### applications[].status退款申请状态
| 值 | 含义 |
|----|------|
| `PENDING_APPROVE` | 待审批 |
| `PENDING_PAYOUT` | 审批通过,待退款打出 |
| `PENDING_ARRIVAL` | 退款已发出,待到账 |
| `COMPLETED` | 已完成到账 |
| `REJECTED` | 已驳回 |
### progress[].status时间线步骤状态
| 值 | 含义 |
|----|------|
| `DONE` | 该步骤已完成 |
| `ACTIVE` | 当前正在该步骤 |
| `PENDING` | 尚未到达该步骤 |
---
## ⑦ 错误码
| 错误码 | 说明 | 触发条件 |
|--------|------|---------|
| `404` / 业务错误 | 订单不存在 | `id` 对应订单不存在 |
| `403` | 无权访问 | JWT 鉴权失败或无该订单访问权限 |
---
## ⑧ 示例
### 8.1 典型成功——订单含一笔退款申请(已完成)
**请求**
```http
GET /v3/admin/order/1902345678901234567/refund
Authorization: Bearer <admin-token>
```
**响应**
```json
{
"code": 200,
"msg": "success",
"data": {
"totalRefundAmount": "1280.00",
"applications": [
{
"applicationId": "1902345678901234568",
"status": "COMPLETED",
"statusText": "已完成",
"refundAmount": "1280.00",
"refundChannel": "原路退回(微信)",
"reason": "同行儿童突发感冒,不参与本次出行",
"appliedAt": "2026-04-25T11:30:00",
"approverName": "张三",
"approvedAt": "2026-04-25T14:00:00",
"actualArriveDate": "2026-04-27",
"progress": [
{
"step": "APPLY",
"label": "已申请",
"status": "DONE",
"occurredAt": "2026-04-25T11:30:00"
},
{
"step": "APPROVE",
"label": "已审批",
"status": "DONE",
"occurredAt": "2026-04-25T14:00:00"
},
{
"step": "PAYOUT",
"label": "退款已发出",
"status": "DONE",
"occurredAt": "2026-04-25T14:30:00"
},
{
"step": "ARRIVED",
"label": "已到账",
"status": "DONE",
"occurredAt": "2026-04-27T09:15:00"
}
]
}
]
}
}
```
---
### 8.2 边界情况——无退款申请refund 节点为 null
**请求**
```http
GET /v3/admin/order/1902345678901234999/refund
Authorization: Bearer <admin-token>
```
**响应**
```json
{
"code": 200,
"msg": "success",
"data": null
}
```
> 前端收到 `data``null` 时应隐藏「退款明细」Tab,不做渲染。
---
### 8.3 业务失败——订单不存在
**请求**
```http
GET /v3/admin/order/9999999999999999999/refund
Authorization: Bearer <admin-token>
```
**响应**
```json
{
"code": 404,
"msg": "订单不存在",
"data": null
}
```
---
## ⑨ 业务边界
**适用场景**
- 仅用于「退款明细」Tab 懒加载,不作为退款管理工作台的数据源
- 展示该订单全部退款申请历史(含已完成、已驳回的历史申请)
**不适用**
- 不返回退款政策/原因配置列表(有单独接口)
- 不返回退款工作台列表数据
**特殊边界**
- 一笔订单采用**串行退款**模式:前一笔退款完成后才能发起下一笔,正常情况下不会同时存在多个进行中的申请
- `refundAmount` 字段:实退额(`actualRefundAmount`)有值时返回实退额,否则返回前端计算额,前端无需特殊处理,直接展示即可
- `approverName` / `approvedAt`:待审批状态下为 `null`,前端渲染时需判空
---
## ⑩ 修改前后对比
### 字段级对比
| 字段 | 变更前 | 变更后 |
|------|--------|--------|
| `applications[].reason` | **不存在** | ✨ 新增,退款原因文字 |
| `applications[].appliedAt` | **不存在** | ✨ 新增,申请时间 ISO 8601 |
| `applications[].estimatedArriveDate` | ⚠️ 存在,预计到账日期 | **已删除**,不再返回 |
| `applications[].items[]` | ⚠️ 存在,逐项退款明细块 | **已删除**,不再返回 |
| `applications[].refundChannel` | 误返回退款类型枚举值(如 `PARTIAL` | 🔧 修正为渠道文案 `"原路退回(微信)"` |
### 行为级对比
| 场景 | 变更前 | 变更后 |
|------|--------|--------|
| 读取退款渠道 | 返回类型枚举 `PARTIAL`/`FULL`,前端当渠道用会显示错误 | 返回渠道文案,直接渲染即可 |
| 退款原因展示 | 无此字段,需前端单独请求其他接口 | 内联在申请对象中,无需额外请求 |
| 申请时间展示 | 无此字段 | 内联在申请对象中 |
---
## ⑪ 影响评估 / 回滚
**破坏兼容性变更(前端必须同步处理)**
- `estimatedArriveDate` 已从出参中删除,前端如有读取此字段的代码,收到 `undefined` 不会报错,但需确认是否有展示逻辑需要移除
- `items[]` 已从出参中删除,前端如有遍历 `items` 的渲染逻辑需要移除
- `refundChannel` 语义变化:若前端曾将该字段作为退款类型判断(如 `PARTIAL` → 部分退款),需改为直接展示文案,不再做枚举判断
**前端同步上线建议**
1. 移除 `estimatedArriveDate` 渲染逻辑
2. 移除 `items[]` 相关渲染块(如退款逐项明细表格)
3. `refundChannel` 改为直接渲染字符串,不做枚举 switch
4. 新增 `reason`(退款原因)和 `appliedAt`(申请时间)展示
**回滚方案**
- 若需回滚,回退 PR #4418 对应 commit 即可恢复旧出参结构
- 回滚后 `reason` / `appliedAt` 消失,`estimatedArriveDate` / `items[]` 恢复,`refundChannel` 恢复为枚举值
---
## ⑫ 注意事项
1. **`refundChannel` 不再是枚举值**:固定返回 `"原路退回(微信)"` 文案字符串,前端直接渲染,不要做枚举 switch 判断
2. **`appliedAt` 格式为 ISO 8601 LocalDateTime**(如 `"2026-04-25T11:30:00"`,无时区后缀),前端渲染时自行格式化
3. **`data` 为 null 时代表无退款**不是接口异常,是正常业务状态,Tab 应隐藏
4. **`actualArriveDate` 是 LocalDate**(仅日期 `"2026-04-27"`),与 `appliedAt` / `approvedAt`LocalDateTime格式不同,注意区分
5. **金额字段均为字符串**BigDecimal 序列化防 JS 精度丢失),不要用 `parseFloat` 直接计算
---
## ⑬ 关联 / 联系人
| 项目 | 链接 |
|------|------|
| Issue | [#4417 退款明细Tab懒加载出参重构](https://git.1814.love:8443/wx/HL/issues/4417) |
| PR | [#4418 feat(order-v3/refund): 退款明细Tab懒加载出参重构](https://git.1814.love:8443/wx/HL/pulls/4418) |
| 后端负责人 | yst |