0.8.3.0
This commit is contained in:
Vendored
+1
-1
File diff suppressed because one or more lines are too long
@@ -707,6 +707,7 @@ const D3OrgChartFlowComponent = forwardRef<D3OrgChartRef, D3OrgChartFlowProps>(
|
||||
">
|
||||
${sp.birthYear}${sp.deathYear ? `-${sp.deathYear}` : '-'}
|
||||
</div>
|
||||
${sp.ageText ? `<div style="font-size: 9px; color: #000000; margin-top: 2px; font-weight: 500; font-family: serif;">${sp.ageText}</div>` : ''}
|
||||
` : ''}
|
||||
</div>
|
||||
`
|
||||
|
||||
@@ -214,9 +214,6 @@ function PersonCard({
|
||||
|
||||
// 是否显示右键菜单(有可添加的选项时才显示)
|
||||
const hasAddOptions = canEdit && (canAddFather || canAddMother || canAddSpouse || canAddChild)
|
||||
|
||||
// 调试日志
|
||||
console.log('PersonCard render:', member.fullName, { canEdit, hasAddOptions, relationMode })
|
||||
|
||||
// 庄严正式的中国风配色
|
||||
const isDead = !!member.deathDate
|
||||
|
||||
@@ -52,6 +52,9 @@ export function TreeLayout({
|
||||
const VERTICAL_GAP = 48 // 3rem = 48px
|
||||
const CONNECTOR_HEIGHT = 48 // 连接线垂直高度
|
||||
|
||||
// 节点注册计数,用于触发连线重新计算
|
||||
const [nodeRegisteredCount, setNodeRegisteredCount] = useState(0)
|
||||
|
||||
// 折叠状态管理:存储被折叠的节点ID
|
||||
const [collapsedNodes, setCollapsedNodes] = useState<Set<string>>(() => new Set())
|
||||
|
||||
@@ -81,6 +84,8 @@ export function TreeLayout({
|
||||
const handleNodeRef = useCallback((memberId: string, el: HTMLDivElement | null) => {
|
||||
if (el) {
|
||||
nodeRefs.current.set(memberId, el)
|
||||
// 触发连线重新计算
|
||||
setNodeRegisteredCount(prev => prev + 1)
|
||||
} else {
|
||||
nodeRefs.current.delete(memberId)
|
||||
}
|
||||
@@ -102,10 +107,14 @@ export function TreeLayout({
|
||||
}, [relationMode, onMemberClick, router])
|
||||
|
||||
// 检查节点是否被任何祖先折叠(使用闭包避免递归依赖问题)
|
||||
// 注意:这个函数用于判断节点是否应该被隐藏,不用于连线计算
|
||||
const isNodeHiddenByCollapse = useCallback((nodeId: string): boolean => {
|
||||
// 如果没有折叠的节点,直接返回 false
|
||||
if (collapsedNodes.size === 0) return false
|
||||
|
||||
const checkHidden = (id: string): boolean => {
|
||||
const member = getMember(id)
|
||||
if (!member) return true
|
||||
if (!member) return false // 找不到成员时返回 false,不隐藏
|
||||
|
||||
// 检查父节点是否被折叠
|
||||
const parentId = member.fatherId || member.motherId
|
||||
@@ -123,26 +132,54 @@ export function TreeLayout({
|
||||
const calculateConnections = useCallback(() => {
|
||||
const newConnections: Connection[] = []
|
||||
const containerRect = containerRef.current?.getBoundingClientRect()
|
||||
if (!containerRect) return
|
||||
if (!containerRect) {
|
||||
return
|
||||
}
|
||||
|
||||
// 检查是否有足够的节点已注册
|
||||
if (nodeRefs.current.size === 0) return
|
||||
if (nodeRefs.current.size === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
let processedCount = 0
|
||||
let skippedNoChildren = 0
|
||||
let skippedCollapsed = 0
|
||||
let skippedHidden = 0
|
||||
let skippedNotInDom = 0
|
||||
let skippedZeroSize = 0
|
||||
|
||||
nodeRefs.current.forEach((nodeElement, nodeId) => {
|
||||
const member = getMember(nodeId)
|
||||
if (!member || !member.childrenIds || member.childrenIds.length === 0) return
|
||||
if (!member || !member.childrenIds || member.childrenIds.length === 0) {
|
||||
skippedNoChildren++
|
||||
return
|
||||
}
|
||||
|
||||
// 如果该节点被折叠,不绘制到子节点的连线
|
||||
if (collapsedNodes.has(nodeId)) return
|
||||
if (collapsedNodes.has(nodeId)) {
|
||||
skippedCollapsed++
|
||||
return
|
||||
}
|
||||
|
||||
// 如果该节点被祖先折叠隐藏,跳过
|
||||
if (isNodeHiddenByCollapse(nodeId)) return
|
||||
if (isNodeHiddenByCollapse(nodeId)) {
|
||||
skippedHidden++
|
||||
return
|
||||
}
|
||||
|
||||
// 检查元素是否仍在 DOM 中且可见
|
||||
if (!document.body.contains(nodeElement)) return
|
||||
if (!document.body.contains(nodeElement)) {
|
||||
skippedNotInDom++
|
||||
return
|
||||
}
|
||||
const parentRect = nodeElement.getBoundingClientRect()
|
||||
// 如果元素不可见(宽高为0),跳过
|
||||
if (parentRect.width === 0 || parentRect.height === 0) return
|
||||
if (parentRect.width === 0 || parentRect.height === 0) {
|
||||
skippedZeroSize++
|
||||
return
|
||||
}
|
||||
|
||||
processedCount++
|
||||
|
||||
// 考虑缩放因素:getBoundingClientRect 返回的是缩放后的尺寸
|
||||
// 需要除以 scale 来获取实际的逻辑位置
|
||||
@@ -209,6 +246,8 @@ export function TreeLayout({
|
||||
timers.push(setTimeout(calculateConnections, 50))
|
||||
timers.push(setTimeout(calculateConnections, 150))
|
||||
timers.push(setTimeout(calculateConnections, 300))
|
||||
timers.push(setTimeout(calculateConnections, 500))
|
||||
timers.push(setTimeout(calculateConnections, 1000))
|
||||
return () => timers.forEach(timer => clearTimeout(timer))
|
||||
}, [collapsedNodes, calculateConnections])
|
||||
|
||||
@@ -217,13 +256,24 @@ export function TreeLayout({
|
||||
calculateConnections()
|
||||
}, [scale, calculateConnections])
|
||||
|
||||
// 节点注册变化时重新计算连线(防抖)
|
||||
useEffect(() => {
|
||||
if (nodeRegisteredCount === 0) return
|
||||
const timer = setTimeout(calculateConnections, 100)
|
||||
return () => clearTimeout(timer)
|
||||
}, [nodeRegisteredCount, calculateConnections])
|
||||
|
||||
useEffect(() => {
|
||||
// 多次尝试计算,确保 DOM 完全渲染
|
||||
// 对于大型族谱(100+人),需要更长的延迟
|
||||
const timers: NodeJS.Timeout[] = []
|
||||
timers.push(setTimeout(calculateConnections, 50))
|
||||
timers.push(setTimeout(calculateConnections, 150))
|
||||
timers.push(setTimeout(calculateConnections, 100))
|
||||
timers.push(setTimeout(calculateConnections, 300))
|
||||
timers.push(setTimeout(calculateConnections, 500))
|
||||
timers.push(setTimeout(calculateConnections, 1000))
|
||||
timers.push(setTimeout(calculateConnections, 2000))
|
||||
timers.push(setTimeout(calculateConnections, 3000))
|
||||
timers.push(setTimeout(calculateConnections, 5000))
|
||||
|
||||
// 监听窗口大小变化
|
||||
window.addEventListener('resize', calculateConnections)
|
||||
@@ -395,7 +445,7 @@ export function TreeLayout({
|
||||
top: `${top}px`,
|
||||
width: `${width}px`,
|
||||
height: `${height}px`,
|
||||
backgroundColor: 'rgba(180, 83, 9, 0.7)', // amber-700 with 70% opacity
|
||||
backgroundColor: 'rgba(180, 83, 9, 0.7)',
|
||||
transform: isHorizontal ? 'scaleY(0.5)' : 'scaleX(0.5)',
|
||||
transformOrigin: 'top left',
|
||||
}}
|
||||
|
||||
@@ -191,6 +191,7 @@ rsync -avz --progress --delete \
|
||||
--exclude 'deploy-manual.sh' \
|
||||
--exclude 'setup-ssh-key.sh' \
|
||||
--exclude '*.tar.gz' \
|
||||
--exclude 'public/uploads' \
|
||||
-e "ssh" \
|
||||
./ $SSH_HOST:$REMOTE_DIR/
|
||||
|
||||
|
||||
Vendored
+1
-1
@@ -1,6 +1,6 @@
|
||||
/// <reference types="next" />
|
||||
/// <reference types="next/image-types/global" />
|
||||
import "./.next/dev/types/routes.d.ts";
|
||||
import "./.next/types/routes.d.ts";
|
||||
|
||||
// NOTE: This file should not be edited
|
||||
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
||||
|
||||
+1
-1
@@ -762,7 +762,7 @@ prunedAt: Sun, 21 Dec 2025 04:00:03 GMT
|
||||
publicHoistPattern: []
|
||||
registries:
|
||||
'@jsr': https://npm.jsr.io/
|
||||
default: https://registry.npmmirror.com/
|
||||
default: https://registry.npmjs.org/
|
||||
skipped:
|
||||
- '@emnapi/runtime@1.7.1'
|
||||
- '@esbuild/aix-ppc64@0.25.12'
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"lastValidatedTimestamp": 1766317151581,
|
||||
"lastValidatedTimestamp": 1766327831114,
|
||||
"projects": {},
|
||||
"pnpmfiles": [],
|
||||
"settings": {
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||
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
|
||||
-----END OPENSSH PRIVATE KEY-----
|
||||
@@ -0,0 +1 @@
|
||||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDNOR+75yVy/k2dDi5vK7ZMYlo8a/z4j39Di3QTpTXAgZap5HY80bh49m9EdCWxFwGU03V1r/G8IuTBj2HHlJWeARJzRzjnVBavgqUqDNyPcvMheJ7U1hiwrG6NUu3Lmk4xJTYVaWuGVDyjtbyE5Domv6xvdxnt1Hx1pUaBVZxoi+NcOwxy4+nolE5wgADncdjF8mNjngxrDtZlLXi7IrHL1x1OsYiEnD6LrGX7+mxnWjRMcV7EyipsGwVggM1/FdoOC2tdUEiVIGWWw9lS/lDEZUfuiO5c8Xxq4Q2nhsane7U4+gmbh38fGy0FEK189wLFoodgsGHw6S36a8ivpQfkG8/3ayi47I47iprlBtnrwcJX0Jj9VrMWL0ed8tnnDnddqq1vRkGG2U+l8qjHs2lOHW48xkjWKfeL70bd2jPuoXc0PMlUMIji2lLCK7Eviwl9/x9+VyznwN4D2iWmd+mBL23hdS5kQYJIKFTQyZOzW3W9AdtltB3bCWh+9L354W+HFM6krf7SKFG9b5rETRR6zAnMSirSVk8BwYllBXmnfcRG/tWS0TvwFJfcNAkEEVqat9W+SOf3f9HK2twrMX3hd/iSFqd/GJI+4Spqns7z8yZoKhsM/airrXE/Ho8K4DvBxEgS43e2d3GnjehK+QmOjrpg9iqJSxwdzXFmFeRp4Q== freedak@Mac-mini.local
|
||||
Reference in New Issue
Block a user