feat: 统一管理端导航为后端下发菜单,移除本地权限过滤
This commit is contained in:
@@ -1,152 +1,25 @@
|
||||
/**
|
||||
* Single source of truth for admin navigation and routes.
|
||||
*
|
||||
* `requiredAny` matches `admin.permissions` from the login response (Laravel `prd.*`).
|
||||
* When omitted, the item is visible to any signed-in admin.
|
||||
*/
|
||||
export const ADMIN_BASE = "/admin" as const;
|
||||
|
||||
export type AdminNavSegment =
|
||||
| "dashboard"
|
||||
| "players"
|
||||
| "draws"
|
||||
| "config"
|
||||
| "tickets"
|
||||
| "wallet"
|
||||
| "risk"
|
||||
| "settings"
|
||||
| "settlement"
|
||||
| "jackpot"
|
||||
| "reports"
|
||||
| "reconcile"
|
||||
| "audit"
|
||||
| "admin_users";
|
||||
|
||||
export type AdminNavItem = {
|
||||
label: string;
|
||||
href: string;
|
||||
segment:
|
||||
| "dashboard"
|
||||
| "players"
|
||||
| "draws"
|
||||
| "config"
|
||||
| "tickets"
|
||||
| "wallet"
|
||||
| "risk"
|
||||
| "settings"
|
||||
| "settlement"
|
||||
| "jackpot"
|
||||
| "reports"
|
||||
| "reconcile"
|
||||
| "audit"
|
||||
| "admin_users";
|
||||
segment: AdminNavSegment;
|
||||
activeMatchPrefix?: string;
|
||||
/** Show the nav item when the user has any of these permission slugs. */
|
||||
requiredAny?: readonly string[];
|
||||
};
|
||||
|
||||
export const adminShellNavItems: AdminNavItem[] = [
|
||||
{ segment: "dashboard", label: "Dashboard", href: "/admin" },
|
||||
{
|
||||
segment: "admin_users",
|
||||
label: "Admin Users",
|
||||
href: "/admin/admin-users",
|
||||
requiredAny: ["prd.admin_user.manage"],
|
||||
},
|
||||
{
|
||||
segment: "players",
|
||||
label: "Players",
|
||||
href: "/admin/players",
|
||||
requiredAny: [
|
||||
"prd.users.manage",
|
||||
"prd.users.view_finance",
|
||||
"prd.users.view_cs",
|
||||
],
|
||||
},
|
||||
{
|
||||
segment: "wallet",
|
||||
label: "Wallet",
|
||||
href: "/admin/wallet/transactions",
|
||||
activeMatchPrefix: "/admin/wallet",
|
||||
requiredAny: [
|
||||
"prd.wallet_reconcile.manage",
|
||||
"prd.wallet_reconcile.view",
|
||||
"prd.wallet_reconcile.view_cs",
|
||||
"prd.users.manage",
|
||||
"prd.users.view_finance",
|
||||
"prd.users.view_cs",
|
||||
],
|
||||
},
|
||||
{
|
||||
segment: "draws",
|
||||
label: "Draws",
|
||||
href: "/admin/draws",
|
||||
requiredAny: ["prd.draw_result.manage", "prd.draw_result.view"],
|
||||
},
|
||||
{
|
||||
segment: "config",
|
||||
label: "Configuration",
|
||||
href: "/admin/config",
|
||||
requiredAny: [
|
||||
"prd.play_switch.manage",
|
||||
"prd.odds.manage",
|
||||
"prd.risk_cap.manage",
|
||||
"prd.risk_cap.view",
|
||||
"prd.rebate.manage",
|
||||
"prd.rebate.view",
|
||||
"prd.jackpot.manage",
|
||||
"prd.jackpot.view",
|
||||
],
|
||||
},
|
||||
{
|
||||
segment: "risk",
|
||||
label: "Risk",
|
||||
href: "/admin/risk",
|
||||
requiredAny: ["prd.draw_result.view", "prd.draw_result.manage"],
|
||||
},
|
||||
{
|
||||
segment: "settlement",
|
||||
label: "Settlement",
|
||||
href: "/admin/settlement-batches",
|
||||
requiredAny: [
|
||||
"prd.payout.manage",
|
||||
"prd.payout.review",
|
||||
"prd.payout.view",
|
||||
],
|
||||
},
|
||||
{
|
||||
segment: "jackpot",
|
||||
label: "Jackpot",
|
||||
href: "/admin/jackpot/pools",
|
||||
activeMatchPrefix: "/admin/jackpot",
|
||||
requiredAny: ["prd.jackpot.manage", "prd.jackpot.view"],
|
||||
},
|
||||
{
|
||||
segment: "reconcile",
|
||||
label: "Reconcile",
|
||||
href: "/admin/reconcile",
|
||||
requiredAny: [
|
||||
"prd.wallet_reconcile.manage",
|
||||
"prd.wallet_reconcile.view",
|
||||
"prd.wallet_reconcile.view_cs",
|
||||
],
|
||||
},
|
||||
{
|
||||
segment: "tickets",
|
||||
label: "Tickets",
|
||||
href: "/admin/tickets",
|
||||
requiredAny: [
|
||||
"prd.users.view_cs",
|
||||
"prd.users.manage",
|
||||
"prd.users.view_finance",
|
||||
"prd.draw_result.view",
|
||||
"prd.draw_result.manage",
|
||||
"prd.payout.view",
|
||||
"prd.payout.review",
|
||||
"prd.payout.manage",
|
||||
"prd.report.player",
|
||||
],
|
||||
},
|
||||
{
|
||||
segment: "reports",
|
||||
label: "Reports",
|
||||
href: "/admin/reports",
|
||||
requiredAny: [
|
||||
"prd.report.all",
|
||||
"prd.report.risk",
|
||||
"prd.report.finance",
|
||||
"prd.report.player",
|
||||
],
|
||||
},
|
||||
{
|
||||
segment: "audit",
|
||||
label: "Audit Logs",
|
||||
href: "/admin/audit-logs",
|
||||
requiredAny: ["prd.audit.all", "prd.audit.self", "prd.audit.finance"],
|
||||
},
|
||||
{ segment: "settings", label: "Settings", href: "/admin/settings" },
|
||||
];
|
||||
|
||||
@@ -30,9 +30,9 @@ export function WalletSubnav(): React.ReactElement {
|
||||
aria-label={t("subnavLabel")}
|
||||
className="mb-6 flex flex-wrap gap-2 border-b border-border pb-3"
|
||||
>
|
||||
{tabs.map((t) => {
|
||||
const allowed = adminHasAnyPermission(perms, [...t.requiredAny]);
|
||||
const active = pathname === t.href || pathname.startsWith(`${t.href}/`);
|
||||
{tabs.map((tab) => {
|
||||
const allowed = adminHasAnyPermission(perms, [...tab.requiredAny]);
|
||||
const active = pathname === tab.href || pathname.startsWith(`${tab.href}/`);
|
||||
const className = cn(
|
||||
"rounded-lg px-3 py-1.5 text-sm font-medium transition-colors",
|
||||
active
|
||||
@@ -42,14 +42,14 @@ export function WalletSubnav(): React.ReactElement {
|
||||
);
|
||||
if (!allowed) {
|
||||
return (
|
||||
<span key={t.href} className={className} title={t("noPermission")}>
|
||||
{t(t.label)}
|
||||
<span key={tab.href} className={className} title={t("noPermission")}>
|
||||
{t(tab.label)}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Link key={t.href} href={t.href} className={className}>
|
||||
{t(t.label)}
|
||||
<Link key={tab.href} href={tab.href} className={className}>
|
||||
{t(tab.label)}
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
|
||||
Reference in New Issue
Block a user