-
${data.name}
-
包含 ${data.children.length} 只股票
-
总市值: ${data.children.reduce((sum, item) => sum + item.value, 0).toFixed(2)} 亿元
-
- `;
- }
- // 个股详情
- return `
-
-
${data.name}
-
代码: ${data.code || '-'}
-
涨跌幅:
- ${data.change > 0 ? '+' : ''}${data.change?.toFixed(2) || 0}%
-
-
市值: ${data.value?.toFixed(2) || 0} 亿元
-
成交额: ${data.amount?.toFixed(2) || 0} 亿元
-
行业: ${data.industry || '未知'}
-
地区: ${data.province || '未知'}
-
- `;
- }
- },
- series: [{
- name: 'A股市场',
- type: 'treemap',
- data: treeData,
- leafDepth: 1,
- roam: false,
- breadcrumb: {
- show: true,
- top: 10,
- left: 10,
- itemStyle: {
- color: colorMode === 'dark' ? '#1a1a2e' : '#f0f0f0',
- borderColor: colorMode === 'dark' ? goldColor : '#ccc',
- borderWidth: 1,
- shadowBlur: colorMode === 'dark' ? 5 : 0,
- shadowColor: colorMode === 'dark' ? `${goldColor}40` : 'transparent',
- textStyle: {
- color: colorMode === 'dark' ? goldColor : '#333'
- }
- },
- emphasis: {
- itemStyle: {
- color: colorMode === 'dark' ? goldColor : '#e0e0e0',
- textStyle: {
- color: colorMode === 'dark' ? '#0a0a0a' : '#333'
- }
- }
- }
- },
-
- levels: [
- {
- itemStyle: {
- borderColor: colorMode === 'dark' ? '#1a1a1a' : '#fff',
- borderWidth: 3,
- gapWidth: 3
- }
- },
- {
- itemStyle: {
- borderColor: colorMode === 'dark' ? '#0a0a0a' : '#fff',
- borderWidth: 1,
- gapWidth: 1
- }
- }
- ],
- itemStyle: {
- borderColor: colorMode === 'dark' ? '#0a0a0a' : '#fff',
- borderWidth: 1
- },
- label: {
- show: true,
- formatter: function(params) {
- const data = params.data;
- // 父节点(市值分组)显示名称
- if (data.children) {
- return params.name;
- }
- // 子节点(个股)根据市值大小决定是否显示
- return data.value > 5 ? data.name : '';
- },
- fontSize: 12,
- color: function(params) {
- if (colorMode === 'dark') {
- // 夜间模式:根据背景色调整文字颜色
- const change = params.data.change || 0;
- if (Math.abs(change) > 5) {
- return 'white';
- }
- return '#ccc';
- }
- return '#333';
- }
- }
- }]
- };
-
- // 设置配置项
- heatmapChart.current.setOption(option);
-
- // 先移除之前的点击事件,避免重复绑定
- heatmapChart.current.off('click');
-
- // 添加点击事件
- heatmapChart.current.on('click', function(params) {
- // 只有点击个股(有code的节点)才跳转
- if (params.data && params.data.code && !params.data.children) {
- const stock = {
- code: params.data.code,
- name: params.data.name,
- change_percent: params.data.change
- };
- const marketCapRange = getMarketCapRange(params.data.value);
-
- // 🎯 追踪热力图股票点击
- trackHeatmapStockClicked(stock, marketCapRange);
-
- navigate(`/company?scode=${params.data.code}`);
- }
- });
- } catch (error) {
- logger.error('StockOverview', 'renderHeatmap', error, {
- dataLength: data?.length || 0
- });
- // ❌ 移除热力图渲染失败 toast(非关键操作)
- }
- }, [colorMode, goldColor, navigate, trackHeatmapStockClicked]); // ✅ 添加追踪函数依赖
-
- // 获取市值区间
- const getMarketCapRange = (cap) => {
- if (cap >= 1000) return '超大盘股(>1000亿)';
- if (cap >= 500) return '大盘股(500-1000亿)';
- if (cap >= 100) return '中盘股(100-500亿)';
- if (cap >= 50) return '小盘股(50-100亿)';
- return '微盘股(<50亿)';
- };
-
// 查看概念详情(模仿概念中心:打开对应HTML页)
const handleConceptClick = (concept, rank = 0) => {
// 🎯 追踪概念点击
@@ -477,35 +250,8 @@ const StockOverview = () => {
fetchTopConcepts();
fetchHeatmapData();
fetchMarketStats();
-
- // 监听窗口大小变化,重新渲染热力图
- const handleResize = () => {
- if (heatmapChart.current) {
- heatmapChart.current.resize();
- }
- };
- window.addEventListener('resize', handleResize);
-
- return () => {
- window.removeEventListener('resize', handleResize);
- if (heatmapChart.current) {
- heatmapChart.current.dispose();
- }
- };
}, []);
- // 监听colorMode和heatmapData变化,重新渲染热力图
- useEffect(() => {
- if (heatmapData.length > 0) {
- // 如果已有实例,先销毁再重新创建
- if (heatmapChart.current) {
- heatmapChart.current.dispose();
- heatmapChart.current = null;
- }
- renderHeatmap(heatmapData);
- }
- }, [heatmapData, colorMode, renderHeatmap]);
-
// 概念卡片骨架屏
const ConceptSkeleton = () => (