更新 ServerCard 组件,增加分组名称的显示功能,优化布局以提升信息展示的清晰度和可读性。同时在 Server 页面中查找服务器所属的分组并传递相关信息。

This commit is contained in:
wood chen 2025-04-29 02:34:46 +08:00
parent 8eec93aff4
commit 06f2e04ba8
2 changed files with 40 additions and 23 deletions

View File

@ -11,7 +11,7 @@ import PlanInfo from "./PlanInfo"
import BillingInfo from "./billingInfo" import BillingInfo from "./billingInfo"
import { Card, CardContent, CardHeader, CardFooter } from "./ui/card" import { Card, CardContent, CardHeader, CardFooter } from "./ui/card"
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "./ui/tooltip" import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "./ui/tooltip"
import { ArrowDown, ArrowUp, Clock, Cpu, HardDrive, Server, Activity, BarChart3, Calendar } from "lucide-react" import { ArrowDown, ArrowUp, Clock, Cpu, HardDrive, Server, Activity, BarChart3 } from "lucide-react"
interface ServerCardProps { interface ServerCardProps {
now: number; now: number;
@ -19,9 +19,10 @@ interface ServerCardProps {
cycleStats?: { cycleStats?: {
[key: string]: CycleTransferData [key: string]: CycleTransferData
}; };
groupName?: string;
} }
export default function ServerCard({ now, serverInfo, cycleStats }: ServerCardProps) { export default function ServerCard({ now, serverInfo, cycleStats, groupName }: ServerCardProps) {
const { t } = useTranslation() const { t } = useTranslation()
const navigate = useNavigate() const navigate = useNavigate()
const { const {
@ -44,7 +45,6 @@ export default function ServerCard({ now, serverInfo, cycleStats }: ServerCardPr
udp, udp,
process, process,
uptime, uptime,
last_active_time_string,
arch, arch,
swap, swap,
swap_total swap_total
@ -201,7 +201,17 @@ export default function ServerCard({ now, serverInfo, cycleStats }: ServerCardPr
onClick={cardClick} onClick={cardClick}
> >
<div className="absolute top-0 left-0 w-1 h-full bg-red-500 rounded-l-md"></div> <div className="absolute top-0 left-0 w-1 h-full bg-red-500 rounded-l-md"></div>
<CardContent className="p-4">
{/* 离线卡片的分组标签 */}
{groupName && (
<div className="absolute top-2 right-2">
<div className="px-1.5 py-0.5 text-[10px] font-medium bg-red-100 text-red-700 dark:bg-red-900/40 dark:text-red-400 rounded-sm border border-red-200 dark:border-red-800">
{groupName}
</div>
</div>
)}
<CardContent className="p-4 pt-6">
<div className="flex items-center gap-3 mb-2"> <div className="flex items-center gap-3 mb-2">
<span className="h-3 w-3 shrink-0 rounded-full bg-red-500 shadow-sm pulse-animation shadow-red-300 dark:shadow-red-900"></span> <span className="h-3 w-3 shrink-0 rounded-full bg-red-500 shadow-sm pulse-animation shadow-red-300 dark:shadow-red-900"></span>
{showFlag && <ServerFlag country_code={country_code} />} {showFlag && <ServerFlag country_code={country_code} />}
@ -272,14 +282,20 @@ export default function ServerCard({ now, serverInfo, cycleStats }: ServerCardPr
)} )}
onClick={cardClick} onClick={cardClick}
> >
{/* 左侧状态条 */}
<div className="absolute top-0 left-0 w-1 h-full bg-green-500 rounded-l-md"></div> <div className="absolute top-0 left-0 w-1 h-full bg-green-500 rounded-l-md"></div>
<CardHeader className="p-4 pb-2"> <CardHeader className="p-4 pb-2 pt-2">
<div className="flex justify-between"> <div className="flex justify-between">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<span className="h-3 w-3 shrink-0 rounded-full bg-green-500 shadow-sm shadow-green-300 dark:shadow-green-900 animate-pulse"></span> <span className="h-3 w-3 shrink-0 rounded-full bg-green-500 shadow-sm shadow-green-300 dark:shadow-green-900 animate-pulse"></span>
{showFlag && <ServerFlag country_code={country_code} />} {showFlag && <ServerFlag country_code={country_code} />}
<h3 className="font-bold text-sm truncate">{name}</h3> <h3 className="font-bold text-sm truncate">{name}</h3>
{groupName && (
<div className="px-1.5 py-0.5 text-[10px] font-medium bg-green-100 text-green-700 dark:bg-green-900/40 dark:text-green-400 rounded-sm border border-green-200 dark:border-green-800">
{groupName}
</div>
)}
</div> </div>
<div className="flex items-center text-xs gap-2 text-muted-foreground"> <div className="flex items-center text-xs gap-2 text-muted-foreground">
@ -308,13 +324,6 @@ export default function ServerCard({ now, serverInfo, cycleStats }: ServerCardPr
<span>{formatUptime(uptime, t)}</span> <span>{formatUptime(uptime, t)}</span>
</div> </div>
)} )}
{last_active_time_string && (
<div className="flex items-center text-xs text-muted-foreground">
<Calendar className="size-[12px] mr-1" />
<span>{last_active_time_string}</span>
</div>
)}
</div> </div>
</div> </div>
</CardHeader> </CardHeader>
@ -434,8 +443,8 @@ export default function ServerCard({ now, serverInfo, cycleStats }: ServerCardPr
<Tooltip> <Tooltip>
<TooltipTrigger asChild> <TooltipTrigger asChild>
<div className={cn("bg-indigo-500/10 text-indigo-600 dark:text-indigo-400 rounded px-1.5 py-0.5 text-center", <div className={cn("bg-indigo-500/10 text-indigo-600 dark:text-indigo-400 rounded px-1.5 py-0.5 text-center",
Number(swap) > 90 ? "bg-red-500/10 text-red-600 dark:text-red-400" : Number(swap) > 90 ? "bg-red-500/10 text-red-600 dark:text-red-400" :
Number(swap) > 70 ? "bg-orange-500/10 text-orange-600 dark:text-orange-400" : "")}> Number(swap) > 70 ? "bg-orange-500/10 text-orange-600 dark:text-orange-400" : "")}>
SWAP:{swap.toFixed(0)}% SWAP:{swap.toFixed(0)}%
</div> </div>
</TooltipTrigger> </TooltipTrigger>
@ -453,7 +462,7 @@ export default function ServerCard({ now, serverInfo, cycleStats }: ServerCardPr
</TooltipContent> </TooltipContent>
</Tooltip> </Tooltip>
</TooltipProvider> </TooltipProvider>
):( ) : (
<div className="bg-amber-500/10 text-amber-600 dark:text-amber-400 rounded px-1.5 py-0.5 text-center"> <div className="bg-amber-500/10 text-amber-600 dark:text-amber-400 rounded px-1.5 py-0.5 text-center">
- -
</div> </div>

View File

@ -335,14 +335,22 @@ export default function Servers() {
{showMap === "1" && <GlobalMap now={nezhaWsData.now} serverList={nezhaWsData?.servers || []} />} {showMap === "1" && <GlobalMap now={nezhaWsData.now} serverList={nezhaWsData?.servers || []} />}
{showServices === "1" && <ServiceTracker serverList={filteredServers} />} {showServices === "1" && <ServiceTracker serverList={filteredServers} />}
<section ref={containerRef} className="grid grid-cols-1 gap-4 md:grid-cols-3 mt-6 server-card-list"> <section ref={containerRef} className="grid grid-cols-1 gap-4 md:grid-cols-3 mt-6 server-card-list">
{filteredServers.map((serverInfo) => ( {filteredServers.map((serverInfo) => {
<ServerCard // 查找服务器所属的分组
now={nezhaWsData.now} const serverGroup = groupData?.data?.find(
key={serverInfo.id} (g: ServerGroup) => Array.isArray(g.servers) && g.servers.includes(serverInfo.id)
serverInfo={serverInfo} );
cycleStats={cycleTransferStats}
/> return (
))} <ServerCard
now={nezhaWsData.now}
key={serverInfo.id}
serverInfo={serverInfo}
cycleStats={cycleTransferStats}
groupName={serverGroup?.group.name}
/>
);
})}
</section> </section>
</div> </div>
) )