22301014 | bc4616f | 2025-06-03 16:59:44 +0800 | [diff] [blame] | 1 | import { Outlet, useLocation, useNavigate } from 'react-router'; |
22301014 | b1477f7 | 2025-06-07 22:54:40 +0800 | [diff] [blame^] | 2 | import { Layout, Menu, Dropdown, Button, Flex } from 'antd'; |
| 3 | import { HomeOutlined, AppstoreOutlined, DownOutlined } from '@ant-design/icons'; |
| 4 | import { useEffect, useMemo } from 'react'; |
| 5 | import logo from "./assets/logo.png"; |
| 6 | import { useAppDispatch, useAppSelector } from './store/hooks'; |
| 7 | import { getUserInfo } from './feature/user/userSlice'; |
| 8 | import { logout } from './feature/auth/authSlice'; |
22301014 | bc4616f | 2025-06-03 16:59:44 +0800 | [diff] [blame] | 9 | const { Header } = Layout; |
| 10 | |
| 11 | const AppLayout = () => { |
| 12 | const location = useLocation(); |
| 13 | const navigate = useNavigate(); |
22301014 | b1477f7 | 2025-06-07 22:54:40 +0800 | [diff] [blame^] | 14 | const userState = useAppSelector(state => state.user); |
| 15 | const dispatch = useAppDispatch(); |
| 16 | |
| 17 | useEffect(() => { |
| 18 | dispatch(getUserInfo()) |
| 19 | }, [dispatch]) |
| 20 | |
| 21 | // 判断是否在登录、注册或找回密码页面 |
| 22 | const isAuthPage = useMemo(() => { |
| 23 | return ['/login', '/register', '/forget'].includes(location.pathname); |
| 24 | }, [location.pathname]); |
| 25 | |
22301014 | bc4616f | 2025-06-03 16:59:44 +0800 | [diff] [blame] | 26 | // 导航项配置 |
| 27 | const menuItems = [ |
| 28 | { |
| 29 | key: 'home', |
| 30 | label: '主页', |
| 31 | icon: <HomeOutlined />, |
| 32 | path: '/', |
| 33 | }, |
| 34 | { |
| 35 | key: 'tasks', |
| 36 | label: '任务清单', |
| 37 | icon: <AppstoreOutlined />, |
| 38 | path: '/tasks', |
| 39 | }, |
| 40 | ]; |
| 41 | |
22301014 | b1477f7 | 2025-06-07 22:54:40 +0800 | [diff] [blame^] | 42 | // 处理登出逻辑 |
| 43 | const handleLogout = () => { |
| 44 | dispatch(logout()) |
| 45 | navigate('/login'); // 重定向到登录页 |
| 46 | }; |
| 47 | |
| 48 | // 下拉菜单内容 |
| 49 | const dropdownMenuItems = [ |
| 50 | { |
| 51 | key: 'profile', |
| 52 | label: '个人中心', |
| 53 | onClick: () => navigate('/profile'), |
| 54 | }, |
| 55 | { |
| 56 | key: 'logout', |
| 57 | label: '登出', |
| 58 | onClick: handleLogout, |
| 59 | }, |
| 60 | ]; |
| 61 | |
22301014 | bc4616f | 2025-06-03 16:59:44 +0800 | [diff] [blame] | 62 | return ( |
| 63 | <Layout style={{ minHeight: '100vh', width: '100%' }}> |
22301014 | b1477f7 | 2025-06-07 22:54:40 +0800 | [diff] [blame^] | 64 | <Header className="header" style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}> |
| 65 | {/* logo */} |
| 66 | <Flex justify='center' align='center'> |
| 67 | <img src={logo} alt="Logo" height='48px' /> |
| 68 | <div style={{ color: 'white', marginLeft: '10px' }}> |
| 69 | 创驿 |
| 70 | </div> |
| 71 | </Flex> |
| 72 | |
| 73 | <div style={{ |
| 74 | height: '30px', |
| 75 | width: '1px', |
| 76 | backgroundColor: 'white', |
| 77 | margin: '0 20px', |
| 78 | }}></div> |
| 79 | |
| 80 | {/* 中间导航菜单 */} |
22301014 | bc4616f | 2025-06-03 16:59:44 +0800 | [diff] [blame] | 81 | <Menu |
| 82 | mode="horizontal" |
22301014 | b1477f7 | 2025-06-07 22:54:40 +0800 | [diff] [blame^] | 83 | theme="dark" |
22301014 | bc4616f | 2025-06-03 16:59:44 +0800 | [diff] [blame] | 84 | selectedKeys={[location.pathname === '/' ? 'home' : location.pathname.slice(1)]} |
| 85 | items={menuItems.map(item => ({ |
| 86 | ...item, |
| 87 | onClick: () => navigate(item.path), |
| 88 | }))} |
22301014 | b1477f7 | 2025-06-07 22:54:40 +0800 | [diff] [blame^] | 89 | style={{ flex: 1 }} |
22301014 | bc4616f | 2025-06-03 16:59:44 +0800 | [diff] [blame] | 90 | /> |
22301014 | b1477f7 | 2025-06-07 22:54:40 +0800 | [diff] [blame^] | 91 | |
| 92 | {/* 右侧用户名和下拉菜单 */} |
| 93 | {!isAuthPage && ( |
| 94 | <div style={{ display: 'flex', alignItems: 'center', color: 'white' }}> |
| 95 | <span>{userState.username}</span> |
| 96 | <Dropdown |
| 97 | trigger={['click']} |
| 98 | menu={{ items: dropdownMenuItems }} |
| 99 | > |
| 100 | <Button type="text" icon={<DownOutlined />} style={{ marginLeft: '10px', color: 'white' }} /> |
| 101 | </Dropdown> |
| 102 | </div> |
| 103 | )} |
22301014 | bc4616f | 2025-06-03 16:59:44 +0800 | [diff] [blame] | 104 | </Header> |
| 105 | <Layout.Content style={{ padding: '24px' }}> |
| 106 | <Outlet /> |
| 107 | </Layout.Content> |
22301014 | b1477f7 | 2025-06-07 22:54:40 +0800 | [diff] [blame^] | 108 | <Layout.Footer style={{ textAlign: 'center' }}> |
| 109 | © 2025 创驿 - 愿做你创作路上的同行者 |
22301014 | bc4616f | 2025-06-03 16:59:44 +0800 | [diff] [blame] | 110 | </Layout.Footer> |
| 111 | </Layout> |
| 112 | ); |
| 113 | }; |
| 114 | |
22301014 | b1477f7 | 2025-06-07 22:54:40 +0800 | [diff] [blame^] | 115 | export default AppLayout; |