图表组件迁移: - AssetTrendChart: 资产走势折线图 → ECharts 面积图 - AssetAllocationChart: 资产配置环形图 → ECharts 饼图 - PositionDistributionChart: 持仓分布饼图 → ECharts 饼图 - ProfitAnalysisChart: 盈亏分析柱状图 → ECharts 柱状图 删除的 ApexCharts 组件: - src/components/Charts/LineChart.js - src/components/Charts/BarChart.js - src/components/Charts/PieChart.js - src/components/Charts/DonutChart.js 技术改进: - 统一使用 ECharts 作为通用图表库 - 新组件使用 TypeScript,类型安全 - 为后续移除 apexcharts 依赖做准备
304 lines
11 KiB
JavaScript
304 lines
11 KiB
JavaScript
// 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 { AssetAllocationChart } from './AssetAllocationChart';
|
|
import IconBox from '../../../components/Icons/IconBox';
|
|
|
|
export default function AccountOverview({ account, tradingEvents }) {
|
|
// tradingEvents 已传递,可用于将来添加的账户重置等功能
|
|
// 例如: tradingEvents.trackAccountReset(beforeResetData)
|
|
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)}%`;
|
|
};
|
|
|
|
|
|
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>
|
|
<AssetAllocationChart
|
|
cashAmount={account?.availableCash || 0}
|
|
stockAmount={account?.marketValue || 0}
|
|
height={280}
|
|
/>
|
|
|
|
{/* 详细配置信息 */}
|
|
<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>
|
|
);
|
|
}
|