0.6.0.1
This commit is contained in:
+106
-52
@@ -10,7 +10,7 @@ import { permissions } from "@/lib/permissions"
|
||||
import { MemberNameWithStatus } from "@/components/member-name-with-status"
|
||||
import { MemberVersionHistory } from "@/components/members/member-version-history"
|
||||
import { useSession } from "next-auth/react"
|
||||
import { useEffect, useState } from "react"
|
||||
import { useEffect, useState, useCallback } from "react"
|
||||
import { useParams, useRouter } from "next/navigation"
|
||||
import Link from "next/link"
|
||||
import { useFamily } from "@/context/family-context"
|
||||
@@ -19,6 +19,7 @@ import { SiteHeader } from "@/components/site-header"
|
||||
import { MemberForm } from "@/components/members/member-form"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs"
|
||||
import { AddRelationDialog, type RelationType } from "@/components/tree/add-relation-dialog"
|
||||
|
||||
export default function MemberProfilePage() {
|
||||
const { id } = useParams()
|
||||
@@ -32,6 +33,11 @@ export default function MemberProfilePage() {
|
||||
const [isUploadingAvatar, setIsUploadingAvatar] = useState(false)
|
||||
const [lastSaveTime, setLastSaveTime] = useState(Date.now())
|
||||
|
||||
// 添加成员对话框状态
|
||||
const [relationDialog, setRelationDialog] = useState<{
|
||||
type: RelationType
|
||||
} | null>(null)
|
||||
|
||||
// 未登录时重定向到登录页
|
||||
useEffect(() => {
|
||||
if (status === 'unauthenticated') {
|
||||
@@ -124,56 +130,100 @@ export default function MemberProfilePage() {
|
||||
}
|
||||
}
|
||||
|
||||
const handleQuickAddChild = () => {
|
||||
// 跳转到新增成员页面,并预填父母信息
|
||||
const params = new URLSearchParams(window.location.search)
|
||||
if (member.gender === 'MALE') {
|
||||
params.set('fatherId', member.id)
|
||||
// 如果父亲有配偶,设置配偶为母亲
|
||||
if (member.spouseIds && member.spouseIds.length > 0) {
|
||||
params.set('motherId', member.spouseIds[0])
|
||||
}
|
||||
} else {
|
||||
params.set('motherId', member.id)
|
||||
// 如果母亲有配偶,设置配偶为父亲
|
||||
if (member.spouseIds && member.spouseIds.length > 0) {
|
||||
params.set('fatherId', member.spouseIds[0])
|
||||
// 姓名分解函数
|
||||
const parseName = (fullName: string): { surname: string; givenName: string } => {
|
||||
const name = fullName.trim()
|
||||
if (!name) return { surname: '', givenName: '' }
|
||||
|
||||
const compoundSurnames = [
|
||||
'欧阳', '太史', '端木', '上官', '司马', '东方', '独孤', '南宫', '万俟', '闻人',
|
||||
'夏侯', '诸葛', '尉迟', '公羊', '赫连', '澹台', '皇甫', '宗政', '濮阳', '公冶',
|
||||
'太叔', '申屠', '公孙', '慕容', '仲孙', '钟离', '长孙', '宇文', '司徒', '鲜于',
|
||||
'司空', '闾丘', '子车', '亓官', '司寇', '巫马', '公西', '颛孙', '壤驷', '公良',
|
||||
'漆雕', '乐正', '宰父', '谷梁', '拓跋', '夹谷', '轩辕', '令狐', '段干', '百里',
|
||||
'呼延', '东郭', '南门', '羊舌', '微生', '公户', '公玉', '公仪', '梁丘', '公仲',
|
||||
'公上', '公门', '公山', '公坚', '左丘', '公伯', '西门', '公祖', '第五', '公乘',
|
||||
'贯丘', '公皙', '南荣', '东里', '东宫', '仲长', '子书', '子桑', '即墨', '达奚', '褚师'
|
||||
]
|
||||
|
||||
for (const compound of compoundSurnames) {
|
||||
if (name.startsWith(compound) && name.length > compound.length) {
|
||||
return { surname: compound, givenName: name.slice(compound.length) }
|
||||
}
|
||||
}
|
||||
params.set('generation', (member.generation + 1).toString())
|
||||
|
||||
if (name.length >= 2) {
|
||||
return { surname: name.charAt(0), givenName: name.slice(1) }
|
||||
}
|
||||
|
||||
return { surname: name, givenName: '' }
|
||||
}
|
||||
|
||||
// 创建新成员的处理函数
|
||||
const handleCreateNewRelation = useCallback((prefillName: string, relationType: RelationType) => {
|
||||
if (!member) return
|
||||
const params = new URLSearchParams()
|
||||
|
||||
const { surname, givenName } = parseName(prefillName)
|
||||
if (surname) params.set("surname", surname)
|
||||
if (givenName) params.set("givenName", givenName)
|
||||
|
||||
if (relationType === "child") {
|
||||
params.set("generation", String(member.generation + 1))
|
||||
if (member.gender === "MALE") {
|
||||
params.set("fatherId", member.id)
|
||||
if (member.spouseIds?.length) {
|
||||
params.set("motherId", member.spouseIds[0])
|
||||
}
|
||||
} else if (member.gender === "FEMALE") {
|
||||
params.set("motherId", member.id)
|
||||
if (member.spouseIds?.length) {
|
||||
params.set("fatherId", member.spouseIds[0])
|
||||
}
|
||||
}
|
||||
} else if (relationType === "spouse") {
|
||||
params.set("generation", String(member.generation))
|
||||
params.set("spouseId", member.id)
|
||||
params.set("gender", member.gender === "MALE" ? "FEMALE" : "MALE")
|
||||
if (member.childrenIds && member.childrenIds.length > 0) {
|
||||
member.childrenIds.forEach(id => {
|
||||
params.append('childrenIds', id)
|
||||
})
|
||||
}
|
||||
} else if (relationType === "father") {
|
||||
params.set("generation", String(member.generation - 1))
|
||||
params.set("childId", member.id)
|
||||
params.set("gender", "MALE")
|
||||
if (member.motherId) {
|
||||
params.set("spouseId", member.motherId)
|
||||
}
|
||||
} else if (relationType === "mother") {
|
||||
params.set("generation", String(member.generation - 1))
|
||||
params.set("childId", member.id)
|
||||
params.set("gender", "FEMALE")
|
||||
if (member.fatherId) {
|
||||
params.set("spouseId", member.fatherId)
|
||||
}
|
||||
}
|
||||
|
||||
if (currentTree?.id) {
|
||||
params.set("treeId", currentTree.id)
|
||||
}
|
||||
|
||||
setRelationDialog(null)
|
||||
router.push(`/members/new?${params.toString()}`)
|
||||
}, [member, currentTree?.id, router])
|
||||
|
||||
const handleQuickAddChild = () => {
|
||||
setRelationDialog({ type: 'child' })
|
||||
}
|
||||
|
||||
const handleQuickAddSpouse = () => {
|
||||
// 跳转到新增成员页面,并预填配偶信息
|
||||
const params = new URLSearchParams(window.location.search)
|
||||
params.set('spouseId', member.id)
|
||||
params.set('generation', member.generation.toString())
|
||||
// 配偶性别与当前成员相反
|
||||
params.set('gender', member.gender === 'MALE' ? 'FEMALE' : 'MALE')
|
||||
|
||||
// 如果当前成员有子女,将他们也作为新配偶的子女
|
||||
if (member.childrenIds && member.childrenIds.length > 0) {
|
||||
// 传递所有子女ID
|
||||
member.childrenIds.forEach(id => {
|
||||
params.append('childrenIds', id)
|
||||
})
|
||||
}
|
||||
|
||||
router.push(`/members/new?${params.toString()}`)
|
||||
setRelationDialog({ type: 'spouse' })
|
||||
}
|
||||
|
||||
const handleQuickAddFather = () => {
|
||||
// 跳转到新增成员页面,并预填父亲信息
|
||||
const params = new URLSearchParams(window.location.search)
|
||||
params.set('childId', member.id)
|
||||
params.set('generation', (member.generation - 1).toString())
|
||||
params.set('gender', 'MALE')
|
||||
// 如果已有母亲,将母亲设置为配偶
|
||||
if (member.motherId) {
|
||||
params.set('spouseId', member.motherId)
|
||||
}
|
||||
router.push(`/members/new?${params.toString()}`)
|
||||
setRelationDialog({ type: 'father' })
|
||||
}
|
||||
|
||||
const handleAvatarUpload = async (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
@@ -216,16 +266,7 @@ export default function MemberProfilePage() {
|
||||
}
|
||||
|
||||
const handleQuickAddMother = () => {
|
||||
// 跳转到新增成员页面,并预填母亲信息
|
||||
const params = new URLSearchParams(window.location.search)
|
||||
params.set('childId', member.id)
|
||||
params.set('generation', (member.generation - 1).toString())
|
||||
params.set('gender', 'FEMALE')
|
||||
// 如果已有父亲,将父亲设置为配偶
|
||||
if (member.fatherId) {
|
||||
params.set('spouseId', member.fatherId)
|
||||
}
|
||||
router.push(`/members/new?${params.toString()}`)
|
||||
setRelationDialog({ type: 'mother' })
|
||||
}
|
||||
|
||||
if (isEditing) {
|
||||
@@ -865,6 +906,19 @@ export default function MemberProfilePage() {
|
||||
</div>
|
||||
</Tabs>
|
||||
</main>
|
||||
|
||||
{/* 添加成员对话框 */}
|
||||
{relationDialog && member && (
|
||||
<AddRelationDialog
|
||||
open={!!relationDialog}
|
||||
onOpenChange={(open) => {
|
||||
if (!open) setRelationDialog(null)
|
||||
}}
|
||||
member={member}
|
||||
relationType={relationDialog.type}
|
||||
onCreateNew={handleCreateNewRelation}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -38,11 +38,25 @@ export default function NewMemberPage() {
|
||||
const childId = searchParams.get('childId')
|
||||
const generation = searchParams.get('generation')
|
||||
const gender = searchParams.get('gender')
|
||||
const surname = searchParams.get('surname')
|
||||
const givenName = searchParams.get('givenName')
|
||||
|
||||
if (!fatherId && !motherId && !spouseId && !childId && !generation && !gender) return undefined
|
||||
if (!fatherId && !motherId && !spouseId && !childId && !generation && !gender && !surname && !givenName) return undefined
|
||||
|
||||
const data: Partial<FamilyMember> = {}
|
||||
|
||||
// 处理姓名信息
|
||||
if (surname) {
|
||||
data.surname = surname
|
||||
}
|
||||
if (givenName) {
|
||||
data.givenName = givenName
|
||||
}
|
||||
// 如果有姓和名,自动生成全名
|
||||
if (surname || givenName) {
|
||||
data.fullName = (surname || '') + (givenName || '')
|
||||
}
|
||||
|
||||
// 处理父母信息
|
||||
if (fatherId) {
|
||||
data.fatherId = fatherId
|
||||
|
||||
+285
-3
@@ -7,7 +7,7 @@ import { useRouter } from "next/navigation"
|
||||
import { Input } from "@/components/ui/input"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { ChineseCard, ChineseCardContent } from "@/components/ui/chinese-card"
|
||||
import { Search, Plus, Filter, X, Users, User } from "lucide-react"
|
||||
import { Search, Plus, Filter, X, Users, User, UserPlus, Baby } from "lucide-react"
|
||||
import Link from "next/link"
|
||||
import { AvatarDisplay } from "@/components/ui/avatar-display"
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
|
||||
@@ -20,6 +20,15 @@ import { permissions } from "@/lib/permissions"
|
||||
import { MemberNameWithStatus } from "@/components/member-name-with-status"
|
||||
import { useSession } from "next-auth/react"
|
||||
import { EmptyStateBadge } from "@/components/empty-state-badge"
|
||||
import { AddRelationDialog, type RelationType } from "@/components/tree/add-relation-dialog"
|
||||
import {
|
||||
ContextMenu,
|
||||
ContextMenuContent,
|
||||
ContextMenuItem,
|
||||
ContextMenuLabel,
|
||||
ContextMenuSeparator,
|
||||
ContextMenuTrigger,
|
||||
} from "@/components/ui/context-menu"
|
||||
|
||||
// 占位符类型
|
||||
interface PlaceholderMember {
|
||||
@@ -69,10 +78,16 @@ const MemberCard = memo(function MemberCard({
|
||||
member,
|
||||
allMembers,
|
||||
onLocateInTree,
|
||||
currentTreeId,
|
||||
canEdit,
|
||||
onOpenAddDialog,
|
||||
}: {
|
||||
member: FamilyMember
|
||||
allMembers: FamilyMember[]
|
||||
onLocateInTree: (id: string) => void
|
||||
currentTreeId?: string
|
||||
canEdit: boolean
|
||||
onOpenAddDialog: (member: FamilyMember, type: RelationType) => void
|
||||
}) {
|
||||
// 判断是否是配偶
|
||||
const isFounder = member.isFounder === true
|
||||
@@ -108,7 +123,79 @@ const MemberCard = memo(function MemberCard({
|
||||
? '!border-2 !border-gray-400 dark:!border-gray-600 !bg-gray-50/50 dark:!bg-gray-900/30' // 已故:灰色深边框
|
||||
: '!border-2 !border-amber-300/70 !bg-card dark:!border-amber-600/50' // 在世:浅金色边框
|
||||
|
||||
return (
|
||||
// 判断可以添加的关系
|
||||
const canAddFather = !member.fatherId
|
||||
const canAddMother = !member.motherId
|
||||
const canAddSpouse = true // 配偶总是可以添加
|
||||
const canAddChild = true // 子女总是可以添加
|
||||
|
||||
// 构建新增成员的 URL
|
||||
const buildAddUrl = (type: 'father' | 'mother' | 'spouse' | 'child') => {
|
||||
const params = new URLSearchParams()
|
||||
if (currentTreeId) {
|
||||
params.set('treeId', currentTreeId)
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case 'father':
|
||||
params.set('childId', member.id)
|
||||
params.set('gender', 'MALE')
|
||||
params.set('generation', (member.generation - 1).toString())
|
||||
// 如果已有母亲,设为配偶
|
||||
if (member.motherId) {
|
||||
params.set('spouseId', member.motherId)
|
||||
}
|
||||
break
|
||||
case 'mother':
|
||||
params.set('childId', member.id)
|
||||
params.set('gender', 'FEMALE')
|
||||
params.set('generation', (member.generation - 1).toString())
|
||||
// 如果已有父亲,设为配偶
|
||||
if (member.fatherId) {
|
||||
params.set('spouseId', member.fatherId)
|
||||
}
|
||||
break
|
||||
case 'spouse':
|
||||
params.set('spouseId', member.id)
|
||||
params.set('generation', member.generation.toString())
|
||||
// 配偶性别与当前成员相反
|
||||
params.set('gender', member.gender === 'MALE' ? 'FEMALE' : 'MALE')
|
||||
|
||||
// 如果当前成员有子女,将他们也作为新配偶的子女
|
||||
if (member.childrenIds && member.childrenIds.length > 0) {
|
||||
member.childrenIds.forEach(id => {
|
||||
params.append('childrenIds', id)
|
||||
})
|
||||
}
|
||||
break
|
||||
case 'child':
|
||||
// 根据当前成员性别设置父/母
|
||||
if (member.gender === 'MALE') {
|
||||
params.set('fatherId', member.id)
|
||||
// 如果父亲有配偶,设置配偶为母亲
|
||||
if (member.spouseIds && member.spouseIds.length > 0) {
|
||||
params.set('motherId', member.spouseIds[0])
|
||||
}
|
||||
} else {
|
||||
params.set('motherId', member.id)
|
||||
// 如果母亲有配偶,设置配偶为父亲
|
||||
if (member.spouseIds && member.spouseIds.length > 0) {
|
||||
params.set('fatherId', member.spouseIds[0])
|
||||
}
|
||||
}
|
||||
params.set('generation', (member.generation + 1).toString())
|
||||
break
|
||||
}
|
||||
|
||||
return `/members/new?${params.toString()}`
|
||||
}
|
||||
|
||||
const handleAddMember = (type: RelationType) => {
|
||||
onOpenAddDialog(member, type)
|
||||
}
|
||||
|
||||
// 卡片内容
|
||||
const cardContent = (
|
||||
<div className="relative group">
|
||||
<Link href={`/members/${member.id}${typeof window !== 'undefined' ? window.location.search : ''}`}>
|
||||
<ChineseCard variant="default" className={`hover:shadow-lg transition-all cursor-pointer h-full ${cardStyle}`}>
|
||||
@@ -258,15 +345,187 @@ const MemberCard = memo(function MemberCard({
|
||||
</Button>
|
||||
</div>
|
||||
)
|
||||
|
||||
// 如果没有编辑权限,直接返回卡片内容
|
||||
if (!canEdit) {
|
||||
return cardContent
|
||||
}
|
||||
|
||||
// 有编辑权限时,包裹右键菜单
|
||||
return (
|
||||
<ContextMenu>
|
||||
<ContextMenuTrigger asChild>
|
||||
{cardContent}
|
||||
</ContextMenuTrigger>
|
||||
<ContextMenuContent className="w-48">
|
||||
<ContextMenuLabel className="text-xs text-muted-foreground">
|
||||
为 {member.fullName} 添加
|
||||
</ContextMenuLabel>
|
||||
<ContextMenuSeparator />
|
||||
|
||||
{canAddFather && (
|
||||
<ContextMenuItem
|
||||
className="gap-2 cursor-pointer"
|
||||
onPointerDown={(e) => {
|
||||
e.preventDefault()
|
||||
handleAddMember('father')
|
||||
}}
|
||||
>
|
||||
<UserPlus className="h-4 w-4 text-blue-500" />
|
||||
添加父亲
|
||||
</ContextMenuItem>
|
||||
)}
|
||||
|
||||
{canAddMother && (
|
||||
<ContextMenuItem
|
||||
className="gap-2 cursor-pointer"
|
||||
onPointerDown={(e) => {
|
||||
e.preventDefault()
|
||||
handleAddMember('mother')
|
||||
}}
|
||||
>
|
||||
<UserPlus className="h-4 w-4 text-pink-500" />
|
||||
添加母亲
|
||||
</ContextMenuItem>
|
||||
)}
|
||||
|
||||
{(canAddFather || canAddMother) && (canAddSpouse || canAddChild) && (
|
||||
<ContextMenuSeparator />
|
||||
)}
|
||||
|
||||
{canAddSpouse && (
|
||||
<ContextMenuItem
|
||||
className="gap-2 cursor-pointer"
|
||||
onPointerDown={(e) => {
|
||||
e.preventDefault()
|
||||
handleAddMember('spouse')
|
||||
}}
|
||||
>
|
||||
<Users className="h-4 w-4 text-red-500" />
|
||||
添加配偶
|
||||
</ContextMenuItem>
|
||||
)}
|
||||
|
||||
{canAddChild && (
|
||||
<ContextMenuItem
|
||||
className="gap-2 cursor-pointer"
|
||||
onPointerDown={(e) => {
|
||||
e.preventDefault()
|
||||
handleAddMember('child')
|
||||
}}
|
||||
>
|
||||
<Baby className="h-4 w-4 text-green-500" />
|
||||
添加子女
|
||||
</ContextMenuItem>
|
||||
)}
|
||||
</ContextMenuContent>
|
||||
</ContextMenu>
|
||||
)
|
||||
})
|
||||
|
||||
export default function MembersPage() {
|
||||
const { treeData, currentTree, searchMembers, setHighlightedMemberId } = useFamily()
|
||||
const { treeData, currentTree, searchMembers, setHighlightedMemberId, refreshData } = useFamily()
|
||||
const { data: session, status } = useSession()
|
||||
const router = useRouter()
|
||||
const [query, setQuery] = useState("")
|
||||
const [showFilters, setShowFilters] = useState(false)
|
||||
|
||||
// 添加成员对话框状态
|
||||
const [relationDialog, setRelationDialog] = useState<{
|
||||
member: FamilyMember
|
||||
type: RelationType
|
||||
} | null>(null)
|
||||
|
||||
|
||||
// 打开添加成员对话框
|
||||
const handleOpenAddDialog = useCallback((member: FamilyMember, type: RelationType) => {
|
||||
setRelationDialog({ member, type })
|
||||
}, [])
|
||||
|
||||
// 姓名分解函数
|
||||
const parseName = (fullName: string): { surname: string; givenName: string } => {
|
||||
const name = fullName.trim()
|
||||
if (!name) return { surname: '', givenName: '' }
|
||||
|
||||
const compoundSurnames = [
|
||||
'欧阳', '太史', '端木', '上官', '司马', '东方', '独孤', '南宫', '万俟', '闻人',
|
||||
'夏侯', '诸葛', '尉迟', '公羊', '赫连', '澹台', '皇甫', '宗政', '濮阳', '公冶',
|
||||
'太叔', '申屠', '公孙', '慕容', '仲孙', '钟离', '长孙', '宇文', '司徒', '鲜于',
|
||||
'司空', '闾丘', '子车', '亓官', '司寇', '巫马', '公西', '颛孙', '壤驷', '公良',
|
||||
'漆雕', '乐正', '宰父', '谷梁', '拓跋', '夹谷', '轩辕', '令狐', '段干', '百里',
|
||||
'呼延', '东郭', '南门', '羊舌', '微生', '公户', '公玉', '公仪', '梁丘', '公仲',
|
||||
'公上', '公门', '公山', '公坚', '左丘', '公伯', '西门', '公祖', '第五', '公乘',
|
||||
'贯丘', '公皙', '南荣', '东里', '东宫', '仲长', '子书', '子桑', '即墨', '达奚', '褚师'
|
||||
]
|
||||
|
||||
for (const compound of compoundSurnames) {
|
||||
if (name.startsWith(compound) && name.length > compound.length) {
|
||||
return { surname: compound, givenName: name.slice(compound.length) }
|
||||
}
|
||||
}
|
||||
|
||||
if (name.length >= 2) {
|
||||
return { surname: name.charAt(0), givenName: name.slice(1) }
|
||||
}
|
||||
|
||||
return { surname: name, givenName: '' }
|
||||
}
|
||||
|
||||
// 创建新成员的处理函数
|
||||
const handleCreateNewRelation = useCallback((prefillName: string, relationType: RelationType) => {
|
||||
if (!relationDialog) return
|
||||
const params = new URLSearchParams()
|
||||
|
||||
const { surname, givenName } = parseName(prefillName)
|
||||
if (surname) params.set("surname", surname)
|
||||
if (givenName) params.set("givenName", givenName)
|
||||
|
||||
if (relationType === "child") {
|
||||
params.set("generation", String(relationDialog.member.generation + 1))
|
||||
if (relationDialog.member.gender === "MALE") {
|
||||
params.set("fatherId", relationDialog.member.id)
|
||||
if (relationDialog.member.spouseIds?.length) {
|
||||
params.set("motherId", relationDialog.member.spouseIds[0])
|
||||
}
|
||||
} else if (relationDialog.member.gender === "FEMALE") {
|
||||
params.set("motherId", relationDialog.member.id)
|
||||
if (relationDialog.member.spouseIds?.length) {
|
||||
params.set("fatherId", relationDialog.member.spouseIds[0])
|
||||
}
|
||||
}
|
||||
} else if (relationType === "spouse") {
|
||||
params.set("generation", String(relationDialog.member.generation))
|
||||
params.set("spouseId", relationDialog.member.id)
|
||||
params.set("gender", relationDialog.member.gender === "MALE" ? "FEMALE" : "MALE")
|
||||
if (relationDialog.member.childrenIds && relationDialog.member.childrenIds.length > 0) {
|
||||
relationDialog.member.childrenIds.forEach(id => {
|
||||
params.append('childrenIds', id)
|
||||
})
|
||||
}
|
||||
} else if (relationType === "father") {
|
||||
params.set("generation", String(relationDialog.member.generation - 1))
|
||||
params.set("childId", relationDialog.member.id)
|
||||
params.set("gender", "MALE")
|
||||
if (relationDialog.member.motherId) {
|
||||
params.set("spouseId", relationDialog.member.motherId)
|
||||
}
|
||||
} else if (relationType === "mother") {
|
||||
params.set("generation", String(relationDialog.member.generation - 1))
|
||||
params.set("childId", relationDialog.member.id)
|
||||
params.set("gender", "FEMALE")
|
||||
if (relationDialog.member.fatherId) {
|
||||
params.set("spouseId", relationDialog.member.fatherId)
|
||||
}
|
||||
}
|
||||
|
||||
if (currentTree?.id) {
|
||||
params.set("treeId", currentTree.id)
|
||||
}
|
||||
|
||||
setRelationDialog(null)
|
||||
router.push(`/members/new?${params.toString()}`)
|
||||
}, [relationDialog, currentTree?.id, router])
|
||||
|
||||
// 未登录时重定向到登录页
|
||||
useEffect(() => {
|
||||
if (status === 'unauthenticated') {
|
||||
@@ -274,6 +533,13 @@ export default function MembersPage() {
|
||||
}
|
||||
}, [status, router])
|
||||
|
||||
// 页面加载时刷新数据
|
||||
useEffect(() => {
|
||||
if (currentTree?.id) {
|
||||
refreshData()
|
||||
}
|
||||
}, [currentTree?.id, refreshData])
|
||||
|
||||
// 从 URL 参数读取搜索关键词
|
||||
useEffect(() => {
|
||||
const params = new URLSearchParams(window.location.search)
|
||||
@@ -608,6 +874,9 @@ export default function MembersPage() {
|
||||
const params = new URLSearchParams(window.location.search)
|
||||
router.push(`/tree?${params.toString()}`)
|
||||
}}
|
||||
currentTreeId={currentTree?.id}
|
||||
canEdit={permissions.canCreate(currentTree?.currentUserRole)}
|
||||
onOpenAddDialog={handleOpenAddDialog}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
@@ -617,6 +886,19 @@ export default function MembersPage() {
|
||||
</div>
|
||||
)}
|
||||
</main>
|
||||
|
||||
{/* 添加成员对话框 */}
|
||||
{relationDialog && (
|
||||
<AddRelationDialog
|
||||
open={!!relationDialog}
|
||||
onOpenChange={(open) => {
|
||||
if (!open) setRelationDialog(null)
|
||||
}}
|
||||
member={relationDialog.member}
|
||||
relationType={relationDialog.type}
|
||||
onCreateNew={handleCreateNewRelation}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
+9
-2
@@ -16,7 +16,7 @@ import {
|
||||
} from "@/components/ui/dropdown-menu"
|
||||
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { ZoomIn, ZoomOut, Move, Download, LayoutGrid, ChevronDown, Users, Network, User, Loader2 } from "lucide-react"
|
||||
import { ZoomIn, ZoomOut, Move, Download, LayoutGrid, ChevronDown, Users, Network, Loader2 } from "lucide-react"
|
||||
import { useState, useRef, useEffect, useCallback } from "react"
|
||||
import { useRouter, useSearchParams } from "next/navigation"
|
||||
import { MemberNameWithStatus } from "@/components/member-name-with-status"
|
||||
@@ -44,7 +44,7 @@ import type { D3OrgChartRef } from "@/components/tree/d3-org-chart-flow"
|
||||
type ViewMode = "traditional" | "d3-org-chart"
|
||||
|
||||
export default function TreePage() {
|
||||
const { treeData } = useFamily()
|
||||
const { treeData, currentTree, refreshData } = useFamily()
|
||||
const { calculateRelationship } = useRelationship()
|
||||
const { data: session, status } = useSession()
|
||||
const router = useRouter()
|
||||
@@ -73,6 +73,13 @@ export default function TreePage() {
|
||||
}
|
||||
}, [status, router])
|
||||
|
||||
// 页面加载时刷新数据
|
||||
useEffect(() => {
|
||||
if (currentTree?.id) {
|
||||
refreshData()
|
||||
}
|
||||
}, [currentTree?.id, refreshData])
|
||||
|
||||
// 从 URL 参数读取视图模式
|
||||
useEffect(() => {
|
||||
const view = searchParams.get('view')
|
||||
|
||||
Reference in New Issue
Block a user