import React, { useState, useRef, useEffect, useMemo } from 'react' import { useLocation, useNavigate } from 'react-router-dom' import { useAuth } from '../contexts/AuthContext' import LanguageSwitcher from './LanguageSwitcher' import NotificationBell from './NotificationBell' import { useTranslation } from '../i18n' import { useActivityLog } from '../hooks/useActivityLog' interface HeaderProps { onToggleSidebar: () => void } /** 格式化相对时间 */ function formatRelativeTime(timestamp: number, locale: string): string { const diff = Date.now() - timestamp const seconds = Math.floor(diff / 1000) const minutes = Math.floor(seconds / 60) const hours = Math.floor(minutes / 60) if (seconds < 60) return locale === 'en' ? 'Just now' : '刚刚' if (minutes < 60) return locale === 'en' ? `${minutes}m ago` : `${minutes}分钟前` if (hours < 24) return locale === 'en' ? `${hours}h ago` : `${hours}小时前` const days = Math.floor(hours / 24) return locale === 'en' ? `${days}d ago` : `${days}天前` } export default function Header({ onToggleSidebar }: HeaderProps) { const location = useLocation() const navigate = useNavigate() const { user, logout } = useAuth() const { t, locale } = useTranslation() const { activities } = useActivityLog() const pathname = location.pathname const pageTitle = (() => { if (pathname.startsWith('/consultation')) return t('nav.consultation') if (pathname.startsWith('/history')) return t('nav.history') if (pathname.startsWith('/record/')) return t('nav.recordDetail') if (pathname.startsWith('/settings')) return t('nav.settings') if (pathname.startsWith('/patients')) return t('nav.patients') if (pathname.startsWith('/admin')) return t('nav.admin') if (pathname.startsWith('/templates')) return t('nav.templates') if (pathname.startsWith('/profile')) return t('nav.profile') if (pathname.startsWith('/lab-results')) return t('nav.labResults') if (pathname.startsWith('/knowledge-base')) return t('nav.knowledge') if (pathname.startsWith('/inventory')) return t('nav.inventory') if (pathname.startsWith('/followups')) return t('nav.followups') if (pathname.startsWith('/appointments')) return t('nav.appointments') return t('nav.dashboard') })() const breadcrumbs: { label: string; href?: string }[] = (() => { const crumbs: { label: string; href?: string }[] = [{ label: t('nav.home'), href: '/' }] if (pathname === '/') return crumbs if (pathname.startsWith('/consultation')) crumbs.push({ label: t('nav.consultation') }) else if (pathname.startsWith('/history')) crumbs.push({ label: t('nav.history') }) else if (pathname.startsWith('/record/')) crumbs.push({ label: t('nav.recordDetail') }) else if (pathname.startsWith('/settings')) crumbs.push({ label: t('nav.settings') }) else if (pathname.startsWith('/patients')) { crumbs.push({ label: t('nav.patients'), href: '/patients' }) if (pathname.includes('/edit') || pathname.includes('/new')) crumbs.push({ label: t('common.edit') }) } else if (pathname.startsWith('/admin')) crumbs.push({ label: t('nav.admin') }) else if (pathname.startsWith('/templates')) crumbs.push({ label: t('nav.templates') }) else if (pathname.startsWith('/profile')) crumbs.push({ label: t('nav.profile') }) else if (pathname.startsWith('/lab-results')) crumbs.push({ label: t('nav.labResults') }) else if (pathname.startsWith('/knowledge-base')) crumbs.push({ label: t('nav.knowledge') }) else if (pathname.startsWith('/inventory')) crumbs.push({ label: t('nav.inventory') }) else if (pathname.startsWith('/followups')) crumbs.push({ label: t('nav.followups') }) return crumbs })() const [showDropdown, setShowDropdown] = useState(false) const [scrolled, setScrolled] = useState(false) const dropdownRef = useRef(null) const headerRef = useRef(null) // 滚动收缩 Header useEffect(() => { let lastScrollY = 0 const handleScroll = () => { const currentScrollY = window.scrollY if (currentScrollY > 40 && currentScrollY > lastScrollY) { setScrolled(true) } else if (currentScrollY < 20) { setScrolled(false) } lastScrollY = currentScrollY } window.addEventListener('scroll', handleScroll, { passive: true }) return () => window.removeEventListener('scroll', handleScroll) }, []) // 点击外部关闭下拉 useEffect(() => { const handler = (e: MouseEvent) => { if (dropdownRef.current && !dropdownRef.current.contains(e.target as Node)) { setShowDropdown(false) } } document.addEventListener('mousedown', handler) return () => document.removeEventListener('mousedown', handler) }, []) const today = new Date().toLocaleDateString(locale === 'en' ? 'en-US' : 'zh-CN', { year: 'numeric', month: 'long', day: 'numeric', weekday: 'long', }) const displayName = user?.nickname || t('profile.defaultUser') const initial = displayName[0] // 最近5条操作 const recentActivities = useMemo(() => activities.slice(0, 5), [activities]) const handleMenuClick = (action: string) => { setShowDropdown(false) if (action === 'profile') { navigate('/profile') } else if (action === 'settings') { navigate('/settings') } else if (action === 'logout') { logout() navigate('/login') } } return (
{/* 移动端汉堡菜单按钮 */}
{/* 面包屑 */}
{breadcrumbs.map((crumb, i) => ( {i > 0 && } {crumb.href ? ( ) : ( {crumb.label} )} ))}
{showDropdown && (
{/* 用户信息区 */}

{user?.nickname || t('auth.doctor')}

{user?.role === 'admin' ? t('auth.hospitalAdmin') : t('auth.doctor')}

{/* 最近操作 */}

{t('ergonomics.recentActivity')}

{recentActivities.length === 0 ? (

{t('ergonomics.noActivity')}

) : (
{recentActivities.map((act) => (
{act.icon && {act.icon}} {act.description} {formatRelativeTime(act.timestamp, locale)}
))}
)}
)}
) }