feat(web): 多主题系统 — 4 套主题 + CSS 变量 + Ant Design 动态主题
- CSS 变量层: :root 默认 blue, [data-theme] 覆盖 warm/dark/emerald - Ant Design: ConfigProvider 按 ThemeName 切换 token + algorithm - ThemeSwitcher: 下拉面板含 4 主题色块预览 + localStorage 持久化 - useThemeMode: 从 store 读取主题名替代色值比对(修复 33 页面暗色失效) - index.html: 添加 Noto Serif SC 字体(warm 主题衬线标题)
This commit is contained in:
@@ -12,8 +12,6 @@ import {
|
||||
LogoutOutlined,
|
||||
MessageOutlined,
|
||||
SearchOutlined,
|
||||
BulbOutlined,
|
||||
BulbFilled,
|
||||
AppstoreOutlined,
|
||||
TeamOutlined,
|
||||
TableOutlined,
|
||||
@@ -39,6 +37,7 @@ import { usePluginStore } from '../stores/plugin';
|
||||
import type { PluginMenuGroup } from '../stores/plugin';
|
||||
import { getMenusForUser, type MenuInfo } from '../api/menus';
|
||||
import NotificationPanel from '../components/NotificationPanel';
|
||||
import ThemeSwitcher from '../components/ThemeSwitcher';
|
||||
|
||||
const { Header, Sider, Content, Footer } = Layout;
|
||||
|
||||
@@ -345,7 +344,7 @@ const DynamicMenuSection = memo(function DynamicMenuSection({
|
||||
});
|
||||
|
||||
export default function MainLayout({ children }: { children: React.ReactNode }) {
|
||||
const { sidebarCollapsed, toggleSidebar, theme: themeMode, setTheme } = useAppStore();
|
||||
const { sidebarCollapsed, toggleSidebar } = useAppStore();
|
||||
const { user, logout } = useAuthStore();
|
||||
const pluginMenuItems = usePluginStore((s) => s.pluginMenuItems);
|
||||
const pluginMenuGroups = usePluginStore((s) => s.pluginMenuGroups);
|
||||
@@ -413,24 +412,23 @@ export default function MainLayout({ children }: { children: React.ReactNode })
|
||||
];
|
||||
|
||||
const sidebarWidth = sidebarCollapsed ? 72 : 240;
|
||||
const isDark = themeMode === 'dark';
|
||||
|
||||
return (
|
||||
<Layout style={{ minHeight: '100vh' }}>
|
||||
{/* 现代深色侧边栏 */}
|
||||
{/* 侧边栏 */}
|
||||
<Sider
|
||||
trigger={null}
|
||||
collapsible
|
||||
collapsed={sidebarCollapsed}
|
||||
width={240}
|
||||
collapsedWidth={72}
|
||||
className={isDark ? 'erp-sider-dark' : 'erp-sider-dark erp-sider-default'}
|
||||
className="erp-sider-dark"
|
||||
>
|
||||
{/* Logo 区域 */}
|
||||
<div className="erp-sidebar-logo" onClick={() => navigate('/')}>
|
||||
<div className="erp-sidebar-logo-icon">E</div>
|
||||
<div className="erp-sidebar-logo-icon">H</div>
|
||||
{!sidebarCollapsed && (
|
||||
<span className="erp-sidebar-logo-text">ERP Platform</span>
|
||||
<span className="erp-sidebar-logo-text">HMS 健康</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -469,22 +467,22 @@ export default function MainLayout({ children }: { children: React.ReactNode })
|
||||
|
||||
{/* 右侧主区域 */}
|
||||
<Layout
|
||||
className={`erp-main-layout ${isDark ? 'erp-main-layout-dark' : 'erp-main-layout-light'}`}
|
||||
className="erp-main-layout"
|
||||
style={{ marginLeft: sidebarWidth }}
|
||||
>
|
||||
{/* 顶部导航栏 */}
|
||||
<Header className={`erp-header ${isDark ? 'erp-header-dark' : 'erp-header-light'}`}>
|
||||
<Header className="erp-header">
|
||||
{/* 左侧:折叠按钮 + 标题 */}
|
||||
<Space size="middle" style={{ alignItems: 'center' }}>
|
||||
<div className="erp-header-btn" onClick={toggleSidebar}>
|
||||
{sidebarCollapsed ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />}
|
||||
</div>
|
||||
<span className={`erp-header-title ${isDark ? 'erp-text-dark' : 'erp-text-light'}`}>
|
||||
<span className="erp-header-title">
|
||||
{headerTitle}
|
||||
</span>
|
||||
</Space>
|
||||
|
||||
{/* 右侧:搜索 + 通知 + 主题切换 + 用户 */}
|
||||
{/* 右侧:搜索 + 主题切换 + 通知 + 用户 */}
|
||||
<Space size={4} style={{ alignItems: 'center' }}>
|
||||
<Tooltip title="搜索">
|
||||
<div className="erp-header-btn">
|
||||
@@ -492,15 +490,11 @@ export default function MainLayout({ children }: { children: React.ReactNode })
|
||||
</div>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip title={isDark ? '切换亮色模式' : '切换暗色模式'}>
|
||||
<div className="erp-header-btn" onClick={() => setTheme(isDark ? 'blue' : 'dark')}>
|
||||
{isDark ? <BulbFilled style={{ fontSize: 16 }} /> : <BulbOutlined style={{ fontSize: 16 }} />}
|
||||
</div>
|
||||
</Tooltip>
|
||||
<ThemeSwitcher />
|
||||
|
||||
<NotificationPanel />
|
||||
|
||||
<div className={`erp-header-divider ${isDark ? 'erp-header-divider-dark' : 'erp-header-divider-light'}`} />
|
||||
<div className="erp-header-divider" />
|
||||
|
||||
<Dropdown menu={{ items: userMenuItems }} placement="bottomRight" trigger={['click']}>
|
||||
<div className="erp-header-user">
|
||||
@@ -511,7 +505,7 @@ export default function MainLayout({ children }: { children: React.ReactNode })
|
||||
{(user?.display_name?.[0] || user?.username?.[0] || 'U').toUpperCase()}
|
||||
</Avatar>
|
||||
{!sidebarCollapsed && (
|
||||
<span className={`erp-user-name ${isDark ? 'erp-text-dark-secondary' : 'erp-text-light-secondary'}`}>
|
||||
<span className="erp-user-name">
|
||||
{user?.display_name || user?.username || 'User'}
|
||||
</span>
|
||||
)}
|
||||
@@ -526,7 +520,7 @@ export default function MainLayout({ children }: { children: React.ReactNode })
|
||||
</Content>
|
||||
|
||||
{/* 底部 */}
|
||||
<Footer className={`erp-footer ${isDark ? 'erp-footer-dark' : 'erp-footer-light'}`}>
|
||||
<Footer className="erp-footer">
|
||||
HMS 健康管理平台
|
||||
</Footer>
|
||||
</Layout>
|
||||
|
||||
Reference in New Issue
Block a user