2026-01-25 19:37:59 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 用户绑定关系API
|
|
|
|
|
|
* 获取指定用户的所有绑定用户列表
|
2026-01-29 11:58:07 +08:00
|
|
|
|
*
|
|
|
|
|
|
* 优先从referral_bindings表查询,同时兼容users表的referred_by字段
|
2026-01-25 19:37:59 +08:00
|
|
|
|
*/
|
|
|
|
|
|
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
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-29 11:58:07 +08:00
|
|
|
|
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表')
|
2026-01-25 19:37:59 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-29 11:58:07 +08:00
|
|
|
|
// 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[]
|
|
|
|
|
|
}
|
2026-01-25 19:37:59 +08:00
|
|
|
|
|
|
|
|
|
|
// 统计信息
|
2026-01-29 11:58:07 +08:00
|
|
|
|
const purchasedCount = referrals.filter(r =>
|
|
|
|
|
|
r.has_full_book ||
|
|
|
|
|
|
r.binding_status === 'converted' ||
|
|
|
|
|
|
(r.purchased_sections && r.purchased_sections !== '[]')
|
|
|
|
|
|
).length
|
2026-01-25 19:37:59 +08:00
|
|
|
|
|
|
|
|
|
|
// 查询该用户的收益信息
|
|
|
|
|
|
const earningsRows = await query(`
|
|
|
|
|
|
SELECT earnings, pending_earnings, withdrawn_earnings
|
2026-01-29 11:58:07 +08:00
|
|
|
|
FROM users WHERE id = ?
|
|
|
|
|
|
`, [userId]) as any[]
|
2026-01-25 19:37:59 +08:00
|
|
|
|
|
|
|
|
|
|
const earnings = earningsRows[0] || { earnings: 0, pending_earnings: 0, withdrawn_earnings: 0 }
|
|
|
|
|
|
|
|
|
|
|
|
// 格式化返回数据
|
|
|
|
|
|
const formattedReferrals = referrals.map(r => ({
|
2026-01-29 11:58:07 +08:00
|
|
|
|
id: r.referee_id || r.id,
|
2026-01-25 19:37:59 +08:00
|
|
|
|
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,
|
2026-01-29 11:58:07 +08:00
|
|
|
|
hasPurchased: r.has_full_book || r.binding_status === 'converted' || (r.purchased_sections && r.purchased_sections !== '[]'),
|
2026-01-25 19:37:59 +08:00
|
|
|
|
hasFullBook: !!r.has_full_book,
|
|
|
|
|
|
purchasedSections: typeof r.purchased_sections === 'string'
|
|
|
|
|
|
? JSON.parse(r.purchased_sections || '[]').length
|
|
|
|
|
|
: 0,
|
2026-01-29 11:58:07 +08:00
|
|
|
|
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')
|
2026-01-25 19:37:59 +08:00
|
|
|
|
}))
|
|
|
|
|
|
|
|
|
|
|
|
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 })
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|