This commit is contained in:
freedakgmail
2025-12-21 17:32:33 +08:00
parent cffdd75e96
commit 5c8c70097c
190 changed files with 2746 additions and 893 deletions
+110 -4
View File
@@ -7,11 +7,11 @@ import dynamic from "next/dynamic"
import { Button } from "@/components/ui/button"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
import { ChineseCard, ChineseCardContent, ChineseCardHeader, ChineseCardTitle, ChineseCardDescription, ChineseDivider } from "@/components/ui/chinese-card"
import { Dialog, DialogContent, DialogTitle } from "@/components/ui/dialog"
import { Dialog, DialogContent, DialogTitle, DialogHeader, DialogDescription, DialogFooter } 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, Images, ChevronDown, ChevronUp, EyeOff, Play, Video } from "lucide-react"
import { UserPlus, Network, Map, Calendar, Users, ArrowRight, Clock, Search, BookOpen, BarChart3, Calculator, Loader2, Images, ChevronDown, ChevronUp, EyeOff, Play, Video, Edit } from "lucide-react"
import { useFamily } from "@/context/family-context"
import { useMemo, useState, useEffect, useRef, useCallback } from "react"
import { useRouter } from "next/navigation"
@@ -24,7 +24,11 @@ import { isInCurrentMonth, solar2lunar, lunar2solar } from "@/lib/lunar-calendar
import { MemberNameWithStatus } from "@/components/member-name-with-status"
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible"
import { Switch } from "@/components/ui/switch"
import { Input } from "@/components/ui/input"
import { Textarea } from "@/components/ui/textarea"
import { Label } from "@/components/ui/label"
import type { FamilyPhoto } from "@/types/family"
import { useDialog } from "@/components/ui/alert-dialog-custom"
// 动态导入统计图表组件(减少初始加载体积)
const StatisticsCharts = dynamic(
@@ -63,10 +67,14 @@ const isVideoFile = (url: string) => {
export default function DashboardPage() {
const { treeData, isLoading, currentTree, updateMember } = useFamily()
const { data: session } = useSession()
const { showAlert } = useDialog()
const [recentActivities, setRecentActivities] = useState<ActivityLog[]>([])
const [selectedPhoto, setSelectedPhoto] = useState<string | null>(null)
const [statsExpanded, setStatsExpanded] = useState(true)
const [adminToggleLoading, setAdminToggleLoading] = useState<string | null>(null)
const [editDialogOpen, setEditDialogOpen] = useState(false)
const [editForm, setEditForm] = useState({ name: '', description: '' })
const [isSaving, setIsSaving] = useState(false)
const router = useRouter()
// 首次登录跳转到使用帮助
@@ -223,6 +231,38 @@ export default function DashboardPage() {
}
}, [isOwner, treeData.members, updateMember])
// 保存编辑
const handleSaveEdit = async () => {
if (!currentTree?.id || !editForm.name.trim()) return
setIsSaving(true)
try {
const response = await fetch(`/api/trees/${currentTree.id}`, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: editForm.name.trim(),
description: editForm.description.trim() || null,
}),
})
if (!response.ok) {
throw new Error('更新失败')
}
setEditDialogOpen(false)
// 刷新页面以显示更新后的数据
window.location.reload()
} catch (error) {
console.error('更新家族信息失败:', error)
await showAlert('更新失败,请重试', "错误")
} finally {
setIsSaving(false)
}
}
// 获取本月纪念日(生日和忌日)- 支持农历
const monthlyAnniversaries = useMemo(() => {
const members = Object.values(treeData.members)
@@ -452,12 +492,28 @@ export default function DashboardPage() {
</div>
<p className="text-muted-foreground mt-1">
{currentTree?.description || '记录家族历史,传承家族文化'}
{stats.maxGeneration > 0 && ` · ${stats.maxGeneration} 代传人`}
{stats.maxGeneration > 0 && ` · ${stats.maxGeneration} 代传人`}
</p>
</div>
<div className="flex items-center gap-2">
{session && currentTree?.ownerId === session.user?.id && (
<CollaboratorDialog />
<>
<CollaboratorDialog />
<Button
variant="outline"
className="gap-2"
onClick={() => {
setEditForm({
name: currentTree?.name || '',
description: currentTree?.description || ''
})
setEditDialogOpen(true)
}}
>
<Edit className="h-4 w-4" />
</Button>
</>
)}
{permissions.canCreate(currentTree?.currentUserRole) && (
<Link href={currentTree?.id ? `/members/new?treeId=${currentTree.id}` : '/members/new'}>
@@ -1181,6 +1237,56 @@ export default function DashboardPage() {
)}
</DialogContent>
</Dialog>
{/* 编辑家族信息对话框 */}
<Dialog open={editDialogOpen} onOpenChange={setEditDialogOpen}>
<DialogContent className="sm:max-w-[500px]">
<DialogHeader>
<DialogTitle></DialogTitle>
<DialogDescription>
</DialogDescription>
</DialogHeader>
<div className="space-y-4 py-4">
<div className="space-y-2">
<Label htmlFor="tree-name"></Label>
<Input
id="tree-name"
value={editForm.name}
onChange={(e) => setEditForm({ ...editForm, name: e.target.value })}
placeholder="请输入家族名称"
maxLength={50}
/>
</div>
<div className="space-y-2">
<Label htmlFor="tree-description"></Label>
<Textarea
id="tree-description"
value={editForm.description}
onChange={(e) => setEditForm({ ...editForm, description: e.target.value })}
placeholder="请输入家族说明"
rows={4}
maxLength={200}
/>
</div>
</div>
<DialogFooter>
<Button
variant="outline"
onClick={() => setEditDialogOpen(false)}
disabled={isSaving}
>
</Button>
<Button
onClick={handleSaveEdit}
disabled={isSaving || !editForm.name.trim()}
>
{isSaving ? '保存中...' : '保存'}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
</main>
</div>
)