From eca886c6ccb5d2025ed51a00fac5d2c459e59909 Mon Sep 17 00:00:00 2001 From: gouki Date: Sun, 2 Aug 2026 21:57:17 +0000 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=B4=A6=E5=8D=95=E6=94=AF=E5=87=BA?= =?UTF-8?q?=E5=9B=BE=E8=A1=A8=EF=BC=88=E6=8C=89=E5=B9=B3=E5=8F=B0=E6=9C=88?= =?UTF-8?q?=E5=BA=A6=E6=94=AF=E5=87=BA=E6=9F=B1=E7=8A=B6=E5=9B=BE=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- static/js/app.js | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/static/js/app.js b/static/js/app.js index b812a03..0595a05 100644 --- a/static/js/app.js +++ b/static/js/app.js @@ -332,6 +332,10 @@ const SubscriptionsView = {
年度约 {{ (v*12).toFixed(2) }}
+
+

按平台月度支出(换算为月均)

+ +
@@ -372,7 +376,37 @@ const SubscriptionsView = { } return m; }); - return { store, Fmt, subs, monthlyByCurrency }; + const byProviderMonthly = computed(() => { + const m = {}; + for (const a of subs.value) { + const prov = a.provider_name || a.provider; + m[prov] = (m[prov] || 0) + normalizedMonthly(a.cost, a.renewal_cycle); + } + return m; + }); + let billingChart = null; + function renderBillingChart() { + const canvas = document.getElementById('billingChart'); + if (!canvas || !window.Chart) return; + const entries = Object.entries(byProviderMonthly.value).sort((x, y) => y[1] - x[1]); + if (!entries.length) return; + if (billingChart) { billingChart.destroy(); billingChart = null; } + billingChart = new Chart(canvas, { + type: 'bar', + data: { + labels: entries.map(e => e[0]), + datasets: [{ label: '月度支出', data: entries.map(e => e[1].toFixed(2)), backgroundColor: '#6366f1', borderRadius: 6 }], + }, + options: { + responsive: true, + scales: { y: { beginAtZero: true } }, + plugins: { legend: { display: false } }, + }, + }); + } + watch([subs, byProviderMonthly], () => { nextTick(renderBillingChart); }, { deep: true }); + onMounted(() => { nextTick(renderBillingChart); }); + return { store, Fmt, subs, monthlyByCurrency, byProviderMonthly }; }, };