import type { Metadata } from "next"; import Link from "next/link"; import { cookies } from "next/headers"; import { ClipboardCheck, ChevronRight, Eye, FileText, MessageSquareText, LayoutDashboard, Coins, Users, Activity, } from "lucide-react"; import { fetchOverview, fetchAdminPendingCounts, fetchAdminAnalytics, type PendingCounts, type AnalyticsOverview, } from "@/lib/api"; import { authCookieHeader } from "@/lib/cookies"; import { getMeCached } from "@/lib/serverData"; import { canModerateAny, isSuperOrOwner, isAdminOrAbove } from "@/lib/roles"; import { AdminPageHeader, AdminStatCard } from "@/components/admin"; import DashboardClient from "./DashboardClient"; export const metadata: Metadata = { title: "管理仪表盘", }; const fmt = (n: number) => n.toLocaleString("zh-CN"); function greeting(hour: number) { if (hour < 6) return "凌晨好"; if (hour < 12) return "上午好"; if (hour < 14) return "中午好"; if (hour < 18) return "下午好"; return "晚上好"; } /** 紧凑待审条:跳转内容管理待审筛选 */ function PendingStrip({ counts }: { counts: PendingCounts }) { const total = counts.posts + counts.comments; const idle = total === 0; const href = counts.posts > 0 || counts.comments === 0 ? "/admin/content?status=pending" : "/admin/content?status=pending&kind=comments"; return (
待审内容 {idle ? ( 暂无待审 ) : ( {fmt(total)} 项 )} 帖子 {fmt(counts.posts)} 评论 {fmt(counts.comments)}
); } const emptyAnalytics = (): AnalyticsOverview => ({ range_days: 7, today_pv: 0, today_uv: 0, visits: [], posts_series: [], comments_series: [], registers_series: [], boards: [], post_types: [], top_viewed: [], }); export default async function AdminDashboardPage() { const cookie = authCookieHeader(await cookies()); const me = await getMeCached(cookie || undefined); const canMod = canModerateAny(me.user); const canUsers = isSuperOrOwner(me.user?.role); const canEconomy = isAdminOrAbove(me.user?.role); const [overview, pendingCounts, analytics] = await Promise.all([ fetchOverview(cookie).catch(() => null), canMod ? fetchAdminPendingCounts(cookie).catch(() => ({ posts: 0, comments: 0 })) : Promise.resolve(null), fetchAdminAnalytics(cookie, "7d").catch(() => emptyAnalytics()), ]); const now = new Date(); const dateLabel = new Intl.DateTimeFormat("zh-CN", { year: "numeric", month: "long", day: "numeric", weekday: "long", }).format(now); const stats = overview?.stats; const newUsers = overview?.new_users ?? []; return (
积分看板 ) : undefined } />
} /> } color="var(--ok)" soft="var(--ok-soft)" /> } color="var(--gold)" soft="var(--gold-soft)" /> } color="var(--clay)" soft="var(--clay-soft)" />
{canMod && pendingCounts && }
); }