2026-01-23 16:31:54 +08:00
|
|
|
/**
|
2026-01-25 19:37:59 +08:00
|
|
|
* 分销数据API
|
|
|
|
|
* 获取用户的推广数据、绑定用户列表、收益统计
|
2026-01-23 16:31:54 +08:00
|
|
|
*/
|
|
|
|
|
|
2026-01-25 19:37:59 +08:00
|
|
|
import { NextRequest, NextResponse } from 'next/server'
|
|
|
|
|
import { query } from '@/lib/db'
|
2026-01-23 16:31:54 +08:00
|
|
|
|
|
|
|
|
/**
|
2026-01-25 19:37:59 +08:00
|
|
|
* GET - 获取分销数据
|
2026-01-23 16:31:54 +08:00
|
|
|
*/
|
2026-01-25 19:37:59 +08:00
|
|
|
export async function GET(request: NextRequest) {
|
|
|
|
|
const { searchParams } = new URL(request.url)
|
|
|
|
|
const userId = searchParams.get('userId')
|
|
|
|
|
|
|
|
|
|
if (!userId) {
|
2026-01-23 16:31:54 +08:00
|
|
|
return NextResponse.json({
|
|
|
|
|
success: false,
|
2026-01-25 19:37:59 +08:00
|
|
|
error: '用户ID不能为空'
|
|
|
|
|
}, { status: 400 })
|
2026-01-23 16:31:54 +08:00
|
|
|
}
|
2026-01-25 19:37:59 +08:00
|
|
|
|
2026-01-23 16:31:54 +08:00
|
|
|
try {
|
2026-01-25 19:37:59 +08:00
|
|
|
// 1. 获取用户基本信息
|
|
|
|
|
const users = await query(`
|
|
|
|
|
SELECT id, nickname, referral_code, earnings, pending_earnings,
|
|
|
|
|
withdrawn_earnings, referral_count
|
|
|
|
|
FROM users WHERE id = ?
|
|
|
|
|
`, [userId]) as any[]
|
|
|
|
|
|
|
|
|
|
if (users.length === 0) {
|
2026-01-23 16:31:54 +08:00
|
|
|
return NextResponse.json({
|
|
|
|
|
success: false,
|
2026-01-25 19:37:59 +08:00
|
|
|
error: '用户不存在'
|
|
|
|
|
}, { status: 404 })
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const user = users[0]
|
|
|
|
|
|
|
|
|
|
// 2. 获取推荐的用户列表
|
|
|
|
|
const referees = await query(`
|
|
|
|
|
SELECT id, nickname, avatar, phone, wechat_id,
|
|
|
|
|
has_full_book, created_at,
|
|
|
|
|
DATEDIFF(DATE_ADD(created_at, INTERVAL 30 DAY), NOW()) as days_remaining
|
|
|
|
|
FROM users
|
|
|
|
|
WHERE referred_by = ?
|
|
|
|
|
ORDER BY created_at DESC
|
|
|
|
|
`, [userId]) as any[]
|
|
|
|
|
|
|
|
|
|
// 3. 分类绑定用户
|
|
|
|
|
const now = new Date()
|
|
|
|
|
const activeBindings: any[] = []
|
|
|
|
|
const convertedBindings: any[] = []
|
|
|
|
|
const expiredBindings: any[] = []
|
|
|
|
|
|
|
|
|
|
for (const referee of referees) {
|
|
|
|
|
const binding = {
|
|
|
|
|
id: referee.id,
|
|
|
|
|
nickname: referee.nickname || '用户' + referee.id.slice(-4),
|
|
|
|
|
avatar: referee.avatar || `https://picsum.photos/100/100?random=${referee.id.slice(-2)}`,
|
|
|
|
|
phone: referee.phone ? referee.phone.slice(0, 3) + '****' + referee.phone.slice(-4) : null,
|
|
|
|
|
hasFullBook: referee.has_full_book,
|
|
|
|
|
daysRemaining: Math.max(0, referee.days_remaining || 0),
|
|
|
|
|
createdAt: referee.created_at
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (referee.has_full_book) {
|
|
|
|
|
// 已转化(已购买)
|
|
|
|
|
convertedBindings.push(binding)
|
|
|
|
|
} else if (binding.daysRemaining <= 0) {
|
|
|
|
|
// 已过期
|
|
|
|
|
expiredBindings.push(binding)
|
|
|
|
|
} else {
|
|
|
|
|
// 活跃中
|
|
|
|
|
activeBindings.push(binding)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 4. 获取收益明细(最近的订单)
|
|
|
|
|
let earningsDetails: any[] = []
|
|
|
|
|
try {
|
|
|
|
|
earningsDetails = await query(`
|
|
|
|
|
SELECT o.id, o.amount, o.product_type, o.created_at,
|
|
|
|
|
u.nickname as buyer_nickname
|
|
|
|
|
FROM orders o
|
|
|
|
|
JOIN users u ON o.user_id = u.id
|
|
|
|
|
WHERE u.referred_by = ? AND o.status = 'paid'
|
|
|
|
|
ORDER BY o.created_at DESC
|
|
|
|
|
LIMIT 20
|
|
|
|
|
`, [userId]) as any[]
|
|
|
|
|
} catch (e) {
|
|
|
|
|
// 订单表可能不存在,忽略
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 5. 统计数据
|
|
|
|
|
const stats = {
|
|
|
|
|
totalReferrals: referees.length,
|
|
|
|
|
activeCount: activeBindings.length,
|
|
|
|
|
convertedCount: convertedBindings.length,
|
|
|
|
|
expiredCount: expiredBindings.length,
|
|
|
|
|
expiringCount: activeBindings.filter(b => b.daysRemaining <= 7).length
|
2026-01-23 16:31:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NextResponse.json({
|
|
|
|
|
success: true,
|
|
|
|
|
data: {
|
2026-01-25 19:37:59 +08:00
|
|
|
// 收益数据
|
|
|
|
|
earnings: parseFloat(user.earnings) || 0,
|
|
|
|
|
pendingEarnings: parseFloat(user.pending_earnings) || 0,
|
|
|
|
|
withdrawnEarnings: parseFloat(user.withdrawn_earnings) || 0,
|
|
|
|
|
|
|
|
|
|
// 推荐码
|
|
|
|
|
referralCode: user.referral_code,
|
|
|
|
|
referralCount: user.referral_count || referees.length,
|
|
|
|
|
|
|
|
|
|
// 绑定用户分类
|
|
|
|
|
activeBindings,
|
|
|
|
|
convertedBindings,
|
|
|
|
|
expiredBindings,
|
|
|
|
|
|
|
|
|
|
// 统计
|
|
|
|
|
stats,
|
|
|
|
|
|
|
|
|
|
// 收益明细
|
|
|
|
|
earningsDetails: earningsDetails.map(e => ({
|
|
|
|
|
id: e.id,
|
|
|
|
|
amount: parseFloat(e.amount) * 0.9, // 90%佣金
|
|
|
|
|
productType: e.product_type,
|
|
|
|
|
buyerNickname: e.buyer_nickname,
|
|
|
|
|
createdAt: e.created_at
|
|
|
|
|
}))
|
2026-01-23 16:31:54 +08:00
|
|
|
}
|
|
|
|
|
})
|
2026-01-25 19:37:59 +08:00
|
|
|
|
2026-01-23 16:31:54 +08:00
|
|
|
} catch (error) {
|
2026-01-25 19:37:59 +08:00
|
|
|
console.error('[ReferralData] 错误:', error)
|
2026-01-23 16:31:54 +08:00
|
|
|
return NextResponse.json({
|
|
|
|
|
success: false,
|
2026-01-25 19:37:59 +08:00
|
|
|
error: '获取分销数据失败: ' + (error as Error).message
|
2026-01-23 16:31:54 +08:00
|
|
|
}, { status: 500 })
|
|
|
|
|
}
|
2026-01-25 19:37:59 +08:00
|
|
|
}
|