polish(admin): 抽出后台控件包并统一各页布局与交互
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -9,6 +9,7 @@ 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 = {
|
||||
@@ -39,67 +40,50 @@ export default async function AdminEconomyPage() {
|
||||
);
|
||||
}
|
||||
|
||||
const cards = [
|
||||
{
|
||||
label: "用户余额合计",
|
||||
value: fmt(stats.total_balance),
|
||||
icon: <Coins size={18} />,
|
||||
hint: "全站可用积分之和",
|
||||
},
|
||||
{
|
||||
label: "今日签到",
|
||||
value: fmt(stats.checkin_today),
|
||||
icon: <Flame size={18} />,
|
||||
hint: "今日已签到人数",
|
||||
},
|
||||
{
|
||||
label: "托管中悬赏",
|
||||
value: `${fmt(stats.open_bounties)} / ${fmt(stats.escrowed_points)}`,
|
||||
icon: <Gift size={18} />,
|
||||
hint: "未结算帖数 / 托管积分",
|
||||
},
|
||||
{
|
||||
label: "流水条数",
|
||||
value: fmt(stats.ledger_count),
|
||||
icon: <Layers size={18} />,
|
||||
hint: "历史入账出账记录",
|
||||
},
|
||||
];
|
||||
|
||||
const typeEntries = Object.entries(stats.posts_by_type || {}).sort(
|
||||
(a, b) => b[1] - a[1]
|
||||
);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="mb-6">
|
||||
<h1 className="text-[22px] font-extrabold" style={{ color: "var(--ink)" }}>
|
||||
积分与类型帖看板
|
||||
</h1>
|
||||
<p className="meta text-[13px] mt-1">
|
||||
观察全站积分流通、悬赏托管与帖子类型分布
|
||||
</p>
|
||||
<AdminPageHeader
|
||||
icon={Coins}
|
||||
title="积分与类型帖看板"
|
||||
description="观察全站积分流通、悬赏托管与帖子类型分布"
|
||||
/>
|
||||
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-4 gap-3 mb-5">
|
||||
<AdminStatCard
|
||||
label="用户余额合计"
|
||||
value={fmt(stats.total_balance)}
|
||||
hint="全站可用积分之和"
|
||||
icon={<Coins size={16} />}
|
||||
/>
|
||||
<AdminStatCard
|
||||
label="今日签到"
|
||||
value={fmt(stats.checkin_today)}
|
||||
hint="今日已签到人数"
|
||||
icon={<Flame size={16} />}
|
||||
color="var(--clay)"
|
||||
soft="var(--clay-soft)"
|
||||
/>
|
||||
<AdminStatCard
|
||||
label="托管中悬赏"
|
||||
value={`${fmt(stats.open_bounties)} / ${fmt(stats.escrowed_points)}`}
|
||||
hint="未结算帖数 / 托管积分"
|
||||
icon={<Gift size={16} />}
|
||||
color="var(--gold)"
|
||||
soft="var(--gold-soft)"
|
||||
/>
|
||||
<AdminStatCard
|
||||
label="流水条数"
|
||||
value={fmt(stats.ledger_count)}
|
||||
hint="历史入账出账记录"
|
||||
icon={<Layers size={16} />}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-4 gap-4 mb-6">
|
||||
{cards.map((c) => (
|
||||
<div key={c.label} className="panel p-5">
|
||||
<div className="flex items-center gap-2 meta text-[12.5px]">
|
||||
<span style={{ color: "var(--accent)" }}>{c.icon}</span>
|
||||
{c.label}
|
||||
</div>
|
||||
<p
|
||||
className="mt-3 text-[22px] font-extrabold tabular-nums leading-none"
|
||||
style={{ color: "var(--ink)" }}
|
||||
>
|
||||
{c.value}
|
||||
</p>
|
||||
<p className="meta text-[12px] mt-2">{c.hint}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-5">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
|
||||
<section className="panel overflow-hidden">
|
||||
<div
|
||||
className="px-5 py-3.5 font-medium text-[15px]"
|
||||
@@ -111,11 +95,11 @@ export default async function AdminEconomyPage() {
|
||||
<p className="meta text-center py-10">暂无数据</p>
|
||||
) : (
|
||||
<ul>
|
||||
{typeEntries.map(([t, n]) => (
|
||||
{typeEntries.map(([t, n], idx) => (
|
||||
<li
|
||||
key={t}
|
||||
className="px-5 py-3 flex items-center justify-between"
|
||||
style={{ borderTop: "1px solid var(--line)" }}
|
||||
style={idx === 0 ? undefined : { borderTop: "1px solid var(--line)" }}
|
||||
>
|
||||
<span className="text-[14px]" style={{ color: "var(--ink)" }}>
|
||||
{postTypeLabel(t)}
|
||||
@@ -138,11 +122,11 @@ export default async function AdminEconomyPage() {
|
||||
<p className="meta text-center py-10">暂无流水</p>
|
||||
) : (
|
||||
<ul>
|
||||
{stats.recent_ledger.map((it) => (
|
||||
{stats.recent_ledger.map((it, idx) => (
|
||||
<li
|
||||
key={it.id}
|
||||
className="px-5 py-3 flex items-start justify-between gap-3"
|
||||
style={{ borderTop: "1px solid var(--line)" }}
|
||||
style={idx === 0 ? undefined : { borderTop: "1px solid var(--line)" }}
|
||||
>
|
||||
<div className="min-w-0">
|
||||
<p className="text-[13.5px] truncate" style={{ color: "var(--ink)" }}>
|
||||
|
||||
Reference in New Issue
Block a user