diff --git a/src/app/admin/(shell)/config/jackpot/page.tsx b/src/app/admin/(shell)/config/jackpot/page.tsx index 96bb1b2..527d678 100644 --- a/src/app/admin/(shell)/config/jackpot/page.tsx +++ b/src/app/admin/(shell)/config/jackpot/page.tsx @@ -1,20 +1,19 @@ -import { JackpotSubNav } from "@/modules/jackpot/jackpot-subnav"; -import { JackpotPoolsConsole } from "@/modules/jackpot/jackpot-pools-console"; +import { Suspense } from "react"; + +import { JackpotConfigScreen } from "@/modules/jackpot/jackpot-config-screen"; import { jackpotModuleMeta } from "@/modules/jackpot/meta"; import type { Metadata } from "next"; export const metadata: Metadata = { - title: `奖池配置 · ${jackpotModuleMeta.title}`, + title: jackpotModuleMeta.title, }; export default function AdminConfigJackpotPage() { return ( -
- -
-

{jackpotModuleMeta.title}

-
- -
+ Loading…

} + > + +
); } diff --git a/src/app/admin/(shell)/config/jackpot/records/page.tsx b/src/app/admin/(shell)/config/jackpot/records/page.tsx index bf72361..2dcd254 100644 --- a/src/app/admin/(shell)/config/jackpot/records/page.tsx +++ b/src/app/admin/(shell)/config/jackpot/records/page.tsx @@ -1,17 +1,6 @@ -import { JackpotSubNav } from "@/modules/jackpot/jackpot-subnav"; -import { JackpotRecordsConsole } from "@/modules/jackpot/jackpot-records-console"; -import { jackpotModuleMeta } from "@/modules/jackpot/meta"; -import type { Metadata } from "next"; - -export const metadata: Metadata = { - title: jackpotModuleMeta.title, -}; +import { redirect } from "next/navigation"; +/** 旧路径保留跳转,避免书签失效 */ export default function AdminConfigJackpotRecordsPage() { - return ( -
- - -
- ); + redirect("/admin/config/jackpot#records"); } diff --git a/src/app/admin/(shell)/jackpot/records/page.tsx b/src/app/admin/(shell)/jackpot/records/page.tsx index 12b3d64..1b086c5 100644 --- a/src/app/admin/(shell)/jackpot/records/page.tsx +++ b/src/app/admin/(shell)/jackpot/records/page.tsx @@ -1,5 +1,5 @@ import { redirect } from "next/navigation"; export default function AdminJackpotRecordsRedirectPage() { - redirect("/admin/config/jackpot/records"); + redirect("/admin/config/jackpot#records"); } diff --git a/src/components/admin/admin-status-badge.tsx b/src/components/admin/admin-status-badge.tsx new file mode 100644 index 0000000..fbaab48 --- /dev/null +++ b/src/components/admin/admin-status-badge.tsx @@ -0,0 +1,39 @@ +import type { ReactNode } from "react"; + +import { Badge } from "@/components/ui/badge"; +import { + adminStatusBadgeClassName, + resolveAdminStatusTone, + type AdminStatusTone, +} from "@/lib/admin-status-tone"; +import { cn } from "@/lib/utils"; + +type AdminStatusBadgeProps = { + children: ReactNode; + /** 用于自动解析色调;也可仅用 `tone` 显式指定 */ + status?: string | number | boolean | null; + tone?: AdminStatusTone; + className?: string; +}; + +export function AdminStatusBadge({ + children, + status, + tone, + className, +}: AdminStatusBadgeProps) { + const resolvedTone = tone ?? resolveAdminStatusTone(status); + + return ( + + {children} + + ); +} diff --git a/src/i18n/locales/en/jackpot.json b/src/i18n/locales/en/jackpot.json index a18761a..edfd21a 100644 --- a/src/i18n/locales/en/jackpot.json +++ b/src/i18n/locales/en/jackpot.json @@ -1,6 +1,10 @@ { "title": "Jackpot", "configTitle": "Jackpot pool configuration", + "pageDescription": "Maintain per-currency pool parameters; contribution and payout logs are below.", + "poolsSectionDescription": "Contribution rate, burst threshold, switch, and manual burst.", + "recordsSectionTitle": "Contribution & payout logs", + "recordsSectionDescription": "Filter payout and contribution entries (read-only).", "loadFailed": "Failed to load", "saveSuccess": "Saved", "saveFailed": "Save failed", @@ -35,9 +39,7 @@ "title": "Jackpot records", "description": "Payout records and pool contribution flows" }, - "subnavLabel": "Jackpot sub navigation", - "subnavPools": "Pool configuration", - "subnavRecords": "Records", + "poolsSectionTitle": "Per-currency pool parameters", "payoutLoadFailed": "Failed to load payout records", "contributionLoadFailed": "Failed to load contribution records", "trigger": "Trigger", diff --git a/src/i18n/locales/ne/jackpot.json b/src/i18n/locales/ne/jackpot.json index f51b22e..91e4286 100644 --- a/src/i18n/locales/ne/jackpot.json +++ b/src/i18n/locales/ne/jackpot.json @@ -1,6 +1,10 @@ { "title": "Jackpot", "configTitle": "Jackpot पूल कन्फिगरेसन", + "pageDescription": "मुद्रा अनुसार पूल प्यारामिटर; तल योगदान र पेआउट लग देख्नुहोस्।", + "poolsSectionDescription": "योगदान दर, बर्स्ट थ्रेसहोल्ड, स्विच र म्यानुअल बर्स्ट।", + "recordsSectionTitle": "योगदान र पेआउट लग", + "recordsSectionDescription": "पेआउट र योगदान प्रविष्टि फिल्टर (पढ्न मात्र)।", "loadFailed": "लोड असफल भयो", "saveSuccess": "सुरक्षित भयो", "saveFailed": "सुरक्षित गर्न असफल", @@ -35,9 +39,7 @@ "title": "Jackpot रेकर्ड", "description": "भुक्तानी रेकर्ड र पूल योगदान प्रवाह" }, - "subnavLabel": "Jackpot उपनेभिगेसन", - "subnavPools": "पूल कन्फिगरेसन", - "subnavRecords": "रेकर्ड", + "poolsSectionTitle": "मुद्रा अनुसार पूल प्यारामिटर", "payoutLoadFailed": "भुक्तानी रेकर्ड लोड असफल भयो", "contributionLoadFailed": "योगदान रेकर्ड लोड असफल भयो", "trigger": "ट्रिगर", diff --git a/src/i18n/locales/zh/jackpot.json b/src/i18n/locales/zh/jackpot.json index bc03c88..a4cd0c1 100644 --- a/src/i18n/locales/zh/jackpot.json +++ b/src/i18n/locales/zh/jackpot.json @@ -1,6 +1,10 @@ { "title": "奖池", "configTitle": "奖池配置", + "pageDescription": "维护各币种奖池参数,下方可查询蓄水与派彩流水。", + "poolsSectionDescription": "蓄水比例、爆池阈值、开关与手动爆池。", + "recordsSectionTitle": "蓄水与派彩流水", + "recordsSectionDescription": "按条件筛选派彩记录与蓄水明细,只读查询。", "loadFailed": "加载失败", "saveSuccess": "已保存", "saveFailed": "保存失败", @@ -35,9 +39,7 @@ "title": "奖池记录", "description": "派彩记录与奖池蓄水流水" }, - "subnavLabel": "奖池子导航", - "subnavPools": "奖池配置", - "subnavRecords": "记录", + "poolsSectionTitle": "各币种奖池参数", "payoutLoadFailed": "派彩记录加载失败", "contributionLoadFailed": "蓄水记录加载失败", "trigger": "触发", diff --git a/src/lib/admin-status-tone.ts b/src/lib/admin-status-tone.ts new file mode 100644 index 0000000..d025f5e --- /dev/null +++ b/src/lib/admin-status-tone.ts @@ -0,0 +1,133 @@ +/** + * 后台状态色标:统一映射到可读色调,列表/详情一眼可辨。 + */ +export type AdminStatusTone = + | "success" + | "info" + | "warning" + | "danger" + | "neutral" + | "indigo" + | "draft" + | "active" + | "archived"; + +export const ADMIN_STATUS_TONE_CLASSES: Record = { + success: + "border-emerald-500/30 bg-emerald-500/12 text-emerald-800 dark:text-emerald-300", + info: "border-primary/30 bg-primary/10 text-primary", + warning: + "border-amber-500/30 bg-amber-500/12 text-amber-900 dark:text-amber-300", + danger: + "border-destructive/35 bg-destructive/10 text-destructive dark:text-red-300", + neutral: "border-border/80 bg-muted text-muted-foreground", + indigo: + "border-indigo-500/30 bg-indigo-500/12 text-indigo-800 dark:text-indigo-300", + draft: + "border-amber-500/30 bg-amber-500/12 text-amber-900 dark:text-amber-300", + active: + "border-emerald-500/30 bg-emerald-500/12 text-emerald-800 dark:text-emerald-300", + archived: + "border-slate-400/35 bg-slate-500/10 text-slate-600 dark:text-slate-300", +}; + +const STATUS_TONE_MAP: Record = { + // 配置版本 + draft: "draft", + active: "active", + archived: "archived", + + // 期次 + open: "info", + closing: "warning", + closed: "neutral", + drawing: "indigo", + review: "warning", + cooldown: "neutral", + pending: "info", + settling: "indigo", + settled: "success", + cancelled: "danger", + + // 结算批次 + running: "warning", + pending_review: "info", + approved: "indigo", + rejected: "neutral", + paid: "success", + completed: "success", + failed: "danger", + + // 注单 + pending_confirm: "info", + partial_pending_confirm: "warning", + success: "success", + pending_payout: "warning", + settled_win: "success", + settled_lose: "neutral", + + // 钱包 / 划转 + processing: "info", + posted: "success", + pending_reconcile: "warning", + reversed: "neutral", + manually_processed: "indigo", + + // 对账 + mismatch: "danger", + matched: "success", + pending_check: "warning", + + // 开关 / 布尔 + enabled: "success", + disabled: "neutral", + true: "success", + false: "neutral", + + // 玩家 status 数值 + "0": "success", + "1": "warning", + "2": "danger", + + // 管理员/角色(1=启用 0=停用) + "role_enabled": "success", + "role_disabled": "neutral", +}; + +/** 玩家:0 正常 1 冻结 2 封禁 */ +export function resolvePlayerStatusTone(status: number): AdminStatusTone { + if (status === 0) return "success"; + if (status === 1) return "warning"; + if (status === 2) return "danger"; + return "neutral"; +} + +/** 后台用户:0 启用 1 停用 */ +export function resolveAdminUserStatusTone(status: number): AdminStatusTone { + return status === 0 ? "success" : "neutral"; +} + +/** 角色:1 启用 0 停用 */ +export function resolveRoleStatusTone(status: number): AdminStatusTone { + return status === 1 ? "success" : "neutral"; +} + +export function resolveAdminStatusTone( + status: string | number | boolean | null | undefined, +): AdminStatusTone { + if (status === null || status === undefined || status === "") { + return "neutral"; + } + if (typeof status === "boolean") { + return status ? "success" : "neutral"; + } + const key = String(status).trim().toLowerCase(); + return STATUS_TONE_MAP[key] ?? "neutral"; +} + +export function adminStatusBadgeClassName( + tone: AdminStatusTone, + className?: string, +): string { + return `${ADMIN_STATUS_TONE_CLASSES[tone]} ${className ?? ""}`.trim(); +} diff --git a/src/modules/admin-roles/admin-roles-console.tsx b/src/modules/admin-roles/admin-roles-console.tsx index 0bac59c..59510e0 100644 --- a/src/modules/admin-roles/admin-roles-console.tsx +++ b/src/modules/admin-roles/admin-roles-console.tsx @@ -13,7 +13,9 @@ import { putAdminRole, putAdminRolePermissions, } from "@/api/admin-users"; +import { AdminStatusBadge } from "@/components/admin/admin-status-badge"; import { Badge } from "@/components/ui/badge"; +import { resolveRoleStatusTone } from "@/lib/admin-status-tone"; import { AdminTableExportButton } from "@/components/admin/admin-table-export-button"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; @@ -363,18 +365,9 @@ export function AdminRolesConsole(): React.ReactElement { )} - {role.status === 1 ? ( - - {t("status.enabled")} - - ) : ( - - {t("status.disabled")} - - )} + + {role.status === 1 ? t("status.enabled") : t("status.disabled")} + {role.user_count} {role.permission_slugs.length} diff --git a/src/modules/admin-users/admin-users-console.tsx b/src/modules/admin-users/admin-users-console.tsx index 2dccebb..5679da4 100644 --- a/src/modules/admin-users/admin-users-console.tsx +++ b/src/modules/admin-users/admin-users-console.tsx @@ -14,7 +14,9 @@ import { } from "@/api/admin-users"; import { AdminListPaginationFooter } from "@/components/admin/admin-list-pagination-footer"; import { AdminTableExportButton } from "@/components/admin/admin-table-export-button"; +import { AdminStatusBadge } from "@/components/admin/admin-status-badge"; import { Badge } from "@/components/ui/badge"; +import { resolveAdminUserStatusTone } from "@/lib/admin-status-tone"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Checkbox } from "@/components/ui/checkbox"; @@ -387,18 +389,9 @@ export function AdminUsersConsole(): React.ReactElement { {row.nickname ?? ""} - {row.status === 0 ? ( - - {t("status.enabled")} - - ) : ( - - {t("status.disabled")} - - )} + + {row.status === 0 ? t("status.enabled") : t("status.disabled")} +
diff --git a/src/modules/config/config-nav-model.ts b/src/modules/config/config-nav-model.ts index 22329e6..fa1d9f1 100644 --- a/src/modules/config/config-nav-model.ts +++ b/src/modules/config/config-nav-model.ts @@ -1,6 +1,12 @@ /** * Single source of truth for config sub-navigation and breadcrumb routes. * Add new config pages here and create the matching `app/admin/(shell)/config/.../page.tsx`. + * + * ## 导航层级约定(避免「侧栏 + 顶栏 + 页内 Tab」叠三层) + * 1. **侧栏**:模块入口(如「运营配置」)— 全站唯一一级。 + * 2. **本文件顶栏(ConfigSubNav)**:运营配置下的「业务子域」切换(玩法、赔率、奖池…)— 最多一层。 + * 3. **页面内**:默认 **禁止再建 Tab/子路由**;改参数与查流水用 **同页分区(ConfigSection)** 或锚点 `#records`。 + * 仅当子域体量极大、且与配置完全无关时再考虑独立路由,且不得与顶栏同名。 */ export type ConfigNavGroup = { diff --git a/src/modules/config/config-section.tsx b/src/modules/config/config-section.tsx index 2879628..565b010 100644 --- a/src/modules/config/config-section.tsx +++ b/src/modules/config/config-section.tsx @@ -8,6 +8,8 @@ type ConfigSectionProps = { actions?: ReactNode; children: ReactNode; className?: string; + /** 页内锚点,供旧链接跳转(如 #records) */ + id?: string; }; export function ConfigSection({ @@ -16,9 +18,10 @@ export function ConfigSection({ actions, children, className, + id, }: ConfigSectionProps) { return ( -
+

{title}

diff --git a/src/modules/config/config-status-badge.tsx b/src/modules/config/config-status-badge.tsx index 2300606..0845b52 100644 --- a/src/modules/config/config-status-badge.tsx +++ b/src/modules/config/config-status-badge.tsx @@ -1,20 +1,15 @@ import { useTranslation } from "react-i18next"; -import { Badge } from "@/components/ui/badge"; -import { cn } from "@/lib/utils"; + +import { AdminStatusBadge } from "@/components/admin/admin-status-badge"; +import { resolveAdminStatusTone } from "@/lib/admin-status-tone"; export function ConfigStatusBadge({ status }: { status: string }) { const { t } = useTranslation("config"); const label = t(`versionStatus.${status}`, { defaultValue: status }); - const className = - status === "active" - ? "border-primary/30 bg-primary/10 text-primary" - : status === "draft" - ? "border-border bg-secondary text-secondary-foreground" - : "border-border/80 bg-muted text-muted-foreground"; return ( - + {label} - + ); } diff --git a/src/modules/config/doc/play-config-doc-screen.tsx b/src/modules/config/doc/play-config-doc-screen.tsx index 0971e4b..95ba563 100644 --- a/src/modules/config/doc/play-config-doc-screen.tsx +++ b/src/modules/config/doc/play-config-doc-screen.tsx @@ -37,6 +37,7 @@ import { TableHeader, TableRow, } from "@/components/ui/table"; +import { AdminStatusBadge } from "@/components/admin/admin-status-badge"; import { ConfigReadonlyValue } from "@/modules/config/config-readonly-value"; import { ConfigVersionActions } from "@/modules/config/config-version-actions"; import { ConfigVersionSwitcher } from "@/modules/config/config-version-switcher"; @@ -499,11 +500,13 @@ export function PlayConfigDocScreen() { aria-label={t("play.aria.enablePlay", { ns: "config", playCode: row.play_code })} /> ) : ( - - {row.is_enabled - ? t("play.states.enabled", { ns: "config" }) - : t("play.states.disabled", { ns: "config" })} - +
+ + {row.is_enabled + ? t("play.states.enabled", { ns: "config" }) + : t("play.states.disabled", { ns: "config" })} + +
)} @@ -595,7 +598,9 @@ export function PlayConfigDocScreen() { {t("play.actions.ruleText", { ns: "config" })} ) : ( - {t("play.states.readOnly", { ns: "config" })} + + {t("play.states.readOnly", { ns: "config" })} + )} diff --git a/src/modules/draws/draw-detail-console.tsx b/src/modules/draws/draw-detail-console.tsx index e4180f4..cd720ac 100644 --- a/src/modules/draws/draw-detail-console.tsx +++ b/src/modules/draws/draw-detail-console.tsx @@ -125,10 +125,12 @@ export function DrawDetailConsole({ drawId }: { drawId: string }) { status={data.status} label={drawStatusText(data.status, t)} /> -

- {t("hallPreviewStatus", { - status: drawStatusText(data.hall_preview_status, t), - })} +

+ {t("hallPreviewStatus", { status: "" }).replace(/\{\{status\}\}/, "").replace(/\s+$/, "")} +

diff --git a/src/modules/draws/draw-finance-console.tsx b/src/modules/draws/draw-finance-console.tsx index 6b88d9d..719c189 100644 --- a/src/modules/draws/draw-finance-console.tsx +++ b/src/modules/draws/draw-finance-console.tsx @@ -7,7 +7,9 @@ import { useTranslation } from "react-i18next"; import { getAdminDrawFinanceSummary } from "@/api/admin-draws"; import { postAdminRunDrawSettlement } from "@/api/admin-settlement"; import { Button, buttonVariants } from "@/components/ui/button"; +import { AdminStatusBadge } from "@/components/admin/admin-status-badge"; import { AdminTableExportButton } from "@/components/admin/admin-table-export-button"; +import { DrawStatusBadge } from "@/modules/draws/draw-status-badge"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Table, @@ -104,7 +106,9 @@ export function DrawFinanceConsole({ drawId }: { drawId: string }): React.ReactE
{t("status")} -

{drawStatusText(data.draw_status, t)}

+

+ +

{t("orderAndItemCount")} @@ -186,7 +190,9 @@ export function DrawFinanceConsole({ drawId }: { drawId: string }): React.ReactE {data.settlement_batches.map((b) => ( {b.id} - {drawStatusText(b.status, t)} + + {drawStatusText(b.status, t)} + {b.total_ticket_count} diff --git a/src/modules/draws/draw-status-badge.tsx b/src/modules/draws/draw-status-badge.tsx index 29c5504..8ebe288 100644 --- a/src/modules/draws/draw-status-badge.tsx +++ b/src/modules/draws/draw-status-badge.tsx @@ -1,14 +1,5 @@ -import { Badge } from "@/components/ui/badge"; - -const emphasis: Record = { - open: "default", - closing: "destructive", - closed: "secondary", - drawing: "secondary", - review: "outline", - cooldown: "secondary", - pending: "outline", -}; +import { AdminStatusBadge } from "@/components/admin/admin-status-badge"; +import { resolveAdminStatusTone } from "@/lib/admin-status-tone"; export function DrawStatusBadge({ status, @@ -18,6 +9,9 @@ export function DrawStatusBadge({ /** 可与 DB 不同时展示预览态文案 */ label?: string; }) { - const v = emphasis[status] ?? "outline"; - return {label ?? status}; + return ( + + {label ?? status} + + ); } diff --git a/src/modules/draws/draws-index-console.tsx b/src/modules/draws/draws-index-console.tsx index d98dc86..d85d061 100644 --- a/src/modules/draws/draws-index-console.tsx +++ b/src/modules/draws/draws-index-console.tsx @@ -267,7 +267,10 @@ export function DrawsIndexConsole() { {formatDt(row.close_time)} {formatDt(row.draw_time)} - + {row.total_bet_minor ?? "—"} diff --git a/src/modules/jackpot/jackpot-config-screen.tsx b/src/modules/jackpot/jackpot-config-screen.tsx new file mode 100644 index 0000000..58cbbf0 --- /dev/null +++ b/src/modules/jackpot/jackpot-config-screen.tsx @@ -0,0 +1,43 @@ +"use client"; + +import { useEffect } from "react"; +import { useTranslation } from "react-i18next"; + +import { ConfigDocPage } from "@/modules/config/config-doc-page"; +import { ConfigSection } from "@/modules/config/config-section"; +import { JackpotPoolsConsole } from "@/modules/jackpot/jackpot-pools-console"; +import { JackpotRecordsConsole } from "@/modules/jackpot/jackpot-records-console"; + +/** + * 奖池:仅保留「侧栏 + 运营配置顶栏」两层导航;池参数与流水在同一页用分区展示。 + */ +export function JackpotConfigScreen() { + const { t } = useTranslation("jackpot"); + + useEffect(() => { + const scrollToRecords = () => { + if (window.location.hash !== "#records") { + return; + } + document.getElementById("jackpot-records")?.scrollIntoView({ behavior: "smooth", block: "start" }); + }; + scrollToRecords(); + window.addEventListener("hashchange", scrollToRecords); + return () => window.removeEventListener("hashchange", scrollToRecords); + }, []); + + return ( + + + + + + + + + ); +} diff --git a/src/modules/jackpot/jackpot-pools-console.tsx b/src/modules/jackpot/jackpot-pools-console.tsx index 6d6fb1d..be35f4d 100644 --- a/src/modules/jackpot/jackpot-pools-console.tsx +++ b/src/modules/jackpot/jackpot-pools-console.tsx @@ -53,7 +53,12 @@ function toDraft(p: AdminJackpotPoolRow): Draft { }; } -export function JackpotPoolsConsole() { +type JackpotPoolsConsoleProps = { + /** 嵌入运营配置单页时去掉外层脚手架与重复标题 */ + embedded?: boolean; +}; + +export function JackpotPoolsConsole({ embedded = false }: JackpotPoolsConsoleProps) { const { t } = useTranslation(["jackpot", "common"]); const [items, setItems] = useState([]); const [drafts, setDrafts] = useState>({}); @@ -146,13 +151,14 @@ export function JackpotPoolsConsole() { } }; - return ( - - + const body = ( + + {!embedded ? ( {t("configTitle")} - + ) : null} + {loading ?

{t("states.loading", { ns: "common" })}

: null} {!loading && items.length === 0 ? (

{t("noPoolData")}

@@ -288,8 +294,13 @@ export function JackpotPoolsConsole() {
); })} - - - + + ); + + if (embedded) { + return body; + } + + return {body}; } diff --git a/src/modules/jackpot/jackpot-records-console.tsx b/src/modules/jackpot/jackpot-records-console.tsx index dd778ae..e98c429 100644 --- a/src/modules/jackpot/jackpot-records-console.tsx +++ b/src/modules/jackpot/jackpot-records-console.tsx @@ -27,7 +27,11 @@ import type { AdminJackpotPayoutLogsData, } from "@/types/api/admin-jackpot"; -export function JackpotRecordsConsole() { +type JackpotRecordsConsoleProps = { + embedded?: boolean; +}; + +export function JackpotRecordsConsole({ embedded = false }: JackpotRecordsConsoleProps) { const { t } = useTranslation(["jackpot", "common"]); const formatDt = useAdminDateTimeFormatter(); const [drawNo, setDrawNo] = useState(""); @@ -101,13 +105,8 @@ export function JackpotRecordsConsole() { return translated === key ? value : translated; }; - return ( - -
-

{t("recordsPage.title")}

-

{t("recordsPage.description")}

-
- + const content = ( + <> {t("filter")} @@ -260,6 +259,12 @@ export function JackpotRecordsConsole() { ) : null} -
+ ); + + if (embedded) { + return content; + } + + return {content}; } diff --git a/src/modules/jackpot/jackpot-subnav.tsx b/src/modules/jackpot/jackpot-subnav.tsx deleted file mode 100644 index 555b906..0000000 --- a/src/modules/jackpot/jackpot-subnav.tsx +++ /dev/null @@ -1,39 +0,0 @@ -"use client"; - -import Link from "next/link"; -import { usePathname } from "next/navigation"; -import { useTranslation } from "react-i18next"; - -import { cn } from "@/lib/utils"; - -const LINKS: { href: string; label: string }[] = [ - { href: "/admin/config/jackpot", label: "subnavPools" }, - { href: "/admin/config/jackpot/records", label: "subnavRecords" }, -]; - -export function JackpotSubNav() { - const { t } = useTranslation("jackpot"); - const pathname = usePathname(); - - return ( - - ); -} diff --git a/src/modules/jackpot/meta.ts b/src/modules/jackpot/meta.ts index 4363e2c..a11cfcd 100644 --- a/src/modules/jackpot/meta.ts +++ b/src/modules/jackpot/meta.ts @@ -1,4 +1,4 @@ export const jackpotModuleMeta = { - title: "奖池记录", + title: "奖池配置", description: "", } as const; diff --git a/src/modules/players/players-console.tsx b/src/modules/players/players-console.tsx index 0eb08c2..e3cb469 100644 --- a/src/modules/players/players-console.tsx +++ b/src/modules/players/players-console.tsx @@ -12,7 +12,8 @@ import { } from "@/api/admin-player"; 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 { AdminStatusBadge } from "@/components/admin/admin-status-badge"; +import { resolvePlayerStatusTone } from "@/lib/admin-status-tone"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { @@ -53,15 +54,6 @@ function playerStatusLabelT(status: number, t: (key: string) => string): string return String(status); } -function playerStatusVariant( - status: number, -): "default" | "secondary" | "destructive" | "outline" { - if (status === 0) return "secondary"; - if (status === 1) return "outline"; - if (status === 2) return "destructive"; - return "default"; -} - const PLAYER_STATUS_OPTIONS = [ { value: 0, label: "statusNormal" }, { value: 1, label: "statusFrozen" }, @@ -354,9 +346,9 @@ export function PlayersConsole(): React.ReactElement { : "—"}
- + {playerStatusLabelT(row.status, t)} - + {row.last_login_at diff --git a/src/modules/reconcile/reconcile-console.tsx b/src/modules/reconcile/reconcile-console.tsx index a661468..b2637d8 100644 --- a/src/modules/reconcile/reconcile-console.tsx +++ b/src/modules/reconcile/reconcile-console.tsx @@ -12,7 +12,7 @@ import { import { getAdminPlayers } from "@/api/admin-player"; import { AdminDateRangeField } from "@/components/admin/admin-date-range-field"; import { AdminListPaginationFooter } from "@/components/admin/admin-list-pagination-footer"; -import { Badge } from "@/components/ui/badge"; +import { AdminStatusBadge } from "@/components/admin/admin-status-badge"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@/components/ui/dialog"; @@ -379,7 +379,9 @@ export function ReconcileConsole(): React.ReactElement { {reconcileTypeLabel(row.reconcile_type, t)} - {jobStatusLabel(row.status, t)} + + {jobStatusLabel(row.status, t)} + @@ -459,7 +461,16 @@ export function ReconcileConsole(): React.ReactElement {
{t("jobNo")} {items.job_no} · - {t("status")} {selectedJob ? jobStatusLabel(selectedJob.status, t) : "—"} + + {t("status")} + {selectedJob ? ( + + {jobStatusLabel(selectedJob.status, t)} + + ) : ( + "—" + )} + · {t("period")} {selectedJob ? `${selectedJob.period_start ? formatTs(selectedJob.period_start) : "—"} ~ ${selectedJob.period_end ? formatTs(selectedJob.period_end) : "—"}` : "—"}
@@ -488,7 +499,11 @@ export function ReconcileConsole(): React.ReactElement { {r.side_a_ref ?? "—"} {r.side_b_ref ?? "—"} {r.difference_amount} - {itemStatusLabel(r.status, t)} + + + {itemStatusLabel(r.status, t)} + + )) )} diff --git a/src/modules/settlement/settlement-batch-details-console.tsx b/src/modules/settlement/settlement-batch-details-console.tsx index e2dedde..084cbe6 100644 --- a/src/modules/settlement/settlement-batch-details-console.tsx +++ b/src/modules/settlement/settlement-batch-details-console.tsx @@ -14,6 +14,7 @@ import { postAdminRejectSettlementBatch, } from "@/api/admin-settlement"; import { AdminListPaginationFooter } from "@/components/admin/admin-list-pagination-footer"; +import { AdminStatusBadge } from "@/components/admin/admin-status-badge"; import { ModuleScaffold } from "@/components/admin/module-scaffold"; import { Button, buttonVariants } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; @@ -208,13 +209,21 @@ export function SettlementBatchDetailsConsole({ batchId }: Props) {

-

- {t("settlementStatus")}{" "} - {settlementStatusText(summary.status, t)} +

+ {t("settlementStatus")} + + {settlementStatusText(summary.status, t)} +

-

- {t("reviewState")}{" "} - {settlementReviewStatusText(summary.review_status, t)} +

+ {t("reviewState")} + {summary.review_status ? ( + + {settlementReviewStatusText(summary.review_status, t)} + + ) : ( + + )}

{t("ticketTotal")}{" "} diff --git a/src/modules/settlement/settlement-batches-console.tsx b/src/modules/settlement/settlement-batches-console.tsx index ffd1fb8..8de96cd 100644 --- a/src/modules/settlement/settlement-batches-console.tsx +++ b/src/modules/settlement/settlement-batches-console.tsx @@ -12,6 +12,7 @@ import { postAdminRejectSettlementBatch, } from "@/api/admin-settlement"; import { AdminListPaginationFooter } from "@/components/admin/admin-list-pagination-footer"; +import { AdminStatusBadge } from "@/components/admin/admin-status-badge"; import { AdminTableExportButton } from "@/components/admin/admin-table-export-button"; import { ModuleScaffold } from "@/components/admin/module-scaffold"; import { Button, buttonVariants } from "@/components/ui/button"; @@ -270,23 +271,19 @@ export function SettlementBatchesConsole() { > {formatAdminMinorUnits(row.platform_profit, row.currency_code ?? "NPR")} - - {settlementReviewStatusText(row.review_status, t)} + + {row.review_status ? ( + + {settlementReviewStatusText(row.review_status, t)} + + ) : ( + + )} - + {settlementStatusText(row.status, t)} - +

diff --git a/src/modules/tickets/player-tickets-console.tsx b/src/modules/tickets/player-tickets-console.tsx index a25e5ca..ba4d879 100644 --- a/src/modules/tickets/player-tickets-console.tsx +++ b/src/modules/tickets/player-tickets-console.tsx @@ -7,7 +7,7 @@ import { getAdminTicketItems } from "@/api/admin-tickets"; import { AdminDateRangeField } from "@/components/admin/admin-date-range-field"; 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 { AdminStatusBadge } from "@/components/admin/admin-status-badge"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { @@ -77,15 +77,6 @@ function ticketStatusSummary(statuses: string[], t: (key: string) => string): st return t("statusSelectedCount", { count: statuses.length, defaultValue: `已选 ${statuses.length} 项` }); } -function ticketStatusVariant( - value: string, -): "default" | "secondary" | "destructive" | "outline" { - if (value === "settled_win") return "secondary"; - if (value === "failed") return "destructive"; - if (value === "pending_payout") return "default"; - return "outline"; -} - export function PlayerTicketsConsole(): React.ReactElement { const { t } = useTranslation(["tickets", "common"]); const formatTs = useAdminDateTimeFormatter(); @@ -344,9 +335,9 @@ export function PlayerTicketsConsole(): React.ReactElement { {row.actual_deduct_amount_formatted} - + {ticketStatusText(row.status, t)} - + {row.fail_reason_text ?? row.fail_reason_code ?? "—"} diff --git a/src/modules/wallet/wallet-console.tsx b/src/modules/wallet/wallet-console.tsx index 6583132..9223eeb 100644 --- a/src/modules/wallet/wallet-console.tsx +++ b/src/modules/wallet/wallet-console.tsx @@ -15,7 +15,7 @@ import { import { AdminDateRangeField } from "@/components/admin/admin-date-range-field"; 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 { AdminStatusBadge } from "@/components/admin/admin-status-badge"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Checkbox } from "@/components/ui/checkbox"; @@ -93,16 +93,6 @@ function CellMonoId({ ); } -function statusBadgeVariant( - status: string, -): "default" | "secondary" | "destructive" | "outline" { - if (status === "success" || status === "posted") return "secondary"; - if (status === "failed") return "destructive"; - if (status === "pending_reconcile") return "outline"; - if (status === "reversed" || status === "manually_processed") return "outline"; - return "default"; -} - function statusLabelT(status: string, t: (key: string) => string): string { switch (status) { case "processing": @@ -476,7 +466,7 @@ export function TransferOrdersPanel(): React.ReactElement { {formatAdminMinorUnits(row.amount, row.currency_code)} - {statusLabelT(row.status, t)} + {statusLabelT(row.status, t)} {row.fail_reason?.trim() ? row.fail_reason : "—"} @@ -798,7 +788,7 @@ export function WalletTxnsPanel(): React.ReactElement { {row.amount} ({row.direction === 1 ? t("in") : t("out")}) - {statusLabelT(row.status, t)} + {statusLabelT(row.status, t)} {formatTs(row.created_at)}