feat(frontend): 管理端页面 — 任务全景树/创建产品/标签打印/认证守卫
App.tsx: - AntApp + AuthProvider + ToastProvider 三层包裹 - /admin/login 独立登录页 - /admin/* 路由认证守卫 AdminLayout: - 未登录→跳转登录; 顶部栏显示用户名+登出 - 侧边栏: 全局概览/产品管理/任务全景 CreateProductDialog (Ant Design 重写): - MOM物料手风琴选择器 (Collapse+Table) - 分组懒加载 + useRef缓存 + 防抖搜索 - HEX ID只读展示 + 序列号/订单号选填 AdminProductsPage: - 打印预览弹窗 (Base64标签预览 + 份数选择) - 打印机设置入口 → AdminPrintConfigPage 扫码组件对齐: - ProductCard: material_name/spec_model/current_location - TaskListCard: 递归 task_tree + 状态配色 + 返工/裂变标签 - QueryResult: task_tree 优先 - ScanPage: 宏观状态栏
This commit is contained in:
@ -1,5 +1,6 @@
|
||||
import { NavLink, Outlet, useLocation } from "react-router-dom";
|
||||
import { QrCode, Package, ArrowLeft, LayoutDashboard, Smartphone, GitBranch } from "lucide-react";
|
||||
import { NavLink, Outlet, useLocation, useNavigate, Navigate } from "react-router-dom";
|
||||
import { QrCode, Package, ArrowLeft, LayoutDashboard, Smartphone, GitBranch, LogOut, User } from "lucide-react";
|
||||
import { useAuth } from "../../contexts/AuthContext";
|
||||
|
||||
const MENU = [
|
||||
{
|
||||
@ -24,6 +25,27 @@ const MENU = [
|
||||
|
||||
export default function AdminLayout() {
|
||||
const location = useLocation();
|
||||
const navigate = useNavigate();
|
||||
const { user, logout, isAuthenticated, loading } = useAuth();
|
||||
|
||||
// 认证加载中
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="flex min-h-screen items-center justify-center bg-gray-50">
|
||||
<div className="h-8 w-8 animate-spin rounded-full border-2 border-blue-500 border-t-transparent" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// 未登录 → 跳转登录页
|
||||
if (!isAuthenticated) {
|
||||
return <Navigate to="/admin/login" replace />;
|
||||
}
|
||||
|
||||
function handleLogout() {
|
||||
logout();
|
||||
navigate("/admin/login", { replace: true });
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex min-h-screen bg-gray-50">
|
||||
@ -74,7 +96,7 @@ export default function AdminLayout() {
|
||||
</aside>
|
||||
|
||||
<main className="ml-56 flex-1">
|
||||
<div className="sticky top-0 z-30 border-b border-gray-200 bg-white px-6 py-3">
|
||||
<div className="sticky top-0 z-30 flex items-center justify-between border-b border-gray-200 bg-white px-6 py-3">
|
||||
<div className="flex items-center gap-2 text-xs text-gray-400">
|
||||
<LayoutDashboard className="h-3 w-3" />
|
||||
<span>管理端</span>
|
||||
@ -83,6 +105,28 @@ export default function AdminLayout() {
|
||||
{MENU.find((m) => location.pathname.startsWith(m.path))?.title ?? "页面"}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* 用户信息 + 登出 */}
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex items-center gap-1.5 text-xs text-gray-500">
|
||||
<User className="h-3.5 w-3.5" />
|
||||
<span className="font-medium text-gray-700">
|
||||
{user?.display_name ?? user?.username ?? "—"}
|
||||
</span>
|
||||
{user?.role && (
|
||||
<span className="rounded bg-gray-100 px-1.5 py-0.5 text-[10px] text-gray-500">
|
||||
{user.role}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<button
|
||||
onClick={handleLogout}
|
||||
className="flex items-center gap-1 rounded-md px-2 py-1 text-xs text-gray-400 transition-colors hover:bg-red-50 hover:text-red-600"
|
||||
>
|
||||
<LogOut className="h-3 w-3" />
|
||||
退出
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-6">
|
||||
<Outlet />
|
||||
|
||||
Reference in New Issue
Block a user