diff --git a/frontend/app/server/page.tsx b/frontend/app/server/page.tsx index 4505695..2510aa8 100644 --- a/frontend/app/server/page.tsx +++ b/frontend/app/server/page.tsx @@ -35,7 +35,7 @@ interface ServerStatus { function bjtStr(ms: number) { const d = new Date(ms + 8 * 3600 * 1000); - return `${d.getUTCFullYear()}-${String(d.getUTCMonth()+1).padStart(2,"0")}-${String(d.getUTCDate()).padStart(2,"0")} ${String(d.getUTCHours()).padStart(2,"0")}:${String(d.getUTCMinutes()).padStart(2,"0")}:${String(d.getUTCSeconds()).padStart(2,"0")}`; + return `${String(d.getUTCMonth()+1).padStart(2,"0")}-${String(d.getUTCDate()).padStart(2,"0")} ${String(d.getUTCHours()).padStart(2,"0")}:${String(d.getUTCMinutes()).padStart(2,"0")}`; } function uptimeStr(ms: number) { @@ -49,34 +49,23 @@ function uptimeStr(ms: number) { return `${m}m`; } -function ProgressBar({ percent, color = "cyan" }: { percent: number; color?: string }) { - const colorClass = percent > 90 ? "bg-red-500" : percent > 70 ? "bg-amber-500" : color === "cyan" ? "bg-cyan-500" : "bg-emerald-500"; +function ProgressBar({ percent }: { percent: number }) { + const color = percent > 90 ? "bg-red-500" : percent > 70 ? "bg-amber-500" : "bg-blue-500"; return ( -
-
+
+
); } -function StatusBadge({ status }: { status: string }) { - const isOnline = status === "online"; - return ( - - - {status} - - ); -} - function numberFmt(n: number) { return n.toLocaleString("en-US"); } export default function ServerPage() { - const { isLoggedIn, accessToken } = useAuth(); + const { isLoggedIn } = useAuth(); const [data, setData] = useState(null); const [loading, setLoading] = useState(true); - const [lastUpdate, setLastUpdate] = useState(0); const fetchData = useCallback(async () => { try { @@ -84,7 +73,6 @@ export default function ServerPage() { if (!res.ok) return; const json = await res.json(); setData(json); - setLastUpdate(Date.now()); } catch (e) { // ignore } finally { @@ -95,192 +83,197 @@ export default function ServerPage() { useEffect(() => { if (!isLoggedIn) return; fetchData(); - const iv = setInterval(fetchData, 10000); // 10秒刷新 + const iv = setInterval(fetchData, 10000); return () => clearInterval(iv); }, [isLoggedIn, fetchData]); if (!isLoggedIn) { return ( -
-
-

请先登录

- 登录 +
+

请先登录查看服务器状态

+
+ 登录 + 注册
); } return ( -
- {/* 顶栏 */} -
-
-
- ← 返回 -

🖥️ 服务器监控

- GCP asia-northeast1-b -
-
- {data?.backfill_running && ( - - - 回补运行中 - - )} - 每10秒刷新 - {lastUpdate > 0 && · 更新于 {bjtStr(lastUpdate)}} -
+
+ {/* 标题 */} +
+
+

服务器监控

+

GCP asia-northeast1-b · 每10秒自动刷新

-
+ {data?.backfill_running && ( + + + 回补运行中 + + )} +
-
- {loading ? ( -
加载中...
- ) : !data ? ( -
获取失败
- ) : ( - <> - {/* 系统概览 4卡片 */} -
- {/* CPU */} -
-
- CPU - {data.cpu.cores} 核 -
-
{data.cpu.percent}%
- -
- 负载: {data.load.load1} / {data.load.load5} / {data.load.load15} -
-
- - {/* 内存 */} -
-
- 内存 - {data.memory.used_gb}G / {data.memory.total_gb}G -
-
{data.memory.percent}%
- - {data.memory.swap_percent > 0 && ( -
Swap: {data.memory.swap_percent}%
- )} -
- - {/* 硬盘 */} -
-
- 硬盘 - {data.disk.free_gb}G 可用 -
-
{data.disk.percent}%
- -
- {data.disk.used_gb}G / {data.disk.total_gb}G -
-
- - {/* 运行时间 & 网络 */} -
-
- 系统 - Uptime -
-
- {data.uptime_hours > 24 ? `${Math.floor(data.uptime_hours/24)}天` : `${data.uptime_hours}h`} -
-
-
↑ 发送: {data.network.bytes_sent_gb} GB
-
↓ 接收: {data.network.bytes_recv_gb} GB
-
+ {loading ? ( +
加载中...
+ ) : !data ? ( +
获取失败
+ ) : ( + <> + {/* 系统概览 4卡片 */} +
+ {/* CPU */} +
+
+ CPU + {data.cpu.cores} 核
+
{data.cpu.percent}%
+ +

+ 负载 {data.load.load1} / {data.load.load5} / {data.load.load15} +

- {/* PM2 进程列表 */} -
-
-

📦 PM2 进程

+ {/* 内存 */} +
+
+ 内存 + {data.memory.used_gb}G / {data.memory.total_gb}G
-
- - - - - - - - - - - - - - {data.pm2.map((p, i) => ( - - - - - - - - - - ))} - -
名称状态CPU内存重启运行时间PID
{p.name}{p.cpu}%{p.memory_mb} MB{p.restarts}{uptimeStr(p.uptime_ms)}{p.pid || "-"}
-
-
- - {/* 数据库信息 */} -
-
-

🗄️ PostgreSQL

-
-
-
-
数据库大小
-
- {data.postgres.db_size_mb > 1024 - ? `${(data.postgres.db_size_mb / 1024).toFixed(1)} GB` - : `${data.postgres.db_size_mb} MB`} -
-
-
-
aggTrades 总条数
-
{numberFmt(data.postgres.agg_trades_count)}
-
-
-
费率快照
-
{numberFmt(data.postgres.rate_snapshots_count)}
-
-
-
回补状态
-
- {data.backfill_running ? "🔄 运行中" : "⏸ 停止"} -
-
-
- {data.postgres.symbols && Object.keys(data.postgres.symbols).length > 0 && ( -
-
数据覆盖范围
-
- {Object.entries(data.postgres.symbols).map(([sym, info]) => ( -
- {sym} -
-
{bjtStr(info.earliest_ms)} → {bjtStr(info.latest_ms)}
-
{info.span_hours > 24 ? `${(info.span_hours/24).toFixed(1)} 天` : `${info.span_hours.toFixed(1)} 小时`}
-
-
- ))} -
-
+
{data.memory.percent}%
+ + {data.memory.swap_percent > 0 && ( +

Swap {data.memory.swap_percent}%

)}
- - )} -
+ + {/* 硬盘 */} +
+
+ 硬盘 + {data.disk.free_gb}G 可用 +
+
{data.disk.percent}%
+ +

{data.disk.used_gb}G / {data.disk.total_gb}G

+
+ + {/* 运行时间 & 网络 */} +
+
+ 系统 +
+
+ {data.uptime_hours > 24 ? `${Math.floor(data.uptime_hours/24)}天` : `${data.uptime_hours}h`} +
+
+

↑ 发送 {data.network.bytes_sent_gb} GB

+

↓ 接收 {data.network.bytes_recv_gb} GB

+
+
+
+ + {/* PM2 进程 */} +
+
+

PM2 进程

+
+
+ + + + + + + + + + + + + {data.pm2.map((p, i) => ( + + + + + + + + + ))} + +
名称状态CPU内存重启运行时间
{p.name} + + + {p.status} + + {p.cpu}%{p.memory_mb} MB{p.restarts}{uptimeStr(p.uptime_ms)}
+
+
+ + {/* PostgreSQL */} +
+
+

PostgreSQL

+
+
+
+

数据库大小

+

+ {data.postgres.db_size_mb > 1024 + ? `${(data.postgres.db_size_mb / 1024).toFixed(1)} GB` + : `${data.postgres.db_size_mb} MB`} +

+
+
+

aggTrades

+

{numberFmt(data.postgres.agg_trades_count)}

+
+
+

费率快照

+

{numberFmt(data.postgres.rate_snapshots_count)}

+
+
+

回补状态

+

+ {data.backfill_running ? "运行中" : "已停止"} +

+
+
+ + {/* 数据覆盖范围 */} + {data.postgres.symbols && Object.keys(data.postgres.symbols).length > 0 && ( +
+

数据覆盖范围

+
+ {Object.entries(data.postgres.symbols).map(([sym, info]) => ( +
+ {sym} +
+

{bjtStr(info.earliest_ms)} → {bjtStr(info.latest_ms)}

+

+ {info.span_hours > 24 ? `${(info.span_hours/24).toFixed(1)} 天` : `${info.span_hours.toFixed(1)} 小时`} +

+
+
+ ))} +
+
+ )} +
+ + {/* 说明 */} +
+ 说明:数据每10秒自动刷新。PM2进程状态实时反映服务运行情况,回补运行中时CPU和网络负载会偏高属正常现象。 +
+ + )}
); }