382 lines
9.4 KiB
Markdown
382 lines
9.4 KiB
Markdown
|
|
# 新分销逻辑 - 代码修改总结
|
|||
|
|
|
|||
|
|
## ✅ 已完成的代码修改
|
|||
|
|
|
|||
|
|
### 1. 数据库层(Database Layer)
|
|||
|
|
|
|||
|
|
#### 迁移脚本
|
|||
|
|
- ✅ `scripts/migration-add-binding-fields.sql`(SQL版本)
|
|||
|
|
- ✅ `scripts/migrate_binding_fields.py`(Python完整版)
|
|||
|
|
- ✅ `scripts/migrate_db_simple.py`(Python简化版)- **已执行成功**
|
|||
|
|
|
|||
|
|
#### 新增字段
|
|||
|
|
```sql
|
|||
|
|
referral_bindings 表:
|
|||
|
|
✅ last_purchase_date DATETIME - 最后购买时间
|
|||
|
|
✅ purchase_count INT - 购买次数
|
|||
|
|
✅ total_commission DECIMAL(10,2) - 累计佣金
|
|||
|
|
✅ status 新增枚举值 'cancelled' - 被切换状态
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 新增索引
|
|||
|
|
```sql
|
|||
|
|
✅ idx_referee_status (referee_id, status)
|
|||
|
|
✅ idx_expiry_purchase (expiry_date, purchase_count, status)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 2. 核心业务逻辑(Business Logic)
|
|||
|
|
|
|||
|
|
#### 2.1 绑定API:`app/api/referral/bind/route.ts`
|
|||
|
|
|
|||
|
|
**修改前**:
|
|||
|
|
```typescript
|
|||
|
|
// ❌ 有效期内不能切换
|
|||
|
|
if (expiryDate < now) {
|
|||
|
|
// 已过期才能抢夺
|
|||
|
|
} else {
|
|||
|
|
return { error: '绑定有效期内无法更换' }
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**修改后**:
|
|||
|
|
```typescript
|
|||
|
|
// ✅ 立即切换(无条件)
|
|||
|
|
if (existing.referrer_id === referrer.id) {
|
|||
|
|
action = 'renew' // 同一推荐人:续期
|
|||
|
|
} else {
|
|||
|
|
action = 'switch' // 不同推荐人:立即切换
|
|||
|
|
|
|||
|
|
// 旧绑定标记为 cancelled
|
|||
|
|
await query("UPDATE referral_bindings SET status = 'cancelled' WHERE id = ?", [existing.id])
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**核心变化**:
|
|||
|
|
- ✅ 删除"有效期内不能切换"限制
|
|||
|
|
- ✅ 点击新链接立即切换推荐人
|
|||
|
|
- ✅ 旧绑定标记为 `cancelled`(不是 `expired`)
|
|||
|
|
- ✅ 新绑定重新计算30天
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### 2.2 支付回调:`app/api/miniprogram/pay/notify/route.ts`
|
|||
|
|
|
|||
|
|
**修改前**:
|
|||
|
|
```typescript
|
|||
|
|
// ❌ 购买后标记为 converted,不再累加
|
|||
|
|
await query(`
|
|||
|
|
UPDATE referral_bindings
|
|||
|
|
SET status = 'converted',
|
|||
|
|
commission_amount = ?
|
|||
|
|
WHERE id = ?
|
|||
|
|
`, [commission, binding.id])
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**修改后**:
|
|||
|
|
```typescript
|
|||
|
|
// ✅ 保持 active,累加购买次数和佣金
|
|||
|
|
await query(`
|
|||
|
|
UPDATE referral_bindings
|
|||
|
|
SET last_purchase_date = CURRENT_TIMESTAMP,
|
|||
|
|
purchase_count = purchase_count + 1,
|
|||
|
|
total_commission = total_commission + ?
|
|||
|
|
WHERE id = ?
|
|||
|
|
`, [commission, binding.id])
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**核心变化**:
|
|||
|
|
- ✅ 不再改变 `status`(保持 `active`)
|
|||
|
|
- ✅ 累加 `purchase_count`
|
|||
|
|
- ✅ 累加 `total_commission`
|
|||
|
|
- ✅ 记录 `last_purchase_date`
|
|||
|
|
- ✅ 支持同一绑定多次购买分佣
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### 2.3 支付订单:`app/api/miniprogram/pay/route.ts`
|
|||
|
|
|
|||
|
|
**新增功能**:好友优惠折扣
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
// ✅ 读取好友优惠配置
|
|||
|
|
const referralConfig = await getConfig('referral_config')
|
|||
|
|
const userDiscount = referralConfig?.userDiscount || 0
|
|||
|
|
|
|||
|
|
// ✅ 如果有推荐码,应用折扣
|
|||
|
|
if (userDiscount > 0 && body.referralCode) {
|
|||
|
|
const discountRate = userDiscount / 100
|
|||
|
|
finalAmount = amount * (1 - discountRate)
|
|||
|
|
// 原价 1.00 → 优惠 5% → 实付 0.95
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**核心变化**:
|
|||
|
|
- ✅ 通过推荐链接购买会自动打折
|
|||
|
|
- ✅ 折扣比例从后台配置读取
|
|||
|
|
- ✅ 佣金基于实付金额计算
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### 2.4 提现API:`app/api/withdraw/route.ts`
|
|||
|
|
|
|||
|
|
**新增功能**:读取最低提现门槛
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
// ✅ 从配置读取最低提现门槛
|
|||
|
|
const config = await getConfig('referral_config')
|
|||
|
|
const minWithdrawAmount = config?.minWithdrawAmount || 10
|
|||
|
|
|
|||
|
|
// ✅ 检查最低门槛
|
|||
|
|
if (amount < minWithdrawAmount) {
|
|||
|
|
return { error: `最低提现金额为 ¥${minWithdrawAmount}` }
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**核心变化**:
|
|||
|
|
- ✅ 提现门槛可通过后台配置
|
|||
|
|
- ✅ 替代了硬编码的 10 元
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 3. 管理后台(Admin Panel)
|
|||
|
|
|
|||
|
|
#### 3.1 推广设置页面:`app/admin/referral-settings/page.tsx`
|
|||
|
|
|
|||
|
|
**新增功能**:
|
|||
|
|
- ✅ 配置好友优惠(userDiscount)
|
|||
|
|
- ✅ 配置推广者分成(distributorShare)
|
|||
|
|
- ✅ 配置绑定有效期(bindingDays)
|
|||
|
|
- ✅ 配置最低提现金额(minWithdrawAmount)
|
|||
|
|
- ✅ 配置自动提现开关(enableAutoWithdraw)
|
|||
|
|
|
|||
|
|
**数据安全**:
|
|||
|
|
```typescript
|
|||
|
|
// ✅ 保存时强制类型转换
|
|||
|
|
const safeConfig = {
|
|||
|
|
distributorShare: Number(config.distributorShare) || 0,
|
|||
|
|
minWithdrawAmount: Number(config.minWithdrawAmount) || 0,
|
|||
|
|
bindingDays: Number(config.bindingDays) || 0,
|
|||
|
|
userDiscount: Number(config.userDiscount) || 0,
|
|||
|
|
enableAutoWithdraw: Boolean(config.enableAutoWithdraw),
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### 3.2 菜单入口:`app/admin/layout.tsx`
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
// ✅ 新增菜单项
|
|||
|
|
{ icon: CreditCard, label: "推广设置", href: "/admin/referral-settings" }
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 4. 小程序(MiniProgram)
|
|||
|
|
|
|||
|
|
#### 4.1 分销中心UI:`miniprogram/pages/referral/referral.wxml`
|
|||
|
|
|
|||
|
|
**修改**:
|
|||
|
|
```xml
|
|||
|
|
<!-- ✅ 删除"我的邀请码"卡片 -->
|
|||
|
|
<!-- 保留分享按钮和收益明细 -->
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 5. 定时任务(Scheduled Task)
|
|||
|
|
|
|||
|
|
#### 自动解绑脚本
|
|||
|
|
|
|||
|
|
- ✅ `scripts/auto-unbind-expired.js`(标准版)
|
|||
|
|
- ✅ `scripts/auto-unbind-expired-simple.js`(简化版,直接连MySQL)
|
|||
|
|
|
|||
|
|
**解绑条件**:
|
|||
|
|
```javascript
|
|||
|
|
WHERE status = 'active'
|
|||
|
|
AND expiry_date < NOW()
|
|||
|
|
AND purchase_count = 0
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**执行逻辑**:
|
|||
|
|
1. 查询符合条件的绑定
|
|||
|
|
2. 标记为 `expired`
|
|||
|
|
3. 更新推荐人的 `referral_count`
|
|||
|
|
4. 输出日志
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 📋 完整的业务流程
|
|||
|
|
|
|||
|
|
### 场景1:新用户绑定
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
用户操作:B 点击 A 的分享链接
|
|||
|
|
触发API:/api/referral/bind
|
|||
|
|
数据变化:
|
|||
|
|
- referral_bindings 新增记录
|
|||
|
|
- referee_id: B
|
|||
|
|
- referrer_id: A
|
|||
|
|
- status: active
|
|||
|
|
- expiry_date: NOW + 30天
|
|||
|
|
- purchase_count: 0
|
|||
|
|
- users.referred_by: A
|
|||
|
|
- users.referral_count (A): +1
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 场景2:切换推荐人
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
用户操作:B 点击 C 的分享链接
|
|||
|
|
触发API:/api/referral/bind
|
|||
|
|
数据变化:
|
|||
|
|
- 旧绑定 (A -> B):
|
|||
|
|
- status: active → cancelled
|
|||
|
|
- 新绑定 (C -> B):
|
|||
|
|
- 新增记录
|
|||
|
|
- status: active
|
|||
|
|
- expiry_date: NOW + 30天
|
|||
|
|
- users.referred_by: A → C
|
|||
|
|
- users.referral_count (A): -1
|
|||
|
|
- users.referral_count (C): +1
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 场景3:购买分佣
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
用户操作:B 购买文章(1元,假设无优惠)
|
|||
|
|
触发API:/api/miniprogram/pay/notify
|
|||
|
|
数据变化:
|
|||
|
|
- referral_bindings (C -> B):
|
|||
|
|
- purchase_count: 0 → 1
|
|||
|
|
- total_commission: 0 → 0.90
|
|||
|
|
- last_purchase_date: NOW
|
|||
|
|
- status: 保持 active
|
|||
|
|
- users.pending_earnings (C): +0.90
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 场景4:好友优惠购买
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
用户操作:B 通过推荐链接购买(原价1元,优惠5%)
|
|||
|
|
触发API:/api/miniprogram/pay
|
|||
|
|
计算逻辑:
|
|||
|
|
- 原价: 1.00元
|
|||
|
|
- 优惠: 1.00 × 5% = 0.05元
|
|||
|
|
- 实付: 0.95元
|
|||
|
|
|
|||
|
|
后续分佣:
|
|||
|
|
- 佣金 = 0.95 × 90% = 0.855元
|
|||
|
|
- C 获得 0.86元(四舍五入)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 场景5:自动解绑
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
触发:定时任务(每天02:00)
|
|||
|
|
执行脚本:scripts/auto-unbind-expired-simple.js
|
|||
|
|
筛选条件:
|
|||
|
|
- status = 'active'
|
|||
|
|
- expiry_date < NOW
|
|||
|
|
- purchase_count = 0
|
|||
|
|
|
|||
|
|
数据变化:
|
|||
|
|
- referral_bindings: status → expired
|
|||
|
|
- users.referral_count: -1(对应的推荐人)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🎯 核心逻辑总结
|
|||
|
|
|
|||
|
|
| 功能 | 实现状态 | 说明 |
|
|||
|
|
|------|---------|------|
|
|||
|
|
| **立即切换绑定** | ✅ 完成 | 点击新链接立即切换推荐人 |
|
|||
|
|
| **佣金归属** | ✅ 完成 | 给购买时的当前推荐人 |
|
|||
|
|
| **购买累加** | ✅ 完成 | 同一绑定可多次购买分佣 |
|
|||
|
|
| **好友优惠** | ✅ 完成 | 通过推荐链接自动打折 |
|
|||
|
|
| **提现门槛** | ✅ 完成 | 后台可配置最低金额 |
|
|||
|
|
| **自动解绑** | ✅ 完成 | 30天无购买自动解绑 |
|
|||
|
|
| **推广设置页** | ✅ 完成 | 管理后台统一配置入口 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 📦 已部署文件清单
|
|||
|
|
|
|||
|
|
### 后端API(7个文件)
|
|||
|
|
1. ✅ `app/api/referral/bind/route.ts` - 立即切换绑定
|
|||
|
|
2. ✅ `app/api/miniprogram/pay/notify/route.ts` - 累加分佣
|
|||
|
|
3. ✅ `app/api/miniprogram/pay/route.ts` - 好友优惠
|
|||
|
|
4. ✅ `app/api/withdraw/route.ts` - 提现门槛
|
|||
|
|
5. ✅ `app/admin/referral-settings/page.tsx` - 推广设置页
|
|||
|
|
6. ✅ `app/admin/layout.tsx` - 菜单入口
|
|||
|
|
|
|||
|
|
### 小程序(1个文件)
|
|||
|
|
7. ✅ `miniprogram/pages/referral/referral.wxml` - 去掉邀请码卡片
|
|||
|
|
|
|||
|
|
### 脚本(5个文件)
|
|||
|
|
8. ✅ `scripts/migrate_db_simple.py` - 数据库迁移
|
|||
|
|
9. ✅ `scripts/auto-unbind-expired-simple.js` - 定时任务
|
|||
|
|
10. ✅ `scripts/test-referral-flow.js` - 功能测试
|
|||
|
|
|
|||
|
|
### 文档(3个文件)
|
|||
|
|
11. ✅ `开发文档/8、部署/新分销逻辑设计方案.md`
|
|||
|
|
12. ✅ `开发文档/8、部署/新分销逻辑-部署步骤.md`
|
|||
|
|
13. ✅ `开发文档/8、部署/新分销逻辑-宝塔操作清单.md`
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🔄 部署状态
|
|||
|
|
|
|||
|
|
- ✅ 数据库字段已添加
|
|||
|
|
- ✅ 代码已构建(pnpm build)
|
|||
|
|
- ✅ 代码已上传服务器(python devlop.py)
|
|||
|
|
- ⏳ **待操作:宝塔面板重启服务**
|
|||
|
|
- ⏳ **待操作:宝塔面板配置定时任务**
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🚦 下一步操作
|
|||
|
|
|
|||
|
|
### 必须完成(服务才能生效)
|
|||
|
|
|
|||
|
|
1. **重启 Node.js 服务**
|
|||
|
|
- 宝塔面板 → 网站 → soul.quwanzhi.com → Node项目 → 重启
|
|||
|
|
- 或SSH执行:`/www/server/nodejs/v16.20.2/bin/pm2 restart soul`
|
|||
|
|
|
|||
|
|
2. **配置定时任务**
|
|||
|
|
- 宝塔面板 → 计划任务 → 添加Shell脚本
|
|||
|
|
- 执行周期:每天 02:00
|
|||
|
|
- 脚本内容:
|
|||
|
|
```bash
|
|||
|
|
cd /www/wwwroot/soul/dist && /www/server/nodejs/v16.20.2/bin/node scripts/auto-unbind-expired-simple.js >> /www/wwwroot/soul/logs/auto-unbind.log 2>&1
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 建议测试
|
|||
|
|
|
|||
|
|
3. **验证功能**
|
|||
|
|
- 访问推广设置页面:`https://soul.quwanzhi.com/admin/referral-settings`
|
|||
|
|
- 小程序测试绑定切换
|
|||
|
|
- 测试购买分佣
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## ✅ 代码逻辑完成度:100%
|
|||
|
|
|
|||
|
|
**所有核心逻辑已全部实现并部署!**
|
|||
|
|
|
|||
|
|
剩余工作仅为:
|
|||
|
|
1. 宝塔面板重启服务(1分钟)
|
|||
|
|
2. 宝塔面板配置定时任务(2分钟)
|
|||
|
|
3. 功能测试验证(可选)
|