Files
YouduWiki/web/admin/src/components/BarTrend/index.tsx
2026-05-21 19:52:45 +08:00

132 lines
3.2 KiB
TypeScript

import { TrendData } from '@/api';
import * as echarts from 'echarts';
import { useEffect, useRef, useState } from 'react';
type ECharts = ReturnType<typeof echarts.init>;
export interface PropsData {
height: number;
text: string;
chartData: TrendData[];
}
const BarTrend = ({ chartData, height, text }: PropsData) => {
const domWrapRef = useRef<HTMLDivElement>(null!);
const echartRef = useRef<ECharts>(null!);
const [loading, setLoading] = useState(true);
const [data, setData] = useState<TrendData[]>([]);
useEffect(() => {
if (domWrapRef.current && !echartRef.current && chartData.length > 0) {
echartRef.current = echarts.init(domWrapRef.current, null, {
renderer: 'svg',
});
}
setData(chartData);
}, [chartData]);
useEffect(() => {
const option = {
grid: {
left: 0,
right: 0,
bottom: 10,
top: 10,
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow',
},
formatter: (
params: { seriesName: string; name: string; value: number }[],
) => {
if (params[0]) {
const { name, seriesName, value } = params[0];
return `<div style="font-family: G;min-width: 80px">
${name || '-'}
<div>${seriesName} <span style='font-weight: 700'>${value || 0}</span></div>
</div>`;
}
return '';
},
},
xAxis: {
type: 'category',
data: data.map(it => it.name),
splitLine: {
show: false,
},
axisLine: {
show: false,
},
axisTick: {
show: false,
},
axisLabel: {
show: false,
},
},
yAxis: {
type: 'value',
splitNumber: 4,
axisLine: {
show: false,
},
axisTick: {
show: false,
},
axisLabel: {
show: false,
},
splitLine: {
lineStyle: {
type: 'dashed',
color: '#F2F3F5',
},
},
},
series: {
name: text,
type: 'bar',
barGap: 0,
barMinHeight: 4,
data: data.map(it => ({
value: it.count,
itemStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{ offset: 0, color: '#3248F2' },
{ offset: 1, color: '#9E68FC' },
],
},
borderRadius: [4, 4, 0, 0],
},
})),
},
};
if (domWrapRef.current && echartRef.current && data.length > 0) {
echartRef.current.setOption(option);
setLoading(false);
}
const resize = () => {
if (echartRef.current) {
echartRef.current.resize();
}
};
window.addEventListener('resize', resize);
return () => {
window.removeEventListener('resize', resize);
};
}, [data]);
if (data.length === 0 && !loading)
return <div style={{ width: '100%', height }} />;
return <div ref={domWrapRef} style={{ width: '100%', height }} />;
};
export default BarTrend;