'use client'; import * as React from 'react'; import { zodResolver } from '@hookform/resolvers/zod'; import { useForm } from 'react-hook-form'; import { z } from 'zod'; import dayjs from 'dayjs'; import 'dayjs/locale/zh-cn'; import { CalendarIcon, Plus, Trash2 } from 'lucide-react'; import { IconChevronDown, IconCheck, IconX } from '@tabler/icons-react'; import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle, SheetFooter, } from '@nice/ui/components/sheet'; import { Button } from '@nice/ui/components/button'; import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage, } from '@nice/ui/components/form'; import { Input } from '@nice/ui/components/input'; import { Textarea } from '@nice/ui/components/textarea'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@nice/ui/components/select'; import { Calendar } from '@nice/ui/components/calendar'; import { Popover, PopoverContent, PopoverTrigger } from '@nice/ui/components/popover'; import { DateTimePicker } from '@nice/ui/components/date-time-picker'; import { Command, CommandEmpty, CommandGroup, CommandItem, CommandList, } from '@nice/ui/components/command'; import { Card, CardContent, CardHeader, CardTitle } from '@nice/ui/components/card'; import { cn } from '@nice/ui/lib/utils'; import { DeptSelect, DutySelect } from '@/components/selector'; import { AvatarUpload } from '@/components/common/avatar-upload'; import { Education, EducationForm, PoliticalStatus, TrainType, AppraisalLevel, ProfileMetadata } from '@fenghuo/common'; import { useProfile } from './profile-provider'; import { useTranslation } from '@nice/i18n'; // 定义表单验证模式 const createProfileFormSchema = (t: (key: string) => string) => z.object({ // 基本信息 name: z.string().min(1, t('profile.profile_sheet.validation.name_required')), gender: z.number().min(1).max(2), idNum: z.string().min(15, t('profile.profile_sheet.validation.id_number_min_length')), paperId: z.string().min(1, t('profile.profile_sheet.validation.certificate_number_required')), // 改为必选 avatar: z.string().optional(), // 添加头像字段,可选 command: z.string(), // 添加编制命令字段 birthday: z.date().optional(), // 添加生日字段 // 入职信息 - 改为必选 hireDate: z.date({ required_error: t('profile.profile_sheet.validation.hire_date_required') }), relativeHireDate: z.date().optional(), // 身份信息 - 改为必选 identity: z.string().min(1, t('profile.profile_sheet.validation.identity_required')), level: z.string().min(1, t('profile.profile_sheet.validation.rank_required')), levelDate: z.date({ required_error: t('profile.profile_sheet.validation.rank_time_required') }), // 职务信息 - 改为必选 dutyCode: z.string().optional(), dutyLevel: z.string().optional(), // 改为非必选 dutyName: z.string().min(1, t('profile.profile_sheet.validation.duty_name_required')), // 组织信息 - 改为必选 organizationId: z.string().min(1, t('profile.profile_sheet.validation.organization_required')), // 元数据 metadata: z.object({ ethnicity: z.string().optional(), bloodType: z.string().optional(), proxyDuty: z.string().optional(), isRehire: z.boolean().optional(), isExtendedDeparture: z.boolean().optional(), positionYear: z.number().optional(), politicalStatus: z.string().optional(), partyPosition: z.string().optional(), native: z.object({ province: z.string().optional(), city: z.string().optional(), county: z.string().optional(), }).optional(), education: z.string().optional(), educationForm: z.string().optional(), isGraduate: z.boolean().optional(), schoolMajor: z.string().optional(), drills: z.number().optional(), train: z.array(z.object({ type: z.string().optional(), location: z.string().optional(), major: z.string().optional(), })).optional(), appraisal: z.array(z.object({ level: z.string().optional(), job: z.string().optional(), })).optional(), foreignLanguage: z.string().optional(), reward: z.string().optional(), punish: z.string().optional(), remark: z.string().optional(), }).optional(), }); // 职务水平选择器组件 interface DutyLevelSelectProps { value?: string; onValueChange?: (value: string) => void; placeholder?: string; className?: string; disabled?: boolean; } function DutyLevelSelect({ value, onValueChange, placeholder = '请选择职务水平', className, disabled = false, }: DutyLevelSelectProps) { const { t } = useTranslation(); const [open, setOpen] = React.useState(false); // 职务水平选项 const dutyLevelOptions = [ { value: '1', label: t('profile.profile_sheet.duty_level_primary') }, { value: '2', label: t('profile.profile_sheet.duty_level_middle') }, { value: '3', label: t('profile.profile_sheet.duty_level_high') }, ]; // 获取当前选中的选项 const selectedOption = dutyLevelOptions.find(option => option.value === value); // 处理选择逻辑 const handleSelect = (selectedValue: string) => { if (!onValueChange) return; // 如果点击的是当前已选中的值,则清空选择 if (value === selectedValue) { onValueChange(''); } else { onValueChange(selectedValue); } setOpen(false); }; // 清除选择 const handleClear = (e: React.MouseEvent) => { e.preventDefault(); e.stopPropagation(); onValueChange?.(''); }; return ( {t('profile.profile_sheet.duty_level_not_found')} {dutyLevelOptions.map((option) => ( handleSelect(option.value)} className={cn( 'flex items-center justify-between cursor-pointer', 'hover:bg-accent hover:text-accent-foreground', value === option.value && 'bg-accent text-accent-foreground', )} > {option.label} {value === option.value && ( )} ))} ); } export function ProfileSheet() { const { t } = useTranslation(); const { isSheetOpen, setIsSheetOpen, editingProfile, sheetMode, handleSubmitEmployee, } = useProfile(); // 创建动态的表单验证模式 const profileFormSchema = React.useMemo(() => createProfileFormSchema(t), [t]); type ProfileFormValues = z.infer; const form = useForm({ resolver: zodResolver(profileFormSchema), defaultValues: { name: '', gender: 1, idNum: '', paperId: '', avatar: '', command: '', birthday: undefined, hireDate: undefined, // 改为 undefined,保持一致性 relativeHireDate: undefined, // 改为 undefined,保持一致性 identity: '', level: '', levelDate: undefined, // 改为 undefined,保持一致性 dutyCode: '', dutyLevel: '', dutyName: '', organizationId: '', metadata: { ethnicity: '', bloodType: '', proxyDuty: '', isRehire: false, isExtendedDeparture: false, positionYear: undefined, politicalStatus: '', partyPosition: '', native: { province: '', city: '', county: '', }, education: '', educationForm: '', isGraduate: false, schoolMajor: '', drills: undefined, train: [{ type: '', location: '', major: '' }], appraisal: [{ level: '', job: '' }], foreignLanguage: '', reward: '', punish: '', remark: '', }, }, }); // 当编辑数据变化时,回显数据 React.useEffect(() => { if (editingProfile && sheetMode === 'edit') { const metadata = editingProfile.metadata as ProfileMetadata; form.reset({ name: editingProfile.name || '', gender: editingProfile.gender || 1, idNum: editingProfile.idNum || '', paperId: editingProfile.paperId || '', avatar: editingProfile.avatar || '', birthday: editingProfile.birthday ? new Date(editingProfile.birthday) : undefined, command: editingProfile.command || '', hireDate: editingProfile.hireDate ? new Date(editingProfile.hireDate) : undefined, relativeHireDate: editingProfile.relativeHireDate ? new Date(editingProfile.relativeHireDate) : undefined, identity: editingProfile.identity || '', level: editingProfile.level || '', levelDate: editingProfile.levelDate ? new Date(editingProfile.levelDate) : undefined, dutyCode: editingProfile.dutyCode || '', dutyLevel: editingProfile.dutyLevel?.toString() || '', dutyName: editingProfile.dutyName || '', organizationId: editingProfile.organizationId || '', metadata: { ethnicity: metadata?.ethnicity || '', bloodType: metadata?.bloodType || '', proxyDuty: metadata?.proxyDuty || '', isRehire: metadata?.isRehire || false, isExtendedDeparture: metadata?.isExtendedDeparture || false, positionYear: metadata?.positionYear, politicalStatus: metadata?.politicalStatus || '', partyPosition: metadata?.partyPosition || '', native: { province: metadata?.native?.province || '', city: metadata?.native?.city || '', county: metadata?.native?.county || '', }, education: metadata?.education || '', educationForm: metadata?.educationForm || '', isGraduate: metadata?.isGraduate || false, schoolMajor: metadata?.schoolMajor || '', drills: metadata?.drills, train: metadata?.train || [{ type: '', location: '', major: '' }], appraisal: metadata?.appraisal || [{ level: '', job: '' }], foreignLanguage: metadata?.foreignLanguage || '', reward: metadata?.reward || '', punish: metadata?.punish || '', remark: metadata?.remark || '', }, }); } else if (sheetMode === 'create') { // 创建模式时重置表单 - 保持与 defaultValues 一致 form.reset({ name: '', gender: 1, idNum: '', paperId: '', avatar: '', birthday: undefined, command: '', hireDate: undefined, relativeHireDate: undefined, identity: '', level: '', levelDate: undefined, dutyCode: '', dutyLevel: '', dutyName: '', organizationId: '', metadata: { ethnicity: '', bloodType: '', proxyDuty: '', isRehire: false, isExtendedDeparture: false, positionYear: undefined, politicalStatus: '', partyPosition: '', native: { province: '', city: '', county: '', }, education: '', educationForm: '', isGraduate: false, schoolMajor: '', drills: undefined, train: [{ type: '', location: '', major: '' }], appraisal: [{ level: '', job: '' }], foreignLanguage: '', reward: '', punish: '', remark: '', }, }); } }, [editingProfile, sheetMode, form]); // 处理 Sheet 开关状态变化 const handleOpenChange = (newOpen: boolean) => { setIsSheetOpen(newOpen); // 当 Sheet 关闭时清空表单 if (!newOpen) { form.reset(); } }; const handleSubmit = (data: ProfileFormValues) => { handleSubmitEmployee(data); setIsSheetOpen(false); form.reset(); }; const addTrainExperience = () => { const current = form.getValues('metadata.train') || []; form.setValue('metadata.train', [...current, { type: '', location: '', major: '' }]); }; const removeTrainExperience = (index: number) => { const current = form.getValues('metadata.train') || []; form.setValue('metadata.train', current.filter((_, i) => i !== index)); }; const addAppraisalExperience = () => { const current = form.getValues('metadata.appraisal') || []; form.setValue('metadata.appraisal', [...current, { level: '', job: '' }]); }; const removeAppraisalExperience = (index: number) => { const current = form.getValues('metadata.appraisal') || []; form.setValue('metadata.appraisal', current.filter((_, i) => i !== index)); }; const politicalStatusOptions = Object.values(PoliticalStatus); const educationFormOptions = Object.values(EducationForm); const trainTypeOptions = Object.values(TrainType); const appraisalLevelOptions = Object.values(AppraisalLevel); const educationOptions = Object.values(Education); return ( {sheetMode === 'edit' ? t('profile.profile_sheet.title_edit') : t('profile.profile_sheet.title_add') } {sheetMode === 'edit' ? t('profile.profile_sheet.description_edit') : t('profile.profile_sheet.description_add') },{t('profile.profile_sheet.required_fields_note')}
{/* 基本信息 */} {t('profile.profile_sheet.basic_info')} {/* 头像和表单字段 */}
{/* 头像上传区域 - 3:4 长方形 */}
( )} />
{/* 表单字段区域 */}
{/* 姓名和性别 */}
( {t('profile.profile_sheet.name') + ' *'} )} /> ( {t('profile.profile_sheet.gender') + ' *'} )} />
{/* 身份证号和证件号 */}
( {t('profile.profile_sheet.id_number') + ' *'} )} /> ( {t('profile.profile_sheet.certificate_number') + ' *'} )} />
{/* 编制命令 - 占据一整行 */} ( {t('profile.profile_sheet.formation_command') + ' *'} )} />
{/* 组织信息 */} {t('profile.profile_sheet.organization_info')} ( {t('profile.profile_sheet.organization') + ' *'} )} /> {/* 职务信息 */} {t('profile.profile_sheet.duty_info')}
( {t('profile.profile_sheet.duty_name') + ' *'} )} /> ( {t('profile.profile_sheet.duty_code')} )} /> ( {t('profile.profile_sheet.duty_level')} )} />
{/* 身份信息 */} {t('profile.profile_sheet.identity_info')}
( {t('profile.profile_sheet.identity') + ' *'} )} /> ( {t('profile.profile_sheet.rank') + ' *'} )} /> ( {t('profile.profile_sheet.rank_time') + ' *'} date > new Date() || date < new Date("1900-01-01") } initialFocus /> )} />
{/* 入职信息 */} {t('profile.profile_sheet.hire_info')}
( {t('profile.profile_sheet.hire_date') + ' *'} date > new Date() || date < new Date("1900-01-01") } initialFocus /> )} /> ( {t('profile.profile_sheet.relative_hire_time')} date > new Date() || date < new Date("1900-01-01") } initialFocus /> )} />
{/* 详细信息 */} {t('profile.profile_sheet.detailed_info')} {/* 基本详细信息 */}
( {t('profile.profile_sheet.ethnicity')} )} /> ( {t('profile.profile_sheet.birth_date')} )} /> ( {t('profile.profile_sheet.blood_type')} )} />
{/* 政治面貌 */}
( {t('profile.profile_sheet.political_status')} )} /> ( {t('profile.profile_sheet.party_position')} )} />
{/* 籍贯 */}
{t('profile.profile_sheet.native_place')}
( )} /> ( )} /> ( )} />
{/* 学历信息 */}
( {t('profile.profile_sheet.education')} )} /> ( {t('profile.profile_sheet.education_form')} )} /> ( {t('profile.profile_sheet.school_major')} )} />
{/* 其他信息 */}
( {t('profile.profile_sheet.position_year')} field.onChange(e.target.value ? Number(e.target.value) : undefined)} /> )} /> ( {t('profile.profile_sheet.foreign_language')} )} />
{/* 培训经历 */}
{t('profile.profile_sheet.train_experience')}
{form.watch('metadata.train')?.map((_, index) => (

{t('profile.profile_sheet.train_experience')} {index + 1}

{index > 0 && ( )}
( {t('profile.profile_sheet.train_type')} )} /> ( {t('profile.profile_sheet.train_location')} )} />
( {t('profile.profile_sheet.train_major')} )} />
))}
{/* 考核经历 */}
{t('profile.profile_sheet.appraisal_experience')}
{form.watch('metadata.appraisal')?.map((_, index) => (

{t('profile.profile_sheet.appraisal_experience')} {index + 1}

{index > 0 && ( )}
( {t('profile.profile_sheet.appraisal_level')} )} /> ( {t('profile.profile_sheet.appraisal_job')} )} />
))}
{/* 奖励 - 独占一行 */} ( {t('profile.profile_sheet.reward')}