import { useState } from 'react'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { Pencil, Upload, User as UserIcon } from 'lucide-react'; import { profileGet, profilePhotoUpload, profileUpsert } from '@/lib/api'; import type { ProfileInfo } from '@/lib/types'; import { Button, Dialog, Field, Input, Select, Textarea, useToast } from '@/components/ui'; const EMPTY: ProfileInfo = { name: '', gender: '', birth: '', nation: '', native: '', political: '', school: '', college: '', major: '', className: '', studentId: '', degree: '', phone: '', email: '', homepage: '', photoUrl: '', selfIntro: '', eduLength: '', eduStart: '', eduEnd: '', majorCourses: '' }; const FIELD_GROUPS: { title: string; fields: { key: keyof ProfileInfo; label: string; type?: string; options?: string[] }[] }[] = [ { title: '基本信息', fields: [ { key: 'name', label: '姓名' }, { key: 'gender', label: '性别', options: ['', '男', '女'] }, { key: 'birth', label: '出生日期', type: 'date' }, { key: 'nation', label: '民族' }, { key: 'native', label: '籍贯' }, { key: 'political', label: '政治面貌' }, ]}, { title: '学校信息', fields: [ { key: 'school', label: '学校' }, { key: 'college', label: '学院' }, { key: 'major', label: '专业' }, { key: 'className', label: '班级' }, { key: 'studentId', label: '学号' }, { key: 'degree', label: '学历层次', options: ['', '专科', '本科', '硕士研究生', '博士研究生'] }, { key: 'eduLength', label: '学制', options: ['', '两年', '三年', '四年', '五年'] }, { key: 'eduStart', label: '入学时间', type: 'month' }, { key: 'eduEnd', label: '毕业时间', type: 'month' }, ]}, { title: '主修课程', fields: [ { key: 'majorCourses', label: '主修课程' }, ]}, { title: '联系方式', fields: [ { key: 'phone', label: '手机' }, { key: 'email', label: '邮箱' }, { key: 'homepage', label: '个人主页 / 博客' }, ]}, ]; export function ProfilePage() { const qc = useQueryClient(); const toast = useToast(); const [editing, setEditing] = useState(false); const [form, setForm] = useState(EMPTY); const [photoBusy, setPhotoBusy] = useState(false); const q = useQuery({ queryKey: ['profile'], queryFn: profileGet }); const info: Partial = q.data?.content?.info ?? {}; const set = (patch: Partial) => setForm(f => ({ ...EMPTY, ...f, ...patch })); const openEdit = () => { setForm({ ...EMPTY, ...info }); setEditing(true); }; const saveMut = useMutation({ mutationFn: () => profileUpsert({ info: form }), onSuccess: () => { toast('success', '个人信息已保存'); setEditing(false); void qc.invalidateQueries({ queryKey: ['profile'] }); }, onError: (e: Error) => toast('error', e.message) }); const onPhoto = async (f: File | undefined) => { if (!f) return; setPhotoBusy(true); try { const url = await profilePhotoUpload(f); // 以已保存档案为底,只更新 photoUrl —— 避免覆盖其他字段 const next = { ...EMPTY, ...info, photoUrl: url }; await profileUpsert({ info: next }); setForm(prev => ({ ...EMPTY, ...prev, photoUrl: url })); void qc.invalidateQueries({ queryKey: ['profile'] }); toast('success', '证件照已上传'); } catch (e) { toast('error', (e as Error).message); } setPhotoBusy(false); }; const photo = info.photoUrl; return (

个人信息

{q.isLoading ? (
加载中…
) : (
{photo ? 证件照 : }
{info.name || '未填写姓名'}
{[info.school, info.college, info.major].filter(Boolean).join(' · ') || '完善学校信息后,简历将自动填充'}
{FIELD_GROUPS.map(g => (
{g.title}
{g.fields.map(f => { const v = (info[f.key] as string) || ''; return (
{f.label}
{v || '未填写'}
); })}
))}
)} {!info.selfIntro && (
提示:编辑里填写「自我评价」后,可一键用于简历生成。
)} setEditing(false)} width={720} title="编辑个人信息" footer={<> 填写一次,填表与简历自动复用 }>
{FIELD_GROUPS.map(g => (
{g.title}
{g.fields.map(f => ( {f.options ? ( set({ [f.key]: e.target.value } as Partial)} /> )} ))}
))}