import { useState, useEffect } from 'react' import { Layout, Badge, Avatar, Dropdown, Space, Popover, List, Tabs, Button, Empty, Typography } from 'antd' import { useNavigate } from 'react-router-dom' import { MenuFoldOutlined, MenuUnfoldOutlined, BellOutlined, QuestionCircleOutlined, FileTextOutlined, CustomerServiceOutlined, UserOutlined, CheckOutlined, ProjectOutlined, TeamOutlined, NotificationOutlined, } from '@ant-design/icons' import useUserStore from '@/stores/userStore' import { getNotifications, getUnreadCount, markAsRead, markAllAsRead } from '@/api/notification' import Toast from '@/components/Toast/Toast' import headerMenuData from '../../data/headerMenuData.json' import './AppHeader.css' const { Header } = Layout const { Text } = Typography // 图标映射 const iconMap = { QuestionCircleOutlined: , FileTextOutlined: , CustomerServiceOutlined: , } function AppHeader({ collapsed, onToggle }) { const navigate = useNavigate() const { user, logout } = useUserStore() // 用户下拉菜单 const userMenuItems = [ { key: 'profile', label: '个人中心', }, { key: 'settings', label: '账户设置', }, { type: 'divider', }, { key: 'logout', label: '退出登录', }, ] const [notifications, setNotifications] = useState([]) const [unreadCount, setUnreadCount] = useState(0) const [loading, setLoading] = useState(false) const [popoverVisible, setPopoverVisible] = useState(false) useEffect(() => { if (user) { fetchUnreadCount() // 每 2 分钟轮询一次 const timer = setInterval(fetchUnreadCount, 120000) return () => clearInterval(timer) } }, [user]) const fetchUnreadCount = async () => { try { const res = await getUnreadCount() setUnreadCount(res.data.unread_count) } catch (error) { console.error('Fetch unread count error:', error) } } const fetchNotifications = async () => { setLoading(true) try { const res = await getNotifications({ page: 1, page_size: 5 }) setNotifications(res.data || []) } catch (error) { console.error('Fetch notifications error:', error) } finally { setLoading(false) } } const handleMarkRead = async (id) => { try { await markAsRead(id) setNotifications(notifications.map(n => n.id === id ? { ...n, is_read: 1 } : n)) fetchUnreadCount() } catch (error) { console.error('Mark read error:', error) } } const handleMarkAllRead = async () => { try { await markAllAsRead() setNotifications(notifications.map(n => ({ ...n, is_read: 1 }))) setUnreadCount(0) Toast.success('操作成功', '所有通知已标记为已读') } catch (error) { console.error('Mark all read error:', error) } } const handleNotificationClick = (n) => { if (n.is_read === 0) { handleMarkRead(n.id) } if (n.link) { navigate(n.link) setPopoverVisible(false) } } const getCategoryIcon = (category) => { switch (category) { case 'project': return case 'collaboration': return default: return } } const notificationContent = (
消息通知 {unreadCount > 0 && ( )}
}} renderItem={(item) => ( handleNotificationClick(item)} > } title={{item.title}} description={
{item.content}
{new Date(item.created_at).toLocaleString('zh-CN')}
} />
)} />
) const handleUserMenuClick = ({ key }) => { if (key === 'logout') { logout() Toast.success('退出成功', '您已安全退出') navigate('/login') } else if (key === 'profile') { navigate('/profile') } else if (key === 'settings') { Toast.info('开发中', '账户设置功能正在开发中') } } const handleHeaderMenuClick = (key) => { console.log('Header menu clicked:', key) if (key === 'support') { Toast.info('开发中', '支持功能正在开发中') } } return (
{/* 左侧:Logo + 折叠按钮 */}
{/* Logo 区域 */}

NEX Docus

{/* 折叠按钮 */}
{collapsed ? : }
{/* 右侧:功能按钮 + 用户信息 */}
{/* 功能图标 */} {/* 动态渲染 header 菜单 */} {headerMenuData.map((item) => (
handleHeaderMenuClick(item.key)} > {iconMap[item.icon]} {item.label}
))} {/* 消息中心 */} { setPopoverVisible(visible) if (visible) { fetchNotifications() } }} placement="bottomRight" overlayClassName="header-notification-popover" >
消息
{/* 用户下拉菜单 */}
} /> {user?.nickname || user?.username || 'User'}
) } export default AppHeader