const header = document.querySelector('.site-header'); function updateHeader() { if (!header) return; header.style.background = window.scrollY > 40 ? 'rgba(15, 18, 24, 0.94)' : 'rgba(15, 18, 24, 0.78)'; } window.addEventListener('scroll', updateHeader, { passive: true }); updateHeader(); const statusDashboard = document.querySelector('[data-status-dashboard]'); const statusText = { noHeartbeat: '\u5c1a\u672a\u6536\u5230\u5fc3\u8df3', secondsAgo: '\u79d2\u524d\u66f4\u65b0', minutesAgo: '\u5206\u9418\u524d\u66f4\u65b0', hoursAgo: '\u5c0f\u6642\u524d\u66f4\u65b0', online: '\u5728\u7dda', offline: '\u96e2\u7dda', normal: '\u6b63\u5e38', abnormal: '\u7570\u5e38', noData: '\u7121\u8cc7\u6599', unknown: '\u672a\u77e5', guildUnit: '\u500b\u4f3a\u670d\u5668', userUnit: '\u4f4d\u6210\u54e1', waitingHeartbeat: '\u7b49\u5f85 Bot \u5fc3\u8df3', apiFailed: '\u66ab\u6642\u7121\u6cd5\u8b80\u53d6\u72c0\u614b API\uff0c\u8acb\u7a0d\u5f8c\u518d\u8a66\u3002', }; function formatRelativeTime(ms) { if (typeof ms !== 'number' || !Number.isFinite(ms)) return statusText.noHeartbeat; const seconds = Math.max(0, Math.round(ms / 1000)); if (seconds < 60) return `${seconds} ${statusText.secondsAgo}`; const minutes = Math.round(seconds / 60); if (minutes < 60) return `${minutes} ${statusText.minutesAgo}`; const hours = Math.round(minutes / 60); return `${hours} ${statusText.hoursAgo}`; } function setStatusText(selector, text, className) { const element = document.querySelector(selector); if (!element) return; element.textContent = text; element.className = className; } async function updateBotStatus() { if (!statusDashboard) return; try { const response = await fetch('/api/status', { cache: 'no-store' }); if (!response.ok) throw new Error(`HTTP ${response.status}`); const status = await response.json(); const bot = status.bot ?? {}; const online = Boolean(status.online); setStatusText('[data-status-main]', online ? statusText.online : statusText.offline, online ? 'status-ok' : 'status-bad'); setStatusText('[data-status-lavalink]', online && bot.lavalink ? statusText.normal : statusText.abnormal, online && bot.lavalink ? 'status-ok' : 'status-bad'); setStatusText('[data-status-sqlite]', online && bot.sqlite ? statusText.normal : statusText.abnormal, online && bot.sqlite ? 'status-ok' : 'status-bad'); setStatusText('[data-status-meta]', online ? `${bot.pingMs ?? '-'} ms` : statusText.noData, online ? 'status-ok' : 'status-bad'); const lastSeen = document.querySelector('[data-status-last-seen]'); if (lastSeen) lastSeen.textContent = formatRelativeTime(status.ageMs); const meta = document.querySelector('[data-status-meta-text]'); if (meta) meta.textContent = online ? `${bot.guilds ?? 0} ${statusText.guildUnit}\uff0c${bot.users ?? 0} ${statusText.userUnit}` : statusText.waitingHeartbeat; const summary = document.querySelector('#status-summary'); if (summary) { summary.textContent = online ? `Corgi Bot \u76ee\u524d\u5728\u7dda\uff0c\u6700\u5f8c\u5fc3\u8df3 ${formatRelativeTime(status.ageMs)}\u3002` : `Corgi Bot \u76ee\u524d\u96e2\u7dda\u6216\u66ab\u6642\u6536\u4e0d\u5230\u5fc3\u8df3\uff0c\u6700\u5f8c\u66f4\u65b0 ${formatRelativeTime(status.ageMs)}\u3002`; } } catch { setStatusText('[data-status-main]', statusText.unknown, 'status-warn'); setStatusText('[data-status-lavalink]', statusText.unknown, 'status-warn'); setStatusText('[data-status-sqlite]', statusText.unknown, 'status-warn'); setStatusText('[data-status-meta]', statusText.unknown, 'status-warn'); const summary = document.querySelector('#status-summary'); if (summary) summary.textContent = statusText.apiFailed; } } updateBotStatus(); if (statusDashboard) setInterval(updateBotStatus, 30_000);