@@ -3,73 +3,67 @@ import useAppearanceStore from 'stores/useAppearanceStore';
33import * as echarts from 'echarts' ;
44import { IChatMessage } from 'intellichat/types' ;
55import { useMemo , useRef } from 'react' ;
6+ import { useTranslation } from 'react-i18next' ;
67
7- export default function useECharts ( { message } : { message : IChatMessage } ) {
8- const theme = useAppearanceStore ( ( state ) => state . theme ) ;
9- const messageId = useMemo ( ( ) => message . id , [ message ] ) ;
10- const containersRef = useRef ( [ ] ) ;
11-
12- const disposeECharts = ( ) => {
13- const chartInstances = containersRef . current ;
14- if ( chartInstances . length < 1 ) return ;
15- chartInstances . forEach ( ( { cleanup } : { cleanup : Function } ) => {
16- cleanup ( ) ;
17- } ) ;
18- chartInstances . length = 0 ;
19- } ;
20-
21- const initECharts = ( ) => {
22-
23- // 清理已有实例
24- disposeECharts ( ) ;
25- const chartInstances = containersRef . current ;
26-
27- // 查找所有图表容器
28- const containers = document . querySelectorAll ( `#${ messageId } .echarts-container` ) ;
29-
30- containers . forEach ( container => {
31- const chartId = container . id ;
32- const encodedConfig = container . getAttribute ( 'data-echarts-config' ) ;
8+ const parseOption = ( optStr : string ) => {
9+ try {
10+ const match = optStr . match ( / \{ ( .+ ) \} / s) ;
11+ if ( ! match ) return { } ;
12+ return new Function ( `return {${ match [ 1 ] } }` ) ( ) ;
13+ } catch ( error ) {
14+ throw new Error ( 'Invalid ECharts option format' ) ;
15+ }
16+ } ;
3317
34- if ( ! encodedConfig ) return ;
35-
36- try {
37- // 解码并解析配置
38- const config = decodeURIComponent ( encodedConfig ) ;
39- const option = new Function ( `return ${ config } ` ) ( ) ;
40-
41- // 初始化图表
42- // 使用类型断言将 container 转换为 HTMLDivElement 类型,以解决类型不匹配问题
43- console . debug ( "echart container:" , container ) ;
44- const chart = echarts . init ( container as HTMLDivElement , theme ) ;
45- chart . setOption ( option ) ;
46-
47- // 响应式调整
48- const resizeHandler = ( ) => chart . resize ( ) ;
49- window . addEventListener ( 'resize' , resizeHandler ) ;
18+ export default function useECharts ( { message } : { message : IChatMessage } ) {
19+ const { t } = useTranslation ( ) ;
20+ const theme = useAppearanceStore ( ( state ) => state . theme ) ;
21+ const messageId = useMemo ( ( ) => message . id , [ message ] ) ;
22+ const containersRef = useRef < { [ key : string ] : echarts . EChartsType } > ( { } ) ;
5023
51- // 保存实例
52- chartInstances . push ( {
53- chartId,
54- instance : chart ,
55- cleanup : ( ) => {
56- window . removeEventListener ( 'resize' , resizeHandler ) ;
57- chart . dispose ( ) ;
58- }
59- } ) ;
60- } catch ( error : any ) {
61- console . error ( 'ECharts初始化错误:' , error ) ;
62- container . innerHTML = `
63- <div style="color:red;padding:20px;">
64- 图表渲染错误: ${ error . message }
65- </div>
66- ` ;
67- }
68- } ) ;
69- } ;
24+ const disposeECharts = ( ) => {
25+ const chartInstances = Object . values ( containersRef . current ) ;
26+ chartInstances . forEach ( ( { cleanup } : { cleanup : Function } ) => {
27+ cleanup ( ) ;
28+ } ) ;
29+ containersRef . current = { } ;
30+ } ;
7031
71- return {
72- disposeECharts,
73- initECharts,
32+ const initECharts = ( prefix : string , chartId : string ) => {
33+ if ( containersRef . current [ `${ prefix } -${ chartId } ` ] ) return ; // already initialized
34+ const chartInstances = containersRef . current ;
35+ const container = document . querySelector (
36+ `#${ messageId } .echarts-container#${ chartId } ` ,
37+ ) as HTMLDivElement ;
38+ if ( ! container ) return ;
39+ const encodedConfig = container . getAttribute ( 'data-echarts-config' ) ;
40+ if ( ! encodedConfig ) return ;
41+ try {
42+ let config = decodeURIComponent ( encodedConfig ) ;
43+ const option = parseOption ( config ) ;
44+ const chart = echarts . init ( container , theme ) ;
45+ chart . setOption ( option ) ;
46+ const resizeHandler = ( ) => chart . resize ( ) ;
47+ window . addEventListener ( 'resize' , resizeHandler ) ;
48+ chartInstances [ `${ prefix } -${ chartId } ` ] = {
49+ chartId,
50+ instance : chart ,
51+ cleanup : ( ) => {
52+ window . removeEventListener ( 'resize' , resizeHandler ) ;
53+ chart . dispose ( ) ;
54+ } ,
55+ } ;
56+ } catch ( error : any ) {
57+ container . innerHTML = `
58+ <div class="text-gray-400">
59+ ${ t ( 'Message.Error.EChartsRenderFailed' ) }
60+ </div>
61+ ` ;
7462 }
75- }
63+ } ;
64+
65+ return {
66+ disposeECharts,
67+ initECharts,
68+ } ;
69+ }
0 commit comments