384 lines
11 KiB
JavaScript
384 lines
11 KiB
JavaScript
/**
|
||
* 个人中心页面
|
||
* 包含用户信息、积分系统、交易记录等
|
||
*/
|
||
|
||
import React, { useState, useEffect } from 'react';
|
||
import {
|
||
Box,
|
||
Container,
|
||
Grid,
|
||
GridItem,
|
||
Heading,
|
||
Text,
|
||
VStack,
|
||
HStack,
|
||
Avatar,
|
||
Button,
|
||
Card,
|
||
CardBody,
|
||
CardHeader,
|
||
Stat,
|
||
StatLabel,
|
||
StatNumber,
|
||
StatHelpText,
|
||
StatArrow,
|
||
Badge,
|
||
Tabs,
|
||
TabList,
|
||
TabPanels,
|
||
Tab,
|
||
TabPanel,
|
||
Table,
|
||
Thead,
|
||
Tbody,
|
||
Tr,
|
||
Th,
|
||
Td,
|
||
Icon,
|
||
useToast,
|
||
Spinner,
|
||
Divider,
|
||
} from '@chakra-ui/react';
|
||
import {
|
||
Wallet,
|
||
TrendingUp,
|
||
Gift,
|
||
History,
|
||
Award,
|
||
Calendar,
|
||
DollarSign,
|
||
Activity,
|
||
} from 'lucide-react';
|
||
import { useAuth } from '@contexts/AuthContext';
|
||
import { getUserAccount, claimDailyBonus } from '@services/predictionMarketService.api';
|
||
import { forumColors } from '@theme/forumTheme';
|
||
|
||
const ProfilePage = () => {
|
||
const toast = useToast();
|
||
const { user } = useAuth();
|
||
|
||
// 状态管理
|
||
const [account, setAccount] = useState(null);
|
||
const [loading, setLoading] = useState(true);
|
||
const [claiming, setClaiming] = useState(false);
|
||
|
||
// 加载用户积分账户
|
||
useEffect(() => {
|
||
const fetchAccount = async () => {
|
||
if (!user) return;
|
||
|
||
try {
|
||
setLoading(true);
|
||
const response = await getUserAccount();
|
||
if (response.success) {
|
||
setAccount(response.data);
|
||
}
|
||
} catch (error) {
|
||
console.error('获取账户失败:', error);
|
||
toast({
|
||
title: '加载失败',
|
||
description: '无法加载账户信息',
|
||
status: 'error',
|
||
duration: 3000,
|
||
});
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
};
|
||
|
||
fetchAccount();
|
||
}, [user, toast]);
|
||
|
||
// 领取每日奖励
|
||
const handleClaimDailyBonus = async () => {
|
||
try {
|
||
setClaiming(true);
|
||
const response = await claimDailyBonus();
|
||
|
||
if (response.success) {
|
||
toast({
|
||
title: '领取成功!',
|
||
description: `获得 ${response.data.bonus_amount} 积分`,
|
||
status: 'success',
|
||
duration: 3000,
|
||
});
|
||
|
||
// 刷新账户数据
|
||
const accountResponse = await getUserAccount();
|
||
if (accountResponse.success) {
|
||
setAccount(accountResponse.data);
|
||
}
|
||
}
|
||
} catch (error) {
|
||
toast({
|
||
title: '领取失败',
|
||
description: error.response?.data?.error || '今日奖励已领取或系统错误',
|
||
status: 'error',
|
||
duration: 3000,
|
||
});
|
||
} finally {
|
||
setClaiming(false);
|
||
}
|
||
};
|
||
|
||
if (loading) {
|
||
return (
|
||
<Box minH="80vh" display="flex" alignItems="center" justifyContent="center">
|
||
<VStack spacing="4">
|
||
<Spinner size="xl" color={forumColors.primary[500]} />
|
||
<Text color={forumColors.text.secondary}>加载中...</Text>
|
||
</VStack>
|
||
</Box>
|
||
);
|
||
}
|
||
|
||
return (
|
||
<Box bg={forumColors.background.main} minH="100vh" py="8">
|
||
<Container maxW="container.xl">
|
||
{/* 用户信息头部 */}
|
||
<Card
|
||
bg={forumColors.background.card}
|
||
borderRadius="xl"
|
||
border="1px solid"
|
||
borderColor={forumColors.border.default}
|
||
mb="6"
|
||
>
|
||
<CardBody>
|
||
<HStack spacing="6" align="start">
|
||
<Avatar
|
||
size="2xl"
|
||
name={user?.nickname || user?.username}
|
||
src={user?.avatar_url}
|
||
bg={forumColors.gradients.goldPrimary}
|
||
color={forumColors.background.main}
|
||
/>
|
||
|
||
<VStack align="start" spacing="3" flex="1">
|
||
<Heading size="lg" color={forumColors.text.primary}>
|
||
{user?.nickname || user?.username}
|
||
</Heading>
|
||
<HStack spacing="4">
|
||
<Badge
|
||
bg={forumColors.gradients.goldSubtle}
|
||
color={forumColors.primary[500]}
|
||
px="3"
|
||
py="1"
|
||
borderRadius="full"
|
||
>
|
||
<Icon as={Award} boxSize="14px" mr="1" />
|
||
会员
|
||
</Badge>
|
||
<Text fontSize="sm" color={forumColors.text.secondary}>
|
||
{user?.email}
|
||
</Text>
|
||
</HStack>
|
||
</VStack>
|
||
</HStack>
|
||
</CardBody>
|
||
</Card>
|
||
|
||
{/* 积分概览 */}
|
||
<Grid templateColumns={{ base: '1fr', md: 'repeat(4, 1fr)' }} gap="6" mb="6">
|
||
{/* 总余额 */}
|
||
<GridItem>
|
||
<Card
|
||
bg={forumColors.gradients.goldSubtle}
|
||
borderRadius="xl"
|
||
border="1px solid"
|
||
borderColor={forumColors.border.gold}
|
||
>
|
||
<CardBody>
|
||
<Stat>
|
||
<StatLabel fontSize="sm" color={forumColors.text.secondary}>
|
||
<Icon as={Wallet} boxSize="16px" mr="1" />
|
||
总余额
|
||
</StatLabel>
|
||
<StatNumber fontSize="3xl" fontWeight="bold" color={forumColors.primary[500]}>
|
||
{account?.balance?.toFixed(0) || 0}
|
||
</StatNumber>
|
||
<StatHelpText color={forumColors.text.tertiary}>积分</StatHelpText>
|
||
</Stat>
|
||
</CardBody>
|
||
</Card>
|
||
</GridItem>
|
||
|
||
{/* 可用余额 */}
|
||
<GridItem>
|
||
<Card
|
||
bg={forumColors.background.card}
|
||
borderRadius="xl"
|
||
border="1px solid"
|
||
borderColor={forumColors.border.default}
|
||
>
|
||
<CardBody>
|
||
<Stat>
|
||
<StatLabel fontSize="sm" color={forumColors.text.secondary}>
|
||
<Icon as={DollarSign} boxSize="16px" mr="1" />
|
||
可用余额
|
||
</StatLabel>
|
||
<StatNumber fontSize="2xl" color={forumColors.text.primary}>
|
||
{account?.available_balance?.toFixed(0) || 0}
|
||
</StatNumber>
|
||
<StatHelpText color={forumColors.text.tertiary}>积分</StatHelpText>
|
||
</Stat>
|
||
</CardBody>
|
||
</Card>
|
||
</GridItem>
|
||
|
||
{/* 累计收益 */}
|
||
<GridItem>
|
||
<Card
|
||
bg={forumColors.background.card}
|
||
borderRadius="xl"
|
||
border="1px solid"
|
||
borderColor={forumColors.border.default}
|
||
>
|
||
<CardBody>
|
||
<Stat>
|
||
<StatLabel fontSize="sm" color={forumColors.text.secondary}>
|
||
<Icon as={TrendingUp} boxSize="16px" mr="1" />
|
||
累计收益
|
||
</StatLabel>
|
||
<StatNumber fontSize="2xl" color={forumColors.success[500]}>
|
||
+{account?.total_earned?.toFixed(0) || 0}
|
||
</StatNumber>
|
||
<StatHelpText>
|
||
<StatArrow type="increase" />
|
||
积分
|
||
</StatHelpText>
|
||
</Stat>
|
||
</CardBody>
|
||
</Card>
|
||
</GridItem>
|
||
|
||
{/* 累计消费 */}
|
||
<GridItem>
|
||
<Card
|
||
bg={forumColors.background.card}
|
||
borderRadius="xl"
|
||
border="1px solid"
|
||
borderColor={forumColors.border.default}
|
||
>
|
||
<CardBody>
|
||
<Stat>
|
||
<StatLabel fontSize="sm" color={forumColors.text.secondary}>
|
||
<Icon as={Activity} boxSize="16px" mr="1" />
|
||
累计消费
|
||
</StatLabel>
|
||
<StatNumber fontSize="2xl" color={forumColors.text.primary}>
|
||
{account?.total_spent?.toFixed(0) || 0}
|
||
</StatNumber>
|
||
<StatHelpText color={forumColors.text.tertiary}>积分</StatHelpText>
|
||
</Stat>
|
||
</CardBody>
|
||
</Card>
|
||
</GridItem>
|
||
</Grid>
|
||
|
||
{/* 每日签到 */}
|
||
<Card
|
||
bg={forumColors.background.card}
|
||
borderRadius="xl"
|
||
border="1px solid"
|
||
borderColor={forumColors.border.default}
|
||
mb="6"
|
||
>
|
||
<CardHeader>
|
||
<HStack justify="space-between">
|
||
<HStack spacing="2">
|
||
<Icon as={Gift} boxSize="20px" color={forumColors.primary[500]} />
|
||
<Heading size="md" color={forumColors.text.primary}>
|
||
每日签到
|
||
</Heading>
|
||
</HStack>
|
||
<Button
|
||
bg={forumColors.gradients.goldPrimary}
|
||
color={forumColors.background.main}
|
||
fontWeight="bold"
|
||
onClick={handleClaimDailyBonus}
|
||
isLoading={claiming}
|
||
loadingText="领取中..."
|
||
_hover={{ opacity: 0.9 }}
|
||
leftIcon={<Icon as={Calendar} />}
|
||
>
|
||
领取今日奖励
|
||
</Button>
|
||
</HStack>
|
||
</CardHeader>
|
||
<CardBody>
|
||
<VStack align="start" spacing="3">
|
||
<HStack spacing="2">
|
||
<Icon as={Calendar} boxSize="16px" color={forumColors.text.secondary} />
|
||
<Text fontSize="sm" color={forumColors.text.secondary}>
|
||
每日登录可领取 100 积分奖励
|
||
</Text>
|
||
</HStack>
|
||
{account?.last_daily_bonus_at && (
|
||
<Text fontSize="xs" color={forumColors.text.tertiary}>
|
||
上次领取时间:{new Date(account.last_daily_bonus_at).toLocaleString('zh-CN')}
|
||
</Text>
|
||
)}
|
||
</VStack>
|
||
</CardBody>
|
||
</Card>
|
||
|
||
{/* 详细信息标签页 */}
|
||
<Card
|
||
bg={forumColors.background.card}
|
||
borderRadius="xl"
|
||
border="1px solid"
|
||
borderColor={forumColors.border.default}
|
||
>
|
||
<CardBody>
|
||
<Tabs colorScheme="yellow" variant="soft-rounded">
|
||
<TabList mb="4">
|
||
<Tab
|
||
_selected={{
|
||
bg: forumColors.gradients.goldPrimary,
|
||
color: forumColors.background.main,
|
||
}}
|
||
>
|
||
<Icon as={History} boxSize="16px" mr="2" />
|
||
交易记录
|
||
</Tab>
|
||
<Tab
|
||
_selected={{
|
||
bg: forumColors.gradients.goldPrimary,
|
||
color: forumColors.background.main,
|
||
}}
|
||
>
|
||
<Icon as={Activity} boxSize="16px" mr="2" />
|
||
积分明细
|
||
</Tab>
|
||
</TabList>
|
||
|
||
<TabPanels>
|
||
{/* 交易记录 */}
|
||
<TabPanel>
|
||
<Box>
|
||
<Text color={forumColors.text.secondary} textAlign="center" py="10">
|
||
暂无交易记录
|
||
</Text>
|
||
</Box>
|
||
</TabPanel>
|
||
|
||
{/* 积分明细 */}
|
||
<TabPanel>
|
||
<Box>
|
||
<Text color={forumColors.text.secondary} textAlign="center" py="10">
|
||
暂无积分明细
|
||
</Text>
|
||
</Box>
|
||
</TabPanel>
|
||
</TabPanels>
|
||
</Tabs>
|
||
</CardBody>
|
||
</Card>
|
||
</Container>
|
||
</Box>
|
||
);
|
||
};
|
||
|
||
export default ProfilePage;
|