更新提现和订单管理逻辑,新增用户佣金信息展示,优化提现审批流程以防止超额提现风险。同时,调整提现页面显示用户佣金详情,提升用户体验。重构API以支持新字段,确保数据一致性和准确性。
This commit is contained in:
@@ -51,15 +51,31 @@ interface Binding {
|
||||
|
||||
interface Withdrawal {
|
||||
id: string
|
||||
user_id: string
|
||||
user_name?: 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' | 'completed' | 'rejected'
|
||||
created_at: string
|
||||
completed_at?: string
|
||||
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 {
|
||||
@@ -81,14 +97,20 @@ interface Order {
|
||||
userId: string
|
||||
userNickname?: string
|
||||
userPhone?: string
|
||||
type: 'section' | 'fullbook' | 'match'
|
||||
sectionId?: string
|
||||
sectionTitle?: 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'
|
||||
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
|
||||
@@ -105,102 +127,207 @@ export default function DistributionAdminPage() {
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [searchTerm, setSearchTerm] = useState('')
|
||||
const [statusFilter, setStatusFilter] = useState<string>('all')
|
||||
|
||||
// 标记哪些数据已加载
|
||||
const [loadedTabs, setLoadedTabs] = useState<Set<string>>(new Set())
|
||||
|
||||
// 初次加载:加载概览和用户数据
|
||||
useEffect(() => {
|
||||
loadData()
|
||||
loadInitialData()
|
||||
}, [])
|
||||
|
||||
// 切换tab:按需加载对应tab的数据
|
||||
useEffect(() => {
|
||||
loadTabData(activeTab)
|
||||
}, [activeTab])
|
||||
|
||||
const loadData = async () => {
|
||||
setLoading(true)
|
||||
// 初始加载:概览 + 用户数据
|
||||
const loadInitialData = async () => {
|
||||
console.log('[Admin] 加载初始数据...')
|
||||
|
||||
// 加载概览数据
|
||||
try {
|
||||
// === 1. 加载概览数据(新接口:从真实数据库统计) ===
|
||||
const overviewRes = await fetch('/api/admin/distribution/overview')
|
||||
const overviewData = await overviewRes.json()
|
||||
if (overviewData.success && overviewData.overview) {
|
||||
setOverview(overviewData.overview)
|
||||
console.log('[Admin] 概览数据加载成功:', overviewData.overview)
|
||||
} else {
|
||||
console.error('[Admin] 加载概览数据失败:', overviewData.error)
|
||||
if (overviewRes.ok) {
|
||||
const overviewData = await overviewRes.json()
|
||||
if (overviewData.success && overviewData.overview) {
|
||||
setOverview(overviewData.overview)
|
||||
console.log('[Admin] 概览数据加载成功')
|
||||
}
|
||||
}
|
||||
|
||||
// === 2. 加载用户数据 ===
|
||||
const usersRes = await fetch('/api/db/users')
|
||||
const usersData = await usersRes.json()
|
||||
const usersArr = usersData.users || []
|
||||
setUsers(usersArr)
|
||||
|
||||
// 加载订单数据
|
||||
const ordersRes = await fetch('/api/orders')
|
||||
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,
|
||||
userNickname: user?.nickname || '未知用户',
|
||||
userPhone: user?.phone || '-',
|
||||
referrerNickname: referrer?.nickname || null,
|
||||
referrerCode: referrer?.referral_code || null,
|
||||
}
|
||||
})
|
||||
setOrders(enrichedOrders)
|
||||
}
|
||||
|
||||
// 加载绑定数据
|
||||
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 || [])
|
||||
|
||||
// 注意:概览数据现在从 /api/admin/distribution/overview 直接获取,不再前端计算
|
||||
} 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,
|
||||
})
|
||||
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,
|
||||
// 状态统一(数据库用 success/failed,前端显示用 completed/rejected)
|
||||
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/db/withdrawals', {
|
||||
await fetch('/api/admin/withdrawals', {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ id, status: 'completed' })
|
||||
body: JSON.stringify({ id, action: 'approve' })
|
||||
})
|
||||
loadData()
|
||||
refreshCurrentTab()
|
||||
} catch (error) {
|
||||
console.error('Approve withdrawal error:', error)
|
||||
alert('操作失败')
|
||||
@@ -212,12 +339,12 @@ export default function DistributionAdminPage() {
|
||||
if (!reason) return
|
||||
|
||||
try {
|
||||
await fetch('/api/db/withdrawals', {
|
||||
await fetch('/api/admin/withdrawals', {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ id, status: 'rejected' })
|
||||
body: JSON.stringify({ id, action: 'reject', errorMessage: reason })
|
||||
})
|
||||
loadData()
|
||||
refreshCurrentTab()
|
||||
} catch (error) {
|
||||
console.error('Reject withdrawal error:', error)
|
||||
alert('操作失败')
|
||||
@@ -232,6 +359,7 @@ export default function DistributionAdminPage() {
|
||||
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',
|
||||
}
|
||||
@@ -242,6 +370,7 @@ export default function DistributionAdminPage() {
|
||||
expired: '已过期',
|
||||
cancelled: '已取消',
|
||||
pending: '待审核',
|
||||
processing: '处理中',
|
||||
completed: '已完成',
|
||||
rejected: '已拒绝',
|
||||
}
|
||||
@@ -290,7 +419,7 @@ export default function DistributionAdminPage() {
|
||||
<p className="text-gray-400 mt-1">统一管理:订单、分销绑定、提现审核</p>
|
||||
</div>
|
||||
<Button
|
||||
onClick={loadData}
|
||||
onClick={refreshCurrentTab}
|
||||
disabled={loading}
|
||||
variant="outline"
|
||||
className="border-gray-700 text-gray-300 hover:bg-gray-800"
|
||||
@@ -589,6 +718,8 @@ export default function DistributionAdminPage() {
|
||||
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))
|
||||
)
|
||||
@@ -609,18 +740,34 @@ export default function DistributionAdminPage() {
|
||||
<td className="p-4">
|
||||
<div>
|
||||
<p className="text-white text-sm">
|
||||
{order.type === 'fullbook' ? '整本购买' :
|
||||
order.type === 'match' ? '匹配次数' :
|
||||
order.sectionTitle || `章节${order.sectionId}`}
|
||||
{(() => {
|
||||
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 || ''}`}`
|
||||
}
|
||||
})()}
|
||||
</p>
|
||||
<p className="text-gray-500 text-xs">
|
||||
{order.type === 'fullbook' ? '全书' :
|
||||
order.type === 'match' ? '功能' : '单章'}
|
||||
{(() => {
|
||||
const type = order.productType || order.type
|
||||
if (type === 'fullbook') {
|
||||
return '全书解锁'
|
||||
} else if (type === 'match') {
|
||||
return '功能权益'
|
||||
} else {
|
||||
return order.chapterTitle || '单章购买'
|
||||
}
|
||||
})()}
|
||||
</p>
|
||||
</div>
|
||||
</td>
|
||||
<td className="p-4 text-[#38bdac] font-bold">
|
||||
¥{(order.amount || 0).toFixed(2)}
|
||||
¥{typeof order.amount === 'number' ? order.amount.toFixed(2) : parseFloat(order.amount || '0').toFixed(2)}
|
||||
</td>
|
||||
<td className="p-4 text-gray-300">
|
||||
{order.paymentMethod === 'wechat' ? '微信支付' :
|
||||
@@ -645,7 +792,11 @@ export default function DistributionAdminPage() {
|
||||
) : '-'}
|
||||
</td>
|
||||
<td className="p-4 text-[#FFD700]">
|
||||
{order.referrerEarnings ? `¥${order.referrerEarnings.toFixed(2)}` : '-'}
|
||||
{order.referrerEarnings
|
||||
? `¥${(typeof order.referrerEarnings === 'number'
|
||||
? order.referrerEarnings
|
||||
: parseFloat(order.referrerEarnings)).toFixed(2)}`
|
||||
: '-'}
|
||||
</td>
|
||||
<td className="p-4 text-gray-400 text-sm">
|
||||
{order.createdAt ? new Date(order.createdAt).toLocaleString('zh-CN') : '-'}
|
||||
@@ -790,7 +941,16 @@ export default function DistributionAdminPage() {
|
||||
{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>
|
||||
<div className="flex items-center gap-2">
|
||||
{withdrawal.userAvatar ? (
|
||||
<img src={withdrawal.userAvatar} alt="" className="w-8 h-8 rounded-full object-cover" />
|
||||
) : (
|
||||
<div className="w-8 h-8 rounded-full bg-gray-600 flex items-center justify-center text-white text-sm font-medium">
|
||||
{(withdrawal.user_name || withdrawal.name || '?').slice(0, 1)}
|
||||
</div>
|
||||
)}
|
||||
<p className="text-white font-medium">{withdrawal.user_name || withdrawal.name}</p>
|
||||
</div>
|
||||
</td>
|
||||
<td className="p-4">
|
||||
<span className="text-[#38bdac] font-bold">¥{withdrawal.amount.toFixed(2)}</span>
|
||||
|
||||
@@ -20,6 +20,12 @@ interface Withdrawal {
|
||||
errorMessage?: string
|
||||
createdAt: string
|
||||
processedAt?: string
|
||||
userCommissionInfo?: {
|
||||
totalCommission: number
|
||||
withdrawnEarnings: number
|
||||
pendingWithdrawals: number
|
||||
availableAfterThis: number
|
||||
}
|
||||
}
|
||||
|
||||
interface Stats {
|
||||
@@ -61,7 +67,15 @@ export default function WithdrawalsPage() {
|
||||
|
||||
// 批准提现
|
||||
const handleApprove = async (id: string) => {
|
||||
if (!confirm("确认已完成打款?批准后将更新用户提现记录。")) return
|
||||
// 检查是否存在超额提现风险
|
||||
const withdrawal = withdrawals.find(w => w.id === id)
|
||||
if (withdrawal?.userCommissionInfo && withdrawal.userCommissionInfo.availableAfterThis < 0) {
|
||||
if (!confirm(`⚠️ 风险警告:该用户审核后余额为负数(¥${withdrawal.userCommissionInfo.availableAfterThis.toFixed(2)}),可能存在超额提现。\n\n确认已核实用户账户并完成打款?`)) {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if (!confirm("确认已完成打款?批准后将更新用户提现记录。")) return
|
||||
}
|
||||
|
||||
setProcessing(id)
|
||||
try {
|
||||
@@ -229,7 +243,8 @@ export default function WithdrawalsPage() {
|
||||
<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>
|
||||
<th className="p-4 text-right font-medium">操作</th>
|
||||
@@ -243,18 +258,52 @@ export default function WithdrawalsPage() {
|
||||
</td>
|
||||
<td className="p-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-8 h-8 rounded-full bg-[#38bdac]/20 flex items-center justify-center text-sm text-[#38bdac]">
|
||||
{w.userNickname?.charAt(0) || "?"}
|
||||
</div>
|
||||
{w.userAvatar ? (
|
||||
<img
|
||||
src={w.userAvatar}
|
||||
alt={w.userNickname}
|
||||
className="w-8 h-8 rounded-full object-cover"
|
||||
/>
|
||||
) : (
|
||||
<div className="w-8 h-8 rounded-full bg-[#38bdac]/20 flex items-center justify-center text-sm text-[#38bdac]">
|
||||
{w.userNickname?.charAt(0) || "?"}
|
||||
</div>
|
||||
)}
|
||||
<div>
|
||||
<p className="font-medium text-white">{w.userNickname}</p>
|
||||
<p className="text-xs text-gray-500">{w.userPhone || w.userId.slice(0, 10)}</p>
|
||||
<p className="text-xs text-gray-500">{w.userPhone || w.referralCode || w.userId.slice(0, 10)}</p>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="p-4">
|
||||
<span className="font-bold text-orange-400">¥{w.amount.toFixed(2)}</span>
|
||||
</td>
|
||||
<td className="p-4">
|
||||
{w.userCommissionInfo ? (
|
||||
<div className="text-xs space-y-1">
|
||||
<div className="flex justify-between gap-4">
|
||||
<span className="text-gray-500">累计佣金:</span>
|
||||
<span className="text-[#38bdac] font-medium">¥{w.userCommissionInfo.totalCommission.toFixed(2)}</span>
|
||||
</div>
|
||||
<div className="flex justify-between gap-4">
|
||||
<span className="text-gray-500">已提现:</span>
|
||||
<span className="text-gray-400">¥{w.userCommissionInfo.withdrawnEarnings.toFixed(2)}</span>
|
||||
</div>
|
||||
<div className="flex justify-between gap-4">
|
||||
<span className="text-gray-500">待审核:</span>
|
||||
<span className="text-orange-400">¥{w.userCommissionInfo.pendingWithdrawals.toFixed(2)}</span>
|
||||
</div>
|
||||
<div className="flex justify-between gap-4 pt-1 border-t border-gray-700/30">
|
||||
<span className="text-gray-500">审核后余额:</span>
|
||||
<span className={w.userCommissionInfo.availableAfterThis >= 0 ? "text-green-400 font-medium" : "text-red-400 font-medium"}>
|
||||
¥{w.userCommissionInfo.availableAfterThis.toFixed(2)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<span className="text-gray-500 text-xs">暂无数据</span>
|
||||
)}
|
||||
</td>
|
||||
<td className="p-4">
|
||||
{getStatusBadge(w.status)}
|
||||
{w.errorMessage && (
|
||||
|
||||
Reference in New Issue
Block a user