This commit is contained in:
freedakgmail
2025-11-24 14:02:34 +08:00
parent b7a8c9ee6e
commit 3d075c6076
941 changed files with 25613 additions and 27641 deletions
+12 -41
View File
@@ -35,7 +35,7 @@ interface ChartNode {
deathYear: string
birthPlace: string
gender: string
avatarImageId: string | null | undefined
avatarUrl: string | null | undefined
spouseName: string
spouseId: string | null
hasChildren: boolean
@@ -133,7 +133,7 @@ const D3OrgChartFlowComponent = forwardRef<D3OrgChartRef, D3OrgChartFlowProps>(
deathYear: member.deathDate ? new Date(member.deathDate).getFullYear().toString() : '',
birthPlace: member.birthPlace || '',
gender: member.gender === 'MALE' ? '男' : '女',
avatarImageId: member.avatarImageId,
avatarUrl: member.avatarUrl,
spouseName: spouses.length > 0 ? spouses.map(s => s.fullName).join(', ') : '',
spouseId: spouses.length > 0 ? spouses[0].id : null,
hasChildren: Object.values(members).some(m => m.fatherId === member.id || m.motherId === member.id),
@@ -151,34 +151,17 @@ const D3OrgChartFlowComponent = forwardRef<D3OrgChartRef, D3OrgChartFlowProps>(
return chartNodes
}
// 加载所有成员的头像
// 构建头像缓存(URL 直接使用)
useEffect(() => {
const loadAvatars = async () => {
const cache = new Map<string, string>()
for (const member of Object.values(members)) {
if (member.avatarImageId) {
try {
const image = await db.images.get(member.avatarImageId)
if (image) {
const url = URL.createObjectURL(image.blob)
cache.set(member.avatarImageId, url)
}
} catch (error) {
console.error(`Failed to load avatar for ${member.fullName}:`, error)
}
}
const cache = new Map<string, string>()
for (const member of Object.values(members)) {
if (member.avatarUrl) {
cache.set(member.avatarUrl, member.avatarUrl)
}
setAvatarCache(cache)
}
loadAvatars()
// 清理函数
return () => {
avatarCache.forEach(url => URL.revokeObjectURL(url))
}
setAvatarCache(cache)
}, [members])
useEffect(() => {
@@ -217,7 +200,7 @@ const D3OrgChartFlowComponent = forwardRef<D3OrgChartRef, D3OrgChartFlowProps>(
const bgColor = node.gender === '男' ? '#dbeafe' : '#fce7f3'
// 获取头像URL
const avatarUrl = node.avatarImageId ? avatarCache.get(node.avatarImageId) : null
const avatarUrl = node.avatarUrl ? avatarCache.get(node.avatarUrl) : null
// 检查是否被选中
const isSelected = selectedMembers.includes(node.id)
@@ -260,8 +243,9 @@ const D3OrgChartFlowComponent = forwardRef<D3OrgChartRef, D3OrgChartFlowProps>(
}
</div>
<div style="flex: 1; min-width: 0;">
<div style="font-size: 13px; font-weight: 600; color: #1f2937; margin-bottom: 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; display: flex; align-items: center; gap: 4px;">
<div style="font-size: 13px; font-weight: 600; color: ${node.deathYear ? '#9ca3af' : '#1f2937'}; margin-bottom: 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; display: flex; align-items: center; gap: 4px; position: relative; padding-right: 12px;">
<span>${node.name}</span>
<span style="position: absolute; right: 2px; top: 4px; width: 8px; height: 8px; border-radius: 50%; background-color: ${node.deathYear ? '#9ca3af' : '#22c55e'};"></span>
${isSelected ? `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#3b82f6" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>` : ''}
</div>
<div style="font-size: 9px; color: #6b7280; padding: 1px 4px; background: #f3f4f6; border-radius: 3px; display: inline-block;">
@@ -304,19 +288,6 @@ const D3OrgChartFlowComponent = forwardRef<D3OrgChartRef, D3OrgChartFlowProps>(
配偶: ${node.spouseName}
</div>
` : ''}
${node.deathYear ? `
<div style="
position: absolute;
bottom: 4px;
left: 4px;
width: 12px;
height: 12px;
border-radius: 50%;
background: #737373;
border: 2px solid white;
"></div>
` : ''}
</div>
`
})