refactor(admin): drop duplicate users card, full-width panels, demo rebuild copy matches new dataset
This commit is contained in:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user