feat: 账单支出图表(按平台月度支出柱状图)
This commit is contained in:
+35
-1
@@ -332,6 +332,10 @@ const SubscriptionsView = {
|
|||||||
<div class="text-xs text-slate-400 mt-1">年度约 {{ (v*12).toFixed(2) }}</div>
|
<div class="text-xs text-slate-400 mt-1">年度约 {{ (v*12).toFixed(2) }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-if="subs.length" class="bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-slate-800 p-4">
|
||||||
|
<h3 class="font-semibold mb-2 text-sm">按平台月度支出(换算为月均)</h3>
|
||||||
|
<canvas id="billingChart" height="80"></canvas>
|
||||||
|
</div>
|
||||||
<div class="bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-slate-800 overflow-hidden">
|
<div class="bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-slate-800 overflow-hidden">
|
||||||
<table class="w-full text-sm">
|
<table class="w-full text-sm">
|
||||||
<thead class="bg-slate-50 dark:bg-slate-800/50 text-slate-500 text-left text-xs">
|
<thead class="bg-slate-50 dark:bg-slate-800/50 text-slate-500 text-left text-xs">
|
||||||
@@ -372,7 +376,37 @@ const SubscriptionsView = {
|
|||||||
}
|
}
|
||||||
return m;
|
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 };
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user