update pay function

This commit is contained in:
2025-11-30 18:31:13 +08:00
parent 84d0cae463
commit 5bf722db13
4 changed files with 178 additions and 35 deletions

View File

@@ -1,8 +1,8 @@
// src/components/ChatBot/EChartsRenderer.js
// ECharts 图表渲染组件
import React, { useEffect, useRef } from 'react';
import { Box, useColorModeValue } from '@chakra-ui/react';
import React, { useEffect, useRef, useCallback, useState } from 'react';
import { Box, useColorModeValue, Skeleton } from '@chakra-ui/react';
import * as echarts from 'echarts';
/**
@@ -67,6 +67,9 @@ const isValidOption = (option) => {
export const EChartsRenderer = ({ option, height = 400, variant = 'auto' }) => {
const chartRef = useRef(null);
const chartInstance = useRef(null);
const resizeObserverRef = useRef(null);
const [isReady, setIsReady] = useState(false);
const initTimeoutRef = useRef(null);
// 系统颜色模式
const systemBgColor = useColorModeValue('white', 'transparent');
@@ -76,7 +79,8 @@ export const EChartsRenderer = ({ option, height = 400, variant = 'auto' }) => {
const isDarkMode = variant === 'dark' ? true : variant === 'light' ? false : systemIsDark;
const bgColor = variant === 'dark' ? 'transparent' : variant === 'light' ? 'white' : systemBgColor;
useEffect(() => {
// 初始化或更新图表的函数
const initChart = useCallback(() => {
if (!chartRef.current || !option) return;
// 验证配置是否有效
@@ -85,9 +89,21 @@ export const EChartsRenderer = ({ option, height = 400, variant = 'auto' }) => {
return;
}
// 确保容器有有效尺寸
const containerWidth = chartRef.current.offsetWidth;
const containerHeight = chartRef.current.offsetHeight;
if (containerWidth < 50 || containerHeight < 50) {
// 容器尺寸太小,延迟重试
initTimeoutRef.current = setTimeout(initChart, 100);
return;
}
// 初始化图表(支持深色模式)
if (!chartInstance.current) {
chartInstance.current = echarts.init(chartRef.current, isDarkMode ? 'dark' : null);
chartInstance.current = echarts.init(chartRef.current, isDarkMode ? 'dark' : null, {
renderer: 'canvas',
});
}
// 深色模式下的默认文字颜色
@@ -117,6 +133,7 @@ export const EChartsRenderer = ({ option, height = 400, variant = 'auto' }) => {
// 设置图表配置(使用 try-catch 防止 ECharts 内部错误)
try {
chartInstance.current.setOption(defaultOption, true);
setIsReady(true);
} catch (error) {
console.error('EChartsRenderer: Failed to render chart', error);
// 销毁出错的图表实例
@@ -124,36 +141,93 @@ export const EChartsRenderer = ({ option, height = 400, variant = 'auto' }) => {
chartInstance.current = null;
return;
}
}, [option, isDarkMode]);
// 响应式调整大小
const handleResize = () => {
chartInstance.current?.resize();
};
// 处理容器尺寸变化
const handleResize = useCallback(() => {
if (chartInstance.current) {
// 使用 requestAnimationFrame 确保在下一帧渲染时调整大小
requestAnimationFrame(() => {
chartInstance.current?.resize();
});
}
}, []);
useEffect(() => {
// 使用 setTimeout 确保 DOM 已经完全渲染
initTimeoutRef.current = setTimeout(() => {
initChart();
}, 50);
// 使用 ResizeObserver 监听容器尺寸变化
if (chartRef.current && typeof ResizeObserver !== 'undefined') {
resizeObserverRef.current = new ResizeObserver((entries) => {
// 防抖处理
if (initTimeoutRef.current) {
clearTimeout(initTimeoutRef.current);
}
initTimeoutRef.current = setTimeout(() => {
handleResize();
}, 100);
});
resizeObserverRef.current.observe(chartRef.current);
}
// 窗口 resize 事件作为备用
window.addEventListener('resize', handleResize);
return () => {
window.removeEventListener('resize', handleResize);
// chartInstance.current?.dispose(); // 不要销毁,避免重新渲染时闪烁
if (resizeObserverRef.current) {
resizeObserverRef.current.disconnect();
}
if (initTimeoutRef.current) {
clearTimeout(initTimeoutRef.current);
}
};
}, [option, isDarkMode, variant]);
}, [initChart, handleResize]);
// option 变化时重新渲染
useEffect(() => {
if (chartInstance.current && option && isValidOption(option)) {
initChart();
}
}, [option, initChart]);
// 组件卸载时销毁图表
useEffect(() => {
return () => {
chartInstance.current?.dispose();
chartInstance.current = null;
if (chartInstance.current) {
chartInstance.current.dispose();
chartInstance.current = null;
}
};
}, []);
return (
<Box
ref={chartRef}
width="100%"
height={`${height}px`}
bg={bgColor}
borderRadius="md"
boxShadow="sm"
/>
<Box position="relative" width="100%" height={`${height}px`}>
{!isReady && (
<Skeleton
position="absolute"
top={0}
left={0}
width="100%"
height="100%"
borderRadius="md"
startColor={isDarkMode ? 'gray.700' : 'gray.100'}
endColor={isDarkMode ? 'gray.600' : 'gray.200'}
/>
)}
<Box
ref={chartRef}
width="100%"
height="100%"
bg={bgColor}
borderRadius="md"
boxShadow="sm"
opacity={isReady ? 1 : 0}
transition="opacity 0.3s ease"
/>
</Box>
);
};