9.0 KiB
9.0 KiB
代码逻辑和数据库最终检查清单 ✅
📊 数据库修改(已完成)
1. referral_bindings 表新增字段
✅ last_purchase_date DATETIME DEFAULT NULL
✅ purchase_count INT DEFAULT 0
✅ total_commission DECIMAL(10,2) DEFAULT 0.00
✅ status ENUM('active', 'expired', 'cancelled') -- 新增 'cancelled'
2. 索引优化
✅ idx_status_expiry (status, expiry_date)
✅ idx_referee_status (referee_id, status)
✅ idx_referrer_status (referrer_id, status)
✅ idx_purchase_count (purchase_count)
3. 数据库迁移执行状态
- ✅ 已通过
scripts/migrate_db_simple.py成功执行 - ✅ 所有字段已添加
- ✅ 所有索引已创建
🔧 核心API逻辑(已验证)
1. /api/referral/bind - 绑定/切换推荐人 ✅
文件: app/api/referral/bind/route.ts
关键逻辑:
✅ 从 referral_config 读取 bindingDays(不再硬编码 30 天)
✅ 同一推荐人 → 续期(刷新 30 天)
✅ 不同推荐人 → 立即切换(无需等待过期)
- 旧绑定标记为 'cancelled'
- 创建新绑定,expiry_date = NOW + bindingDays
- 更新 users.referral_count(旧 -1,新 +1)
验证点:
- ✅ 绑定天数可配置
- ✅ 切换逻辑正确(不检查 expiry_date)
- ✅ 旧绑定正确标记为 'cancelled'
- ✅ 新绑定正确创建
- ✅ 推荐人数量正确更新
2. /api/miniprogram/pay - 创建支付订单 ✅
文件: app/api/miniprogram/pay/route.ts
关键逻辑:
✅ 从 referral_config 读取 userDiscount(如 5 表示 5%)
✅ 如果有 referralCode,计算折后价
finalAmount = amount * (1 - userDiscount / 100)
finalAmount = max(0.01, round(finalAmount, 2))
✅ 微信支付使用 finalAmount(折后价)
✅ 订单表记录 finalAmount(折后价)
验证点:
- ✅ 折扣正确应用(原价 1.00,5% off = 0.95)
- ✅ 最低金额保护(至少 0.01 元)
- ✅ 金额精确到分(Math.round)
- ✅ 订单表记录的是折后价
3. /api/miniprogram/pay/notify - 支付回调 ✅
文件: app/api/miniprogram/pay/notify/route.ts
关键逻辑:
✅ 查找 status = 'active' 的绑定记录
✅ 检查 expiry_date > NOW(过期不分佣)
✅ 从 referral_config 读取 distributorShare
✅ 计算佣金:commission = amount * distributorShare / 100
✅ 更新 users.pending_earnings += commission
✅ 更新 referral_bindings:
- last_purchase_date = NOW
- purchase_count += 1
- total_commission += commission
- status 保持 'active'(不再改为 'converted')
验证点:
- ✅ 只给 active 且未过期的绑定分佣
- ✅ 佣金比例可配置
- ✅ 支持多次购买分佣(不改 status)
- ✅ 正确累加购买次数和佣金
- ✅ 记录最后购买时间
4. /api/withdraw - 提现申请 ✅
文件: app/api/withdraw/route.ts
关键逻辑:
✅ 从 referral_config 读取 minWithdrawAmount
✅ 验证 amount >= minWithdrawAmount(不再硬编码 10 元)
✅ 验证 amount <= pending_earnings
验证点:
- ✅ 最低提现金额可配置
- ✅ 金额验证逻辑正确
5. /api/referral/data - 分销数据统计 ✅
文件: app/api/referral/data/route.ts
关键逻辑:
✅ 绑定统计:
- active: status = 'active' AND expiry_date > NOW
- converted: status = 'active' AND purchase_count > 0
- expired: status IN ('expired', 'cancelled') OR expiry_date <= NOW
✅ 已转化用户列表:
WHERE status = 'active' AND purchase_count > 0
ORDER BY last_purchase_date DESC
✅ 返回购买次数、累计佣金
验证点:
- ✅ 不再查询 status = 'converted'
- ✅ 使用 purchase_count 判断是否已购买
- ✅ 返回新增的字段(purchase_count, total_commission)
- ✅ 统计逻辑正确(包含 'cancelled' 状态)
🎯 管理后台(已验证)
1. 推广设置页面 ✅
文件: app/admin/referral-settings/page.tsx
配置项:
✅ distributorShare (分销比例, 0-100)
✅ minWithdrawAmount (最低提现金额, 元)
✅ bindingDays (绑定天数, 天)
✅ userDiscount (好友优惠, 0-100)
✅ enableAutoWithdraw (自动提现, boolean)
验证点:
- ✅ 读取配置正确
- ✅ 保存配置正确(Number/Boolean 转换)
- ✅ 表单验证正确
- ✅ 成功提示清晰
2. 管理后台菜单 ✅
文件: app/admin/layout.tsx
✅ 新增菜单项: "推广设置" → /admin/referral-settings
✅ 图标: CreditCard
✅ 位置: "用户管理" 和 "系统设置" 之间
📱 小程序端(已完成)
1. UI修改 ✅
✅ 删除"我的邀请码"卡片(miniprogram/pages/referral/referral.wxml)
2. 绑定逻辑 ✅
✅ app.js 调用 /api/referral/bind(后端已实现立即切换)
✅ 无需前端修改
3. 支付逻辑 ✅
✅ pages/read/read.js 传递 referralCode(后端已实现折扣)
✅ 无需前端修改
4. 数据展示 ✅
✅ pages/referral/referral.js 调用 /api/referral/data
✅ 后端已返回新字段(purchase_count, total_commission)
✅ 无需前端修改
⏰ 定时任务(已创建)
1. 自动解绑脚本 ✅
文件: scripts/auto-unbind-expired-simple.js
逻辑:
✅ 查找 status = 'active' AND expiry_date < NOW AND purchase_count = 0
✅ 批量更新为 status = 'expired'
✅ 输出详细日志
部署:
⏸️ 需在宝塔面板配置: 每天 03:00 执行
命令: cd /www/wwwroot/soul.quwanzhi.com && /www/server/nodejs/v20.11.0/bin/node scripts/auto-unbind-expired-simple.js >> logs/auto-unbind.log 2>&1
🔍 业务逻辑验证
场景1: 首次绑定 ✅
A 分享链接 → B 点击 → /api/referral/bind
→ 创建新绑定(status = 'active', expiry_date = NOW + 30天)
→ users.referral_count += 1
场景2: 切换推荐人 ✅
B 已绑定 A → B 点击 C 的链接 → /api/referral/bind
→ 旧绑定(A-B)标记为 'cancelled'
→ 创建新绑定(C-B, status = 'active', expiry_date = NOW + 30天)
→ A.referral_count -= 1, C.referral_count += 1
场景3: 续期绑定 ✅
B 已绑定 A → B 再次点击 A 的链接 → /api/referral/bind
→ 更新绑定(expiry_date = NOW + 30天)
→ referral_count 不变
场景4: 首次购买 ✅
B 绑定 C(5天前)→ B 购买 1.00 元章节(有 5% 优惠)
→ 实付 0.95 元
→ C 获得佣金 0.95 * 90% = 0.855 元(四舍五入 0.86)
→ referral_bindings: purchase_count = 1, total_commission = 0.86, last_purchase_date = NOW
→ C.pending_earnings += 0.86
→ 绑定保持 'active'
场景5: 多次购买 ✅
B 再次购买 1.00 元章节(还在 30 天内)
→ 实付 0.95 元
→ C 再获得佣金 0.86 元
→ referral_bindings: purchase_count = 2, total_commission = 1.72, last_purchase_date = NOW
→ C.pending_earnings += 0.86(累计 1.72)
→ 绑定保持 'active'
场景6: 自动解绑 ✅
B 绑定 A(30 天前)→ B 从未购买 → 定时任务执行
→ 查找: status = 'active' AND expiry_date < NOW AND purchase_count = 0
→ 更新: status = 'expired'
→ A.referral_count -= 1
场景7: 提现 ✅
C 有 pending_earnings = 15.00 元 → 申请提现 12.00 元
→ 验证 amount >= minWithdrawAmount(默认 10)
→ 验证 amount <= pending_earnings
→ 创建提现记录
→ C.pending_earnings -= 12.00 = 3.00
✅ 最终确认
代码逻辑
- ✅ 所有 API 已适配新逻辑
- ✅ 所有硬编码值已改为动态配置
- ✅ 所有状态转换逻辑正确
- ✅ 所有金额计算精确到分
数据库
- ✅ 所有字段已添加
- ✅ 所有索引已创建
- ✅ 数据类型正确
- ✅ 默认值正确
小程序
- ✅ UI 已删除邀请码卡片
- ✅ 绑定逻辑兼容后端
- ✅ 支付逻辑兼容后端
- ✅ 数据展示兼容后端
管理后台
- ✅ 推广设置页面已创建
- ✅ 菜单已添加
- ✅ 配置读写正确
定时任务
- ✅ 脚本已创建
- ⏸️ 需在宝塔配置(部署时)
🚀 部署检查项
部署前确认:
- ✅ 代码已修改
- ✅ 数据库已迁移
- ✅ 本地测试通过
部署后确认:
- ⏸️ PM2 重启成功
- ⏸️ 定时任务配置成功
- ⏸️ 管理后台可访问
/admin/referral-settings - ⏸️ 小程序绑定/支付/分佣功能测试通过
📝 测试用例(可选)
如需本地测试,运行:
node scripts/test-referral-flow.js
测试覆盖:
- ✅ 首次绑定
- ✅ 续期绑定
- ✅ 切换绑定
- ✅ 首次购买分佣
- ✅ 多次购买分佣
- ✅ 过期绑定不分佣
✅ 结论
所有代码逻辑和数据库修改已完成并验证,可以放心部署!
需要在宝塔面板配置的只有:
- 重启 PM2 服务(让新代码生效)
- 配置定时任务(自动解绑)
参考文档: 开发文档/8、部署/新分销逻辑-宝塔操作清单.md