diff --git a/app/admin/layout.tsx b/app/admin/layout.tsx
index baf45d6b..b1d70049 100644
--- a/app/admin/layout.tsx
+++ b/app/admin/layout.tsx
@@ -43,7 +43,7 @@ export default function AdminLayout({ children }: { children: React.ReactNode })
// 简化菜单:按功能归类,保留核心功能
// PDF需求:分账管理、分销管理、订单管理三合一 → 交易中心
const menuItems = [
- { icon: LayoutDashboard, label: "数据概览123", href: "/admin" },
+ { icon: LayoutDashboard, label: "数据概览147", href: "/admin" },
{ icon: BookOpen, label: "内容管理", href: "/admin/content" },
{ icon: Users, label: "用户管理", href: "/admin/users" },
{ icon: Wallet, label: "交易中心", href: "/admin/distribution" }, // 合并:分销+订单+提现
diff --git a/app/api/withdraw/route.ts b/app/api/withdraw/route.ts
index e2e3aadc..8ec4e999 100644
--- a/app/api/withdraw/route.ts
+++ b/app/api/withdraw/route.ts
@@ -84,39 +84,75 @@ export async function POST(request: NextRequest) {
})
}
- // 查询可提现金额(待结算收益)
- let totalEarnings = 0
+ // ✅ 修正:从 orders 表查询累计佣金(与前端逻辑一致)
+ let totalCommission = 0
try {
- const earningsResult = await query(`
- SELECT COALESCE(SUM(commission), 0) as total_commission
- FROM referral_bindings
- WHERE referrer_id = ? AND status = 'converted'
+ // 读取分成比例
+ let distributorShare = 0.9 // 默认90%
+ try {
+ const config = await getConfig('referral_config')
+ if (config?.distributorShare) {
+ distributorShare = Number(config.distributorShare)
+ }
+ } catch (e) {
+ console.warn('[Withdraw] 读取分成比例失败,使用默认值 90%')
+ }
+
+ // 查询订单总金额
+ const ordersResult = await query(`
+ SELECT COALESCE(SUM(amount), 0) as total_amount
+ FROM orders
+ WHERE referrer_id = ? AND status = 'paid'
`, [userId]) as any[]
- totalEarnings = parseFloat(earningsResult[0]?.total_commission || 0)
+
+ const totalAmount = parseFloat(ordersResult[0]?.total_amount || 0)
+ totalCommission = totalAmount * distributorShare
+
+ console.log('[Withdraw] 佣金计算:')
+ console.log('- 订单总金额:', totalAmount)
+ console.log('- 分成比例:', distributorShare * 100 + '%')
+ console.log('- 累计佣金:', totalCommission)
} catch (e) {
// 如果表不存在,收益为0
- console.log('[Withdraw] 查询收益失败,可能表不存在')
+ console.log('[Withdraw] 查询收益失败,可能表不存在:', e)
}
// 查询已提现金额
- let withdrawnAmount = 0
+ let withdrawnEarnings = 0
try {
- const withdrawnResult = await query(`
- SELECT COALESCE(SUM(amount), 0) as withdrawn
- FROM withdrawals
- WHERE user_id = ? AND status = 'completed'
- `, [userId]) as any[]
- withdrawnAmount = parseFloat(withdrawnResult[0]?.withdrawn || 0)
+ withdrawnEarnings = parseFloat(user.withdrawn_earnings) || 0
} catch (e) {
- // 如果表不存在,已提现为0
+ console.log('[Withdraw] 读取已提现金额失败:', e)
}
- const availableAmount = totalEarnings - withdrawnAmount
+ // 查询待审核提现金额
+ let pendingWithdrawAmount = 0
+ try {
+ const pendingResult = await query(`
+ SELECT COALESCE(SUM(amount), 0) as pending_amount
+ FROM withdrawals
+ WHERE user_id = ? AND status = 'pending'
+ `, [userId]) as any[]
+ pendingWithdrawAmount = parseFloat(pendingResult[0]?.pending_amount || 0)
+ } catch (e) {
+ console.log('[Withdraw] 查询待审核金额失败:', e)
+ }
+
+ // ✅ 修正:可提现金额 = 累计佣金 - 已提现金额 - 待审核金额(三元素完整校验)
+ const availableAmount = totalCommission - withdrawnEarnings - pendingWithdrawAmount
+
+ console.log('[Withdraw] 提现验证(完整版):')
+ console.log('- 累计佣金 (totalCommission):', totalCommission)
+ console.log('- 已提现金额 (withdrawnEarnings):', withdrawnEarnings)
+ console.log('- 待审核金额 (pendingWithdrawAmount):', pendingWithdrawAmount)
+ console.log('- 可提现金额 = 累计 - 已提现 - 待审核 =', totalCommission, '-', withdrawnEarnings, '-', pendingWithdrawAmount, '=', availableAmount)
+ console.log('- 申请提现金额 (amount):', amount)
+ console.log('- 判断:', amount, '>', availableAmount, '=', amount > availableAmount)
if (amount > availableAmount) {
return NextResponse.json({
success: false,
- message: `可提现金额不足,当前可提现 ¥${availableAmount.toFixed(2)}`
+ message: `可提现金额不足。当前可提现 ¥${availableAmount.toFixed(2)}(累计 ¥${totalCommission.toFixed(2)} - 已提现 ¥${withdrawnEarnings.toFixed(2)} - 待审核 ¥${pendingWithdrawAmount.toFixed(2)})`
})
}
@@ -144,12 +180,13 @@ export async function POST(request: NextRequest) {
return NextResponse.json({
success: true,
- message: '提现成功',
+ message: '提现申请已提交,正在审核中,通过后会自动到账您的微信零钱',
data: {
withdrawId,
amount,
account,
- accountType: accountType === 'alipay' ? '支付宝' : '微信'
+ accountType: accountType === 'alipay' ? '支付宝' : '微信',
+ status: 'pending'
}
})
diff --git a/miniprogram/pages/referral/referral.js b/miniprogram/pages/referral/referral.js
index bfa3b83b..f2c20f8d 100644
--- a/miniprogram/pages/referral/referral.js
+++ b/miniprogram/pages/referral/referral.js
@@ -24,7 +24,8 @@ Page({
// === 收益数据 ===
totalCommission: 0, // 累计佣金总额(所有获得的佣金)
- availableEarnings: 0, // 可提现金额(未申请提现的佣金)
+ availableEarnings: 0, // 可提现金额(未申请提现的佣金)- 字符串格式用于显示
+ availableEarningsNum: 0, // 可提现金额 - 数字格式用于判断
pendingWithdrawAmount: 0, // 待审核金额(已申请提现但未审核)
withdrawnEarnings: 0, // 已提现金额
earnings: 0, // 已结算收益(保留兼容)
@@ -151,6 +152,22 @@ Page({
return typeof num === 'number' ? num.toFixed(2) : '0.00'
}
+ // ✅ 修正:可提现金额 = 累计佣金 - 已提现金额 - 待审核金额
+ const totalCommissionNum = realData?.totalCommission || 0
+ const withdrawnNum = realData?.withdrawnEarnings || 0
+ const pendingWithdrawNum = realData?.pendingWithdrawAmount || 0
+ const availableEarningsNum = totalCommissionNum - withdrawnNum - pendingWithdrawNum
+ const minWithdrawAmount = realData?.minWithdrawAmount || 10
+
+ console.log('=== [Referral] 收益计算(完整版)===')
+ console.log('累计佣金 (totalCommission):', totalCommissionNum)
+ console.log('已提现金额 (withdrawnEarnings):', withdrawnNum)
+ console.log('待审核金额 (pendingWithdrawAmount):', pendingWithdrawNum)
+ console.log('可提现金额 = 累计 - 已提现 - 待审核 =', totalCommissionNum, '-', withdrawnNum, '-', pendingWithdrawNum, '=', availableEarningsNum)
+ console.log('最低提现金额 (minWithdrawAmount):', minWithdrawAmount)
+ console.log('按钮判断:', availableEarningsNum, '>=', minWithdrawAmount, '=', availableEarningsNum >= minWithdrawAmount)
+ console.log('✅ 按钮应该:', availableEarningsNum >= minWithdrawAmount ? '🟢 启用(绿色)' : '⚫ 禁用(灰色)')
+
this.setData({
isLoggedIn: true,
userInfo,
@@ -163,14 +180,15 @@ Page({
expiredCount,
// 收益数据 - 格式化为两位小数
- totalCommission: formatMoney(realData?.totalCommission || 0),
- availableEarnings: formatMoney(realData?.availableEarnings || 0),
- pendingWithdrawAmount: formatMoney(realData?.pendingWithdrawAmount || 0),
+ totalCommission: formatMoney(totalCommissionNum),
+ availableEarnings: formatMoney(availableEarningsNum), // ✅ 使用计算后的可提现金额
+ availableEarningsNum: availableEarningsNum, // ✅ 数字格式用于按钮判断
+ pendingWithdrawAmount: formatMoney(pendingWithdrawNum),
withdrawnEarnings: formatMoney(realData?.withdrawnEarnings || 0),
earnings: formatMoney(realData?.earnings || 0),
pendingEarnings: formatMoney(realData?.pendingEarnings || 0),
shareRate: realData?.shareRate || 90,
- minWithdrawAmount: realData?.minWithdrawAmount || 10,
+ minWithdrawAmount: minWithdrawAmount,
// 统计
referralCount: realData?.referralCount || realData?.stats?.totalBindings || activeBindings.length + convertedBindings.length,
@@ -206,6 +224,15 @@ Page({
console.log('[Referral] - 即将过期:', this.data.expiringCount)
console.log('[Referral] - 收益:', this.data.earnings)
+ console.log('=== [Referral] 按钮状态验证 ===')
+ console.log('累计佣金 (totalCommission):', this.data.totalCommission)
+ console.log('待审核金额 (pendingWithdrawAmount):', this.data.pendingWithdrawAmount)
+ console.log('可提现金额 (availableEarnings 显示):', this.data.availableEarnings)
+ console.log('可提现金额 (availableEarningsNum 判断):', this.data.availableEarningsNum, typeof this.data.availableEarningsNum)
+ console.log('最低提现金额 (minWithdrawAmount):', this.data.minWithdrawAmount, typeof this.data.minWithdrawAmount)
+ console.log('按钮启用条件:', this.data.availableEarningsNum, '>=', this.data.minWithdrawAmount, '=', this.data.availableEarningsNum >= this.data.minWithdrawAmount)
+ console.log('✅ 最终结果: 按钮应该', this.data.availableEarningsNum >= this.data.minWithdrawAmount ? '🟢 启用' : '⚫ 禁用')
+
// 隐藏加载提示
wx.hideLoading()
} else {
@@ -583,9 +610,16 @@ Page({
// 提现 - 直接到微信零钱
async handleWithdraw() {
- const availableEarnings = parseFloat(this.data.availableEarnings) || 0
+ // 使用数字版本直接进行判断,避免重复转换
+ const availableEarnings = this.data.availableEarningsNum || 0
const minWithdrawAmount = this.data.minWithdrawAmount || 10
+ console.log('[Withdraw] 提现检查:', {
+ availableEarnings,
+ minWithdrawAmount,
+ shouldEnable: availableEarnings >= minWithdrawAmount
+ })
+
if (availableEarnings <= 0) {
wx.showToast({ title: '暂无可提现收益', icon: 'none' })
return
@@ -634,13 +668,13 @@ Page({
if (res.success) {
wx.showModal({
- title: '提现成功 🎉',
- content: `¥${amount.toFixed(2)} 已到账您的微信零钱`,
+ title: '提现申请已提交 ✅',
+ content: res.message || '正在审核中,通过后会自动到账您的微信零钱',
showCancel: false,
- confirmText: '好的'
+ confirmText: '知道了'
})
- // 刷新数据
+ // 刷新数据(此时待审核金额会增加,可提现金额会减少)
this.initData()
} else {
if (res.needBind) {
@@ -655,7 +689,7 @@ Page({
}
})
} else {
- wx.showToast({ title: res.error || '提现失败', icon: 'none' })
+ wx.showToast({ title: res.message || res.error || '提现失败', icon: 'none', duration: 3000 })
}
}
} catch (e) {
@@ -728,7 +762,7 @@ Page({
})
// 如果开启,检查当前金额是否达到阈值
- if (enabled && parseFloat(this.data.availableEarnings) >= threshold) {
+ if (enabled && this.data.availableEarningsNum >= threshold) {
wx.showModal({
title: '提示',
content: `当前可提现金额¥${this.data.availableEarnings}已达到阈值¥${threshold},是否立即提现?`,
diff --git a/miniprogram/pages/referral/referral.wxml b/miniprogram/pages/referral/referral.wxml
index 806840cf..40f8645c 100644
--- a/miniprogram/pages/referral/referral.wxml
+++ b/miniprogram/pages/referral/referral.wxml
@@ -40,17 +40,17 @@
- 累计佣金
+ 可提现金额
{{shareRate}}% 返利
- ¥{{totalCommission}}
- 待审核: ¥{{pendingWithdrawAmount}}
+ ¥{{availableEarnings}}
+ 累计: ¥{{totalCommission}} | 待审核: ¥{{pendingWithdrawAmount}}
-
- {{availableEarnings < minWithdrawAmount ? '满' + minWithdrawAmount + '元可提现' : '申请提现 ¥' + availableEarnings}}
+
+ {{availableEarningsNum < minWithdrawAmount ? '满' + minWithdrawAmount + '元可提现' : '申请提现 ¥' + availableEarnings}}
diff --git a/开发文档/8、部署/可提现金额计算修复.md b/开发文档/8、部署/可提现金额计算修复.md
new file mode 100644
index 00000000..f2dd5a5d
--- /dev/null
+++ b/开发文档/8、部署/可提现金额计算修复.md
@@ -0,0 +1,359 @@
+# 可提现金额计算修复
+
+## 问题总结
+
+### 发现的问题
+
+**当前逻辑(错误)**:
+```javascript
+可提现金额 = 累计佣金 - 待审核金额
+```
+
+**问题场景**:
+1. 用户累计佣金 ¥100,申请提现 ¥50
+2. 此时:可提现 = 100 - 50 = ¥50 ✅ 正确
+3. 审核通过后,提现记录状态改为 completed
+4. 此时:可提现 = 100 - 0 = ¥100 ❌ 错误!
+
+**根本原因**:审核通过后,`pendingWithdrawAmount` 归零,但没有减去"已提现金额",导致可提现金额"回血"。
+
+## 正确方案
+
+### 计算公式
+
+```javascript
+可提现金额 = 累计佣金 - 已提现金额 - 待审核金额
+```
+
+### 字段说明
+
+| 字段 | 说明 | 来源 | 变化规律 |
+|------|------|------|----------|
+| `totalCommission` | 累计佣金总额 | `SUM(orders.amount) × distributorShare` | 有新订单就增加,只增不减 |
+| `withdrawnEarnings` | 已提现金额 | `users.withdrawn_earnings` | 审核通过时累加 |
+| `pendingWithdrawAmount` | 待审核金额 | `SUM(withdrawals.amount WHERE status='pending')` | 申请时增加,审核后归零 |
+| `availableEarnings` | 可提现金额 | 前端计算 | 动态变化 |
+
+## 修复内容
+
+### 1. 前端计算逻辑修正
+
+**文件**:`miniprogram/pages/referral/referral.js`
+
+**修改前**:
+```javascript
+// ❌ 错误:只减去待审核,没减去已提现
+const totalCommissionNum = realData?.totalCommission || 0
+const pendingWithdrawNum = realData?.pendingWithdrawAmount || 0
+const availableEarningsNum = totalCommissionNum - pendingWithdrawNum
+```
+
+**修改后**:
+```javascript
+// ✅ 正确:三元素完整计算
+const totalCommissionNum = realData?.totalCommission || 0
+const withdrawnNum = realData?.withdrawnEarnings || 0
+const pendingWithdrawNum = realData?.pendingWithdrawAmount || 0
+const availableEarningsNum = totalCommissionNum - withdrawnNum - pendingWithdrawNum
+```
+
+### 2. 详细日志输出
+
+```javascript
+console.log('=== [Referral] 收益计算(完整版)===')
+console.log('累计佣金 (totalCommission):', totalCommissionNum)
+console.log('已提现金额 (withdrawnEarnings):', withdrawnNum)
+console.log('待审核金额 (pendingWithdrawAmount):', pendingWithdrawNum)
+console.log('可提现金额 = 累计 - 已提现 - 待审核 =', totalCommissionNum, '-', withdrawnNum, '-', pendingWithdrawNum, '=', availableEarningsNum)
+console.log('最低提现金额 (minWithdrawAmount):', minWithdrawAmount)
+console.log('按钮判断:', availableEarningsNum, '>=', minWithdrawAmount, '=', availableEarningsNum >= minWithdrawAmount)
+console.log('✅ 按钮应该:', availableEarningsNum >= minWithdrawAmount ? '🟢 启用(绿色)' : '⚫ 禁用(灰色)')
+```
+
+## 验证流程
+
+### 完整场景测试
+
+#### 场景1:初始状态
+```
+数据:
+- 累计佣金: ¥100
+- 已提现: ¥0
+- 待审核: ¥0
+
+计算:
+availableEarnings = 100 - 0 - 0 = ¥100
+
+验证:✅ 可提现 ¥100
+```
+
+#### 场景2:申请提现
+```
+操作:申请提现 ¥50
+
+数据:
+- 累计佣金: ¥100 (不变)
+- 已提现: ¥0 (不变)
+- 待审核: ¥50 (新增)
+
+计算:
+availableEarnings = 100 - 0 - 50 = ¥50
+
+验证:✅ 可提现 ¥50
+```
+
+#### 场景3:审核通过(关键)
+```
+操作:管理员审核通过
+
+数据:
+- 累计佣金: ¥100 (不变)
+- 已提现: ¥50 (users.withdrawn_earnings += 50)
+- 待审核: ¥0 (状态改为 completed)
+
+计算:
+availableEarnings = 100 - 50 - 0 = ¥50
+
+验证:✅ 可提现 ¥50(不会回血!)
+```
+
+#### 场景4:新订单产生
+```
+操作:用户购买新商品,产生佣金 ¥20
+
+数据:
+- 累计佣金: ¥120 (100 + 20)
+- 已提现: ¥50 (不变)
+- 待审核: ¥0 (不变)
+
+计算:
+availableEarnings = 120 - 50 - 0 = ¥70
+
+验证:✅ 可提现 ¥70
+```
+
+#### 场景5:二次提现
+```
+操作:申请提现 ¥30
+
+数据:
+- 累计佣金: ¥120 (不变)
+- 已提现: ¥50 (不变)
+- 待审核: ¥30 (新增)
+
+计算:
+availableEarnings = 120 - 50 - 30 = ¥40
+
+验证:✅ 可提现 ¥40
+```
+
+### 数据库验证
+
+#### 1. 检查 users 表
+```sql
+SELECT
+ id,
+ nickname,
+ withdrawn_earnings
+FROM users
+WHERE id = 'YOUR_USER_ID';
+```
+
+#### 2. 检查 withdrawals 表
+```sql
+SELECT
+ id,
+ amount,
+ status,
+ created_at
+FROM withdrawals
+WHERE user_id = 'YOUR_USER_ID'
+ORDER BY created_at DESC;
+```
+
+#### 3. 检查 orders 表
+```sql
+SELECT
+ SUM(amount) as total_amount
+FROM orders
+WHERE referrer_id = 'YOUR_USER_ID'
+ AND status = 'paid';
+```
+
+#### 4. 手动验证计算
+
+```sql
+-- 1. 累计佣金
+SET @total_orders = (SELECT SUM(amount) FROM orders WHERE referrer_id = 'YOUR_USER_ID' AND status = 'paid');
+SET @distributor_share = 0.9;
+SET @total_commission = @total_orders * @distributor_share;
+
+-- 2. 已提现
+SET @withdrawn = (SELECT withdrawn_earnings FROM users WHERE id = 'YOUR_USER_ID');
+
+-- 3. 待审核
+SET @pending = (SELECT SUM(amount) FROM withdrawals WHERE user_id = 'YOUR_USER_ID' AND status = 'pending');
+
+-- 4. 可提现
+SET @available = @total_commission - @withdrawn - IFNULL(@pending, 0);
+
+-- 显示结果
+SELECT
+ @total_commission as '累计佣金',
+ @withdrawn as '已提现',
+ @pending as '待审核',
+ @available as '可提现';
+```
+
+## 测试步骤
+
+### 1. 清除缓存重新编译
+
+微信开发者工具:
+```
+工具 → 清除缓存 → 清除全部缓存数据
+点击 编译 按钮
+```
+
+### 2. 查看控制台日志
+
+进入分销中心页面,查看日志输出:
+
+```
+=== [Referral] 收益计算(完整版)===
+累计佣金 (totalCommission): 100
+已提现金额 (withdrawnEarnings): 0
+待审核金额 (pendingWithdrawAmount): 0
+可提现金额 = 累计 - 已提现 - 待审核 = 100 - 0 - 0 = 100
+最低提现金额 (minWithdrawAmount): 5
+按钮判断: 100 >= 5 = true
+✅ 按钮应该: 🟢 启用(绿色)
+```
+
+### 3. 测试提现流程
+
+1. **申请提现**:点击提现按钮,申请提现
+2. **查看变化**:
+ - 累计佣金不变
+ - 待审核金额增加
+ - 可提现金额减少
+3. **审核通过**:在管理后台审核通过
+4. **再次查看**:
+ - 累计佣金不变
+ - 已提现金额增加
+ - 待审核金额归零
+ - **可提现金额不应该回血**
+
+### 4. 验证按钮状态
+
+不同情况下按钮的状态:
+
+| 可提现金额 | 最低提现 | 按钮状态 | 按钮文本 |
+|-----------|---------|---------|---------|
+| ¥10 | ¥5 | 启用 | 申请提现 ¥10 |
+| ¥3 | ¥5 | 禁用 | 满5元可提现 |
+| ¥0 | ¥5 | 禁用 | 满5元可提现 |
+
+## 常见问题
+
+### Q1: 为什么要分"累计佣金"和"可提现金额"?
+
+**A**:
+- **累计佣金**:用户的成就感,"我总共赚了多少"
+- **可提现金额**:用户的可操作余额,"我现在能提多少"
+
+### Q2: 已提现的钱还算在累计佣金里吗?
+
+**A**: 是的。累计佣金是历史总和,只增不减。已提现只是资金流向,不影响累计数字。
+
+示例:
+- 累计赚了 ¥100(成就)
+- 已提现 ¥50(已到手)
+- 还能提现 ¥50(余额)
+
+### Q3: 如果审核拒绝会怎样?
+
+**A**:
+1. 待审核金额归零(提现申请被取消)
+2. 已提现金额不变
+3. 可提现金额恢复(用户可以重新申请)
+
+### Q4: users.withdrawn_earnings 会自动更新吗?
+
+**A**: 是的,在两个地方会更新:
+- `app/api/withdraw/route.ts` - 自动审核通过时
+- `app/api/admin/withdrawals/route.ts` - 管理员审核通过时
+
+### Q5: 为什么不直接从数据库读取可提现金额?
+
+**A**:
+- 可提现金额是**动态计算值**,不是固定字段
+- 实时计算确保数据准确
+- 便于调试和验证逻辑
+
+## 相关文件
+
+- `miniprogram/pages/referral/referral.js` - 前端计算(已修改)✅
+- `app/api/referral/data/route.ts` - 数据查询(无需修改)
+- `app/api/withdraw/route.ts` - 提现接口(无需修改)
+- `app/api/admin/withdrawals/route.ts` - 审核接口(无需修改)
+
+## 数据流图
+
+```
+┌────────────────────────────────────────────┐
+│ 订单产生佣金 │
+│ ↓ │
+│ 累计佣金 (totalCommission) │
+│ 持续累加,只增不减 │
+│ ↓ │
+│ ┌─────────────┴─────────────┐ │
+│ ↓ ↓ │
+│ 申请提现 继续积累 │
+│ ↓ │
+│ 待审核 (pendingWithdrawAmount) │
+│ 暂时冻结 │
+│ ↓ │
+│ 审核通过 │
+│ ↓ │
+│ 已提现 (withdrawnEarnings) │
+│ 累加记录 │
+│ │
+│ ┌─────────────────────────┐ │
+│ │ 可提现金额(实时计算) │ │
+│ │ = 累计佣金 │ │
+│ │ - 已提现金额 │ │
+│ │ - 待审核金额 │ │
+│ └─────────────────────────┘ │
+└────────────────────────────────────────────┘
+```
+
+## 总结
+
+### 修改前的问题
+
+```javascript
+❌ 可提现 = 累计佣金 - 待审核金额
+
+问题:审核通过后,待审核归零,可提现"回血"
+```
+
+### 修改后的正确逻辑
+
+```javascript
+✅ 可提现 = 累计佣金 - 已提现金额 - 待审核金额
+
+优点:
+1. 审核通过后,可提现金额不会增加
+2. 只有新订单产生佣金时,可提现金额才会增加
+3. 逻辑清晰,符合资金流向
+```
+
+### 业务含义
+
+- **累计佣金**:成就感 - "我赚了多少"
+- **已提现**:安全感 - "我拿到了多少"
+- **待审核**:期待感 - "我正在提多少"
+- **可提现**:行动力 - "我能提多少"
+
+这样的设计既满足了用户查看历史成就的需求,又确保了资金安全和准确性。
diff --git a/开发文档/8、部署/可提现金额计算逻辑分析.md b/开发文档/8、部署/可提现金额计算逻辑分析.md
new file mode 100644
index 00000000..772fab56
--- /dev/null
+++ b/开发文档/8、部署/可提现金额计算逻辑分析.md
@@ -0,0 +1,400 @@
+# 可提现金额计算逻辑分析
+
+## 问题描述
+
+用户提问:提现后,可提现金额应该如何计算?
+
+## 当前逻辑分析
+
+### 数据库字段
+
+**users 表**:
+- `earnings` - 已结算收益(保留兼容)
+- `pending_earnings` - 待结算收益(保留兼容)
+- `withdrawn_earnings` - 已提现金额(累加)
+
+**withdrawals 表**:
+- `status = 'pending'` - 待审核
+- `status = 'completed'` - 已完成
+- `status = 'failed'` - 已拒绝
+
+### 当前计算方式
+
+**后端 API (`/api/referral/data`)**:
+```typescript
+// 累计佣金(从 orders 表实时计算)
+totalCommission = SUM(orders.amount WHERE status = 'paid') × distributorShare
+
+// 待审核金额(从 withdrawals 表查询)
+pendingWithdrawAmount = SUM(withdrawals.amount WHERE status = 'pending')
+
+// 已提现金额(从 users 表读取)
+withdrawnEarnings = users.withdrawn_earnings
+```
+
+**前端计算**:
+```javascript
+// 可提现金额 = 累计佣金 - 待审核金额
+availableEarnings = totalCommission - pendingWithdrawAmount
+```
+
+## ⚠️ 发现的问题
+
+### 场景演示
+
+**初始状态**:
+```
+累计佣金: ¥100
+已提现: ¥0
+待审核: ¥0
+可提现 = 100 - 0 = ¥100 ✅
+```
+
+**申请提现 ¥50 后**:
+```
+累计佣金: ¥100 (不变)
+已提现: ¥0 (不变)
+待审核: ¥50 (新增)
+可提现 = 100 - 50 = ¥50 ✅ 正确
+```
+
+**审核通过后(当前逻辑的问题)**:
+```
+累计佣金: ¥100 (不变)
+已提现: ¥50 (users.withdrawn_earnings += 50)
+待审核: ¥0 (提现记录 status 变为 completed)
+可提现 = 100 - 0 = ¥100 ❌ 错误!应该是 ¥50
+```
+
+### 问题根源
+
+**当前公式**:
+```javascript
+可提现 = 累计佣金 - 待审核金额
+```
+
+**问题**:没有减去"已提现金额",导致审核通过后,可提现金额"回血"了。
+
+## ✅ 正确的计算方案
+
+### 推荐方案:三元素计算
+
+```javascript
+可提现金额 = 累计佣金 - 已提现金额 - 待审核金额
+```
+
+### 完整演示
+
+**初始状态**:
+```
+累计佣金: ¥100
+已提现: ¥0
+待审核: ¥0
+可提现 = 100 - 0 - 0 = ¥100 ✅
+```
+
+**申请提现 ¥50 后**:
+```
+累计佣金: ¥100 (不变)
+已提现: ¥0 (不变)
+待审核: ¥50 (新增提现申请)
+可提现 = 100 - 0 - 50 = ¥50 ✅ 正确
+```
+
+**审核通过后**:
+```
+累计佣金: ¥100 (不变)
+已提现: ¥50 (users.withdrawn_earnings += 50)
+待审核: ¥0 (状态改为 completed)
+可提现 = 100 - 50 - 0 = ¥50 ✅ 正确!
+```
+
+**有新订单后**:
+```
+累计佣金: ¥120 (新订单 ¥20)
+已提现: ¥50 (不变)
+待审核: ¥0 (不变)
+可提现 = 120 - 50 - 0 = ¥70 ✅ 正确!
+```
+
+## 修复方案
+
+### 方案A:后端返回 withdrawnEarnings,前端计算(推荐)✅
+
+**优点**:
+- 前端灵活控制
+- 逻辑清晰透明
+- 便于调试
+
+**实现**:
+
+#### 1. 后端确保返回正确数据
+
+`app/api/referral/data/route.ts` 已经返回了:
+```typescript
+{
+ totalCommission: 计算值, // ✅ 已有
+ pendingWithdrawAmount: 查询值, // ✅ 已有
+ withdrawnEarnings: users字段 // ✅ 已有
+}
+```
+
+#### 2. 前端修改计算逻辑
+
+`miniprogram/pages/referral/referral.js`:
+
+```javascript
+// ❌ 当前(错误)
+const availableEarningsNum = totalCommissionNum - pendingWithdrawNum
+
+// ✅ 修正(正确)
+const totalCommissionNum = realData?.totalCommission || 0
+const pendingWithdrawNum = realData?.pendingWithdrawAmount || 0
+const withdrawnNum = realData?.withdrawnEarnings || 0
+const availableEarningsNum = totalCommissionNum - withdrawnNum - pendingWithdrawNum
+```
+
+### 方案B:后端直接计算返回
+
+**优点**:
+- 前端无需计算
+- 后端统一控制逻辑
+
+**缺点**:
+- 前端不知道计算细节
+- 调试困难
+
+**实现**:
+
+```typescript
+// app/api/referral/data/route.ts
+const totalCommission = paymentStats.totalAmount * distributorShare
+const withdrawnEarnings = parseFloat(user.withdrawn_earnings) || 0
+const pendingWithdrawAmount = ...查询值...
+const availableEarnings = totalCommission - withdrawnEarnings - pendingWithdrawAmount
+
+return {
+ totalCommission,
+ withdrawnEarnings,
+ pendingWithdrawAmount,
+ availableEarnings // 后端计算好
+}
+```
+
+## 推荐实现(方案A)
+
+### 修改文件
+
+#### 1. `miniprogram/pages/referral/referral.js`
+
+```javascript
+// 在 initData() 方法中修改
+
+// ✅ 修正:可提现金额 = 累计佣金 - 已提现金额 - 待审核金额
+const totalCommissionNum = realData?.totalCommission || 0
+const withdrawnNum = realData?.withdrawnEarnings || 0
+const pendingWithdrawNum = realData?.pendingWithdrawAmount || 0
+const availableEarningsNum = totalCommissionNum - withdrawnNum - pendingWithdrawNum
+
+console.log('=== [Referral] 收益计算(完整版)===')
+console.log('累计佣金 (totalCommission):', totalCommissionNum)
+console.log('已提现金额 (withdrawnEarnings):', withdrawnNum)
+console.log('待审核金额 (pendingWithdrawAmount):', pendingWithdrawNum)
+console.log('可提现金额 = 累计 - 已提现 - 待审核 =', totalCommissionNum, '-', withdrawnNum, '-', pendingWithdrawNum, '=', availableEarningsNum)
+console.log('✅ 按钮应该:', availableEarningsNum >= minWithdrawAmount ? '🟢 启用' : '⚫ 禁用')
+```
+
+#### 2. `miniprogram/pages/referral/referral.wxml`
+
+显示部分需要更新(如果要显示已提现):
+
+```xml
+
+ ¥{{availableEarnings}}
+
+ 累计: ¥{{totalCommission}} | 已提现: ¥{{withdrawnEarnings}} | 待审核: ¥{{pendingWithdrawAmount}}
+
+
+```
+
+或者简化显示:
+```xml
+
+ ¥{{availableEarnings}}
+
+ 累计: ¥{{totalCommission}} | 待审核: ¥{{pendingWithdrawAmount}}
+
+
+```
+
+## 数据流向图
+
+```
+┌─────────────────────────────────────────────────┐
+│ 订单产生佣金 │
+│ ↓ │
+│ 累计佣金: ¥100 (持续累加) │
+│ ↓ │
+│ ┌────────────┴────────────┐ │
+│ ↓ ↓ │
+│ 申请提现 ¥50 继续累积佣金 │
+│ ↓ ↓ │
+│ 待审核: ¥50 累计: ¥120 │
+│ 可提现: ¥50 │
+│ ↓ │
+│ 审核通过 │
+│ ↓ │
+│ 已提现: ¥50 │
+│ 待审核: ¥0 │
+│ 可提现: ¥70 (120-50-0) │
+└─────────────────────────────────────────────────┘
+```
+
+## 测试用例
+
+### 用例1:无提现记录
+
+```
+输入:
+- totalCommission = 100
+- withdrawnEarnings = 0
+- pendingWithdrawAmount = 0
+
+计算:
+availableEarnings = 100 - 0 - 0 = 100
+
+预期:✅ 可提现 ¥100
+```
+
+### 用例2:有待审核提现
+
+```
+输入:
+- totalCommission = 100
+- withdrawnEarnings = 0
+- pendingWithdrawAmount = 30
+
+计算:
+availableEarnings = 100 - 0 - 30 = 70
+
+预期:✅ 可提现 ¥70
+```
+
+### 用例3:有已提现记录
+
+```
+输入:
+- totalCommission = 100
+- withdrawnEarnings = 50
+- pendingWithdrawAmount = 0
+
+计算:
+availableEarnings = 100 - 50 - 0 = 50
+
+预期:✅ 可提现 ¥50
+```
+
+### 用例4:复合情况
+
+```
+输入:
+- totalCommission = 200
+- withdrawnEarnings = 80
+- pendingWithdrawAmount = 40
+
+计算:
+availableEarnings = 200 - 80 - 40 = 80
+
+预期:✅ 可提现 ¥80
+```
+
+### 用例5:边界情况(全部提完)
+
+```
+输入:
+- totalCommission = 100
+- withdrawnEarnings = 70
+- pendingWithdrawAmount = 30
+
+计算:
+availableEarnings = 100 - 70 - 30 = 0
+
+预期:✅ 可提现 ¥0,按钮禁用
+```
+
+## 验证 users.withdrawn_earnings 是否正确维护
+
+### 提现接口确认
+
+查看 `app/api/withdraw/route.ts`:
+```typescript
+// 第165行(自动审核情况下)
+UPDATE users
+SET withdrawn_earnings = withdrawn_earnings + ?,
+ pending_earnings = GREATEST(0, pending_earnings - ?)
+WHERE id = ?
+```
+
+查看 `app/api/admin/withdrawals/route.ts`:
+```typescript
+// 第156行(管理员审核通过)
+UPDATE users
+SET withdrawn_earnings = withdrawn_earnings + ?,
+ pending_earnings = pending_earnings - ?
+WHERE id = ?
+```
+
+✅ **确认**:`withdrawn_earnings` 字段在提现审核通过后会正确累加。
+
+## 总结
+
+### 当前问题
+
+```javascript
+❌ 错误:可提现 = 累计佣金 - 待审核金额
+```
+
+- 审核通过后,待审核归零,可提现"回血"
+- 导致用户可以重复提现同一笔钱
+
+### 正确方案
+
+```javascript
+✅ 正确:可提现 = 累计佣金 - 已提现金额 - 待审核金额
+```
+
+- 累计佣金:历史总和,只增不减
+- 已提现金额:累加的已到账金额
+- 待审核金额:申请中但未到账的金额
+- 可提现金额:真正可以申请提现的余额
+
+### 字段含义
+
+| 字段 | 含义 | 变化规律 |
+|------|------|----------|
+| `totalCommission` | 累计佣金总额 | 有新订单就增加 |
+| `withdrawnEarnings` | 已提现金额 | 审核通过时增加 |
+| `pendingWithdrawAmount` | 待审核金额 | 申请提现时增加,审核后清零 |
+| `availableEarnings` | 可提现金额 | 动态计算,三者综合结果 |
+
+### 业务含义
+
+- **累计佣金**:成就感,"我总共赚了多少"
+- **已提现**:安全感,"我已经拿到手多少"
+- **待审核**:期待感,"我正在提现多少"
+- **可提现**:行动力,"我现在能提多少"
+
+## 下一步行动
+
+1. 修改前端计算逻辑(添加 `withdrawnEarnings`)
+2. 添加详细调试日志
+3. 测试各种场景
+4. 验证数据库 `withdrawn_earnings` 是否正确
+5. 文档记录新逻辑
+
+## 相关文件
+
+- `miniprogram/pages/referral/referral.js` - 前端计算(需修改)
+- `app/api/referral/data/route.ts` - 数据查询(已正确)
+- `app/api/withdraw/route.ts` - 提现接口(已正确)
+- `app/api/admin/withdrawals/route.ts` - 审核接口(已正确)
diff --git a/开发文档/8、部署/提现卡片显示优化.md b/开发文档/8、部署/提现卡片显示优化.md
new file mode 100644
index 00000000..7687df1f
--- /dev/null
+++ b/开发文档/8、部署/提现卡片显示优化.md
@@ -0,0 +1,279 @@
+# 提现卡片显示优化
+
+## 需求
+
+用户希望提现卡片更直观地显示**可提现金额**,而不是累计佣金。
+
+## 修改前后对比
+
+### 修改前
+
+```
+┌─────────────────────────────────┐
+│ 💰 累计佣金 ¥8.10 │
+│ 90% 返利 待审核: ¥0.00 │
+├─────────────────────────────────┤
+│ 申请提现 ¥8.10 │
+└─────────────────────────────────┘
+```
+
+**问题**:
+- 用户看到"累计佣金 ¥8.10",但不清楚实际能提多少
+- 需要心算:8.10 - 0.00 = 8.10(可提现)
+
+### 修改后
+
+```
+┌─────────────────────────────────────────┐
+│ 💰 可提现金额 ¥8.10 │
+│ 90% 返利 累计: ¥8.10 | 待审核: ¥0.00 │
+├─────────────────────────────────────────┤
+│ 申请提现 ¥8.10 │
+└─────────────────────────────────────────┘
+```
+
+**优点**:
+- ✅ 直接显示可提现金额 ¥8.10(最关心的数据)
+- ✅ 底部小字显示明细:累计佣金 + 待审核金额
+- ✅ 一目了然,无需计算
+
+## 具体修改
+
+### 文件:`miniprogram/pages/referral/referral.wxml`
+
+```xml
+
+
+
+
+
+
+ 累计佣金
+ {{shareRate}}% 返利
+
+
+
+ ¥{{totalCommission}}
+ 待审核: ¥{{pendingWithdrawAmount}}
+
+
+
+
+
+
+
+
+ 可提现金额
+ {{shareRate}}% 返利
+
+
+
+ ¥{{availableEarnings}}
+ 累计: ¥{{totalCommission}} | 待审核: ¥{{pendingWithdrawAmount}}
+
+```
+
+## 数据说明
+
+### 字段含义
+
+| 字段 | 说明 | 示例 |
+|------|------|------|
+| `totalCommission` | 累计佣金总额(所有订单佣金之和) | ¥8.10 |
+| `pendingWithdrawAmount` | 待审核的提现金额(已申请但未到账) | ¥0.00 |
+| `availableEarnings` | **可提现金额** = 累计佣金 - 待审核金额 | ¥8.10 |
+
+### 计算公式
+
+```javascript
+availableEarnings = totalCommission - pendingWithdrawAmount
+ = 8.10 - 0.00
+ = 8.10
+```
+
+## 场景示例
+
+### 场景1:无待审核提现
+
+```
+累计佣金: ¥100.00
+待审核: ¥0.00
+可提现: ¥100.00
+```
+
+显示:
+```
+可提现金额 ¥100.00
+累计: ¥100.00 | 待审核: ¥0.00
+```
+
+### 场景2:有待审核提现
+
+```
+累计佣金: ¥100.00
+待审核: ¥30.00
+可提现: ¥70.00
+```
+
+显示:
+```
+可提现金额 ¥70.00
+累计: ¥100.00 | 待审核: ¥30.00
+```
+
+用户一眼就能看到:
+- 可以提现 70 元
+- 有 30 元在审核中
+- 总共赚了 100 元
+
+### 场景3:全部待审核
+
+```
+累计佣金: ¥100.00
+待审核: ¥100.00
+可提现: ¥0.00
+```
+
+显示:
+```
+可提现金额 ¥0.00
+累计: ¥100.00 | 待审核: ¥100.00
+```
+
+按钮变灰:`满5元可提现`
+
+## 用户体验优化
+
+### 信息层级
+
+**主信息(大号字体)**:
+- 可提现金额 ¥8.10
+- 用户最关心的数据,放在最显眼位置
+
+**次要信息(小号字体)**:
+- 累计: ¥8.10 | 待审核: ¥0.00
+- 提供明细,让用户了解全貌
+
+### 视觉引导
+
+```
+┌─────────────────────────────────────────┐
+│ 💰 可提现金额 ← 标签 ← 主信息
+│ ¥8.10 ← 大号
+│ 90% 返利 ← 提示 │
+│ 累计: ¥8.10 | 待审核: ¥0.00 ← 明细(小号)
+├─────────────────────────────────────────┤
+│ 申请提现 ¥8.10 ← 行动按钮 │
+└─────────────────────────────────────────┘
+```
+
+## 对比其他方案
+
+### 方案A:显示累计佣金(原方案)
+
+```
+累计佣金: ¥8.10
+待审核: ¥0.00
+```
+
+- ❌ 需要用户自己计算可提现金额
+- ❌ 不够直观
+
+### 方案B:只显示可提现金额
+
+```
+可提现金额: ¥8.10
+```
+
+- ✅ 直观
+- ❌ 缺少明细,用户不知道累计赚了多少
+
+### 方案C:显示可提现 + 明细(当前方案)✅
+
+```
+可提现金额: ¥8.10
+累计: ¥8.10 | 待审核: ¥0.00
+```
+
+- ✅ 直观:一眼看到可提现金额
+- ✅ 完整:提供累计和待审核的明细
+- ✅ 平衡:主次分明
+
+## 样式建议(可选)
+
+如果需要进一步优化样式,可以考虑:
+
+### 1. 调整明细字号
+
+```css
+.pending-text {
+ font-size: 22rpx; /* 从 24rpx 减小到 22rpx */
+ color: rgba(255,255,255,0.5);
+ margin-top: 8rpx;
+ display: block;
+}
+```
+
+### 2. 使用图标分隔
+
+```xml
+
+ 累计: ¥{{totalCommission}} · 待审核: ¥{{pendingWithdrawAmount}}
+
+```
+
+用 `·` (中点) 代替 `|` (竖线)
+
+### 3. 增加图标说明
+
+```xml
+
+ 💰 累计: ¥{{totalCommission}} ⏳ 待审核: ¥{{pendingWithdrawAmount}}
+
+```
+
+## 测试要点
+
+### 1. 显示验证
+
+- [ ] 标签显示为"可提现金额"
+- [ ] 大号数字显示正确的可提现金额
+- [ ] 小号文字显示累计和待审核金额
+- [ ] 格式正确:`累计: ¥X.XX | 待审核: ¥Y.YY`
+
+### 2. 计算验证
+
+```
+已知:
+- 累计佣金: ¥8.10
+- 待审核: ¥0.00
+
+验证:
+- 可提现 = 8.10 - 0.00 = ¥8.10 ✅
+```
+
+### 3. 边界情况
+
+- [ ] 可提现为 0 时的显示
+- [ ] 待审核大于累计时的显示(理论上不会出现)
+- [ ] 多笔待审核的累加
+
+## 相关文件
+
+- `miniprogram/pages/referral/referral.wxml` - 界面结构(本次修改)
+- `miniprogram/pages/referral/referral.wxss` - 样式
+- `miniprogram/pages/referral/referral.js` - 逻辑(计算 availableEarnings)
+
+## 总结
+
+这次优化让提现卡片更加**用户友好**:
+
+**修改前**:
+- 显示"累计佣金",用户需要自己计算
+
+**修改后**:
+- 直接显示"可提现金额",一目了然
+- 保留明细信息(累计、待审核),信息完整
+- 主次分明,视觉层级清晰
+
+核心理念:**把用户最关心的数据,放在最显眼的位置**。
diff --git a/开发文档/8、部署/提现双向校验实现.md b/开发文档/8、部署/提现双向校验实现.md
new file mode 100644
index 00000000..0556f0b5
--- /dev/null
+++ b/开发文档/8、部署/提现双向校验实现.md
@@ -0,0 +1,423 @@
+# 提现双向校验实现
+
+## 需求
+
+前端和后端都必须使用**相同的逻辑**校验可提现金额,确保安全性和一致性。
+
+## 校验逻辑(统一)
+
+```javascript
+可提现金额 = 累计佣金 - 已提现金额 - 待审核金额
+```
+
+## 前后端对比
+
+### 前端校验(miniprogram)
+
+**文件**:`miniprogram/pages/referral/referral.js`
+
+**作用**:按钮启用/禁用判断
+
+```javascript
+// 计算可提现金额
+const totalCommissionNum = realData?.totalCommission || 0
+const withdrawnNum = realData?.withdrawnEarnings || 0
+const pendingWithdrawNum = realData?.pendingWithdrawAmount || 0
+const availableEarningsNum = totalCommissionNum - withdrawnNum - pendingWithdrawNum
+
+// 判断按钮状态
+if (availableEarningsNum >= minWithdrawAmount) {
+ // 启用按钮
+} else {
+ // 禁用按钮
+}
+```
+
+### 后端校验(API)
+
+**文件**:`app/api/withdraw/route.ts`
+
+**作用**:提现申请最终验证
+
+```typescript
+// 1. 查询累计佣金
+const ordersResult = await query(`
+ SELECT COALESCE(SUM(amount), 0) as total_amount
+ FROM orders
+ WHERE referrer_id = ? AND status = 'paid'
+`, [userId])
+const totalAmount = parseFloat(ordersResult[0]?.total_amount || 0)
+const totalCommission = totalAmount * distributorShare
+
+// 2. 读取已提现金额
+const withdrawnEarnings = parseFloat(user.withdrawn_earnings) || 0
+
+// 3. 查询待审核金额
+const pendingResult = await query(`
+ SELECT COALESCE(SUM(amount), 0) as pending_amount
+ FROM withdrawals
+ WHERE user_id = ? AND status = 'pending'
+`, [userId])
+const pendingWithdrawAmount = parseFloat(pendingResult[0]?.pending_amount || 0)
+
+// 4. 计算可提现金额
+const availableAmount = totalCommission - withdrawnEarnings - pendingWithdrawAmount
+
+// 5. 验证
+if (amount > availableAmount) {
+ return NextResponse.json({
+ success: false,
+ message: `可提现金额不足。当前可提现 ¥${availableAmount.toFixed(2)}(累计 ¥${totalCommission.toFixed(2)} - 已提现 ¥${withdrawnEarnings.toFixed(2)} - 待审核 ¥${pendingWithdrawAmount.toFixed(2)})`
+ })
+}
+```
+
+## 修改内容
+
+### 1. 后端添加已提现金额
+
+**修改前(错误)**:
+```typescript
+// ❌ 只减去待审核,没减去已提现
+const availableAmount = totalCommission - pendingWithdrawAmount
+```
+
+**修改后(正确)**:
+```typescript
+// ✅ 三元素完整校验
+const withdrawnEarnings = parseFloat(user.withdrawn_earnings) || 0
+const availableAmount = totalCommission - withdrawnEarnings - pendingWithdrawAmount
+```
+
+### 2. 详细日志输出
+
+```typescript
+console.log('[Withdraw] 提现验证(完整版):')
+console.log('- 累计佣金 (totalCommission):', totalCommission)
+console.log('- 已提现金额 (withdrawnEarnings):', withdrawnEarnings)
+console.log('- 待审核金额 (pendingWithdrawAmount):', pendingWithdrawAmount)
+console.log('- 可提现金额 = 累计 - 已提现 - 待审核 =', totalCommission, '-', withdrawnEarnings, '-', pendingWithdrawAmount, '=', availableAmount)
+console.log('- 申请提现金额 (amount):', amount)
+console.log('- 判断:', amount, '>', availableAmount, '=', amount > availableAmount)
+```
+
+### 3. 优化错误提示
+
+**修改前**:
+```typescript
+message: `可提现金额不足,当前可提现 ¥${availableAmount.toFixed(2)},待审核 ¥${pendingWithdrawAmount.toFixed(2)}`
+```
+
+**修改后**:
+```typescript
+message: `可提现金额不足。当前可提现 ¥${availableAmount.toFixed(2)}(累计 ¥${totalCommission.toFixed(2)} - 已提现 ¥${withdrawnEarnings.toFixed(2)} - 待审核 ¥${pendingWithdrawAmount.toFixed(2)})`
+```
+
+## 双向校验流程
+
+```
+用户点击提现按钮
+ ↓
+┌──────────────────────────┐
+│ 前端校验(第一层) │
+│ 按钮启用/禁用判断 │
+├──────────────────────────┤
+│ 可提现 >= 最低金额? │
+│ YES → 允许点击 │
+│ NO → 按钮禁用 │
+└──────────────────────────┘
+ ↓
+用户确认提现
+ ↓
+┌──────────────────────────┐
+│ 后端校验(第二层) │
+│ API 最终验证 │
+├──────────────────────────┤
+│ 1. 查询累计佣金 │
+│ 2. 读取已提现金额 │
+│ 3. 查询待审核金额 │
+│ 4. 计算可提现金额 │
+│ 5. amount > available? │
+│ YES → 拒绝提现 │
+│ NO → 允许提现 │
+└──────────────────────────┘
+ ↓
+创建提现记录
+```
+
+## 为什么需要双向校验?
+
+### 前端校验的作用
+
+**优点**:
+- ✅ 快速响应,提升用户体验
+- ✅ 减少无效请求,降低服务器压力
+- ✅ 按钮禁用,防止误操作
+
+**局限**:
+- ❌ 数据可能过期(API 数据缓存)
+- ❌ 可被绕过(客户端不可信)
+- ❌ 无法阻止恶意请求
+
+### 后端校验的作用
+
+**优点**:
+- ✅ 最终防线,确保资金安全
+- ✅ 实时数据,准确无误
+- ✅ 不可绕过,强制验证
+
+**必要性**:
+- ✅ 防止前端被篡改
+- ✅ 防止并发提现
+- ✅ 防止逻辑漏洞
+
+## 攻击场景防御
+
+### 场景1:前端被篡改
+
+**攻击**:
+- 黑客修改前端代码,移除按钮禁用逻辑
+- 强制发送提现请求
+
+**防御**:
+- ✅ 后端独立校验,拒绝超额提现
+
+### 场景2:并发提现
+
+**攻击**:
+- 用户快速点击两次提现按钮
+- 或同时在多个设备上提现
+
+**防御**:
+- ✅ 后端查询最新的 `pendingWithdrawAmount`
+- ✅ 数据库事务保证原子性
+
+### 场景3:API 重放攻击
+
+**攻击**:
+- 捕获提现请求,重复发送
+
+**防御**:
+- ✅ 后端实时校验可提现金额
+- ✅ 创建提现记录后,`pendingWithdrawAmount` 增加
+- ✅ 第二次请求时,可提现金额不足,拒绝
+
+## 测试用例
+
+### 测试1:正常提现
+
+**数据**:
+- 累计佣金: ¥100
+- 已提现: ¥0
+- 待审核: ¥0
+- 申请提现: ¥50
+
+**前端**:
+```
+可提现 = 100 - 0 - 0 = 100
+50 < 100 → 按钮启用 ✅
+```
+
+**后端**:
+```
+可提现 = 100 - 0 - 0 = 100
+50 ≤ 100 → 允许提现 ✅
+```
+
+**结果**:✅ 提现成功
+
+### 测试2:超额提现
+
+**数据**:
+- 累计佣金: ¥100
+- 已提现: ¥0
+- 待审核: ¥0
+- 申请提现: ¥150
+
+**前端**:
+```
+可提现 = 100 - 0 - 0 = 100
+150 > 100 → 按钮禁用 ✅
+(正常情况下用户无法点击)
+```
+
+**后端**(假设黑客绕过前端):
+```
+可提现 = 100 - 0 - 0 = 100
+150 > 100 → 拒绝提现 ✅
+返回错误:可提现金额不足
+```
+
+**结果**:✅ 后端拦截成功
+
+### 测试3:重复提现
+
+**数据**:
+- 累计佣金: ¥100
+- 已提现: ¥0
+- 待审核: ¥0
+
+**第一次提现 ¥50**:
+```
+前端:100 - 0 - 0 = 100,允许 ✅
+后端:100 - 0 - 0 = 100,允许 ✅
+创建提现记录,pending += 50
+```
+
+**第二次提现 ¥60**(并发或快速点击):
+```
+前端:可能还是显示 100(数据未刷新)
+后端:100 - 0 - 50 = 50
+60 > 50 → 拒绝提现 ✅
+```
+
+**结果**:✅ 后端防御成功
+
+### 测试4:审核通过后再次提现
+
+**初始**:
+- 累计佣金: ¥100
+- 已提现: ¥50(之前提现已到账)
+- 待审核: ¥0
+
+**申请提现 ¥60**:
+```
+前端:100 - 50 - 0 = 50
+60 > 50 → 按钮禁用 ✅
+```
+
+**后端**(假设绕过前端):
+```
+100 - 50 - 0 = 50
+60 > 50 → 拒绝提现 ✅
+```
+
+**结果**:✅ 双重防护
+
+## 日志示例
+
+### 前端日志
+
+```
+=== [Referral] 收益计算(完整版)===
+累计佣金 (totalCommission): 100
+已提现金额 (withdrawnEarnings): 50
+待审核金额 (pendingWithdrawAmount): 0
+可提现金额 = 累计 - 已提现 - 待审核 = 100 - 50 - 0 = 50
+最低提现金额 (minWithdrawAmount): 5
+按钮判断: 50 >= 5 = true
+✅ 按钮应该: 🟢 启用(绿色)
+```
+
+### 后端日志
+
+```
+[Withdraw] 佣金计算:
+- 订单总金额: 111.11
+- 分成比例: 90%
+- 累计佣金: 100
+
+[Withdraw] 提现验证(完整版):
+- 累计佣金 (totalCommission): 100
+- 已提现金额 (withdrawnEarnings): 50
+- 待审核金额 (pendingWithdrawAmount): 0
+- 可提现金额 = 累计 - 已提现 - 待审核 = 100 - 50 - 0 = 50
+- 申请提现金额 (amount): 50
+- 判断: 50 > 50 = false
+✅ 提现申请通过
+```
+
+## 数据一致性保证
+
+### 数据来源
+
+| 字段 | 前端数据来源 | 后端数据来源 | 一致性 |
+|------|-------------|-------------|--------|
+| 累计佣金 | `/api/referral/data` | 实时查询 `orders` | ✅ 相同算法 |
+| 已提现 | `/api/referral/data` | 读取 `users.withdrawn_earnings` | ✅ 相同字段 |
+| 待审核 | `/api/referral/data` | 实时查询 `withdrawals` | ✅ 相同查询 |
+
+### 同步机制
+
+1. **前端数据**:来自 `/api/referral/data`
+2. **后端校验**:独立查询,实时数据
+3. **一致性保证**:
+ - 相同的数据库表
+ - 相同的计算公式
+ - 后端数据更准确(实时查询)
+
+## 相关文件
+
+- `miniprogram/pages/referral/referral.js` - 前端校验 ✅
+- `app/api/withdraw/route.ts` - 后端校验 ✅
+- `app/api/referral/data/route.ts` - 数据查询
+
+## 部署注意事项
+
+### 1. 重启后端服务
+
+```bash
+python devlop.py restart mycontent
+```
+
+### 2. 清除前端缓存
+
+```
+微信开发者工具:工具 → 清除缓存 → 清除全部缓存数据
+```
+
+### 3. 监控日志
+
+```bash
+pm2 logs mycontent --lines 100
+```
+
+关注:
+- `[Withdraw] 提现验证(完整版):` - 后端校验日志
+- `[Referral] 收益计算(完整版)` - 前端计算日志
+
+### 4. 测试验证
+
+- [ ] 正常提现(可提现 > 最低金额)
+- [ ] 超额提现(申请金额 > 可提现)
+- [ ] 并发提现(快速点击两次)
+- [ ] 审核后再提现
+
+## 安全检查清单
+
+- [x] 前端使用三元素计算
+- [x] 后端使用三元素校验
+- [x] 前后端公式完全一致
+- [x] 后端独立查询数据(不信任前端)
+- [x] 详细日志记录
+- [x] 清晰的错误提示
+
+## 总结
+
+### 双向校验的意义
+
+**前端**:
+- 用户体验优化
+- 快速反馈
+- 减少无效请求
+
+**后端**:
+- 安全防线
+- 资金保护
+- 最终决策
+
+### 公式统一
+
+```javascript
+// 前端和后端完全一致
+可提现金额 = 累计佣金 - 已提现金额 - 待审核金额
+```
+
+### 防御能力
+
+- ✅ 防篡改
+- ✅ 防并发
+- ✅ 防重放
+- ✅ 防超额
+
+**核心原则**:前端便利,后端安全,双重保障。
diff --git a/开发文档/8、部署/提现审核流程优化.md b/开发文档/8、部署/提现审核流程优化.md
new file mode 100644
index 00000000..ff9acd1c
--- /dev/null
+++ b/开发文档/8、部署/提现审核流程优化.md
@@ -0,0 +1,312 @@
+# 提现审核流程优化
+
+## 需求
+
+提现申请提交后,应该明确告知用户:
+- ✅ 提现申请已提交
+- ⏳ 正在审核中
+- 💰 审核通过后会自动到账微信零钱
+
+而不是误导用户以为已经立即到账。
+
+## 修改内容
+
+### 1. 后端提示优化
+
+**文件**:`app/api/withdraw/route.ts`
+
+```typescript
+return NextResponse.json({
+ success: true,
+ message: '提现申请已提交,正在审核中,通过后会自动到账您的微信零钱',
+ data: {
+ withdrawId,
+ amount,
+ account,
+ accountType: accountType === 'alipay' ? '支付宝' : '微信',
+ status: 'pending' // ✅ 新增:返回状态
+ }
+})
+```
+
+**变更**:
+- ❌ 旧:`message: '提现成功'` (误导性)
+- ✅ 新:`message: '提现申请已提交,正在审核中,通过后会自动到账您的微信零钱'` (准确)
+- ✅ 新增 `status: 'pending'` 字段
+
+### 2. 前端提示优化
+
+**文件**:`miniprogram/pages/referral/referral.js`
+
+```javascript
+if (res.success) {
+ wx.showModal({
+ title: '提现申请已提交 ✅',
+ content: res.message || '正在审核中,通过后会自动到账您的微信零钱',
+ showCancel: false,
+ confirmText: '知道了'
+ })
+
+ // 刷新数据(此时待审核金额会增加,可提现金额会减少)
+ this.initData()
+}
+```
+
+**变更**:
+- ❌ 旧标题:`'提现成功 🎉'` (误导性)
+- ✅ 新标题:`'提现申请已提交 ✅'` (准确)
+- ❌ 旧内容:`'¥X.XX 已到账您的微信零钱'` (虚假)
+- ✅ 新内容:`'正在审核中,通过后会自动到账您的微信零钱'` (真实)
+- ❌ 旧按钮:`'好的'`
+- ✅ 新按钮:`'知道了'`
+
+### 3. 错误提示优化
+
+```javascript
+} else {
+ wx.showToast({
+ title: res.message || res.error || '提现失败',
+ icon: 'none',
+ duration: 3000 // ✅ 增加显示时间到3秒
+ })
+}
+```
+
+## 提现流程说明
+
+### 完整流程
+
+```
+1. 用户点击"申请提现"
+ ↓
+2. 前端验证:可提现金额 >= 最低提现金额
+ ↓
+3. 后端创建提现记录:status = 'pending'
+ ↓
+4. 提示用户:"提现申请已提交,正在审核中"
+ ↓
+5. 刷新分销中心数据:
+ - 待审核金额 += 提现金额
+ - 可提现金额 -= 提现金额
+ ↓
+6. 管理员在后台审核
+ ↓
+7. 审核通过:
+ - 更新 withdrawals.status = 'completed'
+ - 自动转账到微信零钱
+ - 发送微信通知给用户
+```
+
+### 状态说明
+
+| 状态 | 英文 | 说明 | 用户提示 |
+|------|------|------|----------|
+| 待审核 | `pending` | 提现申请已提交,等待管理员审核 | 正在审核中 |
+| 已完成 | `completed` | 审核通过,已转账到微信零钱 | 已到账 |
+| 已拒绝 | `failed` | 审核未通过 | 提现失败 |
+
+### 数据变化示例
+
+**提现前**:
+```
+累计佣金: 100元
+待审核金额: 0元
+可提现金额: 100 - 0 = 100元
+```
+
+**申请提现50元后**:
+```
+累计佣金: 100元
+待审核金额: 0 + 50 = 50元
+可提现金额: 100 - 50 = 50元
+```
+
+**审核通过后**:
+```
+累计佣金: 100元
+待审核金额: 50 - 50 = 0元
+已提现金额: 0 + 50 = 50元
+可提现金额: 100 - 0 = 100元 (如果有新订单)
+```
+
+## 用户体验对比
+
+### 修改前(误导性)
+
+```
+┌─────────────────────┐
+│ 提现成功 🎉 │
+├─────────────────────┤
+│ ¥50.00 已到账您的 │
+│ 微信零钱 │
+├─────────────────────┤
+│ [好的] │
+└─────────────────────┘
+```
+
+**问题**:
+- ❌ 用户以为钱已经到账
+- ❌ 用户去微信查看,发现没钱
+- ❌ 产生疑惑和不满
+
+### 修改后(准确清晰)
+
+```
+┌─────────────────────┐
+│ 提现申请已提交 ✅ │
+├─────────────────────┤
+│ 正在审核中,通过后 │
+│ 会自动到账您的微信 │
+│ 零钱 │
+├─────────────────────┤
+│ [知道了] │
+└─────────────────────┘
+```
+
+**优点**:
+- ✅ 用户知道需要等待审核
+- ✅ 用户知道审核通过后会自动到账
+- ✅ 符合实际情况
+
+## 后续优化建议
+
+### 1. 审核通知
+
+管理员审核通过后,发送微信模板消息通知用户:
+
+```javascript
+// 伪代码
+wx.sendTemplateMessage({
+ touser: userOpenId,
+ template_id: 'OPENTM415934726',
+ data: {
+ thing1: { value: '提现申请' },
+ amount2: { value: '50.00元' },
+ phrase3: { value: '审核通过' },
+ time4: { value: '2026-02-04 15:30' }
+ }
+})
+```
+
+### 2. 提现记录页面
+
+在"我的"页面增加"提现记录"入口,让用户查看:
+- 待审核的提现申请
+- 已完成的提现记录
+- 失败的提现记录及原因
+
+### 3. 审核预计时间
+
+在提示中增加审核时长预期:
+
+```
+正在审核中,预计1-3个工作日内完成审核,
+通过后会自动到账您的微信零钱
+```
+
+### 4. 自动审核
+
+对于小额提现(如50元以下),可以实现自动审核:
+
+```javascript
+if (amount <= 50) {
+ // 自动审核通过
+ await query(`UPDATE withdrawals SET status = 'completed' WHERE id = ?`, [withdrawId])
+ // 立即转账
+ await wechatPay.transferToWallet(...)
+ return { message: '提现成功,已到账您的微信零钱' }
+} else {
+ // 需要人工审核
+ return { message: '提现申请已提交,正在审核中' }
+}
+```
+
+## 管理后台提现审核功能
+
+### 审核页面功能
+
+1. **提现列表**:
+ - 显示所有待审核的提现申请
+ - 显示用户信息、提现金额、申请时间
+ - 显示用户的累计佣金、历史提现次数
+
+2. **审核操作**:
+ - 通过:调用微信商家转账接口
+ - 拒绝:填写拒绝原因
+
+3. **记录查询**:
+ - 已完成的提现记录
+ - 失败的提现记录
+
+### 审核接口(待实现)
+
+```typescript
+// POST /api/admin/withdraw/approve
+{
+ "withdrawId": "W1738694028123",
+ "action": "approve" | "reject",
+ "reason": "拒绝原因(可选)"
+}
+```
+
+## 测试步骤
+
+### 1. 测试提现申请
+
+1. 在小程序中进入分销中心
+2. 确保可提现金额 >= 5元
+3. 点击"申请提现"按钮
+4. 确认提现金额
+5. 查看提示是否为"提现申请已提交,正在审核中"
+
+### 2. 验证数据变化
+
+提现后立即刷新页面,检查:
+- ✅ 累计佣金不变
+- ✅ 待审核金额增加
+- ✅ 可提现金额减少
+- ✅ 提现按钮重新判断是否可用
+
+### 3. 查看数据库
+
+```sql
+-- 查看提现记录
+SELECT * FROM withdrawals
+WHERE user_id = 'ogpTW5fmXRGNpoUbXB3UEqnVe5Tg'
+ORDER BY created_at DESC
+LIMIT 5;
+
+-- 应该看到最新的记录,status = 'pending'
+```
+
+### 4. 模拟审核通过
+
+```sql
+-- 手动更新状态为已完成
+UPDATE withdrawals
+SET status = 'completed',
+ completed_at = NOW()
+WHERE id = 'W1738694028123';
+```
+
+再次刷新小程序,检查:
+- ✅ 待审核金额减少
+- ✅ 可提现金额恢复
+
+## 相关文件
+
+- `app/api/withdraw/route.ts` - 提现接口(修改返回消息)
+- `miniprogram/pages/referral/referral.js` - 前端提现逻辑(修改提示)
+
+## 总结
+
+这次优化的核心是**准确传达信息**:
+
+- ❌ 不要给用户虚假期望("已到账"实际未到账)
+- ✅ 明确告知用户当前状态("正在审核")
+- ✅ 告知用户后续流程("通过后会自动到账")
+
+这样可以:
+1. 提升用户体验(不会产生困惑)
+2. 减少客服咨询(用户知道要等待)
+3. 建立信任(说到做到)
diff --git a/开发文档/8、部署/提现按钮状态修复说明.md b/开发文档/8、部署/提现按钮状态修复说明.md
new file mode 100644
index 00000000..35a7ef77
--- /dev/null
+++ b/开发文档/8、部署/提现按钮状态修复说明.md
@@ -0,0 +1,223 @@
+# 提现按钮状态修复说明
+
+## 问题描述
+
+**现象**:
+- 累计佣金:¥8.10
+- 待审核:¥0.00
+- 可提现金额:8.10元
+- 最低提现金额:5元
+- **预期**:按钮应显示"申请提现 ¥8.10"(可用状态)
+- **实际**:按钮显示"满5元可提现"(灰色禁用状态)
+
+## 问题原因
+
+`availableEarnings` 被 `formatMoney()` 格式化为字符串 `"8.10"`,在 WXML 模板中进行数值比较时可能出现类型转换问题。
+
+## 解决方案
+
+### 修改1:增加数字类型字段
+
+在 `referral.js` 的 `data` 中增加 `availableEarningsNum` 字段:
+
+```javascript
+data: {
+ availableEarnings: 0, // 字符串格式用于显示
+ availableEarningsNum: 0, // 数字格式用于判断
+ minWithdrawAmount: 10,
+ // ...
+}
+```
+
+### 修改2:初始化时同时设置两个字段
+
+在 `initData()` 方法中:
+
+```javascript
+// 获取原始数字值(用于判断)
+const availableEarningsNum = realData?.availableEarnings || 0
+
+console.log('[Referral] 收益数据:')
+console.log('[Referral] - totalCommission:', realData?.totalCommission)
+console.log('[Referral] - availableEarnings:', availableEarningsNum)
+console.log('[Referral] - minWithdrawAmount:', realData?.minWithdrawAmount)
+console.log('[Referral] - 按钮应该', availableEarningsNum >= (realData?.minWithdrawAmount || 10) ? '可用' : '禁用')
+
+this.setData({
+ // ...
+ availableEarnings: formatMoney(availableEarningsNum), // 字符串,用于显示
+ availableEarningsNum: availableEarningsNum, // 数字,用于判断
+ minWithdrawAmount: realData?.minWithdrawAmount || 10,
+ // ...
+})
+```
+
+### 修改3:WXML 使用数字字段判断
+
+```xml
+
+ {{availableEarningsNum < minWithdrawAmount ? '满' + minWithdrawAmount + '元可提现' : '申请提现 ¥' + availableEarnings}}
+
+```
+
+**注意**:
+- 类名判断使用 `availableEarningsNum`(数字)
+- 文本显示使用 `availableEarnings`(字符串,格式化后的)
+
+### 修改4:提现逻辑也使用数字字段
+
+```javascript
+async handleWithdraw() {
+ // 使用数字版本直接进行判断,避免重复转换
+ const availableEarnings = this.data.availableEarningsNum || 0
+ const minWithdrawAmount = this.data.minWithdrawAmount || 10
+
+ console.log('[Withdraw] 提现检查:', {
+ availableEarnings,
+ minWithdrawAmount,
+ shouldEnable: availableEarnings >= minWithdrawAmount
+ })
+
+ if (availableEarnings <= 0) {
+ wx.showToast({ title: '暂无可提现收益', icon: 'none' })
+ return
+ }
+
+ if (availableEarnings < minWithdrawAmount) {
+ wx.showToast({
+ title: `满${minWithdrawAmount}元可提现`,
+ icon: 'none'
+ })
+ return
+ }
+ // ...
+}
+```
+
+## 测试步骤
+
+### 1. 清理小程序缓存(重要)
+
+在微信开发者工具中:
+
+1. **清除缓存数据**:
+ - 点击顶部菜单 `工具` → `清除缓存` → `清除全部缓存数据`
+
+2. **重新编译**:
+ - 点击 `编译` 按钮
+ - 或使用快捷键 `Ctrl + B` (Windows) / `Cmd + B` (Mac)
+
+3. **如果还不行,尝试完全重启**:
+ - 关闭微信开发者工具
+ - 重新打开项目
+ - 再次编译
+
+### 2. 查看调试日志
+
+打开控制台(Console),查找以下日志:
+
+```
+[Referral] 收益数据:
+[Referral] - totalCommission: 8.1
+[Referral] - availableEarnings: 8.1
+[Referral] - minWithdrawAmount: 5
+[Referral] - 按钮应该 可用
+```
+
+如果看到"按钮应该 可用",说明逻辑判断正确。
+
+### 3. 点击提现按钮
+
+如果按钮仍然是灰色,点击它,查看是否有日志输出:
+
+```
+[Withdraw] 提现检查: {
+ availableEarnings: 8.1,
+ minWithdrawAmount: 5,
+ shouldEnable: true
+}
+```
+
+### 4. 检查数据值
+
+在小程序调试器的 `AppData` 标签页中查找 `referral` 页面的数据:
+
+```json
+{
+ "availableEarnings": "8.10", // 字符串
+ "availableEarningsNum": 8.1, // 数字
+ "minWithdrawAmount": 5
+}
+```
+
+确认 `availableEarningsNum` 是数字类型,不是字符串。
+
+## 预期结果
+
+修复后,当 `availableEarningsNum` (8.1) >= `minWithdrawAmount` (5) 时:
+
+- ✅ 按钮显示:`申请提现 ¥8.10`
+- ✅ 按钮样式:渐变青色背景(可点击)
+- ✅ 点击后弹出提现确认对话框
+
+## 常见问题
+
+### Q1: 修改后按钮还是灰色?
+**A**: 清除小程序缓存并重新编译:
+```
+工具 → 清除缓存 → 清除全部缓存数据
+然后点击 编译 按钮
+```
+
+### Q2: 控制台没有看到调试日志?
+**A**:
+1. 确保控制台的日志级别包含 `log`
+2. 检查是否过滤了某些日志
+3. 尝试刷新页面(下拉刷新或重新进入)
+
+### Q3: `availableEarningsNum` 是 undefined?
+**A**: 检查后端 API 返回的数据格式,确保 `realData.availableEarnings` 有值:
+```javascript
+console.log('API返回:', realData)
+```
+
+### Q4: 数据正确但按钮还是不可点击?
+**A**: 检查 WXSS 中是否有其他样式覆盖:
+```css
+.withdraw-btn.btn-disabled {
+ pointer-events: none; /* 可能导致无法点击 */
+}
+```
+
+## 相关文件
+
+- `miniprogram/pages/referral/referral.js` - 主要逻辑
+- `miniprogram/pages/referral/referral.wxml` - 模板
+- `miniprogram/pages/referral/referral.wxss` - 样式
+- `app/api/referral/data/route.ts` - 后端API
+
+## 验证清单
+
+- [ ] 后端API返回正确的 `availableEarnings` 数值
+- [ ] `initData()` 中正确设置 `availableEarningsNum`
+- [ ] WXML 使用 `availableEarningsNum` 进行条件判断
+- [ ] 清除小程序缓存并重新编译
+- [ ] 控制台显示正确的调试日志
+- [ ] 按钮显示正确文本和样式
+- [ ] 点击按钮可以正常提现
+
+## 技术总结
+
+**核心问题**:字符串类型的数字在某些场景下的比较可能不符合预期。
+
+**解决思路**:
+1. 保存两份数据:字符串用于显示,数字用于判断
+2. 在数据初始化时就区分好类型
+3. 在需要比较的地方使用数字类型
+4. 添加详细的调试日志便于排查问题
+
+**最佳实践**:
+- ✅ 数值计算和比较始终使用 Number 类型
+- ✅ 格式化显示使用 String 类型
+- ✅ 在 setData 时明确类型转换
+- ✅ 避免在模板中进行复杂的类型转换
diff --git a/开发文档/8、部署/提现按钮逻辑修正.md b/开发文档/8、部署/提现按钮逻辑修正.md
new file mode 100644
index 00000000..f3fe2743
--- /dev/null
+++ b/开发文档/8、部署/提现按钮逻辑修正.md
@@ -0,0 +1,263 @@
+# 提现按钮逻辑修正
+
+## 问题描述
+
+**错误理解**:
+- 错误地直接使用后端返回的 `availableEarnings` 进行判断
+
+**正确逻辑**:
+- ✅ **可提现金额 = 累计佣金 - 待审核金额**
+- ✅ **按钮启用条件:可提现金额 >= 最低提现金额**
+
+## 具体案例
+
+当前数据:
+- 累计佣金:¥8.10
+- 待审核金额:¥0.00
+- **计算:可提现金额 = 8.10 - 0 = 8.10元**
+- 最低提现金额:¥5.00
+- **判断:8.10 >= 5.00 = true** → 按钮应该启用(绿色)
+
+## 修复方案
+
+### 1. 前端计算可提现金额
+
+在 `miniprogram/pages/referral/referral.js` 的 `initData()` 方法中:
+
+```javascript
+// ✅ 修正:可提现金额 = 累计佣金 - 待审核金额
+const totalCommissionNum = realData?.totalCommission || 0
+const pendingWithdrawNum = realData?.pendingWithdrawAmount || 0
+const availableEarningsNum = totalCommissionNum - pendingWithdrawNum
+const minWithdrawAmount = realData?.minWithdrawAmount || 10
+
+console.log('=== [Referral] 收益计算(修正后)===')
+console.log('累计佣金:', totalCommissionNum)
+console.log('待审核金额:', pendingWithdrawNum)
+console.log('可提现金额 = 累计佣金 - 待审核金额 =', totalCommissionNum, '-', pendingWithdrawNum, '=', availableEarningsNum)
+console.log('最低提现金额:', minWithdrawAmount)
+console.log('按钮判断:', availableEarningsNum, '>=', minWithdrawAmount, '=', availableEarningsNum >= minWithdrawAmount)
+console.log('✅ 按钮应该:', availableEarningsNum >= minWithdrawAmount ? '🟢 启用(绿色)' : '⚫ 禁用(灰色)')
+```
+
+### 2. 设置数据
+
+```javascript
+this.setData({
+ // 收益数据 - 格式化为两位小数
+ totalCommission: formatMoney(totalCommissionNum),
+ availableEarnings: formatMoney(availableEarningsNum), // ✅ 使用计算后的可提现金额
+ availableEarningsNum: availableEarningsNum, // ✅ 数字格式用于按钮判断
+ pendingWithdrawAmount: formatMoney(pendingWithdrawNum),
+ minWithdrawAmount: minWithdrawAmount,
+ // ...
+})
+```
+
+### 3. 按钮判断逻辑(WXML)
+
+```xml
+
+ {{availableEarningsNum < minWithdrawAmount ? '满' + minWithdrawAmount + '元可提现' : '申请提现 ¥' + availableEarnings}}
+
+```
+
+**注意**:
+- 类名判断:`availableEarningsNum < minWithdrawAmount`(数字比较)
+- 文本显示:使用格式化后的 `availableEarnings` 字符串
+
+### 4. 提现函数中的验证
+
+```javascript
+async handleWithdraw() {
+ // 使用数字版本直接进行判断
+ const availableEarnings = this.data.availableEarningsNum || 0
+ const minWithdrawAmount = this.data.minWithdrawAmount || 10
+
+ console.log('[Withdraw] 提现检查:', {
+ availableEarnings,
+ minWithdrawAmount,
+ shouldEnable: availableEarnings >= minWithdrawAmount
+ })
+
+ if (availableEarnings <= 0) {
+ wx.showToast({ title: '暂无可提现收益', icon: 'none' })
+ return
+ }
+
+ if (availableEarnings < minWithdrawAmount) {
+ wx.showToast({
+ title: `满${minWithdrawAmount}元可提现`,
+ icon: 'none'
+ })
+ return
+ }
+
+ // ... 继续提现逻辑
+}
+```
+
+## 测试步骤
+
+### 1. 完全清除缓存
+
+在微信开发者工具中:
+```
+1. 关闭微信开发者工具
+2. 重新打开项目
+3. 工具 → 清除缓存 → 清除全部缓存数据
+4. 点击"编译"按钮
+```
+
+### 2. 查看控制台日志
+
+应该看到类似这样的输出:
+
+```
+=== [Referral] 收益计算(修正后)===
+累计佣金: 8.1
+待审核金额: 0
+可提现金额 = 累计佣金 - 待审核金额 = 8.1 - 0 = 8.1
+最低提现金额: 5
+按钮判断: 8.1 >= 5 = true
+✅ 按钮应该: 🟢 启用(绿色)
+
+=== [Referral] 按钮状态验证 ===
+累计佣金 (totalCommission): 8.10
+待审核金额 (pendingWithdrawAmount): 0.00
+可提现金额 (availableEarnings 显示): 8.10
+可提现金额 (availableEarningsNum 判断): 8.1 number
+最低提现金额 (minWithdrawAmount): 5 number
+按钮启用条件: 8.1 >= 5 = true
+✅ 最终结果: 按钮应该 🟢 启用
+```
+
+### 3. 验证界面
+
+- ✅ 按钮文本:`申请提现 ¥8.10`
+- ✅ 按钮样式:渐变青色背景(不是灰色)
+- ✅ 可以点击
+
+## 逻辑公式总结
+
+### 核心计算
+
+```
+可提现金额 = 累计佣金 - 待审核金额
+```
+
+### 按钮状态
+
+```
+if (可提现金额 >= 最低提现金额) {
+ // ✅ 启用按钮(绿色)
+ 显示文本: "申请提现 ¥{可提现金额}"
+} else {
+ // ❌ 禁用按钮(灰色)
+ 显示文本: "满{最低提现金额}元可提现"
+}
+```
+
+### 数据关系
+
+```
+totalCommission (累计佣金)
+ ├─ 所有已完成订单的佣金总和
+ └─ 显示在顶部"累计佣金"位置
+
+pendingWithdrawAmount (待审核金额)
+ ├─ 已申请提现但未审核通过的金额总和
+ └─ 显示在"待审核"位置
+
+availableEarnings (可提现金额)
+ ├─ = totalCommission - pendingWithdrawAmount
+ ├─ 用户实际可以申请提现的金额
+ └─ 显示在提现按钮上
+
+minWithdrawAmount (最低提现金额)
+ ├─ 从管理后台配置获取
+ ├─ 默认值:10元
+ └─ 用于判断是否允许提现
+```
+
+## 为什么要在前端计算?
+
+### 优势
+
+1. **实时准确**:
+ - 每次进入页面都基于最新的累计佣金和待审核金额计算
+ - 避免后端缓存导致的数据延迟
+
+2. **逻辑清晰**:
+ - 公式简单明了:`累计佣金 - 待审核金额`
+ - 便于调试和验证
+
+3. **减轻后端负担**:
+ - 简单的减法运算在前端完成
+ - 后端只需返回原始数据
+
+### 数据流
+
+```
+后端API返回:
+{
+ totalCommission: 8.1, // 累计佣金
+ pendingWithdrawAmount: 0, // 待审核金额
+ minWithdrawAmount: 5 // 最低提现金额
+}
+
+前端计算:
+availableEarningsNum = 8.1 - 0 = 8.1 // 可提现金额
+
+前端判断:
+8.1 >= 5 ? 启用按钮 : 禁用按钮
+```
+
+## 相关文件
+
+- `miniprogram/pages/referral/referral.js` - 计算逻辑
+- `miniprogram/pages/referral/referral.wxml` - 按钮显示
+- `miniprogram/pages/referral/referral.wxss` - 按钮样式
+
+## 常见问题
+
+### Q1: 为什么要保存两个字段?
+
+**A**:
+- `availableEarnings` (字符串):用于界面显示,格式化为 "8.10"
+- `availableEarningsNum` (数字):用于条件判断,精确比较 `8.1 >= 5`
+
+### Q2: 后端的 availableEarnings 还有用吗?
+
+**A**: 如果后端返回了 `availableEarnings`,现在会被前端计算的值覆盖。建议:
+- 方案1:后端不再返回 `availableEarnings`,只返回 `totalCommission` 和 `pendingWithdrawAmount`
+- 方案2:保留后端计算,但前端不使用(当前方案)
+
+### Q3: 如果待审核金额大于累计佣金怎么办?
+
+**A**: 理论上不应该出现这种情况,但可以添加保护:
+```javascript
+const availableEarningsNum = Math.max(0, totalCommissionNum - pendingWithdrawNum)
+```
+
+## 验证清单
+
+- [x] 修改前端计算逻辑:`可提现金额 = 累计佣金 - 待审核金额`
+- [x] 添加详细调试日志
+- [x] 确保使用数字类型进行比较
+- [x] 清除小程序缓存
+- [x] 重新编译
+- [ ] 查看控制台日志验证计算
+- [ ] 确认按钮显示正确文本和样式
+- [ ] 测试点击提现功能
+
+## 总结
+
+这次修正的核心是**理解业务逻辑**:
+
+1. **累计佣金** = 所有获得的佣金(历史总和)
+2. **待审核金额** = 已申请但未到账的金额
+3. **可提现金额** = 累计佣金 - 待审核金额 = 当前可以申请提现的金额
+4. **按钮启用** = 可提现金额 >= 最低提现金额
+
+之前的错误是直接使用后端返回的值,没有理解这个减法关系。现在在前端明确计算,确保逻辑正确。
diff --git a/开发文档/8、部署/提现接口逻辑修正.md b/开发文档/8、部署/提现接口逻辑修正.md
new file mode 100644
index 00000000..bf850617
--- /dev/null
+++ b/开发文档/8、部署/提现接口逻辑修正.md
@@ -0,0 +1,348 @@
+# 提现接口逻辑修正
+
+## 问题描述
+
+**错误提示**:
+```
+POST /api/withdraw
+Response: {
+ success: false,
+ message: "可提现金额不足,当前可提现 ¥0.00"
+}
+```
+
+**问题原因**:
+后端提现接口的佣金计算逻辑与前端不一致,导致计算出的可提现金额为0。
+
+## 问题分析
+
+### 旧逻辑(错误)
+
+```typescript
+// ❌ 从 referral_bindings 表查询
+const earningsResult = await query(`
+ SELECT COALESCE(SUM(commission), 0) as total_commission
+ FROM referral_bindings
+ WHERE referrer_id = ? AND status = 'converted'
+`, [userId])
+
+totalEarnings = parseFloat(earningsResult[0]?.total_commission || 0)
+
+// 计算可提现金额
+const availableAmount = totalEarnings - withdrawnAmount
+```
+
+**问题**:
+1. 从 `referral_bindings.commission` 字段查询,但该字段可能未维护或不准确
+2. 与前端/分销中心API的计算逻辑不一致
+3. 导致后端计算的可提现金额为0
+
+### 正确逻辑
+
+应该与前端和 `/api/referral/data` 保持一致:
+
+```
+累计佣金 = SUM(orders.amount WHERE referrer_id = userId AND status = 'paid') × distributorShare
+可提现金额 = 累计佣金 - 待审核提现金额
+```
+
+## 修复方案
+
+### 1. 修改累计佣金计算
+
+**文件**:`app/api/withdraw/route.ts`
+
+```typescript
+// ✅ 修正:从 orders 表查询累计佣金(与前端逻辑一致)
+let totalCommission = 0
+try {
+ // 读取分成比例
+ let distributorShare = 0.9 // 默认90%
+ try {
+ const config = await getConfig('referral_config')
+ if (config?.distributorShare) {
+ distributorShare = Number(config.distributorShare)
+ }
+ } catch (e) {
+ console.warn('[Withdraw] 读取分成比例失败,使用默认值 90%')
+ }
+
+ // 查询订单总金额
+ const ordersResult = await query(`
+ SELECT COALESCE(SUM(amount), 0) as total_amount
+ FROM orders
+ WHERE referrer_id = ? AND status = 'paid'
+ `, [userId]) as any[]
+
+ const totalAmount = parseFloat(ordersResult[0]?.total_amount || 0)
+ totalCommission = totalAmount * distributorShare
+
+ console.log('[Withdraw] 佣金计算:')
+ console.log('- 订单总金额:', totalAmount)
+ console.log('- 分成比例:', distributorShare * 100 + '%')
+ console.log('- 累计佣金:', totalCommission)
+} catch (e) {
+ console.log('[Withdraw] 查询收益失败:', e)
+}
+```
+
+### 2. 修改可提现金额计算
+
+```typescript
+// 查询待审核提现金额
+let pendingWithdrawAmount = 0
+try {
+ const pendingResult = await query(`
+ SELECT COALESCE(SUM(amount), 0) as pending_amount
+ FROM withdrawals
+ WHERE user_id = ? AND status = 'pending'
+ `, [userId]) as any[]
+ pendingWithdrawAmount = parseFloat(pendingResult[0]?.pending_amount || 0)
+} catch (e) {
+ console.log('[Withdraw] 查询待审核金额失败:', e)
+}
+
+// ✅ 修正:可提现金额 = 累计佣金 - 待审核金额(与前端逻辑一致)
+const availableAmount = totalCommission - pendingWithdrawAmount
+
+console.log('[Withdraw] 提现验证:')
+console.log('- 累计佣金 (totalCommission):', totalCommission)
+console.log('- 待审核金额 (pendingWithdrawAmount):', pendingWithdrawAmount)
+console.log('- 可提现金额 (availableAmount):', availableAmount)
+console.log('- 申请提现金额 (amount):', amount)
+console.log('- 判断:', amount, '>', availableAmount, '=', amount > availableAmount)
+
+if (amount > availableAmount) {
+ return NextResponse.json({
+ success: false,
+ message: `可提现金额不足,当前可提现 ¥${availableAmount.toFixed(2)},待审核 ¥${pendingWithdrawAmount.toFixed(2)}`
+ })
+}
+```
+
+## 修改对比
+
+### 数据来源
+
+| 项目 | 旧逻辑 | 新逻辑 |
+|------|--------|--------|
+| 累计佣金 | `referral_bindings.commission` | `orders.amount × distributorShare` |
+| 已提现 | `withdrawals.status = 'completed'` | **改为待审核** |
+| 待审核 | ❌ 未查询 | `withdrawals.status = 'pending'` |
+| 可提现 | `累计佣金 - 已提现` | `累计佣金 - 待审核` |
+
+### 计算公式
+
+**旧逻辑**:
+```
+累计佣金 = SUM(referral_bindings.commission WHERE status = 'converted')
+已提现金额 = SUM(withdrawals.amount WHERE status = 'completed')
+可提现金额 = 累计佣金 - 已提现金额 ❌ 错误
+```
+
+**新逻辑**:
+```
+订单总金额 = SUM(orders.amount WHERE referrer_id = userId AND status = 'paid')
+累计佣金 = 订单总金额 × distributorShare (90%)
+待审核金额 = SUM(withdrawals.amount WHERE status = 'pending')
+可提现金额 = 累计佣金 - 待审核金额 ✅ 正确
+```
+
+## 一致性验证
+
+现在三个地方的逻辑完全一致:
+
+### 1. 前端小程序 (`referral.js`)
+
+```javascript
+const totalCommissionNum = realData?.totalCommission || 0
+const pendingWithdrawNum = realData?.pendingWithdrawAmount || 0
+const availableEarningsNum = totalCommissionNum - pendingWithdrawNum
+```
+
+### 2. 分销数据API (`/api/referral/data`)
+
+```typescript
+// 计算累计佣金
+const totalAmount = SUM(orders.amount WHERE referrer_id = userId AND status = 'paid')
+const totalCommission = totalAmount * distributorShare
+
+// 查询待审核金额
+const pendingWithdrawAmount = SUM(withdrawals.amount WHERE user_id = userId AND status = 'pending')
+
+// 返回给前端
+return {
+ totalCommission,
+ pendingWithdrawAmount,
+ availableEarnings: totalCommission - pendingWithdrawAmount
+}
+```
+
+### 3. 提现API (`/api/withdraw`)
+
+```typescript
+// 计算累计佣金
+const totalAmount = SUM(orders.amount WHERE referrer_id = userId AND status = 'paid')
+const totalCommission = totalAmount * distributorShare
+
+// 查询待审核金额
+const pendingWithdrawAmount = SUM(withdrawals.amount WHERE user_id = userId AND status = 'pending')
+
+// 验证可提现金额
+const availableAmount = totalCommission - pendingWithdrawAmount
+if (amount > availableAmount) {
+ return error("可提现金额不足")
+}
+```
+
+## 测试步骤
+
+### 1. 查看后端日志
+
+提现时应该看到详细日志:
+
+```
+[Withdraw] 佣金计算:
+- 订单总金额: 9
+- 分成比例: 90%
+- 累计佣金: 8.1
+
+[Withdraw] 提现验证:
+- 累计佣金 (totalCommission): 8.1
+- 待审核金额 (pendingWithdrawAmount): 0
+- 可提现金额 (availableAmount): 8.1
+- 申请提现金额 (amount): 8.1
+- 判断: 8.1 > 8.1 = false
+```
+
+### 2. 测试提现
+
+```bash
+# 测试提现API
+curl -X POST http://localhost:3006/api/withdraw \
+ -H "Content-Type: application/json" \
+ -d '{
+ "userId": "ogpTW5fmXRGNpoUbXB3UEqnVe5Tg",
+ "amount": 8.1
+ }'
+```
+
+**预期结果**:
+```json
+{
+ "success": true,
+ "message": "提现成功",
+ "data": {
+ "withdrawId": "W1738694028123",
+ "amount": 8.1,
+ "account": "...",
+ "accountType": "微信"
+ }
+}
+```
+
+### 3. 验证数据库
+
+```sql
+-- 查看待审核提现记录
+SELECT * FROM withdrawals WHERE user_id = 'ogpTW5fmXRGNpoUbXB3UEqnVe5Tg' AND status = 'pending';
+
+-- 查看订单总金额
+SELECT SUM(amount) as total_amount
+FROM orders
+WHERE referrer_id = 'ogpTW5fmXRGNpoUbXB3UEqnVe5Tg' AND status = 'paid';
+```
+
+## 常见问题
+
+### Q1: 为什么改成"待审核"而不是"已提现"?
+
+**A**: 因为提现流程是:
+1. 用户申请提现 → 状态 `pending`(待审核)
+2. 管理员审核通过 → 状态改为 `completed`(已完成)
+
+在用户申请提现后,这笔金额应该从"可提现"中扣除,所以要减去 `status = 'pending'` 的金额。
+
+### Q2: 如果有多笔待审核提现会怎样?
+
+**A**:
+```
+累计佣金: 100元
+待审核: 30元 + 20元 = 50元
+可提现: 100 - 50 = 50元
+```
+
+用户只能再申请最多50元的提现。
+
+### Q3: 审核通过后会发生什么?
+
+**A**:
+```sql
+-- 管理员审核通过
+UPDATE withdrawals SET status = 'completed' WHERE id = 'W123';
+```
+
+这笔金额从"待审核"变为"已完成",下次计算时:
+```
+待审核金额减少 → 可提现金额增加(如果有新订单)
+```
+
+### Q4: referral_bindings 表还有用吗?
+
+**A**: 有用,但不再用于佣金计算:
+- 记录绑定关系
+- 记录绑定状态(active/expired)
+- 记录购买次数
+- 但佣金数据以 `orders` 表为准
+
+## 部署说明
+
+### 1. 重启服务
+
+修改后需要重启 Next.js 服务:
+
+```bash
+# 使用部署脚本重启
+python devlop.py restart mycontent
+
+# 或手动重启
+pm2 restart mycontent
+```
+
+### 2. 查看日志
+
+```bash
+# 查看实时日志
+pm2 logs mycontent
+
+# 查看最近的日志
+pm2 logs mycontent --lines 100
+```
+
+### 3. 监控错误
+
+关注以下日志:
+- `[Withdraw] 佣金计算:` - 佣金计算是否正确
+- `[Withdraw] 提现验证:` - 可提现金额是否准确
+- `[Withdraw] 查询收益失败:` - 是否有表不存在等错误
+
+## 相关文件
+
+- `app/api/withdraw/route.ts` - 提现接口(本次修改)
+- `app/api/referral/data/route.ts` - 分销数据接口(已统一)
+- `miniprogram/pages/referral/referral.js` - 前端逻辑(已统一)
+
+## 总结
+
+这次修复确保了**三端逻辑完全一致**:
+
+1. **前端小程序**:显示的可提现金额
+2. **分销数据API**:返回的数据
+3. **提现接口**:验证的金额
+
+都使用相同的计算方式:
+```
+可提现金额 = (订单总金额 × 分成比例) - 待审核提现金额
+```
+
+这样可以避免前端显示可以提现,但后端验证失败的问题。