feat(LimitAnalyse): 优化数据可视化组件

- 改进板块分布饼图展示
- 优化涨停时段统计图表

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
zdl
2025-12-24 18:31:25 +08:00
parent 080dbdb26b
commit 4572fcac30

View File

@@ -39,17 +39,6 @@ import {
import { getFormattedTextProps } from '../../../utils/textUtils';
import { ExternalLinkIcon } from '@chakra-ui/icons';
import RiskDisclaimer from '../../../components/RiskDisclaimer';
import {
BarChart, Bar,
PieChart, Pie, Cell,
XAxis, YAxis,
CartesianGrid,
Tooltip as RechartsTooltip,
Legend,
ResponsiveContainer,
Treemap,
Area, AreaChart,
} from 'recharts';
import ReactECharts from 'echarts-for-react';
import 'echarts-wordcloud';
// 颜色配置
@@ -137,6 +126,149 @@ const WordCloud = ({ data }) => {
return <EChartsWordCloud data={data} />;
};
// 板块分布饼图 - ECharts 实现
const SectorPieChart = ({ data }) => {
if (!data || data.length === 0) {
return (
<Center h="400px">
<Text color="gray.500">暂无数据</Text>
</Center>
);
}
const option = {
tooltip: {
trigger: 'item',
formatter: '{b}: {c} ({d}%)'
},
legend: {
orient: 'vertical',
right: 10,
top: 'center',
textStyle: { fontSize: 12 }
},
series: [{
type: 'pie',
radius: ['0%', '65%'],
center: ['40%', '50%'],
avoidLabelOverlap: true,
itemStyle: {
borderRadius: 4,
borderColor: '#fff',
borderWidth: 2
},
label: {
show: true,
formatter: '{b} {d}%',
fontSize: 12
},
labelLine: {
show: true,
length: 10,
length2: 15
},
emphasis: {
label: {
show: true,
fontSize: 14,
fontWeight: 'bold'
},
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
},
data: data.map((item, index) => ({
name: item.name,
value: item.value,
itemStyle: { color: CHART_COLORS[index % CHART_COLORS.length] }
})),
animationDuration: 800
}]
};
return (
<ReactECharts
option={option}
style={{ height: '400px', width: '100%' }}
opts={{ renderer: 'canvas' }}
/>
);
};
// 时间分布环形图 - ECharts 实现
const TimeDistributionChart = ({ data }) => {
if (!data || data.length === 0) {
return (
<Center h="300px">
<Text color="gray.500">暂无数据</Text>
</Center>
);
}
const option = {
tooltip: {
trigger: 'item',
formatter: '{b}: {c} ({d}%)'
},
legend: {
orient: 'horizontal',
bottom: 10,
textStyle: { fontSize: 12 }
},
series: [{
type: 'pie',
radius: ['45%', '70%'],
center: ['50%', '45%'],
avoidLabelOverlap: true,
padAngle: 3,
itemStyle: {
borderRadius: 6,
borderColor: '#fff',
borderWidth: 2
},
label: {
show: true,
position: 'outside',
formatter: '{b}\n{c}只',
fontSize: 11
},
labelLine: {
show: true,
length: 8,
length2: 12
},
emphasis: {
label: {
show: true,
fontSize: 13,
fontWeight: 'bold'
},
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
},
data: data.map(item => ({
name: item.name,
value: item.value,
itemStyle: { color: item.color }
})),
animationDuration: 800
}]
};
return (
<ReactECharts
option={option}
style={{ height: '300px', width: '100%' }}
opts={{ renderer: 'canvas' }}
/>
);
};
// 板块热力图组件
const SectorHeatMap = ({ data }) => {
if (!data) return null;
@@ -496,27 +628,7 @@ export const DataAnalysis = ({ dailyData, wordCloudData, totalStocks, dateStr })
</TabPanel>
<TabPanel>
<ResponsiveContainer width="100%" height={400}>
<PieChart>
<Pie
data={pieData}
cx="50%"
cy="50%"
labelLine={false}
label={({ name, percent }) => `${name} ${(percent * 100).toFixed(0)}%`}
outerRadius={120}
fill="#8884d8"
dataKey="value"
animationBegin={0}
animationDuration={800}
>
{pieData.map((entry, index) => (
<Cell key={`cell-${index}`} fill={CHART_COLORS[index % CHART_COLORS.length]} />
))}
</Pie>
<RechartsTooltip />
</PieChart>
</ResponsiveContainer>
<SectorPieChart data={pieData} />
</TabPanel>
<TabPanel>
@@ -545,25 +657,7 @@ export const DataAnalysis = ({ dailyData, wordCloudData, totalStocks, dateStr })
<TabPanel>
<VStack spacing={4}>
<ResponsiveContainer width="100%" height={300}>
<PieChart>
<Pie
data={timeDistributionData}
cx="50%"
cy="50%"
innerRadius={60}
outerRadius={100}
fill="#8884d8"
paddingAngle={5}
dataKey="value"
>
{timeDistributionData.map((entry, index) => (
<Cell key={`cell-${index}`} fill={entry.color} />
))}
</Pie>
<RechartsTooltip />
</PieChart>
</ResponsiveContainer>
<TimeDistributionChart data={timeDistributionData} />
<SimpleGrid columns={3} spacing={4} w="full">
{timeDistributionData.map((item, index) => (
<Stat key={index} textAlign="center">