diff --git a/src/views/Community/components/HeroPanel.js b/src/views/Community/components/HeroPanel.js index b9b7345e..b144f0a1 100644 --- a/src/views/Community/components/HeroPanel.js +++ b/src/views/Community/components/HeroPanel.js @@ -96,30 +96,39 @@ const isInTradingTime = () => { }; /** - * 紧凑型K线指数卡片 + * 精美K线指数卡片 - 类似 KLineChartModal 风格 */ const CompactIndexCard = ({ indexCode, indexName }) => { const [chartData, setChartData] = useState(null); const [loading, setLoading] = useState(true); const [latestData, setLatestData] = useState(null); - const upColor = '#ec0000'; - const downColor = '#00da3c'; + const upColor = '#ef5350'; // 涨 - 红色 + const downColor = '#26a69a'; // 跌 - 绿色 const loadData = useCallback(async () => { const data = await fetchIndexKline(indexCode); if (data?.data?.length > 0) { const latest = data.data[data.data.length - 1]; - const prevClose = latest.prev_close || latest.close; + const prevClose = latest.prev_close || data.data[data.data.length - 2]?.close || latest.open; + const changeAmount = latest.close - prevClose; + const changePct = prevClose ? ((changeAmount / prevClose) * 100) : 0; + setLatestData({ close: latest.close, - change: prevClose ? (((latest.close - prevClose) / prevClose) * 100).toFixed(2) : '0.00', - isPositive: latest.close >= prevClose + open: latest.open, + high: latest.high, + low: latest.low, + changeAmount: changeAmount, + changePct: changePct, + isPositive: changeAmount >= 0 }); - const recentData = data.data.slice(-40); + + const recentData = data.data.slice(-60); // 增加到60天 setChartData({ dates: recentData.map(item => item.time), klineData: recentData.map(item => [item.open, item.close, item.low, item.high]), + volumes: recentData.map(item => item.volume || 0), rawData: recentData }); } @@ -134,58 +143,204 @@ const CompactIndexCard = ({ indexCode, indexName }) => { if (!chartData) return {}; return { backgroundColor: 'transparent', - grid: { left: 5, right: 5, top: 5, bottom: 5, containLabel: false }, + grid: [ + { left: 0, right: 0, top: 8, bottom: 28, containLabel: false }, + { left: 0, right: 0, top: '75%', bottom: 4, containLabel: false } + ], tooltip: { trigger: 'axis', - axisPointer: { type: 'cross', lineStyle: { color: 'rgba(255, 215, 0, 0.5)', width: 1, type: 'dashed' } }, - backgroundColor: 'rgba(20, 20, 20, 0.95)', - borderColor: '#FFD700', + axisPointer: { + type: 'cross', + crossStyle: { color: 'rgba(255, 215, 0, 0.6)', width: 1 }, + lineStyle: { color: 'rgba(255, 215, 0, 0.4)', width: 1, type: 'dashed' } + }, + backgroundColor: 'rgba(15, 15, 25, 0.98)', + borderColor: 'rgba(255, 215, 0, 0.5)', borderWidth: 1, - textStyle: { color: '#fff', fontSize: 10, fontFamily: 'monospace' }, - padding: [6, 10], + borderRadius: 8, + padding: [12, 16], + textStyle: { color: '#e0e0e0', fontSize: 12 }, + extraCssText: 'box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);', formatter: (params) => { - const idx = params[0].dataIndex; + const idx = params[0]?.dataIndex; + if (idx === undefined) return ''; + const raw = chartData.rawData[idx]; if (!raw) return ''; - const prevClose = raw.prev_close || raw.open; - const changePct = prevClose ? (((raw.close - prevClose) / prevClose) * 100).toFixed(2) : '0.00'; - const isUp = raw.close >= prevClose; - const color = isUp ? '#ec0000' : '#00da3c'; - return `
${raw.time}
收盘: ${raw.close.toFixed(2)}
${isUp ? '+' : ''}${changePct}%
`; + + // 计算涨跌 + const prevClose = raw.prev_close || (idx > 0 ? chartData.rawData[idx - 1]?.close : raw.open) || raw.open; + const changeAmount = raw.close - prevClose; + const changePct = prevClose ? ((changeAmount / prevClose) * 100) : 0; + const isUp = changeAmount >= 0; + const color = isUp ? '#ef5350' : '#26a69a'; + const sign = isUp ? '+' : ''; + + return ` +
+
+ 📅 ${raw.time} +
+
+ 开盘 + ${raw.open.toFixed(2)} + 收盘 + ${raw.close.toFixed(2)} + 最高 + ${raw.high.toFixed(2)} + 最低 + ${raw.low.toFixed(2)} +
+
+ 涨跌幅 + + ${sign}${changeAmount.toFixed(2)} (${sign}${changePct.toFixed(2)}%) + +
+
+ `; } }, - xAxis: { type: 'category', data: chartData.dates, show: false }, - yAxis: { type: 'value', show: false, scale: true }, - series: [{ - type: 'candlestick', - data: chartData.klineData, - itemStyle: { color: upColor, color0: downColor, borderColor: upColor, borderColor0: downColor }, - barWidth: '70%' - }] + xAxis: [ + { + type: 'category', + data: chartData.dates, + gridIndex: 0, + show: false, + boundaryGap: true + }, + { + type: 'category', + data: chartData.dates, + gridIndex: 1, + show: false, + boundaryGap: true + } + ], + yAxis: [ + { + type: 'value', + gridIndex: 0, + show: false, + scale: true + }, + { + type: 'value', + gridIndex: 1, + show: false, + scale: true + } + ], + dataZoom: [{ + type: 'inside', + xAxisIndex: [0, 1], + start: 50, + end: 100, + zoomOnMouseWheel: true, + moveOnMouseMove: true + }], + series: [ + { + name: 'K线', + type: 'candlestick', + data: chartData.klineData, + xAxisIndex: 0, + yAxisIndex: 0, + itemStyle: { + color: upColor, + color0: downColor, + borderColor: upColor, + borderColor0: downColor, + borderWidth: 1 + }, + barWidth: '65%' + }, + { + name: '成交量', + type: 'bar', + data: chartData.volumes, + xAxisIndex: 1, + yAxisIndex: 1, + itemStyle: { + color: (params) => { + const idx = params.dataIndex; + const raw = chartData.rawData[idx]; + return raw && raw.close >= raw.open ? 'rgba(239,83,80,0.5)' : 'rgba(38,166,154,0.5)'; + } + }, + barWidth: '65%' + } + ] }; }, [chartData, upColor, downColor]); - if (loading) return
; + if (loading) { + return ( +
+ + + 加载{indexName}... + +
+ ); + } return ( - - {/* 左侧数据 */} - - {indexName} - - {latestData?.close.toFixed(2)} - + + {/* 顶部:指数名称和数据 */} + + + + + {indexName} + + + + + {latestData?.close?.toFixed(2)} + + + + {latestData?.isPositive ? '▲' : '▼'} {latestData?.isPositive ? '+' : ''}{latestData?.changePct?.toFixed(2)}% + + + + + + {/* K线图区域 */} + + + {/* 底部提示 */} - {latestData?.isPositive ? '▲' : '▼'} {latestData?.isPositive ? '+' : ''}{latestData?.change}% + 滚轮缩放 · 拖动查看 - - {/* 右侧K线图 */} - - ); @@ -377,7 +532,7 @@ const FlowingConcepts = () => { }; /** - * 极简提示标签 - 悬停显示详情 + * 详细使用说明提示框 */ const InfoTooltip = () => { const [isOpen, setIsOpen] = useState(false); @@ -414,16 +569,16 @@ const InfoTooltip = () => { top="calc(100% + 8px)" left="0" zIndex={1000} - minW="320px" - p={4} + w="380px" + p={5} bg="rgba(10,10,20,0.98)" - borderRadius="lg" + borderRadius="xl" border="1px solid rgba(255,215,0,0.3)" - boxShadow="0 10px 40px rgba(0,0,0,0.5), 0 0 0 1px rgba(255,215,0,0.1)" + boxShadow="0 15px 50px rgba(0,0,0,0.6), 0 0 0 1px rgba(255,215,0,0.1), inset 0 1px 0 rgba(255,255,255,0.05)" opacity={isOpen ? 1 : 0} visibility={isOpen ? 'visible' : 'hidden'} transform={isOpen ? 'translateY(0)' : 'translateY(-10px)'} - transition="all 0.2s ease" + transition="all 0.25s ease" onMouseEnter={() => setIsOpen(true)} onMouseLeave={() => setIsOpen(false)} > @@ -440,56 +595,118 @@ const InfoTooltip = () => { transform="rotate(45deg)" /> - - {/* SABC说明 */} - - SABC - - 基于事件影响力评级,非收益预测 - - + + {/* 标题 */} + + 📖 事件中心使用指南 + - {/* 涨跌幅说明 */} - - 涨跌幅 - - 新闻发布时股价 → 当前价格的变化 + {/* 事件级别说明 */} + + + 🏷️ 事件重要性等级 (SABC) - - - {/* 延迟提醒 */} - - - - - - 数据延迟 2-3分钟 - ,切勿追高 - - + + + + S级 + + 重大事件 - 可能引发板块涨停潮 + + + + A级 + + 重要事件 - 龙头股可能涨停 + + + + B级 + + 一般事件 - 相关股票可能异动 + + + + C级 + + 普通事件 - 仅供参考 + + + {/* 分隔线 */} - + - {/* 盘前新闻 */} - - - - 关注盘前新闻 - (收盘后至次日开盘前的消息) + {/* 涨跌幅说明 */} + + + 📊 涨跌幅计算方式 - + + + • 相关股涨跌:新闻发布时 → 当前价格的变化 + + + • 红色 表示上涨,绿色 表示下跌 + + + • K线图悬停可查看:开盘、收盘、最高、最低、涨跌幅 + + + - {/* 利好利空 */} - - - - 事件含 - 利好/ - 利空 - ,需自行判断 + {/* 分隔线 */} + + + {/* 重要提醒 */} + + + ⚠️ 重要提醒 - + + + + + 数据延迟 2-3分钟切勿追高 + + + + + + 关注 盘前新闻(收盘后至次日开盘前发布的消息) + + + + + + 事件可能含 利好利空,需自行分析判断 + + + + + + {/* 操作提示 */} + + + 💡 操作提示 + + + + • 点击事件卡片查看详情和相关股票 + + + • 点击热门概念标签跳转概念详情页 + + + • K线图支持滚轮缩放和拖动查看 + + + @@ -596,14 +813,15 @@ const HeroPanel = () => { @@ -613,14 +831,15 @@ const HeroPanel = () => {