feat: 增加管理端多语言与多模块界面国际化支持
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
import Link from "next/link";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { getAdminDrawFinanceSummary } from "@/api/admin-draws";
|
||||
import { postAdminRunDrawSettlement } from "@/api/admin-settlement";
|
||||
@@ -21,6 +22,7 @@ import type { AdminDrawFinanceSummaryData } from "@/types/api/admin-draw-finance
|
||||
import { toast } from "sonner";
|
||||
|
||||
export function DrawFinanceConsole({ drawId }: { drawId: string }): React.ReactElement {
|
||||
const { t } = useTranslation(["draws", "common"]);
|
||||
const idNum = Number(drawId);
|
||||
const [data, setData] = useState<AdminDrawFinanceSummaryData | null>(null);
|
||||
const [err, setErr] = useState<string | null>(null);
|
||||
@@ -29,7 +31,7 @@ export function DrawFinanceConsole({ drawId }: { drawId: string }): React.ReactE
|
||||
|
||||
const load = useCallback(async () => {
|
||||
if (!Number.isFinite(idNum) || idNum < 1) {
|
||||
setErr("无效的期号 ID");
|
||||
setErr(t("invalidDrawId"));
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
@@ -38,22 +40,22 @@ export function DrawFinanceConsole({ drawId }: { drawId: string }): React.ReactE
|
||||
try {
|
||||
setData(await getAdminDrawFinanceSummary(idNum));
|
||||
} catch (e) {
|
||||
setErr(e instanceof LotteryApiBizError ? e.message : "加载失败");
|
||||
setErr(e instanceof LotteryApiBizError ? e.message : t("errors.loadFailed", { ns: "common" }));
|
||||
setData(null);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [idNum]);
|
||||
}, [idNum, t]);
|
||||
|
||||
async function runSettlement(): Promise<void> {
|
||||
if (!Number.isFinite(idNum) || idNum < 1) return;
|
||||
setSettling(true);
|
||||
try {
|
||||
const res = await postAdminRunDrawSettlement(idNum);
|
||||
toast.success(res.ran ? "已触发结算" : "当前状态不可结算或已处理");
|
||||
toast.success(res.ran ? t("runSettlement") : t("status"));
|
||||
await load();
|
||||
} catch (e) {
|
||||
toast.error(e instanceof LotteryApiBizError ? e.message : "触发结算失败");
|
||||
toast.error(e instanceof LotteryApiBizError ? e.message : t("actionFailed", { name: t("runSettlement") }));
|
||||
} finally {
|
||||
setSettling(false);
|
||||
}
|
||||
@@ -66,44 +68,44 @@ export function DrawFinanceConsole({ drawId }: { drawId: string }): React.ReactE
|
||||
}, [load]);
|
||||
|
||||
if (loading && !data) {
|
||||
return <p className="text-muted-foreground text-sm">加载中…</p>;
|
||||
return <p className="text-muted-foreground text-sm">{t("states.loading", { ns: "common" })}</p>;
|
||||
}
|
||||
|
||||
if (err || !data) {
|
||||
return <p className="text-destructive text-sm">{err ?? "无数据"}</p>;
|
||||
return <p className="text-destructive text-sm">{err ?? t("states.noData", { ns: "common" })}</p>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-lg">期号收支概览</CardTitle>
|
||||
<CardTitle className="text-lg">{t("financeOverview")}</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="grid gap-3 text-sm sm:grid-cols-2 lg:grid-cols-3">
|
||||
<div>
|
||||
<span className="text-muted-foreground">期号</span>
|
||||
<span className="text-muted-foreground">{t("drawNo")}</span>
|
||||
<p className="font-mono font-semibold">{data.draw_no}</p>
|
||||
</div>
|
||||
<div>
|
||||
<span className="text-muted-foreground">状态</span>
|
||||
<span className="text-muted-foreground">{t("status")}</span>
|
||||
<p>{data.draw_status}</p>
|
||||
</div>
|
||||
<div>
|
||||
<span className="text-muted-foreground">订单数 / 注项数</span>
|
||||
<span className="text-muted-foreground">{t("orderAndItemCount")}</span>
|
||||
<p className="tabular-nums">
|
||||
{data.order_count} / {data.ticket_item_count}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<span className="text-muted-foreground">当期实扣投注</span>
|
||||
<span className="text-muted-foreground">{t("actualBet")}</span>
|
||||
<p className="tabular-nums font-medium">{data.total_bet_minor}</p>
|
||||
</div>
|
||||
<div>
|
||||
<span className="text-muted-foreground">当期派彩合计</span>
|
||||
<span className="text-muted-foreground">{t("currentPayout")}</span>
|
||||
<p className="tabular-nums font-medium">{data.total_payout_minor}</p>
|
||||
</div>
|
||||
<div>
|
||||
<span className="text-muted-foreground">近似毛损益</span>
|
||||
<span className="text-muted-foreground">{t("grossProfit")}</span>
|
||||
<p
|
||||
className={cn(
|
||||
"tabular-nums font-semibold",
|
||||
@@ -118,38 +120,38 @@ export function DrawFinanceConsole({ drawId }: { drawId: string }): React.ReactE
|
||||
|
||||
<div className="flex flex-wrap gap-2">
|
||||
<Button type="button" variant="secondary" size="sm" onClick={() => void load()}>
|
||||
刷新
|
||||
{t("actions.refresh", { ns: "common" })}
|
||||
</Button>
|
||||
<Button type="button" size="sm" disabled={settling} onClick={() => void runSettlement()}>
|
||||
{settling ? "处理中…" : "触发结算"}
|
||||
{settling ? t("processing") : t("runSettlement")}
|
||||
</Button>
|
||||
<Link
|
||||
href="/admin/settlement-batches"
|
||||
className={cn(buttonVariants({ variant: "outline", size: "sm" }))}
|
||||
>
|
||||
结算批次列表(按期号筛选)
|
||||
{t("settlementBatchList")}
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-base">本关联期结算批次</CardTitle>
|
||||
<CardTitle className="text-base">{t("relatedSettlementBatches")}</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
{data.settlement_batches.length === 0 ? (
|
||||
<p className="text-muted-foreground text-sm">暂无结算批次记录。</p>
|
||||
<p className="text-muted-foreground text-sm">{t("noSettlementBatches")}</p>
|
||||
) : (
|
||||
<div className="overflow-x-auto rounded-md border">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead className="w-20">ID</TableHead>
|
||||
<TableHead>状态</TableHead>
|
||||
<TableHead className="text-right">票数</TableHead>
|
||||
<TableHead className="text-right">中奖数</TableHead>
|
||||
<TableHead className="text-right">派彩</TableHead>
|
||||
<TableHead className="text-right">Jackpot</TableHead>
|
||||
<TableHead>完成时间</TableHead>
|
||||
<TableHead>{t("status")}</TableHead>
|
||||
<TableHead className="text-right">{t("ticketCount")}</TableHead>
|
||||
<TableHead className="text-right">{t("winCount")}</TableHead>
|
||||
<TableHead className="text-right">{t("payoutTotal")}</TableHead>
|
||||
<TableHead className="text-right">{t("jackpot")}</TableHead>
|
||||
<TableHead>{t("finishedAt")}</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
|
||||
Reference in New Issue
Block a user