/* 订阅视图 */
const SubscriptionsView = {
template: `
💸 这里是「付费资产」汇总:自动收集所有设置了费用或到期日的资产(跨 VPS / 域名 / AI 账号),统一看每个月花多少钱、哪些该续费。
月度支出({{ cur }})
{{ v.toFixed(2) }}
年度约 {{ (v*12).toFixed(2) }}
按平台月度支出(换算为月均)
| 项目 |
平台 |
费用 |
到期 |
管理 |
| 暂无付费资产(给资产设置费用和到期日即可出现) |
| {{ a.name }} |
{{ a.provider_name || a.provider }} |
{{ a.cost }} {{ a.currency }}/{{ Fmt.CYCLE_LABELS[a.renewal_cycle] || a.renewal_cycle }} |
{{ a.expiry_date || '—' }}({{ a.days_to_expiry }}天) |
续费
取消
—
|
`,
setup() {
const subs = Vue.computed(() => store.assets
.filter(a => (a.cost > 0 || a.expiry_date) && a.status !== 'cancelled')
.sort((x, y) => (x.days_to_expiry ?? 9999) - (y.days_to_expiry ?? 9999)));
const monthlyByCurrency = Vue.computed(() => {
const m = {};
for (const a of subs.value) {
const cur = a.currency || 'USD';
m[cur] = (m[cur] || 0) + normalizedMonthly(a.cost, a.renewal_cycle);
}
return m;
});
const byProviderMonthly = Vue.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 } },
},
});
}
Vue.watch([subs, byProviderMonthly], () => { Vue.nextTick(renderBillingChart); }, { deep: true });
Vue.onMounted(() => { Vue.nextTick(renderBillingChart); });
Vue.onUnmounted(() => { if (billingChart) { billingChart.destroy(); billingChart = null; } });
return { store, Fmt, subs, monthlyByCurrency, byProviderMonthly };
},
};