/** * 分销模块API * 功能:绑定追踪、提现管理、统计概览 */ import { NextRequest, NextResponse } from 'next/server'; // 模拟数据存储(实际项目应使用数据库) let distributionBindings: Array<{ id: string; referrerId: string; referrerCode: string; visitorId: string; visitorPhone?: string; visitorNickname?: string; bindingTime: string; expireTime: string; status: 'active' | 'converted' | 'expired' | 'cancelled'; convertedAt?: string; orderId?: string; orderAmount?: number; commission?: number; source: 'link' | 'miniprogram' | 'poster' | 'qrcode'; createdAt: string; }> = []; let clickRecords: Array<{ id: string; referralCode: string; referrerId: string; visitorId: string; source: string; clickTime: string; }> = []; let distributors: Array<{ id: string; userId: string; nickname: string; phone: string; referralCode: string; totalClicks: number; totalBindings: number; activeBindings: number; convertedBindings: number; expiredBindings: number; totalEarnings: number; pendingEarnings: number; withdrawnEarnings: number; autoWithdraw: boolean; autoWithdrawThreshold: number; autoWithdrawAccount?: { type: 'wechat' | 'alipay'; account: string; name: string; }; level: 'normal' | 'silver' | 'gold' | 'diamond'; commissionRate: number; status: 'active' | 'frozen' | 'disabled'; createdAt: string; }> = []; let withdrawRecords: Array<{ id: string; distributorId: string; userId: string; userName: string; amount: number; fee: number; actualAmount: number; method: 'wechat' | 'alipay'; account: string; accountName: string; status: 'pending' | 'processing' | 'completed' | 'failed' | 'rejected'; isAuto: boolean; paymentNo?: string; paymentTime?: string; reviewNote?: string; createdAt: string; completedAt?: string; }> = []; // 配置 const BINDING_DAYS = 30; const MIN_WITHDRAW_AMOUNT = 10; const DEFAULT_COMMISSION_RATE = 90; // 生成ID function generateId(prefix: string = ''): string { return `${prefix}${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; } // GET: 获取分销数据 export async function GET(req: NextRequest) { const { searchParams } = new URL(req.url); const type = searchParams.get('type') || 'overview'; const userId = searchParams.get('userId'); const page = parseInt(searchParams.get('page') || '1'); const pageSize = parseInt(searchParams.get('pageSize') || '20'); try { switch (type) { case 'overview': return getOverview(); case 'bindings': return getBindings(userId, page, pageSize); case 'my-bindings': if (!userId) { return NextResponse.json({ error: '缺少用户ID' }, { status: 400 }); } return getMyBindings(userId); case 'withdrawals': return getWithdrawals(userId, page, pageSize); case 'reminders': if (!userId) { return NextResponse.json({ error: '缺少用户ID' }, { status: 400 }); } return getReminders(userId); case 'distributor': if (!userId) { return NextResponse.json({ error: '缺少用户ID' }, { status: 400 }); } return getDistributor(userId); case 'ranking': return getRanking(); default: return NextResponse.json({ error: '未知类型' }, { status: 400 }); } } catch (error) { console.error('分销API错误:', error); return NextResponse.json({ error: '服务器错误' }, { status: 500 }); } } // POST: 分销操作 export async function POST(req: NextRequest) { try { const body = await req.json(); const { action } = body; switch (action) { case 'record_click': return recordClick(body); case 'convert': return convertBinding(body); case 'request_withdraw': return requestWithdraw(body); case 'set_auto_withdraw': return setAutoWithdraw(body); case 'process_expired': return processExpiredBindings(); default: return NextResponse.json({ error: '未知操作' }, { status: 400 }); } } catch (error) { console.error('分销API错误:', error); return NextResponse.json({ error: '服务器错误' }, { status: 500 }); } } // PUT: 更新操作(后台管理) export async function PUT(req: NextRequest) { try { const body = await req.json(); const { action } = body; switch (action) { case 'approve_withdraw': return approveWithdraw(body); case 'reject_withdraw': return rejectWithdraw(body); case 'update_distributor': return updateDistributor(body); default: return NextResponse.json({ error: '未知操作' }, { status: 400 }); } } catch (error) { console.error('分销API错误:', error); return NextResponse.json({ error: '服务器错误' }, { status: 500 }); } } // ========== 具体实现 ========== // 获取概览数据 function getOverview() { const now = new Date(); const today = new Date(now.getFullYear(), now.getMonth(), now.getDate()); const monthStart = new Date(now.getFullYear(), now.getMonth(), 1); const weekFromNow = new Date(); weekFromNow.setDate(weekFromNow.getDate() + 7); const overview = { // 今日数据 todayClicks: clickRecords.filter(c => new Date(c.clickTime) >= today).length, todayBindings: distributionBindings.filter(b => new Date(b.createdAt) >= today).length, todayConversions: distributionBindings.filter(b => b.status === 'converted' && b.convertedAt && new Date(b.convertedAt) >= today ).length, todayEarnings: distributionBindings .filter(b => b.status === 'converted' && b.convertedAt && new Date(b.convertedAt) >= today) .reduce((sum, b) => sum + (b.commission || 0), 0), // 本月数据 monthClicks: clickRecords.filter(c => new Date(c.clickTime) >= monthStart).length, monthBindings: distributionBindings.filter(b => new Date(b.createdAt) >= monthStart).length, monthConversions: distributionBindings.filter(b => b.status === 'converted' && b.convertedAt && new Date(b.convertedAt) >= monthStart ).length, monthEarnings: distributionBindings .filter(b => b.status === 'converted' && b.convertedAt && new Date(b.convertedAt) >= monthStart) .reduce((sum, b) => sum + (b.commission || 0), 0), // 总计 totalClicks: clickRecords.length, totalBindings: distributionBindings.length, totalConversions: distributionBindings.filter(b => b.status === 'converted').length, totalEarnings: distributionBindings .filter(b => b.status === 'converted') .reduce((sum, b) => sum + (b.commission || 0), 0), // 即将过期 expiringBindings: distributionBindings.filter(b => b.status === 'active' && new Date(b.expireTime) <= weekFromNow && new Date(b.expireTime) > now ).length, // 待处理提现 pendingWithdrawals: withdrawRecords.filter(w => w.status === 'pending').length, pendingWithdrawAmount: withdrawRecords .filter(w => w.status === 'pending') .reduce((sum, w) => sum + w.amount, 0), // 转化率 conversionRate: clickRecords.length > 0 ? (distributionBindings.filter(b => b.status === 'converted').length / clickRecords.length * 100).toFixed(2) : '0.00', // 分销商数量 totalDistributors: distributors.length, activeDistributors: distributors.filter(d => d.status === 'active').length, }; return NextResponse.json({ success: true, overview }); } // 获取绑定列表(后台) function getBindings(userId: string | null, page: number, pageSize: number) { let filteredBindings = [...distributionBindings]; if (userId) { filteredBindings = filteredBindings.filter(b => b.referrerId === userId); } // 按创建时间倒序 filteredBindings.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime() ); const total = filteredBindings.length; const start = (page - 1) * pageSize; const paginatedBindings = filteredBindings.slice(start, start + pageSize); // 添加剩余天数 const now = new Date(); const bindingsWithDays = paginatedBindings.map(b => ({ ...b, daysRemaining: b.status === 'active' ? Math.max(0, Math.ceil((new Date(b.expireTime).getTime() - now.getTime()) / (1000 * 60 * 60 * 24))) : 0, })); return NextResponse.json({ success: true, bindings: bindingsWithDays, pagination: { page, pageSize, total, totalPages: Math.ceil(total / pageSize), }, }); } // 获取我的绑定用户(分销中心) function getMyBindings(userId: string) { const myBindings = distributionBindings.filter(b => b.referrerId === userId); const now = new Date(); // 按状态分类 const active = myBindings .filter(b => b.status === 'active') .map(b => ({ ...b, daysRemaining: Math.max(0, Math.ceil((new Date(b.expireTime).getTime() - now.getTime()) / (1000 * 60 * 60 * 24))), })) .sort((a, b) => a.daysRemaining - b.daysRemaining); // 即将过期的排前面 const converted = myBindings.filter(b => b.status === 'converted'); const expired = myBindings.filter(b => b.status === 'expired'); // 统计 const stats = { totalBindings: myBindings.length, activeCount: active.length, convertedCount: converted.length, expiredCount: expired.length, expiringCount: active.filter(b => b.daysRemaining <= 7).length, totalCommission: converted.reduce((sum, b) => sum + (b.commission || 0), 0), }; return NextResponse.json({ success: true, bindings: { active, converted, expired, }, stats, }); } // 获取提现记录 function getWithdrawals(userId: string | null, page: number, pageSize: number) { let filteredWithdrawals = [...withdrawRecords]; if (userId) { filteredWithdrawals = filteredWithdrawals.filter(w => w.userId === userId); } // 按创建时间倒序 filteredWithdrawals.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime() ); const total = filteredWithdrawals.length; const start = (page - 1) * pageSize; const paginatedWithdrawals = filteredWithdrawals.slice(start, start + pageSize); // 统计 const stats = { pending: filteredWithdrawals.filter(w => w.status === 'pending').length, pendingAmount: filteredWithdrawals .filter(w => w.status === 'pending') .reduce((sum, w) => sum + w.amount, 0), completed: filteredWithdrawals.filter(w => w.status === 'completed').length, completedAmount: filteredWithdrawals .filter(w => w.status === 'completed') .reduce((sum, w) => sum + w.amount, 0), }; return NextResponse.json({ success: true, withdrawals: paginatedWithdrawals, stats, pagination: { page, pageSize, total, totalPages: Math.ceil(total / pageSize), }, }); } // 获取提醒 function getReminders(userId: string) { const now = new Date(); const weekFromNow = new Date(); weekFromNow.setDate(weekFromNow.getDate() + 7); const myBindings = distributionBindings.filter(b => b.referrerId === userId && b.status === 'active' ); const expiringSoon = myBindings.filter(b => { const expireTime = new Date(b.expireTime); return expireTime <= weekFromNow && expireTime > now; }).map(b => ({ type: 'expiring_soon', binding: b, daysRemaining: Math.ceil((new Date(b.expireTime).getTime() - now.getTime()) / (1000 * 60 * 60 * 24)), message: `用户 ${b.visitorNickname || b.visitorPhone || '未知'} 的绑定将在 ${Math.ceil((new Date(b.expireTime).getTime() - now.getTime()) / (1000 * 60 * 60 * 24))} 天后过期`, })); return NextResponse.json({ success: true, reminders: expiringSoon, count: expiringSoon.length, }); } // 获取分销商信息 function getDistributor(userId: string) { const distributor = distributors.find(d => d.userId === userId); if (!distributor) { return NextResponse.json({ success: true, distributor: null, message: '用户尚未成为分销商', }); } return NextResponse.json({ success: true, distributor }); } // 获取排行榜 function getRanking() { const ranking = [...distributors] .filter(d => d.status === 'active') .sort((a, b) => b.totalEarnings - a.totalEarnings) .slice(0, 10) .map((d, index) => ({ rank: index + 1, distributorId: d.id, nickname: d.nickname, totalEarnings: d.totalEarnings, totalConversions: d.convertedBindings, level: d.level, })); return NextResponse.json({ success: true, ranking }); } // 记录点击 function recordClick(body: { referralCode: string; referrerId: string; visitorId: string; visitorPhone?: string; visitorNickname?: string; source: 'link' | 'miniprogram' | 'poster' | 'qrcode'; }) { const now = new Date(); // 1. 记录点击 const click = { id: generateId('click_'), referralCode: body.referralCode, referrerId: body.referrerId, visitorId: body.visitorId, source: body.source, clickTime: now.toISOString(), }; clickRecords.push(click); // 2. 检查现有绑定 const existingBinding = distributionBindings.find(b => b.visitorId === body.visitorId && b.status === 'active' && new Date(b.expireTime) > now ); if (existingBinding) { // 已有有效绑定,只记录点击 return NextResponse.json({ success: true, message: '点击已记录,用户已被其他分销商绑定', click, binding: null, }); } // 3. 创建新绑定 const expireDate = new Date(now); expireDate.setDate(expireDate.getDate() + BINDING_DAYS); const binding = { id: generateId('bind_'), referrerId: body.referrerId, referrerCode: body.referralCode, visitorId: body.visitorId, visitorPhone: body.visitorPhone, visitorNickname: body.visitorNickname, bindingTime: now.toISOString(), expireTime: expireDate.toISOString(), status: 'active' as const, source: body.source, createdAt: now.toISOString(), }; distributionBindings.push(binding); // 4. 更新分销商统计 const distributorIndex = distributors.findIndex(d => d.userId === body.referrerId); if (distributorIndex !== -1) { distributors[distributorIndex].totalClicks++; distributors[distributorIndex].totalBindings++; distributors[distributorIndex].activeBindings++; } return NextResponse.json({ success: true, message: '点击已记录,绑定创建成功', click, binding, expireTime: expireDate.toISOString(), bindingDays: BINDING_DAYS, }); } // 转化绑定(用户付款) function convertBinding(body: { visitorId: string; orderId: string; orderAmount: number; }) { const now = new Date(); // 查找有效绑定 const bindingIndex = distributionBindings.findIndex(b => b.visitorId === body.visitorId && b.status === 'active' && new Date(b.expireTime) > now ); if (bindingIndex === -1) { return NextResponse.json({ success: false, message: '未找到有效绑定,该订单不计入分销', }); } const binding = distributionBindings[bindingIndex]; // 查找分销商 const distributorIndex = distributors.findIndex(d => d.userId === binding.referrerId); const commissionRate = distributorIndex !== -1 ? distributors[distributorIndex].commissionRate : DEFAULT_COMMISSION_RATE; const commission = body.orderAmount * (commissionRate / 100); // 更新绑定 distributionBindings[bindingIndex] = { ...binding, status: 'converted', convertedAt: now.toISOString(), orderId: body.orderId, orderAmount: body.orderAmount, commission, }; // 更新分销商 if (distributorIndex !== -1) { distributors[distributorIndex].activeBindings--; distributors[distributorIndex].convertedBindings++; distributors[distributorIndex].totalEarnings += commission; distributors[distributorIndex].pendingEarnings += commission; // 检查是否需要自动提现 checkAutoWithdraw(distributors[distributorIndex]); } return NextResponse.json({ success: true, message: '订单转化成功', binding: distributionBindings[bindingIndex], commission, referrerId: binding.referrerId, }); } // 申请提现 function requestWithdraw(body: { userId: string; amount: number; method: 'wechat' | 'alipay'; account: string; accountName: string; }) { // 查找分销商 const distributorIndex = distributors.findIndex(d => d.userId === body.userId); if (distributorIndex === -1) { return NextResponse.json({ success: false, error: '分销商不存在' }, { status: 404 }); } const distributor = distributors[distributorIndex]; if (body.amount < MIN_WITHDRAW_AMOUNT) { return NextResponse.json({ success: false, error: `最低提现金额为 ${MIN_WITHDRAW_AMOUNT} 元` }, { status: 400 }); } if (body.amount > distributor.pendingEarnings) { return NextResponse.json({ success: false, error: '提现金额超过可提现余额' }, { status: 400 }); } // 创建提现记录 const withdrawal = { id: generateId('withdraw_'), distributorId: distributor.id, userId: body.userId, userName: distributor.nickname, amount: body.amount, fee: 0, actualAmount: body.amount, method: body.method, account: body.account, accountName: body.accountName, status: 'pending' as const, isAuto: false, createdAt: new Date().toISOString(), }; withdrawRecords.push(withdrawal); // 扣除待提现金额 distributors[distributorIndex].pendingEarnings -= body.amount; return NextResponse.json({ success: true, message: '提现申请已提交', withdrawal, }); } // 设置自动提现 function setAutoWithdraw(body: { userId: string; enabled: boolean; threshold?: number; account?: { type: 'wechat' | 'alipay'; account: string; name: string; }; }) { const distributorIndex = distributors.findIndex(d => d.userId === body.userId); if (distributorIndex === -1) { return NextResponse.json({ success: false, error: '分销商不存在' }, { status: 404 }); } distributors[distributorIndex] = { ...distributors[distributorIndex], autoWithdraw: body.enabled, autoWithdrawThreshold: body.threshold || distributors[distributorIndex].autoWithdrawThreshold, autoWithdrawAccount: body.account || distributors[distributorIndex].autoWithdrawAccount, }; return NextResponse.json({ success: true, message: body.enabled ? '自动提现已开启' : '自动提现已关闭', distributor: distributors[distributorIndex], }); } // 处理过期绑定 function processExpiredBindings() { const now = new Date(); let expiredCount = 0; distributionBindings.forEach((binding, index) => { if (binding.status === 'active' && new Date(binding.expireTime) <= now) { distributionBindings[index].status = 'expired'; expiredCount++; // 更新分销商统计 const distributorIndex = distributors.findIndex(d => d.userId === binding.referrerId); if (distributorIndex !== -1) { distributors[distributorIndex].activeBindings--; distributors[distributorIndex].expiredBindings++; } } }); return NextResponse.json({ success: true, message: `已处理 ${expiredCount} 个过期绑定`, expiredCount, }); } // 审核通过提现 async function approveWithdraw(body: { withdrawalId: string; reviewedBy?: string }) { const withdrawalIndex = withdrawRecords.findIndex(w => w.id === body.withdrawalId); if (withdrawalIndex === -1) { return NextResponse.json({ success: false, error: '提现记录不存在' }, { status: 404 }); } const withdrawal = withdrawRecords[withdrawalIndex]; if (withdrawal.status !== 'pending') { return NextResponse.json({ success: false, error: '该提现申请已处理' }, { status: 400 }); } // 更新状态为处理中 withdrawRecords[withdrawalIndex].status = 'processing'; // 模拟打款(实际项目中调用支付接口) try { // 模拟延迟 await new Promise(resolve => setTimeout(resolve, 500)); // 打款成功 withdrawRecords[withdrawalIndex] = { ...withdrawRecords[withdrawalIndex], status: 'completed', paymentNo: `PAY${Date.now()}`, paymentTime: new Date().toISOString(), completedAt: new Date().toISOString(), }; // 更新分销商已提现金额 const distributorIndex = distributors.findIndex(d => d.userId === withdrawal.userId); if (distributorIndex !== -1) { distributors[distributorIndex].withdrawnEarnings += withdrawal.amount; } return NextResponse.json({ success: true, message: '打款成功', withdrawal: withdrawRecords[withdrawalIndex], }); } catch (error) { // 打款失败,退还金额 withdrawRecords[withdrawalIndex].status = 'failed'; const distributorIndex = distributors.findIndex(d => d.userId === withdrawal.userId); if (distributorIndex !== -1) { distributors[distributorIndex].pendingEarnings += withdrawal.amount; } return NextResponse.json({ success: false, error: '打款失败' }, { status: 500 }); } } // 拒绝提现 function rejectWithdraw(body: { withdrawalId: string; reason: string; reviewedBy?: string }) { const withdrawalIndex = withdrawRecords.findIndex(w => w.id === body.withdrawalId); if (withdrawalIndex === -1) { return NextResponse.json({ success: false, error: '提现记录不存在' }, { status: 404 }); } const withdrawal = withdrawRecords[withdrawalIndex]; if (withdrawal.status !== 'pending') { return NextResponse.json({ success: false, error: '该提现申请已处理' }, { status: 400 }); } // 更新状态 withdrawRecords[withdrawalIndex] = { ...withdrawal, status: 'rejected', reviewNote: body.reason, }; // 退还金额 const distributorIndex = distributors.findIndex(d => d.userId === withdrawal.userId); if (distributorIndex !== -1) { distributors[distributorIndex].pendingEarnings += withdrawal.amount; } return NextResponse.json({ success: true, message: '提现申请已拒绝', withdrawal: withdrawRecords[withdrawalIndex], }); } // 更新分销商信息 function updateDistributor(body: { userId: string; commissionRate?: number; level?: 'normal' | 'silver' | 'gold' | 'diamond'; status?: 'active' | 'frozen' | 'disabled'; }) { const distributorIndex = distributors.findIndex(d => d.userId === body.userId); if (distributorIndex === -1) { return NextResponse.json({ success: false, error: '分销商不存在' }, { status: 404 }); } distributors[distributorIndex] = { ...distributors[distributorIndex], ...(body.commissionRate !== undefined && { commissionRate: body.commissionRate }), ...(body.level && { level: body.level }), ...(body.status && { status: body.status }), }; return NextResponse.json({ success: true, message: '分销商信息已更新', distributor: distributors[distributorIndex], }); } // 检查自动提现 function checkAutoWithdraw(distributor: typeof distributors[0]) { if (!distributor.autoWithdraw || !distributor.autoWithdrawAccount) { return; } if (distributor.pendingEarnings >= distributor.autoWithdrawThreshold) { // 创建自动提现记录 const withdrawal = { id: generateId('withdraw_'), distributorId: distributor.id, userId: distributor.userId, userName: distributor.nickname, amount: distributor.pendingEarnings, fee: 0, actualAmount: distributor.pendingEarnings, method: distributor.autoWithdrawAccount.type, account: distributor.autoWithdrawAccount.account, accountName: distributor.autoWithdrawAccount.name, status: 'processing' as const, isAuto: true, createdAt: new Date().toISOString(), }; withdrawRecords.push(withdrawal); // 扣除待提现金额 const distributorIndex = distributors.findIndex(d => d.id === distributor.id); if (distributorIndex !== -1) { distributors[distributorIndex].pendingEarnings = 0; } // 模拟打款(实际项目中调用支付接口) processAutoWithdraw(withdrawal.id); } } // 处理自动提现打款 async function processAutoWithdraw(withdrawalId: string) { const withdrawalIndex = withdrawRecords.findIndex(w => w.id === withdrawalId); if (withdrawalIndex === -1) return; try { // 模拟延迟 await new Promise(resolve => setTimeout(resolve, 1000)); // 打款成功 const withdrawal = withdrawRecords[withdrawalIndex]; withdrawRecords[withdrawalIndex] = { ...withdrawal, status: 'completed', paymentNo: `AUTO_PAY${Date.now()}`, paymentTime: new Date().toISOString(), completedAt: new Date().toISOString(), }; // 更新分销商已提现金额 const distributorIndex = distributors.findIndex(d => d.userId === withdrawal.userId); if (distributorIndex !== -1) { distributors[distributorIndex].withdrawnEarnings += withdrawal.amount; } console.log(`自动提现成功: ${withdrawal.userName}, 金额: ¥${withdrawal.amount}`); } catch (error) { // 打款失败 withdrawRecords[withdrawalIndex].status = 'failed'; const withdrawal = withdrawRecords[withdrawalIndex]; const distributorIndex = distributors.findIndex(d => d.userId === withdrawal.userId); if (distributorIndex !== -1) { distributors[distributorIndex].pendingEarnings += withdrawal.amount; } console.error(`自动提现失败: ${withdrawal.userName}`); } }