Files
soul-yongping/开发文档/8、部署/后台提现审核功能完善说明.md

547 lines
17 KiB
Markdown
Raw Normal View History

# 后台提现审核功能完善说明
## 概述
完善后台管理的"提现审核"页面,增加用户佣金信息展示,帮助管理员做出准确的审核决策。
## 功能增强
### 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;
```
## 总结
这次数据对接实现了:
### 信息完整性
- ✅ 显示用户的累计佣金
- ✅ 显示用户的已提现金额
- ✅ 显示用户的待审核金额
- ✅ 计算审核后余额
### 风险防控
- ✅ 超额提现自动标红
- ✅ 批准时弹出风险警告
- ✅ 帮助管理员做出正确决策
### 用户体验
- ✅ 界面清晰,数据一目了然
- ✅ 颜色区分(绿色安全,红色风险)
- ✅ 详细的计算明细
**核心价值**:让管理员能够**快速准确地审核提现申请**,同时**有效防范超额提现风险**。