|  |  | import { Card } from "antd"; | 
|  |  | import * as echarts from "echarts/core"; | 
|  |  | import { GridComponent, GridComponentOption } from "echarts/components"; | 
|  |  | import { BarChart, BarSeriesOption } from "echarts/charts"; | 
|  |  | import { | 
|  |  | GridComponent, | 
|  |  | TooltipComponent, | 
|  |  | LegendComponent, | 
|  |  | TitleComponent, | 
|  |  | } from "echarts/components"; | 
|  |  | import { | 
|  |  | BarChart, | 
|  |  | PieChart, | 
|  |  | LineChart, | 
|  |  | BarSeriesOption, | 
|  |  | PieSeriesOption, | 
|  |  | LineSeriesOption, | 
|  |  | } from "echarts/charts"; | 
|  |  | import { CanvasRenderer } from "echarts/renderers"; | 
|  |  | import { useRef, useState } from "react"; | 
|  |  | const tabList = [ | 
|  |  | { | 
|  |  | key: "bar", | 
|  |  | label: "柱状图", | 
|  |  | }, | 
|  |  | { | 
|  |  | key: "pie", | 
|  |  | label: "饼图", | 
|  |  | }, | 
|  |  | { | 
|  |  | key: "line", | 
|  |  | label: "折线图", | 
|  |  | }, | 
|  |  | ]; | 
|  |  | import { useRef, useEffect, useState } from "react"; | 
|  |  | import { ChartComponentProps, ChartData } from "./getChartData"; | 
|  |  |  | 
|  |  | // 注册必要的组件 | 
|  |  | echarts.use([ | 
|  |  | GridComponent, | 
|  |  | TooltipComponent, | 
|  |  | LegendComponent, | 
|  |  | TitleComponent, | 
|  |  | BarChart, | 
|  |  | PieChart, | 
|  |  | LineChart, | 
|  |  | CanvasRenderer, | 
|  |  | ]); | 
|  |  |  | 
|  |  | echarts.use([GridComponent, BarChart, CanvasRenderer]); | 
|  |  | type EChartsOption = echarts.ComposeOption< | 
|  |  | GridComponentOption | BarSeriesOption | 
|  |  | BarSeriesOption | PieSeriesOption | LineSeriesOption | 
|  |  | >; | 
|  |  |  | 
|  |  | var option: EChartsOption; | 
|  |  | const tabList = [ | 
|  |  | { key: "bar", label: "柱状图" }, | 
|  |  | { key: "pie", label: "饼图" }, | 
|  |  | { key: "line", label: "折线图" }, | 
|  |  | ]; | 
|  |  |  | 
|  |  | option = { | 
|  |  | xAxis: { | 
|  |  | type: "category", | 
|  |  | data: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"], | 
|  |  | }, | 
|  |  | yAxis: { | 
|  |  | type: "value", | 
|  |  | }, | 
|  |  | series: [ | 
|  |  | { | 
|  |  | data: [120, 200, 150, 80, 70, 110, 130], | 
|  |  | type: "bar", | 
|  |  | }, | 
|  |  | ], | 
|  |  | }; | 
|  |  | export function ChartComponent() { | 
|  |  | const [activeTabKey, setActiveTabKey] = useState<string>("bar"); | 
|  |  | const line = useRef<HTMLCanvasElement>(null); | 
|  |  | const bar = useRef<HTMLCanvasElement>(null); | 
|  |  | const pie = useRef<HTMLCanvasElement>(null); | 
|  |  | const contentListNoTitle: Record<string, React.ReactNode> = { | 
|  |  | bar: <canvas ref={bar}></canvas>, | 
|  |  | pie: <canvas ref={pie}></canvas>, | 
|  |  | line: <canvas ref={line}></canvas>, | 
|  |  | // 图表配置生成器 | 
|  |  | const getOption = (type: string, data: ChartData): EChartsOption => { | 
|  |  | const commonOption = { | 
|  |  | title: { text: `${tabList.find((t) => t.key === type)?.label}` }, | 
|  |  | tooltip: { trigger: "item" }, | 
|  |  | }; | 
|  |  | // var myChart = echarts.init(bar); | 
|  |  |  | 
|  |  | // 提取数值数组 | 
|  |  | const values = data.values.map((item) => item.value); | 
|  |  |  | 
|  |  | switch (type) { | 
|  |  | case "bar": | 
|  |  | return { | 
|  |  | ...commonOption, | 
|  |  | xAxis: { type: "category", data: data.categories }, | 
|  |  | yAxis: { type: "value" }, | 
|  |  | series: [{ data: values, type: "bar" }], | 
|  |  | }; | 
|  |  | case "pie": | 
|  |  | return { | 
|  |  | ...commonOption, | 
|  |  | series: [ | 
|  |  | { | 
|  |  | type: "pie", | 
|  |  | data: data.categories.map((name, i) => ({ | 
|  |  | name, | 
|  |  | value: values[i], | 
|  |  | })), | 
|  |  | radius: "50%", | 
|  |  | }, | 
|  |  | ], | 
|  |  | }; | 
|  |  | case "line": | 
|  |  | return { | 
|  |  | ...commonOption, | 
|  |  | xAxis: { type: "category", data: data.categories }, | 
|  |  | yAxis: { type: "value" }, | 
|  |  | series: [ | 
|  |  | { | 
|  |  | data: values, | 
|  |  | type: "line", | 
|  |  | smooth: true, | 
|  |  | areaStyle: {}, | 
|  |  | }, | 
|  |  | ], | 
|  |  | }; | 
|  |  | default: | 
|  |  | return {}; | 
|  |  | } | 
|  |  | }; | 
|  |  |  | 
|  |  | export function ChartComponent({ | 
|  |  | data = { categories: [], values: [] }, | 
|  |  | }: ChartComponentProps) { | 
|  |  | const [activeTabKey, setActiveTabKey] = useState("bar"); | 
|  |  | const chartRef = useRef<HTMLDivElement>(null); | 
|  |  | const chartInstance = useRef<echarts.ECharts | null>(null); | 
|  |  |  | 
|  |  | useEffect(() => { | 
|  |  | if (!chartRef.current) return; | 
|  |  |  | 
|  |  | // 数据校验 | 
|  |  | if ( | 
|  |  | !data?.categories?.length || | 
|  |  | !data?.values?.length || | 
|  |  | data.values.some((item) => typeof item.value !== "number") | 
|  |  | ) { | 
|  |  | console.warn("Invalid chart data"); | 
|  |  | return; | 
|  |  | } | 
|  |  |  | 
|  |  | // 销毁旧实例 | 
|  |  | if (chartInstance.current) { | 
|  |  | chartInstance.current.dispose(); | 
|  |  | } | 
|  |  |  | 
|  |  | // 初始化新图表 | 
|  |  | chartInstance.current = echarts.init(chartRef.current); | 
|  |  | chartInstance.current.setOption(getOption(activeTabKey, data)); | 
|  |  |  | 
|  |  | // 窗口resize监听 | 
|  |  | const resizeHandler = () => chartInstance.current?.resize(); | 
|  |  | window.addEventListener("resize", resizeHandler); | 
|  |  |  | 
|  |  | // 清理函数 | 
|  |  | return () => { | 
|  |  | window.removeEventListener("resize", resizeHandler); | 
|  |  | chartInstance.current?.dispose(); | 
|  |  | }; | 
|  |  | }, [activeTabKey, data]); | 
|  |  |  | 
|  |  | return ( | 
|  |  | <> | 
|  |  | <Card | 
|  |  | style={{ width: "100%" }} | 
|  |  | tabList={tabList} | 
|  |  | activeTabKey={activeTabKey} | 
|  |  | onTabChange={setActiveTabKey} | 
|  |  | tabProps={{ size: "middle" }} | 
|  |  | > | 
|  |  | {contentListNoTitle[activeTabKey]} | 
|  |  | </Card> | 
|  |  | </> | 
|  |  | <Card | 
|  |  | style={{ width: "100%", minHeight: 400 }} | 
|  |  | tabList={tabList} | 
|  |  | activeTabKey={activeTabKey} | 
|  |  | onTabChange={setActiveTabKey} | 
|  |  | tabProps={{ size: "middle" }} | 
|  |  | > | 
|  |  | <div | 
|  |  | ref={chartRef} | 
|  |  | style={{ | 
|  |  | width: "100%", | 
|  |  | height: 400, | 
|  |  | minHeight: 400, | 
|  |  | }} | 
|  |  | /> | 
|  |  | </Card> | 
|  |  | ); | 
|  |  | } | 
... | ... |  |