feat: 添加MSW模拟服务和数据源集成
refactor: 重构页面组件移除冗余Layout组件 feat: 实现WebSocket和事件总线系统 feat: 添加队列和调度系统 docs: 更新架构文档和服务映射 style: 清理重复接口定义使用数据源 chore: 更新依赖项配置 feat: 添加运行时系统和领域引导 ci: 配置ESLint边界检查规则 build: 添加Redis和WebSocket依赖 test: 添加MSW浏览器环境入口 perf: 优化数据获取逻辑使用统一数据源 fix: 修复类型定义和状态管理问题
This commit is contained in:
337
dashboard/src/layouts/index.tsx
Normal file
337
dashboard/src/layouts/index.tsx
Normal file
@@ -0,0 +1,337 @@
|
||||
// 全局布局组件 - 包含左侧菜单和头部
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Layout, Menu, Typography, Avatar, Dropdown, Badge, Space } from 'antd';
|
||||
import {
|
||||
DashboardOutlined,
|
||||
ShoppingOutlined,
|
||||
FileTextOutlined,
|
||||
UserOutlined,
|
||||
TruckOutlined,
|
||||
AlertOutlined,
|
||||
AuditOutlined,
|
||||
DollarOutlined,
|
||||
BarChartOutlined,
|
||||
SettingOutlined,
|
||||
TeamOutlined,
|
||||
MenuFoldOutlined,
|
||||
MenuUnfoldOutlined,
|
||||
BellOutlined,
|
||||
DownOutlined,
|
||||
ShopOutlined,
|
||||
ScheduleOutlined,
|
||||
WalletOutlined,
|
||||
SafetyCertificateOutlined,
|
||||
GlobalOutlined,
|
||||
TrophyOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import { Link, useLocation, history, Outlet } from 'umi';
|
||||
|
||||
const { Header, Sider, Content } = Layout;
|
||||
const { Title, Text } = Typography;
|
||||
|
||||
// 菜单项配置
|
||||
const menuItems = [
|
||||
{
|
||||
key: '/',
|
||||
icon: <DashboardOutlined />,
|
||||
label: <Link to="/">首页</Link>,
|
||||
},
|
||||
{
|
||||
key: '/Product',
|
||||
icon: <ShoppingOutlined />,
|
||||
label: <Link to="/Product">商品管理</Link>,
|
||||
},
|
||||
{
|
||||
key: '/Orders',
|
||||
icon: <FileTextOutlined />,
|
||||
label: <Link to="/Orders">订单管理</Link>,
|
||||
},
|
||||
{
|
||||
key: '/Merchant',
|
||||
icon: <ShopOutlined />,
|
||||
label: <Link to="/Merchant">商户管理</Link>,
|
||||
},
|
||||
{
|
||||
key: '/TaskCenter',
|
||||
icon: <ScheduleOutlined />,
|
||||
label: <Link to="/TaskCenter">任务中心</Link>,
|
||||
},
|
||||
{
|
||||
key: '/Logistics',
|
||||
icon: <TruckOutlined />,
|
||||
label: <Link to="/Logistics">物流管理</Link>,
|
||||
},
|
||||
{
|
||||
key: '/AfterSales',
|
||||
icon: <AlertOutlined />,
|
||||
label: <Link to="/AfterSales">售后服务</Link>,
|
||||
},
|
||||
{
|
||||
key: '/Compliance',
|
||||
icon: <SafetyCertificateOutlined />,
|
||||
label: <Link to="/Compliance">合规管理</Link>,
|
||||
},
|
||||
{
|
||||
key: '/Blacklist',
|
||||
icon: <AuditOutlined />,
|
||||
label: <Link to="/Blacklist">黑名单管理</Link>,
|
||||
},
|
||||
{
|
||||
key: '/B2B',
|
||||
icon: <DollarOutlined />,
|
||||
label: <Link to="/B2B">B2B贸易</Link>,
|
||||
},
|
||||
{
|
||||
key: '/Ad',
|
||||
icon: <BarChartOutlined />,
|
||||
label: <Link to="/Ad">广告管理</Link>,
|
||||
},
|
||||
{
|
||||
key: '/Analytics',
|
||||
icon: <GlobalOutlined />,
|
||||
label: <Link to="/Analytics">数据分析</Link>,
|
||||
},
|
||||
{
|
||||
key: '/Leaderboard',
|
||||
icon: <TrophyOutlined />,
|
||||
label: <Link to="/Leaderboard">收益排行榜</Link>,
|
||||
},
|
||||
{
|
||||
key: '/StrategyMarketplace',
|
||||
icon: <ShopOutlined />,
|
||||
label: <Link to="/StrategyMarketplace">策略市场</Link>,
|
||||
},
|
||||
{
|
||||
key: '/Finance',
|
||||
icon: <WalletOutlined />,
|
||||
label: <Link to="/Finance">财务管理</Link>,
|
||||
},
|
||||
{
|
||||
key: '/User',
|
||||
icon: <UserOutlined />,
|
||||
label: <Link to="/User">用户管理</Link>,
|
||||
},
|
||||
{
|
||||
key: '/Role',
|
||||
icon: <TeamOutlined />,
|
||||
label: <Link to="/Role">角色管理</Link>,
|
||||
},
|
||||
{
|
||||
key: '/Settings',
|
||||
icon: <SettingOutlined />,
|
||||
label: <Link to="/Settings">系统设置</Link>,
|
||||
},
|
||||
];
|
||||
|
||||
// 用户菜单项
|
||||
const userMenuItems = [
|
||||
{
|
||||
key: 'profile',
|
||||
label: '个人中心',
|
||||
},
|
||||
{
|
||||
key: 'settings',
|
||||
label: '账号设置',
|
||||
},
|
||||
{
|
||||
type: 'divider',
|
||||
},
|
||||
{
|
||||
key: 'logout',
|
||||
label: '退出登录',
|
||||
},
|
||||
];
|
||||
|
||||
const MainLayout: React.FC = () => {
|
||||
const location = useLocation();
|
||||
const [collapsed, setCollapsed] = useState(false);
|
||||
const [selectedKeys, setSelectedKeys] = useState<string[]>(['/']);
|
||||
|
||||
// 根据当前路径设置选中的菜单项
|
||||
useEffect(() => {
|
||||
const pathname = location.pathname;
|
||||
// 找到匹配的菜单项
|
||||
const matchedItem = menuItems.find(item => {
|
||||
if (item.key === '/') {
|
||||
return pathname === '/';
|
||||
}
|
||||
return pathname.startsWith(item.key as string);
|
||||
});
|
||||
if (matchedItem) {
|
||||
setSelectedKeys([matchedItem.key as string]);
|
||||
}
|
||||
}, [location.pathname]);
|
||||
|
||||
// 从 localStorage 读取菜单折叠状态
|
||||
useEffect(() => {
|
||||
const savedCollapsed = localStorage.getItem('sidebar_collapsed');
|
||||
if (savedCollapsed !== null) {
|
||||
setCollapsed(savedCollapsed === 'true');
|
||||
}
|
||||
}, []);
|
||||
|
||||
// 保存菜单折叠状态到 localStorage
|
||||
const handleCollapse = (value: boolean) => {
|
||||
setCollapsed(value);
|
||||
localStorage.setItem('sidebar_collapsed', String(value));
|
||||
};
|
||||
|
||||
const handleUserMenuClick = ({ key }: { key: string }) => {
|
||||
if (key === 'logout') {
|
||||
// 处理登出逻辑
|
||||
localStorage.removeItem('token');
|
||||
history.push('/Auth/LoginPage');
|
||||
} else if (key === 'profile') {
|
||||
history.push('/Settings/ProfileSettings');
|
||||
} else if (key === 'settings') {
|
||||
history.push('/Settings');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Layout style={{ minHeight: '100vh' }}>
|
||||
{/* 左侧菜单栏 */}
|
||||
<Sider
|
||||
trigger={null}
|
||||
collapsible
|
||||
collapsed={collapsed}
|
||||
collapsedWidth={80}
|
||||
width={220}
|
||||
style={{
|
||||
background: '#001529',
|
||||
position: 'fixed',
|
||||
left: 0,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
zIndex: 100,
|
||||
boxShadow: '2px 0 8px rgba(0, 0, 0, 0.15)',
|
||||
}}
|
||||
>
|
||||
{/* Logo 区域 */}
|
||||
<div
|
||||
style={{
|
||||
height: '64px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: collapsed ? 'center' : 'flex-start',
|
||||
padding: collapsed ? '0' : '0 24px',
|
||||
background: '#002140',
|
||||
borderBottom: '1px solid rgba(255, 255, 255, 0.1)',
|
||||
}}
|
||||
>
|
||||
{collapsed ? (
|
||||
<div style={{ color: '#fff', fontSize: '20px', fontWeight: 'bold' }}>C</div>
|
||||
) : (
|
||||
<Title level={4} style={{ color: '#fff', margin: 0, whiteSpace: 'nowrap' }}>
|
||||
Crawlful Hub
|
||||
</Title>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* 菜单 */}
|
||||
<Menu
|
||||
theme="dark"
|
||||
mode="inline"
|
||||
selectedKeys={selectedKeys}
|
||||
items={menuItems}
|
||||
style={{
|
||||
borderRight: 0,
|
||||
paddingTop: '8px',
|
||||
}}
|
||||
/>
|
||||
</Sider>
|
||||
|
||||
{/* 右侧内容区域 */}
|
||||
<Layout
|
||||
style={{
|
||||
marginLeft: collapsed ? 80 : 220,
|
||||
transition: 'all 0.2s',
|
||||
}}
|
||||
>
|
||||
{/* 顶部Header */}
|
||||
<Header
|
||||
style={{
|
||||
background: '#fff',
|
||||
padding: '0 24px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
boxShadow: '0 1px 4px rgba(0, 21, 41, 0.08)',
|
||||
position: 'sticky',
|
||||
top: 0,
|
||||
zIndex: 99,
|
||||
}}
|
||||
>
|
||||
{/* 左侧:折叠按钮 */}
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
cursor: 'pointer',
|
||||
padding: '8px',
|
||||
borderRadius: '4px',
|
||||
transition: 'background 0.3s',
|
||||
}}
|
||||
onClick={() => handleCollapse(!collapsed)}
|
||||
onMouseEnter={(e) => {
|
||||
e.currentTarget.style.background = '#f0f0f0';
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
e.currentTarget.style.background = 'transparent';
|
||||
}}
|
||||
>
|
||||
{collapsed ? <MenuUnfoldOutlined style={{ fontSize: '18px' }} /> : <MenuFoldOutlined style={{ fontSize: '18px' }} />}
|
||||
</div>
|
||||
|
||||
{/* 右侧:通知和用户 */}
|
||||
<Space size={24}>
|
||||
{/* 通知图标 */}
|
||||
<Badge count={5} size="small">
|
||||
<BellOutlined style={{ fontSize: '18px', cursor: 'pointer', color: '#666' }} />
|
||||
</Badge>
|
||||
|
||||
{/* 用户下拉菜单 */}
|
||||
<Dropdown
|
||||
menu={{ items: userMenuItems, onClick: handleUserMenuClick }}
|
||||
placement="bottomRight"
|
||||
>
|
||||
<Space style={{ cursor: 'pointer' }}>
|
||||
<Avatar style={{ backgroundColor: '#1890ff' }} icon={<UserOutlined />} />
|
||||
{!collapsed && (
|
||||
<>
|
||||
<Text strong>管理员</Text>
|
||||
<DownOutlined style={{ fontSize: '12px', color: '#999' }} />
|
||||
</>
|
||||
)}
|
||||
</Space>
|
||||
</Dropdown>
|
||||
</Space>
|
||||
</Header>
|
||||
|
||||
{/* 主内容区域 */}
|
||||
<Content
|
||||
style={{
|
||||
margin: '24px',
|
||||
padding: '24px',
|
||||
background: '#f0f2f5',
|
||||
minHeight: 280,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
background: '#fff',
|
||||
padding: '24px',
|
||||
borderRadius: '8px',
|
||||
minHeight: 'calc(100vh - 184px)',
|
||||
boxShadow: '0 1px 2px rgba(0, 0, 0, 0.06)',
|
||||
}}
|
||||
>
|
||||
<Outlet />
|
||||
</div>
|
||||
</Content>
|
||||
</Layout>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
export default MainLayout;
|
||||
Reference in New Issue
Block a user