feat: 实现前端管理后台(React + Vite + Ant Design + Zustand)

This commit is contained in:
2026-06-29 17:46:41 +06:00
parent da06866360
commit c714ea95ac
21 changed files with 1193 additions and 0 deletions
+93
View File
@@ -0,0 +1,93 @@
import { Layout as AntLayout, Menu, Dropdown, Space, Button, theme } from 'antd';
import {
VideoCameraOutlined,
SettingOutlined,
FileTextOutlined,
UserOutlined,
LogoutOutlined,
} from '@ant-design/icons';
import { Outlet, useLocation, useNavigate } from 'react-router-dom';
import { useAuthStore } from '../store/auth';
const { Header, Sider, Content } = AntLayout;
export default function Layout() {
const location = useLocation();
const navigate = useNavigate();
const { user, clearAuth } = useAuthStore();
const {
token: { colorBgContainer, borderRadiusLG },
} = theme.useToken();
const menuItems = [
{ key: '/videos', icon: <VideoCameraOutlined />, label: '视频库' },
{ key: '/accounts', icon: <SettingOutlined />, label: '账号配置' },
{ key: '/logs', icon: <FileTextOutlined />, label: '操作日志' },
];
const handleMenuClick = ({ key }: { key: string }) => {
navigate(key);
};
const handleLogout = () => {
clearAuth();
navigate('/login');
};
const userMenuItems = [
{ key: 'user', label: user?.username, disabled: true },
{ key: 'role', label: `角色: ${user?.role === 'admin' ? '管理员' : '只读'}`, disabled: true },
{ type: 'divider' as const },
{ key: 'logout', icon: <LogoutOutlined />, label: '退出登录', onClick: handleLogout },
];
return (
<AntLayout style={{ minHeight: '100vh' }}>
<Sider trigger={null} collapsible theme="light">
<div
style={{
height: 64,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
fontWeight: 'bold',
fontSize: 16,
}}
>
VOD
</div>
<Menu
mode="inline"
selectedKeys={[location.pathname]}
items={menuItems}
onClick={handleMenuClick}
/>
</Sider>
<AntLayout>
<Header style={{ padding: '0 24px', background: colorBgContainer }}>
<div style={{ display: 'flex', justifyContent: 'flex-end', alignItems: 'center', height: '100%' }}>
<Dropdown menu={{ items: userMenuItems }} placement="bottomRight">
<Button type="text">
<Space>
<UserOutlined />
{user?.username}
</Space>
</Button>
</Dropdown>
</div>
</Header>
<Content
style={{
margin: 24,
padding: 24,
background: colorBgContainer,
borderRadius: borderRadiusLG,
minHeight: 280,
}}
>
<Outlet />
</Content>
</AntLayout>
</AntLayout>
);
}