Files
soul/app/admin/distribution/page.tsx

822 lines
36 KiB
TypeScript
Raw Normal View History

"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
user_id: string
user_name?: string
amount: number
method: 'wechat' | 'alipay'
account: string
name: string
status: 'pending' | 'completed' | 'rejected'
created_at: string
completed_at?: string
}
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
}
export default function DistributionAdminPage() {
const [activeTab, setActiveTab] = useState<'overview' | 'bindings' | 'withdrawals' | 'distributors'>('overview')
const [overview, setOverview] = useState<DistributionOverview | null>(null)
const [bindings, setBindings] = useState<Binding[]>([])
const [withdrawals, setWithdrawals] = useState<Withdrawal[]>([])
const [distributors, setDistributors] = useState<User[]>([])
const [loading, setLoading] = useState(true)
const [searchTerm, setSearchTerm] = useState('')
const [statusFilter, setStatusFilter] = useState<string>('all')
useEffect(() => {
loadData()
}, [activeTab])
const loadData = async () => {
setLoading(true)
try {
// 加载用户数据(分销商)
const usersRes = await fetch('/api/db/users')
const usersData = await usersRes.json()
const users = usersData.users || []
setDistributors(users)
// 加载绑定数据
const bindingsRes = await fetch('/api/db/distribution')
const bindingsData = await bindingsRes.json()
setBindings(bindingsData.bindings || [])
// 加载提现数据
const withdrawalsRes = await fetch('/api/db/withdrawals')
const withdrawalsData = await withdrawalsRes.json()
setWithdrawals(withdrawalsData.withdrawals || [])
// 加载购买记录
const purchasesRes = await fetch('/api/db/purchases')
const purchasesData = await purchasesRes.json()
const purchases = purchasesData.purchases || []
// 计算概览数据
const today = new Date().toISOString().split('T')[0]
const monthStart = new Date(new Date().getFullYear(), new Date().getMonth(), 1).toISOString()
const todayBindings = (bindingsData.bindings || []).filter((b: Binding) =>
b.bound_at?.startsWith(today)
).length
const monthBindings = (bindingsData.bindings || []).filter((b: Binding) =>
b.bound_at >= monthStart
).length
const todayConversions = (bindingsData.bindings || []).filter((b: Binding) =>
b.status === 'converted' && b.bound_at?.startsWith(today)
).length
const monthConversions = (bindingsData.bindings || []).filter((b: Binding) =>
b.status === 'converted' && b.bound_at >= monthStart
).length
const totalConversions = (bindingsData.bindings || []).filter((b: Binding) =>
b.status === 'converted'
).length
// 计算佣金
const totalEarnings = users.reduce((sum: number, u: User) => sum + (u.earnings || 0), 0)
const pendingWithdrawAmount = (withdrawalsData.withdrawals || [])
.filter((w: Withdrawal) => w.status === 'pending')
.reduce((sum: number, w: Withdrawal) => sum + w.amount, 0)
// 即将过期绑定7天内
const sevenDaysLater = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString()
const expiringBindings = (bindingsData.bindings || []).filter((b: Binding) =>
b.status === 'active' && b.expires_at <= sevenDaysLater && b.expires_at > new Date().toISOString()
).length
setOverview({
todayClicks: Math.floor(Math.random() * 100) + 50, // 暂用模拟数据
todayBindings,
todayConversions,
todayEarnings: purchases.filter((p: any) => p.created_at?.startsWith(today))
.reduce((sum: number, p: any) => sum + (p.referrer_earnings || 0), 0),
monthClicks: Math.floor(Math.random() * 1000) + 500,
monthBindings,
monthConversions,
monthEarnings: purchases.filter((p: any) => p.created_at >= monthStart)
.reduce((sum: number, p: any) => sum + (p.referrer_earnings || 0), 0),
totalClicks: Math.floor(Math.random() * 5000) + 2000,
totalBindings: (bindingsData.bindings || []).length,
totalConversions,
totalEarnings,
expiringBindings,
pendingWithdrawals: (withdrawalsData.withdrawals || []).filter((w: Withdrawal) => w.status === 'pending').length,
pendingWithdrawAmount,
conversionRate: ((bindingsData.bindings || []).length > 0
? (totalConversions / (bindingsData.bindings || []).length * 100).toFixed(2)
: '0'),
totalDistributors: users.filter((u: User) => u.referral_code).length,
activeDistributors: users.filter((u: User) => (u.earnings || 0) > 0).length,
})
} catch (error) {
console.error('Load distribution data error:', error)
// 如果加载失败,设置空数据
setOverview({
todayClicks: 0,
todayBindings: 0,
todayConversions: 0,
todayEarnings: 0,
monthClicks: 0,
monthBindings: 0,
monthConversions: 0,
monthEarnings: 0,
totalClicks: 0,
totalBindings: 0,
totalConversions: 0,
totalEarnings: 0,
expiringBindings: 0,
pendingWithdrawals: 0,
pendingWithdrawAmount: 0,
conversionRate: '0',
totalDistributors: 0,
activeDistributors: 0,
})
} finally {
setLoading(false)
}
}
// 处理提现审核
const handleApproveWithdrawal = async (id: string) => {
if (!confirm('确认审核通过并打款?')) return
try {
await fetch('/api/db/withdrawals', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ id, status: 'completed' })
})
loadData()
} catch (error) {
console.error('Approve withdrawal error:', error)
alert('操作失败')
}
}
const handleRejectWithdrawal = async (id: string) => {
const reason = prompt('请输入拒绝原因:')
if (!reason) return
try {
await fetch('/api/db/withdrawals', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ id, status: 'rejected' })
})
loadData()
} catch (error) {
console.error('Reject withdrawal error:', error)
alert('操作失败')
}
}
// 获取状态徽章
const getStatusBadge = (status: string) => {
const styles: Record<string, string> = {
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',
completed: 'bg-green-500/20 text-green-400',
rejected: 'bg-red-500/20 text-red-400',
}
const labels: Record<string, string> = {
active: '有效',
converted: '已转化',
expired: '已过期',
cancelled: '已取消',
pending: '待审核',
completed: '已完成',
rejected: '已拒绝',
}
return (
<Badge className={`${styles[status] || 'bg-gray-500/20 text-gray-400'} border-0`}>
{labels[status] || status}
</Badge>
)
}
// 过滤数据
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
})
const filteredDistributors = distributors.filter(d => {
if (!d.referral_code) return false
if (searchTerm) {
const term = searchTerm.toLowerCase()
return (
d.nickname?.toLowerCase().includes(term) ||
d.phone?.includes(term) ||
d.referral_code?.toLowerCase().includes(term)
)
}
return true
})
return (
<div className="p-8 max-w-7xl mx-auto">
{/* 页面标题 */}
<div className="flex items-center justify-between mb-8">
<div>
<h1 className="text-2xl font-bold text-white"></h1>
<p className="text-gray-400 mt-1"></p>
</div>
<Button
onClick={loadData}
disabled={loading}
variant="outline"
className="border-gray-700 text-gray-300 hover:bg-gray-800"
>
<RefreshCw className={`w-4 h-4 mr-2 ${loading ? 'animate-spin' : ''}`} />
</Button>
</div>
{/* Tab切换 */}
<div className="flex gap-2 mb-6 border-b border-gray-700 pb-4">
{[
{ key: 'overview', label: '数据概览', icon: TrendingUp },
{ key: 'bindings', label: '绑定管理', icon: Link2 },
{ key: 'withdrawals', label: '提现审核', icon: Wallet },
{ key: 'distributors', label: '分销商', icon: Users },
].map(tab => (
<button
key={tab.key}
onClick={() => {
setActiveTab(tab.key as typeof activeTab)
setStatusFilter('all')
setSearchTerm('')
}}
className={`flex items-center gap-2 px-4 py-2 rounded-lg text-sm font-medium transition-colors ${
activeTab === tab.key
? 'bg-[#38bdac] text-white'
: 'text-gray-400 hover:text-white hover:bg-gray-800'
}`}
>
<tab.icon className="w-4 h-4" />
{tab.label}
</button>
))}
</div>
{loading ? (
<div className="flex items-center justify-center py-20">
<RefreshCw className="w-8 h-8 text-[#38bdac] animate-spin" />
<span className="ml-2 text-gray-400">...</span>
</div>
) : (
<>
{/* 数据概览 */}
{activeTab === 'overview' && overview && (
<div className="space-y-6">
{/* 今日数据 */}
<div className="grid grid-cols-4 gap-4">
<Card className="bg-[#0f2137] border-gray-700/50">
<CardContent className="p-6">
<div className="flex items-center justify-between">
<div>
<p className="text-gray-400 text-sm"></p>
<p className="text-2xl font-bold text-white mt-1">{overview.todayClicks}</p>
</div>
<div className="w-12 h-12 rounded-xl bg-blue-500/20 flex items-center justify-center">
<Eye className="w-6 h-6 text-blue-400" />
</div>
</div>
</CardContent>
</Card>
<Card className="bg-[#0f2137] border-gray-700/50">
<CardContent className="p-6">
<div className="flex items-center justify-between">
<div>
<p className="text-gray-400 text-sm"></p>
<p className="text-2xl font-bold text-white mt-1">{overview.todayBindings}</p>
</div>
<div className="w-12 h-12 rounded-xl bg-green-500/20 flex items-center justify-center">
<Link2 className="w-6 h-6 text-green-400" />
</div>
</div>
</CardContent>
</Card>
<Card className="bg-[#0f2137] border-gray-700/50">
<CardContent className="p-6">
<div className="flex items-center justify-between">
<div>
<p className="text-gray-400 text-sm"></p>
<p className="text-2xl font-bold text-white mt-1">{overview.todayConversions}</p>
</div>
<div className="w-12 h-12 rounded-xl bg-purple-500/20 flex items-center justify-center">
<CheckCircle className="w-6 h-6 text-purple-400" />
</div>
</div>
</CardContent>
</Card>
<Card className="bg-[#0f2137] border-gray-700/50">
<CardContent className="p-6">
<div className="flex items-center justify-between">
<div>
<p className="text-gray-400 text-sm"></p>
<p className="text-2xl font-bold text-[#38bdac] mt-1">¥{overview.todayEarnings.toFixed(2)}</p>
</div>
<div className="w-12 h-12 rounded-xl bg-[#38bdac]/20 flex items-center justify-center">
<DollarSign className="w-6 h-6 text-[#38bdac]" />
</div>
</div>
</CardContent>
</Card>
</div>
{/* 重要提醒 */}
<div className="grid grid-cols-2 gap-4">
<Card className="bg-orange-500/10 border-orange-500/30">
<CardContent className="p-6">
<div className="flex items-center gap-4">
<div className="w-12 h-12 rounded-xl bg-orange-500/20 flex items-center justify-center">
<Clock className="w-6 h-6 text-orange-400" />
</div>
<div className="flex-1">
<p className="text-orange-300 font-medium"></p>
<p className="text-2xl font-bold text-white">{overview.expiringBindings} </p>
<p className="text-orange-300/60 text-sm">7</p>
</div>
</div>
</CardContent>
</Card>
<Card className="bg-blue-500/10 border-blue-500/30">
<CardContent className="p-6">
<div className="flex items-center gap-4">
<div className="w-12 h-12 rounded-xl bg-blue-500/20 flex items-center justify-center">
<Wallet className="w-6 h-6 text-blue-400" />
</div>
<div className="flex-1">
<p className="text-blue-300 font-medium"></p>
<p className="text-2xl font-bold text-white">{overview.pendingWithdrawals} </p>
<p className="text-blue-300/60 text-sm"> ¥{overview.pendingWithdrawAmount.toFixed(2)}</p>
</div>
<Button
onClick={() => setActiveTab('withdrawals')}
variant="outline"
className="border-blue-500/50 text-blue-400 hover:bg-blue-500/20"
>
</Button>
</div>
</CardContent>
</Card>
</div>
{/* 本月/累计统计 */}
<div className="grid grid-cols-2 gap-6">
<Card className="bg-[#0f2137] border-gray-700/50">
<CardHeader>
<CardTitle className="text-white flex items-center gap-2">
<Calendar className="w-5 h-5 text-[#38bdac]" />
</CardTitle>
</CardHeader>
<CardContent>
<div className="grid grid-cols-2 gap-4">
<div className="p-4 bg-white/5 rounded-lg">
<p className="text-gray-400 text-sm"></p>
<p className="text-xl font-bold text-white">{overview.monthClicks}</p>
</div>
<div className="p-4 bg-white/5 rounded-lg">
<p className="text-gray-400 text-sm"></p>
<p className="text-xl font-bold text-white">{overview.monthBindings}</p>
</div>
<div className="p-4 bg-white/5 rounded-lg">
<p className="text-gray-400 text-sm"></p>
<p className="text-xl font-bold text-white">{overview.monthConversions}</p>
</div>
<div className="p-4 bg-white/5 rounded-lg">
<p className="text-gray-400 text-sm"></p>
<p className="text-xl font-bold text-[#38bdac]">¥{overview.monthEarnings.toFixed(2)}</p>
</div>
</div>
</CardContent>
</Card>
<Card className="bg-[#0f2137] border-gray-700/50">
<CardHeader>
<CardTitle className="text-white flex items-center gap-2">
<TrendingUp className="w-5 h-5 text-[#38bdac]" />
</CardTitle>
</CardHeader>
<CardContent>
<div className="grid grid-cols-2 gap-4">
<div className="p-4 bg-white/5 rounded-lg">
<p className="text-gray-400 text-sm"></p>
<p className="text-xl font-bold text-white">{overview.totalClicks.toLocaleString()}</p>
</div>
<div className="p-4 bg-white/5 rounded-lg">
<p className="text-gray-400 text-sm"></p>
<p className="text-xl font-bold text-white">{overview.totalBindings.toLocaleString()}</p>
</div>
<div className="p-4 bg-white/5 rounded-lg">
<p className="text-gray-400 text-sm"></p>
<p className="text-xl font-bold text-white">{overview.totalConversions}</p>
</div>
<div className="p-4 bg-white/5 rounded-lg">
<p className="text-gray-400 text-sm"></p>
<p className="text-xl font-bold text-[#38bdac]">¥{overview.totalEarnings.toFixed(2)}</p>
</div>
</div>
<div className="mt-4 p-4 bg-[#38bdac]/10 rounded-lg flex items-center justify-between">
<span className="text-gray-300"></span>
<span className="text-[#38bdac] font-bold text-xl">{overview.conversionRate}%</span>
</div>
</CardContent>
</Card>
</div>
{/* 分销商统计 */}
<Card className="bg-[#0f2137] border-gray-700/50">
<CardHeader>
<CardTitle className="text-white flex items-center gap-2">
<Users className="w-5 h-5 text-[#38bdac]" />
</CardTitle>
</CardHeader>
<CardContent>
<div className="grid grid-cols-4 gap-4">
<div className="p-4 bg-white/5 rounded-lg text-center">
<p className="text-3xl font-bold text-white">{overview.totalDistributors}</p>
<p className="text-gray-400 text-sm mt-1"></p>
</div>
<div className="p-4 bg-white/5 rounded-lg text-center">
<p className="text-3xl font-bold text-green-400">{overview.activeDistributors}</p>
<p className="text-gray-400 text-sm mt-1"></p>
</div>
<div className="p-4 bg-white/5 rounded-lg text-center">
<p className="text-3xl font-bold text-[#38bdac]">90%</p>
<p className="text-gray-400 text-sm mt-1"></p>
</div>
<div className="p-4 bg-white/5 rounded-lg text-center">
<p className="text-3xl font-bold text-orange-400">30</p>
<p className="text-gray-400 text-sm mt-1"></p>
</div>
</div>
</CardContent>
</Card>
</div>
)}
{/* 绑定管理 */}
{activeTab === 'bindings' && (
<div className="space-y-4">
<div className="flex gap-4">
<div className="relative flex-1">
<Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400" />
<Input
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
placeholder="搜索用户昵称、手机号、推广码..."
className="pl-10 bg-[#0f2137] border-gray-700 text-white"
/>
</div>
<select
value={statusFilter}
onChange={(e) => setStatusFilter(e.target.value)}
className="px-4 py-2 bg-[#0f2137] border border-gray-700 rounded-lg text-white"
>
<option value="all"></option>
<option value="active"></option>
<option value="converted"></option>
<option value="expired"></option>
</select>
</div>
<Card className="bg-[#0f2137] border-gray-700/50">
<CardContent className="p-0">
{filteredBindings.length === 0 ? (
<div className="py-12 text-center text-gray-500"></div>
) : (
<div className="overflow-x-auto">
<table className="w-full text-sm">
<thead>
<tr className="bg-[#0a1628] text-gray-400">
<th className="p-4 text-left font-medium">访</th>
<th className="p-4 text-left font-medium"></th>
<th className="p-4 text-left font-medium"></th>
<th className="p-4 text-left font-medium"></th>
<th className="p-4 text-left font-medium"></th>
<th className="p-4 text-left font-medium"></th>
</tr>
</thead>
<tbody className="divide-y divide-gray-700/50">
{filteredBindings.map(binding => (
<tr key={binding.id} className="hover:bg-[#0a1628] transition-colors">
<td className="p-4">
<div>
<p className="text-white font-medium">{binding.referee_nickname || '匿名用户'}</p>
<p className="text-gray-500 text-xs">{binding.referee_phone}</p>
</div>
</td>
<td className="p-4">
<div>
<p className="text-white">{binding.referrer_name || '-'}</p>
<p className="text-gray-500 text-xs font-mono">{binding.referrer_code}</p>
</div>
</td>
<td className="p-4 text-gray-400">
{binding.bound_at ? new Date(binding.bound_at).toLocaleDateString('zh-CN') : '-'}
</td>
<td className="p-4 text-gray-400">
{binding.expires_at ? new Date(binding.expires_at).toLocaleDateString('zh-CN') : '-'}
</td>
<td className="p-4">{getStatusBadge(binding.status)}</td>
<td className="p-4">
{binding.commission ? (
<span className="text-[#38bdac] font-medium">¥{binding.commission.toFixed(2)}</span>
) : (
<span className="text-gray-500">-</span>
)}
</td>
</tr>
))}
</tbody>
</table>
</div>
)}
</CardContent>
</Card>
</div>
)}
{/* 提现审核 */}
{activeTab === 'withdrawals' && (
<div className="space-y-4">
<div className="flex gap-4">
<div className="relative flex-1">
<Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400" />
<Input
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
placeholder="搜索用户名称、账号..."
className="pl-10 bg-[#0f2137] border-gray-700 text-white"
/>
</div>
<select
value={statusFilter}
onChange={(e) => setStatusFilter(e.target.value)}
className="px-4 py-2 bg-[#0f2137] border border-gray-700 rounded-lg text-white"
>
<option value="all"></option>
<option value="pending"></option>
<option value="completed"></option>
<option value="rejected"></option>
</select>
</div>
<Card className="bg-[#0f2137] border-gray-700/50">
<CardContent className="p-0">
{filteredWithdrawals.length === 0 ? (
<div className="py-12 text-center text-gray-500"></div>
) : (
<div className="overflow-x-auto">
<table className="w-full text-sm">
<thead>
<tr className="bg-[#0a1628] text-gray-400">
<th className="p-4 text-left font-medium"></th>
<th className="p-4 text-left font-medium"></th>
<th className="p-4 text-left font-medium"></th>
<th className="p-4 text-left font-medium"></th>
<th className="p-4 text-left font-medium"></th>
<th className="p-4 text-left font-medium"></th>
<th className="p-4 text-right font-medium"></th>
</tr>
</thead>
<tbody className="divide-y divide-gray-700/50">
{filteredWithdrawals.map(withdrawal => (
<tr key={withdrawal.id} className="hover:bg-[#0a1628] transition-colors">
<td className="p-4">
<p className="text-white font-medium">{withdrawal.user_name || withdrawal.name}</p>
</td>
<td className="p-4">
<span className="text-[#38bdac] font-bold">¥{withdrawal.amount.toFixed(2)}</span>
</td>
<td className="p-4">
<Badge className={
withdrawal.method === 'wechat'
? 'bg-green-500/20 text-green-400 border-0'
: 'bg-blue-500/20 text-blue-400 border-0'
}>
{withdrawal.method === 'wechat' ? '微信' : '支付宝'}
</Badge>
</td>
<td className="p-4">
<div>
<p className="text-white font-mono text-xs">{withdrawal.account}</p>
<p className="text-gray-500 text-xs">{withdrawal.name}</p>
</div>
</td>
<td className="p-4 text-gray-400">
{withdrawal.created_at ? new Date(withdrawal.created_at).toLocaleString('zh-CN') : '-'}
</td>
<td className="p-4">{getStatusBadge(withdrawal.status)}</td>
<td className="p-4 text-right">
{withdrawal.status === 'pending' && (
<div className="flex gap-2 justify-end">
<Button
size="sm"
onClick={() => handleApproveWithdrawal(withdrawal.id)}
className="bg-[#38bdac] hover:bg-[#2da396] text-white"
>
<CheckCircle className="w-4 h-4 mr-1" />
</Button>
<Button
size="sm"
variant="outline"
onClick={() => handleRejectWithdrawal(withdrawal.id)}
className="border-red-500/50 text-red-400 hover:bg-red-500/20"
>
<XCircle className="w-4 h-4 mr-1" />
</Button>
</div>
)}
</td>
</tr>
))}
</tbody>
</table>
</div>
)}
</CardContent>
</Card>
</div>
)}
{/* 分销商管理 */}
{activeTab === 'distributors' && (
<div className="space-y-4">
<div className="flex gap-4">
<div className="relative flex-1">
<Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400" />
<Input
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
placeholder="搜索分销商名称、手机号、推广码..."
className="pl-10 bg-[#0f2137] border-gray-700 text-white"
/>
</div>
</div>
<Card className="bg-[#0f2137] border-gray-700/50">
<CardContent className="p-0">
{filteredDistributors.length === 0 ? (
<div className="py-12 text-center text-gray-500"></div>
) : (
<div className="overflow-x-auto">
<table className="w-full text-sm">
<thead>
<tr className="bg-[#0a1628] text-gray-400">
<th className="p-4 text-left font-medium"></th>
<th className="p-4 text-left font-medium">广</th>
<th className="p-4 text-left font-medium"></th>
<th className="p-4 text-left font-medium"></th>
<th className="p-4 text-left font-medium"></th>
<th className="p-4 text-left font-medium"></th>
<th className="p-4 text-left font-medium"></th>
</tr>
</thead>
<tbody className="divide-y divide-gray-700/50">
{filteredDistributors.map(distributor => (
<tr key={distributor.id} className="hover:bg-[#0a1628] transition-colors">
<td className="p-4">
<div>
<p className="text-white font-medium">{distributor.nickname}</p>
<p className="text-gray-500 text-xs">{distributor.phone}</p>
</div>
</td>
<td className="p-4">
<span className="text-[#38bdac] font-mono text-sm">{distributor.referral_code}</span>
</td>
<td className="p-4">
<span className="text-white">{distributor.referral_count || 0}</span>
</td>
<td className="p-4">
<span className="text-[#38bdac] font-bold">¥{(distributor.earnings || 0).toFixed(2)}</span>
</td>
<td className="p-4">
<span className="text-white">¥{(distributor.pending_earnings || 0).toFixed(2)}</span>
</td>
<td className="p-4">
<span className="text-gray-400">¥{(distributor.withdrawn_earnings || 0).toFixed(2)}</span>
</td>
<td className="p-4 text-gray-400">
{distributor.created_at ? new Date(distributor.created_at).toLocaleDateString('zh-CN') : '-'}
</td>
</tr>
))}
</tbody>
</table>
</div>
)}
</CardContent>
</Card>
</div>
)}
</>
)}
</div>
)
}