0.3.0.0
This commit is contained in:
+82
-33
@@ -4,16 +4,13 @@ import { useFamily } from "@/context/family-context"
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
|
||||
import { ScrollArea } from "@/components/ui/scroll-area"
|
||||
import { Clock, Map as MapIcon, ArrowRight, Calendar, User } from 'lucide-react'
|
||||
import dynamic from 'next/dynamic'
|
||||
import { useMemo, useEffect, useState } from 'react'
|
||||
import * as echarts from 'echarts'
|
||||
import { Clock, Map as MapIcon, ArrowRight, Calendar, User, Loader2 } from 'lucide-react'
|
||||
import { useMemo, useEffect, useState, useRef, useCallback } from 'react'
|
||||
import { MemberNameWithStatus } from "@/components/member-name-with-status"
|
||||
import { useSession } from 'next-auth/react'
|
||||
import { EmptyStateBadge } from '@/components/empty-state-badge'
|
||||
import { useRouter } from 'next/navigation'
|
||||
|
||||
const ReactECharts = dynamic(() => import('echarts-for-react'), { ssr: false })
|
||||
import type { ECharts } from 'echarts'
|
||||
|
||||
// 中国地图 GeoJSON 数据 - 完整的轮廓
|
||||
const chinaGeoJSON = {
|
||||
@@ -194,6 +191,7 @@ export default function TimelinePage() {
|
||||
const [mapLoaded, setMapLoaded] = useState(false)
|
||||
const treeId = currentTree?.id
|
||||
const router = useRouter()
|
||||
const chartInstanceRef = useRef<ECharts | null>(null)
|
||||
|
||||
// 未登录时重定向到登录页
|
||||
useEffect(() => {
|
||||
@@ -204,18 +202,38 @@ export default function TimelinePage() {
|
||||
|
||||
// 注册中国地图 - 从外部文件加载完整数据(必须在条件渲染之前)
|
||||
useEffect(() => {
|
||||
fetch('/china.json')
|
||||
.then(response => response.json())
|
||||
.then(geoJson => {
|
||||
echarts.registerMap('china', geoJson)
|
||||
setMapLoaded(true)
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Failed to load China map:', error)
|
||||
// 如果加载失败,使用简化版本
|
||||
echarts.registerMap('china', chinaGeoJSON as any)
|
||||
setMapLoaded(true)
|
||||
})
|
||||
let isMounted = true
|
||||
|
||||
// 动态导入 echarts 并注册地图
|
||||
const loadMap = async () => {
|
||||
try {
|
||||
const echarts = await import('echarts')
|
||||
|
||||
try {
|
||||
const response = await fetch('/china.json')
|
||||
const geoJson = await response.json()
|
||||
if (isMounted) {
|
||||
echarts.registerMap('china', geoJson)
|
||||
setMapLoaded(true)
|
||||
}
|
||||
} catch (fetchError) {
|
||||
console.error('Failed to load China map JSON, using fallback:', fetchError)
|
||||
// 如果加载失败,使用简化版本
|
||||
if (isMounted) {
|
||||
echarts.registerMap('china', chinaGeoJSON as any)
|
||||
setMapLoaded(true)
|
||||
}
|
||||
}
|
||||
} catch (importError) {
|
||||
console.error('Failed to import echarts:', importError)
|
||||
}
|
||||
}
|
||||
|
||||
loadMap()
|
||||
|
||||
return () => {
|
||||
isMounted = false
|
||||
}
|
||||
}, [])
|
||||
|
||||
// -- Timeline Logic -- (必须在条件渲染之前)
|
||||
@@ -482,6 +500,50 @@ export default function TimelinePage() {
|
||||
}
|
||||
}, [migrations])
|
||||
|
||||
// 使用 callback ref 来确保 DOM 元素挂载后初始化图表
|
||||
const initChartRef = useCallback((node: HTMLDivElement | null) => {
|
||||
if (!node || !mapLoaded) {
|
||||
console.log('initChartRef: node或mapLoaded不存在', { node: !!node, mapLoaded })
|
||||
return
|
||||
}
|
||||
|
||||
console.log('initChartRef: 开始初始化图表')
|
||||
|
||||
// 动态导入并初始化图表
|
||||
import('echarts').then((echarts) => {
|
||||
// 再次检查节点是否存在
|
||||
if (!node) return
|
||||
|
||||
// 检查是否已有实例
|
||||
let chart = echarts.getInstanceByDom(node)
|
||||
|
||||
if (!chart) {
|
||||
console.log('创建新的图表实例')
|
||||
// 创建新实例
|
||||
chart = echarts.init(node)
|
||||
chartInstanceRef.current = chart
|
||||
|
||||
// 监听窗口大小变化
|
||||
const handleResize = () => {
|
||||
chart?.resize()
|
||||
}
|
||||
window.addEventListener('resize', handleResize)
|
||||
|
||||
// 保存清理函数到节点
|
||||
;(node as any).__resizeHandler = handleResize
|
||||
} else {
|
||||
console.log('使用已有的图表实例')
|
||||
}
|
||||
|
||||
// 设置选项
|
||||
console.log('设置图表选项')
|
||||
chart.setOption(mapOption, { notMerge: true })
|
||||
console.log('图表选项设置完成')
|
||||
}).catch(error => {
|
||||
console.error('Failed to initialize chart:', error)
|
||||
})
|
||||
}, [mapLoaded, mapOption])
|
||||
|
||||
// 未登录时不渲染内容(已在 useEffect 中重定向)
|
||||
if (status === 'loading' || !session) {
|
||||
return null
|
||||
@@ -724,23 +786,10 @@ export default function TimelinePage() {
|
||||
<p>加载地图中...</p>
|
||||
</div>
|
||||
</div>
|
||||
) : migrations.length === 0 ? (
|
||||
<div className="flex items-center justify-center h-full">
|
||||
<div className="text-center space-y-4">
|
||||
<div className="inline-flex items-center justify-center w-16 h-16 text-primary/80">
|
||||
<MapIcon className="h-16 w-16" strokeWidth={1} />
|
||||
</div>
|
||||
<p className="text-sm text-foreground font-light tracking-wide">山河未绘</p>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<ReactECharts
|
||||
key="migration-map"
|
||||
option={mapOption}
|
||||
<div
|
||||
ref={initChartRef}
|
||||
style={{ height: '100%', width: '100%' }}
|
||||
opts={{ renderer: 'canvas' }}
|
||||
notMerge={true}
|
||||
lazyUpdate={true}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user