feat: 完成TikTok短剧管理后台基础功能开发

本次提交搭建了完整的后台管理系统,包含:
1.  登录认证与权限校验体系
2.  工作台、短剧、用户、角色、人员、日志等全业务模块
3.  响应式布局与通用样式组件
4.  菜单动态过滤与路由权限控制
5.  移除了README中冗余的权限管理菜单项
This commit is contained in:
2026-07-01 15:24:13 +08:00
parent 6722752d5e
commit 51e26025c6
27 changed files with 1364 additions and 1282 deletions

78
src/layout/menu.tsx Normal file
View File

@@ -0,0 +1,78 @@
import type { ReactNode } from 'react';
import { Menu } from '@arco-design/web-react';
import {
IconApps,
IconDashboard,
IconFile,
IconSettings,
IconUser,
IconVideoCamera,
} from '@arco-design/web-react/icon';
import type { AdminProfile } from '../api/types';
import { hasPermissions } from '../utils/permission';
export type MenuConfig = {
key: string;
label: string;
icon?: ReactNode;
requiredPermissions?: string[];
children?: MenuConfig[];
};
export const SYSTEM_MENU_KEY = '/system';
export const menuItems: MenuConfig[] = [
{ key: '/dashboard', label: '工作台', icon: <IconDashboard /> },
{ key: '/dramas', label: '短剧管理', icon: <IconVideoCamera />, requiredPermissions: ['drama:read'] },
{ key: '/users', label: '用户管理', icon: <IconUser />, requiredPermissions: ['user:read'] },
{
key: SYSTEM_MENU_KEY,
label: '系统管理',
icon: <IconSettings />,
children: [
{ key: '/roles', label: '角色管理', icon: <IconApps />, requiredPermissions: ['role:read'] },
{ key: '/personnel', label: '人员管理', icon: <IconUser />, requiredPermissions: ['admin-user:read'] },
{ key: '/profile', label: '个人中心', icon: <IconUser /> },
{ key: '/logs', label: '日志管理', icon: <IconFile />, requiredPermissions: ['log:read'] },
],
},
];
export function filterMenuItems(items: MenuConfig[], profile: AdminProfile | null): MenuConfig[] {
return items
.map((item) => {
if (item.children) {
const children = filterMenuItems(item.children, profile);
return children.length ? { ...item, children } : null;
}
return hasPermissions(profile, item.requiredPermissions) ? item : null;
})
.filter((item): item is MenuConfig => Boolean(item));
}
export function findCurrentMenu(pathname: string) {
for (const item of menuItems) {
if (item.children) {
const child = item.children.find((childItem) => pathname.startsWith(childItem.key));
if (child) {
return { item: child, parent: item };
}
}
if (pathname.startsWith(item.key)) {
return { item };
}
}
return undefined;
}
export function renderMenuItem(item: MenuConfig) {
if (item.children) {
return (
<Menu.SubMenu key={item.key} title={<span>{item.icon}{item.label}</span>}>
{item.children.map((child) => renderMenuItem(child))}
</Menu.SubMenu>
);
}
return <Menu.Item key={item.key}>{item.icon}{item.label}</Menu.Item>;
}