@@ -123,13 +118,13 @@ export function DrawDetailConsole({ drawId }: { drawId: string }) {
- {t("hallPreviewStatus", { status: "" }).replace(/\{\{status\}\}/, "").replace(/\s+$/, "")}
+ {t("hallPreviewStatusLabel")}
@@ -147,7 +142,7 @@ export function DrawDetailConsole({ drawId }: { drawId: string }) {
-
{data.result_source ?? "—"}
+
{drawResultSourceLabel(data.result_source, t)}
{data.current_result_version}
{data.settle_version}
{data.is_reopened ? t("yes") : t("no")}
diff --git a/src/modules/draws/draw-display.ts b/src/modules/draws/draw-display.ts
new file mode 100644
index 0000000..69f5a32
--- /dev/null
+++ b/src/modules/draws/draw-display.ts
@@ -0,0 +1,62 @@
+type DrawTranslate = (
+ key: string,
+ options?: { ns?: string; index?: number },
+) => string;
+
+/** 期号状态文案(draws.statusOptions) */
+export function drawStatusLabel(status: string, t: DrawTranslate): string {
+ const key = `statusOptions.${status}`;
+ const translated = t(key, { ns: "draws" });
+ return translated === key ? status : translated;
+}
+
+/** 开奖结果来源(draws.resultSourceOptions) */
+export function drawResultSourceLabel(
+ source: string | null | undefined,
+ t: DrawTranslate,
+): string {
+ if (source == null || source === "") {
+ return "—";
+ }
+ const key = `resultSourceOptions.${source}`;
+ const translated = t(key, { ns: "draws" });
+ return translated === key ? source : translated;
+}
+
+/** 开奖结果批次状态(draws.batchStatusOptions) */
+export function drawBatchStatusLabel(status: string, t: DrawTranslate): string {
+ const key = `batchStatusOptions.${status}`;
+ const translated = t(key, { ns: "draws" });
+ return translated === key ? status : translated;
+}
+
+/** 结算批次状态(settlement.statusOptions) */
+export function settlementBatchStatusLabel(status: string, t: DrawTranslate): string {
+ const key = `statusOptions.${status}`;
+ const translated = t(key, { ns: "settlement" });
+ return translated === key ? status : translated;
+}
+
+/** 奖项类型 + 序号 → 展示名(draws.resultSlots) */
+export function drawPrizeTypeLabel(
+ prizeType: string,
+ prizeIndex: number,
+ t: DrawTranslate,
+): string {
+ if (prizeType === "first") {
+ return t("resultSlots.first", { ns: "draws" });
+ }
+ if (prizeType === "second") {
+ return t("resultSlots.second", { ns: "draws" });
+ }
+ if (prizeType === "third") {
+ return t("resultSlots.third", { ns: "draws" });
+ }
+ if (prizeType === "starter") {
+ return t("resultSlots.starter", { ns: "draws", index: prizeIndex + 1 });
+ }
+ if (prizeType === "consolation") {
+ return t("resultSlots.consolation", { ns: "draws", index: prizeIndex + 1 });
+ }
+ return prizeType;
+}
diff --git a/src/modules/draws/draw-finance-console.tsx b/src/modules/draws/draw-finance-console.tsx
index 8e4baed..10a94ed 100644
--- a/src/modules/draws/draw-finance-console.tsx
+++ b/src/modules/draws/draw-finance-console.tsx
@@ -26,18 +26,16 @@ import { LotteryApiBizError } from "@/types/api/errors";
import type { AdminDrawFinanceSummaryData } from "@/types/api/admin-draw-finance";
import { toast } from "sonner";
+import { useAdminCurrencyCatalog } from "@/hooks/use-admin-currency-catalog";
import { useExportLabels } from "@/hooks/use-export-labels";
+import { formatAdminMinorUnits } from "@/lib/money";
+import { drawStatusLabel, settlementBatchStatusLabel } from "./draw-display";
import { PRD_PAYOUT_MANAGE, PRD_PAYOUT_REVIEW } from "./draw-prd";
-function drawStatusText(status: string, t: (key: string) => string): string {
- const key = `statusOptions.${status}`;
- const translated = t(key);
- return translated === key ? status : translated;
-}
-
export function DrawFinanceConsole({ drawId }: { drawId: string }): React.ReactElement {
- const { t } = useTranslation(["draws", "common"]);
+ const { t } = useTranslation(["draws", "settlement", "common"]);
+ useAdminCurrencyCatalog();
const idNum = Number(drawId);
const profile = useAdminProfile();
const canRunSettlement = adminHasAnyPermission(profile?.permissions, [
@@ -96,6 +94,9 @@ export function DrawFinanceConsole({ drawId }: { drawId: string }): React.ReactE
return
{err ?? t("states.noData", { ns: "common" })}
;
}
+ const currencyCode = data.currency_code ?? "NPR";
+ const formatMoney = (minor: number) => formatAdminMinorUnits(minor, currencyCode);
+
return (
@@ -110,7 +111,7 @@ export function DrawFinanceConsole({ drawId }: { drawId: string }): React.ReactE
@@ -121,11 +122,11 @@ export function DrawFinanceConsole({ drawId }: { drawId: string }): React.ReactE
{t("actualBet")}
-
{data.total_bet_minor}
+
{formatMoney(data.total_bet_minor)}
{t("currentPayout")}
-
{data.total_payout_minor}
+
{formatMoney(data.total_payout_minor)}
{t("grossProfit")}
@@ -135,7 +136,7 @@ export function DrawFinanceConsole({ drawId }: { drawId: string }): React.ReactE
data.approx_house_gross_minor >= 0 ? "text-emerald-600" : "text-destructive",
)}
>
- {data.approx_house_gross_minor}
+ {formatMoney(data.approx_house_gross_minor)}
@@ -185,7 +186,7 @@ export function DrawFinanceConsole({ drawId }: { drawId: string }): React.ReactE
{t("ticketCount")}
{t("winCount")}
{t("payoutTotal")}
- {t("jackpot")}
+ {t("jackpotPayout")}
{t("finishedAt")}
@@ -194,7 +195,9 @@ export function DrawFinanceConsole({ drawId }: { drawId: string }): React.ReactE
{b.id}
- {drawStatusText(b.status, t)}
+
+ {settlementBatchStatusLabel(b.status, t)}
+
{b.total_ticket_count}
@@ -203,10 +206,10 @@ export function DrawFinanceConsole({ drawId }: { drawId: string }): React.ReactE
{b.total_win_count}
- {b.total_payout_amount}
+ {formatMoney(b.total_payout_amount)}
- {b.total_jackpot_payout_amount}
+ {formatMoney(b.total_jackpot_payout_amount)}
{b.finished_at ?? "—"}
diff --git a/src/modules/draws/draw-publish-console.tsx b/src/modules/draws/draw-publish-console.tsx
index 3f392d2..abd55ea 100644
--- a/src/modules/draws/draw-publish-console.tsx
+++ b/src/modules/draws/draw-publish-console.tsx
@@ -23,6 +23,7 @@ import { useAdminProfile } from "@/stores/admin-session";
import { LotteryApiBizError } from "@/types/api/errors";
import type { AdminDrawBatchRow, AdminDrawBatchesData } from "@/types/api/admin-draws";
+import { drawBatchStatusLabel, drawPrizeTypeLabel, drawStatusLabel } from "./draw-display";
import { PRD_DRAW_RESULT_MANAGE } from "./draw-prd";
export function DrawPublishConsole({ drawId, batchId }: { drawId: string; batchId: string }) {
@@ -73,7 +74,12 @@ export function DrawPublishConsole({ drawId, batchId }: { drawId: string; batchI
setPublishing(true);
try {
const res = await postAdminPublishResultBatch(idNum, batchNum);
- toast.success(t("publishSuccess", { drawNo: res.draw_no, status: res.status }));
+ toast.success(
+ t("publishSuccess", {
+ drawNo: res.draw_no,
+ status: drawStatusLabel(res.status, t),
+ }),
+ );
await load();
} catch (e) {
const msg = e instanceof LotteryApiBizError ? e.message : t("publishFailed");
@@ -125,7 +131,9 @@ export function DrawPublishConsole({ drawId, batchId }: { drawId: string; batchI
{!canPublish && canManageDraw ? (
{t("cannotPublish")}
- {t("cannotPublishDesc", { status: batch.status })}
+
+ {t("cannotPublishDesc", { status: drawBatchStatusLabel(batch.status, t) })}
+
) : null}
{canPublish ? (
@@ -147,7 +155,9 @@ export function DrawPublishConsole({ drawId, batchId }: { drawId: string; batchI
{batch.items.map((it) => (
- {it.prize_type}
+
+ {drawPrizeTypeLabel(it.prize_type, it.prize_index, t)}
+
{it.prize_index}
{it.number_4d}
diff --git a/src/modules/draws/draw-results-console.tsx b/src/modules/draws/draw-results-console.tsx
index eee06b9..4604eb8 100644
--- a/src/modules/draws/draw-results-console.tsx
+++ b/src/modules/draws/draw-results-console.tsx
@@ -21,6 +21,7 @@ import { useAdminProfile } from "@/stores/admin-session";
import { LotteryApiBizError } from "@/types/api/errors";
import type { AdminDrawBatchRow, AdminDrawBatchesData } from "@/types/api/admin-draws";
+import { drawPrizeTypeLabel } from "./draw-display";
import { PRD_DRAW_RESULT_MANAGE } from "./draw-prd";
import { DrawStatusBadge } from "./draw-status-badge";
@@ -129,7 +130,9 @@ function BatchTable({ batch }: { batch: AdminDrawBatchRow }) {
{batch.items.map((it) => (
- {it.prize_type}
+
+ {drawPrizeTypeLabel(it.prize_type, it.prize_index, t)}
+
{it.prize_index}
{it.number_4d}
diff --git a/src/modules/draws/draw-review-console.tsx b/src/modules/draws/draw-review-console.tsx
index 66eef77..dd9261d 100644
--- a/src/modules/draws/draw-review-console.tsx
+++ b/src/modules/draws/draw-review-console.tsx
@@ -23,6 +23,7 @@ import { useAdminProfile } from "@/stores/admin-session";
import { LotteryApiBizError } from "@/types/api/errors";
import type { AdminDrawBatchesData } from "@/types/api/admin-draws";
+import { drawStatusLabel } from "./draw-display";
import { PRD_DRAW_RESULT_MANAGE } from "./draw-prd";
import { DrawStatusBadge } from "./draw-status-badge";
@@ -129,13 +130,12 @@ export function DrawReviewConsole({ drawId }: { drawId: string }) {
{t("manualResultEntry")}
- {t("currentStatusAndDraft", {
- status: data.draw_status,
- }).split(data.draw_status)[0]}
-
- {t("currentStatusAndDraft", {
- status: data.draw_status,
- }).split(data.draw_status)[1] ?? ""}
+ {t("currentStatusLabel")}
+
+ · {t("currentStatusDraftHint")}
diff --git a/src/modules/draws/draws-index-console.tsx b/src/modules/draws/draws-index-console.tsx
index b8304c5..07d2e90 100644
--- a/src/modules/draws/draws-index-console.tsx
+++ b/src/modules/draws/draws-index-console.tsx
@@ -27,7 +27,9 @@ import {
TableHeader,
TableRow,
} from "@/components/ui/table";
+import { useAdminCurrencyCatalog } from "@/hooks/use-admin-currency-catalog";
import { useAdminDateTimeFormatter } from "@/hooks/use-admin-datetime-formatter";
+import { formatAdminMinorUnits } from "@/lib/money";
import { useExportLabels } from "@/hooks/use-export-labels";
import { adminHasAnyPermission } from "@/lib/admin-permissions";
import { cn } from "@/lib/utils";
@@ -35,6 +37,7 @@ import { useAdminProfile } from "@/stores/admin-session";
import { LotteryApiBizError } from "@/types/api/errors";
import type { AdminDrawListData, AdminDrawListItem } from "@/types/api/admin-draws";
+import { drawStatusLabel } from "./draw-display";
import { PRD_DRAW_RESULT_MANAGE } from "./draw-prd";
import { DrawStatusBadge } from "./draw-status-badge";
@@ -67,7 +70,9 @@ function drawAdminStatusSelectLabel(raw: unknown, t: (key: string) => string): s
export function DrawsIndexConsole() {
const { t } = useTranslation(["draws", "common"]);
const exportLabels = useExportLabels("drawsList");
+ useAdminCurrencyCatalog();
const formatDt = useAdminDateTimeFormatter();
+ const defaultCurrency = "NPR";
const profile = useAdminProfile();
const canManageDraw = adminHasAnyPermission(profile?.permissions, [PRD_DRAW_RESULT_MANAGE]);
const [data, setData] = useState(null);
@@ -271,22 +276,28 @@ export function DrawsIndexConsole() {
-
- {row.total_bet_minor ?? "—"}
+
+ {row.total_bet_minor != null
+ ? formatAdminMinorUnits(row.total_bet_minor, defaultCurrency)
+ : "—"}
-
- {row.total_payout_minor ?? "—"}
+
+ {row.total_payout_minor != null
+ ? formatAdminMinorUnits(row.total_payout_minor, defaultCurrency)
+ : "—"}
- {row.profit_loss_minor ?? "—"}
+ {row.profit_loss_minor != null
+ ? formatAdminMinorUnits(row.profit_loss_minor, defaultCurrency)
+ : "—"}
(REPORTS[0].key);
const [filters, setFilters] = useState(emptyFilters);
@@ -388,17 +396,20 @@ export function ReportsConsole() {
const loadPlayOptions = useCallback(async () => {
try {
- const payload = await getAdminPlayTypes();
+ await getAdminPlayTypesLoadPromise(getAdminPlayTypes);
setPlayOptions(
- payload.items.map((item) => ({
+ getCachedAdminPlayTypes().map((item) => ({
code: item.play_code,
- label: optionText(item.display_name_zh, item.play_code),
+ label: optionText(
+ resolveAdminPlayTypeDisplayName(item.play_code, i18n.language, item),
+ item.play_code,
+ ),
})),
);
} catch {
setPlayOptions([]);
}
- }, []);
+ }, [i18n.language]);
useEffect(() => {
void loadPlayOptions();
@@ -1056,7 +1067,7 @@ export function ReportsConsole() {
#{item.id}
{item.action_type}
{formatPlainMoney(item.amount, result.raw.currency_code)}
- {item.play_code || "-"}
+ {playCodeLabel(item.play_code)}
{item.ticket_no || "-"}
{item.player_id || "-"}
{item.source_reason || "-"}
@@ -1115,7 +1126,7 @@ export function ReportsConsole() {
if (result.key === "play_dimension") {
return result.raw.map((item) => (
- {item.play_code}
+ {playCodeLabel(item.play_code)}
{item.dimension}D
{formatPlainMoney(item.total_bet_minor, "NPR")}
{formatPlainMoney(item.total_payout_minor, "NPR")}
@@ -1130,7 +1141,7 @@ export function ReportsConsole() {
if (result.key === "rebate_commission") {
return result.raw.map((item) => (
- {item.play_code}
+ {playCodeLabel(item.play_code)}
{item.order_count}
{formatPlainMoney(item.total_rebate_minor, "NPR")}
{item.ticket_item_count}
diff --git a/src/modules/risk/risk-display.ts b/src/modules/risk/risk-display.ts
new file mode 100644
index 0000000..0785acc
--- /dev/null
+++ b/src/modules/risk/risk-display.ts
@@ -0,0 +1,27 @@
+type RiskTranslate = (key: string, options?: { ns?: string }) => string;
+
+/** 风控占用流水来源(risk.sourceReasonOptions) */
+export function riskSourceReasonLabel(
+ reason: string | null | undefined,
+ t: RiskTranslate,
+): string {
+ if (reason == null || reason === "") {
+ return "—";
+ }
+ const key = `sourceReasonOptions.${reason}`;
+ const translated = t(key, { ns: "risk" });
+ return translated === key ? reason : translated;
+}
+
+export type RiskPoolsPageTitleKey = "hotPageTitle" | "soldOutPageTitle" | "allPoolsPageTitle";
+
+/** 锁定 / 释放动作(risk.lock / risk.release) */
+export function riskActionTypeLabel(action: string, t: RiskTranslate): string {
+ if (action === "lock") {
+ return t("lock", { ns: "risk" });
+ }
+ if (action === "release") {
+ return t("release", { ns: "risk" });
+ }
+ return action;
+}
diff --git a/src/modules/risk/risk-lock-logs-console.tsx b/src/modules/risk/risk-lock-logs-console.tsx
index 833e622..19365a2 100644
--- a/src/modules/risk/risk-lock-logs-console.tsx
+++ b/src/modules/risk/risk-lock-logs-console.tsx
@@ -27,33 +27,30 @@ import {
TableRow,
} from "@/components/ui/table";
import { useAdminCurrencyCatalog } from "@/hooks/use-admin-currency-catalog";
+import { useAdminPlayCodeLabel } from "@/hooks/use-admin-play-type-catalog";
import { useAdminDateTimeFormatter } from "@/hooks/use-admin-datetime-formatter";
+import { riskActionTypeLabel, riskSourceReasonLabel } from "@/modules/risk/risk-display";
import { formatAdminMinorUnits } from "@/lib/money";
import { LotteryApiBizError } from "@/types/api/errors";
import type { AdminRiskLockLogListData, AdminRiskLockLogRow } from "@/types/api/admin-risk";
const ACTION_ALL = "__all__";
-function riskActionLabel(
+function riskActionFilterLabel(
value: string,
t: (key: string) => string,
): string {
if (value === ACTION_ALL) {
return t("noLimit");
}
- if (value === "lock") {
- return t("lock");
- }
- if (value === "release") {
- return t("release");
- }
- return value;
+ return riskActionTypeLabel(value, t);
}
export function RiskLockLogsConsole({ drawId }: { drawId: number }) {
const { t } = useTranslation(["risk", "common"]);
const exportLabels = useExportLabels("riskLockLogs");
useAdminCurrencyCatalog();
+ const playCodeLabel = useAdminPlayCodeLabel();
const formatDt = useAdminDateTimeFormatter();
const [page, setPage] = useState(1);
const [perPage, setPerPage] = useState(10);
@@ -129,7 +126,7 @@ export function RiskLockLogsConsole({ drawId }: { drawId: number }) {
}}
>
- {riskActionLabel(draftAction, t)}
+ {riskActionFilterLabel(draftAction, t)}
{t("noLimit")}
@@ -185,16 +182,16 @@ export function RiskLockLogsConsole({ drawId }: { drawId: number }) {
{row.normalized_number}
- {riskActionLabel(row.action_type, t)}
+ {riskActionTypeLabel(row.action_type, t)}
{formatAdminMinorUnits(row.amount, data?.currency_code ?? "NPR")}
- {row.source_reason ?? "—"}
+ {riskSourceReasonLabel(row.source_reason, t)}
{row.ticket_no ?? "—"}
- {row.play_code ?? "—"}
+ {playCodeLabel(row.play_code)}
))}
diff --git a/src/modules/risk/risk-pool-detail-console.tsx b/src/modules/risk/risk-pool-detail-console.tsx
index 394531b..bf2367a 100644
--- a/src/modules/risk/risk-pool-detail-console.tsx
+++ b/src/modules/risk/risk-pool-detail-console.tsx
@@ -18,8 +18,10 @@ import {
TableRow,
} from "@/components/ui/table";
import { useAdminCurrencyCatalog } from "@/hooks/use-admin-currency-catalog";
+import { useAdminPlayCodeLabel } from "@/hooks/use-admin-play-type-catalog";
import { useExportLabels } from "@/hooks/use-export-labels";
import { useAdminDateTimeFormatter } from "@/hooks/use-admin-datetime-formatter";
+import { riskActionTypeLabel, riskSourceReasonLabel } from "@/modules/risk/risk-display";
import { formatAdminMinorUnits } from "@/lib/money";
import { cn } from "@/lib/utils";
import { LotteryApiBizError } from "@/types/api/errors";
@@ -35,6 +37,7 @@ export function RiskPoolDetailConsole({
const { t } = useTranslation(["risk", "common"]);
const exportLabels = useExportLabels("riskPoolDetail", { number: number4d });
useAdminCurrencyCatalog();
+ const playCodeLabel = useAdminPlayCodeLabel();
const formatDt = useAdminDateTimeFormatter();
const [page, setPage] = useState(1);
const [perPage, setPerPage] = useState(10);
@@ -172,15 +175,15 @@ export function RiskPoolDetailConsole({
{row.created_at ? formatDt(row.created_at) : "—"}
- {row.action_type}
+ {riskActionTypeLabel(row.action_type, t)}
{formatAdminMinorUnits(row.amount, currencyCode)}
- {row.source_reason ?? "—"}
+ {riskSourceReasonLabel(row.source_reason, t)}
{row.ticket_no ?? "—"}
- {row.play_code ?? "—"}
+ {playCodeLabel(row.play_code)}
))}
diff --git a/src/modules/risk/risk-pools-console.tsx b/src/modules/risk/risk-pools-console.tsx
index bf44130..6611513 100644
--- a/src/modules/risk/risk-pools-console.tsx
+++ b/src/modules/risk/risk-pools-console.tsx
@@ -37,6 +37,7 @@ import { useExportLabels } from "@/hooks/use-export-labels";
import { formatAdminMinorUnits } from "@/lib/money";
import { cn } from "@/lib/utils";
import { LotteryApiBizError } from "@/types/api/errors";
+import type { RiskPoolsPageTitleKey } from "@/modules/risk/risk-display";
import type { AdminRiskPoolListData, AdminRiskPoolRow } from "@/types/api/admin-risk";
const SORT_OPTIONS: { value: "usage_desc" | "locked_desc" | "remaining_asc" | "number_asc"; label: string }[] =
@@ -59,7 +60,9 @@ type RiskFilter = "all" | "sold_out" | "high_risk";
type RiskPoolsConsoleProps = {
drawId: number;
- title: string;
+ /** @deprecated 优先使用 titleKey */
+ title?: string;
+ titleKey?: RiskPoolsPageTitleKey;
soldOutOnly: boolean;
defaultSort: "usage_desc" | "locked_desc" | "remaining_asc" | "number_asc";
allowSortChange?: boolean;
@@ -68,11 +71,13 @@ type RiskPoolsConsoleProps = {
export function RiskPoolsConsole({
drawId,
title,
+ titleKey,
soldOutOnly,
defaultSort,
allowSortChange = false,
}: RiskPoolsConsoleProps) {
const { t } = useTranslation(["risk", "common"]);
+ const pageTitle = titleKey ? t(titleKey) : (title ?? t("poolsTitle"));
const exportLabels = useExportLabels("riskPools");
useAdminCurrencyCatalog();
const [sort, setSort] = useState(defaultSort);
@@ -145,7 +150,7 @@ export function RiskPoolsConsole({
return (
- {title}
+ {pageTitle}
+
+
+
{t("system.frontendConfig", { ns: "config", defaultValue: "前端配置" })}
+
+
+
+
+
+
+ {t("system.fields.playRulesHtmlDesc", { ns: "config", defaultValue: "该内容将直接在玩家端的玩法规则页面作为 HTML 渲染。留空则显示前端默认提示。" })}
+
+
+
+
+
+ {dirty && (
+
+ )}
+
+
+
+
{t("wallet.title", { ns: "config" })}
diff --git a/src/modules/settlement/settlement-batch-details-console.tsx b/src/modules/settlement/settlement-batch-details-console.tsx
index 084cbe6..060cb24 100644
--- a/src/modules/settlement/settlement-batch-details-console.tsx
+++ b/src/modules/settlement/settlement-batch-details-console.tsx
@@ -37,6 +37,7 @@ import {
} from "@/components/ui/table";
import { Textarea } from "@/components/ui/textarea";
import { useAdminCurrencyCatalog } from "@/hooks/use-admin-currency-catalog";
+import { useAdminPlayCodeLabel } from "@/hooks/use-admin-play-type-catalog";
import { useAdminDateTimeFormatter } from "@/hooks/use-admin-datetime-formatter";
import { adminHasAnyPermission } from "@/lib/admin-permissions";
import { formatAdminMinorUnits } from "@/lib/money";
@@ -72,6 +73,7 @@ export function SettlementBatchDetailsConsole({ batchId }: Props) {
const { t } = useTranslation(["settlement", "common"]);
const profile = useAdminProfile();
useAdminCurrencyCatalog();
+ const playCodeLabel = useAdminPlayCodeLabel();
const canReviewSettlement = adminHasAnyPermission(profile?.permissions, [PRD_PAYOUT_REVIEW]);
const canManagePayout = adminHasAnyPermission(profile?.permissions, [PRD_PAYOUT_MANAGE]);
const formatDt = useAdminDateTimeFormatter();
@@ -333,7 +335,7 @@ export function SettlementBatchDetailsConsole({ batchId }: Props) {
{details.items.map((r) => (
{r.ticket_no ?? "—"}
- {r.play_code ?? "—"}
+ {playCodeLabel(r.play_code)}
{r.player_username ?? r.site_player_id ?? r.player_id ?? "—"}
diff --git a/src/modules/tickets/player-tickets-console.tsx b/src/modules/tickets/player-tickets-console.tsx
index 357bb41..757275b 100644
--- a/src/modules/tickets/player-tickets-console.tsx
+++ b/src/modules/tickets/player-tickets-console.tsx
@@ -28,6 +28,7 @@ import {
TableRow,
} from "@/components/ui/table";
import { useAdminDateTimeFormatter } from "@/hooks/use-admin-datetime-formatter";
+import { useAdminPlayCodeLabel } from "@/hooks/use-admin-play-type-catalog";
import { LotteryApiBizError } from "@/types/api/errors";
import type { AdminTicketItemsData } from "@/types/api/admin-tickets";
import { ChevronDown } from "lucide-react";
@@ -60,13 +61,18 @@ const emptyTicketFilters: TicketFilters = {
statuses: [],
};
-function ticketStatusText(value: string, t: (key: string) => string): string {
+type TicketTranslateFn = (
+ key: string,
+ options?: { count?: number },
+) => string;
+
+function ticketStatusText(value: string, t: TicketTranslateFn): string {
const key = `statusOptions.${value}`;
const translated = t(key);
return translated === key ? value : translated;
}
-function ticketStatusSummary(statuses: string[], t: (key: string) => string): string {
+function ticketStatusSummary(statuses: string[], t: TicketTranslateFn): string {
if (statuses.length === 0) {
return t("statusOptions.all");
}
@@ -80,6 +86,7 @@ function ticketStatusSummary(statuses: string[], t: (key: string) => string): st
export function PlayerTicketsConsole(): React.ReactElement {
const { t } = useTranslation(["tickets", "common"]);
+ const playCodeLabel = useAdminPlayCodeLabel();
const exportLabels = useExportLabels("tickets");
const formatTs = useAdminDateTimeFormatter();
const [draft, setDraft] = useState(emptyTicketFilters);
@@ -328,7 +335,7 @@ export function PlayerTicketsConsole(): React.ReactElement {
{row.order_no ?? "—"}
{row.draw_no ?? "—"}
- {row.play_code}
+ {playCodeLabel(row.play_code)}
{row.original_number ?? "—"}
{row.total_bet_amount_formatted}