# A股智投分析平台 - 前端实现文档 ## 一、组件清单 ### 1.1 公共组件 | 组件名 | 文件路径 | 功能描述 | 复杂度 | |-------|---------|---------|-------| | Navbar | `components/Navbar.tsx` | 导航栏,含搜索功能 | 高 | | CandlestickChart | `components/CandlestickChart.tsx` | K线蜡烛图+均线+成交量 | 高 | | StockDetailModal | `components/StockDetailModal.tsx` | 个股详情弹窗 | 高 | | SectorDetailModal | `components/SectorDetailModal.tsx` | 版块详情弹窗 | 高 | | Footer | `components/Footer.tsx` | 页脚 | 低 | ### 1.2 页面区块组件 | 组件名 | 文件路径 | 功能描述 | 复杂度 | |-------|---------|---------|-------| | MarketOverview | `sections/MarketOverview.tsx` | 市场概览 | 中 | | MomentumSectors | `sections/MomentumSectors.tsx` | 动量版块分析 | 高 | | HighLowStocks | `sections/HighLowStocks.tsx` | 新高新低个股 | 中 | | PriceDistribution | `sections/PriceDistribution.tsx` | 涨跌幅分布 | 中 | | MomentumRecommendation | `sections/MomentumRecommendation.tsx` | 动量股推荐 | 中 | --- ## 二、核心组件详解 ### 2.1 CandlestickChart 组件 **功能**: K线蜡烛图,支持均线和成交量 **Props** ```typescript interface CandlestickChartProps { data: KLineData[]; // K线数据 height?: number; // 图表高度,默认400 showVolume?: boolean; // 是否显示成交量,默认true showMaSettings?: boolean; // 是否显示均线设置,默认true } ``` **实现要点** - 使用 Recharts ComposedChart 组合图表 - 自定义蜡烛图形状(红涨绿跌) - 支持5条均线(MA5/MA10/MA20/MA30/MA60) - 成交量附图,颜色与K线对应 - 点击均线标签切换显示/隐藏 **代码片段** ```typescript // 均线配置 const defaultMaPeriods: MaPeriod[] = [ { key: 'ma5', label: 'MA5', days: 5, color: '#ff9f43', visible: true }, { key: 'ma10', label: 'MA10', days: 10, color: '#3498db', visible: true }, { key: 'ma20', label: 'MA20', days: 20, color: '#9b59b6', visible: true }, { key: 'ma30', label: 'MA30', days: 30, color: '#e74c3c', visible: false }, { key: 'ma60', label: 'MA60', days: 60, color: '#2ecc71', visible: false }, ]; // 渲染蜡烛图 const renderCandle = (props, maxPrice, minPrice, pricePadding) => { const { x, y, width, height, payload } = props; const { open, close } = payload; const isUp = close >= open; const color = isUp ? '#ff3b30' : '#00c853'; // 计算影线坐标 // 计算实体坐标 // 返回SVG元素 }; ``` ### 2.2 StockDetailModal 组件 **功能**: 个股详情弹窗 **Props** ```typescript interface StockDetailModalProps { stockCode: string | null; // 股票代码 isOpen: boolean; // 是否打开 onClose: () => void; // 关闭回调 } ``` **实现要点** - 使用 Framer Motion 实现动画 - 获取个股详情和K线数据 - 显示基本信息、K线图、技术指标、基本面 - 支持日线/周线/月线切换 **代码片段** ```typescript const [stock, setStock] = useState(null); const [klineData, setKlineData] = useState([]); const [timeRange, setTimeRange] = useState<'day' | 'week' | 'month'>('day'); useEffect(() => { if (stockCode && isOpen) { setStock(stockDataService.getStockDetail(stockCode)); setKlineData(stockDataService.getKLineData(stockCode, 60)); } }, [stockCode, isOpen]); ``` ### 2.3 SectorDetailModal 组件 **功能**: 版块详情弹窗 **Props** ```typescript interface SectorDetailModalProps { sector: Sector | null; // 版块数据 isOpen: boolean; // 是否打开 onClose: () => void; // 关闭回调 onStockClick?: (code: string) => void; // 股票点击回调 } ``` **实现要点** - 三个标签页:历史排名、动量个股、K线走势 - 历史排名使用组合图表(排名线+动量分柱状图) - 动量个股列表支持点击打开个股详情 - K线使用 CandlestickChart 组件 ### 2.4 Navbar 组件 **功能**: 导航栏,含搜索功能 **Props** ```typescript interface NavbarProps { onSectorClick?: (sector: Sector) => void; // 版块点击回调 onStockClick?: (code: string) => void; // 个股点击回调 } ``` **实现要点** - 滚动时添加背景和边框 - 搜索框展开/收起动画 - 实时搜索,分类展示结果 - 点击结果打开对应详情 **代码片段** ```typescript const [searchOpen, setSearchOpen] = useState(false); const [searchKeyword, setSearchKeyword] = useState(''); const [searchResults, setSearchResults] = useState({ sectors: [], stocks: [] }); // 搜索逻辑 useEffect(() => { if (searchKeyword.trim().length >= 1) { const sectors = stockDataService.searchSectors(searchKeyword); const stocks = stockDataService.searchStocks(searchKeyword); setSearchResults({ sectors, stocks }); } }, [searchKeyword]); ``` --- ## 三、数据服务 ### 3.1 StockDataService **文件**: `services/stockData.ts` **主要方法** | 方法名 | 功能 | 返回值 | |-------|------|-------| | `getMarketIndices()` | 获取市场指数 | `MarketIndex[]` | | `getUpDownStats()` | 获取涨跌家数 | `{up, down, flat}` | | `getSectorsWithMomentum()` | 获取版块列表(带动量) | `Sector[]` | | `getSectorRankHistory(name)` | 获取版块历史排名 | `SectorMomentumHistory[]` | | `getSectorStocks(name)` | 获取版块内股票 | `Stock[]` | | `getSectorMomentumStocks(name)` | 获取版块内动量股票 | `MomentumStock[]` | | `getSectorKLineData(name, days)` | 获取版块K线 | `KLineData[]` | | `getNewHighStocks()` | 获取创新高股票 | `HighLowStock[]` | | `getNewLowStocks()` | 获取创新低股票 | `HighLowStock[]` | | `getPriceDistribution()` | 获取涨跌幅分布 | `PriceDistribution[]` | | `getMomentumStocks()` | 获取动量股推荐 | `MomentumStock[]` | | `getStockDetail(code)` | 获取个股详情 | `StockDetail` | | `getKLineData(code, days)` | 获取个股K线 | `KLineData[]` | | `searchSectors(keyword)` | 搜索版块 | `Sector[]` | | `searchStocks(keyword)` | 搜索股票 | `Stock[]` | ### 3.2 均线计算 **代码片段** ```typescript private calculateMA(data: KLineData[]): KLineData[] { const periods = [5, 10, 20, 30, 60]; return data.map((item, index) => { const ma: Record = {}; for (const period of periods) { if (index >= period - 1) { const sum = data .slice(index - period + 1, index + 1) .reduce((acc, d) => acc + d.close, 0); ma[`ma${period}`] = this.formatNumber(sum / period); } } return { ...item, ...ma }; }); } ``` --- ## 四、类型定义 ### 4.1 核心类型 **文件**: `types/index.ts` ```typescript // 股票基础信息 export interface Stock { code: string; // 股票代码 name: string; // 股票名称 price: number; // 当前价格 change: number; // 涨跌额 changePercent: number; // 涨跌幅 volume: number; // 成交量 turnover: number; // 成交额 marketCap?: number; // 总市值 pe?: number; // 市盈率 pb?: number; // 市净率 industry?: string; // 所属行业 } // 版块信息 export interface Sector { name: string; // 版块名称 code: string; // 版块代码 change: number; // 涨跌额 changePercent: number; // 涨跌幅 volume: number; // 成交量 turnover: number; // 成交额 leadingStock?: string; // 领涨股 momentumScore?: number; // 动量分数 rank?: number; // 当前排名 previousRank?: number; // 昨日排名 rankChange?: number; // 排名变化 } // K线数据 export interface KLineData { date: string; // 日期 open: number; // 开盘价 high: number; // 最高价 low: number; // 最低价 close: number; // 收盘价 volume: number; // 成交量 ma5?: number; // 5日均线 ma10?: number; // 10日均线 ma20?: number; // 20日均线 ma30?: number; // 30日均线 ma60?: number; // 60日均线 } // 均线周期配置 export interface MaPeriod { key: string; // 标识 label: string; // 显示名称 days: number; // 周期天数 color: string; // 颜色 visible: boolean; // 是否显示 } ``` --- ## 五、动画实现 ### 5.1 页面加载动画 ```typescript const containerVariants = { hidden: { opacity: 0 }, visible: { opacity: 1, transition: { staggerChildren: 0.1, delayChildren: 0.2 } } }; const itemVariants = { hidden: { opacity: 0, y: 30 }, visible: { opacity: 1, y: 0, transition: { duration: 0.6, ease: [0.165, 0.84, 0.44, 1] as const } } }; ``` ### 5.2 数字动画 ```typescript function AnimatedNumber({ value, decimals = 2 }: { value: number; decimals?: number }) { const [displayValue, setDisplayValue] = useState(0); const prevValue = useRef(value); useEffect(() => { const start = prevValue.current; const end = value; const duration = 800; const startTime = performance.now(); const animate = (currentTime: number) => { const elapsed = currentTime - startTime; const progress = Math.min(elapsed / duration, 1); const easeOut = 1 - Math.pow(1 - progress, 4); const current = start + (end - start) * easeOut; setDisplayValue(current); if (progress < 1) { requestAnimationFrame(animate); } else { prevValue.current = value; } }; requestAnimationFrame(animate); }, [value]); return {displayValue.toFixed(decimals)}; } ``` ### 5.3 弹窗动画 ```typescript {/* 弹窗内容 */} ``` --- ## 六、样式规范 ### 6.1 颜色系统 ```css /* 主色调 */ --background: #0a0a0a; /* 背景色 */ --card: #1a1a1a; /* 卡片背景 */ --border: #2a2a2a; /* 边框色 */ --accent: #ff6b35; /* 强调色(橙色) */ /* 文字色 */ --text-primary: #ffffff; /* 主文字 */ --text-secondary: #b0b0b0; /* 次要文字 */ /* 功能色 */ --up: #ff3b30; /* 上涨(红) */ --down: #00c853; /* 下跌(绿) */ /* 均线色 */ --ma5: #ff9f43; /* MA5 - 橙色 */ --ma10: #3498db; /* MA10 - 蓝色 */ --ma20: #9b59b6; /* MA20 - 紫色 */ --ma30: #e74c3c; /* MA30 - 红色 */ --ma60: #2ecc71; /* MA60 - 绿色 */ ``` ### 6.2 字体规范 ```css /* 字体家族 */ font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; /* 数字字体 */ .number-font { font-family: 'JetBrains Mono', monospace; font-variant-numeric: tabular-nums; } ``` ### 6.3 间距规范 ```css /* 区块间距 */ --section-gap: 3rem; /* 48px */ --card-gap: 1rem; /* 16px */ --card-padding: 1.5rem; /* 24px */ /* 圆角 */ --radius-sm: 8px; --radius-md: 12px; --radius-lg: 16px; ``` --- ## 七、性能优化 ### 7.1 已实现的优化 | 优化项 | 实现方式 | |-------|---------| | 组件懒加载 | 使用动态导入 | | 数据缓存 | useMemo 缓存计算结果 | | 动画优化 | 使用 transform 和 opacity | | 虚拟列表 | 大量数据时使用 | ### 7.2 待优化项 - [ ] 图片懒加载 - [ ] Service Worker 缓存 - [ ] 代码分割优化 - [ ] Tree Shaking --- ## 八、测试策略 ### 8.1 单元测试 ```typescript // 示例: CandlestickChart 测试 describe('CandlestickChart', () => { it('should render candlestick chart', () => { const data = [ { date: '2024-01-15', open: 50, high: 55, low: 48, close: 52, volume: 1000000 } ]; render(); expect(screen.getByRole('img')).toBeInTheDocument(); }); }); ``` ### 8.2 E2E测试 ```typescript // 示例: 搜索功能测试 describe('Search', () => { it('should search and display results', () => { cy.visit('/'); cy.get('[data-testid="search-button"]').click(); cy.get('[data-testid="search-input"]').type('茅台'); cy.get('[data-testid="search-result"]').should('contain', '贵州茅台'); }); }); ``` --- ## 九、待实现功能 ### 9.1 前端待实现 - [ ] 用户登录/注册页面 - [ ] 自选股管理页面 - [ ] 预警设置页面 - [ ] 主题切换(深色/浅色) - [ ] 多语言支持 ### 9.2 与后端对接 - [ ] 接入真实API - [ ] WebSocket实时数据 - [ ] 用户认证 - [ ] 数据持久化