804 lines
37 KiB
TypeScript
804 lines
37 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 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: '豁免',
|
|
};
|
|
|
|
/**
|
|
* 用户详情页面
|
|
*/
|
|
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 className={styles.userDetail__statCard}>
|
|
<span className={styles.userDetail__statLabel}>活跃直推</span>
|
|
<span className={styles.userDetail__statValue}>
|
|
{formatNumber(userDetail.referralInfo.activeDirectCount)}
|
|
</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 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}>
|
|
<span className={cn(
|
|
styles.ledgerTable__status,
|
|
styles[`ledgerTable__status--${item.status.toLowerCase()}`]
|
|
)}>
|
|
{plantingStatusLabels[item.status] || item.status}
|
|
</span>
|
|
</div>
|
|
<div className={styles.ledgerTable__cell}>
|
|
{item.selectedProvince || '-'} / {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}>DST 可用</span>
|
|
<span className={styles.walletTab__summaryValue}>
|
|
{formatAmount(walletData.summary.dstAvailable)}
|
|
</span>
|
|
</div>
|
|
<div className={styles.walletTab__summaryItem}>
|
|
<span className={styles.walletTab__summaryLabel}>算力</span>
|
|
<span className={styles.walletTab__summaryValue}>
|
|
{formatAmount(walletData.summary.hashpower)}
|
|
</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>
|
|
);
|
|
}
|