diff --git a/src/components/report/TrendLineChart/TrendLineChart.tsx b/src/components/report/TrendLineChart/TrendLineChart.tsx index accf021..f92cd2a 100644 --- a/src/components/report/TrendLineChart/TrendLineChart.tsx +++ b/src/components/report/TrendLineChart/TrendLineChart.tsx @@ -38,18 +38,232 @@ function TrendLineChart({ data, title = '收支趋势', loading = false }: Trend trigger: 'axis', confine: true, // Keep tooltip inside chart area backgroundColor: 'rgba(255, 255, 255, 0.8)', - // ... (keep existing properties) ... + borderColor: '#e2e8f0', + borderWidth: 1, + textStyle: { + color: '#1e293b', + }, + extraCssText: 'backdrop-filter: blur(8px); border-radius: 8px; box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);', + axisPointer: { + type: 'cross', + label: { + backgroundColor: '#6a7985', + }, + }, + formatter: (params: any) => { + let result = `
${params[0].axisValue}
`; + + let income = 0; + let expense = 0; + + params.forEach((param: any) => { + const color = param.color; + const value = param.value; + if (param.seriesName === '收入') income = value; + if (param.seriesName === '支出') expense = value; + + result += `
+ + + ${param.seriesName} + + ¥${value.toLocaleString('zh-CN', { + minimumFractionDigits: 2, + maximumFractionDigits: 2, + })} +
`; + }); + + const net = income - expense; + const isSurplus = net >= 0; + const netColor = isSurplus ? '#10b981' : '#ef4444'; + const netLabel = isSurplus ? '结余' : '赤字'; + + result += `
+ 本日${netLabel} + + ${isSurplus ? '+' : ''}¥${net.toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })} + +
`; + + return result; + }, }, - // ... - return( -
- -
+ dataZoom: [ + { + type: 'slider', + show: true, + xAxisIndex: [0], + start: 0, + end: 100, + bottom: 0, + borderColor: 'transparent', + fillerColor: 'rgba(99, 102, 241, 0.1)', + handleStyle: { + color: '#6366f1', + }, + }, + { + type: 'inside', + xAxisIndex: [0], + start: 0, + end: 100, + }, + ], + legend: { + data: ['收入', '支出', '结余'], + top: 40, + left: 'center', + }, + grid: { + left: '3%', + right: '4%', + bottom: '3%', + top: 80, + containLabel: true, + }, + xAxis: { + type: 'category', + boundaryGap: false, + data: data.map((item) => formatDate(item.date)), + axisLabel: { + rotate: 45, + fontSize: 11, + }, + }, + yAxis: { + type: 'value', + axisLabel: { + formatter: (value: number) => { + if (value >= 10000) { + return `${(value / 10000).toFixed(1)}万`; + } + return value.toFixed(0); + }, + }, + }, + series: [ + { + name: '收入', + type: 'line', + smooth: true, + data: data.map((item) => item.income), + itemStyle: { + color: '#10b981', + }, + areaStyle: { + color: { + type: 'linear', + x: 0, + y: 0, + x2: 0, + y2: 1, + colorStops: [ + { offset: 0, color: 'rgba(16, 185, 129, 0.3)' }, + { offset: 1, color: 'rgba(16, 185, 129, 0.05)' }, + ], + }, + }, + }, + { + name: '支出', + type: 'line', + smooth: true, + data: data.map((item) => item.expense), + itemStyle: { + color: '#ef4444', + }, + areaStyle: { + color: { + type: 'linear', + x: 0, + y: 0, + x2: 0, + y2: 1, + colorStops: [ + { offset: 0, color: 'rgba(239, 68, 68, 0.3)' }, + { offset: 1, color: 'rgba(239, 68, 68, 0.05)' }, + ], + }, + }, + markPoint: { + data: [ + { type: 'max', name: '最大支出' }, + ], + symbol: 'pin', + symbolSize: 45, + itemStyle: { + color: '#ef4444' + }, + label: { + color: '#fff', + fontSize: 10, + formatter: 'Max' + } + }, + }, + { + name: '结余', + type: 'line', + smooth: true, + showSymbol: false, + data: data.map((item) => item.balance), + itemStyle: { + color: '#3b82f6', + }, + lineStyle: { + width: 2, + type: 'dashed', + }, + markPoint: { + data: [ + { type: 'max', name: 'Max' }, + { type: 'min', name: 'Min' }, + ], + symbol: 'pin', + symbolSize: 40, + label: { + color: '#fff', + fontSize: 10, + formatter: '{c}' + } + }, + markLine: { + data: [{ type: 'average', name: 'Avg' }], + precision: 0, + label: { + formatter: '均值: {c}' + } + }, + }, + ], + }; + + if (loading) { + return ( +
+
加载中...
+
+ ); + } + + if (!data || data.length === 0) { + return ( +
+
暂无数据
+
+ ); + } + + return ( +
+ +
); }