chore: initialize tuhui repository
This commit is contained in:
150
frontend/src/components/Header.jsx
Normal file
150
frontend/src/components/Header.jsx
Normal file
@@ -0,0 +1,150 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { Input, Button, Space, Dropdown, Avatar } from 'antd';
|
||||
import { SearchOutlined, CameraOutlined, MenuOutlined, UserOutlined, LogoutOutlined, ShoppingOutlined } from '@ant-design/icons';
|
||||
import { getCurrentUser, isLoggedIn, logout } from '../api/auth';
|
||||
import LoginModal from './LoginModal';
|
||||
import RegisterModal from './RegisterModal';
|
||||
import './Header.css';
|
||||
|
||||
const Header = () => {
|
||||
const [searchValue, setSearchValue] = useState('');
|
||||
const [loginOpen, setLoginOpen] = useState(false);
|
||||
const [registerOpen, setRegisterOpen] = useState(false);
|
||||
const [user, setUser] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (isLoggedIn()) {
|
||||
setUser(getCurrentUser());
|
||||
}
|
||||
}, []);
|
||||
|
||||
const menuItems = [
|
||||
{ key: 'type', label: '类型', children: [
|
||||
{ key: 'poster', label: '海报' },
|
||||
{ key: 'banner', label: 'Banner' },
|
||||
{ key: 'ecommerce', label: '电商' },
|
||||
{ key: 'illustration', label: '插画' },
|
||||
]},
|
||||
{ key: 'theme', label: '主题', children: [
|
||||
{ key: 'realestate', label: '地产' },
|
||||
{ key: 'medical', label: '医美' },
|
||||
{ key: 'travel', label: '旅游' },
|
||||
{ key: 'tech', label: '科技' },
|
||||
]},
|
||||
{ key: 'style', label: '风格', children: [
|
||||
{ key: 'chinese', label: '中式' },
|
||||
{ key: 'premium', label: '高端' },
|
||||
{ key: 'creative', label: '创意' },
|
||||
{ key: 'minimalist', label: '清新' },
|
||||
]},
|
||||
];
|
||||
|
||||
const handleOpenLogin = () => {
|
||||
setRegisterOpen(false);
|
||||
setLoginOpen(true);
|
||||
};
|
||||
|
||||
const handleOpenRegister = () => {
|
||||
setLoginOpen(false);
|
||||
setRegisterOpen(true);
|
||||
};
|
||||
|
||||
const handleCloseLogin = () => {
|
||||
setLoginOpen(false);
|
||||
};
|
||||
|
||||
const handleCloseRegister = () => {
|
||||
setRegisterOpen(false);
|
||||
};
|
||||
|
||||
const handleLogout = () => {
|
||||
logout();
|
||||
};
|
||||
|
||||
const userMenuItems = [
|
||||
{
|
||||
key: 'orders',
|
||||
label: '我的订单',
|
||||
icon: <ShoppingOutlined />
|
||||
},
|
||||
{
|
||||
key: 'logout',
|
||||
label: '退出登录',
|
||||
icon: <LogoutOutlined />,
|
||||
onClick: handleLogout
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
<header className="header">
|
||||
<div className="header-container">
|
||||
<div className="header-left">
|
||||
<a href="/" className="logo">
|
||||
<svg viewBox="0 0 40 24" className="logo-icon">
|
||||
<path d="M20 0c-5.5 0-10 4.5-10 10s4.5 10 10 10c2.8 0 5.3-1.1 7.1-2.9L20 10l7.1-7.1C25.3 1.1 22.8 0 20 0z" fill="#ff5a5a"/>
|
||||
<path d="M30 4c-5.5 0-10 4.5-10 10s4.5 10 10 10c5.5 0 10-4.5 10-10S35.5 4 30 4zm0 16c-3.3 0-6-2.7-6-6s2.7-6 6-6 6 2.7 6 6-2.7 6-6 6z" fill="#ff5a5a"/>
|
||||
</svg>
|
||||
<span className="logo-text">图汇</span>
|
||||
<span className="logo-domain">DESIGN006.COM</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<nav className="header-nav">
|
||||
<Dropdown menu={{ items: menuItems }} placement="bottom">
|
||||
<a className="nav-item" onClick={e => e.preventDefault()}>
|
||||
<MenuOutlined /> 目录
|
||||
</a>
|
||||
</Dropdown>
|
||||
<a href="#" className="nav-item">热门</a>
|
||||
<a href="#" className="nav-item nav-new">
|
||||
最新
|
||||
<span className="new-dot"></span>
|
||||
</a>
|
||||
<a href="#" className="nav-item">图片</a>
|
||||
<a href="#" className="nav-item">字体</a>
|
||||
</nav>
|
||||
|
||||
<div className="header-search">
|
||||
<Input
|
||||
placeholder="搜索作品或编号"
|
||||
value={searchValue}
|
||||
onChange={(e) => setSearchValue(e.target.value)}
|
||||
prefix={<SearchOutlined style={{ color: '#999' }} />}
|
||||
suffix={<CameraOutlined style={{ color: '#999', cursor: 'pointer' }} />}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="header-right">
|
||||
{user ? (
|
||||
<Dropdown menu={{ items: userMenuItems }} placement="bottomRight">
|
||||
<div style={{ display: 'flex', alignItems: 'center', cursor: 'pointer' }} data-testid="user-dropdown">
|
||||
<Avatar icon={<UserOutlined />} style={{ marginRight: 8 }} className="ant-avatar" />
|
||||
<span>{user.nickname || user.phone}</span>
|
||||
</div>
|
||||
</Dropdown>
|
||||
) : (
|
||||
<>
|
||||
<Button className="btn-register" onClick={handleOpenRegister} data-testid="header-register-btn">注册</Button>
|
||||
<Button className="btn-login" onClick={handleOpenLogin} data-testid="header-login-btn">登录</Button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<LoginModal
|
||||
open={loginOpen}
|
||||
onClose={handleCloseLogin}
|
||||
onSwitchToRegister={handleOpenRegister}
|
||||
/>
|
||||
<RegisterModal
|
||||
open={registerOpen}
|
||||
onClose={handleCloseRegister}
|
||||
onSwitchToLogin={handleOpenLogin}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Header;
|
||||
Reference in New Issue
Block a user