Files
s2f/frontend/components/layout/Header.tsx
T
freedakgmail b93929eb1a feat: UI优化和功能完善
- 添加公共分页组件,支持上边显示、分页大小10
- 侧边栏/Header按Liner风格优化,添加动画效果
- 异常处理列表支持分页和明细弹窗
- 任务结果页面支持已匹配列表分页
- 修复Dialog弹窗背景透明问题
- 新增dropdown-menu组件
- 添加parsed_file_record模型和回填脚本
- 前端枚举中文化
2026-07-07 12:57:15 +08:00

115 lines
3.9 KiB
TypeScript

"use client";
import { useState } from "react";
import { useRouter } from "next/navigation";
import {
LogOut,
User,
Bell,
Moon,
Sun,
Workflow
} from "lucide-react";
import { useAuthStore } from "@/lib/stores/auth-store";
import { Button } from "@/components/ui/button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { api } from "@/lib/api/client";
import ENDPOINTS from "@/lib/api/endpoints";
import { cn } from "@/lib/utils";
const ROLE_LABELS: Record<string, string> = {
admin: "管理员",
accountant: "会计",
viewer: "查看者",
};
export function Header() {
const router = useRouter();
const { user, logout } = useAuthStore();
const handleLogout = async () => {
try {
await api.post(ENDPOINTS.AUTH.LOGOUT);
} catch {
// 即使后端失败也清除本地状态
}
logout();
router.push("/login");
};
if (!user) return null;
return (
<header className="sticky top-0 z-50 w-full border-b border-border bg-card/95 backdrop-blur supports-[backdrop-filter]:bg-card/60">
<div className="flex h-14 items-center justify-between px-6">
{/* 左侧 - Logo 和系统名称 */}
<div className="flex items-center gap-3">
<div className="w-8 h-8 rounded-lg bg-primary/10 flex items-center justify-center shrink-0">
<Workflow className="w-4 h-4 text-primary" />
</div>
<div className="flex flex-col">
<span className="text-sm font-semibold text-foreground leading-tight">AI助手</span>
<span className="text-[10px] text-muted-foreground">S2F </span>
</div>
</div>
{/* 右侧 - 用户信息和操作 */}
<div className="flex items-center gap-2">
{/* 通知按钮 */}
<Button variant="ghost" size="icon" className="relative">
<Bell className="w-4 h-4" />
<span className="absolute top-1.5 right-1.5 w-2 h-2 bg-red-500 rounded-full" />
</Button>
{/* 用户下拉菜单 */}
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" className="gap-2 h-9 px-2">
<div className="w-7 h-7 rounded-full bg-primary/10 flex items-center justify-center">
<User className="w-3.5 h-3.5 text-primary" />
</div>
<div className="flex flex-col items-start">
<span className="text-sm font-medium text-foreground leading-tight">
{user.full_name}
</span>
<span className="text-[10px] text-muted-foreground">
{ROLE_LABELS[user.role] || user.role}
</span>
</div>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-56">
<DropdownMenuLabel className="font-normal">
<div className="flex flex-col space-y-1">
<p className="text-sm font-medium">{user.full_name}</p>
<p className="text-xs text-muted-foreground">{user.email}</p>
</div>
</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuItem className="gap-2">
<User className="w-4 h-4" />
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem
onClick={handleLogout}
className="gap-2 text-destructive focus:text-destructive"
>
<LogOut className="w-4 h-4" />
退
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
</div>
</header>
);
}