feat(StrategyCenter): 新增投资规划中心组件

- Q1计划卡片(进度条+要点列表)
- 银行股防守卡片(仓位+策略)
- AI算力交易卡片(浮盈数据)
- 消费复盘卡片(趋势图+心得)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
zdl
2025-12-22 16:51:01 +08:00
parent 1a55e037c9
commit 10e34d911f
6 changed files with 502 additions and 0 deletions

View File

@@ -0,0 +1,84 @@
// AI 算力交易卡片
import React from 'react';
import { Box, Text, VStack, HStack, Icon } from '@chakra-ui/react';
import { Cpu, TrendingUp, Lightbulb } from 'lucide-react';
const AITradingCard = ({
title = 'AI 算力交易',
currentProfit = 8.5,
targetProfit = 8.5,
strategies = [
'AI界缓充提镂',
'筱略:高源分析',
],
}) => {
const profitColor = currentProfit >= 0 ? '#EF4444' : '#22C55E';
const profitSign = currentProfit >= 0 ? '+' : '';
return (
<Box
bg="rgba(26, 26, 46, 0.7)"
borderRadius="lg"
p={4}
border="1px solid"
borderColor="rgba(212, 175, 55, 0.15)"
backdropFilter="blur(8px)"
h="100%"
>
<VStack align="stretch" spacing={3}>
{/* 标题 */}
<HStack spacing={2}>
<Icon as={Cpu} boxSize={4} color="#22C55E" />
<Text
fontSize="sm"
fontWeight="bold"
color="rgba(255, 255, 255, 0.95)"
>
[{title}]
</Text>
</HStack>
{/* 浮盈数据 */}
<VStack align="stretch" spacing={2}>
<HStack spacing={2}>
<Icon as={TrendingUp} boxSize={3} color={profitColor} />
<Text fontSize="xs" color="rgba(255, 255, 255, 0.6)">
当前浮盈:
</Text>
<Text fontSize="xs" color={profitColor} fontWeight="bold">
{profitSign}{currentProfit}%
</Text>
</HStack>
<HStack spacing={2}>
<Icon as={TrendingUp} boxSize={3} color={profitColor} />
<Text fontSize="xs" color="rgba(255, 255, 255, 0.6)">
当前浮盈:
</Text>
<Text fontSize="xs" color={profitColor} fontWeight="bold">
{profitSign}{targetProfit}%
</Text>
</HStack>
</VStack>
{/* 策略列表 */}
<VStack align="stretch" spacing={1}>
<HStack spacing={1}>
<Icon as={Lightbulb} boxSize={3} color="rgba(212, 175, 55, 0.9)" />
<Text fontSize="xs" color="rgba(255, 255, 255, 0.6)">
策略:
</Text>
</HStack>
{strategies.map((item, index) => (
<HStack key={index} spacing={1} fontSize="xs" pl={4}>
<Text color="rgba(255, 255, 255, 0.5)"></Text>
<Text color="rgba(255, 255, 255, 0.85)">{item}</Text>
</HStack>
))}
</VStack>
</VStack>
</Box>
);
};
export default AITradingCard;

View File

@@ -0,0 +1,81 @@
// 银行股防守卡片
import React from 'react';
import { Box, Text, VStack, HStack, Icon } from '@chakra-ui/react';
import { Building2, Lock, TrendingUp, Lightbulb } from 'lucide-react';
const DefenseStrategyCard = ({
title = '银行股防守',
position = '30%',
strategy = '高股息',
strategies = [
'AI辅AEI银行化分析',
'AI筏跌股鬈股',
],
}) => {
return (
<Box
bg="rgba(26, 26, 46, 0.7)"
borderRadius="lg"
p={4}
border="1px solid"
borderColor="rgba(212, 175, 55, 0.15)"
backdropFilter="blur(8px)"
h="100%"
>
<VStack align="stretch" spacing={3}>
{/* 标题 */}
<HStack spacing={2}>
<Icon as={Building2} boxSize={4} color="rgba(212, 175, 55, 0.9)" />
<Text
fontSize="sm"
fontWeight="bold"
color="rgba(255, 255, 255, 0.95)"
>
[{title}]
</Text>
</HStack>
{/* 仓位和策略 */}
<VStack align="stretch" spacing={2}>
<HStack spacing={2}>
<Icon as={Lock} boxSize={3} color="rgba(255, 255, 255, 0.5)" />
<Text fontSize="xs" color="rgba(255, 255, 255, 0.6)">
仓位:
</Text>
<Text fontSize="xs" color="rgba(255, 255, 255, 0.9)" fontWeight="medium">
{position}
</Text>
</HStack>
<HStack spacing={2}>
<Icon as={TrendingUp} boxSize={3} color="rgba(255, 255, 255, 0.5)" />
<Text fontSize="xs" color="rgba(255, 255, 255, 0.6)">
策略:
</Text>
<Text fontSize="xs" color="rgba(255, 255, 255, 0.9)" fontWeight="medium">
{strategy}
</Text>
</HStack>
</VStack>
{/* 策略列表 */}
<VStack align="stretch" spacing={1}>
<HStack spacing={1}>
<Icon as={Lightbulb} boxSize={3} color="#22C55E" />
<Text fontSize="xs" color="rgba(255, 255, 255, 0.6)">
策略:
</Text>
</HStack>
{strategies.map((item, index) => (
<HStack key={index} spacing={1} fontSize="xs" pl={4}>
<Text color="rgba(255, 255, 255, 0.5)"></Text>
<Text color="rgba(255, 255, 255, 0.85)">{item}</Text>
</HStack>
))}
</VStack>
</VStack>
</Box>
);
};
export default DefenseStrategyCard;

View File

@@ -0,0 +1,126 @@
// 季度计划卡片 - 2025 Q1 计划
import React from 'react';
import { Box, Text, VStack, HStack, Progress, Icon } from '@chakra-ui/react';
import { Calendar } from 'lucide-react';
const QuarterPlanCard = ({
title = '2025 Q1 计划',
progress = { execute: 70, strategy: 100, target: 15 },
keyPoints = [
{ label: '重点', value: 'AI、数字经济' },
{ label: '重点', value: 'AI、数字经济' },
{ label: '目标', value: '收益率+15%' },
],
}) => {
return (
<Box
bg="rgba(26, 26, 46, 0.7)"
borderRadius="lg"
p={4}
border="1px solid"
borderColor="rgba(212, 175, 55, 0.15)"
backdropFilter="blur(8px)"
h="100%"
>
<VStack align="stretch" spacing={3}>
{/* 标题 */}
<HStack spacing={2}>
<Icon as={Calendar} boxSize={4} color="rgba(100, 149, 237, 0.9)" />
<Text
fontSize="sm"
fontWeight="bold"
color="rgba(255, 255, 255, 0.95)"
>
[{title}]
</Text>
</HStack>
{/* 进度条区域 */}
<VStack align="stretch" spacing={2}>
{/* 进行 */}
<HStack spacing={2}>
<Text fontSize="xs" color="rgba(255, 255, 255, 0.6)" w="35px">
进行
</Text>
<Box flex={1}>
<Progress
value={progress.execute}
size="sm"
borderRadius="full"
bg="rgba(255, 255, 255, 0.1)"
sx={{
'& > div': {
bg: 'linear-gradient(90deg, #3B82F6 0%, #60A5FA 100%)',
},
}}
/>
</Box>
<Text fontSize="xs" color="rgba(255, 255, 255, 0.8)" w="35px" textAlign="right">
{progress.execute}%
</Text>
</HStack>
{/* 缓略 */}
<HStack spacing={2}>
<Text fontSize="xs" color="rgba(255, 255, 255, 0.6)" w="35px">
缓略
</Text>
<Box flex={1}>
<Progress
value={progress.strategy}
size="sm"
borderRadius="full"
bg="rgba(255, 255, 255, 0.1)"
sx={{
'& > div': {
bg: 'linear-gradient(90deg, #3B82F6 0%, #60A5FA 100%)',
},
}}
/>
</Box>
<Text fontSize="xs" color="rgba(255, 255, 255, 0.8)" w="35px" textAlign="right">
{progress.strategy}%
</Text>
</HStack>
{/* 目标 */}
<HStack spacing={2}>
<Text fontSize="xs" color="rgba(255, 255, 255, 0.6)" w="35px">
目标
</Text>
<Box flex={1}>
<Progress
value={Math.abs(progress.target)}
max={20}
size="sm"
borderRadius="full"
bg="rgba(255, 255, 255, 0.1)"
sx={{
'& > div': {
bg: 'linear-gradient(90deg, #3B82F6 0%, #60A5FA 100%)',
},
}}
/>
</Box>
<Text fontSize="xs" color="#22C55E" w="35px" textAlign="right">
+{progress.target}%
</Text>
</HStack>
</VStack>
{/* 要点列表 */}
<VStack align="stretch" spacing={1} mt={1}>
{keyPoints.map((point, index) => (
<HStack key={index} spacing={1} fontSize="xs">
<Text color="rgba(255, 255, 255, 0.5)"></Text>
<Text color="rgba(255, 255, 255, 0.6)">{point.label}:</Text>
<Text color="rgba(255, 255, 255, 0.85)">{point.value}</Text>
</HStack>
))}
</VStack>
</VStack>
</Box>
);
};
export default QuarterPlanCard;

View File

@@ -0,0 +1,143 @@
// 消费复盘卡片(带图表)
import React, { useMemo } from 'react';
import { Box, Text, VStack, HStack, Icon } from '@chakra-ui/react';
import { ShoppingBag, Heart } from 'lucide-react';
const ReviewCard = ({
title = '消费复盘',
chartData = [8000, 10000, 9500, 11000, 12000, 11500, 10500, 9000, 10000, 11000, 12500, 11000],
insight = '关注复苏节奏',
}) => {
// 生成图表路径
const { linePath, areaPath } = useMemo(() => {
if (!chartData || chartData.length < 2) return { linePath: '', areaPath: '' };
const width = 140;
const height = 60;
const padding = { top: 8, right: 4, bottom: 16, left: 4 };
const chartWidth = width - padding.left - padding.right;
const chartHeight = height - padding.top - padding.bottom;
const min = Math.min(...chartData);
const max = Math.max(...chartData);
const range = max - min || 1;
const points = chartData.map((val, i) => {
const x = padding.left + (i / (chartData.length - 1)) * chartWidth;
const y = padding.top + chartHeight - ((val - min) / range) * chartHeight;
return { x, y };
});
const linePathStr = points.map((p, i) => `${i === 0 ? 'M' : 'L'} ${p.x},${p.y}`).join(' ');
const areaPathStr = `${linePathStr} L ${points[points.length - 1].x},${height - padding.bottom} L ${padding.left},${height - padding.bottom} Z`;
return { linePath: linePathStr, areaPath: areaPathStr };
}, [chartData]);
// Y轴刻度
const yTicks = useMemo(() => {
const max = Math.max(...chartData);
return [max, Math.round(max / 2), 0];
}, [chartData]);
// X轴刻度
const xTicks = ['10:05', '11:13', '12:15', '13:05'];
return (
<Box
bg="rgba(26, 26, 46, 0.7)"
borderRadius="lg"
p={4}
border="1px solid"
borderColor="rgba(212, 175, 55, 0.15)"
backdropFilter="blur(8px)"
h="100%"
>
<VStack align="stretch" spacing={2}>
{/* 标题 */}
<HStack spacing={2}>
<Icon as={ShoppingBag} boxSize={4} color="#F59E0B" />
<Text
fontSize="sm"
fontWeight="bold"
color="rgba(255, 255, 255, 0.95)"
>
[{title}]
</Text>
</HStack>
{/* 图表区域 */}
<Box position="relative" h="70px">
<svg width="100%" height="70" viewBox="0 0 140 70" preserveAspectRatio="none">
{/* Y轴标签 */}
<text x="2" y="12" fontSize="6" fill="rgba(255,255,255,0.4)">
{yTicks[0]}
</text>
<text x="2" y="35" fontSize="6" fill="rgba(255,255,255,0.4)">
{yTicks[1]}
</text>
<text x="2" y="58" fontSize="6" fill="rgba(255,255,255,0.4)">
{yTicks[2]}
</text>
{/* 网格线 */}
<line x1="20" y1="8" x2="136" y2="8" stroke="rgba(255,255,255,0.1)" strokeWidth="0.5" strokeDasharray="2,2" />
<line x1="20" y1="30" x2="136" y2="30" stroke="rgba(255,255,255,0.1)" strokeWidth="0.5" strokeDasharray="2,2" />
<line x1="20" y1="52" x2="136" y2="52" stroke="rgba(255,255,255,0.1)" strokeWidth="0.5" strokeDasharray="2,2" />
{/* 填充区域 */}
<path
d={areaPath}
fill="url(#reviewGradient)"
/>
{/* 线条 */}
<path
d={linePath}
fill="none"
stroke="#F59E0B"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
{/* 渐变定义 */}
<defs>
<linearGradient id="reviewGradient" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" stopColor="rgba(245, 158, 11, 0.3)" />
<stop offset="100%" stopColor="rgba(245, 158, 11, 0.05)" />
</linearGradient>
</defs>
</svg>
{/* X轴标签 */}
<HStack
position="absolute"
bottom="0"
left="15px"
right="4px"
justify="space-between"
fontSize="6px"
color="rgba(255,255,255,0.4)"
>
{xTicks.map((tick, i) => (
<Text key={i}>{tick}</Text>
))}
</HStack>
</Box>
{/* 心得 */}
<HStack spacing={1} fontSize="xs">
<Text color="rgba(255, 255, 255, 0.5)"></Text>
<Icon as={Heart} boxSize={3} color="#EF4444" />
<Text color="rgba(255, 255, 255, 0.6)">心得:</Text>
<Text color="rgba(255, 255, 255, 0.85)">{insight}</Text>
</HStack>
</VStack>
</Box>
);
};
export default ReviewCard;

View File

@@ -0,0 +1,5 @@
// 投资规划中心子组件导出
export { default as QuarterPlanCard } from './QuarterPlanCard';
export { default as DefenseStrategyCard } from './DefenseStrategyCard';
export { default as AITradingCard } from './AITradingCard';
export { default as ReviewCard } from './ReviewCard';

View File

@@ -0,0 +1,63 @@
// 投资规划中心组件 (Strategy Center)
import React from 'react';
import { Box, Text, HStack, SimpleGrid, Icon } from '@chakra-ui/react';
import { Target } from 'lucide-react';
import GlassCard from '@components/GlassCard';
import {
QuarterPlanCard,
DefenseStrategyCard,
AITradingCard,
ReviewCard,
} from './components';
const StrategyCenter = () => {
return (
<GlassCard
variant="transparent"
rounded="2xl"
padding="md"
hoverable={false}
cornerDecor
>
{/* 标题栏 */}
<HStack mb={4} spacing={2}>
<Icon
as={Target}
boxSize={5}
color="rgba(212, 175, 55, 0.9)"
/>
<Text
fontSize="lg"
fontWeight="bold"
color="rgba(255, 255, 255, 0.95)"
letterSpacing="wide"
>
投资规划中心
</Text>
<Text
fontSize="sm"
color="rgba(255, 255, 255, 0.5)"
fontWeight="normal"
>
(Strategy Center)
</Text>
<Box
h="1px"
flex={1}
bgGradient="linear(to-r, rgba(212, 175, 55, 0.4), transparent)"
ml={2}
/>
</HStack>
{/* 4列卡片布局 */}
<SimpleGrid columns={{ base: 1, md: 2, lg: 4 }} spacing={4}>
<QuarterPlanCard />
<DefenseStrategyCard />
<AITradingCard />
<ReviewCard />
</SimpleGrid>
</GlassCard>
);
};
export default StrategyCenter;