Files
xiaoxia-saas/apps/web/src/components/layout/Sidebar.tsx
T
Xiaoxia AI 80a57ff0fe Phase 6: Complete admin pages (Analytics, Monitor, Logs) and Phase 7: Asset management foundation
Phase 6 completion:
- Add Analytics page with charts (user growth, revenue, retention)
- Add SystemMonitor page (CPU, memory, services health)
- Add LogViewer page (log search, filtering, details)
- Update sidebar navigation with Admin submenu
- Add recharts to package.json for data visualization

Phase 7 Day 1-2:
- Create Asset and AssetLibrary domain entities
- Define AssetRepository and AssetLibraryRepository interfaces
- Implement InMemory repositories for testing
- Implement PostgreSQL repository adapter
- Update SQLAlchemy models for assets and asset_libraries
- Add database migration script 004_asset_management.sql

Architecture: Strict Clean Architecture compliance
Testing: InMemory adapters ready for unit tests
Database: Migration script with indexes and foreign keys
2026-06-17 17:41:48 +08:00

142 lines
3.1 KiB
TypeScript

/**
* 侧边栏导航
*/
import React from 'react';
import { Layout, Menu } from 'antd';
import {
HomeOutlined,
AppstoreOutlined,
TeamOutlined,
CrownOutlined,
UserOutlined,
DashboardOutlined,
BarChartOutlined,
MonitorOutlined,
FileTextOutlined,
} from '@ant-design/icons';
import { useNavigate, useLocation } from 'react-router-dom';
import type { MenuProps } from 'antd';
const { Sider } = Layout;
interface SidebarProps {
collapsed: boolean;
}
const Sidebar: React.FC<SidebarProps> = ({ collapsed }) => {
const navigate = useNavigate();
const location = useLocation();
const menuItems: MenuProps['items'] = [
{
key: '/workspaces',
icon: <HomeOutlined />,
label: '工作空间',
onClick: () => navigate('/workspaces'),
},
{
key: '/projects',
icon: <AppstoreOutlined />,
label: '项目',
onClick: () => navigate('/projects'),
},
{
key: '/members',
icon: <TeamOutlined />,
label: '成员管理',
onClick: () => navigate('/members'),
},
{
key: '/subscription',
icon: <CrownOutlined />,
label: '订阅管理',
onClick: () => navigate('/subscription'),
},
{
key: '/admin',
icon: <DashboardOutlined />,
label: 'Admin',
children: [
{
key: '/admin',
icon: <DashboardOutlined />,
label: 'Dashboard',
onClick: () => navigate('/admin'),
},
{
key: '/admin/users',
icon: <TeamOutlined />,
label: '用户管理',
onClick: () => navigate('/admin/users'),
},
{
key: '/admin/analytics',
icon: <BarChartOutlined />,
label: '数据分析',
onClick: () => navigate('/admin/analytics'),
},
{
key: '/admin/monitor',
icon: <MonitorOutlined />,
label: '系统监控',
onClick: () => navigate('/admin/monitor'),
},
{
key: '/admin/logs',
icon: <FileTextOutlined />,
label: '日志查看',
onClick: () => navigate('/admin/logs'),
},
],
},
{
key: '/profile',
icon: <UserOutlined />,
label: '个人中心',
onClick: () => navigate('/profile'),
},
];
// 根据当前路径选中菜单项
const selectedKey = '/' + location.pathname.split('/')[1];
return (
<Sider
collapsible
collapsed={collapsed}
trigger={null}
width={200}
style={{
overflow: 'auto',
height: '100vh',
position: 'sticky',
left: 0,
top: 0,
bottom: 0,
}}
>
<div
style={{
height: 64,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
color: '#fff',
fontSize: '18px',
fontWeight: 'bold',
}}
>
{collapsed ? '🦐' : '小虾 SaaS'}
</div>
<Menu
theme="dark"
mode="inline"
selectedKeys={[selectedKey]}
items={menuItems}
/>
</Sider>
);
};
export default Sidebar;