"use client" import { useState, useEffect } from "react" import { Users, TrendingUp, Clock, Wallet, Search, RefreshCw, CheckCircle, XCircle, Zap, Calendar, DollarSign, Link2, Eye } from "lucide-react" import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" import { Badge } from "@/components/ui/badge" // 类型定义 interface DistributionOverview { todayClicks: number todayBindings: number todayConversions: number todayEarnings: number monthClicks: number monthBindings: number monthConversions: number monthEarnings: number totalClicks: number totalBindings: number totalConversions: number totalEarnings: number expiringBindings: number pendingWithdrawals: number pendingWithdrawAmount: number conversionRate: string totalDistributors: number activeDistributors: number } interface Binding { id: string referrer_id: string referrer_name?: string referrer_code: string referee_id: string referee_phone?: string referee_nickname?: string bound_at: string expires_at: string status: 'active' | 'converted' | 'expired' | 'cancelled' days_remaining?: number commission?: number order_amount?: number source?: string } interface Withdrawal { id: string userId?: string user_id?: string // 兼容旧格式 userNickname?: string user_name?: string // 兼容旧格式 userPhone?: string userAvatar?: string referralCode?: string amount: number method?: 'wechat' | 'alipay' account?: string name?: string status: 'pending' | 'success' | 'failed' | 'completed' | 'rejected' // 支持数据库和前端状态 wechatOpenid?: string transactionId?: string errorMessage?: string createdAt?: string created_at?: string // 兼容旧格式 processedAt?: string completed_at?: string // 兼容旧格式 userCommissionInfo?: { totalCommission: number withdrawnEarnings: number pendingWithdrawals: number availableAfterThis: number } } interface User { id: string nickname: string phone: string referral_code: string has_full_book: boolean earnings: number pending_earnings: number withdrawn_earnings: number referral_count: number created_at: string } // 订单类型(用于交易中心的订单管理标签) interface Order { id: string userId: string userNickname?: string userPhone?: string productType: 'section' | 'fullbook' | 'match' // API 返回的字段名 type?: 'section' | 'fullbook' | 'match' // 兼容旧字段名 productId?: string sectionId?: string // 兼容旧字段名 bookName?: string // 书名 chapterTitle?: string // 章标题 sectionTitle?: string // 节标题 amount: number status: 'pending' | 'completed' | 'failed' | 'paid' | 'created' // 增加更多状态 paymentMethod?: string referrerEarnings?: number referrerId?: string | null referrerNickname?: string | null // 推荐人昵称 referrerCode?: string | null // 推荐码 /** 下单时记录的邀请码(订单表 referral_code) */ referralCode?: string | null createdAt: string } export default function DistributionAdminPage() { // 标签页:数据概览、订单管理、绑定管理、提现审核 const [activeTab, setActiveTab] = useState<'overview' | 'orders' | 'bindings' | 'withdrawals'>('overview') const [orders, setOrders] = useState([]) const [overview, setOverview] = useState(null) const [bindings, setBindings] = useState([]) const [withdrawals, setWithdrawals] = useState([]) const [users, setUsers] = useState([]) const [loading, setLoading] = useState(true) const [searchTerm, setSearchTerm] = useState('') const [statusFilter, setStatusFilter] = useState('all') // 标记哪些数据已加载 const [loadedTabs, setLoadedTabs] = useState>(new Set()) // 初次加载:加载概览和用户数据 useEffect(() => { loadInitialData() }, []) // 切换tab:按需加载对应tab的数据 useEffect(() => { loadTabData(activeTab) }, [activeTab]) // 初始加载:概览 + 用户数据 const loadInitialData = async () => { console.log('[Admin] 加载初始数据...') // 加载概览数据 try { const overviewRes = await fetch('/api/admin/distribution/overview') if (overviewRes.ok) { const overviewData = await overviewRes.json() if (overviewData.success && overviewData.overview) { setOverview(overviewData.overview) console.log('[Admin] 概览数据加载成功') } } } catch (error) { console.error('[Admin] 概览接口异常:', error) } // 加载用户数据(多个tab都需要用到) try { const usersRes = await fetch('/api/db/users') if (usersRes.ok) { const usersData = await usersRes.json() setUsers(usersData.users || []) console.log('[Admin] 用户数据加载成功') } } catch (error) { console.error('[Admin] 用户数据加载失败:', error) } } // 按需加载tab数据 const loadTabData = async (tab: string) => { // 如果已加载过且不是刷新操作,跳过 if (loadedTabs.has(tab)) { console.log(`[Admin] ${tab} 数据已缓存,跳过加载`) return } setLoading(true) console.log(`[Admin] 加载 ${tab} 数据...`) try { const usersArr = users // 使用已加载的用户数据 // 根据不同tab加载对应数据 switch (tab) { case 'overview': // 概览tab不需要加载额外数据,已在初始化时加载 break case 'orders': // 加载订单数据 try { const ordersRes = await fetch('/api/orders') if (!ordersRes.ok) { console.error('[Admin] 订单接口错误:', ordersRes.status) setOrders([]) } else { const ordersData = await ordersRes.json() if (ordersData.success && ordersData.orders) { const enrichedOrders = ordersData.orders.map((order: Order) => { const user = usersArr.find((u: User) => u.id === order.userId) const referrer = order.referrerId ? usersArr.find((u: User) => u.id === order.referrerId) : null return { ...order, amount: parseFloat(order.amount as any) || 0, userNickname: user?.nickname || order.userNickname || '未知用户', userPhone: user?.phone || order.userPhone || '-', referrerNickname: referrer?.nickname || null, referrerCode: referrer?.referral_code || null, type: order.productType || order.type, } }) setOrders(enrichedOrders) console.log('[Admin] 订单数据加载成功:', enrichedOrders.length, '条') } else { setOrders([]) } } } catch (error) { console.error('[Admin] 加载订单数据失败:', error) setOrders([]) } break case 'bindings': // 加载绑定数据 try { const bindingsRes = await fetch('/api/db/distribution') if (bindingsRes.ok) { const bindingsData = await bindingsRes.json() setBindings(bindingsData.bindings || []) console.log('[Admin] 绑定数据加载成功:', bindingsData.bindings?.length || 0, '条') } else { setBindings([]) } } catch (error) { console.error('[Admin] 加载绑定数据失败:', error) setBindings([]) } break case 'withdrawals': // 加载提现数据 try { console.log('[Admin] 请求提现数据...') const withdrawalsRes = await fetch('/api/admin/withdrawals') console.log('[Admin] 提现接口响应状态:', withdrawalsRes.status, withdrawalsRes.statusText) if (withdrawalsRes.ok) { const withdrawalsData = await withdrawalsRes.json() console.log('[Admin] 提现接口返回数据:', withdrawalsData) if (withdrawalsData.success) { // 数据映射:统一字段名 const formattedWithdrawals = (withdrawalsData.withdrawals || []).map((w: any) => ({ ...w, user_id: w.userId || w.user_id, user_name: w.userNickname || w.user_name, created_at: w.createdAt || w.created_at, completed_at: w.processedAt || w.completed_at, account: w.account ?? '未绑定微信号', status: w.status === 'success' ? 'completed' : (w.status === 'failed' ? 'rejected' : w.status) })) setWithdrawals(formattedWithdrawals) console.log('[Admin] 提现数据加载成功:', formattedWithdrawals.length, '条') } else { console.error('[Admin] 提现接口返回失败:', withdrawalsData.error || withdrawalsData.message) alert(`获取提现记录失败: ${withdrawalsData.error || withdrawalsData.message || '未知错误'}`) setWithdrawals([]) } } else { // HTTP 错误 const errorText = await withdrawalsRes.text() console.error('[Admin] 提现接口HTTP错误:', withdrawalsRes.status, errorText) try { const errorData = JSON.parse(errorText) alert(`获取提现记录失败 (${withdrawalsRes.status}): ${errorData.error || errorData.message || '服务器错误'}`) } catch { alert(`获取提现记录失败 (${withdrawalsRes.status}): ${errorText || '服务器错误'}`) } setWithdrawals([]) } } catch (error: any) { console.error('[Admin] 加载提现数据异常:', error) alert(`加载提现数据失败: ${error.message || '网络错误'}`) setWithdrawals([]) } break } // 标记该tab已加载 setLoadedTabs(prev => new Set(prev).add(tab)) } catch (error) { console.error(`[Admin] 加载 ${tab} 数据失败:`, error) } finally { setLoading(false) } } const refreshCurrentTab = () => { setLoadedTabs((prev) => { const newSet = new Set(prev) newSet.delete(activeTab) return newSet }) if (activeTab === 'overview') { loadInitialData() } loadTabData(activeTab) } const handleApproveWithdrawal = async (id: string) => { if (!confirm('确认审核通过并打款?')) return try { await fetch('/api/admin/withdrawals', { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ id, action: 'approve' }) }) refreshCurrentTab() } catch (error) { console.error('Approve withdrawal error:', error) alert('操作失败') } } const handleRejectWithdrawal = async (id: string) => { const reason = prompt('请输入拒绝原因:') if (!reason) return try { await fetch('/api/admin/withdrawals', { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ id, action: 'reject', errorMessage: reason }) }) refreshCurrentTab() } catch (error) { console.error('Reject withdrawal error:', error) alert('操作失败') } } // 获取状态徽章 const getStatusBadge = (status: string) => { const styles: Record = { active: 'bg-green-500/20 text-green-400', converted: 'bg-blue-500/20 text-blue-400', expired: 'bg-gray-500/20 text-gray-400', cancelled: 'bg-red-500/20 text-red-400', pending: 'bg-orange-500/20 text-orange-400', processing: 'bg-blue-500/20 text-blue-400', completed: 'bg-green-500/20 text-green-400', rejected: 'bg-red-500/20 text-red-400', } const labels: Record = { active: '有效', converted: '已转化', expired: '已过期', cancelled: '已取消', pending: '待审核', processing: '处理中', completed: '已完成', rejected: '已拒绝', } return ( {labels[status] || status} ) } // 过滤数据 const filteredBindings = bindings.filter(b => { if (statusFilter !== 'all' && b.status !== statusFilter) return false if (searchTerm) { const term = searchTerm.toLowerCase() return ( b.referee_nickname?.toLowerCase().includes(term) || b.referee_phone?.includes(term) || b.referrer_name?.toLowerCase().includes(term) || b.referrer_code?.toLowerCase().includes(term) ) } return true }) const filteredWithdrawals = withdrawals.filter(w => { if (statusFilter !== 'all' && w.status !== statusFilter) return false if (searchTerm) { const term = searchTerm.toLowerCase() return ( w.user_name?.toLowerCase().includes(term) || w.account?.toLowerCase().includes(term) ) } return true }) return (
{/* 页面标题 */}

交易中心

统一管理:订单、分销绑定、提现审核

{/* Tab切换 - 交易中心:合并分销+订单+提现 */}
{[ { key: 'overview', label: '数据概览', icon: TrendingUp }, { key: 'orders', label: '订单管理', icon: DollarSign }, { key: 'bindings', label: '绑定管理', icon: Link2 }, { key: 'withdrawals', label: '提现审核', icon: Wallet }, ].map(tab => ( ))}
{loading ? (
加载中...
) : ( <> {/* 数据概览 */} {activeTab === 'overview' && overview && (
{/* 今日数据 */}

今日点击

{overview.todayClicks}

今日绑定

{overview.todayBindings}

今日转化

{overview.todayConversions}

今日佣金

¥{overview.todayEarnings.toFixed(2)}

{/* 重要提醒 */}

即将过期绑定

{overview.expiringBindings} 个

7天内到期,需关注转化

待审核提现

{overview.pendingWithdrawals} 笔

共 ¥{overview.pendingWithdrawAmount.toFixed(2)}

{/* 本月/累计统计 */}
本月统计

点击量

{overview.monthClicks}

绑定数

{overview.monthBindings}

转化数

{overview.monthConversions}

佣金

¥{overview.monthEarnings.toFixed(2)}

累计统计

总点击

{overview.totalClicks.toLocaleString()}

总绑定

{overview.totalBindings.toLocaleString()}

总转化

{overview.totalConversions}

总佣金

¥{overview.totalEarnings.toFixed(2)}

点击转化率 {overview.conversionRate}%
{/* 推广统计 */} 推广统计

{overview.totalDistributors}

推广用户数

{overview.activeDistributors}

有收益用户

90%

佣金比例

30天

绑定有效期

)} {/* 订单管理 - 新增标签页 */} {activeTab === 'orders' && (
setSearchTerm(e.target.value)} placeholder="搜索订单号、用户名、手机号..." className="pl-10 bg-[#0f2137] border-gray-700 text-white" />
{orders.length === 0 ? (
暂无订单数据
) : (
{orders .filter(order => { if (statusFilter !== 'all' && order.status !== statusFilter) return false if (searchTerm) { const term = searchTerm.toLowerCase() return ( order.id?.toLowerCase().includes(term) || order.userNickname?.toLowerCase().includes(term) || order.userPhone?.includes(term) || order.sectionTitle?.toLowerCase().includes(term) || order.chapterTitle?.toLowerCase().includes(term) || order.bookName?.toLowerCase().includes(term) || (order.referrerCode && order.referrerCode.toLowerCase().includes(term)) || (order.referrerNickname && order.referrerNickname.toLowerCase().includes(term)) ) } return true }) .map(order => ( ))}
订单号 用户 商品 金额 支付方式 状态 推荐人/邀请码 分销佣金 下单时间
{order.id?.slice(0, 12)}...

{order.userNickname}

{order.userPhone}

{(() => { const type = order.productType || order.type if (type === 'fullbook') { return `${order.bookName || '《底层逻辑》'} - 全本` } else if (type === 'match') { return '匹配次数购买' } else { // section - 单章购买 return `${order.bookName || '《底层逻辑》'} - ${order.sectionTitle || order.chapterTitle || `章节${order.productId || order.sectionId || ''}`}` } })()}

{(() => { const type = order.productType || order.type if (type === 'fullbook') { return '全书解锁' } else if (type === 'match') { return '功能权益' } else { return order.chapterTitle || '单章购买' } })()}

¥{typeof order.amount === 'number' ? order.amount.toFixed(2) : parseFloat(order.amount || '0').toFixed(2)} {order.paymentMethod === 'wechat' ? '微信支付' : order.paymentMethod === 'alipay' ? '支付宝' : order.paymentMethod || '微信支付'} {order.status === 'completed' || order.status === 'paid' ? ( 已完成 ) : order.status === 'pending' || order.status === 'created' ? ( 待支付 ) : ( 已失败 )} {order.referrerId || order.referralCode ? ( {order.referrerNickname || order.referralCode || order.referrerCode || order.referrerId?.slice(0, 8)} {(order.referralCode || order.referrerCode) ? ` (${order.referralCode || order.referrerCode})` : ''} ) : '-'} {order.referrerEarnings ? `¥${(typeof order.referrerEarnings === 'number' ? order.referrerEarnings : parseFloat(order.referrerEarnings)).toFixed(2)}` : '-'} {order.createdAt ? new Date(order.createdAt).toLocaleString('zh-CN') : '-'}
)}
)} {/* 绑定管理 */} {activeTab === 'bindings' && (
setSearchTerm(e.target.value)} placeholder="搜索用户昵称、手机号、推广码..." className="pl-10 bg-[#0f2137] border-gray-700 text-white" />
{filteredBindings.length === 0 ? (
暂无绑定数据
) : (
{filteredBindings.map(binding => ( ))}
访客 分销商 绑定时间 到期时间 状态 佣金

{binding.referee_nickname || '匿名用户'}

{binding.referee_phone}

{binding.referrer_name || '-'}

{binding.referrer_code}

{binding.bound_at ? new Date(binding.bound_at).toLocaleDateString('zh-CN') : '-'} {binding.expires_at ? new Date(binding.expires_at).toLocaleDateString('zh-CN') : '-'} {getStatusBadge(binding.status)} {binding.commission ? ( ¥{binding.commission.toFixed(2)} ) : ( - )}
)}
)} {/* 提现审核 */} {activeTab === 'withdrawals' && (
setSearchTerm(e.target.value)} placeholder="搜索用户名称、账号..." className="pl-10 bg-[#0f2137] border-gray-700 text-white" />
{filteredWithdrawals.length === 0 ? (
暂无提现记录
) : (
{filteredWithdrawals.map(withdrawal => ( ))}
申请人 金额 收款方式 收款账号 申请时间 状态 操作
{withdrawal.userAvatar ? ( ) : (
{(withdrawal.user_name || withdrawal.name || '?').slice(0, 1)}
)}

{withdrawal.user_name || withdrawal.name}

¥{withdrawal.amount.toFixed(2)} {withdrawal.method === 'wechat' ? '微信' : '支付宝'}

{withdrawal.account}

{withdrawal.name}

{withdrawal.created_at ? new Date(withdrawal.created_at).toLocaleString('zh-CN') : '-'} {getStatusBadge(withdrawal.status)} {withdrawal.status === 'pending' && (
)}
)}
)} )}
) }