feat: 移除服务台模块,更新管理员导航以重定向至菜单权限页面
This commit is contained in:
@@ -3,6 +3,15 @@ import type { NextConfig } from "next";
|
|||||||
const nextConfig: NextConfig = {
|
const nextConfig: NextConfig = {
|
||||||
/* config options here */
|
/* config options here */
|
||||||
reactCompiler: true,
|
reactCompiler: true,
|
||||||
|
async redirects() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
source: "/admin/service-desk",
|
||||||
|
destination: "/admin/menu-permissions",
|
||||||
|
permanent: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default nextConfig;
|
export default nextConfig;
|
||||||
|
|||||||
19
src/app/admin/(shell)/menu-permissions/page.tsx
Normal file
19
src/app/admin/(shell)/menu-permissions/page.tsx
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { ModuleScaffold } from "@/components/admin/module-scaffold";
|
||||||
|
import { MenuPermissionsConsole } from "@/modules/menu-permissions/menu-permissions-console";
|
||||||
|
import { menuPermissionsModuleMeta } from "@/modules/menu-permissions/meta";
|
||||||
|
import type { Metadata } from "next";
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: menuPermissionsModuleMeta.title,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function AdminMenuPermissionsPage() {
|
||||||
|
return (
|
||||||
|
<ModuleScaffold className="w-full max-w-none">
|
||||||
|
<div className="mb-8">
|
||||||
|
<h1 className="text-2xl font-semibold tracking-tight">{menuPermissionsModuleMeta.title}</h1>
|
||||||
|
</div>
|
||||||
|
<MenuPermissionsConsole />
|
||||||
|
</ModuleScaffold>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
import { ModuleScaffold } from "@/components/admin/module-scaffold";
|
|
||||||
import { ServiceDeskConsole } from "@/modules/service-desk/service-desk-console";
|
|
||||||
import { serviceDeskModuleMeta } from "@/modules/service-desk/meta";
|
|
||||||
import type { Metadata } from "next";
|
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
|
||||||
title: serviceDeskModuleMeta.title,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function AdminServiceDeskPage() {
|
|
||||||
return (
|
|
||||||
<ModuleScaffold className="w-full max-w-none">
|
|
||||||
<div className="mb-8">
|
|
||||||
<h1 className="text-2xl font-semibold tracking-tight">{serviceDeskModuleMeta.title}</h1>
|
|
||||||
</div>
|
|
||||||
<ServiceDeskConsole />
|
|
||||||
</ModuleScaffold>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -8,7 +8,6 @@ import { SparklesIcon } from "lucide-react";
|
|||||||
import {
|
import {
|
||||||
Sidebar,
|
Sidebar,
|
||||||
SidebarContent,
|
SidebarContent,
|
||||||
SidebarFooter,
|
|
||||||
SidebarGroup,
|
SidebarGroup,
|
||||||
SidebarGroupContent,
|
SidebarGroupContent,
|
||||||
SidebarGroupLabel,
|
SidebarGroupLabel,
|
||||||
@@ -19,10 +18,7 @@ import {
|
|||||||
SidebarRail,
|
SidebarRail,
|
||||||
SidebarSeparator,
|
SidebarSeparator,
|
||||||
} from "@/components/ui/sidebar";
|
} from "@/components/ui/sidebar";
|
||||||
import {
|
import { adminNavIconBySegment } from "@/modules/_config/admin-nav-icons";
|
||||||
adminNavIconBySegment,
|
|
||||||
LogIn,
|
|
||||||
} from "@/modules/_config/admin-nav-icons";
|
|
||||||
import { adminNavItemVisible } from "@/lib/admin-nav-visibility";
|
import { adminNavItemVisible } from "@/lib/admin-nav-visibility";
|
||||||
import { adminShellNavItems, ADMIN_BASE } from "@/modules/_config/admin-nav";
|
import { adminShellNavItems, ADMIN_BASE } from "@/modules/_config/admin-nav";
|
||||||
import { useAdminProfile } from "@/stores/admin-session";
|
import { useAdminProfile } from "@/stores/admin-session";
|
||||||
@@ -94,19 +90,6 @@ export function AdminAppSidebar() {
|
|||||||
</SidebarGroup>
|
</SidebarGroup>
|
||||||
</SidebarContent>
|
</SidebarContent>
|
||||||
<SidebarSeparator />
|
<SidebarSeparator />
|
||||||
<SidebarFooter className="border-t border-sidebar-border">
|
|
||||||
<SidebarMenu>
|
|
||||||
<SidebarMenuItem>
|
|
||||||
<SidebarMenuButton
|
|
||||||
tooltip="登录"
|
|
||||||
render={<Link href="/admin/login" />}
|
|
||||||
>
|
|
||||||
<LogIn data-icon="inline-start" aria-hidden />
|
|
||||||
<span>登录入口</span>
|
|
||||||
</SidebarMenuButton>
|
|
||||||
</SidebarMenuItem>
|
|
||||||
</SidebarMenu>
|
|
||||||
</SidebarFooter>
|
|
||||||
<SidebarRail />
|
<SidebarRail />
|
||||||
</Sidebar>
|
</Sidebar>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ import {
|
|||||||
CalendarClock,
|
CalendarClock,
|
||||||
CircleDollarSign,
|
CircleDollarSign,
|
||||||
FileSpreadsheet,
|
FileSpreadsheet,
|
||||||
Headphones,
|
|
||||||
Landmark,
|
Landmark,
|
||||||
LayoutDashboard,
|
LayoutDashboard,
|
||||||
|
ListTree,
|
||||||
LogIn,
|
LogIn,
|
||||||
Scale,
|
Scale,
|
||||||
ScrollText,
|
ScrollText,
|
||||||
@@ -24,7 +24,7 @@ import type { AdminNavItem } from "@/modules/_config/admin-nav";
|
|||||||
export const adminNavIconBySegment: Record<AdminNavItem["segment"], LucideIcon> =
|
export const adminNavIconBySegment: Record<AdminNavItem["segment"], LucideIcon> =
|
||||||
{
|
{
|
||||||
dashboard: LayoutDashboard,
|
dashboard: LayoutDashboard,
|
||||||
service_desk: Headphones,
|
menu_permissions: ListTree,
|
||||||
players: Users,
|
players: Users,
|
||||||
draws: CalendarClock,
|
draws: CalendarClock,
|
||||||
config: SlidersHorizontal,
|
config: SlidersHorizontal,
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export type AdminNavItem = {
|
|||||||
href: string;
|
href: string;
|
||||||
segment:
|
segment:
|
||||||
| "dashboard"
|
| "dashboard"
|
||||||
| "service_desk"
|
| "menu_permissions"
|
||||||
| "players"
|
| "players"
|
||||||
| "draws"
|
| "draws"
|
||||||
| "config"
|
| "config"
|
||||||
@@ -126,20 +126,9 @@ export const adminShellNavItems: AdminNavItem[] = [
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
segment: "service_desk",
|
segment: "menu_permissions",
|
||||||
label: "客服 / 财务",
|
label: "菜单权限",
|
||||||
href: "/admin/service-desk",
|
href: "/admin/menu-permissions",
|
||||||
requiredAny: [
|
|
||||||
"prd.users.view_cs",
|
|
||||||
"prd.users.view_finance",
|
|
||||||
"prd.users.manage",
|
|
||||||
"prd.wallet_reconcile.view_cs",
|
|
||||||
"prd.wallet_reconcile.view",
|
|
||||||
"prd.wallet_reconcile.manage",
|
|
||||||
"prd.report.finance",
|
|
||||||
"prd.report.player",
|
|
||||||
"prd.draw_result.view",
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
segment: "reports",
|
segment: "reports",
|
||||||
|
|||||||
61
src/modules/menu-permissions/menu-permissions-console.tsx
Normal file
61
src/modules/menu-permissions/menu-permissions-console.tsx
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
import Link from "next/link";
|
||||||
|
|
||||||
|
import {
|
||||||
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCell,
|
||||||
|
TableHead,
|
||||||
|
TableHeader,
|
||||||
|
TableRow,
|
||||||
|
} from "@/components/ui/table";
|
||||||
|
import { adminShellNavItems } from "@/modules/_config/admin-nav";
|
||||||
|
|
||||||
|
export function MenuPermissionsConsole() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<p className="text-muted-foreground text-sm leading-relaxed">
|
||||||
|
以下为侧栏各菜单与 Laravel 功能权限 slug(<code className="text-foreground">prd.*</code>
|
||||||
|
)的对应关系。未配置「所需权限」的项对任意已登录管理员显示;已配置的项需拥有所列权限中的<strong className="text-foreground font-medium">至少一项</strong>
|
||||||
|
才会出现在侧栏。
|
||||||
|
</p>
|
||||||
|
<Table>
|
||||||
|
<TableHeader>
|
||||||
|
<TableRow>
|
||||||
|
<TableHead className="w-[160px]">菜单</TableHead>
|
||||||
|
<TableHead className="w-[200px]">路径</TableHead>
|
||||||
|
<TableHead>所需权限(任一)</TableHead>
|
||||||
|
</TableRow>
|
||||||
|
</TableHeader>
|
||||||
|
<TableBody>
|
||||||
|
{adminShellNavItems.map((item) => {
|
||||||
|
const req = item.requiredAny;
|
||||||
|
const permCell =
|
||||||
|
req === undefined || req.length === 0 ? (
|
||||||
|
<span className="text-muted-foreground">—(任意已登录)</span>
|
||||||
|
) : (
|
||||||
|
<ul className="font-mono text-xs leading-relaxed">
|
||||||
|
{req.map((slug) => (
|
||||||
|
<li key={slug}>{slug}</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<TableRow key={item.segment}>
|
||||||
|
<TableCell className="font-medium">{item.label}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Link
|
||||||
|
href={item.href}
|
||||||
|
className="text-primary font-mono text-xs underline-offset-4 hover:underline"
|
||||||
|
>
|
||||||
|
{item.href}
|
||||||
|
</Link>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>{permCell}</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
5
src/modules/menu-permissions/meta.ts
Normal file
5
src/modules/menu-permissions/meta.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export const menuPermissionsModuleMeta = {
|
||||||
|
segment: "menu_permissions",
|
||||||
|
title: "菜单权限",
|
||||||
|
description: "",
|
||||||
|
} as const;
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
export const serviceDeskModuleMeta = {
|
|
||||||
segment: "service-desk",
|
|
||||||
title: "服务台",
|
|
||||||
description: "",
|
|
||||||
} as const;
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import type { ReactElement } from "react";
|
|
||||||
import Link from "next/link";
|
|
||||||
|
|
||||||
import { buttonVariants } from "@/components/ui/button";
|
|
||||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
|
||||||
import { cn } from "@/lib/utils";
|
|
||||||
|
|
||||||
const items: { title: string; href: string }[] = [
|
|
||||||
{ title: "玩家注单", href: "/admin/tickets" },
|
|
||||||
{ title: "钱包流水", href: "/admin/wallet/transactions" },
|
|
||||||
{ title: "转账单", href: "/admin/wallet/transfer-orders" },
|
|
||||||
{ title: "期号列表", href: "/admin/draws" },
|
|
||||||
{ title: "报表导出", href: "/admin/reports" },
|
|
||||||
];
|
|
||||||
|
|
||||||
export function ServiceDeskConsole(): ReactElement {
|
|
||||||
return (
|
|
||||||
<div className="grid gap-6 md:grid-cols-2">
|
|
||||||
{items.map((it) => (
|
|
||||||
<Card key={it.href}>
|
|
||||||
<CardHeader>
|
|
||||||
<CardTitle className="text-base">{it.title}</CardTitle>
|
|
||||||
</CardHeader>
|
|
||||||
<CardContent>
|
|
||||||
<Link href={it.href} className={cn(buttonVariants({ size: "sm" }), "w-fit")}>
|
|
||||||
打开
|
|
||||||
</Link>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user