diff --git a/admin/assets/app.js b/admin/assets/app.js index a7b70c8..86c0bcd 100644 --- a/admin/assets/app.js +++ b/admin/assets/app.js @@ -9,6 +9,7 @@ let tlsForwardersState = []; let editingXrayClientId = null; let wzInbounds = []; let dashboardCache = { sshUsers: [], xrayInbounds: [], me: null }; +let currentTab = "dashboard"; // ─── DOM refs ───────────────────────────────────────────────────────────────── const loginOverlay = document.getElementById("loginOverlay"); @@ -206,6 +207,7 @@ const tabTitles = { }; function selectTab(tab) { + currentTab = tab; const pane = document.getElementById("tab-" + tab); const btn = document.querySelector(`.tab-btn[data-tab="${tab}"]`); if (!pane || !btn) return; @@ -311,14 +313,18 @@ function initAfterLogin() { selectTab("dashboard"); if (currentRole === "superadmin") { - loadStats(); - statsTimer = setInterval(loadStats, 2000); + loadDashboardStats(); + statsTimer = setInterval(() => { + loadDashboardStats(); + if (currentTab === "stats") loadStats(); + }, 2000); } else { loadMe(); } - xrayTimer = setInterval(loadXrayStatus, 7000); + xrayTimer = setInterval(() => { loadXrayStatus(); if (currentTab === "xray") loadInbounds(); }, 7000); loadUsers(); + loadXrayStatus(); loadInbounds(); usersTimer = setInterval(() => loadUsersSilent(), 3000); } @@ -1072,6 +1078,22 @@ async function deleteReseller(username) { // ─── Stats ──────────────────────────────────────────────────────────────────── document.querySelector("[data-tab='stats']")?.addEventListener("click", loadStats); +async function loadDashboardStats() { + try { + const res = await api("/api/stats"); + if (!res.ok) throw new Error(await res.text()); + const s = await res.json(); + updateDashboardStats(s); + } catch (e) { + if (e.message === "auth") doAuthError(); + else { + if (dashCpuVal) dashCpuVal.textContent = "erro"; + if (dashRamVal) dashRamVal.textContent = "erro"; + if (dashNetVal) dashNetVal.textContent = "erro"; + } + } +} + function updateDashboardStats(s) { if (!s) return; const cpu = Number(s.cpu_percent ?? 0); @@ -1101,28 +1123,33 @@ function updateDashboardStats(s) { async function loadStats() { try { const res = await api("/api/stats"); + if (!res.ok) throw new Error(await res.text()); const s = await res.json(); updateDashboardStats(s); - const cpu = s?.cpu_percent ?? 0; - cpuVal.textContent = fmtPct(cpu); - cpuBar.style.width = Math.min(100, Math.max(0, cpu)) + "%"; - const mp = s?.mem_percent ?? null; - memVal.textContent = mp == null ? "--%" : fmtPct(mp); - memBar.style.width = mp == null ? "0%" : Math.min(100, Math.max(0, mp)) + "%"; + const cpu = Number(s?.cpu_percent ?? 0); + if (cpuVal) cpuVal.textContent = fmtPct(cpu); + if (cpuBar) cpuBar.style.width = Math.min(100, Math.max(0, cpu)) + "%"; + const mp = s?.mem_percent == null ? null : Number(s.mem_percent); + if (memVal) memVal.textContent = mp == null ? "--%" : fmtPct(mp); + if (memBar) memBar.style.width = mp == null ? "0%" : Math.min(100, Math.max(0, mp)) + "%"; const mu = s?.mem_used_bytes, mt = s?.mem_total_bytes; - memDetail.textContent = (mu != null && mt != null) ? `${fmtBytes(mu)} / ${fmtBytes(mt)}` : ""; + if (memDetail) memDetail.textContent = (mu != null && mt != null) ? `${fmtBytes(mu)} / ${fmtBytes(mt)}` : ""; const ifaces = Array.isArray(s.interfaces) ? s.interfaces : []; - ifaceBody.innerHTML = ""; + if (ifaceBody) ifaceBody.innerHTML = ""; let totRx = 0, totTx = 0; ifaces.forEach(it => { - totRx += it.rx_bytes||0; totTx += it.tx_bytes||0; + totRx += Number(it.rx_bytes||0); totTx += Number(it.tx_bytes||0); + if (!ifaceBody) return; const tr = document.createElement("tr"); tr.innerHTML = `