update ui
This commit is contained in:
@@ -19,6 +19,8 @@ import {
|
||||
} from '@chakra-ui/react';
|
||||
import { TrendingUp, Activity, Globe, Zap } from 'lucide-react';
|
||||
import ReactECharts from 'echarts-for-react';
|
||||
import * as echarts from 'echarts';
|
||||
import 'echarts-wordcloud'; // 导入词云插件
|
||||
import { logger } from '../../../utils/logger';
|
||||
|
||||
/**
|
||||
@@ -130,7 +132,8 @@ const MiniIndexChart = ({ indexCode, indexName }) => {
|
||||
item.close,
|
||||
item.low,
|
||||
item.high
|
||||
])
|
||||
]),
|
||||
rawData: recentData // 保存原始数据用于 tooltip
|
||||
});
|
||||
}
|
||||
|
||||
@@ -223,6 +226,59 @@ const MiniIndexChart = ({ indexCode, indexName }) => {
|
||||
bottom: 20,
|
||||
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',
|
||||
borderWidth: 1,
|
||||
textStyle: {
|
||||
color: '#fff',
|
||||
fontSize: 11,
|
||||
fontFamily: 'monospace'
|
||||
},
|
||||
padding: [8, 12],
|
||||
formatter: function (params) {
|
||||
const dataIndex = params[0].dataIndex;
|
||||
const rawDataItem = chartData.rawData[dataIndex];
|
||||
|
||||
if (!rawDataItem) return '';
|
||||
|
||||
const open = rawDataItem.open;
|
||||
const high = rawDataItem.high;
|
||||
const low = rawDataItem.low;
|
||||
const close = rawDataItem.close;
|
||||
const prevClose = rawDataItem.prev_close || open;
|
||||
const change = close - prevClose;
|
||||
const changePct = prevClose ? ((change / prevClose) * 100).toFixed(2) : '0.00';
|
||||
const isUp = close >= prevClose;
|
||||
|
||||
// Bloomberg 风格格式化
|
||||
const changeColor = isUp ? '#00da3c' : '#ec0000';
|
||||
const changeSign = isUp ? '+' : '';
|
||||
|
||||
return `
|
||||
<div style="font-weight: bold; border-bottom: 1px solid #FFD700; padding-bottom: 4px; margin-bottom: 6px;">
|
||||
${rawDataItem.time}
|
||||
</div>
|
||||
<div style="display: grid; grid-template-columns: auto 1fr; gap: 4px 12px; line-height: 1.6;">
|
||||
<span style="color: #aaa;">开盘</span><span style="font-weight: bold;">${open.toFixed(2)}</span>
|
||||
<span style="color: #aaa;">最高</span><span style="font-weight: bold; color: #00da3c;">${high.toFixed(2)}</span>
|
||||
<span style="color: #aaa;">最低</span><span style="font-weight: bold; color: #ec0000;">${low.toFixed(2)}</span>
|
||||
<span style="color: #aaa;">收盘</span><span style="font-weight: bold;">${close.toFixed(2)}</span>
|
||||
<span style="color: #aaa;">涨跌</span><span style="font-weight: bold; color: ${changeColor};">${changeSign}${change.toFixed(2)}</span>
|
||||
<span style="color: #aaa;">涨跌幅</span><span style="font-weight: bold; color: ${changeColor};">${changeSign}${changePct}%</span>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: chartData.dates,
|
||||
@@ -324,16 +380,35 @@ const ConceptWordCloud = () => {
|
||||
}, []);
|
||||
|
||||
const chartOption = useMemo(() => {
|
||||
if (concepts.length === 0) return {};
|
||||
if (concepts.length === 0) {
|
||||
logger.warn('ConceptWordCloud', 'No concepts data available');
|
||||
return {};
|
||||
}
|
||||
|
||||
logger.debug('ConceptWordCloud', 'Rendering word cloud with concepts', {
|
||||
count: concepts.length,
|
||||
sample: concepts.slice(0, 3)
|
||||
});
|
||||
|
||||
return {
|
||||
backgroundColor: chartBg,
|
||||
tooltip: {
|
||||
show: true,
|
||||
backgroundColor: 'rgba(20, 20, 20, 0.95)',
|
||||
borderColor: '#FFD700',
|
||||
borderWidth: 1,
|
||||
textStyle: {
|
||||
color: '#fff',
|
||||
fontSize: 12
|
||||
},
|
||||
formatter: (params) => {
|
||||
const changePct = params.data.change_pct;
|
||||
const sign = changePct > 0 ? '+' : '';
|
||||
return `${params.name}<br/>涨跌: ${sign}${changePct.toFixed(2)}%`;
|
||||
const color = changePct > 0 ? '#ec0000' : '#00da3c';
|
||||
return `
|
||||
<div style="font-weight: bold; margin-bottom: 4px;">${params.name}</div>
|
||||
<div style="color: ${color}; font-weight: bold;">涨跌幅: ${sign}${changePct.toFixed(2)}%</div>
|
||||
`;
|
||||
}
|
||||
},
|
||||
series: [{
|
||||
@@ -345,33 +420,35 @@ const ConceptWordCloud = () => {
|
||||
height: '100%',
|
||||
right: null,
|
||||
bottom: null,
|
||||
sizeRange: [12, 40],
|
||||
rotationRange: [-45, 45],
|
||||
rotationStep: 45,
|
||||
gridSize: 8,
|
||||
sizeRange: [14, 42],
|
||||
rotationRange: [-30, 30],
|
||||
rotationStep: 15,
|
||||
gridSize: 10,
|
||||
drawOutOfBound: false,
|
||||
layoutAnimation: true,
|
||||
textStyle: {
|
||||
fontFamily: 'sans-serif',
|
||||
fontWeight: 'bold',
|
||||
color: function (params) {
|
||||
// 根据涨跌幅设置颜色
|
||||
// 根据涨跌幅设置颜色(中国市场惯例:涨红跌绿)
|
||||
const changePct = params.data.change_pct;
|
||||
if (changePct > 5) return '#ff4d4f'; // 大涨:红色
|
||||
if (changePct > 3) return '#ff7875'; // 中涨:浅红
|
||||
if (changePct > 0) return '#ffa940'; // 小涨:橙色
|
||||
if (changePct > 5) return '#ff1744'; // 大涨:亮红色
|
||||
if (changePct > 3) return '#ff4d4f'; // 中涨:红色
|
||||
if (changePct > 1) return '#ff7875'; // 小涨:浅红
|
||||
if (changePct > 0) return '#ffa940'; // 微涨:橙色
|
||||
if (changePct === 0) return '#FFD700'; // 平盘:金色
|
||||
if (changePct > -3) return '#95de64'; // 小跌:浅绿
|
||||
if (changePct > -5) return '#52c41a'; // 中跌:绿色
|
||||
return '#13c2c2'; // 大跌:青色
|
||||
if (changePct > -1) return '#95de64'; // 微跌:浅绿
|
||||
if (changePct > -3) return '#52c41a'; // 小跌:绿色
|
||||
if (changePct > -5) return '#00c853'; // 中跌:深绿
|
||||
return '#00796b'; // 大跌:墨绿
|
||||
}
|
||||
},
|
||||
emphasis: {
|
||||
focus: 'self',
|
||||
textStyle: {
|
||||
shadowBlur: 10,
|
||||
shadowBlur: 12,
|
||||
shadowColor: '#FFD700',
|
||||
fontSize: 20
|
||||
fontSize: 24
|
||||
}
|
||||
},
|
||||
data: concepts
|
||||
@@ -387,11 +464,24 @@ const ConceptWordCloud = () => {
|
||||
);
|
||||
}
|
||||
|
||||
if (concepts.length === 0) {
|
||||
return (
|
||||
<Center h="200px">
|
||||
<Text fontSize="sm" color="whiteAlpha.600">
|
||||
暂无热门概念数据
|
||||
</Text>
|
||||
</Center>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<ReactECharts
|
||||
echarts={echarts}
|
||||
option={chartOption}
|
||||
style={{ height: '200px', width: '100%' }}
|
||||
opts={{ renderer: 'canvas' }}
|
||||
notMerge={true}
|
||||
lazyUpdate={true}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user