'use client'; import { useEffect, useMemo, useState } from 'react'; import { useRouter } from 'next/navigation'; import { LogOut, User, KeyRound, Eye, EyeOff, Mail, Loader2, Check } from 'lucide-react'; import { useAuthStore } from '@/stores/useAuthStore'; import { useMemberStore } from '@/stores/useMemberStore'; import { FieldError } from '@/components/FieldError'; type Tab = 'info' | 'password'; export default function ProfilePage() { const router = useRouter(); const user = useAuthStore((s) => s.user); const logout = useAuthStore((s) => s.logout); const { fetchMembers, roles, departments } = useMemberStore(); const [activeTab, setActiveTab] = useState('info'); useEffect(() => { fetchMembers(); }, [fetchMembers]); useEffect(() => { if (!user) router.push('/login'); }, [user, router]); if (!user) return null; const role = roles.find((r) => r.id === user.roleId); const deptName = useMemo(() => { const d = departments.find((x) => x.id === user.departmentId); if (!d) return '-'; if (d.parentId) { const parent = departments.find((x) => x.id === d.parentId); return parent ? `${parent.name} / ${d.name}` : d.name; } return d.name; }, [departments, user.departmentId]); const handleLogout = () => { if (!confirm('确认退出当前账号?')) return; logout(); router.push('/login'); }; return (
{user.name?.[0] ?? '?'}

{user.name}

{role?.name ?? '-'} · {deptName}

{user.username} {user.email && ( {user.email} )}
setActiveTab('info')} icon={User} label="个人信息" /> setActiveTab('password')} icon={KeyRound} label="修改密码" />
{activeTab === 'info' ? : }
); } function TabButton({ active, onClick, icon: Icon, label }: { active: boolean; onClick: () => void; icon: any; label: string }) { return ( ); } function CardHeader({ title, subtitle }: { title: string; subtitle: string }) { return (

{title}

{subtitle}

); } function InfoForm() { const user = useAuthStore((s) => s.user)!; const refreshUser = useAuthStore((s) => s.refreshUser); const { members, departments, roles, updateMember } = useMemberStore(); const member = members.find((m) => m.id === user.id); const [name, setName] = useState(member?.name ?? user.name); const [email, setEmail] = useState(member?.email ?? user.email); const [errors, setErrors] = useState<{ name?: string; email?: string }>({}); const [submitting, setSubmitting] = useState(false); const [savedAt, setSavedAt] = useState(0); const deptName = useMemo(() => { const d = departments.find((x) => x.id === user.departmentId); if (!d) return '-'; if (d.parentId) { const parent = departments.find((x) => x.id === d.parentId); return parent ? `${parent.name} / ${d.name}` : d.name; } return d.name; }, [departments, user.departmentId]); const roleName = roles.find((r) => r.id === user.roleId)?.name ?? '-'; const handleReset = () => { setName(member?.name ?? user.name); setEmail(member?.email ?? user.email); setErrors({}); }; const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); const errs: typeof errors = {}; if (!name.trim()) errs.name = '请输入姓名'; else if (name.trim().length > 20) errs.name = '姓名最长 20 字符'; if (!email.trim()) errs.email = '请输入邮箱'; else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email.trim())) errs.email = '邮箱格式错误'; setErrors(errs); if (Object.keys(errs).length > 0) return; setSubmitting(true); setTimeout(() => { updateMember(user.id, { name: name.trim(), email: email.trim() }); refreshUser(); setSubmitting(false); setSavedAt(Date.now()); setTimeout(() => setSavedAt(0), 3000); }, 200); }; return (
setName(e.target.value)} className="h-9 w-full rounded-lg border border-[var(--line)] bg-[var(--bg-card)] px-3 text-[13px] focus:border-[var(--accent)] focus:outline-none" /> setEmail(e.target.value)} placeholder="name@company.com" className="h-9 w-full rounded-lg border border-[var(--line)] bg-[var(--bg-card)] px-3 text-[13px] focus:border-[var(--accent)] focus:outline-none" />
{savedAt > 0 && ( 已保存 )}
); } function PasswordForm() { const user = useAuthStore((s) => s.user)!; const { members, updateMember } = useMemberStore(); const [oldPwd, setOldPwd] = useState(''); const [newPwd, setNewPwd] = useState(''); const [confirmPwd, setConfirmPwd] = useState(''); const [showOld, setShowOld] = useState(false); const [showNew, setShowNew] = useState(false); const [showConfirm, setShowConfirm] = useState(false); const [errors, setErrors] = useState<{ oldPwd?: string; newPwd?: string; confirmPwd?: string }>({}); const [submitting, setSubmitting] = useState(false); const [savedAt, setSavedAt] = useState(0); const handleReset = () => { setOldPwd(''); setNewPwd(''); setConfirmPwd(''); setErrors({}); }; const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); const member = members.find((m) => m.id === user.id); const errs: typeof errors = {}; if (!oldPwd) errs.oldPwd = '请输入当前密码'; else if (member && oldPwd !== member.password) errs.oldPwd = '当前密码错误'; if (!newPwd) errs.newPwd = '请输入新密码'; else if (newPwd.length < 8) errs.newPwd = '新密码长度至少 8 位'; else if (newPwd === oldPwd) errs.newPwd = '新密码不能与当前密码相同'; if (!confirmPwd) errs.confirmPwd = '请再次输入新密码'; else if (confirmPwd !== newPwd) errs.confirmPwd = '两次输入不一致'; setErrors(errs); if (Object.keys(errs).length > 0) return; setSubmitting(true); setTimeout(() => { updateMember(user.id, { password: newPwd }); handleReset(); setSubmitting(false); setSavedAt(Date.now()); setTimeout(() => setSavedAt(0), 3000); }, 200); }; return (
setShowOld(!showOld)} /> setShowNew(!showNew)} /> setShowConfirm(!showConfirm)} />
{savedAt > 0 && ( 密码已修改,下次登录生效 )}
); } function Field({ label, required, children }: { label: string; required?: boolean; children: React.ReactNode }) { return (
{children}
); } function PwdInput({ value, onChange, show, onToggle }: { value: string; onChange: (v: string) => void; show: boolean; onToggle: () => void }) { return (
onChange(e.target.value)} className="h-9 w-full rounded-lg border border-[var(--line)] bg-[var(--bg-card)] px-3 pr-9 text-[13px] focus:border-[var(--accent)] focus:outline-none" />
); }