feat: complete Phase 1 infrastructure

- erp-core: error types, shared types, event bus, ErpModule trait
- erp-server: config loading, database/Redis connections, migrations
- erp-server/migration: tenants table with SeaORM
- apps/web: Vite + React 18 + TypeScript + Ant Design 5 + TailwindCSS
- Web frontend: main layout with sidebar, header, routing
- Docker: PostgreSQL 16 + Redis 7 development environment
- All workspace crates compile successfully (cargo check passes)
This commit is contained in:
iven
2026-04-11 01:07:31 +08:00
parent eb856b1d73
commit 5901ee82f0
36 changed files with 4542 additions and 221 deletions

View File

@@ -0,0 +1,87 @@
import { Layout, Menu, theme, Button, Avatar, Badge, Space } from 'antd';
import {
HomeOutlined,
UserOutlined,
SafetyOutlined,
BellOutlined,
SettingOutlined,
MenuFoldOutlined,
MenuUnfoldOutlined,
} from '@ant-design/icons';
import { useAppStore } from '../stores/app';
const { Header, Sider, Content, Footer } = Layout;
const menuItems = [
{ key: '/', icon: <HomeOutlined />, label: '首页' },
{ key: '/users', icon: <UserOutlined />, label: '用户管理' },
{ key: '/roles', icon: <SafetyOutlined />, label: '权限管理' },
{ key: '/settings', icon: <SettingOutlined />, label: '系统设置' },
];
export default function MainLayout({ children }: { children: React.ReactNode }) {
const { sidebarCollapsed, toggleSidebar, tenantName } = useAppStore();
const { token } = theme.useToken();
return (
<Layout style={{ minHeight: '100vh' }}>
<Sider trigger={null} collapsible collapsed={sidebarCollapsed} width={220}>
<div
style={{
height: 48,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
color: '#fff',
fontSize: sidebarCollapsed ? 16 : 18,
fontWeight: 'bold',
}}
>
{sidebarCollapsed ? 'E' : 'ERP Platform'}
</div>
<Menu theme="dark" mode="inline" items={menuItems} defaultSelectedKeys={['/']} />
</Sider>
<Layout>
<Header
style={{
padding: '0 16px',
background: token.colorBgContainer,
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
borderBottom: `1px solid ${token.colorBorderSecondary}`,
}}
>
<Space>
<Button
type="text"
icon={sidebarCollapsed ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />}
onClick={toggleSidebar}
/>
</Space>
<Space size="middle">
<Badge count={5}>
<BellOutlined style={{ fontSize: 18 }} />
</Badge>
<Avatar icon={<UserOutlined />} />
<span>Admin</span>
</Space>
</Header>
<Content
style={{
margin: 16,
padding: 24,
background: token.colorBgContainer,
borderRadius: token.borderRadiusLG,
minHeight: 280,
}}
>
{children}
</Content>
<Footer style={{ textAlign: 'center', padding: '8px 16px' }}>
{tenantName || 'ERP Platform'} · v0.1.0
</Footer>
</Layout>
</Layout>
);
}