first commit

Co-Authored-By: Codex <noreply@openai.com>
This commit is contained in:
HouYunFei
2026-05-19 07:53:53 +08:00
commit 472bf8b732
133 changed files with 16869 additions and 0 deletions
+86
View File
@@ -0,0 +1,86 @@
"use client";
import { FileTextOutlined, HomeOutlined, LogoutOutlined, PictureOutlined } from "@ant-design/icons";
import { Button, Flex, Layout, Menu, Typography } from "antd";
import { LogOut } from "lucide-react";
import Link from "next/link";
import { usePathname, useRouter } from "next/navigation";
import type { ReactNode } from "react";
import { useEffect } from "react";
import { UserStatusActions } from "@/components/user-status-actions";
import { useThemeStore } from "@/stores/use-theme-store";
import { useUserStore } from "@/stores/use-user-store";
export default function AdminLayout({ children }: { children: ReactNode }) {
const router = useRouter();
const pathname = usePathname();
const token = useUserStore((state) => state.token);
const user = useUserStore((state) => state.user);
const isReady = useUserStore((state) => state.isReady);
const logout = useUserStore((state) => state.clearSession);
const colorTheme = useThemeStore((state) => state.theme);
const setTheme = useThemeStore((state) => state.setTheme);
const activeKey = pathname.startsWith("/admin/assets") ? "/admin/assets" : pathname.startsWith("/admin/prompts") ? "/admin/prompts" : "";
const pageTitle = pathname.startsWith("/admin/assets") ? "素材库管理" : "提示词管理";
const appVersion = process.env.NEXT_PUBLIC_APP_VERSION || "dev";
useEffect(() => {
if (!isReady) return;
if (!token) {
router.replace("/login?redirect=/admin");
return;
}
if (user?.role !== "admin") {
router.replace("/");
}
}, [isReady, router, token, user?.role]);
if (!isReady || !token || user?.role !== "admin") {
return (
<div style={{ display: "flex", minHeight: "100vh", alignItems: "center", justifyContent: "center", background: "var(--background)" }}>
<span />
</div>
);
}
return (
<Layout className="admin-layout" hasSider style={{ height: "100vh", overflow: "hidden" }}>
<Layout.Sider width={232} style={{ height: "100vh", overflow: "hidden" }}>
<Flex className="admin-brand" align="center" gap={12} style={{ height: 56, padding: "0 20px" }}>
<span className="admin-logo" aria-hidden />
<Typography.Text strong style={{ fontSize: 16 }}></Typography.Text>
</Flex>
<Menu
mode="inline"
selectedKeys={[activeKey]}
style={{ borderInlineEnd: 0, padding: "12px 8px" }}
items={[
{ key: "/admin/prompts", icon: <FileTextOutlined />, label: <Link href="/admin/prompts" style={{ color: "inherit" }}></Link> },
{ key: "/admin/assets", icon: <PictureOutlined />, label: <Link href="/admin/assets" style={{ color: "inherit" }}></Link> },
]}
/>
<Flex vertical gap={8} style={{ position: "absolute", bottom: 0, insetInline: 0, padding: 12 }}>
<Button block icon={<HomeOutlined />} href="/canvas" target="_blank" rel="noreferrer"></Button>
<Button block icon={<LogoutOutlined />} onClick={logout}>退</Button>
</Flex>
</Layout.Sider>
<Layout>
<Layout.Header style={{ display: "flex", alignItems: "center", justifyContent: "space-between", height: 56, padding: "0 24px" }}>
<Typography.Title level={5} style={{ margin: 0 }}>{pageTitle}</Typography.Title>
<Flex align="center" gap={4}>
<UserStatusActions
version={appVersion}
theme={colorTheme}
onThemeChange={setTheme}
showConfig={false}
userName={user.username}
menuItems={[{ key: "logout", icon: <LogOut className="size-4" />, label: "退出登录", onClick: logout }]}
/>
</Flex>
</Layout.Header>
<Layout.Content style={{ minHeight: 0, overflow: "auto" }}>{children}</Layout.Content>
</Layout>
</Layout>
);
}