website-01/components/admin/AdminHeader.tsx

58 lines
1.6 KiB
TypeScript
Raw Normal View History

2026-06-22 14:43:46 +08:00
'use client';
import { useRouter } from 'next/navigation';
import { useEffect, useState } from 'react';
import { useAdminStore } from '@/store/adminStore';
import { tokenStorage } from '@/lib/api';
import { Loader2 } from 'lucide-react';
interface AdminHeaderProps {
title: string;
description?: string;
actions?: React.ReactNode;
}
export function AdminHeader({ title, description, actions }: AdminHeaderProps) {
const router = useRouter();
const token = useAdminStore((s) => s.token);
const [checking, setChecking] = useState(true);
useEffect(() => {
// 客户端兜底:如果 store 中没 token 但 localStorage 有,刷新一下
const lsToken = tokenStorage.get();
if (!token && lsToken) {
useAdminStore.setState({
token: lsToken,
admin: useAdminStore.getState().admin,
});
}
setChecking(false);
}, [token]);
useEffect(() => {
if (!checking && !token) {
router.replace('/admin/login');
}
}, [checking, token, router]);
if (checking || !token) {
return (
<div className="flex h-40 items-center justify-center text-gray-400">
<Loader2 className="mr-2 h-5 w-5 animate-spin" />
</div>
);
}
return (
<header className="mb-6 flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between">
<div>
<h1 className="text-xl font-semibold text-gray-900">{title}</h1>
{description && (
<p className="mt-1 text-sm text-gray-500">{description}</p>
)}
</div>
{actions && <div className="flex items-center gap-2">{actions}</div>}
</header>
);
}