完成Work组件的界面和一些小修改
> 1. 修改优化路由守卫
> 2. 去除拦截器中的调试信息
> 3. 修改头部导航条下拉菜单的样式增加图标。
> 4. work组件现在使用mock数据
Change-Id: Ic602a35bb02e645a0d5253c5cbd12a68d70bfb33
diff --git a/src/AppLayout.tsx b/src/AppLayout.tsx
index 99765e6..ba15c74 100644
--- a/src/AppLayout.tsx
+++ b/src/AppLayout.tsx
@@ -1,26 +1,43 @@
+// src/AppLayout.tsx
+
+import React, { useEffect, useMemo } from 'react';
import { Outlet, useLocation, useNavigate } from 'react-router';
-import { Layout, Menu, Dropdown, Button, Flex } from 'antd';
-import { HomeOutlined, AppstoreOutlined, DownOutlined } from '@ant-design/icons';
-import { useEffect, useMemo } from 'react';
+import { Layout, Menu, Dropdown, Button, Flex, Space } from 'antd';
+import {
+ HomeOutlined,
+ AppstoreOutlined,
+ DownOutlined,
+ UserOutlined,
+ SettingOutlined,
+ LogoutOutlined
+} from '@ant-design/icons';
import logo from "./assets/logo.png";
import { useAppDispatch, useAppSelector } from './store/hooks';
import { getUserInfo } from './feature/user/userSlice';
import { logout } from './feature/auth/authSlice';
-const { Header } = Layout;
-const AppLayout = () => {
+const { Header, Content, Footer } = Layout;
+
+const AppLayout: React.FC = () => {
const location = useLocation();
const navigate = useNavigate();
- const userState = useAppSelector(state => state.user);
const dispatch = useAppDispatch();
- useEffect(() => {
- dispatch(getUserInfo())
- }, [dispatch])
+ // Redux状态
+ const { isAuth } = useAppSelector(state => state.auth);
+ const userState = useAppSelector(state => state.user);
- // 判断是否在登录、注册或找回密码页面
+ // 获取用户信息
+ useEffect(() => {
+ if (isAuth) {
+ dispatch(getUserInfo());
+ }
+ }, [dispatch, isAuth]);
+
+ // 判断是否在认证页面
const isAuthPage = useMemo(() => {
- return ['/login', '/register', '/forget'].includes(location.pathname);
+ const authPaths = ['/login', '/register', '/forget'];
+ return authPaths.includes(location.pathname);
}, [location.pathname]);
// 导航项配置
@@ -32,17 +49,24 @@
path: '/',
},
{
- key: 'tasks',
- label: '任务清单',
+ key: 'works',
+ label: '作品',
icon: <AppstoreOutlined />,
- path: '/tasks',
+ path: '/works',
},
];
+ // 获取当前选中的菜单项
+ const selectedKey = useMemo(() => {
+ if (location.pathname === '/') return 'home';
+ if (location.pathname.startsWith('/works')) return 'works';
+ return '';
+ }, [location.pathname]);
+
// 处理登出逻辑
const handleLogout = () => {
- dispatch(logout())
- navigate('/login'); // 重定向到登录页
+ dispatch(logout());
+ navigate('/login', { replace: true });
};
// 下拉菜单内容
@@ -50,66 +74,137 @@
{
key: 'profile',
label: '个人中心',
+ icon: <UserOutlined />,
onClick: () => navigate('/profile'),
},
{
+ key: 'settings',
+ label: '设置',
+ icon: <SettingOutlined />,
+ onClick: () => navigate('/settings'),
+ },
+ {
+ type: 'divider' as const,
+ },
+ {
key: 'logout',
label: '登出',
+ icon: <LogoutOutlined />,
onClick: handleLogout,
+ danger: true,
},
];
+ // 处理菜单点击
+ const handleMenuClick = (path: string) => {
+ navigate(path);
+ };
+
return (
<Layout style={{ minHeight: '100vh', width: '100%' }}>
- <Header className="header" style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
- {/* logo */}
- <Flex justify='center' align='center'>
- <img src={logo} alt="Logo" height='48px' />
- <div style={{ color: 'white', marginLeft: '10px' }}>
+ <Header
+ style={{
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: 'space-between',
+ padding: '0 24px',
+ background: '#001529'
+ }}
+ >
+ {/* Logo区域 */}
+ <Flex
+ align="center"
+ style={{ cursor: 'pointer' }}
+ onClick={() => navigate('/')}
+ >
+ <img
+ src={logo}
+ alt="创驿Logo"
+ style={{ height: 48 }}
+ />
+ <div style={{
+ color: 'white',
+ marginLeft: 12,
+ fontSize: 18,
+ fontWeight: 'bold'
+ }}>
创驿
</div>
</Flex>
- <div style={{
- height: '30px',
- width: '1px',
- backgroundColor: 'white',
- margin: '0 20px',
- }}></div>
-
- {/* 中间导航菜单 */}
- <Menu
- mode="horizontal"
- theme="dark"
- selectedKeys={[location.pathname === '/' ? 'home' : location.pathname.slice(1)]}
- items={menuItems.map(item => ({
- ...item,
- onClick: () => navigate(item.path),
- }))}
- style={{ flex: 1 }}
- />
-
- {/* 右侧用户名和下拉菜单 */}
+ {/* 分割线 */}
{!isAuthPage && (
- <div style={{ display: 'flex', alignItems: 'center', color: 'white' }}>
- <span>{userState.username}</span>
+ <div style={{
+ height: 30,
+ width: 1,
+ backgroundColor: 'rgba(255, 255, 255, 0.3)',
+ margin: '0 20px',
+ }} />
+ )}
+
+ {/* 导航菜单 */}
+ {!isAuthPage && (
+ <Menu
+ mode="horizontal"
+ theme="dark"
+ selectedKeys={selectedKey ? [selectedKey] : []}
+ items={menuItems.map(item => ({
+ ...item,
+ onClick: () => handleMenuClick(item.path),
+ }))}
+ style={{
+ flex: 1,
+ minWidth: 0,
+ backgroundColor: 'transparent',
+ borderBottom: 'none'
+ }}
+ />
+ )}
+
+ {/* 用户信息区域 */}
+ {!isAuthPage && isAuth && (
+ <Space size="middle">
+ <span style={{ color: 'white' }}>
+ 欢迎,{userState.username || '用户'}
+ </span>
<Dropdown
- trigger={['click']}
menu={{ items: dropdownMenuItems }}
+ trigger={['click']}
+ placement="bottomRight"
>
- <Button type="text" icon={<DownOutlined />} style={{ marginLeft: '10px', color: 'white' }} />
+ <Button
+ type="text"
+ style={{
+ color: 'white',
+ display: 'flex',
+ alignItems: 'center'
+ }}
+ >
+ <DownOutlined />
+ </Button>
</Dropdown>
- </div>
+ </Space>
)}
</Header>
- <Layout.Content style={{ padding: '24px' }}>
+
+ <Content style={{
+ padding: isAuthPage ? 0 : 24,
+ minHeight: 'calc(100vh - 64px - 70px)' // 减去header和footer高度
+ }}>
<Outlet />
- </Layout.Content>
- <Layout.Footer style={{ textAlign: 'center' }}>
- © 2025 创驿 - 愿做你创作路上的同行者
- </Layout.Footer>
+ </Content>
+
+ {!isAuthPage && (
+ <Footer style={{
+ textAlign: 'center',
+ background: '#f0f2f5',
+ padding: '24px 50px'
+ }}>
+ © 2025 创驿 - 愿做你创作路上的同行者
+ </Footer>
+ )}
</Layout>
);
};
-export default AppLayout;
+export default AppLayout;
\ No newline at end of file