803 lines
36 KiB
TypeScript
803 lines
36 KiB
TypeScript
'use client';
|
||
|
||
import { useState, useCallback } from 'react';
|
||
import { useParams, useRouter } from 'next/navigation';
|
||
import Image from 'next/image';
|
||
import Link from 'next/link';
|
||
import { Button, toast } from '@/components/common';
|
||
import { PageContainer } from '@/components/layout';
|
||
import { cn } from '@/utils/helpers';
|
||
import { formatNumber, formatRanking } from '@/utils/formatters';
|
||
import {
|
||
useUserFullDetail,
|
||
useReferralTree,
|
||
usePlantingLedger,
|
||
useWalletLedger,
|
||
useAuthorizationDetail,
|
||
} from '@/hooks/useUserDetailPage';
|
||
import type {
|
||
ReferralNode,
|
||
PlantingLedgerItem,
|
||
WalletLedgerItem,
|
||
WALLET_ENTRY_TYPE_LABELS,
|
||
ASSET_TYPE_LABELS,
|
||
PLANTING_STATUS_LABELS,
|
||
AUTHORIZATION_ROLE_LABELS,
|
||
AUTHORIZATION_STATUS_LABELS,
|
||
ASSESSMENT_RESULT_LABELS,
|
||
} from '@/types/userDetail.types';
|
||
import { PROVINCE_CODE_NAMES, CITY_CODE_NAMES } from '@/types';
|
||
import styles from './user-detail.module.scss';
|
||
|
||
// Tab 类型
|
||
type TabType = 'referral' | 'planting' | 'wallet' | 'authorization';
|
||
|
||
const tabs: { key: TabType; label: string }[] = [
|
||
{ key: 'referral', label: '引荐关系' },
|
||
{ key: 'planting', label: '认种信息' },
|
||
{ key: 'wallet', label: '钱包信息' },
|
||
{ key: 'authorization', label: '授权信息' },
|
||
];
|
||
|
||
// 流水类型标签
|
||
const entryTypeLabels: Record<string, string> = {
|
||
DEPOSIT: '充值',
|
||
DEPOSIT_USDT: 'USDT充值',
|
||
DEPOSIT_BNB: 'BNB充值',
|
||
WITHDRAW: '提现',
|
||
WITHDRAW_FROZEN: '提现冻结',
|
||
WITHDRAW_CONFIRMED: '提现确认',
|
||
WITHDRAW_CANCELLED: '提现取消',
|
||
PLANTING_PAYMENT: '认种支付',
|
||
PLANTING_FROZEN: '认种冻结',
|
||
PLANTING_DEDUCT: '认种扣款',
|
||
REWARD_PENDING: '收益待领取',
|
||
REWARD_SETTLED: '收益结算',
|
||
REWARD_EXPIRED: '收益过期',
|
||
TRANSFER_OUT: '转出',
|
||
TRANSFER_IN: '转入',
|
||
INTERNAL_TRANSFER: '内部转账',
|
||
ADMIN_ADJUSTMENT: '管理员调整',
|
||
SYSTEM_DEDUCT: '系统扣款',
|
||
FEE: '手续费',
|
||
};
|
||
|
||
const assetTypeLabels: Record<string, string> = {
|
||
USDT: '绿积分',
|
||
DST: 'DST',
|
||
BNB: 'BNB',
|
||
OG: 'OG',
|
||
RWAD: 'RWAD',
|
||
HASHPOWER: '算力',
|
||
};
|
||
|
||
const plantingStatusLabels: Record<string, string> = {
|
||
CREATED: '已创建',
|
||
PAID: '已支付',
|
||
FUND_ALLOCATED: '资金已分配',
|
||
MINING_ENABLED: '已开始挖矿',
|
||
CANCELLED: '已取消',
|
||
EXPIRED: '已过期',
|
||
};
|
||
|
||
const roleTypeLabels: Record<string, string> = {
|
||
COMMUNITY_PARTNER: '社区合伙人',
|
||
PROVINCE_COMPANY: '省公司',
|
||
CITY_COMPANY: '市公司',
|
||
AUTH_PROVINCE_COMPANY: '授权省公司',
|
||
AUTH_CITY_COMPANY: '授权市公司',
|
||
};
|
||
|
||
const authStatusLabels: Record<string, string> = {
|
||
PENDING: '待授权',
|
||
AUTHORIZED: '已授权',
|
||
REVOKED: '已撤销',
|
||
EXPIRED: '已过期',
|
||
};
|
||
|
||
const assessmentResultLabels: Record<string, string> = {
|
||
NOT_ASSESSED: '未考核',
|
||
PASSED: '通过',
|
||
FAILED: '未通过',
|
||
BYPASSED: '豁免',
|
||
};
|
||
|
||
/**
|
||
* 将区域代码转换为名称
|
||
* @param code 区域代码,如 450000(省)或 451200(市)
|
||
* @returns 区域名称
|
||
*/
|
||
const getRegionName = (code: string | null | undefined): string => {
|
||
if (!code) return '-';
|
||
// 先尝试查找城市
|
||
if (CITY_CODE_NAMES[code]) {
|
||
return CITY_CODE_NAMES[code];
|
||
}
|
||
// 再尝试查找省份
|
||
if (PROVINCE_CODE_NAMES[code]) {
|
||
return PROVINCE_CODE_NAMES[code];
|
||
}
|
||
// 尝试去掉后4位的0(如 450000 -> 45)查找省份
|
||
if (code.length === 6 && code.endsWith('0000')) {
|
||
const shortCode = code.substring(0, 2);
|
||
if (PROVINCE_CODE_NAMES[shortCode]) {
|
||
return PROVINCE_CODE_NAMES[shortCode];
|
||
}
|
||
}
|
||
return code;
|
||
};
|
||
|
||
/**
|
||
* 用户详情页面
|
||
*/
|
||
export default function UserDetailPage() {
|
||
const params = useParams();
|
||
const router = useRouter();
|
||
const accountSequence = params.id as string;
|
||
|
||
const [activeTab, setActiveTab] = useState<TabType>('referral');
|
||
const [treeRootUser, setTreeRootUser] = useState<string>(accountSequence);
|
||
const [plantingPage, setPlantingPage] = useState(1);
|
||
const [walletPage, setWalletPage] = useState(1);
|
||
|
||
// 获取用户完整信息
|
||
const { data: userDetail, isLoading: detailLoading, error: detailError } = useUserFullDetail(accountSequence);
|
||
|
||
// 获取推荐关系树(以当前选中的用户为根)
|
||
const { data: referralTree, isLoading: treeLoading } = useReferralTree(treeRootUser, 'both', 1);
|
||
|
||
// 获取认种分类账
|
||
const { data: plantingData, isLoading: plantingLoading } = usePlantingLedger(accountSequence, {
|
||
page: plantingPage,
|
||
pageSize: 10,
|
||
});
|
||
|
||
// 获取钱包分类账
|
||
const { data: walletData, isLoading: walletLoading } = useWalletLedger(accountSequence, {
|
||
page: walletPage,
|
||
pageSize: 10,
|
||
});
|
||
|
||
// 获取授权信息
|
||
const { data: authData, isLoading: authLoading } = useAuthorizationDetail(accountSequence);
|
||
|
||
// 切换推荐关系树的根节点
|
||
const handleTreeNodeClick = useCallback((node: ReferralNode) => {
|
||
setTreeRootUser(node.accountSequence);
|
||
}, []);
|
||
|
||
// 返回列表
|
||
const handleBack = useCallback(() => {
|
||
router.push('/users');
|
||
}, [router]);
|
||
|
||
// 格式化日期
|
||
const formatDate = (dateStr: string | null) => {
|
||
if (!dateStr) return '-';
|
||
return new Date(dateStr).toLocaleString('zh-CN');
|
||
};
|
||
|
||
// 格式化金额
|
||
const formatAmount = (amount: string | null) => {
|
||
if (!amount) return '-';
|
||
const num = parseFloat(amount);
|
||
return num.toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 8 });
|
||
};
|
||
|
||
if (detailLoading) {
|
||
return (
|
||
<PageContainer title="用户详情">
|
||
<div className={styles.loading}>加载中...</div>
|
||
</PageContainer>
|
||
);
|
||
}
|
||
|
||
if (detailError || !userDetail) {
|
||
return (
|
||
<PageContainer title="用户详情">
|
||
<div className={styles.error}>
|
||
<p>加载失败: {(detailError as Error)?.message || '用户不存在'}</p>
|
||
<Button onClick={handleBack}>返回列表</Button>
|
||
</div>
|
||
</PageContainer>
|
||
);
|
||
}
|
||
|
||
return (
|
||
<PageContainer title={`用户详情 - ${userDetail.accountSequence}`}>
|
||
<div className={styles.userDetail}>
|
||
{/* 返回按钮 */}
|
||
<div className={styles.userDetail__backBar}>
|
||
<button className={styles.userDetail__backBtn} onClick={handleBack}>
|
||
<span className={styles.userDetail__backIcon}>←</span>
|
||
返回用户列表
|
||
</button>
|
||
</div>
|
||
|
||
{/* 用户基本信息卡片 */}
|
||
<div className={styles.userDetail__basicCard}>
|
||
<div className={styles.userDetail__basicHeader}>
|
||
<div
|
||
className={styles.userDetail__avatar}
|
||
style={{ backgroundImage: `url(${userDetail.avatar || '/images/Data@2x.png'})` }}
|
||
>
|
||
<div
|
||
className={cn(
|
||
styles.userDetail__status,
|
||
userDetail.isOnline ? styles['userDetail__status--online'] : styles['userDetail__status--offline']
|
||
)}
|
||
/>
|
||
</div>
|
||
<div className={styles.userDetail__basicInfo}>
|
||
<h1 className={styles.userDetail__nickname}>
|
||
{userDetail.nickname || '未设置昵称'}
|
||
<span className={cn(
|
||
styles.userDetail__statusBadge,
|
||
styles[`userDetail__statusBadge--${userDetail.status}`]
|
||
)}>
|
||
{userDetail.status === 'active' ? '正常' : userDetail.status === 'frozen' ? '冻结' : '停用'}
|
||
</span>
|
||
</h1>
|
||
<div className={styles.userDetail__basicMeta}>
|
||
<span>账户序号: <strong>{userDetail.accountSequence}</strong></span>
|
||
<span>手机号: {userDetail.phoneNumberMasked || '未绑定'}</span>
|
||
<span>KYC: {userDetail.kycStatus}</span>
|
||
</div>
|
||
<div className={styles.userDetail__basicMeta}>
|
||
<span>注册时间: {formatDate(userDetail.registeredAt)}</span>
|
||
<span>最后活跃: {formatDate(userDetail.lastActiveAt)}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* 统计卡片 */}
|
||
<div className={styles.userDetail__statsGrid}>
|
||
<div className={styles.userDetail__statCard}>
|
||
<span className={styles.userDetail__statLabel}>个人认种量</span>
|
||
<span className={styles.userDetail__statValue}>{formatNumber(userDetail.personalAdoptions)}</span>
|
||
</div>
|
||
<div className={styles.userDetail__statCard}>
|
||
<span className={styles.userDetail__statLabel}>团队认种量</span>
|
||
<span className={styles.userDetail__statValue}>{formatNumber(userDetail.teamAdoptions)}</span>
|
||
</div>
|
||
<div className={styles.userDetail__statCard}>
|
||
<span className={styles.userDetail__statLabel}>团队地址数</span>
|
||
<span className={styles.userDetail__statValue}>{formatNumber(userDetail.teamAddresses)}</span>
|
||
</div>
|
||
<div className={styles.userDetail__statCard}>
|
||
<span className={styles.userDetail__statLabel}>龙虎榜排名</span>
|
||
<span className={cn(
|
||
styles.userDetail__statValue,
|
||
userDetail.ranking && userDetail.ranking <= 10 && styles['userDetail__statValue--gold']
|
||
)}>
|
||
{userDetail.ranking ? formatRanking(userDetail.ranking) : '-'}
|
||
</span>
|
||
</div>
|
||
<div className={styles.userDetail__statCard}>
|
||
<span className={styles.userDetail__statLabel}>引荐人数</span>
|
||
<span className={styles.userDetail__statValue}>
|
||
{formatNumber(userDetail.referralInfo.directReferralCount)}
|
||
</span>
|
||
</div>
|
||
</div>
|
||
|
||
{/* 引荐人信息 */}
|
||
{userDetail.referralInfo.referrerSequence && (
|
||
<div className={styles.userDetail__referrerInfo}>
|
||
<span className={styles.userDetail__referrerLabel}>引荐人:</span>
|
||
<Link
|
||
href={`/users/${userDetail.referralInfo.referrerSequence}`}
|
||
className={styles.userDetail__referrerLink}
|
||
>
|
||
{userDetail.referralInfo.referrerSequence}
|
||
{userDetail.referralInfo.referrerNickname && ` (${userDetail.referralInfo.referrerNickname})`}
|
||
</Link>
|
||
<span className={styles.userDetail__referrerMeta}>
|
||
邀请码: {userDetail.referralInfo.usedReferralCode || '-'}
|
||
</span>
|
||
<span className={styles.userDetail__referrerMeta}>
|
||
层级深度: {userDetail.referralInfo.depth}
|
||
</span>
|
||
</div>
|
||
)}
|
||
</div>
|
||
|
||
{/* Tab 切换 */}
|
||
<div className={styles.userDetail__tabs}>
|
||
{tabs.map((tab) => (
|
||
<button
|
||
key={tab.key}
|
||
className={cn(
|
||
styles.userDetail__tab,
|
||
activeTab === tab.key && styles['userDetail__tab--active']
|
||
)}
|
||
onClick={() => setActiveTab(tab.key)}
|
||
>
|
||
{tab.label}
|
||
</button>
|
||
))}
|
||
</div>
|
||
|
||
{/* Tab 内容 */}
|
||
<div className={styles.userDetail__tabContent}>
|
||
{/* 引荐关系 Tab */}
|
||
{activeTab === 'referral' && (
|
||
<div className={styles.referralTab}>
|
||
<div className={styles.referralTab__header}>
|
||
<h3>引荐关系树</h3>
|
||
{treeRootUser !== accountSequence && (
|
||
<Button
|
||
variant="outline"
|
||
size="sm"
|
||
onClick={() => setTreeRootUser(accountSequence)}
|
||
>
|
||
返回当前用户
|
||
</Button>
|
||
)}
|
||
</div>
|
||
|
||
{treeLoading ? (
|
||
<div className={styles.referralTab__loading}>加载中...</div>
|
||
) : referralTree ? (
|
||
<div className={styles.referralTree}>
|
||
{/* 向上的引荐人链 */}
|
||
{referralTree.ancestors.length > 0 && (
|
||
<div className={styles.referralTree__ancestors}>
|
||
<div className={styles.referralTree__label}>引荐人链 (向上)</div>
|
||
<div className={styles.referralTree__nodeList}>
|
||
{referralTree.ancestors.map((ancestor, index) => (
|
||
<div key={ancestor.accountSequence} className={styles.referralTree__nodeWrapper}>
|
||
<button
|
||
className={styles.referralTree__node}
|
||
onClick={() => handleTreeNodeClick(ancestor)}
|
||
>
|
||
<span className={styles.referralTree__nodeSeq}>{ancestor.accountSequence}</span>
|
||
<span className={styles.referralTree__nodeNickname}>
|
||
{ancestor.nickname || '未设置'}
|
||
</span>
|
||
<span className={styles.referralTree__nodeAdoptions}>
|
||
认种: {formatNumber(ancestor.personalAdoptions)}
|
||
</span>
|
||
</button>
|
||
{index < referralTree.ancestors.length - 1 && (
|
||
<div className={styles.referralTree__connector}>↑</div>
|
||
)}
|
||
</div>
|
||
))}
|
||
</div>
|
||
<div className={styles.referralTree__connector}>↑</div>
|
||
</div>
|
||
)}
|
||
|
||
{/* 当前用户 */}
|
||
<div className={styles.referralTree__current}>
|
||
<div
|
||
className={cn(
|
||
styles.referralTree__node,
|
||
styles['referralTree__node--current'],
|
||
referralTree.currentUser.accountSequence === accountSequence &&
|
||
styles['referralTree__node--highlight']
|
||
)}
|
||
>
|
||
<span className={styles.referralTree__nodeSeq}>
|
||
{referralTree.currentUser.accountSequence}
|
||
</span>
|
||
<span className={styles.referralTree__nodeNickname}>
|
||
{referralTree.currentUser.nickname || '未设置'}
|
||
</span>
|
||
<span className={styles.referralTree__nodeAdoptions}>
|
||
认种: {formatNumber(referralTree.currentUser.personalAdoptions)}
|
||
</span>
|
||
<span className={styles.referralTree__nodeCount}>
|
||
引荐: {formatNumber(referralTree.currentUser.directReferralCount)}
|
||
</span>
|
||
</div>
|
||
</div>
|
||
|
||
{/* 引荐用户 */}
|
||
{referralTree.directReferrals.length > 0 && (
|
||
<div className={styles.referralTree__directReferrals}>
|
||
<div className={styles.referralTree__connector}>↓</div>
|
||
<div className={styles.referralTree__label}>
|
||
引荐用户 ({referralTree.directReferrals.length})
|
||
</div>
|
||
<div className={styles.referralTree__nodeGrid}>
|
||
{referralTree.directReferrals.map((referral) => (
|
||
<button
|
||
key={referral.accountSequence}
|
||
className={styles.referralTree__node}
|
||
onClick={() => handleTreeNodeClick(referral)}
|
||
>
|
||
<span className={styles.referralTree__nodeSeq}>{referral.accountSequence}</span>
|
||
<span className={styles.referralTree__nodeNickname}>
|
||
{referral.nickname || '未设置'}
|
||
</span>
|
||
<span className={styles.referralTree__nodeAdoptions}>
|
||
认种: {formatNumber(referral.personalAdoptions)}
|
||
</span>
|
||
{referral.directReferralCount > 0 && (
|
||
<span className={styles.referralTree__nodeCount}>
|
||
引荐: {formatNumber(referral.directReferralCount)}
|
||
</span>
|
||
)}
|
||
</button>
|
||
))}
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{referralTree.directReferrals.length === 0 && referralTree.ancestors.length === 0 && (
|
||
<div className={styles.referralTree__empty}>暂无引荐关系</div>
|
||
)}
|
||
</div>
|
||
) : (
|
||
<div className={styles.referralTab__empty}>暂无引荐关系数据</div>
|
||
)}
|
||
</div>
|
||
)}
|
||
|
||
{/* 认种信息 Tab */}
|
||
{activeTab === 'planting' && (
|
||
<div className={styles.plantingTab}>
|
||
{plantingLoading ? (
|
||
<div className={styles.plantingTab__loading}>加载中...</div>
|
||
) : plantingData ? (
|
||
<>
|
||
{/* 认种汇总 */}
|
||
<div className={styles.plantingTab__summary}>
|
||
<h3>认种汇总</h3>
|
||
<div className={styles.plantingTab__summaryGrid}>
|
||
<div className={styles.plantingTab__summaryItem}>
|
||
<span className={styles.plantingTab__summaryLabel}>总订单数</span>
|
||
<span className={styles.plantingTab__summaryValue}>
|
||
{formatNumber(plantingData.summary.totalOrders)}
|
||
</span>
|
||
</div>
|
||
<div className={styles.plantingTab__summaryItem}>
|
||
<span className={styles.plantingTab__summaryLabel}>总认种量</span>
|
||
<span className={styles.plantingTab__summaryValue}>
|
||
{formatNumber(plantingData.summary.totalTreeCount)}
|
||
</span>
|
||
</div>
|
||
<div className={styles.plantingTab__summaryItem}>
|
||
<span className={styles.plantingTab__summaryLabel}>总金额 (绿积分)</span>
|
||
<span className={styles.plantingTab__summaryValue}>
|
||
{formatAmount(plantingData.summary.totalAmount)}
|
||
</span>
|
||
</div>
|
||
<div className={styles.plantingTab__summaryItem}>
|
||
<span className={styles.plantingTab__summaryLabel}>有效认种量</span>
|
||
<span className={styles.plantingTab__summaryValue}>
|
||
{formatNumber(plantingData.summary.effectiveTreeCount)}
|
||
</span>
|
||
</div>
|
||
<div className={styles.plantingTab__summaryItem}>
|
||
<span className={styles.plantingTab__summaryLabel}>首次认种</span>
|
||
<span className={styles.plantingTab__summaryValue}>
|
||
{formatDate(plantingData.summary.firstPlantingAt)}
|
||
</span>
|
||
</div>
|
||
<div className={styles.plantingTab__summaryItem}>
|
||
<span className={styles.plantingTab__summaryLabel}>最近认种</span>
|
||
<span className={styles.plantingTab__summaryValue}>
|
||
{formatDate(plantingData.summary.lastPlantingAt)}
|
||
</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* 认种分类账 */}
|
||
<div className={styles.plantingTab__ledger}>
|
||
<h3>认种分类账明细</h3>
|
||
<div className={styles.ledgerTable}>
|
||
<div className={styles.ledgerTable__header}>
|
||
<div className={styles.ledgerTable__cell}>订单号</div>
|
||
<div className={styles.ledgerTable__cell}>认种数量</div>
|
||
<div className={styles.ledgerTable__cell}>金额</div>
|
||
<div className={styles.ledgerTable__cell}>省市</div>
|
||
<div className={styles.ledgerTable__cell}>创建时间</div>
|
||
<div className={styles.ledgerTable__cell}>支付时间</div>
|
||
</div>
|
||
{plantingData.items.length === 0 ? (
|
||
<div className={styles.ledgerTable__empty}>暂无认种记录</div>
|
||
) : (
|
||
plantingData.items.map((item) => (
|
||
<div key={item.orderId} className={styles.ledgerTable__row}>
|
||
<div className={styles.ledgerTable__cell}>{item.orderNo}</div>
|
||
<div className={styles.ledgerTable__cell}>{formatNumber(item.treeCount)}</div>
|
||
<div className={styles.ledgerTable__cell}>{formatAmount(item.totalAmount)}</div>
|
||
<div className={styles.ledgerTable__cell}>
|
||
{getRegionName(item.selectedProvince)} / {getRegionName(item.selectedCity)}
|
||
</div>
|
||
<div className={styles.ledgerTable__cell}>{formatDate(item.createdAt)}</div>
|
||
<div className={styles.ledgerTable__cell}>{formatDate(item.paidAt)}</div>
|
||
</div>
|
||
))
|
||
)}
|
||
</div>
|
||
|
||
{/* 分页 */}
|
||
{plantingData.totalPages > 1 && (
|
||
<div className={styles.pagination}>
|
||
<button
|
||
disabled={plantingPage === 1}
|
||
onClick={() => setPlantingPage((p) => p - 1)}
|
||
>
|
||
上一页
|
||
</button>
|
||
<span>第 {plantingPage} / {plantingData.totalPages} 页</span>
|
||
<button
|
||
disabled={plantingPage === plantingData.totalPages}
|
||
onClick={() => setPlantingPage((p) => p + 1)}
|
||
>
|
||
下一页
|
||
</button>
|
||
</div>
|
||
)}
|
||
</div>
|
||
</>
|
||
) : (
|
||
<div className={styles.plantingTab__empty}>暂无认种数据</div>
|
||
)}
|
||
</div>
|
||
)}
|
||
|
||
{/* 钱包信息 Tab */}
|
||
{activeTab === 'wallet' && (
|
||
<div className={styles.walletTab}>
|
||
{walletLoading ? (
|
||
<div className={styles.walletTab__loading}>加载中...</div>
|
||
) : walletData ? (
|
||
<>
|
||
{/* 钱包汇总 */}
|
||
<div className={styles.walletTab__summary}>
|
||
<h3>钱包汇总</h3>
|
||
<div className={styles.walletTab__summaryGrid}>
|
||
<div className={styles.walletTab__summaryItem}>
|
||
<span className={styles.walletTab__summaryLabel}>绿积分 可用</span>
|
||
<span className={styles.walletTab__summaryValue}>
|
||
{formatAmount(walletData.summary.usdtAvailable)}
|
||
</span>
|
||
</div>
|
||
<div className={styles.walletTab__summaryItem}>
|
||
<span className={styles.walletTab__summaryLabel}>绿积分 冻结</span>
|
||
<span className={styles.walletTab__summaryValue}>
|
||
{formatAmount(walletData.summary.usdtFrozen)}
|
||
</span>
|
||
</div>
|
||
<div className={styles.walletTab__summaryItem}>
|
||
<span className={styles.walletTab__summaryLabel}>待领取收益</span>
|
||
<span className={styles.walletTab__summaryValue}>
|
||
{formatAmount(walletData.summary.pendingUsdt)}
|
||
</span>
|
||
</div>
|
||
<div className={styles.walletTab__summaryItem}>
|
||
<span className={styles.walletTab__summaryLabel}>可结算收益</span>
|
||
<span className={styles.walletTab__summaryValue}>
|
||
{formatAmount(walletData.summary.settleableUsdt)}
|
||
</span>
|
||
</div>
|
||
<div className={styles.walletTab__summaryItem}>
|
||
<span className={styles.walletTab__summaryLabel}>已结算收益</span>
|
||
<span className={styles.walletTab__summaryValue}>
|
||
{formatAmount(walletData.summary.settledTotalUsdt)}
|
||
</span>
|
||
</div>
|
||
<div className={styles.walletTab__summaryItem}>
|
||
<span className={styles.walletTab__summaryLabel}>过期收益</span>
|
||
<span className={styles.walletTab__summaryValue}>
|
||
{formatAmount(walletData.summary.expiredTotalUsdt)}
|
||
</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* 钱包分类账 */}
|
||
<div className={styles.walletTab__ledger}>
|
||
<h3>钱包分类账明细</h3>
|
||
<div className={styles.ledgerTable}>
|
||
<div className={styles.ledgerTable__header}>
|
||
<div className={styles.ledgerTable__cell}>流水ID</div>
|
||
<div className={styles.ledgerTable__cell}>类型</div>
|
||
<div className={styles.ledgerTable__cell}>资产</div>
|
||
<div className={styles.ledgerTable__cell}>金额</div>
|
||
<div className={styles.ledgerTable__cell}>余额快照</div>
|
||
<div className={styles.ledgerTable__cell}>关联订单</div>
|
||
<div className={styles.ledgerTable__cell}>时间</div>
|
||
</div>
|
||
{walletData.items.length === 0 ? (
|
||
<div className={styles.ledgerTable__empty}>暂无钱包流水</div>
|
||
) : (
|
||
walletData.items.map((item) => (
|
||
<div key={item.entryId} className={styles.ledgerTable__row}>
|
||
<div className={styles.ledgerTable__cell}>{item.entryId}</div>
|
||
<div className={styles.ledgerTable__cell}>
|
||
{entryTypeLabels[item.entryType] || item.entryType}
|
||
</div>
|
||
<div className={styles.ledgerTable__cell}>
|
||
{assetTypeLabels[item.assetType] || item.assetType}
|
||
</div>
|
||
<div className={cn(
|
||
styles.ledgerTable__cell,
|
||
parseFloat(item.amount) >= 0
|
||
? styles['ledgerTable__cell--positive']
|
||
: styles['ledgerTable__cell--negative']
|
||
)}>
|
||
{parseFloat(item.amount) >= 0 ? '+' : ''}{formatAmount(item.amount)}
|
||
</div>
|
||
<div className={styles.ledgerTable__cell}>
|
||
{formatAmount(item.balanceAfter)}
|
||
</div>
|
||
<div className={styles.ledgerTable__cell}>
|
||
{item.refOrderId || item.refTxHash || '-'}
|
||
</div>
|
||
<div className={styles.ledgerTable__cell}>{formatDate(item.createdAt)}</div>
|
||
</div>
|
||
))
|
||
)}
|
||
</div>
|
||
|
||
{/* 分页 */}
|
||
{walletData.totalPages > 1 && (
|
||
<div className={styles.pagination}>
|
||
<button
|
||
disabled={walletPage === 1}
|
||
onClick={() => setWalletPage((p) => p - 1)}
|
||
>
|
||
上一页
|
||
</button>
|
||
<span>第 {walletPage} / {walletData.totalPages} 页</span>
|
||
<button
|
||
disabled={walletPage === walletData.totalPages}
|
||
onClick={() => setWalletPage((p) => p + 1)}
|
||
>
|
||
下一页
|
||
</button>
|
||
</div>
|
||
)}
|
||
</div>
|
||
</>
|
||
) : (
|
||
<div className={styles.walletTab__empty}>暂无钱包数据</div>
|
||
)}
|
||
</div>
|
||
)}
|
||
|
||
{/* 授权信息 Tab */}
|
||
{activeTab === 'authorization' && (
|
||
<div className={styles.authTab}>
|
||
{authLoading ? (
|
||
<div className={styles.authTab__loading}>加载中...</div>
|
||
) : authData ? (
|
||
<>
|
||
{/* 授权角色列表 */}
|
||
<div className={styles.authTab__roles}>
|
||
<h3>授权角色</h3>
|
||
{authData.roles.length === 0 ? (
|
||
<div className={styles.authTab__empty}>暂无授权角色</div>
|
||
) : (
|
||
<div className={styles.authTab__roleGrid}>
|
||
{authData.roles.map((role) => (
|
||
<div key={role.id} className={styles.authTab__roleCard}>
|
||
<div className={styles.authTab__roleHeader}>
|
||
<span className={styles.authTab__roleType}>
|
||
{roleTypeLabels[role.roleType] || role.roleType}
|
||
</span>
|
||
<span className={cn(
|
||
styles.authTab__roleStatus,
|
||
styles[`authTab__roleStatus--${role.status.toLowerCase()}`]
|
||
)}>
|
||
{authStatusLabels[role.status] || role.status}
|
||
</span>
|
||
</div>
|
||
<div className={styles.authTab__roleInfo}>
|
||
<p><strong>区域:</strong> {role.regionName} ({role.regionCode})</p>
|
||
<p><strong>显示头衔:</strong> {role.displayTitle}</p>
|
||
<p>
|
||
<strong>权益状态:</strong>
|
||
{role.benefitActive ? (
|
||
<span className={styles.authTab__benefitActive}>已激活</span>
|
||
) : (
|
||
<span className={styles.authTab__benefitInactive}>未激活</span>
|
||
)}
|
||
</p>
|
||
<p><strong>初始目标:</strong> {formatNumber(role.initialTargetTreeCount)} 棵</p>
|
||
<p><strong>月度目标类型:</strong> {role.monthlyTargetType}</p>
|
||
<p><strong>授权时间:</strong> {formatDate(role.authorizedAt)}</p>
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
)}
|
||
</div>
|
||
|
||
{/* 月度考核记录 */}
|
||
<div className={styles.authTab__assessments}>
|
||
<h3>月度考核记录</h3>
|
||
{authData.assessments.length === 0 ? (
|
||
<div className={styles.authTab__empty}>暂无考核记录</div>
|
||
) : (
|
||
<div className={styles.ledgerTable}>
|
||
<div className={styles.ledgerTable__header}>
|
||
<div className={styles.ledgerTable__cell}>考核月份</div>
|
||
<div className={styles.ledgerTable__cell}>角色</div>
|
||
<div className={styles.ledgerTable__cell}>月度目标/完成</div>
|
||
<div className={styles.ledgerTable__cell}>累计目标/完成</div>
|
||
<div className={styles.ledgerTable__cell}>结果</div>
|
||
<div className={styles.ledgerTable__cell}>区域排名</div>
|
||
</div>
|
||
{authData.assessments.map((assessment) => (
|
||
<div key={assessment.id} className={styles.ledgerTable__row}>
|
||
<div className={styles.ledgerTable__cell}>{assessment.assessmentMonth}</div>
|
||
<div className={styles.ledgerTable__cell}>
|
||
{roleTypeLabels[assessment.roleType] || assessment.roleType}
|
||
</div>
|
||
<div className={styles.ledgerTable__cell}>
|
||
{formatNumber(assessment.monthlyCompleted)} / {formatNumber(assessment.monthlyTarget)}
|
||
</div>
|
||
<div className={styles.ledgerTable__cell}>
|
||
{formatNumber(assessment.cumulativeCompleted)} / {formatNumber(assessment.cumulativeTarget)}
|
||
</div>
|
||
<div className={styles.ledgerTable__cell}>
|
||
<span className={cn(
|
||
styles.ledgerTable__result,
|
||
styles[`ledgerTable__result--${assessment.result.toLowerCase()}`]
|
||
)}>
|
||
{assessmentResultLabels[assessment.result] || assessment.result}
|
||
</span>
|
||
</div>
|
||
<div className={styles.ledgerTable__cell}>
|
||
{assessment.rankingInRegion || '-'}
|
||
{assessment.isFirstPlace && ' 🥇'}
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
)}
|
||
</div>
|
||
|
||
{/* 系统账户流水(如果有) */}
|
||
{authData.systemAccountLedger.length > 0 && (
|
||
<div className={styles.authTab__systemLedger}>
|
||
<h3>系统账户流水</h3>
|
||
<div className={styles.ledgerTable}>
|
||
<div className={styles.ledgerTable__header}>
|
||
<div className={styles.ledgerTable__cell}>流水ID</div>
|
||
<div className={styles.ledgerTable__cell}>账户类型</div>
|
||
<div className={styles.ledgerTable__cell}>流水类型</div>
|
||
<div className={styles.ledgerTable__cell}>金额</div>
|
||
<div className={styles.ledgerTable__cell}>余额</div>
|
||
<div className={styles.ledgerTable__cell}>时间</div>
|
||
</div>
|
||
{authData.systemAccountLedger.map((ledger) => (
|
||
<div key={ledger.ledgerId} className={styles.ledgerTable__row}>
|
||
<div className={styles.ledgerTable__cell}>{ledger.ledgerId}</div>
|
||
<div className={styles.ledgerTable__cell}>{ledger.accountType}</div>
|
||
<div className={styles.ledgerTable__cell}>{ledger.entryType}</div>
|
||
<div className={cn(
|
||
styles.ledgerTable__cell,
|
||
parseFloat(ledger.amount) >= 0
|
||
? styles['ledgerTable__cell--positive']
|
||
: styles['ledgerTable__cell--negative']
|
||
)}>
|
||
{parseFloat(ledger.amount) >= 0 ? '+' : ''}{formatAmount(ledger.amount)}
|
||
</div>
|
||
<div className={styles.ledgerTable__cell}>{formatAmount(ledger.balanceAfter)}</div>
|
||
<div className={styles.ledgerTable__cell}>{formatDate(ledger.createdAt)}</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
)}
|
||
</>
|
||
) : (
|
||
<div className={styles.authTab__empty}>暂无授权数据</div>
|
||
)}
|
||
</div>
|
||
)}
|
||
</div>
|
||
</div>
|
||
</PageContainer>
|
||
);
|
||
}
|