feat: 增加管理端多语言与多模块界面国际化支持

This commit is contained in:
2026-05-19 09:11:55 +08:00
parent 49a4caf01e
commit 1b1dfc92ab
110 changed files with 4053 additions and 1308 deletions

View File

@@ -2,6 +2,7 @@
import Link from "next/link";
import { useCallback, useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { getAdminRiskPoolDetail } from "@/api/admin-risk";
import { AdminListPaginationFooter } from "@/components/admin/admin-list-pagination-footer";
@@ -28,6 +29,7 @@ export function RiskPoolDetailConsole({
drawId: number;
number4d: string;
}) {
const { t } = useTranslation(["risk", "common"]);
const formatDt = useAdminDateTimeFormatter();
const [page, setPage] = useState(1);
const [perPage, setPerPage] = useState(20);
@@ -43,13 +45,13 @@ export function RiskPoolDetailConsole({
setData(d);
} catch (e) {
const msg =
e instanceof LotteryApiBizError ? e.message : "加载风险池详情失败";
e instanceof LotteryApiBizError ? e.message : t("loadDetailFailed");
setError(msg);
setData(null);
} finally {
setLoading(false);
}
}, [drawId, number4d, page, perPage]);
}, [drawId, number4d, page, perPage, t]);
useEffect(() => {
queueMicrotask(() => {
@@ -59,9 +61,9 @@ export function RiskPoolDetailConsole({
if (error && !data) {
return (
<Card className="border-destructive/40">
<Card className="border-destructive/40">
<CardHeader>
<CardTitle className="text-lg"></CardTitle>
<CardTitle className="text-lg">{t("detailTitle")}</CardTitle>
</CardHeader>
<CardContent className="space-y-2">
<p className="text-sm text-destructive">{error}</p>
@@ -69,7 +71,7 @@ export function RiskPoolDetailConsole({
href={`/admin/risk/draws/${drawId}/pools`}
className={cn(buttonVariants({ variant: "outline", size: "sm" }))}
>
{t("backToList")}
</Link>
</CardContent>
</Card>
@@ -77,7 +79,7 @@ export function RiskPoolDetailConsole({
}
if (loading && !data) {
return <p className="text-sm text-muted-foreground"></p>;
return <p className="text-sm text-muted-foreground">{t("states.loading", { ns: "common" })}</p>;
}
if (!data) {
@@ -93,41 +95,41 @@ export function RiskPoolDetailConsole({
href={`/admin/risk/draws/${drawId}/pools`}
className={cn(buttonVariants({ variant: "ghost", size: "sm" }))}
>
{t("backToAllPools")}
</Link>
</div>
<Card>
<CardHeader>
<CardTitle className="text-lg">
<span className="font-mono">{pool.normalized_number}</span>
{t("numberTitle", { number: pool.normalized_number })}
</CardTitle>
<p className="text-sm text-muted-foreground"> {data.draw_no}</p>
<p className="text-sm text-muted-foreground">{t("drawMeta", { drawNo: data.draw_no })}</p>
</CardHeader>
<CardContent className="grid gap-3 sm:grid-cols-2 lg:grid-cols-4">
<div className="rounded-lg border bg-muted/40 p-3">
<p className="text-xs text-muted-foreground"></p>
<p className="text-xs text-muted-foreground">{t("totalCap")}</p>
<p className="mt-1 font-mono text-sm font-medium tabular-nums">
{formatAdminMinorUnits(pool.total_cap_amount)}
</p>
</div>
<div className="rounded-lg border bg-muted/40 p-3">
<p className="text-xs text-muted-foreground"></p>
<p className="text-xs text-muted-foreground">{t("lockedWorstCase")}</p>
<p className="mt-1 font-mono text-sm font-medium tabular-nums">
{formatAdminMinorUnits(pool.locked_amount)}
</p>
</div>
<div className="rounded-lg border bg-muted/40 p-3">
<p className="text-xs text-muted-foreground"></p>
<p className="text-xs text-muted-foreground">{t("remainingSellable")}</p>
<p className="mt-1 font-mono text-sm font-medium tabular-nums">
{formatAdminMinorUnits(pool.remaining_amount)}
</p>
</div>
<div className="rounded-lg border bg-muted/40 p-3">
<p className="text-xs text-muted-foreground"></p>
<p className="mt-1 text-sm font-medium">{pool.is_sold_out ? "是" : "否"}</p>
<p className="text-xs text-muted-foreground">{t("isSoldOut")}</p>
<p className="mt-1 text-sm font-medium">{pool.is_sold_out ? t("yes") : t("no")}</p>
<p className="mt-0.5 text-xs text-muted-foreground">
{" "}
{t("usageRatio")}{" "}
{pool.usage_ratio != null ? `${(pool.usage_ratio * 100).toFixed(2)}%` : "—"}
</p>
</div>
@@ -136,19 +138,19 @@ export function RiskPoolDetailConsole({
<Card>
<CardHeader>
<CardTitle className="text-base"> / </CardTitle>
<CardTitle className="text-base">{t("occupationLogs")}</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
<div className="overflow-x-auto rounded-md border">
<Table>
<TableHeader>
<TableRow>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead className="text-right"></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead>{t("time")}</TableHead>
<TableHead>{t("action")}</TableHead>
<TableHead className="text-right">{t("amount")}</TableHead>
<TableHead>{t("source")}</TableHead>
<TableHead>{t("ticketNo")}</TableHead>
<TableHead>{t("playCode")}</TableHead>
</TableRow>
</TableHeader>
<TableBody>