Files
soul-yongping/开发文档/8、部署/后台提现审核功能完善说明.md
2026-02-09 15:09:29 +08:00

547 lines
17 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 后台提现审核功能完善说明
## 概述
完善后台管理的"提现审核"页面,增加用户佣金信息展示,帮助管理员做出准确的审核决策。
## 功能增强
### 1. 新增用户佣金信息展示
在提现记录表格中,新增"用户佣金信息"列,显示:
| 字段 | 说明 | 计算方式 | 颜色 |
|------|------|----------|------|
| 累计佣金 | 用户的历史总佣金 | `SUM(orders.amount) × 90%` | 青色 |
| 已提现 | 已到账的金额 | `users.withdrawn_earnings` | 灰色 |
| 待审核 | 所有待审核的提现申请 | `SUM(withdrawals.amount WHERE status='pending')` | 橙色 |
| 审核后余额 | 如果通过该申请,用户剩余的可提现金额 | `累计 - 已提现 - 待审核` | 绿色(≥0) / 红色(<0) |
### 2. 超额提现风险警告
"审核后余额"为负数时
- 以红色显示
- 批准时弹出二次确认警告
```
⚠️ 风险警告:该用户审核后余额为负数(¥-20.00),可能存在超额提现。
确认已核实用户账户并完成打款?
```
### 3. 用户头像显示
优化用户信息展示
- 如果有头像显示真实头像
- 如果无头像显示昵称首字母
- 显示推荐码如果有
## 技术实现
### 后端API (`app/api/admin/withdrawals/route.ts`)
#### 查询优化
```typescript
SELECT
w.*,
u.nickname as user_nickname,
u.phone as user_phone,
u.avatar as user_avatar,
u.referral_code,
u.withdrawn_earnings,
u.earnings,
u.pending_earnings,
-- 计算累计佣金(从 orders 表)
(SELECT COALESCE(SUM(o.amount), 0)
FROM orders o
WHERE o.referrer_id = w.user_id AND o.status = 'paid') as total_order_amount,
-- 计算待审核提现金额(不包括当前这条)
(SELECT COALESCE(SUM(w2.amount), 0)
FROM withdrawals w2
WHERE w2.user_id = w.user_id AND w2.status = 'pending' AND w2.id != w.id) as other_pending_amount
FROM withdrawals w
LEFT JOIN users u ON w.user_id = u.id
```
#### 返回数据结构
```typescript
{
id: string,
userId: string,
userNickname: string,
userPhone: string,
userAvatar: string,
referralCode: string,
amount: number,
status: string,
createdAt: string,
processedAt: string,
// ✅ 新增:用户佣金信息
userCommissionInfo: {
totalCommission: number, // 累计佣金
withdrawnEarnings: number, // 已提现
pendingWithdrawals: number, // 待审核(包括当前)
availableAfterThis: number // 审核后余额
}
}
```
#### 计算逻辑
```typescript
// 累计佣金90%分成)
const totalCommission = parseFloat(w.total_order_amount) * 0.9
// 已提现金额
const withdrawnEarnings = parseFloat(w.withdrawn_earnings) || 0
// 其他待审核金额(不包括当前这笔)
const otherPendingAmount = parseFloat(w.other_pending_amount) || 0
// 当前提现金额
const currentWithdrawAmount = parseFloat(w.amount)
// ✅ 审核后余额 = 累计佣金 - 已提现 - 其他待审核 - 当前提现
const availableAfterThis = totalCommission - withdrawnEarnings - otherPendingAmount - currentWithdrawAmount
```
### 前端页面 (`app/admin/withdrawals/page.tsx`)
#### 界面布局
```tsx
<td className="p-4">
{w.userCommissionInfo ? (
<div className="text-xs space-y-1">
{/* 累计佣金 */}
<div className="flex justify-between gap-4">
<span className="text-gray-500">累计佣金:</span>
<span className="text-[#38bdac] font-medium">
¥{w.userCommissionInfo.totalCommission.toFixed(2)}
</span>
</div>
{/* 已提现 */}
<div className="flex justify-between gap-4">
<span className="text-gray-500">已提现:</span>
<span className="text-gray-400">
¥{w.userCommissionInfo.withdrawnEarnings.toFixed(2)}
</span>
</div>
{/* 待审核 */}
<div className="flex justify-between gap-4">
<span className="text-gray-500">待审核:</span>
<span className="text-orange-400">
¥{w.userCommissionInfo.pendingWithdrawals.toFixed(2)}
</span>
</div>
{/* 审核后余额(带边框分隔) */}
<div className="flex justify-between gap-4 pt-1 border-t border-gray-700/30">
<span className="text-gray-500">审核后余额:</span>
<span className={
w.userCommissionInfo.availableAfterThis >= 0
? "text-green-400 font-medium"
: "text-red-400 font-medium"
}>
¥{w.userCommissionInfo.availableAfterThis.toFixed(2)}
</span>
</div>
</div>
) : (
<span className="text-gray-500 text-xs">暂无数据</span>
)}
</td>
```
#### 风险警告
```typescript
const handleApprove = async (id: string) => {
const withdrawal = withdrawals.find(w => w.id === id)
// 检查超额提现风险
if (withdrawal?.userCommissionInfo?.availableAfterThis < 0) {
if (!confirm(`⚠️ 风险警告:该用户审核后余额为负数...`)) {
return
}
} else {
if (!confirm("确认已完成打款?批准后将更新用户提现记录。")) {
return
}
}
// 执行批准操作
// ...
}
```
## 使用场景
### 场景1正常提现
**用户A的提现申请**
- 累计佣金: ¥100.00
- 已提现: ¥30.00
- 待审核: ¥40.00包括当前 ¥40
- 审核后余额: ¥30.00 绿色
**管理员判断**
- 数据正常
- 审核通过后还有 ¥30 余额
- 可以批准
### 场景2超额提现风险
**用户B的提现申请**
- 累计佣金: ¥100.00
- 已提现: ¥30.00
- 待审核: ¥80.00当前 ¥60 + 其他 ¥20
- 审核后余额: **-¥10.00** 红色
**管理员判断**
- 超额提现风险
- 待审核总额 ¥80 > 可提现 ¥70
- ⚠️ 可能是并发提现或恶意提现
- 🛑 建议拒绝,或核实后只批准部分
### 场景3多笔待审核
**用户C的多笔提现**
**第一笔申请 ¥40**
- 累计佣金: ¥100.00
- 已提现: ¥0.00
- 待审核: ¥40.00
- 审核后余额: ¥60.00 ✅
**第二笔申请 ¥30**
- 累计佣金: ¥100.00
- 已提现: ¥0.00
- 待审核: ¥70.00¥40 + ¥30
- 审核后余额: ¥30.00 ✅
**第三笔申请 ¥40**
- 累计佣金: ¥100.00
- 已提现: ¥0.00
- 待审核: ¥110.00¥40 + ¥30 + ¥40
- 审核后余额: **-¥10.00** ❌ 红色
**管理员策略**
- ✅ 批准第一笔¥40
- ✅ 批准第二笔¥30
- ❌ 拒绝第三笔¥40- 余额不足
## 测试验证
### 1. 准备测试数据
```sql
-- 用户A正常用户
INSERT INTO users (id, nickname, phone, withdrawn_earnings, referral_code)
VALUES ('user_a', '测试用户A', '13800138000', 0, 'SOULA001');
INSERT INTO orders (id, user_id, amount, referrer_id, status, pay_time)
VALUES ('order_a1', 'buyer_1', 100, 'user_a', 'paid', NOW());
INSERT INTO withdrawals (id, user_id, amount, status)
VALUES ('W_A1', 'user_a', 50, 'pending');
-- 用户B超额提现用户
INSERT INTO users (id, nickname, phone, withdrawn_earnings, referral_code)
VALUES ('user_b', '测试用户B', '13900139000', 30, 'SOULB001');
INSERT INTO orders (id, user_id, amount, referrer_id, status, pay_time)
VALUES ('order_b1', 'buyer_2', 100, 'user_b', 'paid', NOW());
INSERT INTO withdrawals (id, user_id, amount, status)
VALUES
('W_B1', 'user_b', 20, 'pending'),
('W_B2', 'user_b', 60, 'pending');
```
### 2. 访问页面
```
http://localhost:3006/admin/withdrawals
```
### 3. 验证显示
**用户A的记录**
- 累计佣金: ¥90.00100 × 90%
- 已提现: ¥0.00
- 待审核: ¥50.00
- 审核后余额: ¥40.00 ✅ 绿色
**用户B的记录W_B1**
- 累计佣金: ¥90.00
- 已提现: ¥30.00
- 待审核: ¥80.0020 + 60
- 审核后余额: **-¥20.00** ❌ 红色
**用户B的记录W_B2**
- 累计佣金: ¥90.00
- 已提现: ¥30.00
- 待审核: ¥80.0020 + 60
- 审核后余额: **-¥20.00** ❌ 红色
### 4. 测试批准操作
**批准用户A的提现**
- 正常弹出确认框
- 批准成功
**批准用户B的提现**
- ⚠️ 弹出风险警告
- 显示负数余额
- 需要二次确认
## 管理员决策指南
### 何时批准?
- ✅ 审核后余额 ≥ 0
- ✅ 用户信息真实完整
- ✅ 累计佣金合理(有订单支持)
- ✅ 已完成线下打款(或准备自动转账)
### 何时拒绝?
- ❌ 审核后余额 < 0
- 累计佣金异常没有订单但有佣金
- 同一用户有多笔待审核且总额超额
- 用户信息不全或异常
### 如何处理并发提现?
**发现场景**同一用户有多笔待审核总额超出可提现金额
**处理策略**
1. 按时间顺序查看
2. 计算每笔的"审核后余额"
3. 批准最早的几笔余额充足的
4. 拒绝超额的后续申请
5. 联系用户说明情况
## 数据完整性说明
### 数据来源
| 数据 | 来源 | 可靠性 |
|------|------|--------|
| 累计佣金 | `orders` 表实时计算 | ⭐⭐⭐⭐⭐ 最准确 |
| 已提现 | `users.withdrawn_earnings` | ⭐⭐⭐⭐ 需要提现接口正确维护 |
| 待审核 | `withdrawals` 表实时查询 | ⭐⭐⭐⭐⭐ 实时准确 |
### 计算公式
```
累计佣金 = Σ(已付款订单金额) × 分成比例(90%)
已提现金额 = users.withdrawn_earnings
待审核金额 = Σ(status='pending'的提现申请)
审核后余额 = 累计佣金 - 已提现金额 - 待审核金额
```
## 界面效果
### 提现记录表格
```
┌──────────────┬───────────┬──────────┬─────────────────────┬────────┬──────────┬────────┐
│ 申请时间 │ 用户 │ 提现金额 │ 用户佣金信息 │ 状态 │ 处理时间 │ 操作 │
├──────────────┼───────────┼──────────┼─────────────────────┼────────┼──────────┼────────┤
│ 2026-02-04 │ [头像] │ ¥50.00 │ 累计佣金: ¥100.00 │ 待处理 │ - │ 批准 │
│ 15:30 │ 张三 │ │ 已提现: ¥30.00 │ │ │ 拒绝 │
│ │ 138***00 │ │ 待审核: ¥50.00 │ │ │ │
│ │ │ │ ───────────────── │ │ │ │
│ │ │ │ 审核后余额: ¥20.00 │ │ │ │
└──────────────┴───────────┴──────────┴─────────────────────┴────────┴──────────┴────────┘
```
### 风险提示(审核后余额<0
```
┌──────────────┬───────────┬──────────┬─────────────────────┬────────┬──────────┬────────┐
│ 申请时间 │ 用户 │ 提现金额 │ 用户佣金信息 │ 状态 │ 处理时间 │ 操作 │
├──────────────┼───────────┼──────────┼─────────────────────┼────────┼──────────┼────────┤
│ 2026-02-04 │ [头像] │ ¥80.00 │ 累计佣金: ¥100.00 │ 待处理 │ - │ 批准 │
│ 15:35 │ 李四 │ │ 已提现: ¥30.00 │ │ │ 拒绝 │
│ │ 139***00 │ │ 待审核: ¥80.00 │ │ │ │
│ │ │ │ ───────────────── │ │ │ │
│ │ │ │ 审核后余额: -¥10.00 │ │ │ │
│ │ │ │ ↑ [红色] │ │ │ │
└──────────────┴───────────┴──────────┴─────────────────────┴────────┴──────────┴────────┘
```
**点击批准时**
```
┌─────────────────────────────────────────┐
│ ⚠️ 风险警告 │
├─────────────────────────────────────────┤
│ 该用户审核后余额为负数(¥-10.00
│ 可能存在超额提现。 │
│ │
│ 确认已核实用户账户并完成打款? │
├─────────────────────────────────────────┤
│ [取消] [确定] │
└─────────────────────────────────────────┘
```
## 审核流程示例
### 正常流程
1. **管理员查看**
- 用户张三
- 提现金额:¥50
- 累计佣金:¥100已提现:¥30待审核:¥50
- 审核后余额:¥20
2. **判断**数据正常余额充足
3. **操作**点击"批准"
4. **结果**
- 提现记录状态改为 success
- 用户的 withdrawn_earnings += 50
- 用户收到微信零钱自动转账
### 风险流程
1. **管理员查看**
- 用户李四
- 提现金额:¥80
- 累计佣金:¥100已提现:¥30待审核:¥80
- 审核后余额**-¥10**
2. **判断**超额提现存在风险
3. **操作**
- 方案A直接拒绝备注"余额不足"
- 方案B核实数据后只批准部分金额
4. **结果**
- 拒绝用户的待审核金额归零可重新申请
- 部分批准需要先拒绝原申请等用户重新申请合理金额
## 相关文件
### 后端文件
- `app/api/admin/withdrawals/route.ts` - 提现审核API
- `app/api/withdraw/route.ts` - 用户提现接口
- `app/api/referral/data/route.ts` - 分销数据接口
### 前端文件
- `app/admin/withdrawals/page.tsx` - 提现审核页面
- `miniprogram/pages/referral/referral.js` - 小程序提现页面
### 脚本文件
- `scripts/verify-withdrawal-data.sql` - 数据验证SQL脚本
## 部署步骤
### 1. 重启后端服务
```bash
python devlop.py restart mycontent
```
### 2. 访问管理后台
```
http://localhost:3006/admin/withdrawals
```
### 3. 验证数据显示
- [ ] 用户信息完整昵称头像电话
- [ ] 提现金额正确
- [ ] 佣金信息完整累计已提现待审核审核后余额
- [ ] 审核后余额颜色正确绿色/红色
- [ ] 批准/拒绝按钮可用
### 4. 测试审核操作
- [ ] 批准正常提现审核后余额0
- [ ] 批准风险提现会弹出警告
- [ ] 拒绝提现余额返还
### 5. 验证数据更新
批准后
```sql
-- 检查提现记录状态
SELECT status FROM withdrawals WHERE id = 'W_XXX';
-- 应该是 'success'
-- 检查用户已提现金额
SELECT withdrawn_earnings FROM users WHERE id = 'user_xxx';
-- 应该增加了提现金额
```
## 后续优化建议
### 1. 批量审核
选中多条记录一键批准所有
```tsx
<Button onClick={handleBatchApprove}>
批量批准已勾选项
</Button>
```
### 2. 自动审核
小额提现 ¥50自动审核通过
```typescript
if (amount <= 50 && availableAmount >= amount) {
// 自动批准
}
```
### 3. 审核备注
添加备注字段记录审核原因
```sql
ALTER TABLE withdrawals ADD COLUMN admin_note VARCHAR(500);
```
### 4. 审核历史
记录审核人和审核时间
```sql
ALTER TABLE withdrawals
ADD COLUMN approved_by VARCHAR(64),
ADD COLUMN approved_at TIMESTAMP;
```
## 总结
这次数据对接实现了
### 信息完整性
- 显示用户的累计佣金
- 显示用户的已提现金额
- 显示用户的待审核金额
- 计算审核后余额
### 风险防控
- 超额提现自动标红
- 批准时弹出风险警告
- 帮助管理员做出正确决策
### 用户体验
- 界面清晰数据一目了然
- 颜色区分绿色安全红色风险
- 详细的计算明细
**核心价值**让管理员能够**快速准确地审核提现申请**同时**有效防范超额提现风险**。