/* 服务器监控视图 */ const ServersView = { template: `
请在「资产」页点击 VPS 的「监控」查看服务器资源与安全状态
`, setup() { const m = Vue.computed(() => store.serverMetrics); const latest = Vue.computed(() => (m.value.metrics && m.value.metrics.length) ? m.value.metrics[0] : null); let chartInstance = null; function renderChart() { const canvas = document.getElementById('metricsChart'); if (!canvas || !window.Chart) return; if (!m.value.metrics || m.value.metrics.length < 2) return; if (chartInstance) { chartInstance.destroy(); chartInstance = null; } const data = [...m.value.metrics].reverse(); const labels = data.map(p => new Date(p.ts).toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' })); chartInstance = new Chart(canvas, { type: 'line', data: { labels, datasets: [ { label: 'CPU %', data: data.map(p => p.cpu_pct), borderColor: '#3b82f6', backgroundColor: 'rgba(59,130,246,0.1)', tension: 0.3, pointRadius: 0 }, { label: '内存 %', data: data.map(p => p.mem_pct), borderColor: '#10b981', backgroundColor: 'rgba(16,185,129,0.1)', tension: 0.3, pointRadius: 0 }, { label: '磁盘 %', data: data.map(p => p.disk_pct), borderColor: '#f59e0b', backgroundColor: 'rgba(245,158,11,0.1)', tension: 0.3, pointRadius: 0 }, ], }, options: { responsive: true, interaction: { mode: 'index', intersect: false }, scales: { y: { min: 0, max: 100, ticks: { callback: v => v + '%' } } }, plugins: { legend: { position: 'top' } }, }, }); } Vue.watch(m, () => { Vue.nextTick(renderChart); }, { deep: true }); Vue.onMounted(() => { Vue.nextTick(renderChart); }); Vue.onUnmounted(() => { if (chartInstance) { chartInstance.destroy(); chartInstance = null; } }); function scoreClass(level) { return { good: 'text-emerald-600 dark:text-emerald-400', warning: 'text-amber-600 dark:text-amber-400', risk: 'text-red-600 dark:text-red-400', unknown: 'text-slate-400' }[level] || 'text-slate-400'; } function goBack() { window.location.hash = '#assets'; } return { store, Fmt, m, latest, scoreClass, goBack }; }, };