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.
100 lines
2.8 KiB
100 lines
2.8 KiB
"use client";
|
|
|
|
import { useEffect, useState } from "react";
|
|
import Link from "next/link";
|
|
import {
|
|
Warning,
|
|
Users,
|
|
Percent,
|
|
ListMagnifyingGlass,
|
|
} 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 { adminGetAlerts } 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 adminGetAlerts("", token, 1, 1, undefined, "open").then((res) => {
|
|
if (res.code === 0) {
|
|
setOpenAlerts(res.data.total);
|
|
}
|
|
});
|
|
}, [token]);
|
|
|
|
const entries: EntryCard[] = [
|
|
{
|
|
href: "/admin/alerts",
|
|
title: "预警中心",
|
|
desc: "查看查价失败根因与客户地址货物信息",
|
|
icon: Warning,
|
|
badge: openAlerts,
|
|
},
|
|
{
|
|
href: "/admin/queues",
|
|
title: "查价记录",
|
|
desc: "最近询价流水、成功失败与客户查询详情",
|
|
icon: ListMagnifyingGlass,
|
|
},
|
|
{
|
|
href: "/admin/customers",
|
|
title: "客户管理",
|
|
desc: "新增客户、签发 API Key 与状态管理",
|
|
icon: Users,
|
|
},
|
|
{
|
|
href: "/admin/markup",
|
|
title: "加价配置",
|
|
desc: "按客户设置报价加价比例",
|
|
icon: Percent,
|
|
},
|
|
];
|
|
|
|
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>
|
|
);
|
|
}
|