feat: 重构管理端列表与风控/结算导航,新增表格导出和结算审核确认

This commit is contained in:
2026-05-19 17:06:56 +08:00
parent a1fb163f1b
commit 37b13278ef
47 changed files with 1255 additions and 524 deletions

View File

@@ -13,6 +13,7 @@ import {
putAdminUserRoles,
} from "@/api/admin-users";
import { AdminListPaginationFooter } from "@/components/admin/admin-list-pagination-footer";
import { AdminTableExportButton } from "@/components/admin/admin-table-export-button";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
@@ -25,6 +26,7 @@ import {
DialogTitle,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
Table,
TableBody,
@@ -296,47 +298,61 @@ export function AdminUsersConsole(): React.ReactElement {
return (
<div className="flex w-full max-w-none flex-col gap-6">
<Card>
<CardHeader className="flex flex-row flex-wrap items-end justify-between gap-4">
<Card className="admin-list-card">
<CardHeader className="admin-list-header flex flex-col gap-4">
<div className="flex flex-col gap-2 sm:flex-row sm:items-center sm:gap-3">
<CardTitle>{t("listTitle")}</CardTitle>
<CardTitle className="admin-list-title">{t("listTitle")}</CardTitle>
<Button type="button" size="sm" onClick={() => openCreateAccount()}>
{t("createAdmin")}
</Button>
</div>
<div className="flex w-full max-w-lg gap-2">
<Input
value={keyword}
placeholder={t("searchPlaceholder")}
onChange={(e) => setKeyword(e.target.value)}
onKeyDown={(e) => {
if (e.key === "Enter") {
<div className="admin-list-toolbar">
<div className="admin-list-field xl:min-w-0">
<Label htmlFor="admin-user-search" className="sm:w-20 sm:shrink-0">
{t("actions.search", { ns: "common" })}
</Label>
<Input
id="admin-user-search"
value={keyword}
className="w-full sm:w-[18rem] xl:w-[24rem]"
placeholder={t("searchPlaceholder")}
onChange={(e) => setKeyword(e.target.value)}
onKeyDown={(e) => {
if (e.key === "Enter") {
setPage(1);
setQuery(keyword.trim());
}
}}
/>
</div>
<div className="admin-list-actions">
<AdminTableExportButton
tableId="admin-users-table"
filename="后台用户列表"
sheetName="后台用户"
/>
<Button
type="button"
onClick={() => {
setPage(1);
setQuery(keyword.trim());
}
}}
/>
<Button
type="button"
onClick={() => {
setPage(1);
setQuery(keyword.trim());
}}
>
{t("actions.search", { ns: "common" })}
</Button>
<Button type="button" variant="secondary" onClick={() => void load()}>
{t("actions.refresh", { ns: "common" })}
</Button>
}}
>
{t("actions.search", { ns: "common" })}
</Button>
<Button type="button" variant="secondary" onClick={() => void load()}>
{t("actions.refresh", { ns: "common" })}
</Button>
</div>
</div>
</CardHeader>
<CardContent className="space-y-4">
<CardContent className="admin-list-content">
{err ? <p className="text-sm text-red-600 dark:text-red-400">{err}</p> : null}
{loading && items.length === 0 ? (
<p className="text-sm text-muted-foreground">{t("states.loading", { ns: "common" })}</p>
) : null}
<div className="rounded-md border">
<Table>
<div className="admin-table-shell">
<Table id="admin-users-table">
<TableHeader>
<TableRow>
<TableHead className="w-16">ID</TableHead>