11 KiB
11 KiB
退款明细 Tab 懒加载——出参契约重构
① 接口背景
订单详情页「退款明细」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<RefundApplicationVO> | 退款申请列表(全部历史申请) |
当订单无任何退款申请时,整个
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<ProgressStepVO> | 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 典型成功——订单含一笔退款申请(已完成)
请求
GET /v3/admin/order/1902345678901234567/refund
Authorization: Bearer <admin-token>
响应
{
"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)
请求
GET /v3/admin/order/1902345678901234999/refund
Authorization: Bearer <admin-token>
响应
{
"code": 200,
"msg": "success",
"data": null
}
前端收到
data为null时应隐藏「退款明细」Tab,不做渲染。
8.3 业务失败——订单不存在
请求
GET /v3/admin/order/9999999999999999999/refund
Authorization: Bearer <admin-token>
响应
{
"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→ 部分退款),需改为直接展示文案,不再做枚举判断
前端同步上线建议
- 移除
estimatedArriveDate渲染逻辑 - 移除
items[]相关渲染块(如退款逐项明细表格) refundChannel改为直接渲染字符串,不做枚举 switch- 新增
reason(退款原因)和appliedAt(申请时间)展示
回滚方案
- 若需回滚,回退 PR #4418 对应 commit 即可恢复旧出参结构
- 回滚后
reason/appliedAt消失,estimatedArriveDate/items[]恢复,refundChannel恢复为枚举值
⑫ 注意事项
refundChannel不再是枚举值:固定返回"原路退回(微信)"文案字符串,前端直接渲染,不要做枚举 switch 判断appliedAt格式为 ISO 8601 LocalDateTime(如"2026-04-25T11:30:00",无时区后缀),前端渲染时自行格式化data为 null 时代表无退款:不是接口异常,是正常业务状态,Tab 应隐藏actualArriveDate是 LocalDate(仅日期"2026-04-27"),与appliedAt/approvedAt(LocalDateTime)格式不同,注意区分- 金额字段均为字符串(BigDecimal 序列化防 JS 精度丢失),不要用
parseFloat直接计算
⑬ 关联 / 联系人
| 项目 | 链接 |
|---|---|
| Issue | #4417 退款明细Tab懒加载出参重构 |
| PR | #4418 feat(order-v3/refund): 退款明细Tab懒加载出参重构 |
| 后端负责人 | yst |