181 lines
4.5 KiB
Markdown
181 lines
4.5 KiB
Markdown
|
|
# 服务商提现功能优化
|
||
|
|
|
||
|
|
**日期:** 2026-01-31
|
||
|
|
**功能:** 服务商提现申请后,可提取金额立即减少
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 问题描述
|
||
|
|
|
||
|
|
用户反馈:提交提现申请后,可提取金额没有变化。
|
||
|
|
|
||
|
|
### 原因分析
|
||
|
|
|
||
|
|
**修改前的逻辑:**
|
||
|
|
```
|
||
|
|
可提取金额 = 总收益(所有已完成订单的金额)
|
||
|
|
```
|
||
|
|
|
||
|
|
问题:
|
||
|
|
- 提现申请只创建了记录,没有扣减可提现余额
|
||
|
|
- 无论提现多少次,可提取金额始终等于总收益
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 解决方案
|
||
|
|
|
||
|
|
### 修改后的逻辑
|
||
|
|
|
||
|
|
```
|
||
|
|
可提取金额 = 总收益 - 已提现金额 - 提现中金额
|
||
|
|
```
|
||
|
|
|
||
|
|
其中:
|
||
|
|
- **总收益**: 所有已完成订单(status=4)的金额总和
|
||
|
|
- **已提现金额**: 状态为 `approved` 或 `completed` 的提现记录金额总和
|
||
|
|
- **提现中金额**: 状态为 `pending` 的提现记录金额总和
|
||
|
|
|
||
|
|
### 状态流转
|
||
|
|
|
||
|
|
```
|
||
|
|
pending (待审核) → approved (已通过) → completed (已完成)
|
||
|
|
↘ rejected (已拒绝)
|
||
|
|
```
|
||
|
|
|
||
|
|
- **pending**: 用户提交提现申请,金额从"可提取"转为"提现中"
|
||
|
|
- **approved**: 管理员审核通过,金额仍在"已提现"
|
||
|
|
- **rejected**: 管理员拒绝,金额回到"可提取"
|
||
|
|
- **completed**: 提现完成,金额在"已提现"
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 修改内容
|
||
|
|
|
||
|
|
### 文件: `ProviderServiceImpl.java`
|
||
|
|
|
||
|
|
**方法:** `getEarningsStats(Long providerId)`
|
||
|
|
|
||
|
|
**修改点:**
|
||
|
|
|
||
|
|
1. **计算已提现金额**
|
||
|
|
```java
|
||
|
|
// 查询状态为 approved 或 completed 的提现记录
|
||
|
|
LambdaQueryWrapper<Withdraw> withdrawnWrapper = new LambdaQueryWrapper<>();
|
||
|
|
withdrawnWrapper.eq(Withdraw::getTeacherId, providerId)
|
||
|
|
.in(Withdraw::getStatus, "approved", "completed");
|
||
|
|
List<Withdraw> withdrawnRecords = withdrawMapper.selectList(withdrawnWrapper);
|
||
|
|
BigDecimal withdrawnAmount = withdrawnRecords.stream()
|
||
|
|
.map(Withdraw::getAmount)
|
||
|
|
.filter(amount -> amount != null)
|
||
|
|
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||
|
|
```
|
||
|
|
|
||
|
|
2. **计算提现中金额**
|
||
|
|
```java
|
||
|
|
// 查询状态为 pending 的提现记录
|
||
|
|
LambdaQueryWrapper<Withdraw> withdrawingWrapper = new LambdaQueryWrapper<>();
|
||
|
|
withdrawingWrapper.eq(Withdraw::getTeacherId, providerId)
|
||
|
|
.eq(Withdraw::getStatus, "pending");
|
||
|
|
List<Withdraw> withdrawingRecords = withdrawMapper.selectList(withdrawingWrapper);
|
||
|
|
BigDecimal withdrawingAmount = withdrawingRecords.stream()
|
||
|
|
.map(Withdraw::getAmount)
|
||
|
|
.filter(amount -> amount != null)
|
||
|
|
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||
|
|
```
|
||
|
|
|
||
|
|
3. **计算可提现余额**
|
||
|
|
```java
|
||
|
|
// 可提现余额 = 总收益 - 已提现金额 - 提现中金额
|
||
|
|
BigDecimal availableBalance = totalEarnings
|
||
|
|
.subtract(withdrawnAmount)
|
||
|
|
.subtract(withdrawingAmount);
|
||
|
|
|
||
|
|
// 确保可提现余额不为负数
|
||
|
|
if (availableBalance.compareTo(BigDecimal.ZERO) < 0) {
|
||
|
|
availableBalance = BigDecimal.ZERO;
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 测试步骤
|
||
|
|
|
||
|
|
### 1. 查看当前收益状态
|
||
|
|
```sql
|
||
|
|
-- 查看服务商的订单收益
|
||
|
|
SELECT SUM(pay_amount) as total_earnings
|
||
|
|
FROM `order`
|
||
|
|
WHERE teacher_id = ? AND status = 4;
|
||
|
|
|
||
|
|
-- 查看提现记录
|
||
|
|
SELECT status, SUM(amount) as total
|
||
|
|
FROM withdraw
|
||
|
|
WHERE teacher_id = ?
|
||
|
|
GROUP BY status;
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2. 提交提现申请
|
||
|
|
- 前端: 进入"收益查看"页面 → 点击"提取收益"
|
||
|
|
- 输入提现金额 → 提交
|
||
|
|
|
||
|
|
### 3. 验证可提取金额变化
|
||
|
|
- 提交后,刷新页面
|
||
|
|
- 可提取金额应该减少(扣除提现申请的金额)
|
||
|
|
- 提现中金额应该增加
|
||
|
|
|
||
|
|
### 4. 测试审核流程
|
||
|
|
- 管理员审核通过: 金额从"提现中"转为"已提现"
|
||
|
|
- 管理员拒绝: 金额回到"可提取"
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 预期效果
|
||
|
|
|
||
|
|
### 场景1: 提交提现申请
|
||
|
|
|
||
|
|
**操作前:**
|
||
|
|
- 总收益: ¥1000
|
||
|
|
- 可提取: ¥1000
|
||
|
|
- 提现中: ¥0
|
||
|
|
- 已提现: ¥0
|
||
|
|
|
||
|
|
**提交¥300提现申请后:**
|
||
|
|
- 总收益: ¥1000
|
||
|
|
- 可提取: ¥700 ✅
|
||
|
|
- 提现中: ¥300 ✅
|
||
|
|
- 已提现: ¥0
|
||
|
|
|
||
|
|
### 场景2: 审核通过
|
||
|
|
|
||
|
|
**审核通过后:**
|
||
|
|
- 总收益: ¥1000
|
||
|
|
- 可提取: ¥700
|
||
|
|
- 提现中: ¥0 ✅
|
||
|
|
- 已提现: ¥300 ✅
|
||
|
|
|
||
|
|
### 场景3: 审核拒绝
|
||
|
|
|
||
|
|
**审核拒绝后:**
|
||
|
|
- 总收益: ¥1000
|
||
|
|
- 可提取: ¥1000 ✅ (金额回到可提取)
|
||
|
|
- 提现中: ¥0 ✅
|
||
|
|
- 已提现: ¥0
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 注意事项
|
||
|
|
|
||
|
|
1. **数据一致性**: 确保提现记录的状态正确更新
|
||
|
|
2. **并发控制**: 多次提现申请时,需要确保余额计算正确
|
||
|
|
3. **负数保护**: 可提现余额不能为负数
|
||
|
|
4. **日志记录**: 关键操作都有日志输出,便于排查问题
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 相关文件
|
||
|
|
|
||
|
|
- `peidu/backend/src/main/java/com/peidu/service/impl/ProviderServiceImpl.java`
|
||
|
|
- `peidu/backend/src/main/java/com/peidu/entity/Withdraw.java`
|
||
|
|
- `peidu/uniapp/src/provider-package/pages/provider/earnings.vue`
|
||
|
|
- `peidu/uniapp/src/provider-package/pages/provider/withdraw.vue`
|