import ServerFlag from "@/components/ServerFlag" import ServerUsageBar from "@/components/ServerUsageBar" import { formatBytes } from "@/lib/format" import { GetFontLogoClass, GetOsName, MageMicrosoftWindows } from "@/lib/logo-class" import { cn, formatNezhaInfo, parsePublicNote } from "@/lib/utils" import { CycleTransferData, NezhaServer } from "@/types/nezha-api" import { useTranslation } from "react-i18next" import { useNavigate } from "react-router-dom" import PlanInfo from "./PlanInfo" import BillingInfo from "./billingInfo" import { Badge } from "./ui/badge" import { Card, CardContent, CardHeader, CardFooter } from "./ui/card" import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "./ui/tooltip" import { ArrowDown, ArrowUp, Clock, Cpu, HardDrive, Server, Activity, BarChart3, Calendar } from "lucide-react" interface ServerCardProps { now: number; serverInfo: NezhaServer; cycleStats?: { [key: string]: CycleTransferData }; } export default function ServerCard({ now, serverInfo, cycleStats }: ServerCardProps) { const { t } = useTranslation() const navigate = useNavigate() const { name, country_code, online, cpu, up, down, mem, stg, net_in_transfer, net_out_transfer, public_note, platform, cpu_info, mem_total, disk_total, tcp, udp, process, uptime, last_active_time_string } = formatNezhaInfo( now, serverInfo, ) const cardClick = () => { sessionStorage.setItem("fromMainPage", "true") navigate(`/server/${serverInfo.id}`) } const showFlag = true const customBackgroundImage = (window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined // @ts-expect-error ShowNetTransfer is a global variable const showNetTransfer = window.ShowNetTransfer as boolean // @ts-expect-error ShowServerDetails is a global variable const showServerDetails = window.ShowServerDetails !== undefined ? window.ShowServerDetails as boolean : true const parsedData = parsePublicNote(public_note) // 获取匹配当前服务器的流量计费周期 const getServerCycleData = () => { if (!cycleStats) { return null; } // 确保服务器ID的所有可能形式 const serverId = String(serverInfo.id); const serverIdNum = Number(serverInfo.id); const matchedCycles: Array<{ name: string; from: string; to: string; max: number; transfer: number; nextUpdate: string; progress: number; }> = [] // 遍历所有流量周期,查找匹配当前服务器ID的数据 Object.values(cycleStats).forEach((cycleData) => { if (!cycleData.server_name) { return; } const serverIdsInCycle = Object.keys(cycleData.server_name); // 检查各种可能的ID形式 let matchedId = null; // 1. 直接匹配字符串ID if (serverIdsInCycle.includes(serverId)) { matchedId = serverId; } // 2. 尝试匹配数字ID (如果API返回的是数字ID) else if (serverIdsInCycle.includes(String(serverIdNum))) { matchedId = String(serverIdNum); } // 3. 通过名称匹配 else { // 检查名称是否匹配 const serverNames = Object.entries(cycleData.server_name); for (const [id, name] of serverNames) { if (name === serverInfo.name) { matchedId = id; break; } } // 如果还没匹配,尝试循环比较所有ID if (!matchedId) { for (const id of serverIdsInCycle) { if (Number(id) === serverIdNum) { matchedId = id; break; } } } } // 如果找到匹配的ID,且有对应的传输数据 if (matchedId && cycleData.transfer && cycleData.transfer[matchedId] !== undefined) { const transfer = cycleData.transfer[matchedId]; const progress = (transfer / cycleData.max) * 100; matchedCycles.push({ name: cycleData.name, from: cycleData.from, to: cycleData.to, max: cycleData.max, transfer: transfer, nextUpdate: cycleData.next_update?.[matchedId] || "", progress: progress }); } }); return matchedCycles.length > 0 ? matchedCycles : null; } const serverCycleData = getServerCycleData() // 格式化运行时间 const formatUptime = (seconds: number, t: any) => { if (seconds >= 86400) { return `${Math.floor(seconds / 86400)} ${t("serverCard.days")}` } else { return `${Math.floor(seconds / 3600)} ${t("serverCard.hours")}` } } // 格式化网络速度 const formatSpeed = (speed: number) => { return speed >= 1024 ? `${(speed / 1024).toFixed(2)}G/s` : speed >= 1 ? `${speed.toFixed(2)}M/s` : `${(speed * 1024).toFixed(2)}K/s` } // 获取颜色等级 const getColorClass = (value: number) => { if (value > 90) return "text-red-500" if (value > 70) return "text-orange-400" return "text-green-500" } // 根据进度获取状态颜色 const getProgressColorClass = (value: number) => { if (value > 90) return "bg-red-500" if (value > 70) return "bg-orange-500" return "bg-emerald-500" } // 格式化大数值,超过1000显示为k格式 const formatLargeNumber = (num: number) => { if (num >= 10000) { return `${Math.floor(num / 1000)}k+` } else if (num >= 1000) { return `${(num / 1000).toFixed(1)}k` } return num.toString() } if (!online) { return (
{showFlag && }

{name}

{parsedData?.billingDataMod && (
)} {parsedData?.planDataMod && (
)}
{/* 添加流量使用统计 */} {serverCycleData && serverCycleData.length > 0 && (
{serverCycleData.map((cycle, index) => (
{cycle.name}
{new Date(cycle.from).toLocaleDateString()} - {new Date(cycle.to).toLocaleDateString()}
{formatBytes(cycle.transfer)} / {formatBytes(cycle.max)}
{cycle.progress.toFixed(1)}%
{cycle.nextUpdate && (
{t("cycleTransfer.nextUpdate")}: {new Date(cycle.nextUpdate).toLocaleTimeString()}
)}
))}
)} ) } return (
{showFlag && }

{name}

{platform.includes("Windows") ? ( ) : ( )} {platform.includes("Windows") ? "Windows" : GetOsName(platform)}
{parsedData?.billingDataMod && (
)}
{uptime > 0 && (
{formatUptime(uptime, t)}
)} {last_active_time_string && (
{last_active_time_string}
)}
{/* 流量使用统计 */} {serverCycleData && serverCycleData.length > 0 && (
{serverCycleData.map((cycle, index) => (
{cycle.name}
{cycle.progress.toFixed(1)}%
{formatBytes(cycle.transfer)} / {formatBytes(cycle.max)}
{new Date(cycle.from).toLocaleDateString()} - {new Date(cycle.to).toLocaleDateString()} {cycle.nextUpdate && ( {t("cycleTransfer.nextUpdate")}: {new Date(cycle.nextUpdate).toLocaleTimeString()} )}
))}
)} {/* 主要资源使用情况 - 全新设计 */}
{/* CPU使用率 */}
CPU
{cpu.toFixed(0)}%
{/* 内存使用率 */}
{t("serverCard.mem")}
{mem.toFixed(0)}%
{/* 存储使用率 */}
{t("serverCard.stg")}
{stg.toFixed(0)}%
{/* 网络使用情况 */}
{/* 网络速率 */}
{t("serverCard.upload")}
{formatSpeed(up)}
{t("serverCard.download")}
{formatSpeed(down)}
{/* 连接数与进程数 */}
T: {formatLargeNumber(tcp)}
U: {formatLargeNumber(udp)}
P: {formatLargeNumber(process)}
{/* 服务器详细信息区域 */} {showServerDetails && (
{/* CPU信息 */} {cpu_info && cpu_info.length > 0 && ( {cpu_info[0].includes("Physical") ? "pCPU: " : "vCPU: "} {cpu_info[0].match(/(\d+)\s+(?:Physical|Virtual)\s+Core/)?.[1] || "-"} {cpu_info.join(", ")} )} {/* 内存大小 */} {mem_total > 0 ? ( RAM: {formatBytes(mem_total)} ) : ( RAM: - )} {/* 存储大小 */} {disk_total > 0 ? ( DISK: {formatBytes(disk_total)} ) : ( DISK: - )}
)} {/* 套餐信息 */} {parsedData?.planDataMod && (
)} {/* 网络传输信息 */} {showNetTransfer && (
{t("serverCard.upload")}
{formatBytes(net_out_transfer)}
{t("serverCard.download")}
{formatBytes(net_in_transfer)}
)}
{/* 视觉元素:左侧状态条 */} ) }