diff --git a/changelogs-v2/2026-06/26_4417_退款明细Tab懒加载-修改接口-管理后台.md b/changelogs-v2/2026-06/26_4417_退款明细Tab懒加载-修改接口-管理后台.md new file mode 100644 index 0000000..ec3af23 --- /dev/null +++ b/changelogs-v2/2026-06/26_4417_退款明细Tab懒加载-修改接口-管理后台.md @@ -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 懒加载) | +| **认证** | 需要管理后台 JWT(Bearer Token) | +| **幂等性** | 只读接口,天然幂等 | +| **限流** | 无特殊限流 | + +--- + +## ④ 入参 + +### 4.1 路径参数 + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| `id` | Long(字符串传输) | 是 | 订单 ID | + +### 4.2 请求体 + +无请求体。 + +--- + +## ⑤ 出参字段 + +**顶层结构(RefundDetailVO)** + +| 字段 | 类型 | 说明 | +|------|------|------| +| `totalRefundAmount` | String(BigDecimal 序列化) | 合计退款金额,单位:元 | +| `applications` | Array\ | 退款申请列表(全部历史申请) | + +> 当订单无任何退款申请时,整个 `refund` 节点返回 `null`,前端据此隐藏 Tab。 + +**applications[] 元素(RefundApplicationVO)——完整字段** + +| 字段 | 类型 | 说明 | +|------|------|------| +| `applicationId` | Long(字符串序列化) | 退款申请 ID | +| `status` | String | 退款进度状态码(见 §⑥ 枚举) | +| `statusText` | String | 状态文案,如 `"待审批"` | +| `refundAmount` | String(BigDecimal 序列化) | 退款金额(实退额为空时回退计算额),单位:元 | +| `refundChannel` | String | 退款渠道,固定返回 `"原路退回(微信)"` | +| `reason` | String | **【新增】** 退款原因,如 `"同行儿童突发感冒,不参与本次出行"` | +| `appliedAt` | String(ISO 8601 LocalDateTime) | **【新增】** 申请时间,如 `"2026-04-25T11:30:00"` | +| `approverName` | String | 审批人姓名,未审批时为 `null` | +| `approvedAt` | String(ISO 8601 LocalDateTime) | 审批时间,未审批时为 `null` | +| `actualArriveDate` | String(ISO 8601 LocalDate) | 实际到账日期,未到账时为 `null` | +| `progress` | Array\ | 4 步时间线(APPLY / APPROVE / PAYOUT / ARRIVED) | + +**progress[] 元素(ProgressStepVO)** + +| 字段 | 类型 | 说明 | +|------|------|------| +| `step` | String | 步骤码:`APPLY` / `APPROVE` / `PAYOUT` / `ARRIVED` | +| `label` | String | 步骤中文标签,如 `"已申请"` | +| `status` | String | 步骤状态:`DONE`(已完成)/ `ACTIVE`(进行中)/ `PENDING`(待进行) | +| `occurredAt` | String(ISO 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 +``` + +**响应** + +```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 +``` + +**响应** + +```json +{ + "code": 200, + "msg": "success", + "data": null +} +``` + +> 前端收到 `data` 为 `null` 时应隐藏「退款明细」Tab,不做渲染。 + +--- + +### 8.3 业务失败——订单不存在 + +**请求** + +```http +GET /v3/admin/order/9999999999999999999/refund +Authorization: Bearer +``` + +**响应** + +```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 |