import type { Metadata } from "next"; import Link from "next/link"; import { cookies } from "next/headers"; import { Coins, Flame, Gift, Layers } from "lucide-react"; import { fetchAdminEconomyStats } from "@/lib/api"; import { authCookieHeader } from "@/lib/cookies"; import { getMeCached } from "@/lib/serverData"; import { isAdminOrAbove } from "@/lib/roles"; import { postTypeLabel } from "@/lib/postMeta"; import { pointReasonLabel } from "@/lib/points"; import { formatRelative } from "@/lib/format"; import { AdminPageHeader, AdminStatCard } from "@/components/admin"; import Forbidden from "../Forbidden"; export const metadata: Metadata = { title: "积分看板", }; const fmt = (n: number) => n.toLocaleString("zh-CN"); export default async function AdminEconomyPage() { const cookie = authCookieHeader(await cookies()); const me = await getMeCached(cookie || undefined); if (!me.user || !isAdminOrAbove(me.user.role)) { return ; } let stats: Awaited> | null = null; try { stats = await fetchAdminEconomyStats(cookie); } catch { stats = null; } if (!stats) { return ( 暂时无法加载积分数据 ); } const typeEntries = Object.entries(stats.posts_by_type || {}).sort( (a, b) => b[1] - a[1] ); return ( } /> } color="var(--clay)" soft="var(--clay-soft)" /> } color="var(--gold)" soft="var(--gold-soft)" /> } /> 帖子类型分布 {typeEntries.length === 0 ? ( 暂无数据 ) : ( {typeEntries.map(([t, n], idx) => ( {postTypeLabel(t)} {fmt(n)} ))} )} 最近流水 {(stats.recent_ledger || []).length === 0 ? ( 暂无流水 ) : ( {stats.recent_ledger.map((it, idx) => ( {pointReasonLabel(it.reason)} {it.note ? ` · ${it.note}` : ""} {formatRelative(it.created_at)} = 0 ? "var(--accent)" : "var(--danger)" }} > {it.delta >= 0 ? `+${it.delta}` : it.delta} ))} )} 用户可在{" "} /points {" "} 查看个人流水。 ); }
暂时无法加载积分数据
暂无数据
暂无流水
{pointReasonLabel(it.reason)} {it.note ? ` · ${it.note}` : ""}
{formatRelative(it.created_at)}
用户可在{" "} /points {" "} 查看个人流水。