Initial commit

This commit is contained in:
2026-02-06 14:06:49 +08:00
commit 5fc7b33b3b
28 changed files with 5004 additions and 0 deletions

View File

@@ -0,0 +1,148 @@
import { Outlet, useNavigate, useLocation } from 'react-router-dom';
import { Layout, Menu, Dropdown, Avatar, message, Modal } from 'antd';
import {
DashboardOutlined,
QrcodeOutlined,
TeamOutlined,
SearchOutlined,
UserOutlined,
LogoutOutlined,
LockOutlined,
ExclamationCircleOutlined,
} from '@ant-design/icons';
import { authApi } from '@/services/api';
import './styles/AdminLayout.css';
import logo from '@/assets/img/logo.png?url';
const { Header, Sider, Content } = Layout;
function AdminLayout() {
const navigate = useNavigate();
const location = useLocation();
const user = authApi.getCurrentUser();
const menuItems = [
{
key: 'dashboard',
icon: <DashboardOutlined />,
label: '控制台',
onClick: () => navigate('/admin/dashboard'),
},
{
key: 'generate',
icon: <QrcodeOutlined />,
label: '生成二维码',
onClick: () => navigate('/admin/generate'),
},
{
key: 'manage',
icon: <TeamOutlined />,
label: '企业管理',
onClick: () => navigate('/admin/manage'),
},
{
key: 'query',
icon: <SearchOutlined />,
label: '序列号查询',
onClick: () => navigate('/admin/query'),
},
];
const handleLogout = () => {
Modal.confirm({
title: '确认退出',
icon: <ExclamationCircleOutlined />,
content: '您确定要退出登录吗?',
okText: '确定',
cancelText: '取消',
onOk: async () => {
try {
await authApi.logout();
message.success('已退出登录');
navigate('/login');
} catch (error) {
message.error('退出失败');
}
},
});
};
const userMenuItems = [
{
key: 'profile',
icon: <UserOutlined />,
label: '用户资料',
onClick: () => navigate('/admin/profile'),
},
{
key: 'changePassword',
icon: <LockOutlined />,
label: '修改密码',
onClick: () => {
message.info('修改密码功能即将上线');
},
},
{
type: 'divider' as const,
},
{
key: 'logout',
icon: <LogoutOutlined />,
label: '退出登录',
onClick: handleLogout,
danger: true,
},
];
const getSelectedKey = () => {
const path = location.pathname;
if (path.includes('/dashboard')) return 'dashboard';
if (path.includes('/generate')) return 'generate';
if (path.includes('/manage')) return 'manage';
if (path.includes('/query')) return 'query';
if (path.includes('/profile')) return 'profile';
return 'dashboard';
};
return (
<Layout className="admin-layout">
<Sider
className="admin-sider"
width={256}
>
<div className="logo">
<img src={logo} alt="Logo" style={{ height: '40px' }} />
</div>
<Menu
theme="light"
mode="inline"
selectedKeys={[getSelectedKey()]}
items={menuItems}
className="admin-menu"
/>
</Sider>
<Layout>
<Header className="admin-header">
<div className="header-title">
{menuItems.find((item) => item.key === getSelectedKey())?.label}
</div>
<div className="header-right">
<Dropdown menu={{ items: userMenuItems }} placement="bottomRight">
<div className="user-info">
<Avatar icon={<UserOutlined />} />
<span className="username">{user?.name || user?.username}</span>
</div>
</Dropdown>
</div>
</Header>
<Content className="admin-content">
<Outlet />
</Content>
</Layout>
</Layout>
);
}
export default AdminLayout;