2626</template >
2727
2828<script setup lang="ts">
29- import { ref } from ' vue' ;
29+ import { ref , onMounted , onUnmounted , watch , markRaw } from ' vue' ;
3030import { FDatePicker , FButton } from ' @fesjs/fes-design' ;
3131import { ReloadOutlined } from ' @fesjs/fes-design/icon' ;
32- import { useChart , type ChartConfig } from ' ./useChart' ;
32+ import type { EChartsOption , TooltipComponentFormatterCallback } from ' echarts' ;
33+ import echarts from ' ./useEcharts' ;
3334import {
3435 getYear , getMonth , getDate , subDays , differenceInDays ,
3536 format ,
@@ -38,6 +39,24 @@ import { useLocale } from '../hooks/useLocale';
3839
3940const locale = useLocale ();
4041const chartsLocale = locale .Charts ;
42+
43+ interface BarStyle {
44+ color: string ;
45+ borderColor: string ;
46+ }
47+
48+ interface ChartConfig {
49+ title: string ;
50+ series: {
51+ field: string ;
52+ name: string ;
53+ itemStyle: BarStyle ;
54+ }[];
55+ fetchData: (startTime : number , endTime : number ) => Promise <any []>;
56+ xAxisField: string ;
57+ tooltipFormatter? : (params : any []) => string ;
58+ }
59+
4160interface Props {
4261 chartId: string ;
4362 config: ChartConfig ;
@@ -83,13 +102,187 @@ const updateDays = (newDays: number) => {
83102 endDate .value = _endDate .getTime ();
84103};
85104
86- // 图表相关
87- const { loading, updateChart } = useChart (
88- props .chartId ,
89- props .config ,
90- startDate ,
91- endDate
92- );
105+ // 图表相关逻辑
106+ let chartInstance: echarts .ECharts | null = null ;
107+ const loading = ref (false );
108+
109+ const initChart = () => {
110+ const chartDom = document .getElementById (props .chartId );
111+ const instance = echarts .getInstanceByDom (chartDom as HTMLElement );
112+ if (instance ) {
113+ instance .dispose ();
114+ }
115+ if (chartDom ) {
116+ chartInstance = markRaw (echarts .init (chartDom ));
117+ }
118+ };
119+
120+ const transformData = (data : any []) => {
121+ const xAxisData = data .map (item => item [props .config .xAxisField ]);
122+ // 计算每个系列的总和
123+ const seriesTotal = props .config .series .reduce ((acc , series ) => {
124+ const total = data .reduce ((sum , item ) => sum + (Number (item [series .field ]) || 0 ), 0 );
125+ acc [series .name ] = total ;
126+ return acc ;
127+ }, {} as Record <string , number >);
128+
129+ // 计算最大值来确定左侧留白
130+ let maxSum = 0 ;
131+ let leftGridSize = 16 ; // 基础留白大小
132+
133+ data .forEach (item => {
134+ // 计算所有系列的当前数据点总和
135+ const currentSum = props .config .series .reduce ((sum , series ) => {
136+ return sum + (item [series .field ] || 0 );
137+ }, 0 );
138+ maxSum = Math .max (maxSum , currentSum );
139+ });
140+
141+ // 根据最大值的位数调整留白
142+ const maxSumLen = String (maxSum ).length ;
143+ if (maxSumLen > 0 ) {
144+ leftGridSize += (maxSumLen - 1 ) * 8 ;
145+ }
146+
147+ const series = props .config .series .map (item => ({
148+ name: item .name ,
149+ type: ' bar' as const ,
150+ data: data .map (d => d [item .field ]),
151+ itemStyle: item .itemStyle ,
152+ emphasis: {
153+ focus: ' series' as const
154+ }
155+ }));
156+
157+ return {
158+ xAxisData ,
159+ series ,
160+ leftGridSize ,
161+ seriesTotal
162+ };
163+ };
164+
165+ const genTooltipStr = (tempData : any []) => {
166+ const showList = tempData .map ((item : { value: any ; seriesName: any ; }) => ({
167+ value: item .value ,
168+ name: item .seriesName
169+ }));
170+ const dateStr = showList .length ? ` ${chartsLocale .date }${tempData [0 ].name } <br /> ` : ' ' ;
171+ const total = showList .reduce ((pre : any , cur : { value: any ; }) => pre + cur .value , 0 );
172+ const totalStr = showList .length ? ` ${chartsLocale .total }${total } <br /> ` : ' ' ;
173+ const showListStr = showList .reduce ((pre : any , cur : { name: any ; value: any ; }) =>
174+ ` ${pre }${cur .name }: ${cur .value }<br /> ` , ' ' );
175+ return dateStr + totalStr + showListStr ;
176+ };
177+
178+ const updateChart = async () => {
179+ if (! chartInstance ) return ;
180+
181+ try {
182+ loading .value = true ;
183+ const data = await props .config .fetchData (startDate .value , endDate .value );
184+ const { xAxisData, series, leftGridSize, seriesTotal } = transformData (data );
185+
186+ const option: EChartsOption = {
187+ backgroundColor: ' #fff' ,
188+ grid: {
189+ top: 17 ,
190+ right: 0 ,
191+ left: leftGridSize ,
192+ bottom: 95 ,
193+ containLabel: true
194+ },
195+ tooltip: {
196+ trigger: ' axis' ,
197+ axisPointer: {
198+ type: " shadow" ,
199+ },
200+ formatter: ((params ) => {
201+ const formattedParams = params as any [];
202+ return props .config .tooltipFormatter
203+ ? props .config .tooltipFormatter (formattedParams )
204+ : genTooltipStr (formattedParams );
205+ }) as TooltipComponentFormatterCallback <any >
206+ },
207+ dataZoom: {
208+ type: ' slider' ,
209+ startValue: 0 ,
210+ endValue: 6 ,
211+ xAxisIndex: [0 ],
212+ handleSize: 0 ,
213+ height: 5 ,
214+ bottom: 70 ,
215+ borderColor: ' transparent' ,
216+ fillerColor: ' transparent' ,
217+ backgroundColor: ' transparent' ,
218+ showDataShadow: false ,
219+ showDetail: false ,
220+ realtime: true ,
221+ filterMode: ' filter'
222+ },
223+ legend: {
224+ bottom: 0 ,
225+ icon: ' rect' ,
226+ height: 20 ,
227+ itemWidth: 10 ,
228+ itemHeight: 10 ,
229+ itemGap: 32 ,
230+ itemStyle: {
231+ borderWidth: 1
232+ },
233+ formatter : (name ) => {
234+ return ` ${name }(${seriesTotal [name ]}) ` ;
235+ },
236+ data: props .config .series .map (item => ({
237+ name: item .name ,
238+ itemStyle: item .itemStyle
239+ }))
240+ },
241+ xAxis: [{
242+ type: ' category' ,
243+ axisTick: { show: false },
244+ axisLine: { show: false },
245+ data: xAxisData
246+ }],
247+ yAxis: [{
248+ type: ' value' ,
249+ splitLine: {
250+ lineStyle: {
251+ width: 1 ,
252+ color: ' #F1F1F2'
253+ }
254+ }
255+ }],
256+ series
257+ };
258+
259+ chartInstance .setOption (option );
260+ } finally {
261+ loading .value = false ;
262+ }
263+ };
264+
265+ const handleResize = () => {
266+ chartInstance ?.resize ();
267+ };
268+
269+ // 监听日期变化
270+ watch ([startDate , endDate ], () => {
271+ updateChart ();
272+ }, {
273+ immediate: true
274+ });
275+
276+ onMounted (() => {
277+ initChart ();
278+ updateChart ();
279+ window .addEventListener (' resize' , handleResize );
280+ });
281+
282+ onUnmounted (() => {
283+ window .removeEventListener (' resize' , handleResize );
284+ chartInstance ?.dispose ();
285+ });
93286
94287const lastUpdateTime = ref (format (new Date (), ' yyyy-MM-dd HH:mm:ss' ));
95288
0 commit comments