Initial commit
This commit is contained in:
364
src/views/TradingSimulation/components/AccountOverview.js
Normal file
364
src/views/TradingSimulation/components/AccountOverview.js
Normal file
@@ -0,0 +1,364 @@
|
||||
// src/views/TradingSimulation/components/AccountOverview.js - 账户概览组件(现代化版本)
|
||||
import React from 'react';
|
||||
import {
|
||||
Grid,
|
||||
GridItem,
|
||||
Stat,
|
||||
StatLabel,
|
||||
StatNumber,
|
||||
StatHelpText,
|
||||
StatArrow,
|
||||
Box,
|
||||
Text,
|
||||
Badge,
|
||||
VStack,
|
||||
HStack,
|
||||
Progress,
|
||||
useColorModeValue,
|
||||
Icon,
|
||||
Flex,
|
||||
SimpleGrid,
|
||||
Card,
|
||||
CardBody,
|
||||
CardHeader
|
||||
} from '@chakra-ui/react';
|
||||
import { FiTrendingUp, FiTrendingDown, FiDollarSign, FiPieChart, FiTarget, FiActivity } from 'react-icons/fi';
|
||||
|
||||
// 导入现有的图表组件
|
||||
import DonutChart from '../../../components/Charts/DonutChart';
|
||||
import IconBox from '../../../components/Icons/IconBox';
|
||||
|
||||
export default function AccountOverview({ account }) {
|
||||
const textColor = useColorModeValue('gray.700', 'white');
|
||||
const secondaryColor = useColorModeValue('gray.500', 'gray.400');
|
||||
const profitColor = account?.totalProfit >= 0 ? 'green.500' : 'red.500';
|
||||
const profitBg = useColorModeValue(
|
||||
account?.totalProfit >= 0 ? 'green.50' : 'red.50',
|
||||
account?.totalProfit >= 0 ? 'green.900' : 'red.900'
|
||||
);
|
||||
|
||||
if (!account) {
|
||||
return (
|
||||
<Box p={4}>
|
||||
<Text color={secondaryColor}>暂无账户数据</Text>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
// 安全地计算资产配置比例
|
||||
const cashRatio = account?.totalAssets > 0 ? (account.availableCash / account.totalAssets) * 100 : 0;
|
||||
const stockRatio = account?.totalAssets > 0 ? (account.marketValue / account.totalAssets) * 100 : 0;
|
||||
|
||||
// 格式化数字
|
||||
const formatCurrency = (amount) => {
|
||||
return new Intl.NumberFormat('zh-CN', {
|
||||
style: 'currency',
|
||||
currency: 'CNY',
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2
|
||||
}).format(amount || 0);
|
||||
};
|
||||
|
||||
const formatPercent = (percent) => {
|
||||
return `${(percent || 0) >= 0 ? '+' : ''}${(percent || 0).toFixed(2)}%`;
|
||||
};
|
||||
|
||||
// 安全地准备资产配置饼图数据
|
||||
const assetAllocationData = account?.totalAssets > 0 ? [
|
||||
(account.availableCash / account.totalAssets) * 100,
|
||||
(account.marketValue / account.totalAssets) * 100
|
||||
] : [100, 0];
|
||||
|
||||
const assetAllocationOptions = {
|
||||
labels: ['现金资产', '股票资产'],
|
||||
colors: ['#4299E1', '#48BB78'],
|
||||
chart: {
|
||||
width: "100%",
|
||||
height: "280px"
|
||||
},
|
||||
states: {
|
||||
hover: {
|
||||
filter: {
|
||||
type: "none",
|
||||
},
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
show: true,
|
||||
position: 'bottom',
|
||||
fontSize: '12px',
|
||||
labels: {
|
||||
colors: textColor
|
||||
}
|
||||
},
|
||||
dataLabels: {
|
||||
enabled: true,
|
||||
style: {
|
||||
fontSize: '12px',
|
||||
fontWeight: 'bold',
|
||||
colors: ['#fff']
|
||||
},
|
||||
formatter: function (val) {
|
||||
return (val || 0).toFixed(1) + "%"
|
||||
}
|
||||
},
|
||||
plotOptions: {
|
||||
pie: {
|
||||
expandOnClick: false,
|
||||
donut: {
|
||||
labels: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
fill: {
|
||||
colors: ['#4299E1', '#48BB78'],
|
||||
},
|
||||
tooltip: {
|
||||
enabled: true,
|
||||
theme: "dark",
|
||||
y: {
|
||||
formatter: function(val) {
|
||||
return formatCurrency(val / 100 * (account?.totalAssets || 0))
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<SimpleGrid columns={{ base: 1, lg: 2 }} spacing={6}>
|
||||
{/* 左侧:主要资产数据 */}
|
||||
<VStack spacing={6} align="stretch">
|
||||
{/* 核心资产指标 */}
|
||||
<SimpleGrid columns={{ base: 2, md: 2 }} spacing={4}>
|
||||
{/* 总资产卡片 */}
|
||||
<Card minH="120px">
|
||||
<CardBody>
|
||||
<Flex direction="row" align="center" justify="center" w="100%">
|
||||
<Stat me="auto">
|
||||
<StatLabel
|
||||
fontSize="sm"
|
||||
color={secondaryColor}
|
||||
fontWeight="bold"
|
||||
pb=".1rem"
|
||||
>
|
||||
总资产
|
||||
</StatLabel>
|
||||
<Flex>
|
||||
<StatNumber fontSize="lg" color={textColor} fontWeight="bold">
|
||||
{formatCurrency(account?.totalAssets)}
|
||||
</StatNumber>
|
||||
</Flex>
|
||||
</Stat>
|
||||
<IconBox
|
||||
as="div"
|
||||
h={"45px"}
|
||||
w={"45px"}
|
||||
bg="linear-gradient(90deg, #4481EB 0%, #04BEFE 100%)"
|
||||
icon={<Icon as={FiDollarSign} color="white" w="24px" h="24px" />}
|
||||
/>
|
||||
</Flex>
|
||||
</CardBody>
|
||||
</Card>
|
||||
|
||||
{/* 总收益卡片 */}
|
||||
<Card minH="120px">
|
||||
<CardBody>
|
||||
<Flex direction="row" align="center" justify="center" w="100%">
|
||||
<Stat me="auto">
|
||||
<StatLabel
|
||||
fontSize="sm"
|
||||
color={secondaryColor}
|
||||
fontWeight="bold"
|
||||
pb=".1rem"
|
||||
>
|
||||
总收益
|
||||
</StatLabel>
|
||||
<Flex align="center">
|
||||
<StatNumber fontSize="lg" color={profitColor} fontWeight="bold">
|
||||
{formatCurrency(account?.totalProfit)}
|
||||
</StatNumber>
|
||||
<StatArrow
|
||||
type={(account?.totalProfit || 0) >= 0 ? 'increase' : 'decrease'}
|
||||
color={profitColor}
|
||||
ml={2}
|
||||
/>
|
||||
</Flex>
|
||||
<StatHelpText color={profitColor} fontSize="sm" fontWeight="bold">
|
||||
{formatPercent(account?.totalProfitPercent)}
|
||||
</StatHelpText>
|
||||
</Stat>
|
||||
<IconBox
|
||||
as="div"
|
||||
h={"45px"}
|
||||
w={"45px"}
|
||||
bg={(account?.totalProfit || 0) >= 0
|
||||
? "linear-gradient(90deg, #4FD1C7 0%, #81E6D9 100%)"
|
||||
: "linear-gradient(90deg, #FEB2B2 0%, #F56565 100%)"
|
||||
}
|
||||
icon={
|
||||
<Icon
|
||||
as={(account?.totalProfit || 0) >= 0 ? FiTrendingUp : FiTrendingDown}
|
||||
color="white"
|
||||
w="24px"
|
||||
h="24px"
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</Flex>
|
||||
</CardBody>
|
||||
</Card>
|
||||
|
||||
{/* 可用资金卡片 */}
|
||||
<Card minH="120px">
|
||||
<CardBody>
|
||||
<Flex direction="row" align="center" justify="center" w="100%">
|
||||
<Stat me="auto">
|
||||
<StatLabel
|
||||
fontSize="sm"
|
||||
color={secondaryColor}
|
||||
fontWeight="bold"
|
||||
pb=".1rem"
|
||||
>
|
||||
可用资金
|
||||
</StatLabel>
|
||||
<Flex>
|
||||
<StatNumber fontSize="lg" color={textColor} fontWeight="bold">
|
||||
{formatCurrency(account?.availableCash)}
|
||||
</StatNumber>
|
||||
</Flex>
|
||||
<StatHelpText color={secondaryColor} fontSize="xs">
|
||||
现金占比: {(cashRatio || 0).toFixed(1)}%
|
||||
</StatHelpText>
|
||||
</Stat>
|
||||
<IconBox
|
||||
as="div"
|
||||
h={"45px"}
|
||||
w={"45px"}
|
||||
bg="linear-gradient(90deg, #FFE57F 0%, #FFB74D 100%)"
|
||||
icon={<Icon as={FiTarget} color="white" w="24px" h="24px" />}
|
||||
/>
|
||||
</Flex>
|
||||
</CardBody>
|
||||
</Card>
|
||||
|
||||
{/* 持仓市值卡片 */}
|
||||
<Card minH="120px">
|
||||
<CardBody>
|
||||
<Flex direction="row" align="center" justify="center" w="100%">
|
||||
<Stat me="auto">
|
||||
<StatLabel
|
||||
fontSize="sm"
|
||||
color={secondaryColor}
|
||||
fontWeight="bold"
|
||||
pb=".1rem"
|
||||
>
|
||||
持仓市值
|
||||
</StatLabel>
|
||||
<Flex>
|
||||
<StatNumber fontSize="lg" color={textColor} fontWeight="bold">
|
||||
{formatCurrency(account?.marketValue)}
|
||||
</StatNumber>
|
||||
</Flex>
|
||||
<StatHelpText color={secondaryColor} fontSize="xs">
|
||||
持仓占比: {(stockRatio || 0).toFixed(1)}%
|
||||
</StatHelpText>
|
||||
</Stat>
|
||||
<IconBox
|
||||
as="div"
|
||||
h={"45px"}
|
||||
w={"45px"}
|
||||
bg="linear-gradient(90deg, #9F7AEA 0%, #805AD5 100%)"
|
||||
icon={<Icon as={FiPieChart} color="white" w="24px" h="24px" />}
|
||||
/>
|
||||
</Flex>
|
||||
</CardBody>
|
||||
</Card>
|
||||
</SimpleGrid>
|
||||
|
||||
{/* 风险等级和账户状态 */}
|
||||
<Card>
|
||||
<CardBody>
|
||||
<VStack spacing={4}>
|
||||
<HStack justify="space-between" w="full">
|
||||
<HStack spacing={3}>
|
||||
<IconBox
|
||||
as="div"
|
||||
h={"35px"}
|
||||
w={"35px"}
|
||||
bg="linear-gradient(90deg, #F093FB 0%, #F5576C 100%)"
|
||||
icon={<Icon as={FiActivity} color="white" w="16px" h="16px" />}
|
||||
/>
|
||||
<VStack align="start" spacing={0}>
|
||||
<Text fontSize="sm" fontWeight="bold" color={textColor}>账户状态</Text>
|
||||
<Text fontSize="xs" color={secondaryColor}>风险等级: 中等</Text>
|
||||
</VStack>
|
||||
</HStack>
|
||||
<Badge
|
||||
colorScheme={(account?.totalProfit || 0) >= 0 ? 'green' : 'red'}
|
||||
variant="solid"
|
||||
borderRadius="full"
|
||||
px={3}
|
||||
py={1}
|
||||
>
|
||||
{(account?.totalProfit || 0) >= 0 ? '盈利中' : '亏损中'}
|
||||
</Badge>
|
||||
</HStack>
|
||||
|
||||
<HStack justify="space-between" w="full" fontSize="xs" color={secondaryColor}>
|
||||
<Text>创建时间: {account?.createdAt ? new Date(account.createdAt).toLocaleDateString('zh-CN') : '-'}</Text>
|
||||
<Text>最后更新: {account?.lastUpdated ? new Date(account.lastUpdated).toLocaleString('zh-CN') : '-'}</Text>
|
||||
</HStack>
|
||||
</VStack>
|
||||
</CardBody>
|
||||
</Card>
|
||||
</VStack>
|
||||
|
||||
{/* 右侧:资产配置图表 */}
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<HStack justify="space-between" w="full">
|
||||
<Text fontSize="lg" fontWeight="bold" color={textColor}>
|
||||
资产配置
|
||||
</Text>
|
||||
<Badge colorScheme="blue" variant="outline">
|
||||
实时更新
|
||||
</Badge>
|
||||
</HStack>
|
||||
</CardHeader>
|
||||
<CardBody>
|
||||
<Box h="280px">
|
||||
<DonutChart
|
||||
chartData={assetAllocationData}
|
||||
chartOptions={assetAllocationOptions}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
{/* 详细配置信息 */}
|
||||
<VStack spacing={3} mt={4}>
|
||||
<HStack justify="space-between" w="full">
|
||||
<HStack spacing={2}>
|
||||
<Box w={3} h={3} bg="blue.400" borderRadius="sm" />
|
||||
<Text fontSize="sm" color={textColor}>现金资产</Text>
|
||||
</HStack>
|
||||
<Text fontSize="sm" fontWeight="bold" color={textColor}>
|
||||
{formatCurrency(account?.availableCash)}
|
||||
</Text>
|
||||
</HStack>
|
||||
|
||||
<HStack justify="space-between" w="full">
|
||||
<HStack spacing={2}>
|
||||
<Box w={3} h={3} bg="green.400" borderRadius="sm" />
|
||||
<Text fontSize="sm" color={textColor}>股票资产</Text>
|
||||
</HStack>
|
||||
<Text fontSize="sm" fontWeight="bold" color={textColor}>
|
||||
{formatCurrency(account?.marketValue)}
|
||||
</Text>
|
||||
</HStack>
|
||||
</VStack>
|
||||
</CardBody>
|
||||
</Card>
|
||||
</SimpleGrid>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user