/** * 运维控制面板页面 * * 功能: * - 服务器系统资源概况(CPU / 内存 / 磁盘) * - 各环境服务状态 + 启停重启按钮 * - 各环境 Git 状态 + pull / 同步依赖按钮 * - 各环境 .env 配置查看(敏感值脱敏) */ import React, { useEffect, useState, useCallback } from "react"; import { Card, Row, Col, Tag, Button, Space, Statistic, Progress, Modal, message, Descriptions, Spin, Tooltip, Typography, Input, } from "antd"; import { PlayCircleOutlined, PauseCircleOutlined, ReloadOutlined, CloudDownloadOutlined, SyncOutlined, FileTextOutlined, CheckCircleOutlined, CloseCircleOutlined, ClockCircleOutlined, DesktopOutlined, } from "@ant-design/icons"; import type { SystemInfo, ServiceStatus, GitInfo, } from "../api/opsPanel"; import { fetchSystemInfo, fetchServicesStatus, fetchGitInfo, startService, stopService, restartService, gitPull, syncDeps, fetchEnvFile, } from "../api/opsPanel"; const { Text, Title } = Typography; const { TextArea } = Input; /* ------------------------------------------------------------------ */ /* 工具函数 */ /* ------------------------------------------------------------------ */ /** 秒数格式化为 "Xd Xh Xm" */ function formatUptime(seconds: number | null): string { if (seconds == null) return "-"; const d = Math.floor(seconds / 86400); const h = Math.floor((seconds % 86400) / 3600); const m = Math.floor((seconds % 3600) / 60); const parts: string[] = []; if (d > 0) parts.push(`${d}天`); if (h > 0) parts.push(`${h}时`); parts.push(`${m}分`); return parts.join(" "); } /* ------------------------------------------------------------------ */ /* 组件 */ /* ------------------------------------------------------------------ */ const OpsPanel: React.FC = () => { const [system, setSystem] = useState(null); const [services, setServices] = useState([]); const [gitInfos, setGitInfos] = useState([]); const [loading, setLoading] = useState(true); const [actionLoading, setActionLoading] = useState>({}); const [envModalOpen, setEnvModalOpen] = useState(false); const [envModalContent, setEnvModalContent] = useState(""); const [envModalTitle, setEnvModalTitle] = useState(""); // ---- 数据加载 ---- const loadAll = useCallback(async () => { try { const [sys, svc, git] = await Promise.all([ fetchSystemInfo(), fetchServicesStatus(), fetchGitInfo(), ]); setSystem(sys); setServices(svc); setGitInfos(git); } catch { message.error("加载运维数据失败"); } finally { setLoading(false); } }, []); useEffect(() => { loadAll(); const timer = setInterval(loadAll, 15_000); return () => clearInterval(timer); }, [loadAll]); // ---- 操作处理 ---- const withAction = async (key: string, fn: () => Promise) => { setActionLoading((prev) => ({ ...prev, [key]: true })); try { await fn(); } finally { setActionLoading((prev) => ({ ...prev, [key]: false })); } }; const handleStart = (env: string) => withAction(`start-${env}`, async () => { const r = await startService(env); r.success ? message.success(r.message) : message.warning(r.message); await loadAll(); }); const handleStop = (env: string) => withAction(`stop-${env}`, async () => { const r = await stopService(env); r.success ? message.success(r.message) : message.warning(r.message); await loadAll(); }); const handleRestart = (env: string) => withAction(`restart-${env}`, async () => { const r = await restartService(env); r.success ? message.success(r.message) : message.warning(r.message); await loadAll(); }); const handlePull = (env: string) => withAction(`pull-${env}`, async () => { const r = await gitPull(env); if (r.success) { message.success("拉取成功"); Modal.info({ title: `Git Pull - ${env}`, content:
{r.output}
, width: 600 }); } else { message.error("拉取失败"); Modal.error({ title: `Git Pull 失败 - ${env}`, content:
{r.output}
, width: 600 }); } await loadAll(); }); const handleSyncDeps = (env: string) => withAction(`sync-${env}`, async () => { const r = await syncDeps(env); r.success ? message.success("依赖同步完成") : message.error(r.message); }); const handleViewEnv = async (env: string, label: string) => { try { const r = await fetchEnvFile(env); setEnvModalTitle(`${label} .env 配置`); setEnvModalContent(r.content); setEnvModalOpen(true); } catch { message.error("读取配置文件失败"); } }; // ---- 渲染 ---- if (loading) { return ; } return (
<DesktopOutlined style={{ marginRight: 8 }} /> 运维控制面板 {/* ---- 系统资源 ---- */} {system && ( 80 ? "exception" : "normal"} showInfo={false} /> 85 ? "exception" : "normal"} showInfo={false} /> 90 ? "exception" : "normal"} showInfo={false} /> 开机时间:{new Date(system.boot_time).toLocaleString()} )} {/* ---- 服务状态 ---- */} {services.map((svc) => ( {svc.running ? : } {svc.label} {svc.running ? "运行中" : "已停止"} } extra={:{svc.port}} > {svc.running && ( {svc.pid} {formatUptime(svc.uptime_seconds)} {svc.memory_mb ?? "-"} MB )} {!svc.running && ( )} {svc.running && ( <> )} ))} {/* ---- Git 状态 & 配置 ---- */} {gitInfos.map((git) => { const envCfg = services.find((s) => s.env === git.env); const label = envCfg?.label ?? git.env; return ( {git.branch} {git.has_local_changes && ( 有变更 )} {git.last_commit_hash} {git.last_commit_message} {git.last_commit_time} ); })} {/* ---- 配置查看弹窗 ---- */} setEnvModalOpen(false)} footer={null} width={700} >