168 lines
4.7 KiB
TypeScript
168 lines
4.7 KiB
TypeScript
import { prisma } from "./prisma"
|
|
|
|
/**
|
|
* 重新计算家族树所有成员的代数
|
|
* @param treeId 家族树ID
|
|
* @param offset 代数偏移量(正数表示增加,负数表示减少)
|
|
* @param excludeMemberId 排除的成员ID(通常是新添加的成员)
|
|
*/
|
|
export async function recalculateGenerations(
|
|
treeId: string,
|
|
offset: number,
|
|
excludeMemberId?: string
|
|
): Promise<void> {
|
|
if (offset === 0) return
|
|
|
|
await prisma.$transaction(async (tx) => {
|
|
const members = await tx.familyMember.findMany({
|
|
where: {
|
|
treeId,
|
|
...(excludeMemberId ? { id: { not: excludeMemberId } } : {}),
|
|
},
|
|
select: {
|
|
id: true,
|
|
generation: true,
|
|
},
|
|
})
|
|
|
|
for (const member of members) {
|
|
const newGeneration = member.generation + offset
|
|
if (newGeneration < 1) {
|
|
throw new Error(`代数调整后出现无效值: ${newGeneration},成员ID: ${member.id}`)
|
|
}
|
|
|
|
await tx.familyMember.update({
|
|
where: { id: member.id },
|
|
data: { generation: newGeneration },
|
|
})
|
|
}
|
|
})
|
|
}
|
|
|
|
/**
|
|
* 查找家族树的新根成员(第1代且无父母的成员)
|
|
* 优先选择年龄最大的(出生日期最早的)直系成员
|
|
* @param treeId 家族树ID
|
|
* @returns 新根成员的ID,如果没有则返回null
|
|
*/
|
|
export async function findNewRootMember(treeId: string): Promise<string | null> {
|
|
const firstGenMembers = await prisma.familyMember.findMany({
|
|
where: {
|
|
treeId,
|
|
generation: 1,
|
|
fatherId: null,
|
|
motherId: null,
|
|
},
|
|
select: {
|
|
id: true,
|
|
birthDate: true,
|
|
createdAt: true,
|
|
},
|
|
})
|
|
|
|
if (firstGenMembers.length === 0) return null
|
|
|
|
// 按出生日期排序(年龄最大的优先),如果没有出生日期则按创建时间排序
|
|
const sorted = firstGenMembers.sort((a, b) => {
|
|
// 如果都有出生日期,按出生日期排序(早的在前)
|
|
if (a.birthDate && b.birthDate) {
|
|
return a.birthDate.localeCompare(b.birthDate)
|
|
}
|
|
// 如果只有一个有出生日期,有出生日期的优先
|
|
if (a.birthDate) return -1
|
|
if (b.birthDate) return 1
|
|
// 如果都没有出生日期,按创建时间排序
|
|
return a.createdAt.getTime() - b.createdAt.getTime()
|
|
})
|
|
|
|
return sorted[0].id
|
|
}
|
|
|
|
/**
|
|
* 获取家族树中的最小代数
|
|
* @param treeId 家族树ID
|
|
* @returns 最小代数,如果没有成员则返回null
|
|
*/
|
|
export async function getMinGeneration(treeId: string): Promise<number | null> {
|
|
const result = await prisma.familyMember.aggregate({
|
|
where: { treeId },
|
|
_min: {
|
|
generation: true,
|
|
},
|
|
})
|
|
|
|
return result._min.generation
|
|
}
|
|
|
|
/**
|
|
* 检查成员是否是根成员(第1代且无父母)
|
|
* @param memberId 成员ID
|
|
* @returns 是否是根成员
|
|
*/
|
|
export async function isRootMember(memberId: string): Promise<boolean> {
|
|
const member = await prisma.familyMember.findUnique({
|
|
where: { id: memberId },
|
|
select: {
|
|
generation: true,
|
|
fatherId: true,
|
|
motherId: true,
|
|
},
|
|
})
|
|
|
|
if (!member) return false
|
|
|
|
return member.generation === 1 && !member.fatherId && !member.motherId
|
|
}
|
|
|
|
/**
|
|
* 检查成员是否有子女
|
|
* @param memberId 成员ID
|
|
* @returns 是否有子女
|
|
*/
|
|
export async function hasChildren(memberId: string): Promise<boolean> {
|
|
const member = await prisma.familyMember.findUnique({
|
|
where: { id: memberId },
|
|
select: {
|
|
childrenIds: true,
|
|
},
|
|
})
|
|
|
|
return member ? member.childrenIds.length > 0 : false
|
|
}
|
|
|
|
|
|
// ============================================
|
|
// 前端工具函数(不依赖 Prisma,可在客户端使用)
|
|
// ============================================
|
|
|
|
/**
|
|
* 检查成员是否为第1代成员(需要显示代数重新计算警告)
|
|
* 这是一个纯函数,可以在前端使用
|
|
* @param member 家族成员对象,需要包含 generation 字段
|
|
* @returns 是否为第1代成员
|
|
*/
|
|
export function isFirstGenerationMember(member: { generation?: number | null }): boolean {
|
|
// 处理边界情况:generation 为 undefined、null 或无效值时返回 false
|
|
if (member.generation === undefined || member.generation === null) {
|
|
return false
|
|
}
|
|
return member.generation === 1
|
|
}
|
|
|
|
/**
|
|
* 检查添加父母操作是否需要显示代数重新计算警告
|
|
* @param member 目标成员对象
|
|
* @param relationType 关系类型
|
|
* @returns 是否需要显示警告
|
|
*/
|
|
export function shouldShowGenerationWarning(
|
|
member: { generation?: number | null },
|
|
relationType: 'father' | 'mother' | 'spouse' | 'child'
|
|
): boolean {
|
|
// 只有添加父母(father/mother)时才需要检查
|
|
if (relationType !== 'father' && relationType !== 'mother') {
|
|
return false
|
|
}
|
|
return isFirstGenerationMember(member)
|
|
}
|