// src/components/ChatBot/EChartsRenderer.js // ECharts 图表渲染组件 import React, { useEffect, useRef } from 'react'; import { Box, useColorModeValue } from '@chakra-ui/react'; import * as echarts from 'echarts'; /** * 验证 ECharts 配置是否有效 */ const isValidOption = (option) => { if (!option || typeof option !== 'object') return false; // 检查 xAxis 配置 if (option.xAxis) { const xAxis = Array.isArray(option.xAxis) ? option.xAxis[0] : option.xAxis; if (xAxis && xAxis.type === 'category' && (!xAxis.data || xAxis.data.length === 0)) { // category 类型的 xAxis 必须有数据 return false; } } // 检查 series 配置 if (option.series) { const series = Array.isArray(option.series) ? option.series : [option.series]; const hasValidSeries = series.some(s => s && s.data && s.data.length > 0); if (!hasValidSeries) { return false; } } return true; }; /** * ECharts 图表渲染组件 * @param {Object} option - ECharts 配置对象 * @param {number} height - 图表高度(默认 400px) * @param {string} variant - 主题变体: 'light' | 'dark' | 'auto' (默认 auto) */ export const EChartsRenderer = ({ option, height = 400, variant = 'auto' }) => { const chartRef = useRef(null); const chartInstance = useRef(null); // 系统颜色模式 const systemBgColor = useColorModeValue('white', 'transparent'); const systemIsDark = useColorModeValue(false, true); // 根据 variant 决定实际使用的模式 const isDarkMode = variant === 'dark' ? true : variant === 'light' ? false : systemIsDark; const bgColor = variant === 'dark' ? 'transparent' : variant === 'light' ? 'white' : systemBgColor; useEffect(() => { if (!chartRef.current || !option) return; // 验证配置是否有效 if (!isValidOption(option)) { console.warn('EChartsRenderer: Invalid or empty chart configuration, skipping render'); return; } // 初始化图表(支持深色模式) if (!chartInstance.current) { chartInstance.current = echarts.init(chartRef.current, isDarkMode ? 'dark' : null); } // 深色模式下的默认文字颜色 const darkModeTextStyle = isDarkMode ? { textStyle: { color: '#e5e7eb' }, title: { textStyle: { color: '#f3f4f6' }, ...option?.title }, legend: { textStyle: { color: '#d1d5db' }, ...option?.legend }, xAxis: { axisLabel: { color: '#9ca3af' }, axisLine: { lineStyle: { color: '#4b5563' } }, ...option?.xAxis }, yAxis: { axisLabel: { color: '#9ca3af' }, axisLine: { lineStyle: { color: '#4b5563' } }, splitLine: { lineStyle: { color: '#374151' } }, ...option?.yAxis }, } : {}; // 设置默认主题配置 const defaultOption = { backgroundColor: 'transparent', grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true, }, ...option, ...darkModeTextStyle, }; // 设置图表配置 chartInstance.current.setOption(defaultOption, true); // 响应式调整大小 const handleResize = () => { chartInstance.current?.resize(); }; window.addEventListener('resize', handleResize); return () => { window.removeEventListener('resize', handleResize); // chartInstance.current?.dispose(); // 不要销毁,避免重新渲染时闪烁 }; }, [option, isDarkMode, variant]); // 组件卸载时销毁图表 useEffect(() => { return () => { chartInstance.current?.dispose(); chartInstance.current = null; }; }, []); return ( ); };