diff --git a/app/(account)/layout.tsx b/app/(account)/layout.tsx index 80590d4..e34dc15 100644 --- a/app/(account)/layout.tsx +++ b/app/(account)/layout.tsx @@ -1,16 +1,14 @@ +import { AccountSidebar } from "@/components/account-sidebar" +import { Header } from "@/components/header" + export default function AccountLayout({ children }: { children: React.ReactNode }) { return ( -
- -
{children}
+
+
+
+ +
{children}
+
) } diff --git a/app/(dashboard)/layout.tsx b/app/(dashboard)/layout.tsx index af93192..a731a1f 100644 --- a/app/(dashboard)/layout.tsx +++ b/app/(dashboard)/layout.tsx @@ -1,15 +1,14 @@ +import { DashboardSidebar } from "@/components/dashboard-sidebar" +import { Header } from "@/components/header" + export default function DashboardLayout({ children }: { children: React.ReactNode }) { return ( -
- -
{children}
+
+
+
+ +
{children}
+
) } diff --git a/app/(main)/layout.tsx b/app/(main)/layout.tsx index 27a0c33..b8d4708 100644 --- a/app/(main)/layout.tsx +++ b/app/(main)/layout.tsx @@ -1,20 +1,12 @@ +import { Footer } from "@/components/footer" +import { Header } from "@/components/header" + export default function MainLayout({ children }: { children: React.ReactNode }) { return (
-
- -
+
{children}
-
-
- © 聚玩 - 游戏陪玩服务平台 -
-
+
) } diff --git a/app/(order)/layout.tsx b/app/(order)/layout.tsx index c13be86..a26f97c 100644 --- a/app/(order)/layout.tsx +++ b/app/(order)/layout.tsx @@ -1,3 +1,10 @@ +import { Header } from "@/components/header" + export default function OrderLayout({ children }: { children: React.ReactNode }) { - return
{children}
+ return ( +
+
+
{children}
+
+ ) } diff --git a/app/providers.tsx b/app/providers.tsx index 23363f8..c8049ea 100644 --- a/app/providers.tsx +++ b/app/providers.tsx @@ -2,6 +2,7 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query" import { useState } from "react" +import { TooltipProvider } from "@/components/ui/tooltip" export function Providers({ children }: { children: React.ReactNode }) { const [queryClient] = useState( @@ -16,5 +17,9 @@ export function Providers({ children }: { children: React.ReactNode }) { }), ) - return {children} + return ( + + {children} + + ) } diff --git a/components/account-sidebar.tsx b/components/account-sidebar.tsx new file mode 100644 index 0000000..8b5d36b --- /dev/null +++ b/components/account-sidebar.tsx @@ -0,0 +1,44 @@ +"use client" + +import { Bell, CreditCard, Settings, ShieldCheck } from "lucide-react" +import Link from "next/link" +import { usePathname } from "next/navigation" +import { cn } from "@/lib/utils" + +const links = [ + { href: "/settings", label: "个人设置", icon: Settings }, + { href: "/wallet", label: "钱包", icon: CreditCard }, + { href: "/notifications", label: "通知中心", icon: Bell }, + { href: "/verify", label: "身份认证", icon: ShieldCheck }, +] + +export function AccountSidebar() { + const pathname = usePathname() + + return ( + + ) +} diff --git a/components/dashboard-sidebar.tsx b/components/dashboard-sidebar.tsx new file mode 100644 index 0000000..3ef6dab --- /dev/null +++ b/components/dashboard-sidebar.tsx @@ -0,0 +1,66 @@ +"use client" + +import { + Gamepad2, + LayoutDashboard, + ListOrdered, + Palette, + Settings2, + Store, + Users, +} from "lucide-react" +import Link from "next/link" +import { usePathname } from "next/navigation" +import { cn } from "@/lib/utils" +import { useAuthStore } from "@/store/auth" + +const playerLinks = [ + { href: "/dashboard", label: "概览", icon: LayoutDashboard }, + { href: "/dashboard/services", label: "服务管理", icon: ListOrdered }, +] + +const ownerLinks = [ + { href: "/dashboard", label: "概览", icon: LayoutDashboard }, + { href: "/dashboard/services", label: "服务管理", icon: ListOrdered }, + { href: "/dashboard/shop", label: "店铺管理", icon: Store }, + { href: "/dashboard/shop/employees", label: "员工管理", icon: Users }, + { href: "/dashboard/shop/templates", label: "模板编辑", icon: Palette }, + { href: "/dashboard/settings", label: "店铺设置", icon: Settings2 }, +] + +export function DashboardSidebar() { + const pathname = usePathname() + const { currentRole } = useAuthStore() + + const links = currentRole === "owner" ? ownerLinks : playerLinks + + return ( + + ) +} diff --git a/components/footer.tsx b/components/footer.tsx new file mode 100644 index 0000000..4f43539 --- /dev/null +++ b/components/footer.tsx @@ -0,0 +1,52 @@ +import { Gamepad2 } from "lucide-react" +import Link from "next/link" + +export function Footer() { + return ( +
+
+
+
+ + + 聚玩 + +

专业游戏陪玩服务平台

+
+
+

服务

+ +
+
+

支持

+ +
+
+

联系我们

+ +
+
+
+ © 2025 聚玩 - 游戏陪玩服务平台 +
+
+
+ ) +} diff --git a/components/header.tsx b/components/header.tsx new file mode 100644 index 0000000..e9aad90 --- /dev/null +++ b/components/header.tsx @@ -0,0 +1,321 @@ +"use client" + +import { + Bell, + Gamepad2, + LogOut, + Menu, + MessageSquare, + Search, + Settings, + ShoppingBag, + User, + Wallet, +} from "lucide-react" +import Link from "next/link" +import { usePathname, useRouter } from "next/navigation" +import { useState } from "react" +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" +import { Badge } from "@/components/ui/badge" +import { Button } from "@/components/ui/button" +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuGroup, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu" +import { Input } from "@/components/ui/input" +import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger } from "@/components/ui/sheet" +import { currentUser, mockNotifications } from "@/lib/mock-data" +import type { UserRole } from "@/lib/types" +import { cn } from "@/lib/utils" +import { useAuthStore } from "@/store/auth" + +const roleLabels: Record = { + consumer: "消费者", + player: "打手", + owner: "店主", +} + +const navLinks = [ + { href: "/", label: "首页" }, + { href: "/community", label: "社区" }, + { href: "/orders", label: "订单" }, + { href: "/chat", label: "消息" }, +] + +export function Header() { + const [mobileOpen, setMobileOpen] = useState(false) + const pathname = usePathname() + const router = useRouter() + const { isAuthenticated, currentRole, switchRole, login, logout } = useAuthStore() + + const unreadCount = mockNotifications.filter((n) => !n.read).length + + const handleSearch = (e: React.FormEvent) => { + e.preventDefault() + const formData = new FormData(e.currentTarget) + const q = formData.get("q") as string + if (q.trim()) router.push(`/search?q=${encodeURIComponent(q.trim())}`) + } + + return ( +
+
+ + + 聚玩 + + + + +
+
+ + +
+
+ +
+ {isAuthenticated ? ( + <> + + + + + + 切换身份 + + {(Object.entries(roleLabels) as [UserRole, string][]).map(([role, label]) => ( + switchRole(role)} + className={cn(currentRole === role && "bg-accent")} + > + {label} + + ))} + + + + + + + + + + + {currentUser.nickname} + + + + + + 个人主页 + + + + + + 我的订单 + + + + + + 消息 + + + + + + 钱包 + + + {(currentRole === "player" || currentRole === "owner") && ( + + + + 管理后台 + + + )} + + + + 设置 + + + + + + + 退出登录 + + + + + ) : ( +
+ + +
+ )} + + + + + + + + + + 聚玩 + + +
+
+
+ + +
+
+ + {isAuthenticated && ( +
+ + + {currentUser.nickname[0]} + +
+

{currentUser.nickname}

+

{roleLabels[currentRole]}

+
+
+ )} + + + + {isAuthenticated && ( +
+

切换身份

+
+ {(Object.entries(roleLabels) as [UserRole, string][]).map(([role, label]) => ( + + ))} +
+
+ )} + + {!isAuthenticated && ( +
+ + +
+ )} +
+
+
+
+
+
+ ) +}