"use client" import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" import { Button } from "@/components/ui/button" import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" import { Input } from "@/components/ui/input" import { Label } from "@/components/ui/label" import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select" import { Separator } from "@/components/ui/separator" import { Switch } from "@/components/ui/switch" import { Textarea } from "@/components/ui/textarea" import { getCurrentUserForLogin, switchCurrentRole, updateCurrentUser, uploadFile } from "@/lib/api" import { toApiError } from "@/lib/errors" import { notifyInfo, notifySuccess } from "@/lib/toast" import type { UserRole } from "@/lib/types" import type { ThemePreference } from "@/store/auth" import { useAuthStore } from "@/store/auth" import { Camera } from "lucide-react" import { useTheme } from "next-themes" import Link from "next/link" import { useRef, useState } from "react" export default function SettingsPage() { const { currentRole, verifiedRoles, user, login, notificationPrefs, setNotificationPref } = useAuthStore() const [nickname, setNickname] = useState(user?.nickname ?? "") const [bio, setBio] = useState(user?.bio ?? "") const [avatar, setAvatar] = useState(user?.avatar ?? "") const [uploadingAvatar, setUploadingAvatar] = useState(false) const fileRef = useRef(null) const isRoleVerified = (role: UserRole) => verifiedRoles.includes(role) const { theme, setTheme } = useTheme() const setThemePreference = useAuthStore((s) => s.setThemePreference) function handleThemeChange(value: string) { const pref = value as ThemePreference setTheme(pref) setThemePreference(pref) } async function handleAvatarFile(file: File, resetInput: () => void) { setUploadingAvatar(true) try { const url = await uploadFile(file, "avatar") setAvatar(url) notifySuccess("头像已上传") } catch (error) { notifyInfo(toApiError(error).msg) } finally { setUploadingAvatar(false) resetInput() } } async function handleProfileSave() { if (!user) { notifyInfo("请先登录") return } try { const updated = await updateCurrentUser({ nickname: nickname.trim() || user.nickname, bio: bio.trim(), avatar, }) login(updated, updated.verifiedRoles ?? [updated.role]) notifySuccess("资料已保存") } catch (error) { notifyInfo(toApiError(error).msg) } } async function handleRoleChange(value: string) { const role = value as UserRole if (!isRoleVerified(role) || role === currentRole) return try { await switchCurrentRole(role) const updated = await getCurrentUserForLogin() login(updated, updated.verifiedRoles ?? [updated.role]) notifySuccess("身份已切换") } catch (error) { notifyInfo(toApiError(error).msg) } } return (

个人设置

头像
{user?.nickname?.[0] ?? "?"} { const target = event.currentTarget const file = target.files?.[0] if (!file) return void handleAvatarFile(file, () => { target.value = "" }) }} />

{uploadingAvatar ? "头像上传中..." : "点击上传头像,支持 JPG、PNG 格式"}

基本信息
setNickname(event.target.value)} />