)
}
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}
+
)
}
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 (
)
}
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 (
+
+ )
+}
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 && (
+
+
+
+
+ )}
+
+
+
+
+
+
+ )
+}