feat: 服务器资源趋势图表(Chart.js本地化+CPU/内存/磁盘趋势)

This commit is contained in:
gouki
2026-08-02 21:52:29 +00:00
parent e53361d1e4
commit d15fe834b3
3 changed files with 49 additions and 2 deletions
+34 -2
View File
@@ -1,5 +1,5 @@
/* vps-manager 前端应用(Vue 3 组件化) */
const { createApp, reactive, ref, computed, onMounted, watch } = Vue;
const { createApp, reactive, ref, computed, onMounted, watch, nextTick } = Vue;
const Api = window.VpsApi;
const Fmt = window.VpsFmt;
@@ -156,7 +156,7 @@ async function viewServer(a) {
store.view = 'servers';
try {
const [metrics, info, checks] = await Promise.all([
Api.get('/monitor/' + a.id + '/metrics'),
Api.get('/monitor/' + a.id + '/metrics?limit=200'),
Api.get('/monitor/' + a.id + '/info'),
Api.get('/monitor/' + a.id + '/security'),
]);
@@ -494,6 +494,10 @@ const ServersView = {
<div>公网 IP{{ m.info.public_ip || '—' }}</div><div>状态:{{ m.info.status }}</div>
</div>
</div>
<div v-if="m.metrics && m.metrics.length > 1" 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">资源趋势(最近 {{ m.metrics.length }} 次采样)</h3>
<canvas id="metricsChart" height="90"></canvas>
</div>
<div 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>
<div class="space-y-2">
@@ -513,6 +517,34 @@ const ServersView = {
setup() {
const m = computed(() => store.serverMetrics);
const latest = 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' } },
},
});
}
watch(m, () => { nextTick(renderChart); }, { deep: true });
onMounted(() => { nextTick(renderChart); });
return { store, Fmt, m, latest };
},
};
File diff suppressed because one or more lines are too long