"use client"; import { useEffect, useRef } from "react"; export type SnapshotLite = { cpu_load?: { "1m"?: number; "5m"?: number; "15m"?: number }; disk?: { total?: number; free?: number; used?: number }; memory?: { total?: number; available?: number; free?: number }; }; export default function OverviewCharts({ snapshot, theme, tr, }: { snapshot: SnapshotLite | null; theme: "dark" | "light"; tr: (zh: string, en: string) => string; }) { const ref = useRef(null); useEffect(() => { const el = ref.current; if (!el || !snapshot) return; let disposed = false; let chart: import("echarts").ECharts | null = null; const fg = theme === "light" ? "#0f172a" : "#e2e8f0"; const muted = theme === "light" ? "#64748b" : "#94a3b8"; const gridLine = theme === "light" ? "rgba(15,23,42,0.1)" : "rgba(148,163,184,0.12)"; import("echarts").then((echarts) => { if (disposed || !ref.current) return; chart = echarts.init(ref.current, undefined, { renderer: "canvas" }); const l1 = snapshot.cpu_load?.["1m"] ?? 0; const l5 = snapshot.cpu_load?.["5m"] ?? 0; const l15 = snapshot.cpu_load?.["15m"] ?? 0; const memTotal = snapshot.memory?.total || 1; const memAvail = snapshot.memory?.available ?? snapshot.memory?.free ?? 0; const memUsed = Math.max(0, memTotal - memAvail); const diskTotal = snapshot.disk?.total || 1; const diskFree = snapshot.disk?.free || 0; const diskUsed = Math.max(0, diskTotal - diskFree); chart.setOption({ animationDurationUpdate: 450, textStyle: { color: fg }, title: { text: tr("无人直播节点 · 资源", "Unmanned live · resources"), left: 12, top: 8, textStyle: { color: fg, fontSize: 12, fontWeight: 600 }, }, tooltip: { trigger: "axis" }, grid: { left: 52, right: "48%", top: 52, bottom: 36 }, xAxis: { type: "category", data: ["1m", "5m", "15m"], axisLabel: { color: muted, fontSize: 10 }, axisLine: { lineStyle: { color: gridLine } }, }, yAxis: { type: "value", name: tr("负载", "Load"), nameTextStyle: { color: muted, fontSize: 10 }, axisLabel: { color: muted, fontSize: 10 }, splitLine: { lineStyle: { color: gridLine } }, }, series: [ { name: tr("CPU", "CPU"), type: "bar", data: [l1, l5, l15], barMaxWidth: 28, itemStyle: { borderRadius: [6, 6, 0, 0], color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ { offset: 0, color: "#22d3ee" }, { offset: 1, color: "#6366f1" }, ]), }, }, { name: tr("内存", "RAM"), type: "pie", radius: ["26%", "40%"], center: ["78%", "38%"], label: { color: fg, fontSize: 9 }, data: [ { value: memUsed, name: tr("已用", "Used") }, { value: Math.max(0, memAvail), name: tr("可用", "Free") }, ], }, { name: tr("磁盘", "Disk"), type: "pie", radius: ["20%", "32%"], center: ["78%", "72%"], label: { color: fg, fontSize: 9 }, data: [ { value: diskUsed, name: tr("已用", "Used") }, { value: Math.max(0, diskFree), name: tr("空闲", "Free") }, ], }, ], }); }); const ro = new ResizeObserver(() => chart?.resize()); ro.observe(el); return () => { disposed = true; ro.disconnect(); chart?.dispose(); }; }, [snapshot, theme, tr]); if (!snapshot) return null; return (

{tr("ECharts 动态图表", "ECharts live charts")}

); }