134 lines
4.9 KiB
TypeScript
134 lines
4.9 KiB
TypeScript
'use client'
|
||
|
||
import { useState } from 'react'
|
||
import { User, LogOut, KeyRound } from 'lucide-react'
|
||
import { DevPanel } from '@/app/(main)/dev/panel'
|
||
import { ChangePasswordDialog } from '@/components/layout/change-password-dialog'
|
||
import { UserProfileDialog } from '@/components/layout/user-profile-dialog'
|
||
import { Button } from '@/components/ui/button'
|
||
import {
|
||
DropdownMenu,
|
||
DropdownMenuContent,
|
||
DropdownMenuItem,
|
||
DropdownMenuLabel,
|
||
DropdownMenuSeparator,
|
||
DropdownMenuTrigger,
|
||
} from '@/components/ui/dropdown-menu'
|
||
import { Badge } from '@/components/ui/badge'
|
||
import { Separator } from '@/components/ui/separator'
|
||
import { SidebarTrigger } from '@/components/ui/sidebar'
|
||
import { signOut } from 'next-auth/react'
|
||
import { useRouter, usePathname } from 'next/navigation'
|
||
import { useTheme } from 'next-themes'
|
||
import { ThemeToggleButton, useThemeTransition } from '@/components/common/theme-toggle-button'
|
||
import { getMenuTitle } from '@/constants/menu'
|
||
import type { User as AppUser } from '@/types/user'
|
||
|
||
interface HeaderProps {
|
||
user?: AppUser
|
||
}
|
||
|
||
export function Header({ user }: HeaderProps) {
|
||
const router = useRouter()
|
||
const pathname = usePathname()
|
||
const { theme, setTheme } = useTheme()
|
||
const { startTransition } = useThemeTransition()
|
||
const [isChangePasswordOpen, setIsChangePasswordOpen] = useState(false)
|
||
const [isUserProfileOpen, setIsUserProfileOpen] = useState(false)
|
||
|
||
const pageTitle = getMenuTitle(pathname, 2) // 只匹配到第二级菜单
|
||
|
||
const handleThemeToggle = () => {
|
||
startTransition(() => {
|
||
setTheme(theme === 'dark' ? 'light' : 'dark')
|
||
})
|
||
}
|
||
|
||
const handleLogout = async () => {
|
||
await signOut({ redirect: false })
|
||
router.push('/login')
|
||
}
|
||
|
||
// 如果没有用户信息,不显示Header(应该被中间件重定向)
|
||
if (!user) {
|
||
return null
|
||
}
|
||
|
||
return (
|
||
<header className="flex h-16 shrink-0 items-center gap-2 border-b px-4">
|
||
<SidebarTrigger />
|
||
<Separator orientation="vertical" className="mr-2 h-4" />
|
||
<div className="flex items-center justify-between flex-1">
|
||
<h2 className="text-lg font-semibold">
|
||
{pageTitle}
|
||
</h2>
|
||
<div className="flex items-center space-x-4">
|
||
{/* 主题切换按钮 */}
|
||
<ThemeToggleButton
|
||
theme={theme === 'dark' ? 'dark' : 'light'}
|
||
variant="polygon"
|
||
onClick={handleThemeToggle}
|
||
className="border-0 shadow-none"
|
||
/>
|
||
|
||
{/* 开发者工具按钮 - 仅开发环境 */}
|
||
{process.env.NODE_ENV === 'development' && user.isSuperAdmin && <DevPanel />}
|
||
|
||
{/* 用户菜单 */}
|
||
<DropdownMenu>
|
||
<DropdownMenuTrigger asChild>
|
||
<Button variant="ghost" className="flex items-center space-x-2 px-3">
|
||
<div className="w-8 h-8 bg-primary/10 rounded-full flex items-center justify-center">
|
||
<User className="h-4 w-4 text-primary" />
|
||
</div>
|
||
<div className="text-left hidden sm:block">
|
||
<p className="text-sm font-medium">{user.name}</p>
|
||
<p className="text-xs text-muted-foreground">
|
||
{user.isSuperAdmin ? '超级管理员' : (Array.isArray(user.roles) ? user.roles.join('、') : user.roles)}
|
||
</p>
|
||
</div>
|
||
</Button>
|
||
</DropdownMenuTrigger>
|
||
<DropdownMenuContent align="end" className="w-56">
|
||
<DropdownMenuLabel>我的账户</DropdownMenuLabel>
|
||
<DropdownMenuSeparator />
|
||
<DropdownMenuItem onClick={() => setIsUserProfileOpen(true)}>
|
||
<User className="mr-2 h-4 w-4" />
|
||
个人资料
|
||
</DropdownMenuItem>
|
||
<DropdownMenuItem onClick={() => setIsChangePasswordOpen(true)}>
|
||
<KeyRound className="mr-2 h-4 w-4" />
|
||
修改密码
|
||
</DropdownMenuItem>
|
||
<DropdownMenuSeparator />
|
||
<DropdownMenuLabel>角色</DropdownMenuLabel>
|
||
<DropdownMenuItem disabled>
|
||
{user.isSuperAdmin ? '超级管理员' : (Array.isArray(user.roles) ? user.roles.join('、') : user.roles)}
|
||
</DropdownMenuItem>
|
||
<DropdownMenuSeparator />
|
||
<DropdownMenuItem
|
||
className="text-red-600 cursor-pointer"
|
||
onClick={handleLogout}
|
||
>
|
||
<LogOut className="mr-2 h-4 w-4" />
|
||
退出登录
|
||
</DropdownMenuItem>
|
||
</DropdownMenuContent>
|
||
</DropdownMenu>
|
||
</div>
|
||
</div>
|
||
|
||
{/* 修改密码对话框 */}
|
||
<ChangePasswordDialog
|
||
isOpen={isChangePasswordOpen}
|
||
onClose={() => setIsChangePasswordOpen(false)}
|
||
/>
|
||
|
||
{/* 用户资料对话框 */}
|
||
<UserProfileDialog
|
||
isOpen={isUserProfileOpen}
|
||
onClose={() => setIsUserProfileOpen(false)}
|
||
/>
|
||
</header>
|
||
)
|
||
} |