feat: 增加管理端多语言与多模块界面国际化支持
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { getAdminAuditLogs } from "@/api/admin-audit";
|
||||
import { AdminListPaginationFooter } from "@/components/admin/admin-list-pagination-footer";
|
||||
@@ -21,6 +22,7 @@ import { LotteryApiBizError } from "@/types/api/errors";
|
||||
import type { AdminAuditLogListData } from "@/types/api/admin-audit";
|
||||
|
||||
export function AuditLogsConsole(): React.ReactElement {
|
||||
const { t } = useTranslation(["audit", "common"]);
|
||||
const formatTs = useAdminDateTimeFormatter();
|
||||
const [data, setData] = useState<AdminAuditLogListData | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
@@ -47,12 +49,12 @@ export function AuditLogsConsole(): React.ReactElement {
|
||||
});
|
||||
setData(d);
|
||||
} catch (e) {
|
||||
setErr(e instanceof LotteryApiBizError ? e.message : "加载失败");
|
||||
setErr(e instanceof LotteryApiBizError ? e.message : t("errors.loadFailed", { ns: "common" }));
|
||||
setData(null);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [page, perPage, appliedModule, appliedAction, appliedOpType]);
|
||||
}, [page, perPage, appliedModule, appliedAction, appliedOpType, t]);
|
||||
|
||||
useEffect(() => {
|
||||
queueMicrotask(() => {
|
||||
@@ -66,39 +68,39 @@ export function AuditLogsConsole(): React.ReactElement {
|
||||
<Card className="w-full max-w-none">
|
||||
<CardHeader className="flex flex-row flex-wrap items-end justify-between gap-4">
|
||||
<div>
|
||||
<CardTitle>审计日志</CardTitle>
|
||||
<CardTitle>{t("title")}</CardTitle>
|
||||
</div>
|
||||
<Button type="button" variant="secondary" size="sm" onClick={() => void load()}>
|
||||
刷新
|
||||
{t("actions.refresh", { ns: "common" })}
|
||||
</Button>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
|
||||
<div className="grid gap-1.5">
|
||||
<Label htmlFor="aud-mod">module_code</Label>
|
||||
<Label htmlFor="aud-mod">{t("moduleCode")}</Label>
|
||||
<Input
|
||||
id="aud-mod"
|
||||
value={moduleCode}
|
||||
onChange={(e) => setModuleCode(e.target.value)}
|
||||
placeholder="精确匹配"
|
||||
placeholder={t("exactMatch")}
|
||||
/>
|
||||
</div>
|
||||
<div className="grid gap-1.5">
|
||||
<Label htmlFor="aud-act">action_code</Label>
|
||||
<Label htmlFor="aud-act">{t("actionCode")}</Label>
|
||||
<Input
|
||||
id="aud-act"
|
||||
value={actionCode}
|
||||
onChange={(e) => setActionCode(e.target.value)}
|
||||
placeholder="精确匹配"
|
||||
placeholder={t("exactMatch")}
|
||||
/>
|
||||
</div>
|
||||
<div className="grid gap-1.5">
|
||||
<Label htmlFor="aud-op">operator_type</Label>
|
||||
<Label htmlFor="aud-op">{t("operatorType")}</Label>
|
||||
<Input
|
||||
id="aud-op"
|
||||
value={operatorType}
|
||||
onChange={(e) => setOperatorType(e.target.value)}
|
||||
placeholder="如 admin / system"
|
||||
placeholder={t("operatorTypePlaceholder")}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-end">
|
||||
@@ -111,14 +113,14 @@ export function AuditLogsConsole(): React.ReactElement {
|
||||
setPage(1);
|
||||
}}
|
||||
>
|
||||
搜索
|
||||
{t("actions.search", { ns: "common" })}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{err ? <p className="text-sm text-red-600 dark:text-red-400">{err}</p> : null}
|
||||
{loading && !data ? (
|
||||
<p className="text-muted-foreground text-sm">加载中…</p>
|
||||
<p className="text-muted-foreground text-sm">{t("states.loading", { ns: "common" })}</p>
|
||||
) : null}
|
||||
|
||||
{data ? (
|
||||
@@ -128,18 +130,18 @@ export function AuditLogsConsole(): React.ReactElement {
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead className="w-20">ID</TableHead>
|
||||
<TableHead>操作者</TableHead>
|
||||
<TableHead>模块</TableHead>
|
||||
<TableHead>动作</TableHead>
|
||||
<TableHead>目标</TableHead>
|
||||
<TableHead>时间</TableHead>
|
||||
<TableHead>{t("operator")}</TableHead>
|
||||
<TableHead>{t("module")}</TableHead>
|
||||
<TableHead>{t("action")}</TableHead>
|
||||
<TableHead>{t("target")}</TableHead>
|
||||
<TableHead>{t("time")}</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{data.items.length === 0 ? (
|
||||
<TableRow>
|
||||
<TableCell colSpan={6} className="text-muted-foreground">
|
||||
无数据
|
||||
{t("empty")}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
) : (
|
||||
|
||||
Reference in New Issue
Block a user