"use client" import Link from "next/link" import { useRouter, useSearchParams } from "next/navigation" import { Suspense, type ReactNode } from "react" import { useTranslations } from "next-intl" import { User, Palette, Lock, Bell, Sparkles } from "lucide-react" import { signOut } from "next-auth/react" import { ThemePreferencesCard } from "@/modules/settings/components/theme-preferences-card" import { ProfileSettingsForm } from "@/modules/settings/components/profile-settings-form" import { PasswordChangeForm } from "@/modules/settings/components/password-change-form" import { NotificationPreferencesForm } from "@/modules/settings/components/notification-preferences-form" import { AiProviderSettingsCard } from "@/modules/settings/components/ai-provider-settings-card" import { SettingsSectionErrorBoundary } from "@/modules/settings/components/settings-section-error-boundary" import { Button } from "@/shared/components/ui/button" import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/shared/components/ui/card" import { Skeleton } from "@/shared/components/ui/skeleton" import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/shared/components/ui/tabs" import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, } from "@/shared/components/ui/alert-dialog" import type { UserProfile } from "@/modules/users/data-access" import type { NotificationPreferences } from "@/modules/notifications/types" import { usePermission } from "@/shared/hooks/use-permission" import { Permissions } from "@/shared/types/permissions" interface SettingsViewProps { /** 页面副标题描述(i18n 键) */ description: string /** 返回仪表盘的链接 */ backHref: string /** 当前用户 */ user: UserProfile /** 通知偏好 */ notificationPreferences: NotificationPreferences /** General 标签页中 ProfileSettingsForm 下方的内容(角色专属快捷链接等) */ generalExtra?: ReactNode } const VALID_TABS = ["general", "notifications", "appearance", "security", "ai"] as const type TabValue = (typeof VALID_TABS)[number] function isTabValue(value: string | null): value is TabValue { return value !== null && (VALID_TABS as readonly string[]).includes(value) } function SettingsSectionSkeleton(): ReactNode { return ( {Array.from({ length: 4 }).map((_, i) => ( ))} ) } /** * 统一设置页视图 * * 消除 admin / teacher / student / parent 四个设置视图的重复布局: * - 相同的页面头部(标题 + 描述 + 返回按钮) * - 相同的标签页(General / Notifications / Appearance / Security / AI) * - 相同的 Notifications / Appearance / Security 标签页内容 * - 相同的 Session 卡片(登出) * * 角色差异通过 `description`、`backHref` 和 `generalExtra` 三个 props 注入。 * 当前激活的标签页通过 URL `?tab=` 参数持久化。 * 每个标签页内容用 Error Boundary + Suspense 包裹,局部失败不影响整页。 */ function SettingsViewInner({ description, backHref, user, notificationPreferences, generalExtra, }: SettingsViewProps) { const t = useTranslations("settings") const router = useRouter() const searchParams = useSearchParams() const { hasPermission } = usePermission() const tabParam = searchParams.get("tab") const activeTab: TabValue = isTabValue(tabParam) ? tabParam : "general" const handleTabChange = (value: string) => { const params = new URLSearchParams(searchParams.toString()) if (value === "general") { params.delete("tab") } else { params.set("tab", value) } const query = params.toString() router.push(query ? `?${query}` : "?", { scroll: false }) } const canConfigureAi = hasPermission(Permissions.AI_CONFIGURE) return (

{t("title")}

{description}
{t("tabs.general")} {t("tabs.notifications")} {t("tabs.appearance")} {t("tabs.security")} {canConfigureAi ? ( {t("tabs.ai")} ) : null} }> {generalExtra} }> }> }> {t("security.session.title")} {t("security.session.description")}
{t("security.session.signOut")}
{t("security.session.signOutDesc")}
{t("security.session.confirmTitle")} {t("security.session.confirmDesc")} {t("security.session.cancel")} signOut({ callbackUrl: "/login" })}> {t("security.session.confirm")}
{canConfigureAi ? ( }> ) : null}
) } export function SettingsView(props: SettingsViewProps) { return ( ) }