diff --git a/client/data/config.json b/client/data/config.json index 2b6b5cd6e..5bfd65fc1 100644 --- a/client/data/config.json +++ b/client/data/config.json @@ -61,4 +61,4 @@ "maxToken": 16000, "price": 0 } -} +} \ No newline at end of file diff --git a/client/package.json b/client/package.json index 5a9076498..6f0dea05f 100644 --- a/client/package.json +++ b/client/package.json @@ -25,6 +25,7 @@ "date-fns": "^2.30.0", "dayjs": "^1.11.7", "echarts": "^5.4.1", + "echarts-gl": "^2.0.9", "formidable": "^2.1.1", "framer-motion": "^9.0.6", "hyperdown": "^2.4.29", diff --git a/client/src/components/Markdown/img/EChartsCodeBlock.tsx b/client/src/components/Markdown/img/EChartsCodeBlock.tsx new file mode 100644 index 000000000..032749153 --- /dev/null +++ b/client/src/components/Markdown/img/EChartsCodeBlock.tsx @@ -0,0 +1,26 @@ +// EChartsCodeBlock.tsx + +import React, { useMemo } from 'react'; +import EChartsRenderer from './EChartsRenderer'; +import * as echarts from 'echarts'; + + +interface EChartsCodeBlockProps { + code: string; +} + +const EChartsCodeBlock: React.FC = ({ code }) => { + const getOption = useMemo(() => { + try { + const optionFunction = new Function("echarts",'"use strict";' + code + '; return getChartOption;'); + return optionFunction(echarts); // 添加 echarts 参数 + } catch (error) { + console.error('Error parsing ECharts code:', '\n', error, '\n', 'Code:', code); + return null; + } + }, [code]); + + return getOption ? : null; +}; + +export default EChartsCodeBlock; diff --git a/client/src/components/Markdown/img/EChartsRenderer.tsx b/client/src/components/Markdown/img/EChartsRenderer.tsx new file mode 100644 index 000000000..ff7a5c443 --- /dev/null +++ b/client/src/components/Markdown/img/EChartsRenderer.tsx @@ -0,0 +1,35 @@ +import React, { useRef, useEffect } from 'react'; +import { ECharts } from 'echarts'; + +interface EChartsRendererProps { + getOption: () => any; +} + + +const EChartsRenderer: React.FC = ({ getOption }) => { + const chartRef = useRef(null); + + useEffect(() => { + let chartInstance: ECharts | null = null; + + (async () => { + const echarts = await import('echarts'); + await import('echarts-gl'); + if (chartRef.current) { + chartInstance = echarts.init(chartRef.current, { renderer: 'svg', ssr: true }); + const option = getOption(); + chartInstance.setOption(option); + } + })(); + + return () => { + if (chartInstance) { + chartInstance.dispose(); + } + }; + }, [getOption]); + + return
; +}; + +export default EChartsRenderer; diff --git a/client/src/components/Markdown/index.tsx b/client/src/components/Markdown/index.tsx index 523b10d0a..a2b481335 100644 --- a/client/src/components/Markdown/index.tsx +++ b/client/src/components/Markdown/index.tsx @@ -14,6 +14,7 @@ import CodeLight from './CodeLight'; const MermaidCodeBlock = dynamic(() => import('./img/MermaidCodeBlock')); const MdImage = dynamic(() => import('./img/Image')); const ChatGuide = dynamic(() => import('./chat/Guide')); +const EChartsCodeBlock = dynamic(() => import('./img/EChartsCodeBlock')); function Code({ inline, className, children }: any) { const match = /language-(\w+)/.exec(className || ''); @@ -26,7 +27,9 @@ function Code({ inline, className, children }: any) { if (codeType === 'guide') { return ; } - + if (codeType === 'echarts') { + return ; + } return ( {children} diff --git a/client/src/types/echarts-gl.d.ts b/client/src/types/echarts-gl.d.ts new file mode 100644 index 000000000..2ec17990f --- /dev/null +++ b/client/src/types/echarts-gl.d.ts @@ -0,0 +1,4 @@ +declare module 'echarts-gl' { + export default echarts-gl + } +