refactor: 更新管理端页面元数据,统一国际化支持,移除冗余代码
This commit is contained in:
105
src/lib/admin-page-title.ts
Normal file
105
src/lib/admin-page-title.ts
Normal file
@@ -0,0 +1,105 @@
|
||||
export type PageTitleSpec = {
|
||||
ns: string;
|
||||
key: string;
|
||||
params?: Record<string, string>;
|
||||
};
|
||||
|
||||
const EXACT_ROUTES: Record<string, PageTitleSpec> = {
|
||||
"/admin": { ns: "dashboard", key: "title" },
|
||||
"/admin/players": { ns: "players", key: "title" },
|
||||
"/admin/draws": { ns: "draws", key: "statusListTitle" },
|
||||
"/admin/tickets": { ns: "tickets", key: "title" },
|
||||
"/admin/settlement-batches": { ns: "settlement", key: "batchList" },
|
||||
"/admin/reconcile": { ns: "reconcile", key: "title" },
|
||||
"/admin/audit-logs": { ns: "audit", key: "title" },
|
||||
"/admin/admin-users": { ns: "adminUsers", key: "title" },
|
||||
"/admin/admin-roles": { ns: "adminRoles", key: "title" },
|
||||
"/admin/wallet": { ns: "wallet", key: "title" },
|
||||
"/admin/wallet/transactions": { ns: "wallet", key: "walletTransactions" },
|
||||
"/admin/wallet/transfer-orders": { ns: "wallet", key: "transferOrders" },
|
||||
"/admin/wallet/player": { ns: "wallet", key: "playerWalletQuery" },
|
||||
"/admin/risk": { ns: "risk", key: "center" },
|
||||
"/admin/settings": { ns: "common", key: "nav.settings" },
|
||||
"/admin/settings/currencies": { ns: "config", key: "currencies.title" },
|
||||
"/admin/currencies": { ns: "config", key: "currencies.title" },
|
||||
"/admin/config": { ns: "config", key: "hub.title" },
|
||||
"/admin/rules/plays": { ns: "config", key: "nav.rulesPlaysTitle" },
|
||||
"/admin/rules/odds": { ns: "config", key: "nav.rulesOddsTitle" },
|
||||
"/admin/jackpot": { ns: "jackpot", key: "configTitle" },
|
||||
"/admin/risk/cap": { ns: "config", key: "nav.riskCapTitle" },
|
||||
"/admin/login": { ns: "auth", key: "title" },
|
||||
};
|
||||
|
||||
type RoutePattern = {
|
||||
test: (pathname: string) => boolean;
|
||||
resolve: (pathname: string) => PageTitleSpec;
|
||||
};
|
||||
|
||||
const ROUTE_PATTERNS: RoutePattern[] = [
|
||||
{
|
||||
test: (p) => /^\/admin\/draws\/\d+\/finance$/.test(p),
|
||||
resolve: () => ({ ns: "draws", key: "subnav.finance" }),
|
||||
},
|
||||
{
|
||||
test: (p) => /^\/admin\/draws\/\d+\/results$/.test(p),
|
||||
resolve: () => ({ ns: "draws", key: "subnav.results" }),
|
||||
},
|
||||
{
|
||||
test: (p) => /^\/admin\/draws\/\d+\/review$/.test(p),
|
||||
resolve: () => ({ ns: "draws", key: "subnav.review" }),
|
||||
},
|
||||
{
|
||||
test: (p) => /^\/admin\/draws\/\d+\/publish\/\d+$/.test(p),
|
||||
resolve: () => ({ ns: "draws", key: "publishTitle" }),
|
||||
},
|
||||
{
|
||||
test: (p) => /^\/admin\/draws\/\d+\/risk\/occupancy$/.test(p) || /^\/admin\/risk\/draws\/\d+\/occupancy$/.test(p),
|
||||
resolve: () => ({ ns: "draws", key: "subnav.riskOccupancy" }),
|
||||
},
|
||||
{
|
||||
test: (p) => /^\/admin\/draws\/\d+\/risk\/hot$/.test(p) || /^\/admin\/risk\/draws\/\d+\/hot$/.test(p),
|
||||
resolve: () => ({ ns: "draws", key: "subnav.riskHot" }),
|
||||
},
|
||||
{
|
||||
test: (p) => /^\/admin\/draws\/\d+\/risk\/sold-out$/.test(p) || /^\/admin\/risk\/draws\/\d+\/sold-out$/.test(p),
|
||||
resolve: () => ({ ns: "draws", key: "subnav.riskSoldOut" }),
|
||||
},
|
||||
{
|
||||
test: (p) => /^\/admin\/draws\/\d+\/risk\/pools$/.test(p) || /^\/admin\/risk\/draws\/\d+\/pools$/.test(p),
|
||||
resolve: () => ({ ns: "draws", key: "subnav.riskPools" }),
|
||||
},
|
||||
{
|
||||
test: (p) => /^\/admin\/draws\/\d+\/risk\/pools\/[^/]+$/.test(p) || /^\/admin\/risk\/draws\/\d+\/pools\/[^/]+$/.test(p),
|
||||
resolve: (p) => {
|
||||
const number = decodeURIComponent(p.split("/").pop() ?? "");
|
||||
return { ns: "risk", key: "numberTitle", params: { number } };
|
||||
},
|
||||
},
|
||||
{
|
||||
test: (p) => /^\/admin\/draws\/\d+\/risk$/.test(p),
|
||||
resolve: () => ({ ns: "risk", key: "title" }),
|
||||
},
|
||||
{
|
||||
test: (p) => /^\/admin\/draws\/\d+$/.test(p),
|
||||
resolve: () => ({ ns: "draws", key: "drawDetail" }),
|
||||
},
|
||||
{
|
||||
test: (p) => /^\/admin\/settlement-batches\/\d+\/details$/.test(p),
|
||||
resolve: () => ({ ns: "settlement", key: "details" }),
|
||||
},
|
||||
];
|
||||
|
||||
/** 根据路径解析浏览器标题用的 i18n 规格。 */
|
||||
export function resolveAdminPageTitle(pathname: string): PageTitleSpec | null {
|
||||
if (EXACT_ROUTES[pathname]) {
|
||||
return EXACT_ROUTES[pathname];
|
||||
}
|
||||
|
||||
for (const pattern of ROUTE_PATTERNS) {
|
||||
if (pattern.test(pathname)) {
|
||||
return pattern.resolve(pathname);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
57
src/lib/page-metadata.ts
Normal file
57
src/lib/page-metadata.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import type { Metadata } from "next";
|
||||
|
||||
import enAdminRoles from "@/i18n/locales/en/adminRoles.json";
|
||||
import enAdminUsers from "@/i18n/locales/en/adminUsers.json";
|
||||
import enAudit from "@/i18n/locales/en/audit.json";
|
||||
import enAuth from "@/i18n/locales/en/auth.json";
|
||||
import enConfig from "@/i18n/locales/en/config.json";
|
||||
import enDashboard from "@/i18n/locales/en/dashboard.json";
|
||||
import enDraws from "@/i18n/locales/en/draws.json";
|
||||
import enJackpot from "@/i18n/locales/en/jackpot.json";
|
||||
import enPlayers from "@/i18n/locales/en/players.json";
|
||||
import enReconcile from "@/i18n/locales/en/reconcile.json";
|
||||
import enRisk from "@/i18n/locales/en/risk.json";
|
||||
import enSettlement from "@/i18n/locales/en/settlement.json";
|
||||
import enCommon from "@/i18n/locales/en/common.json";
|
||||
import enTickets from "@/i18n/locales/en/tickets.json";
|
||||
import enWallet from "@/i18n/locales/en/wallet.json";
|
||||
|
||||
const EN_FLAT: Record<string, Record<string, unknown>> = {
|
||||
dashboard: enDashboard,
|
||||
players: enPlayers,
|
||||
draws: enDraws,
|
||||
tickets: enTickets,
|
||||
settlement: enSettlement,
|
||||
reconcile: enReconcile,
|
||||
audit: enAudit,
|
||||
adminUsers: enAdminUsers,
|
||||
adminRoles: enAdminRoles,
|
||||
wallet: enWallet,
|
||||
risk: enRisk,
|
||||
jackpot: enJackpot,
|
||||
config: enConfig,
|
||||
common: enCommon,
|
||||
auth: enAuth,
|
||||
};
|
||||
|
||||
function getByPath(obj: Record<string, unknown>, path: string): string | undefined {
|
||||
const parts = path.split(".");
|
||||
let cur: unknown = obj;
|
||||
for (const part of parts) {
|
||||
if (cur == null || typeof cur !== "object") {
|
||||
return undefined;
|
||||
}
|
||||
cur = (cur as Record<string, unknown>)[part];
|
||||
}
|
||||
return typeof cur === "string" ? cur : undefined;
|
||||
}
|
||||
|
||||
/** SSR 默认英文标题;客户端由 {@link AdminDocumentTitle} 按用户语言覆盖。 */
|
||||
export function buildPageMetadata(ns: string, key: string): Metadata {
|
||||
const bundle = EN_FLAT[ns];
|
||||
const title = bundle ? getByPath(bundle as Record<string, unknown>, key) : undefined;
|
||||
|
||||
return {
|
||||
title: title ?? key,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user