商城售后退款
售后退款负责处理商城订单付款后的退款、退货退款、商家审核、收货确认和支付退款回调。RuoYi Office 当前管理端已经提供售后列表、售后详情、同意/拒绝售后、确认收货、拒绝收货和确认退款等能力。
本页基于当前 AfterSaleController、管理端 views/mall/trade/afterSale 和 Pay 退款回调链路整理,重点说明状态流转、操作权限和排查方法。
模块边界
| 层 | 路径 / 接口 |
|---|---|
| 后端模块 | ruoyi-office/yudao-module-mall/yudao-module-trade-server |
| 控制器 | controller/admin/aftersale/AfterSaleController.java |
| 服务 | service/aftersale/AfterSaleService、AfterSaleLogService |
| 订单服务 | TradeOrderQueryService、TradeOrderUpdateService |
| 支付联动 | cn.iocoder.yudao.module.pay.api.notify.dto.PayRefundNotifyReqDTO |
| 管理端页面 | apps/web-antd/src/views/mall/trade/afterSale |
| 管理端 API | apps/web-antd/src/api/mall/trade/afterSale/index.ts |
| 接口前缀 | /admin-api/trade/after-sale |
售后处理链路
实际状态值以 DICT_TYPE.TRADE_AFTER_SALE_STATUS 和后端枚举为准。管理端按钮会根据当前状态显示:待审核时显示“同意售后 / 拒绝售后”,待收货时显示“确认收货 / 拒绝收货”,待退款时显示“确认退款”。
管理端页面能力
售后列表
列表页位于 views/mall/trade/afterSale/index.vue,使用 Tabs + VbenVxeGrid 实现:
- 顶部 Tab 根据
TRADE_AFTER_SALE_STATUS字典生成。 - 切换状态后重新查询分页。
- 商品列展示图片、SPU 名称和规格属性。
- 订单号可跳转交易订单详情。
- “处理退款”进入售后详情页。
| 功能 | 接口 | 权限 |
|---|---|---|
| 售后分页 | GET /trade/after-sale/page | trade:after-sale:query |
| 售后详情 | GET /trade/after-sale/get-detail | trade:after-sale:query |
| 同意售后 | PUT /trade/after-sale/agree | trade:after-sale:agree |
| 拒绝售后 | PUT /trade/after-sale/disagree | trade:after-sale:disagree |
| 确认收货 | PUT /trade/after-sale/receive | trade:after-sale:receive |
| 拒绝收货 | PUT /trade/after-sale/refuse | trade:after-sale:receive |
| 确认退款 | PUT /trade/after-sale/refund | trade:after-sale:refund |
售后详情
详情页位于 views/mall/trade/afterSale/detail/index.vue,页面会组合展示:
- 订单信息:订单号、配送方式、订单类型、收货人、支付单号、付款方式、买家等。
- 售后信息:退款编号、申请时间、售后类型、售后方式、退款金额、申请原因、凭证图片等。
- 退款状态:当前状态和操作提醒。
- 商品信息:售后对应的订单项快照。
- 售后日志:系统、会员、运营人员的处理记录。
详情数据由 AfterSaleController#getOrderDetail 组合售后单、订单、订单项、会员和日志后返回,二次开发时不要只看售后主表。
退款回调链路
确认退款后,系统会通过 Pay 模块发起退款。退款成功后,Pay 通过 AfterSaleController#updateAfterSaleRefunded 通知交易模块更新售后单状态。
update-refunded 使用 @PermitAll,不是无保护接口。它的安全性依赖 Pay 模块回调参数、业务单号和服务内部校验。排查时要关注 merchantRefundId:
- 以
order-开头:表示订单级退款,调用tradeOrderUpdateService.updatePaidOrderRefunded。 - 其他值:按售后单退款处理,调用
afterSaleService.updateAfterSaleRefunded。
金额与图片字段
| 字段 | 含义 | 前端处理 |
|---|---|---|
refundPrice | 退款金额,单位分 | 详情页使用 fenToYuan 展示 |
applyPicUrls | 用户申请凭证图片 | 详情页用 Image 组件展示 |
payRefundId | Pay 退款单编号 | 用于和支付模块排查退款状态 |
log.content | 售后日志内容 | 详情页售后日志表格展示 |
新增金额字段时继续保持“后端分、前端元”的约定;新增凭证字段时要确认文件访问权限和图片 URL 是否可被管理端访问。
操作建议
- 待审核:先核对订单是否已发货、买家申请原因和凭证;未发货场景通常可以直接同意退款。
- 退货退款:同意后等待买家退货,收到货后再确认收货;实际未收到或商品异常时走拒绝收货。
- 确认退款:退款会进入 Pay 模块,需关注支付渠道是否支持原路退回以及退款任务是否正常。
- 拒绝售后:必须填写明确原因,便于客服和买家理解处理结果。
- 售后日志:每个关键动作都应有日志,方便后续审计和争议处理。
二次开发建议
- 新增状态:同步更新后端枚举、字典、前端 Tab、详情按钮显示条件和日志内容。
- 新增审核字段:修改 VO、Convert、详情 schema 和拒绝/审核弹窗。
- 接入仓库收货:可在确认收货前增加仓库质检、图片凭证或责任判定。
- 退款失败重试:优先在 Pay 退款单和回调任务层处理,不建议在售后单上直接跳过支付状态。
- 权限隔离:审核、收货、退款建议拆分给不同角色,避免一个运营账号完成所有敏感动作。
排查清单
| 现象 | 优先检查 |
|---|---|
| 列表 Tab 数量或状态不对 | TRADE_AFTER_SALE_STATUS 字典、分页查询条件、租户数据 |
| 详情页商品或订单信息为空 | 售后单关联的 orderId、orderItemId 是否存在 |
| 同意/拒绝按钮不显示 | 当前售后状态是否符合按钮 ifShow 条件,账号是否有权限 |
| 确认退款后状态不变 | Pay 退款单、退款渠道、PayNotifyJob、update-refunded 日志 |
| 凭证图片无法预览 | 文件 URL、访问权限、浏览器跨域或图片已被删除 |
| 金额显示异常 | 是否把“分”重复转换为“元”,或接口新增字段未按分返回 |
下一步
售后依赖交易订单和支付退款。建议配合阅读:
