"use client" import type React from "react" import { useState, useEffect } from "react" import type { FamilyMember, FamilyPhoto } from "@/types/family" import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { Label } from "@/components/ui/label" import { Textarea } from "@/components/ui/textarea" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select" import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group" import { CalendarIcon, User, Scroll, Users, Images, BookOpen } from "lucide-react" import { ChineseCard, ChineseCardContent, ChineseCardHeader, ChineseCardTitle, ChineseCardDescription } from "@/components/ui/chinese-card" import { Switch } from "@/components/ui/switch" import { ImageUpload } from "@/components/ui/image-upload" import { PhotoGallery } from "./photo-gallery" import { StoryManager } from "./story-manager" import { DateInputWithLunar } from "@/components/ui/date-input-with-lunar" import { MemberNameWithStatus } from "@/components/member-name-with-status" import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs" interface MemberFormProps { initialData?: Partial existingMembers?: FamilyMember[] onSubmit: (data: FamilyMember) => void onCancel: () => void isFounder?: boolean hideTabs?: boolean activeTab?: string } export function MemberForm({ initialData, existingMembers = [], onSubmit, onCancel, isFounder = false, hideTabs = false, activeTab = "basic" }: MemberFormProps) { // 计算最大世系 const maxGeneration = existingMembers.length > 0 ? Math.max(...existingMembers.map(m => m.generation || 1)) : 1 // 获取始祖的姓氏(第1世成员) const ancestorSurname = existingMembers.find(m => m.generation === 1)?.surname || "" // 始祖专用样式 const founderCardClass = isFounder ? "border-2 border-amber-400 shadow-md" : "" // 生成兼容的UUID const generateUUID = () => { if (typeof crypto !== 'undefined' && crypto.randomUUID) { return crypto.randomUUID() } // 降级方案:生成简单的UUID return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { const r = Math.random() * 16 | 0 const v = c === 'x' ? r : (r & 0x3 | 0x8) return v.toString(16) }) } // Initialize state with default values or initialData const [formData, setFormData] = useState>(() => { const defaults = { id: generateUUID(), surname: ancestorSurname, givenName: "", fullName: "", gender: "MALE" as "MALE" | "FEMALE", generation: maxGeneration, spouseIds: [], childrenIds: [], tags: [], photos: [] as FamilyPhoto[], photoIds: [] as string[], } if (!initialData) return defaults const normalizedPhotos: FamilyPhoto[] = initialData.photos && initialData.photos.length > 0 ? initialData.photos : (initialData.photoIds || []).map((url) => ({ url, uploadedAt: initialData.updatedAt || new Date().toISOString(), })) return { ...defaults, ...initialData, gender: (initialData.gender || "MALE").toUpperCase() as "MALE" | "FEMALE", spouseIds: initialData.spouseIds || [], childrenIds: initialData.childrenIds || [], tags: initialData.tags || [], fatherId: initialData.fatherId || undefined, motherId: initialData.motherId || undefined, photos: normalizedPhotos, photoIds: initialData.photoIds || normalizedPhotos.map((photo) => photo.url), } }) const [errors, setErrors] = useState([]) const handleChange = (field: keyof FamilyMember, value: any) => { setFormData((prev) => { const newData = { ...prev, [field]: value } // 自动更新全名 if (field === "surname" || field === "givenName") { newData.fullName = `${newData.surname || ""}${newData.givenName || ""}` } // 自动设置母亲从父亲 if (field === "fatherId" && value) { const father = existingMembers.find(m => m.id === value) if (father && father.spouseIds && father.spouseIds.length > 0) { const motherId = father.spouseIds[0] if (!newData.motherId) { newData.motherId = motherId } } } // 自动设置父亲从母亲 if (field === "motherId" && value) { const mother = existingMembers.find(m => m.id === value) if (mother && mother.spouseIds && mother.spouseIds.length > 0) { const fatherId = mother.spouseIds[0] if (!newData.fatherId) { newData.fatherId = fatherId } } } return newData }) } const handlePhotosChange = (photos: FamilyPhoto[]) => { setFormData((prev) => ({ ...prev, photos, photoIds: photos.map(p => p.url), })) } const handleSpouseAdd = (spouseId: string) => { if (spouseId === "none") return setFormData((prev) => ({ ...prev, spouseIds: [...(prev.spouseIds || []), spouseId], })) } const handleSpouseRemove = (spouseId: string) => { setFormData((prev) => ({ ...prev, spouseIds: (prev.spouseIds || []).filter((id) => id !== spouseId), })) } const handleChildAdd = (childId: string) => { if (childId === "none") return setFormData((prev) => ({ ...prev, childrenIds: [...(prev.childrenIds || []), childId], })) } const handleChildRemove = (childId: string) => { setFormData((prev) => ({ ...prev, childrenIds: (prev.childrenIds || []).filter((id) => id !== childId), })) } const validateForm = (): boolean => { const newErrors: string[] = [] if (!formData.surname?.trim()) { newErrors.push("请填写姓氏") } if (!formData.givenName?.trim()) { newErrors.push("请填写名字") } if (!formData.gender) { newErrors.push("请选择性别") } if (!formData.generation || formData.generation < 1) { newErrors.push("请填写正确的世系") } // 注:允许孤立成员存在,可以后续通过族谱关联功能建立关系 // 这样可以修正错误的关系设置 setErrors(newErrors) return newErrors.length === 0 } const handleSubmit = (e: React.FormEvent) => { e.preventDefault() if (!validateForm()) { return } // 确保所有必填字段都有值 // 注意:fatherId/motherId 需要显式设为 null 而不是 undefined, // 否则 JSON.stringify 会忽略 undefined 值,导致后端收不到更新 const memberData: FamilyMember = { id: formData.id || generateUUID(), surname: formData.surname || "", givenName: formData.givenName || "", fullName: formData.fullName || `${formData.surname || ""}${formData.givenName || ""}`, gender: formData.gender as "MALE" | "FEMALE", generation: formData.generation || 1, spouseIds: formData.spouseIds || [], childrenIds: formData.childrenIds || [], tags: formData.tags || [], photos: formData.photos || [], photoIds: formData.photoIds || [], fatherId: formData.fatherId, motherId: formData.motherId, spouseFatherName: formData.spouseFatherName, spouseMotherName: formData.spouseMotherName, phone: formData.phone, telephone: formData.telephone, email: formData.email, occupation: formData.occupation, courtesyName: formData.courtesyName, artName: formData.artName, generationName: formData.generationName, posthumousName: formData.posthumousName, birthDate: formData.birthDate, deathDate: formData.deathDate, isLunarDate: formData.isLunarDate || false, ancestralHome: formData.ancestralHome, birthPlace: formData.birthPlace, deathPlace: formData.deathPlace, burialPlace: formData.burialPlace, address: formData.address, bio: formData.bio, avatarUrl: formData.avatarUrl, stories: formData.stories || [], createdAt: formData.createdAt || new Date().toISOString(), updatedAt: new Date().toISOString(), } onSubmit(memberData) } const potentialRelatives = existingMembers.filter((m) => m.id !== formData.id) return (
{errors.length > 0 && (

请检查以下问题:

    {errors.map((err, index) => (
  • {err}
  • ))}
)} {!hideTabs && (
基本信息 详细资料 生平影像 家族故事
)}
{/* 基本信息Tab - 包含基本信息和家庭关系 */} {/* 基本信息卡片 */} 基本信息 {/* 头像和基本信息两栏布局 */}
{/* 左侧:头像 */}
handleChange("avatarUrl", imageUrl || null)} />
{/* 右侧:表单 */}
handleChange("surname", e.target.value)} placeholder="例如:李" className={errors.includes("surname") ? "border-red-500" : ""} />
handleChange("givenName", e.target.value)} placeholder="例如:明" className={errors.includes("givenName") ? "border-red-500" : ""} />
handleChange("gender", val)} className="flex space-x-4" >
handleChange("generation", parseInt(e.target.value) || 0)} className="w-32" min={1} />
{/* 家庭关系 - 左右两个独立卡片 */}
{/* 左栏:父母 */} 父母 {!isFounder && ( 需关联父母或配偶以连接至家族树 )}
{isFounder ? (
handleChange("spouseFatherName", e.target.value)} />

始祖为第一世,父母信息仅记录姓名

) : (
{!formData.fatherId && ( handleChange("spouseFatherName", e.target.value)} className="w-32" /> )}
)}
{isFounder ? (
handleChange("spouseMotherName", e.target.value)} />

始祖为第一世,父母信息仅记录姓名

) : (
{!formData.motherId && ( handleChange("spouseMotherName", e.target.value)} className="w-32" /> )}
)}
{/* 右栏:配偶和子女 */} 配偶与子女 {!isFounder && ( 需关联父母或配偶以连接至家族树 )}
{formData.spouseIds && formData.spouseIds.length > 0 && (
{formData.spouseIds.map((spouseId, index) => { const spouse = existingMembers.find(m => m.id === spouseId) if (!spouse) return null return (
{index + 1}.
) })}
)}
{formData.childrenIds && formData.childrenIds.length > 0 && (
{formData.childrenIds.map((childId, index) => { const child = existingMembers.find(m => m.id === childId) if (!child) return null return (
{index + 1}.
) })}
)}
{/* 详细资料Tab */} {/* 使用两列布局放置两个卡片 */}
传统称谓
handleChange("courtesyName", e.target.value)} placeholder="例如:伯虎" />
handleChange("artName", e.target.value)} placeholder="例如:六如居士" />
handleChange("generationName", e.target.value)} />
handleChange("posthumousName", e.target.value)} />
生平日期
handleChange("birthDate", value)} onLunarChange={(isLunar) => handleChange("isLunarDate", isLunar)} showLunarToggle={true} /> handleChange("deathDate", value)} onLunarChange={(isLunar) => handleChange("isLunarDate", isLunar)} showLunarToggle={true} />
{/* 地点和简介卡片 */} 地点与简介
handleChange("ancestralHome", e.target.value)} placeholder="请输入籍贯" />
handleChange("birthPlace", e.target.value)} placeholder="请输入出生地" />
handleChange("address", e.target.value)} placeholder="请输入居住地" />
handleChange("deathPlace", e.target.value)} placeholder="请输入逝世地" />
handleChange("burialPlace", e.target.value)} placeholder="请输入安葬地" />
handleChange("occupation", e.target.value)} placeholder="请输入职业" />
handleChange("phone", e.target.value)} placeholder="请输入手机号" />
handleChange("telephone", e.target.value)} placeholder="请输入固定电话" />
handleChange("email", e.target.value)} placeholder="请输入电子邮箱" />