0.3.0.3
This commit is contained in:
+106
-2
@@ -6,10 +6,11 @@ import Image from "next/image"
|
||||
import dynamic from "next/dynamic"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
|
||||
import { Dialog, DialogContent } from "@/components/ui/dialog"
|
||||
import { SiteHeader } from "@/components/site-header"
|
||||
import { ScrollArea } from "@/components/ui/scroll-area"
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
|
||||
import { UserPlus, Network, Map, Calendar, Users, ArrowRight, Clock, Search, BookOpen, BarChart3, Calculator, Loader2 } from "lucide-react"
|
||||
import { UserPlus, Network, Map, Calendar, Users, ArrowRight, Clock, Search, BookOpen, BarChart3, Calculator, Loader2, Images } from "lucide-react"
|
||||
import { useFamily } from "@/context/family-context"
|
||||
import { useMemo, useState, useEffect, useRef, useCallback } from "react"
|
||||
import { useRouter } from "next/navigation"
|
||||
@@ -53,6 +54,7 @@ export default function DashboardPage() {
|
||||
const { treeData, isLoading, currentTree } = useFamily()
|
||||
const { data: session } = useSession()
|
||||
const [recentActivities, setRecentActivities] = useState<ActivityLog[]>([])
|
||||
const [selectedPhoto, setSelectedPhoto] = useState<string | null>(null)
|
||||
const router = useRouter()
|
||||
|
||||
// 首次登录跳转到使用帮助
|
||||
@@ -152,6 +154,32 @@ export default function DashboardPage() {
|
||||
.slice(0, 5)
|
||||
}, [treeData])
|
||||
|
||||
// 收集所有成员的照片
|
||||
const allPhotos = useMemo(() => {
|
||||
const photos: Array<{
|
||||
url: string
|
||||
memberId: string
|
||||
memberName: string
|
||||
isDead: boolean
|
||||
}> = []
|
||||
|
||||
Object.values(treeData.members).forEach(member => {
|
||||
if (member.photoIds && member.photoIds.length > 0) {
|
||||
member.photoIds.forEach(url => {
|
||||
photos.push({
|
||||
url,
|
||||
memberId: member.id,
|
||||
memberName: member.fullName,
|
||||
isDead: !!member.deathDate
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// 随机打乱顺序,让展示更有趣
|
||||
return photos.sort(() => Math.random() - 0.5)
|
||||
}, [treeData])
|
||||
|
||||
// 获取本月纪念日(生日和忌日)- 支持农历
|
||||
const monthlyAnniversaries = useMemo(() => {
|
||||
const members = Object.values(treeData.members)
|
||||
@@ -476,9 +504,10 @@ export default function DashboardPage() {
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<Tabs defaultValue="recent" className="w-full flex-1 flex flex-col overflow-hidden">
|
||||
<Tabs defaultValue="photos" className="w-full flex-1 flex flex-col overflow-hidden">
|
||||
<div className="flex items-center justify-between mb-4 flex-shrink-0">
|
||||
<TabsList className="bg-muted/50">
|
||||
<TabsTrigger value="photos">照片展示</TabsTrigger>
|
||||
<TabsTrigger value="recent">最近更新</TabsTrigger>
|
||||
<TabsTrigger value="anniversaries">近期纪念日</TabsTrigger>
|
||||
<TabsTrigger value="statistics">统计图表</TabsTrigger>
|
||||
@@ -491,6 +520,68 @@ export default function DashboardPage() {
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{/* 照片展示标签页 */}
|
||||
<TabsContent value="photos" className="mt-0 flex-1 overflow-y-auto">
|
||||
<Card className="border-none shadow-sm bg-card/50 backdrop-blur">
|
||||
<CardHeader>
|
||||
<CardTitle className="font-serif flex items-center gap-2">
|
||||
<Images className="h-5 w-5 text-primary" />
|
||||
家族影像
|
||||
</CardTitle>
|
||||
<CardDescription>珍藏的家族照片,记录美好时光</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
{allPhotos.length > 0 ? (
|
||||
<div className="columns-2 md:columns-3 lg:columns-4 xl:columns-5 gap-4 space-y-4">
|
||||
{allPhotos.map((photo, index) => (
|
||||
<div
|
||||
key={`${photo.memberId}-${index}`}
|
||||
className="break-inside-avoid group"
|
||||
>
|
||||
<div className="rounded-lg overflow-hidden bg-card shadow-sm hover:shadow-lg transition-all duration-300 hover:-translate-y-1 border border-border/50">
|
||||
{/* 照片区域 - 点击放大 */}
|
||||
<div
|
||||
className="relative cursor-zoom-in"
|
||||
onClick={() => setSelectedPhoto(photo.url)}
|
||||
>
|
||||
<img
|
||||
src={photo.url}
|
||||
alt={`${photo.memberName}的照片`}
|
||||
className="w-full h-auto object-cover"
|
||||
loading="lazy"
|
||||
/>
|
||||
</div>
|
||||
{/* 底部显示成员名称 - 点击跳转 */}
|
||||
<div className="px-3 py-2 bg-card border-t border-border/30">
|
||||
<div className="flex items-center gap-1.5 text-xs">
|
||||
<span className="text-muted-foreground">来自</span>
|
||||
<Link
|
||||
href={`/members/${photo.memberId}${currentTree?.id ? `?treeId=${currentTree.id}` : ''}`}
|
||||
className="hover:text-primary hover:underline"
|
||||
>
|
||||
<MemberNameWithStatus
|
||||
name={photo.memberName}
|
||||
isDead={photo.isDead}
|
||||
className="text-foreground font-medium"
|
||||
/>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div className="text-center py-16">
|
||||
<Images className="h-12 w-12 mx-auto text-muted-foreground/30 mb-4" />
|
||||
<p className="text-muted-foreground">暂无照片</p>
|
||||
<p className="text-sm text-muted-foreground/70 mt-1">在成员详情页可以添加照片</p>
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="recent" className="mt-0 flex-1 overflow-y-auto">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||
<div className="space-y-6">
|
||||
@@ -898,6 +989,19 @@ export default function DashboardPage() {
|
||||
</Card>
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
|
||||
{/* 照片放大预览 Dialog */}
|
||||
<Dialog open={!!selectedPhoto} onOpenChange={() => setSelectedPhoto(null)}>
|
||||
<DialogContent className="max-w-4xl p-0 bg-black/95 border-none">
|
||||
{selectedPhoto && (
|
||||
<img
|
||||
src={selectedPhoto}
|
||||
alt="照片预览"
|
||||
className="w-full h-auto max-h-[90vh] object-contain"
|
||||
/>
|
||||
)}
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</main>
|
||||
</div>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user