b93929eb1a
- 添加公共分页组件,支持上边显示、分页大小10 - 侧边栏/Header按Liner风格优化,添加动画效果 - 异常处理列表支持分页和明细弹窗 - 任务结果页面支持已匹配列表分页 - 修复Dialog弹窗背景透明问题 - 新增dropdown-menu组件 - 添加parsed_file_record模型和回填脚本 - 前端枚举中文化
115 lines
3.9 KiB
TypeScript
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>
|
|
);
|
|
} |