0.8.0.0
This commit is contained in:
@@ -5,6 +5,7 @@ import { prisma } from "@/lib/prisma"
|
||||
import { checkPermission } from "@/lib/permissions"
|
||||
import { Role } from "@prisma/client"
|
||||
import { recordMemberHistory } from "@/lib/member-history"
|
||||
import { recalculateGenerations, isRootMember, hasChildren, findNewRootMember } from "@/lib/generation-utils"
|
||||
|
||||
// 获取单个成员
|
||||
export async function GET(
|
||||
@@ -323,10 +324,183 @@ export async function DELETE(
|
||||
return NextResponse.json({ error: "成员不存在" }, { status: 404 })
|
||||
}
|
||||
|
||||
// 获取家族树信息
|
||||
const tree = await prisma.familyTree.findUnique({
|
||||
where: { id: treeId },
|
||||
select: { rootMemberId: true }
|
||||
})
|
||||
|
||||
// 检查是否删除的是根成员(始祖)
|
||||
const isDeletingRoot = await isRootMember(memberId)
|
||||
const memberHasChildren = await hasChildren(memberId)
|
||||
let needRecalculate = false
|
||||
let newRootId: string | null = null
|
||||
|
||||
// 如果删除的是根成员且有子女,需要调整全族代数
|
||||
if (isDeletingRoot && memberHasChildren) {
|
||||
needRecalculate = true
|
||||
}
|
||||
|
||||
// 清理关系引用
|
||||
// 1. 清理配偶关系
|
||||
if (existingMember.spouseIds && existingMember.spouseIds.length > 0) {
|
||||
for (const spouseId of existingMember.spouseIds) {
|
||||
const spouse = await prisma.familyMember.findUnique({
|
||||
where: { id: spouseId }
|
||||
})
|
||||
if (spouse && spouse.spouseIds.includes(memberId)) {
|
||||
await prisma.familyMember.update({
|
||||
where: { id: spouseId },
|
||||
data: {
|
||||
spouseIds: spouse.spouseIds.filter(id => id !== memberId)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 清理父母的子女引用
|
||||
if (existingMember.fatherId) {
|
||||
const father = await prisma.familyMember.findUnique({
|
||||
where: { id: existingMember.fatherId }
|
||||
})
|
||||
if (father && father.childrenIds.includes(memberId)) {
|
||||
await prisma.familyMember.update({
|
||||
where: { id: existingMember.fatherId },
|
||||
data: {
|
||||
childrenIds: father.childrenIds.filter(id => id !== memberId)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (existingMember.motherId) {
|
||||
const mother = await prisma.familyMember.findUnique({
|
||||
where: { id: existingMember.motherId }
|
||||
})
|
||||
if (mother && mother.childrenIds.includes(memberId)) {
|
||||
await prisma.familyMember.update({
|
||||
where: { id: existingMember.motherId },
|
||||
data: {
|
||||
childrenIds: mother.childrenIds.filter(id => id !== memberId)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 清理子女的父母引用
|
||||
if (existingMember.childrenIds && existingMember.childrenIds.length > 0) {
|
||||
for (const childId of existingMember.childrenIds) {
|
||||
const child = await prisma.familyMember.findUnique({
|
||||
where: { id: childId }
|
||||
})
|
||||
if (child) {
|
||||
const updates: any = {}
|
||||
if (child.fatherId === memberId) {
|
||||
updates.fatherId = null
|
||||
}
|
||||
if (child.motherId === memberId) {
|
||||
updates.motherId = null
|
||||
}
|
||||
if (Object.keys(updates).length > 0) {
|
||||
await prisma.familyMember.update({
|
||||
where: { id: childId },
|
||||
data: updates
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 删除成员
|
||||
await prisma.familyMember.delete({
|
||||
where: { id: memberId }
|
||||
})
|
||||
|
||||
// 如果需要调整全族代数
|
||||
if (needRecalculate) {
|
||||
try {
|
||||
// 将所有成员的代数 -1
|
||||
await recalculateGenerations(treeId, -1)
|
||||
|
||||
// 查找新的根成员
|
||||
newRootId = await findNewRootMember(treeId)
|
||||
|
||||
if (newRootId) {
|
||||
// 更新家族树的 rootMemberId
|
||||
await prisma.familyTree.update({
|
||||
where: { id: treeId },
|
||||
data: { rootMemberId: newRootId }
|
||||
})
|
||||
|
||||
// 将新根成员设为始祖
|
||||
await prisma.familyMember.update({
|
||||
where: { id: newRootId },
|
||||
data: { isFounder: true }
|
||||
})
|
||||
} else {
|
||||
// 如果没有找到新的根成员,清空 rootMemberId
|
||||
await prisma.familyTree.update({
|
||||
where: { id: treeId },
|
||||
data: { rootMemberId: null }
|
||||
})
|
||||
}
|
||||
|
||||
// 记录全族代数调整的日志
|
||||
await prisma.activityLog.create({
|
||||
data: {
|
||||
treeId,
|
||||
userId: session.user.id,
|
||||
action: 'UPDATE',
|
||||
entityType: 'TREE',
|
||||
entityId: treeId,
|
||||
entityName: `全族代数调整(-1代)`,
|
||||
changes: {
|
||||
reason: '删除始祖',
|
||||
offset: -1,
|
||||
newRootMemberId: newRootId,
|
||||
deletedMemberId: memberId,
|
||||
deletedMemberName: existingMember.fullName
|
||||
}
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('调整全族代数失败:', error)
|
||||
// 注意:此时成员已被删除,无法回滚
|
||||
// 记录错误日志
|
||||
await prisma.activityLog.create({
|
||||
data: {
|
||||
treeId,
|
||||
userId: session.user.id,
|
||||
action: 'ERROR',
|
||||
entityType: 'TREE',
|
||||
entityId: treeId,
|
||||
entityName: '代数调整失败',
|
||||
changes: {
|
||||
error: '删除始祖后调整代数失败',
|
||||
deletedMemberId: memberId
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
} else if (tree?.rootMemberId === memberId) {
|
||||
// 如果删除的是根成员但没有子女,需要更新 rootMemberId
|
||||
// 情况1: 有配偶,配偶成为新根
|
||||
if (existingMember.spouseIds && existingMember.spouseIds.length > 0) {
|
||||
const newRoot = existingMember.spouseIds[0]
|
||||
await prisma.familyTree.update({
|
||||
where: { id: treeId },
|
||||
data: { rootMemberId: newRoot }
|
||||
})
|
||||
} else {
|
||||
// 情况2: 无配偶无子女,清空 rootMemberId
|
||||
await prisma.familyTree.update({
|
||||
where: { id: treeId },
|
||||
data: { rootMemberId: null }
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 记录操作日志
|
||||
await prisma.activityLog.create({
|
||||
data: {
|
||||
@@ -339,7 +513,11 @@ export async function DELETE(
|
||||
}
|
||||
})
|
||||
|
||||
return NextResponse.json({ success: true })
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
generationRecalculated: needRecalculate,
|
||||
newRootMemberId: newRootId
|
||||
})
|
||||
} catch (error) {
|
||||
console.error("删除成员失败:", error)
|
||||
return NextResponse.json(
|
||||
|
||||
@@ -6,6 +6,7 @@ import { checkPermission } from "@/lib/permissions"
|
||||
import { Role, Gender } from "@prisma/client"
|
||||
import { z } from "zod"
|
||||
import { recordMemberHistory } from "@/lib/member-history"
|
||||
import { recalculateGenerations, getMinGeneration, findNewRootMember } from "@/lib/generation-utils"
|
||||
|
||||
const createMemberSchema = z.object({
|
||||
surname: z.string().min(1),
|
||||
@@ -122,6 +123,35 @@ export async function POST(
|
||||
const body = await req.json()
|
||||
const data = createMemberSchema.parse(body)
|
||||
|
||||
// 检查是否需要调整全族代数
|
||||
const minGeneration = await getMinGeneration(treeId)
|
||||
let needRecalculate = false
|
||||
let generationOffset = 0
|
||||
|
||||
// 检查是否给第1代成员添加父母
|
||||
let isAddingParentToFounder = false
|
||||
if (data.childrenIds && data.childrenIds.length > 0) {
|
||||
// 检查子女中是否有第1代成员
|
||||
const children = await prisma.familyMember.findMany({
|
||||
where: {
|
||||
id: { in: data.childrenIds },
|
||||
generation: 1
|
||||
},
|
||||
select: { id: true }
|
||||
})
|
||||
isAddingParentToFounder = children.length > 0
|
||||
}
|
||||
|
||||
if (minGeneration !== null && data.generation < minGeneration) {
|
||||
// 新成员的代数小于当前最小代数,需要调整全族代数
|
||||
needRecalculate = true
|
||||
generationOffset = minGeneration - data.generation
|
||||
} else if (isAddingParentToFounder && minGeneration === 1) {
|
||||
// 给第1代成员添加父母,需要将全族代数+1
|
||||
needRecalculate = true
|
||||
generationOffset = 1
|
||||
}
|
||||
|
||||
const member = await prisma.familyMember.create({
|
||||
data: {
|
||||
...data,
|
||||
@@ -204,6 +234,82 @@ export async function POST(
|
||||
}
|
||||
}
|
||||
|
||||
// 如果需要调整全族代数
|
||||
if (needRecalculate) {
|
||||
try {
|
||||
if (isAddingParentToFounder) {
|
||||
// 给第1代成员添加父母的情况
|
||||
// 1. 先将所有现有成员的代数+1(包括原来的第1代)
|
||||
await recalculateGenerations(treeId, generationOffset, member.id)
|
||||
|
||||
// 2. 将原始祖的 isFounder 设为 false
|
||||
const oldFounders = await prisma.familyMember.findMany({
|
||||
where: {
|
||||
treeId,
|
||||
isFounder: true,
|
||||
id: { not: member.id }
|
||||
}
|
||||
})
|
||||
for (const oldFounder of oldFounders) {
|
||||
await prisma.familyMember.update({
|
||||
where: { id: oldFounder.id },
|
||||
data: { isFounder: false }
|
||||
})
|
||||
}
|
||||
|
||||
// 3. 新父母成员保持代数为1,并设为始祖
|
||||
await prisma.familyMember.update({
|
||||
where: { id: member.id },
|
||||
data: { generation: 1, isFounder: true }
|
||||
})
|
||||
|
||||
// 4. 更新家族树的 rootMemberId 为新父母
|
||||
await prisma.familyTree.update({
|
||||
where: { id: treeId },
|
||||
data: { rootMemberId: member.id }
|
||||
})
|
||||
} else {
|
||||
// 其他情况:新成员代数小于最小代数
|
||||
// 调整其他成员的代数(排除新创建的成员)
|
||||
await recalculateGenerations(treeId, generationOffset, member.id)
|
||||
|
||||
// 将新成员的代数设为1(成为新的始祖)
|
||||
await prisma.familyMember.update({
|
||||
where: { id: member.id },
|
||||
data: { generation: 1 }
|
||||
})
|
||||
|
||||
// 更新家族树的 rootMemberId
|
||||
await prisma.familyTree.update({
|
||||
where: { id: treeId },
|
||||
data: { rootMemberId: member.id }
|
||||
})
|
||||
}
|
||||
|
||||
// 记录全族代数调整的日志
|
||||
await prisma.activityLog.create({
|
||||
data: {
|
||||
treeId,
|
||||
userId: session.user.id,
|
||||
action: 'UPDATE',
|
||||
entityType: 'TREE',
|
||||
entityId: treeId,
|
||||
entityName: `全族代数调整(+${generationOffset}代)`,
|
||||
changes: {
|
||||
reason: isAddingParentToFounder ? '给始祖添加父母' : '添加更早代数成员',
|
||||
offset: generationOffset,
|
||||
newRootMemberId: member.id
|
||||
}
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('调整全族代数失败:', error)
|
||||
// 如果调整失败,删除新创建的成员
|
||||
await prisma.familyMember.delete({ where: { id: member.id } })
|
||||
throw new Error('调整全族代数失败,操作已回滚')
|
||||
}
|
||||
}
|
||||
|
||||
// 记录成员历史版本
|
||||
await recordMemberHistory({
|
||||
memberId: member.id,
|
||||
@@ -225,7 +331,11 @@ export async function POST(
|
||||
}
|
||||
})
|
||||
|
||||
return NextResponse.json({ member }, { status: 201 })
|
||||
return NextResponse.json({
|
||||
member,
|
||||
generationRecalculated: needRecalculate,
|
||||
generationOffset: needRecalculate ? generationOffset : 0
|
||||
}, { status: 201 })
|
||||
} catch (error) {
|
||||
if (error instanceof z.ZodError) {
|
||||
return NextResponse.json(
|
||||
|
||||
Reference in New Issue
Block a user