9.4 KiB
9.4 KiB
新分销逻辑 - 代码修改总结
✅ 已完成的代码修改
1. 数据库层(Database Layer)
迁移脚本
- ✅
scripts/migration-add-binding-fields.sql(SQL版本) - ✅
scripts/migrate_binding_fields.py(Python完整版) - ✅
scripts/migrate_db_simple.py(Python简化版)- 已执行成功
新增字段
referral_bindings 表:
✅ last_purchase_date DATETIME - 最后购买时间
✅ purchase_count INT - 购买次数
✅ total_commission DECIMAL(10,2) - 累计佣金
✅ status 新增枚举值 'cancelled' - 被切换状态
新增索引
✅ 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
修改前:
// ❌ 有效期内不能切换
if (expiryDate < now) {
// 已过期才能抢夺
} else {
return { error: '绑定有效期内无法更换' }
}
修改后:
// ✅ 立即切换(无条件)
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
修改前:
// ❌ 购买后标记为 converted,不再累加
await query(`
UPDATE referral_bindings
SET status = 'converted',
commission_amount = ?
WHERE id = ?
`, [commission, binding.id])
修改后:
// ✅ 保持 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
新增功能:好友优惠折扣
// ✅ 读取好友优惠配置
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
新增功能:读取最低提现门槛
// ✅ 从配置读取最低提现门槛
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)
数据安全:
// ✅ 保存时强制类型转换
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
// ✅ 新增菜单项
{ icon: CreditCard, label: "推广设置", href: "/admin/referral-settings" }
4. 小程序(MiniProgram)
4.1 分销中心UI:miniprogram/pages/referral/referral.wxml
修改:
<!-- ✅ 删除"我的邀请码"卡片 -->
<!-- 保留分享按钮和收益明细 -->
5. 定时任务(Scheduled Task)
自动解绑脚本
- ✅
scripts/auto-unbind-expired.js(标准版) - ✅
scripts/auto-unbind-expired-simple.js(简化版,直接连MySQL)
解绑条件:
WHERE status = 'active'
AND expiry_date < NOW()
AND purchase_count = 0
执行逻辑:
- 查询符合条件的绑定
- 标记为
expired - 更新推荐人的
referral_count - 输出日志
📋 完整的业务流程
场景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个文件)
- ✅
app/api/referral/bind/route.ts- 立即切换绑定 - ✅
app/api/miniprogram/pay/notify/route.ts- 累加分佣 - ✅
app/api/miniprogram/pay/route.ts- 好友优惠 - ✅
app/api/withdraw/route.ts- 提现门槛 - ✅
app/admin/referral-settings/page.tsx- 推广设置页 - ✅
app/admin/layout.tsx- 菜单入口
小程序(1个文件)
- ✅
miniprogram/pages/referral/referral.wxml- 去掉邀请码卡片
脚本(5个文件)
- ✅
scripts/migrate_db_simple.py- 数据库迁移 - ✅
scripts/auto-unbind-expired-simple.js- 定时任务 - ✅
scripts/test-referral-flow.js- 功能测试
文档(3个文件)
- ✅
开发文档/8、部署/新分销逻辑设计方案.md - ✅
开发文档/8、部署/新分销逻辑-部署步骤.md - ✅
开发文档/8、部署/新分销逻辑-宝塔操作清单.md
🔄 部署状态
- ✅ 数据库字段已添加
- ✅ 代码已构建(pnpm build)
- ✅ 代码已上传服务器(python devlop.py)
- ⏳ 待操作:宝塔面板重启服务
- ⏳ 待操作:宝塔面板配置定时任务
🚦 下一步操作
必须完成(服务才能生效)
-
重启 Node.js 服务
- 宝塔面板 → 网站 → soul.quwanzhi.com → Node项目 → 重启
- 或SSH执行:
/www/server/nodejs/v16.20.2/bin/pm2 restart soul
-
配置定时任务
- 宝塔面板 → 计划任务 → 添加Shell脚本
- 执行周期:每天 02:00
- 脚本内容:
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
建议测试
- 验证功能
- 访问推广设置页面:
https://soul.quwanzhi.com/admin/referral-settings - 小程序测试绑定切换
- 测试购买分佣
- 访问推广设置页面:
✅ 代码逻辑完成度:100%
所有核心逻辑已全部实现并部署!
剩余工作仅为:
- 宝塔面板重启服务(1分钟)
- 宝塔面板配置定时任务(2分钟)
- 功能测试验证(可选)