You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

89 lines
2.6 KiB

"use client";
import { useEffect, useState } from "react";
import Link from "next/link";
import { Warning, ChartLine, Robot } from "@phosphor-icons/react";
import { AdminLayout } from "@/components/layout/admin-layout";
import { PageHeader } from "@/components/layout/page-header";
import { Card } from "@/components/ui/card";
import { useAuth } from "@/hooks/use-auth";
import { adminGetMetrics } from "@/lib/frontend/api-client";
interface EntryCard {
href: string;
title: string;
desc: string;
icon: typeof Warning;
badge?: number;
}
export default function DashboardPage() {
const { token } = useAuth();
const [openAlerts, setOpenAlerts] = useState(0);
useEffect(() => {
if (!token) return;
void adminGetMetrics("", token).then((res) => {
if (res.code === 0) {
setOpenAlerts(res.data.open_alerts_count);
}
});
}, [token]);
const entries: EntryCard[] = [
{
href: "/admin/alerts",
title: "预警中心",
desc: "处理 RPA 失败、价格偏差与降级预警",
icon: Warning,
badge: openAlerts,
},
{
href: "/admin/rpa",
title: "RPA 状态",
desc: "查看 Worker 在线状态、队列深度与熔断",
icon: Robot,
},
{
href: "/admin/dashboard",
title: "指标看板",
desc: "API/RPA 成功率、缓存命中率与 P95 延迟",
icon: ChartLine,
},
];
return (
<AdminLayout>
<PageHeader
title="工作台"
subtitle="管理员快捷入口"
/>
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
{entries.map((entry) => {
const Icon = entry.icon;
return (
<Link key={entry.href} href={entry.href}>
<Card className="cursor-pointer transition-shadow hover:shadow-modal">
<div className="flex items-start justify-between">
<div className="flex h-11 w-11 items-center justify-center rounded-md bg-primary/10 text-primary">
<Icon size={24} weight="fill" />
</div>
{entry.badge ? (
<span className="rounded-sm bg-error/10 px-2 py-0.5 text-xs text-error">
{entry.badge}
</span>
) : null}
</div>
<h3 className="mt-4 text-lg font-semibold text-text-primary">
{entry.title}
</h3>
<p className="mt-1 text-sm text-text-secondary">{entry.desc}</p>
</Card>
</Link>
);
})}
</div>
</AdminLayout>
);
}