Files
soul/app/api/db/users/referrals/route.ts
卡若 d17150154c 全面优化:小程序 + 后台管理
## 小程序优化
1. 我的页面:
   - 头像点击获取微信头像(button open-type="chooseAvatar")
   - 昵称点击直接修改
   - 去掉"创业伙伴"图标
   - ID优先显示微信号

2. 设置页面:
   - 一键获取微信手机号
   - 微信号/支付宝绑定优化

## 后台管理优化
1. 内容管理:
   - 章节编辑增加"免费章节"开关
   - 保存时自动去重标题(如#1.2重复)

2. 用户管理:
   - 修复绑定关系显示(优先查referral_bindings表)
2026-01-29 11:58:07 +08:00

140 lines
4.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 用户绑定关系API
* 获取指定用户的所有绑定用户列表
*
* 优先从referral_bindings表查询同时兼容users表的referred_by字段
*/
import { NextResponse } from 'next/server'
import { query } from '@/lib/db'
export async function GET(request: Request) {
try {
const { searchParams } = new URL(request.url)
const userId = searchParams.get('userId')
const referralCode = searchParams.get('code')
if (!userId && !referralCode) {
return NextResponse.json({
success: false,
error: '缺少用户ID或推广码'
}, { status: 400 })
}
// 如果传入userId先获取该用户的推广码
let code = referralCode
if (userId && !referralCode) {
const userRows = await query('SELECT referral_code FROM users WHERE id = ?', [userId]) as any[]
if (userRows.length === 0) {
return NextResponse.json({
success: false,
error: '用户不存在'
}, { status: 404 })
}
code = userRows[0].referral_code
}
let referrals: any[] = []
// 1. 首先从referral_bindings表查询绑定关系
try {
const bindingsReferrals = await query(`
SELECT
rb.id as binding_id,
rb.referee_id,
rb.status as binding_status,
rb.binding_date,
rb.expiry_date,
rb.commission_amount,
u.id, u.nickname, u.avatar, u.phone, u.open_id,
u.has_full_book, u.purchased_sections,
u.created_at, u.updated_at,
DATEDIFF(rb.expiry_date, NOW()) as days_remaining
FROM referral_bindings rb
JOIN users u ON rb.referee_id = u.id
WHERE rb.referrer_id = ?
ORDER BY rb.binding_date DESC
`, [userId]) as any[]
if (bindingsReferrals.length > 0) {
referrals = bindingsReferrals
}
} catch (e) {
console.log('[Referrals] referral_bindings表查询失败使用users表')
}
// 2. 如果referral_bindings表没有数据再从users表查询
if (referrals.length === 0 && code) {
referrals = await query(`
SELECT
id, nickname, avatar, phone, open_id,
has_full_book, purchased_sections,
created_at, updated_at,
NULL as binding_status,
NULL as binding_date,
NULL as expiry_date,
NULL as days_remaining,
NULL as commission_amount
FROM users
WHERE referred_by = ?
ORDER BY created_at DESC
`, [code]) as any[]
}
// 统计信息
const purchasedCount = referrals.filter(r =>
r.has_full_book ||
r.binding_status === 'converted' ||
(r.purchased_sections && r.purchased_sections !== '[]')
).length
// 查询该用户的收益信息
const earningsRows = await query(`
SELECT earnings, pending_earnings, withdrawn_earnings
FROM users WHERE id = ?
`, [userId]) as any[]
const earnings = earningsRows[0] || { earnings: 0, pending_earnings: 0, withdrawn_earnings: 0 }
// 格式化返回数据
const formattedReferrals = referrals.map(r => ({
id: r.referee_id || r.id,
nickname: r.nickname || '微信用户',
avatar: r.avatar,
phone: r.phone ? r.phone.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2') : null,
hasOpenId: !!r.open_id,
hasPurchased: r.has_full_book || r.binding_status === 'converted' || (r.purchased_sections && r.purchased_sections !== '[]'),
hasFullBook: !!r.has_full_book,
purchasedSections: typeof r.purchased_sections === 'string'
? JSON.parse(r.purchased_sections || '[]').length
: 0,
createdAt: r.binding_date || r.created_at,
bindingStatus: r.binding_status || 'active',
daysRemaining: r.days_remaining,
commission: parseFloat(r.commission_amount) || 0,
status: r.binding_status === 'converted' ? 'converted'
: r.has_full_book ? 'vip'
: (r.purchased_sections && r.purchased_sections !== '[]' ? 'paid' : 'active')
}))
return NextResponse.json({
success: true,
referrals: formattedReferrals,
stats: {
total: referrals.length,
purchased: purchasedCount,
free: referrals.length - purchasedCount,
earnings: parseFloat(earnings.earnings) || 0,
pendingEarnings: parseFloat(earnings.pending_earnings) || 0,
withdrawnEarnings: parseFloat(earnings.withdrawn_earnings) || 0
}
})
} catch (error) {
console.error('Get referrals error:', error)
return NextResponse.json({
success: false,
error: '获取绑定关系失败'
}, { status: 500 })
}
}