refactor(admin): drop duplicate users card, full-width panels, demo rebuild copy matches new dataset

This commit is contained in:
root
2026-10-17 17:04:38 +08:00
parent 0fdba1944e
commit 265edc9009
+7 -26
View File
@@ -9,9 +9,10 @@ import {
import { Badge, Button, Card, CardBody, CardHeader, Dialog, Empty, Input, useToast } from '@/components/ui';
import { fmtDateTime, fmtSize } from '@/lib/format';
type Filter = 'all' | 'valid' | 'used' | 'disabled';
type Filter = 'all' | 'valid' | 'used' | 'gone' | 'disabled';
function InviteStatus({ i }: { i: InviteRow }) {
if (i.used_by && i.holder_gone) return <Badge color="var(--danger)">已销户</Badge>;
if (i.used_by) return <Badge color="var(--text-3)">已使用</Badge>;
return i.valid ? <Badge color="var(--success)">可用</Badge> : <Badge color="var(--warning)">已停用</Badge>;
}
@@ -86,10 +87,10 @@ export function AdminPage() {
});
const invites = useMemo(() => invitesQ.data?.invites ?? [], [invitesQ.data]);
const users = usersQ.data?.users ?? [];
const filtered = useMemo(() => invites.filter((i) => {
if (filter === 'valid') return i.valid && !i.used_by;
if (filter === 'used') return !!i.used_by;
if (filter === 'used') return !!i.used_by && !i.holder_gone;
if (filter === 'gone') return !!i.used_by && !!i.holder_gone;
if (filter === 'disabled') return !i.valid && !i.used_by;
return true;
}), [invites, filter]);
@@ -158,7 +159,7 @@ export function AdminPage() {
</CardBody>
</Card>
<div className="grid grid-cols-1 gap-4 lg:grid-cols-2">
<Card>
<CardHeader title={'邀请码(' + (invitesQ.data?.total ?? 0) + ')'} extra={
<div className="flex gap-1.5">
@@ -193,7 +194,7 @@ export function AdminPage() {
)}
<div className="flex gap-1 border-b border-line px-4 py-2 text-[12px]">
{([['all', '全部'], ['valid', '可用'], ['used', '已使用'], ['disabled', '已停用']] as [Filter, string][]).map(([k, label]) => (
{([['all', '全部'], ['valid', '可用'], ['used', '已使用'], ['gone', '已销户'], ['disabled', '已停用']] as [Filter, string][]).map(([k, label]) => (
<button key={k}
className={'rounded-md px-2.5 py-1 transition-colors ' + (filter === k ? 'bg-brand-subtle font-medium text-brand-text' : 'text-ink-3 hover:bg-surface-3')}
onClick={() => setFilter(k)}>{label}</button>
@@ -275,26 +276,6 @@ export function AdminPage() {
)}
</CardBody>
</Card>
<Card>
<CardHeader title={'用户(' + (usersQ.data?.total ?? 0) + ')'} />
<CardBody className="p-0">
{users.length ? (
<div className="divide-y divide-line max-h-[520px] overflow-y-auto">
{users.map((u) => (
<div key={u.id} className="flex flex-wrap items-center gap-2 px-4 py-2.5 text-[12.5px]">
<span className="font-medium text-ink-1">{u.username}</span>
{u.is_admin && <Badge color="var(--brand-text)">管理员</Badge>}
<span className="num ml-auto text-ink-3">{u.devices} 设备 · {u.records} 记录 · {fmtSize(u.attachment_bytes)}</span>
</div>
))}
</div>
) : (
<Empty icon={<Users2 size={32} strokeWidth={1.5} />} title="暂无用户" />
)}
</CardBody>
</Card>
</div>
<Dialog
open={!!delUser}
onClose={() => setDelUser(null)}
@@ -339,7 +320,7 @@ export function AdminPage() {
</>}>
<div className="text-[12.5px] leading-relaxed text-ink-2">
将<b>删除现有 demo 账号及其全部数据</b>,然后重新创建并播种全套虚拟演示数据
(个人信息档案、16 条足迹、4 学期成绩、简历内容)。
(个人信息档案、25 条足迹(含 10 项竞赛获奖与证书附件)、4 学期学科成绩、简历内容)。
<div className="mt-2 text-ink-3">demo / demo1234 · 仅影响演示账号,其他用户不受影响。</div>
</div>
</Dialog>