|
@@ -0,0 +1,229 @@
|
|
|
|
|
+# 退款流程问题追踪 — 2026-07-12
|
|
|
|
|
+
|
|
|
|
|
+**发现日期**: 2026-07-12
|
|
|
|
|
+**模块**: 商城退款 / 售后管理 / Dashboard
|
|
|
|
|
+**发现人**: Sisyphus (代码审查)
|
|
|
|
|
+**来源**: 用户反馈 + 代码审查
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 问题总览
|
|
|
|
|
+
|
|
|
|
|
+| # | 问题ID | 模块 | 严重度 | 状态 | 描述 |
|
|
|
|
|
+|---|--------|------|:---:|------|------|
|
|
|
|
|
+| 1 | ~~ISSUE-007~~ | ~~小程序售后列表~~ | 🔴 高 | ✅ 已修复 | 状态筛选失效,`data: {}` 未传 status |
|
|
|
|
|
+| 2 | ~~ISSUE-008~~ | ~~退款到账中止~~ | 🔴 高 | ✅ 已修复 | cancelPendingRefund 未恢复订单状态 |
|
|
|
|
|
+| 3 | ~~ISSUE-009~~ | ~~订单搜索条件~~ | 🟡 中 | ✅ 已修复 | 缺少商品/时间/显式搜索按钮 |
|
|
|
|
|
+| 4 | ~~ISSUE-010~~ | ~~Dashboard~~ | 🟡 中 | ✅ 已修复 | 缺少退款审核计数卡片 |
|
|
|
|
|
+| 5 | ~~ISSUE-011~~ | ~~余额不足提示~~ | 🟢 低 | ✅ 已修复 | 提示不明确,管理员可能不知情 |
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## ISSUE-007:小程序售后记录列表状态筛选失效
|
|
|
|
|
+
|
|
|
|
|
+**严重度**: 🔴 高
|
|
|
|
|
+**状态**: ✅ 已修复
|
|
|
|
|
+**模块**: 小程序售后管理
|
|
|
|
|
+**文件**: `cfc-frontend/pages/shop/after-sales/after-sales.vue`
|
|
|
|
|
+
|
|
|
|
|
+### 问题描述
|
|
|
|
|
+
|
|
|
|
|
+小程序"售后记录"页面的 5 个状态 Tab(全部/待审核/已通过/已拒绝/已完成)切换后显示的列表内容完全一样,状态筛选功能失效。
|
|
|
|
|
+
|
|
|
|
|
+### 根因分析
|
|
|
|
|
+
|
|
|
|
|
+**双重 bug:前端未传参数 + 后端未接收参数。**
|
|
|
|
|
+
|
|
|
|
|
+**前端** (`after-sales.vue` 第96-103行):
|
|
|
|
|
+```javascript
|
|
|
|
|
+uni.request({
|
|
|
|
|
+ url: config.api('/api/shop/after-sales/list'),
|
|
|
|
|
+ method: 'POST',
|
|
|
|
|
+ data: {}, // ← BUG: 永远传空对象,不传 status
|
|
|
|
|
+ // ...
|
|
|
|
|
+})
|
|
|
|
|
+```
|
|
|
|
|
+`onTabChange(value)` 正确设置了 `this.currentTab = value`,但 `loadList()` 发送请求时 `data: {}` 根本没传 status。
|
|
|
|
|
+
|
|
|
|
|
+**后端** (`AfterSalesService.list()` 第58-65行):
|
|
|
|
|
+```java
|
|
|
|
|
+public Result<List<AfterSalesRequest>> list(Long userId) {
|
|
|
|
|
+ List<AfterSalesRequest> list = afterSalesRequestMapper.selectList(
|
|
|
|
|
+ new LambdaQueryWrapper<AfterSalesRequest>()
|
|
|
|
|
+ .eq(AfterSalesRequest::getUserId, userId)
|
|
|
|
|
+ .orderByDesc(AfterSalesRequest::getCreatedAt)
|
|
|
|
|
+ );
|
|
|
|
|
+ return Result.success(list);
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+后端也不接收/处理 status 参数,总是返回全量数据。
|
|
|
|
|
+
|
|
|
|
|
+### 修复方案
|
|
|
|
|
+
|
|
|
|
|
+1. **前端**: `data: {}` → `data: { status: this.currentTab || undefined }`
|
|
|
|
|
+2. **后端**: `AfterSalesService.list() + AfterSalesController.list()` 增加 status 参数处理
|
|
|
|
|
+
|
|
|
|
|
+### 验证方式
|
|
|
|
|
+
|
|
|
|
|
+切换不同状态 Tab,确认列表内容随 Tab 切换而变化。
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## ISSUE-008:退款到账中中止退款后订单状态未恢复
|
|
|
|
|
+
|
|
|
|
|
+**严重度**: 🔴 高
|
|
|
|
|
+**状态**: ✅ 已修复
|
|
|
|
|
+**模块**: 商城退款流程
|
|
|
|
|
+**文件**: `cfc-backend/src/main/java/com/etotem/cfc/service/PendingRefundService.java`
|
|
|
|
|
+
|
|
|
|
|
+### 问题描述
|
|
|
|
|
+
|
|
|
|
|
+当退款因微信商户余额不足进入"退款到账中"状态(`refundStatus=4`, `status="refund_pending"`),管理员在"待退款列表"中点击「中止退款」后,`pending_refund` 记录被标记为 `cancelled`,但 **`product_orders` 表的订单状态没有恢复**。订单保持在 `refundStatus=4` / `status="refund_pending"` 无法继续处理。
|
|
|
|
|
+
|
|
|
|
|
+### 根因分析
|
|
|
|
|
+
|
|
|
|
|
+**`PendingRefundService.cancelPendingRefund()`** 只更新了 `pending_refund` 表,完全没有动 `product_orders` 表:
|
|
|
|
|
+
|
|
|
|
|
+```java
|
|
|
|
|
+// 当前代码 (第128-137行)
|
|
|
|
|
+@Transactional
|
|
|
|
|
+public void cancelPendingRefund(Long refundId) {
|
|
|
|
|
+ PendingRefund refund = pendingRefundMapper.selectById(refundId);
|
|
|
|
|
+ if (refund != null) {
|
|
|
|
|
+ refund.setStatus("cancelled");
|
|
|
|
|
+ refund.setRemark("管理员中止退款");
|
|
|
|
|
+ refund.setUpdatedAt(new Date());
|
|
|
|
|
+ pendingRefundMapper.updateById(refund);
|
|
|
|
|
+ }
|
|
|
|
|
+ // ← 缺失: 未恢复 ProductOrder 状态!
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+对比正常退款后 `RefundScheduledTasks.processProductRefund()` 的做法:
|
|
|
|
|
+```java
|
|
|
|
|
+order.setRefundStatus(2); // 已退款
|
|
|
|
|
+order.setStatus("refunded");
|
|
|
|
|
+productOrderMapper.updateById(order);
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 修复方案
|
|
|
|
|
+
|
|
|
|
|
+`cancelPendingRefund` 需根据 `orderType` + `orderNo` 找到对应的 `ProductOrder`,恢复状态:`refundStatus=1` (`申请中`), `status="refunding"`。
|
|
|
|
|
+
|
|
|
|
|
+需在 `PendingRefundService` 中注入 `ProductOrderMapper`。
|
|
|
|
|
+
|
|
|
|
|
+### 验证方式
|
|
|
|
|
+
|
|
|
|
|
+1. 创建退款请求 → 管理员通过 → 触发余额不足 → 进入 `refund_pending`
|
|
|
|
|
+2. 管理员在待退款列表中中止该退款
|
|
|
|
|
+3. 检查 `product_orders` 表:`refundStatus` 应回到 1,`status` 应回到 `"refunding"`
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## ISSUE-009:后台订单管理搜索条件不足
|
|
|
|
|
+
|
|
|
|
|
+**严重度**: 🟡 中
|
|
|
|
|
+**状态**: ✅ 已修复
|
|
|
|
|
+**模块**: Web管理端 订单管理
|
|
|
|
|
+**文件**:
|
|
|
|
|
+- `cfc-web/src/views/admin/OrderManage.vue`
|
|
|
|
|
+- `cfc-backend/src/main/java/com/etotem/cfc/service/ProductOrderService.java`
|
|
|
|
|
+
|
|
|
|
|
+### 问题描述
|
|
|
|
|
+
|
|
|
|
|
+管理员订单管理页面仅支持按订单状态筛选,缺少商品名称筛选、时间范围筛选、精确订单号搜索,且没有显式的搜索按钮(仅靠 Enter 触发)。
|
|
|
|
|
+
|
|
|
|
|
+### 根因分析
|
|
|
|
|
+
|
|
|
|
|
+| 缺失项 | 前端状态 | 后端状态 |
|
|
|
|
|
+|--------|:---:|:---:|
|
|
|
|
|
+| keyword 搜索 | ✅ 前端传参 | ❌ 后端未处理 |
|
|
|
|
|
+| 商品名称筛选 | ❌ 不存在 | ❌ 不存在 |
|
|
|
|
|
+| 时间范围筛选 | ❌ 不存在 | ❌ 不存在 |
|
|
|
|
|
+| 显式搜索按钮 | ❌ 不存在 | — |
|
|
|
|
|
+
|
|
|
|
|
+前端 `loadList()` 正确将 `keyword` 放入 params,但后端 `ProductOrderService.adminOrderPage()` **完全没处理 keyword**,只处理了 status。
|
|
|
|
|
+
|
|
|
|
|
+### 修复方案
|
|
|
|
|
+
|
|
|
|
|
+1. **后端**: `adminOrderPage()` 增加 keyword(模糊匹配 productName + orderNo)和 startDate/endDate
|
|
|
|
|
+2. **前端**: 增加 `<el-date-picker>` 时间范围选择器 + `<el-button>` 搜索按钮
|
|
|
|
|
+3. **前端 API**: `getOrderList(params)` 传递新增参数(已正确传递 keyword,无需改)
|
|
|
|
|
+
|
|
|
|
|
+### 验证方式
|
|
|
|
|
+
|
|
|
|
|
+管理端订单管理页面:
|
|
|
|
|
+1. 关键字搜索能按商品名/订单号过滤
|
|
|
|
|
+2. 时间范围筛选正确
|
|
|
|
|
+3. 点击搜索按钮触发查询
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## ISSUE-010:Dashboard 缺少退款审核计数
|
|
|
|
|
+
|
|
|
|
|
+**严重度**: 🟡 中
|
|
|
|
|
+**状态**: ✅ 已修复
|
|
|
|
|
+**模块**: Web管理端 Dashboard
|
|
|
|
|
+**文件**:
|
|
|
|
|
+- `cfc-web/src/views/admin/Dashboard.vue`
|
|
|
|
|
+- `cfc-backend/src/main/java/com/etotem/cfc/controller/stats/StatsController.java`
|
|
|
|
|
+
|
|
|
|
|
+### 问题描述
|
|
|
|
|
+
|
|
|
|
|
+管理员 Dashboard 统计卡片有 6 项(家庭总数、家长总数、孩子总数、规划师总数、待审核规划师、待审核套餐),但缺少退款审核相关的计数,管理员无法在首页快速了解待处理的退款量。
|
|
|
|
|
+
|
|
|
|
|
+### 根因分析
|
|
|
|
|
+
|
|
|
|
|
+- 前端 `Dashboard.vue` `statCards` 数组无退款卡片
|
|
|
|
|
+- 后端 `StatsController.getDashboardSummary()` 未查询 `pendingRefundCount`
|
|
|
|
|
+- 后端已有能力:`PendingRefundService.getTotalPendingAmount()` 可获取待退款总额;通过 `AfterSalesRequest mapper` 可统计待审核售后数
|
|
|
|
|
+
|
|
|
|
|
+### 修复方案
|
|
|
|
|
+
|
|
|
|
|
+1. **后端** `StatsController.getDashboardSummary()`: 新增异步查询 `pendingRefundCount` (= 待审核的 `AfterSalesRequest` 数量,status='pending')
|
|
|
|
|
+2. **前端** `Dashboard.vue`: `statCards` 新增一条:`{ label: '待退款审核', value: '-', icon: 'el-icon-warning', color: 'orange' }`
|
|
|
|
|
+
|
|
|
|
|
+### 验证方式
|
|
|
|
|
+
|
|
|
|
|
+Dashboard 首页出现"待退款审核"卡片,数值正确。
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## ISSUE-011:退款余额不足提示不明确
|
|
|
|
|
+
|
|
|
|
|
+**严重度**: 🟢 低
|
|
|
|
|
+**状态**: ✅ 已修复
|
|
|
|
|
+**模块**: Web管理端 退款审核
|
|
|
|
|
+**文件**:
|
|
|
|
|
+- `cfc-backend/src/main/java/com/etotem/cfc/service/ProductOrderService.java`
|
|
|
|
|
+- `cfc-web/src/views/admin/OrderManage.vue`
|
|
|
|
|
+
|
|
|
|
|
+### 问题描述
|
|
|
|
|
+
|
|
|
|
|
+管理员点击"同意退款"后,若微信商户余额不足,后端返回 `Result.success("余额不足,退款已加入等待队列...")`。但前端 `handleApproveRefundConfirm()` 硬编码显示 `this.$message.success('已同意退款')`,管理员看到绿色"成功"提示,可能完全没注意到余额不足的事实。
|
|
|
|
|
+
|
|
|
|
|
+### 根因分析
|
|
|
|
|
+
|
|
|
|
|
+```
|
|
|
|
|
+后端: return Result.success("余额不足,退款已加入等待队列,到账后将自动退款")
|
|
|
|
|
+前端: this.$message.success('已同意退款') // ← 硬编码,忽略后端 message
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+`Result.success()` 不表示业务完全成功,而是表示"请求被接受"。前端应显示后端返回的 message 而非硬编码。
|
|
|
|
|
+
|
|
|
|
|
+### 修复方案
|
|
|
|
|
+
|
|
|
|
|
+1. **后端**: message 加 ⚠️ 前缀,如 `"⚠️ 账户余额不足,退款已加入等待队列"`
|
|
|
|
|
+2. **前端**: 使用后端返回的 `res.message` 替代硬编码的 `'已同意退款'`
|
|
|
|
|
+
|
|
|
|
|
+### 验证方式
|
|
|
|
|
+
|
|
|
|
|
+触发余额不足场景,管理员应看到包含余额不足说明的提示信息。
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 更新记录
|
|
|
|
|
+
|
|
|
|
|
+| 日期 | 操作人 | 内容 |
|
|
|
|
|
+|------|--------|------|
|
|
|
|
|
+| 2026-07-12 | Sisyphus | 📋 创建退款流程问题追踪文档,录入 ISSUE-007 ~ ISSUE-011 |
|