Files
s2f/frontend/components/layout/Header.tsx
T
freedakgmail 33b4c734aa feat: 完善前后端核心功能模块
后端:
- 新增认证(auth)、任务(tasks)、映射(mappings)、对账(reconciliation)、异常(exceptions)、导出(exports) API
- 新增核心模块: database, security, permissions, tenant, exceptions, error_handlers
- 新增数据模型: user, company, reconciliation_task, field_mapping, uploaded_file 等
- 新增服务层: ai_recognizer, file_parser, file_storage, mapping, reconciliation 等
- 添加数据库迁移脚本

前端:
- 新增登录页面和仪表盘页面
- 新增任务列表、任务详情、字段映射页面
- 新增异常处理页面和规则设置页面
- 新增 API 代理路由 /api/[...path]
- 新增 UI 组件库 (button, card, dialog, input, table 等)
- 新增 auth 组件 (ProtectedRoute, PermissionGate)
- 新增 layout 组件 (Header, Sidebar)
- 新增 mapping 组件 (FieldMappingTable, AISuggestionPanel)
- 新增 API 客户端和 hooks (useAsync, useToast, usePermission 等)
- 新增状态管理 (auth-store, company-store, ui-store)
- 集成 Tailwind CSS 和 shadcn/ui 组件库

其他:
- 添加 Alembic 数据库迁移配置
- 添加初始化示例数据脚本
- 更新项目文档
2026-07-07 09:04:47 +08:00

82 lines
2.8 KiB
TypeScript

"use client";
import { useRouter } from "next/navigation";
import { LogOut, User } from "lucide-react";
import { useAuthStore } from "@/lib/stores/auth-store";
import { Button } from "@/components/ui/button";
import { api } from "@/lib/api/client";
import ENDPOINTS from "@/lib/api/endpoints";
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-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/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">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
className="lucide lucide-shield w-4 h-4 text-primary"
aria-hidden="true"
>
<path d="M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"></path>
</svg>
</div>
<span className="font-semibold text-foreground">AI助手</span>
</div>
{/* 右侧 - 用户信息和登出 */}
<div className="flex items-center gap-4">
{/* 用户信息 */}
<div className="flex items-center gap-3 text-sm">
<div className="flex items-center gap-2 px-3 py-1.5 rounded-lg bg-muted/50">
<User className="w-4 h-4 text-muted-foreground" />
<span className="font-medium text-foreground">{user.full_name}</span>
<span className="text-muted-foreground">·</span>
<span className="text-muted-foreground">{user.role}</span>
</div>
</div>
{/* 登出按钮 */}
<Button
variant="ghost"
size="sm"
onClick={handleLogout}
className="gap-2 text-muted-foreground hover:text-foreground"
>
<LogOut className="w-4 h-4" />
<span></span>
</Button>
</div>
</div>
</header>
);
}