chore: 📌 优化后台风格显示

This commit is contained in:
Stev_Wang
2026-01-03 20:11:05 +08:00
parent a950d1d526
commit 5b8999b188
5 changed files with 172 additions and 27 deletions

View File

@@ -1,4 +1,4 @@
import { useState } from 'react';
import { useState, useMemo } from 'react';
import { Layout, Menu, Button, theme, App } from 'antd';
import {
MenuFoldOutlined,
@@ -6,9 +6,12 @@ import {
DashboardOutlined,
SettingOutlined,
LogoutOutlined,
SunOutlined,
MoonOutlined,
} from '@ant-design/icons';
import { Outlet, useNavigate, useLocation } from 'react-router-dom';
import { useAuthStore } from '../stores/authStore';
import { useThemeStore } from '../stores/themeStore';
import { adminAuthService } from '../services/adminAuthService';
const { Header, Sider, Content, Footer } = Layout;
@@ -23,6 +26,16 @@ const AdminLayout = () => {
const adminUser = useAuthStore((state) => state.adminUser);
const logout = useAuthStore((state) => state.logout);
const { message } = App.useApp();
const { themeMode, toggleTheme } = useThemeStore();
// 根据当前路径计算应该展开的菜单
const openKeys = useMemo(() => {
const path = location.pathname;
if (path.startsWith('/admin/users')) {
return ['user'];
}
return [];
}, [location.pathname]);
const handleLogout = async () => {
try {
@@ -56,26 +69,34 @@ const AdminLayout = () => {
return (
<Layout style={{ minHeight: '100vh' }}>
<Sider trigger={null} collapsible collapsed={collapsed}>
<Sider
trigger={null}
collapsible
collapsed={collapsed}
style={{
background: themeMode === 'dark' ? '#001529' : '#ffffff',
}}
>
<div
style={{
height: 32,
margin: 16,
background: 'rgba(255, 255, 255, 0.2)',
background: themeMode === 'dark' ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.05)',
borderRadius: 6,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
color: 'white',
color: themeMode === 'dark' ? 'white' : '#1890ff',
fontWeight: 'bold',
}}
>
{collapsed ? '运营' : '运营管理系统'}
</div>
<Menu
theme="dark"
theme={themeMode === 'dark' ? 'dark' : 'light'}
mode="inline"
selectedKeys={[location.pathname]}
openKeys={openKeys}
items={menuItems}
onClick={({ key }) => navigate(key)}
/>
@@ -99,14 +120,23 @@ const AdminLayout = () => {
fontSize: '16px',
width: 64,
height: 64,
outline: 'none',
}}
/>
<div style={{ display: 'flex', alignItems: 'center', gap: 16 }}>
<Button
type="text"
icon={themeMode === 'dark' ? <SunOutlined /> : <MoonOutlined />}
onClick={toggleTheme}
style={{ outline: 'none' }}
title={themeMode === 'dark' ? '切换到亮色主题' : '切换到暗色主题'}
/>
<span>, {adminUser?.username}</span>
<Button
type="text"
icon={<LogoutOutlined />}
onClick={handleLogout}
style={{ outline: 'none' }}
>
退
</Button>
@@ -123,7 +153,12 @@ const AdminLayout = () => {
>
<Outlet />
</Content>
<Footer style={{ textAlign: 'center' }}>
<Footer
style={{
textAlign: 'center',
background: themeMode === 'dark' ? '#001529' : '#ffffff',
}}
>
西 ©2025 Created by JGE
</Footer>
</Layout>

View File

@@ -0,0 +1,34 @@
import { ReactNode, useMemo } from 'react';
import { ConfigProvider, theme } from 'antd';
import zhCN from 'antd/locale/zh_CN';
import { useThemeStore } from '../stores/themeStore';
import { getThemeByMode } from '../theme';
interface ThemeProviderProps {
children: ReactNode;
}
// 主题提供者组件
export const ThemeProvider = ({ children }: ThemeProviderProps) => {
const { themeMode } = useThemeStore();
// 根据主题模式获取主题配置和算法
const currentTheme = useMemo(() => {
const customTheme = getThemeByMode(themeMode);
const algorithm = themeMode === 'dark' ? theme.darkAlgorithm : theme.defaultAlgorithm;
return {
algorithm,
...customTheme,
};
}, [themeMode]);
return (
<ConfigProvider
locale={zhCN}
theme={currentTheme}
>
{children}
</ConfigProvider>
);
};

View File

@@ -1,24 +1,17 @@
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import { RouterProvider } from 'react-router-dom';
import { ConfigProvider, App, theme } from 'antd';
import zhCN from 'antd/locale/zh_CN';
import { App } from 'antd';
import './index.css';
import router from './router';
import { appTheme } from './theme';
import { ThemeProvider } from './components/ThemeProvider';
createRoot(document.getElementById('root')!).render(
<StrictMode>
<ConfigProvider
locale={zhCN}
theme={{
algorithm: theme.defaultAlgorithm,
...appTheme,
}}
>
<ThemeProvider>
<App>
<RouterProvider router={router} />
</App>
</ConfigProvider>
</ThemeProvider>
</StrictMode>,
);

View File

@@ -0,0 +1,34 @@
import { create } from 'zustand';
// 主题类型
export type ThemeMode = 'light' | 'dark';
// 从 localStorage 读取主题模式
const getInitialThemeMode = (): ThemeMode => {
const savedTheme = localStorage.getItem('adminThemeMode');
if (savedTheme === 'light' || savedTheme === 'dark') {
return savedTheme;
}
return 'dark'; // 默认暗色主题
};
// 主题状态接口
interface ThemeState {
themeMode: ThemeMode;
toggleTheme: () => void;
setTheme: (mode: ThemeMode) => void;
}
// 主题状态管理
export const useThemeStore = create<ThemeState>((set) => ({
themeMode: getInitialThemeMode(),
toggleTheme: () => set((state) => {
const newMode = state.themeMode === 'light' ? 'dark' : 'light';
localStorage.setItem('adminThemeMode', newMode);
return { themeMode: newMode };
}),
setTheme: (mode) => {
localStorage.setItem('adminThemeMode', mode);
set({ themeMode: mode });
},
}));

View File

@@ -1,8 +1,9 @@
// 全局主题配置
import type { ThemeConfig } from 'antd';
import type { ThemeMode } from '../stores/themeStore';
// 自定义主题配置
export const appTheme: ThemeConfig = {
// 亮色主题配置
export const lightTheme: ThemeConfig = {
token: {
// 主色调
colorPrimary: '#1890ff',
@@ -22,18 +23,66 @@ export const appTheme: ThemeConfig = {
components: {
// Layout 组件主题
Layout: {
headerBg: '#001529', // 顶部导航和侧边栏背景色
footerBg: '#001529', // 页脚背景色
siderBg: '#001529', // 侧边栏背景色
headerBg: '#ffffff', // 顶部导航背景色(亮色)
footerBg: '#ffffff', // 页脚背景色(亮色)
siderBg: '#ffffff', // 侧边栏背景色(亮色)
},
// Menu 组件主题
Menu: {
darkItemSelectedBg: '#1890ff', // 菜单激活背景色
darkItemHoverBg: 'rgba(24, 144, 255, 0.2)', // 菜单悬停背景色
darkItemColor: 'rgba(255, 255, 255, 0.65)', // 菜单项文字颜色
darkItemSelectedColor: '#fff', // 菜单激活文字颜色
darkItemHoverColor: '#fff', // 菜单悬停文字颜色
itemSelectedBg: '#e6f7ff', // 菜单激活背景色(亮色)
itemHoverBg: 'rgba(24, 144, 255, 0.1)', // 菜单悬停背景色(亮色)
itemColor: 'rgba(0, 0, 0, 0.65)', // 菜单项文字颜色(亮色)
itemSelectedColor: '#1890ff', // 菜单激活文字颜色(亮色)
itemHoverColor: '#1890ff', // 菜单悬停文字颜色(亮色)
itemSelectedStyle: {
boxShadow: 'none', // 去除菜单激活项的阴影
},
},
},
};
// 暗色主题配置
export const darkTheme: ThemeConfig = {
token: {
// 主色调
colorPrimary: '#1890ff',
colorSuccess: '#52c41a',
colorWarning: '#faad14',
colorError: '#ff4d4f',
colorInfo: '#1890ff',
// 字体设置
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',
fontSize: 14,
// 圆角
borderRadius: 3,
},
components: {
// Layout 组件主题
Layout: {
headerBg: '#001529', // 顶部导航和侧边栏背景色(暗色)
footerBg: '#001529', // 页脚背景色(暗色)
siderBg: '#001529', // 侧边栏背景色(暗色)
},
// Menu 组件主题
Menu: {
darkItemSelectedBg: '#1890ff', // 菜单激活背景色(暗色)
darkItemHoverBg: 'rgba(24, 144, 255, 0.2)', // 菜单悬停背景色(暗色)
darkItemColor: 'rgba(255, 255, 255, 0.65)', // 菜单项文字颜色(暗色)
darkItemSelectedColor: '#fff', // 菜单激活文字颜色(暗色)
darkItemHoverColor: '#fff', // 菜单悬停文字颜色(暗色)
},
},
};
// 根据主题模式获取主题配置
export const getThemeByMode = (mode: ThemeMode): ThemeConfig => {
return mode === 'light' ? lightTheme : darkTheme;
};
// 默认主题配置(向后兼容)
export const appTheme: ThemeConfig = darkTheme;