From 7a39258bc8c09d845033142861c4dc1c6ee2c56b Mon Sep 17 00:00:00 2001 From: SunCheng Date: Thu, 19 Feb 2026 21:34:55 +0800 Subject: [PATCH] fix --- .../components/Budget/BudgetChartAnalysis.vue | 88 ++++++++++++++++++- .../statisticsV2/modules/DailyTrendChart.vue | 2 +- .../modules/MonthlyExpenseCard.vue | 2 - 3 files changed, 86 insertions(+), 6 deletions(-) diff --git a/Web/src/components/Budget/BudgetChartAnalysis.vue b/Web/src/components/Budget/BudgetChartAnalysis.vue index b2c1e35..2fe44b4 100644 --- a/Web/src/components/Budget/BudgetChartAnalysis.vue +++ b/Web/src/components/Budget/BudgetChartAnalysis.vue @@ -166,6 +166,7 @@ type="bar" :data="varianceChartData" :options="varianceChartOptions" + :plugins="varianceChartPlugins" class="chart-body variance-chart" :style="{ height: calculateChartHeight(budgets) + 'px' }" /> @@ -447,6 +448,78 @@ const calculateChartHeight = (budgets) => { return calculatedHeight } +const varianceLabelPlugin = { + id: 'variance-label-plugin', + afterDatasetsDraw: (chart) => { + const dataset = chart.data?.datasets?.[0] + const metaData = dataset?._meta + if (!dataset || !metaData) { + return + } + + const meta = chart.getDatasetMeta(0) + if (!meta?.data) { + return + } + + const { ctx, chartArea } = chart + const fontFamily = '"PingFang SC", "Microsoft YaHei", "Helvetica Neue", Arial, sans-serif' + ctx.save() + ctx.font = `12px ${fontFamily}` + ctx.textBaseline = 'middle' + + meta.data.forEach((bar, index) => { + const item = metaData[index] + if (!item || item.value === 0) { + return + } + + const label = formatVarianceLabelValue(item.value) + const textWidth = ctx.measureText(label).width + const position = bar.tooltipPosition ? bar.tooltipPosition() : { x: bar.x, y: bar.y } + const offset = 8 + const isPositive = item.value > 0 + ctx.fillStyle = getVarianceLabelColor(item.value) + let x = position.x + (isPositive ? offset : -offset) + const y = position.y + + if (chartArea) { + const rightLimit = chartArea.right - 4 + const leftLimit = chartArea.left + 4 + if (isPositive && x + textWidth > rightLimit) { + x = rightLimit - textWidth + } + if (!isPositive && x - textWidth < leftLimit) { + x = leftLimit + textWidth + } + } + + ctx.textAlign = isPositive ? 'left' : 'right' + + ctx.fillText(label, x, y) + }) + + ctx.restore() + } +} + +const varianceChartPlugins = computed(() => [varianceLabelPlugin]) + +const formatVarianceLabelValue = (value) => { + const absValue = Math.abs(Math.round(value || 0)) + return absValue.toLocaleString(undefined, { + minimumFractionDigits: 0, + maximumFractionDigits: 0 + }) +} + +const getVarianceLabelColor = (value) => { + if (props.activeTab === BudgetCategory.Expense) { + return value > 0 ? getCssVar('--van-danger-color') : getCssVar('--van-success-color') + } + return value > 0 ? getCssVar('--van-success-color') : getCssVar('--van-danger-color') +} + // 偏差分析图表数据 const varianceChartData = computed(() => { if (!props.budgets || props.budgets.length === 0) { @@ -469,10 +542,19 @@ const varianceChartData = computed(() => { const monthlyData = data.filter((item) => item.type === BudgetPeriodType.Month) const annualData = data.filter((item) => item.type === BudgetPeriodType.Year) - monthlyData.sort((a, b) => Math.abs(b.value) - Math.abs(a.value)) - annualData.sort((a, b) => Math.abs(b.value) - Math.abs(a.value)) + const sortByLimitAndRemaining = (a, b) => { + if (a.limit !== b.limit) { + return a.limit - b.limit + } + const remainingA = a.limit - a.current + const remainingB = b.limit - b.current + return remainingB - remainingA + } - const sortedData = [...annualData, ...monthlyData] + monthlyData.sort(sortByLimitAndRemaining) + annualData.sort(sortByLimitAndRemaining) + + const sortedData = [...monthlyData, ...annualData] return { labels: sortedData.map((item) => item.name), diff --git a/Web/src/views/statisticsV2/modules/DailyTrendChart.vue b/Web/src/views/statisticsV2/modules/DailyTrendChart.vue index f05fc1d..ad8e557 100644 --- a/Web/src/views/statisticsV2/modules/DailyTrendChart.vue +++ b/Web/src/views/statisticsV2/modules/DailyTrendChart.vue @@ -267,6 +267,6 @@ const chartOptions = computed(() => { .trend-chart { width: 100%; - height: 190px; + height: 200px; } diff --git a/Web/src/views/statisticsV2/modules/MonthlyExpenseCard.vue b/Web/src/views/statisticsV2/modules/MonthlyExpenseCard.vue index 827d31a..fab6a25 100644 --- a/Web/src/views/statisticsV2/modules/MonthlyExpenseCard.vue +++ b/Web/src/views/statisticsV2/modules/MonthlyExpenseCard.vue @@ -456,7 +456,5 @@ const chartOptions = computed(() => { .trend-chart { width: 100%; height: 200px; - overflow: hidden; - position: relative; }