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:
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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';
|
||||
63
src/views/Profile/components/StrategyCenter/index.js
Normal file
63
src/views/Profile/components/StrategyCenter/index.js
Normal 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;
|
||||
Reference in New Issue
Block a user