添加95带宽计算
This commit is contained in:
@@ -25,6 +25,7 @@
|
||||
traffic24hRx: document.getElementById('traffic24hRx'),
|
||||
traffic24hTx: document.getElementById('traffic24hTx'),
|
||||
traffic24hTotal: document.getElementById('traffic24hTotal'),
|
||||
trafficP95: document.getElementById('trafficP95'),
|
||||
networkCanvas: document.getElementById('networkCanvas'),
|
||||
serverTableBody: document.getElementById('serverTableBody'),
|
||||
btnSettings: document.getElementById('btnSettings'),
|
||||
@@ -58,7 +59,8 @@
|
||||
closeLoginModal: document.getElementById('closeLoginModal'),
|
||||
loginForm: document.getElementById('loginForm'),
|
||||
loginError: document.getElementById('loginError'),
|
||||
gaugesTime: document.getElementById('gaugesTime')
|
||||
gaugesTime: document.getElementById('gaugesTime'),
|
||||
footerTime: document.getElementById('footerTime')
|
||||
};
|
||||
|
||||
// ---- State ----
|
||||
@@ -120,7 +122,7 @@
|
||||
// Start data fetching
|
||||
fetchMetrics();
|
||||
fetchNetworkHistory();
|
||||
|
||||
|
||||
// Site settings
|
||||
if (window.SITE_SETTINGS) {
|
||||
applySiteSettings(window.SITE_SETTINGS);
|
||||
@@ -128,14 +130,14 @@
|
||||
const savedTheme = localStorage.getItem('theme');
|
||||
const currentTheme = savedTheme || window.SITE_SETTINGS.default_theme || 'dark';
|
||||
updateThemeIcons(currentTheme);
|
||||
|
||||
|
||||
// Still populate inputs
|
||||
dom.pageNameInput.value = window.SITE_SETTINGS.page_name || '';
|
||||
dom.siteTitleInput.value = window.SITE_SETTINGS.title || '';
|
||||
dom.logoUrlInput.value = window.SITE_SETTINGS.logo_url || '';
|
||||
dom.defaultThemeInput.value = window.SITE_SETTINGS.default_theme || 'dark';
|
||||
}
|
||||
|
||||
|
||||
loadSiteSettings();
|
||||
|
||||
setInterval(fetchMetrics, REFRESH_INTERVAL);
|
||||
@@ -155,7 +157,7 @@
|
||||
if (theme === 'auto') {
|
||||
actualTheme = window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
|
||||
}
|
||||
|
||||
|
||||
const isLight = actualTheme === 'light';
|
||||
dom.themeToggle.checked = isLight;
|
||||
document.documentElement.classList.toggle('light-theme', isLight);
|
||||
@@ -259,8 +261,12 @@
|
||||
}
|
||||
|
||||
function updateGaugesTime() {
|
||||
const clockStr = formatClock();
|
||||
if (dom.gaugesTime) {
|
||||
dom.gaugesTime.textContent = formatClock();
|
||||
dom.gaugesTime.textContent = clockStr;
|
||||
}
|
||||
if (dom.footerTime) {
|
||||
dom.footerTime.textContent = clockStr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -387,6 +393,9 @@
|
||||
const response = await fetch('/api/metrics/network-history');
|
||||
const data = await response.json();
|
||||
networkChart.setData(data);
|
||||
if (dom.trafficP95 && networkChart.p95) {
|
||||
dom.trafficP95.textContent = formatBandwidth(networkChart.p95);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Error fetching network history:', err);
|
||||
}
|
||||
@@ -419,7 +428,7 @@
|
||||
try {
|
||||
const response = await fetch('/api/settings');
|
||||
const settings = await response.json();
|
||||
|
||||
|
||||
window.SITE_SETTINGS = settings; // Cache it globally
|
||||
|
||||
// Update inputs
|
||||
@@ -427,7 +436,7 @@
|
||||
dom.siteTitleInput.value = settings.title || '';
|
||||
dom.logoUrlInput.value = settings.logo_url || '';
|
||||
dom.defaultThemeInput.value = settings.default_theme || 'dark';
|
||||
|
||||
|
||||
// Apply to UI
|
||||
applySiteSettings(settings);
|
||||
|
||||
@@ -457,7 +466,7 @@
|
||||
if (settings.title) {
|
||||
dom.logoText.textContent = settings.title;
|
||||
}
|
||||
|
||||
|
||||
// Logo Icon
|
||||
if (settings.logo_url) {
|
||||
dom.logoIconContainer.innerHTML = `<img src="${escapeHtml(settings.logo_url)}" alt="Logo" class="logo-icon-img">`;
|
||||
|
||||
@@ -47,6 +47,18 @@ class AreaChart {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
// Calculate P95 (95th percentile)
|
||||
// Common standard: 95th percentile of the peak (max of rx/tx or sum)
|
||||
// We'll use max(rx, tx) at each point which is common for billing
|
||||
const combined = data.rx.map((r, i) => Math.max(r || 0, data.tx[i] || 0));
|
||||
if (combined.length > 0) {
|
||||
const sorted = [...combined].sort((a, b) => a - b);
|
||||
const p95Idx = Math.floor(sorted.length * 0.95);
|
||||
this.p95 = sorted[p95Idx];
|
||||
} else {
|
||||
this.p95 = null;
|
||||
}
|
||||
|
||||
this.animProgress = 0;
|
||||
this.animate();
|
||||
}
|
||||
@@ -173,6 +185,35 @@ class AreaChart {
|
||||
this.drawArea(ctx, rx, getX, getY, chartH, p,
|
||||
'rgba(6, 182, 212, 0.25)', 'rgba(6, 182, 212, 0.02)',
|
||||
'#06b6d4', len);
|
||||
|
||||
// Draw P95 line
|
||||
if (this.p95 && this.animProgress === 1) {
|
||||
const p95Y = getY(this.p95);
|
||||
// Only draw if within visible range
|
||||
if (p95Y >= p.top && p95Y <= p.top + chartH) {
|
||||
ctx.save();
|
||||
ctx.beginPath();
|
||||
ctx.setLineDash([6, 4]);
|
||||
ctx.strokeStyle = 'rgba(244, 63, 94, 0.85)'; // --accent-rose
|
||||
ctx.lineWidth = 1.5;
|
||||
ctx.moveTo(p.left, p95Y);
|
||||
ctx.lineTo(p.left + chartW, p95Y);
|
||||
ctx.stroke();
|
||||
|
||||
// P95 label background
|
||||
const label = '95计费: ' + (window.formatBandwidth ? window.formatBandwidth(this.p95) : this.p95.toFixed(2));
|
||||
ctx.font = 'bold 11px "JetBrains Mono", monospace';
|
||||
const metrics = ctx.measureText(label);
|
||||
ctx.fillStyle = 'rgba(244, 63, 94, 0.15)';
|
||||
ctx.fillRect(p.left + 8, p95Y - 20, metrics.width + 12, 18);
|
||||
|
||||
// P95 label text
|
||||
ctx.fillStyle = '#f43f5e';
|
||||
ctx.textAlign = 'left';
|
||||
ctx.fillText(label, p.left + 14, p95Y - 7);
|
||||
ctx.restore();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
drawArea(ctx, values, getX, getY, chartH, p, fillColorTop, fillColorBottom, strokeColor, len) {
|
||||
|
||||
Reference in New Issue
Block a user