v0.11.0 后台 CRM 化:媒体上传/单页面 Elementor/修订/分类标签/菜单/用户/审计/设置/Dashboard v2 + dusuniot-cms MCP 服务器
This commit is contained in:
+46
-16
@@ -12,34 +12,60 @@ import {
|
||||
Image as ImageIcon,
|
||||
Languages,
|
||||
LayoutDashboard,
|
||||
List,
|
||||
LogOut,
|
||||
Package,
|
||||
Route as RouteIcon,
|
||||
ScrollText,
|
||||
Settings,
|
||||
ShoppingCart,
|
||||
SlidersHorizontal,
|
||||
UserRound,
|
||||
} from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import { useState, type ReactNode } from "react";
|
||||
import { StyleProvider } from "@ant-design/cssinjs";
|
||||
import { getCurrentUser, loginFn, logoutFn } from "~/server/auth";
|
||||
|
||||
/** # 类型 后台菜单项(key 即目标路由路径) **/
|
||||
const MENU_ITEMS = [
|
||||
{ key: "/admin/", icon: <LayoutDashboard size={16} aria-hidden />, label: "Dashboard" },
|
||||
{ key: "/admin/contents/", icon: <Files size={16} aria-hidden />, label: "内容" },
|
||||
{ key: "/admin/products/", icon: <Package size={16} aria-hidden />, label: "产品" },
|
||||
{ key: "/admin/orders/", icon: <ShoppingCart size={16} aria-hidden />, label: "订单" },
|
||||
{ key: "/admin/inquiries/", icon: <Inbox size={16} aria-hidden />, label: "询盘" },
|
||||
{ key: "/admin/media/", icon: <ImageIcon size={16} aria-hidden />, label: "媒体" },
|
||||
{ key: "/admin/languages/", icon: <Languages size={16} aria-hidden />, label: "语言" },
|
||||
{ key: "/admin/seo/", icon: <RouteIcon size={16} aria-hidden />, label: "SEO / 重定向" },
|
||||
{ key: "/admin/filters/", icon: <SlidersHorizontal size={16} aria-hidden />, label: "筛选" },
|
||||
{ key: "/admin/users/", icon: <Settings size={16} aria-hidden />, label: "系统设置" },
|
||||
] as const;
|
||||
/** # 类型 后台菜单分组(分组标签不可点;key 即目标路由路径) **/
|
||||
const MENU_GROUPS: { label: string; children: { key: string; icon: ReactNode; label: string }[] }[] = [
|
||||
{
|
||||
label: "概览",
|
||||
children: [{ key: "/admin/", icon: <LayoutDashboard size={16} aria-hidden />, label: "Dashboard" }],
|
||||
},
|
||||
{
|
||||
label: "内容",
|
||||
children: [
|
||||
{ key: "/admin/contents/", icon: <Files size={16} aria-hidden />, label: "页面 / 文章" },
|
||||
{ key: "/admin/menus/", icon: <List size={16} aria-hidden />, label: "菜单" },
|
||||
{ key: "/admin/media/", icon: <ImageIcon size={16} aria-hidden />, label: "媒体库" },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "商务",
|
||||
children: [
|
||||
{ key: "/admin/products/", icon: <Package size={16} aria-hidden />, label: "产品" },
|
||||
{ key: "/admin/orders/", icon: <ShoppingCart size={16} aria-hidden />, label: "订单" },
|
||||
{ key: "/admin/inquiries/", icon: <Inbox size={16} aria-hidden />, label: "询盘" },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "系统",
|
||||
children: [
|
||||
{ key: "/admin/filters/", icon: <SlidersHorizontal size={16} aria-hidden />, label: "筛选" },
|
||||
{ key: "/admin/languages/", icon: <Languages size={16} aria-hidden />, label: "语言" },
|
||||
{ key: "/admin/seo/", icon: <RouteIcon size={16} aria-hidden />, label: "SEO / 重定向" },
|
||||
{ key: "/admin/users/", icon: <UserRound size={16} aria-hidden />, label: "用户" },
|
||||
{ key: "/admin/settings/", icon: <Settings size={16} aria-hidden />, label: "系统设置" },
|
||||
{ key: "/admin/audit/", icon: <ScrollText size={16} aria-hidden />, label: "审计日志" },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
/** # 类型 后台菜单项(扁平视图,用于路径高亮匹配) **/
|
||||
const MENU_ITEMS = MENU_GROUPS.flatMap((g) => g.children);
|
||||
|
||||
/** # 类型 合法菜单路径(用于类型安全的导航) **/
|
||||
type MenuKey = (typeof MENU_ITEMS)[number]["key"];
|
||||
type MenuKey = string;
|
||||
|
||||
/** # 类型 拥有后台权限的角色 **/
|
||||
const ADMIN_ROLES = ["admin", "editor", "manager"];
|
||||
@@ -159,7 +185,11 @@ function AdminShell({ user }: { user: { displayName: string | null; email: strin
|
||||
<Menu
|
||||
theme="dark"
|
||||
mode="inline"
|
||||
items={MENU_ITEMS.map((m) => ({ key: m.key, icon: m.icon, label: m.label }))}
|
||||
items={MENU_GROUPS.map((g) => ({
|
||||
type: "group" as const,
|
||||
label: <span style={{ fontSize: 12, opacity: 0.6 }}>{g.label}</span>,
|
||||
children: g.children.map((m) => ({ key: m.key, icon: m.icon, label: m.label })),
|
||||
}))}
|
||||
selectedKeys={[selectedKey]}
|
||||
onClick={({ key }) => void navigate({ to: key as MenuKey })}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user