update ui
This commit is contained in:
@@ -19,6 +19,8 @@ import {
|
|||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import { TrendingUp, Activity, Globe, Zap } from 'lucide-react';
|
import { TrendingUp, Activity, Globe, Zap } from 'lucide-react';
|
||||||
import ReactECharts from 'echarts-for-react';
|
import ReactECharts from 'echarts-for-react';
|
||||||
|
import * as echarts from 'echarts';
|
||||||
|
import 'echarts-wordcloud'; // 导入词云插件
|
||||||
import { logger } from '../../../utils/logger';
|
import { logger } from '../../../utils/logger';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -130,7 +132,8 @@ const MiniIndexChart = ({ indexCode, indexName }) => {
|
|||||||
item.close,
|
item.close,
|
||||||
item.low,
|
item.low,
|
||||||
item.high
|
item.high
|
||||||
])
|
]),
|
||||||
|
rawData: recentData // 保存原始数据用于 tooltip
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,6 +226,59 @@ const MiniIndexChart = ({ indexCode, indexName }) => {
|
|||||||
bottom: 20,
|
bottom: 20,
|
||||||
containLabel: false
|
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: {
|
xAxis: {
|
||||||
type: 'category',
|
type: 'category',
|
||||||
data: chartData.dates,
|
data: chartData.dates,
|
||||||
@@ -324,16 +380,35 @@ const ConceptWordCloud = () => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const chartOption = useMemo(() => {
|
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 {
|
return {
|
||||||
backgroundColor: chartBg,
|
backgroundColor: chartBg,
|
||||||
tooltip: {
|
tooltip: {
|
||||||
show: true,
|
show: true,
|
||||||
|
backgroundColor: 'rgba(20, 20, 20, 0.95)',
|
||||||
|
borderColor: '#FFD700',
|
||||||
|
borderWidth: 1,
|
||||||
|
textStyle: {
|
||||||
|
color: '#fff',
|
||||||
|
fontSize: 12
|
||||||
|
},
|
||||||
formatter: (params) => {
|
formatter: (params) => {
|
||||||
const changePct = params.data.change_pct;
|
const changePct = params.data.change_pct;
|
||||||
const sign = changePct > 0 ? '+' : '';
|
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: [{
|
series: [{
|
||||||
@@ -345,33 +420,35 @@ const ConceptWordCloud = () => {
|
|||||||
height: '100%',
|
height: '100%',
|
||||||
right: null,
|
right: null,
|
||||||
bottom: null,
|
bottom: null,
|
||||||
sizeRange: [12, 40],
|
sizeRange: [14, 42],
|
||||||
rotationRange: [-45, 45],
|
rotationRange: [-30, 30],
|
||||||
rotationStep: 45,
|
rotationStep: 15,
|
||||||
gridSize: 8,
|
gridSize: 10,
|
||||||
drawOutOfBound: false,
|
drawOutOfBound: false,
|
||||||
layoutAnimation: true,
|
layoutAnimation: true,
|
||||||
textStyle: {
|
textStyle: {
|
||||||
fontFamily: 'sans-serif',
|
fontFamily: 'sans-serif',
|
||||||
fontWeight: 'bold',
|
fontWeight: 'bold',
|
||||||
color: function (params) {
|
color: function (params) {
|
||||||
// 根据涨跌幅设置颜色
|
// 根据涨跌幅设置颜色(中国市场惯例:涨红跌绿)
|
||||||
const changePct = params.data.change_pct;
|
const changePct = params.data.change_pct;
|
||||||
if (changePct > 5) return '#ff4d4f'; // 大涨:红色
|
if (changePct > 5) return '#ff1744'; // 大涨:亮红色
|
||||||
if (changePct > 3) return '#ff7875'; // 中涨:浅红
|
if (changePct > 3) return '#ff4d4f'; // 中涨:红色
|
||||||
if (changePct > 0) return '#ffa940'; // 小涨:橙色
|
if (changePct > 1) return '#ff7875'; // 小涨:浅红
|
||||||
|
if (changePct > 0) return '#ffa940'; // 微涨:橙色
|
||||||
if (changePct === 0) return '#FFD700'; // 平盘:金色
|
if (changePct === 0) return '#FFD700'; // 平盘:金色
|
||||||
if (changePct > -3) return '#95de64'; // 小跌:浅绿
|
if (changePct > -1) return '#95de64'; // 微跌:浅绿
|
||||||
if (changePct > -5) return '#52c41a'; // 中跌:绿色
|
if (changePct > -3) return '#52c41a'; // 小跌:绿色
|
||||||
return '#13c2c2'; // 大跌:青色
|
if (changePct > -5) return '#00c853'; // 中跌:深绿
|
||||||
|
return '#00796b'; // 大跌:墨绿
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
emphasis: {
|
emphasis: {
|
||||||
focus: 'self',
|
focus: 'self',
|
||||||
textStyle: {
|
textStyle: {
|
||||||
shadowBlur: 10,
|
shadowBlur: 12,
|
||||||
shadowColor: '#FFD700',
|
shadowColor: '#FFD700',
|
||||||
fontSize: 20
|
fontSize: 24
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data: concepts
|
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 (
|
return (
|
||||||
<ReactECharts
|
<ReactECharts
|
||||||
|
echarts={echarts}
|
||||||
option={chartOption}
|
option={chartOption}
|
||||||
style={{ height: '200px', width: '100%' }}
|
style={{ height: '200px', width: '100%' }}
|
||||||
opts={{ renderer: 'canvas' }}
|
opts={{ renderer: 'canvas' }}
|
||||||
|
notMerge={true}
|
||||||
|
lazyUpdate={true}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user