0.0.8.1
This commit is contained in:
@@ -86,12 +86,6 @@ export default function RegisterPage() {
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
<Alert className="bg-blue-50 border-blue-200 dark:bg-blue-950 dark:border-blue-800">
|
||||
<AlertDescription className="text-sm text-blue-800 dark:text-blue-200">
|
||||
💡 系统已有测试账号,建议直接<Link href="/auth/signin" className="underline font-semibold">登录</Link>使用
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="name">姓名</Label>
|
||||
<Input
|
||||
@@ -144,7 +138,7 @@ export default function RegisterPage() {
|
||||
</div>
|
||||
</CardContent>
|
||||
|
||||
<CardFooter className="flex flex-col space-y-4">
|
||||
<CardFooter className="flex flex-col space-y-4 pt-6">
|
||||
<Button
|
||||
type="submit"
|
||||
className="w-full"
|
||||
|
||||
@@ -13,8 +13,8 @@ import { BookOpen } from "lucide-react"
|
||||
|
||||
export default function SignInPage() {
|
||||
const router = useRouter()
|
||||
const [email, setEmail] = useState("wang@example.com")
|
||||
const [password, setPassword] = useState("123456")
|
||||
const [email, setEmail] = useState("")
|
||||
const [password, setPassword] = useState("")
|
||||
const [error, setError] = useState("")
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
@@ -76,46 +76,6 @@ export default function SignInPage() {
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
<Alert className="bg-blue-50 border-blue-200 dark:bg-blue-950 dark:border-blue-800">
|
||||
<AlertDescription className="text-sm text-blue-800 dark:text-blue-200">
|
||||
<div className="space-y-2">
|
||||
<div className="font-semibold">💡 测试账号:</div>
|
||||
<div className="space-y-1 text-xs">
|
||||
<div className="flex items-center justify-between">
|
||||
<span>王先生: wang@example.com / 123456</span>
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="h-6 px-2 text-xs"
|
||||
onClick={() => {
|
||||
setEmail("wang@example.com")
|
||||
setPassword("123456")
|
||||
}}
|
||||
>
|
||||
使用
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<span>虞女士: yu@example.com / 123456</span>
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="h-6 px-2 text-xs"
|
||||
onClick={() => {
|
||||
setEmail("yu@example.com")
|
||||
setPassword("123456")
|
||||
}}
|
||||
>
|
||||
使用
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="email">邮箱</Label>
|
||||
<Input
|
||||
@@ -143,7 +103,7 @@ export default function SignInPage() {
|
||||
</div>
|
||||
</CardContent>
|
||||
|
||||
<CardFooter className="flex flex-col space-y-4">
|
||||
<CardFooter className="flex flex-col space-y-4 pt-6">
|
||||
<Button
|
||||
type="submit"
|
||||
className="w-full"
|
||||
|
||||
@@ -156,6 +156,17 @@
|
||||
height: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes scroll {
|
||||
0% {
|
||||
transform: translateY(0);
|
||||
}
|
||||
100% {
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
}
|
||||
|
||||
--animate-scroll: scroll 20s linear infinite;
|
||||
}
|
||||
|
||||
@layer base {
|
||||
|
||||
@@ -0,0 +1,296 @@
|
||||
"use client"
|
||||
|
||||
import { SiteHeader } from "@/components/site-header"
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
|
||||
import { BookOpen, Users, Network, Settings, Shield, FileText } from "lucide-react"
|
||||
|
||||
export default function HelpPage() {
|
||||
return (
|
||||
<div className="min-h-screen flex flex-col bg-background">
|
||||
<SiteHeader />
|
||||
|
||||
<main className="flex-1 container mx-auto px-4 py-8">
|
||||
<div className="max-w-5xl mx-auto space-y-8">
|
||||
{/* 标题 */}
|
||||
<div>
|
||||
<h1 className="text-3xl font-serif font-bold mb-2">使用帮助</h1>
|
||||
<p className="text-muted-foreground">
|
||||
华夏家谱系统使用指南
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<Tabs defaultValue="guide" className="space-y-6">
|
||||
<TabsList className="grid w-full grid-cols-3">
|
||||
<TabsTrigger value="guide">快速入门</TabsTrigger>
|
||||
<TabsTrigger value="roles">角色权限</TabsTrigger>
|
||||
<TabsTrigger value="features">功能说明</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
{/* 快速入门 */}
|
||||
<TabsContent value="guide" className="space-y-6">
|
||||
<Card className="border-none shadow-sm bg-card/50 backdrop-blur">
|
||||
<CardHeader>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex h-12 w-12 items-center justify-center rounded-full bg-primary/10 text-primary">
|
||||
<BookOpen className="h-6 w-6" />
|
||||
</div>
|
||||
<div>
|
||||
<CardTitle className="text-xl font-serif font-light">使用流程</CardTitle>
|
||||
<CardDescription className="font-light">从创建到完善的完整流程</CardDescription>
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-6">
|
||||
<div className="space-y-4">
|
||||
<div className="flex gap-4">
|
||||
<div className="flex-shrink-0 w-8 h-8 rounded-full bg-primary text-primary-foreground flex items-center justify-center font-bold">
|
||||
1
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<h3 className="font-medium mb-1">注册账号</h3>
|
||||
<p className="text-sm text-muted-foreground font-light">
|
||||
使用邮箱注册账号,验证后即可登录系统
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-4">
|
||||
<div className="flex-shrink-0 w-8 h-8 rounded-full bg-primary text-primary-foreground flex items-center justify-center font-bold">
|
||||
2
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<h3 className="font-medium mb-1">创建家族树</h3>
|
||||
<p className="text-sm text-muted-foreground font-light">
|
||||
首次登录后,点击"开始记录"创建您的第一个家族树,填写家族名称和描述
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-4">
|
||||
<div className="flex-shrink-0 w-8 h-8 rounded-full bg-primary text-primary-foreground flex items-center justify-center font-bold">
|
||||
3
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<h3 className="font-medium mb-1">添加始祖</h3>
|
||||
<p className="text-sm text-muted-foreground font-light">
|
||||
添加家族的第一位成员(始祖),填写基本信息如姓名、生卒年月、籍贯等
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-4">
|
||||
<div className="flex-shrink-0 w-8 h-8 rounded-full bg-primary text-primary-foreground flex items-center justify-center font-bold">
|
||||
4
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<h3 className="font-medium mb-1">添加配偶和子女</h3>
|
||||
<p className="text-sm text-muted-foreground font-light">
|
||||
为成员添加配偶关系和子女,系统会自动建立家族关系网络
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-4">
|
||||
<div className="flex-shrink-0 w-8 h-8 rounded-full bg-primary text-primary-foreground flex items-center justify-center font-bold">
|
||||
5
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<h3 className="font-medium mb-1">完善信息</h3>
|
||||
<p className="text-sm text-muted-foreground font-light">
|
||||
上传照片、填写生平事迹、添加标签等,丰富家族档案
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-4">
|
||||
<div className="flex-shrink-0 w-8 h-8 rounded-full bg-primary text-primary-foreground flex items-center justify-center font-bold">
|
||||
6
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<h3 className="font-medium mb-1">邀请协作</h3>
|
||||
<p className="text-sm text-muted-foreground font-light">
|
||||
邀请家族成员共同编辑,一起完善家族树
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className="border-none shadow-sm bg-card/50 backdrop-blur">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-xl font-serif font-light">温馨提示</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="space-y-2 text-sm text-muted-foreground font-light">
|
||||
<li>• 建议先从近代祖先开始录入,逐步向上追溯</li>
|
||||
<li>• 尽量填写完整的生卒年月和籍贯信息,便于生成统计和迁徙图</li>
|
||||
<li>• 定期备份数据,可使用导出功能保存家族数据</li>
|
||||
<li>• 上传的照片建议使用清晰的正面照</li>
|
||||
<li>• 邀请家族成员协作时,建议赋予"编辑者"角色</li>
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
|
||||
{/* 角色权限 */}
|
||||
<TabsContent value="roles" className="space-y-6">
|
||||
<Card className="border-none shadow-sm bg-card/50 backdrop-blur">
|
||||
<CardHeader>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex h-12 w-12 items-center justify-center rounded-full bg-primary/10 text-primary">
|
||||
<Shield className="h-6 w-6" />
|
||||
</div>
|
||||
<div>
|
||||
<CardTitle className="text-xl font-serif font-light">角色说明</CardTitle>
|
||||
<CardDescription className="font-light">不同角色的权限范围</CardDescription>
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-6">
|
||||
<div className="space-y-6">
|
||||
<div className="p-4 bg-primary/5 rounded-lg">
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
<div className="w-2 h-2 rounded-full bg-primary"></div>
|
||||
<h3 className="font-medium">创建者 (Owner)</h3>
|
||||
</div>
|
||||
<p className="text-sm text-muted-foreground font-light mb-3">
|
||||
家族树的创建者,拥有最高权限
|
||||
</p>
|
||||
<div className="space-y-1 text-sm">
|
||||
<p className="text-muted-foreground font-light">✓ 查看所有信息</p>
|
||||
<p className="text-muted-foreground font-light">✓ 添加、编辑、删除成员</p>
|
||||
<p className="text-muted-foreground font-light">✓ 管理协作者</p>
|
||||
<p className="text-muted-foreground font-light">✓ 导入导出数据</p>
|
||||
<p className="text-muted-foreground font-light">✓ 删除家族树</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="p-4 bg-muted/30 rounded-lg">
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
<div className="w-2 h-2 rounded-full bg-blue-500"></div>
|
||||
<h3 className="font-medium">编辑者 (Editor)</h3>
|
||||
</div>
|
||||
<p className="text-sm text-muted-foreground font-light mb-3">
|
||||
可以编辑家族树内容的协作者
|
||||
</p>
|
||||
<div className="space-y-1 text-sm">
|
||||
<p className="text-muted-foreground font-light">✓ 查看所有信息</p>
|
||||
<p className="text-muted-foreground font-light">✓ 添加、编辑成员</p>
|
||||
<p className="text-muted-foreground font-light">✓ 上传照片和文档</p>
|
||||
<p className="text-muted-foreground font-light">✗ 删除成员</p>
|
||||
<p className="text-muted-foreground font-light">✗ 管理协作者</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="p-4 bg-muted/30 rounded-lg">
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
<div className="w-2 h-2 rounded-full bg-green-500"></div>
|
||||
<h3 className="font-medium">查看者 (Viewer)</h3>
|
||||
</div>
|
||||
<p className="text-sm text-muted-foreground font-light mb-3">
|
||||
只能查看家族树信息的协作者
|
||||
</p>
|
||||
<div className="space-y-1 text-sm">
|
||||
<p className="text-muted-foreground font-light">✓ 查看所有信息</p>
|
||||
<p className="text-muted-foreground font-light">✓ 查看族谱图</p>
|
||||
<p className="text-muted-foreground font-light">✓ 查看统计数据</p>
|
||||
<p className="text-muted-foreground font-light">✗ 编辑任何内容</p>
|
||||
<p className="text-muted-foreground font-light">✗ 添加或删除成员</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
|
||||
{/* 功能说明 */}
|
||||
<TabsContent value="features" className="space-y-6">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<Card className="border-none shadow-sm bg-card/50 backdrop-blur">
|
||||
<CardHeader>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex h-10 w-10 items-center justify-center rounded-full bg-primary/10 text-primary">
|
||||
<Users className="h-5 w-5" />
|
||||
</div>
|
||||
<CardTitle className="text-lg font-serif font-light">成员管理</CardTitle>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="space-y-2 text-sm text-muted-foreground font-light">
|
||||
<li>• 添加、编辑、删除家族成员</li>
|
||||
<li>• 上传成员照片和文档</li>
|
||||
<li>• 记录生平事迹和重要信息</li>
|
||||
<li>• 设置成员标签和分类</li>
|
||||
<li>• 搜索和筛选成员</li>
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className="border-none shadow-sm bg-card/50 backdrop-blur">
|
||||
<CardHeader>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex h-10 w-10 items-center justify-center rounded-full bg-primary/10 text-primary">
|
||||
<Network className="h-5 w-5" />
|
||||
</div>
|
||||
<CardTitle className="text-lg font-serif font-light">族谱图</CardTitle>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="space-y-2 text-sm text-muted-foreground font-light">
|
||||
<li>• 可视化展示家族关系</li>
|
||||
<li>• 支持缩放和拖拽</li>
|
||||
<li>• 快速定位成员位置</li>
|
||||
<li>• 导出族谱图片</li>
|
||||
<li>• 多种视图模式</li>
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className="border-none shadow-sm bg-card/50 backdrop-blur">
|
||||
<CardHeader>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex h-10 w-10 items-center justify-center rounded-full bg-primary/10 text-primary">
|
||||
<FileText className="h-5 w-5" />
|
||||
</div>
|
||||
<CardTitle className="text-lg font-serif font-light">关系计算</CardTitle>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="space-y-2 text-sm text-muted-foreground font-light">
|
||||
<li>• 自动计算成员间的亲属关系</li>
|
||||
<li>• 显示关系路径</li>
|
||||
<li>• 查看直系亲属信息</li>
|
||||
<li>• 支持复杂关系计算</li>
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className="border-none shadow-sm bg-card/50 backdrop-blur">
|
||||
<CardHeader>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex h-10 w-10 items-center justify-center rounded-full bg-primary/10 text-primary">
|
||||
<Settings className="h-5 w-5" />
|
||||
</div>
|
||||
<CardTitle className="text-lg font-serif font-light">数据管理</CardTitle>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="space-y-2 text-sm text-muted-foreground font-light">
|
||||
<li>• 导入已有家族数据</li>
|
||||
<li>• 导出备份数据</li>
|
||||
<li>• 查看修谱记录</li>
|
||||
<li>• 统计分析功能</li>
|
||||
<li>• 时间轴和迁徙图</li>
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
import type React from "react"
|
||||
import type { Metadata } from "next"
|
||||
import { Geist, Geist_Mono } from "next/font/google"
|
||||
import { Analytics } from "@vercel/analytics/next"
|
||||
// import { Analytics } from "@vercel/analytics/next"
|
||||
import "./globals.css"
|
||||
import { FamilyProvider } from "@/context/family-context"
|
||||
import { PWAProvider } from "@/components/pwa/pwa-provider"
|
||||
@@ -57,7 +57,7 @@ export default function RootLayout({
|
||||
</FamilyProvider>
|
||||
</DialogProvider>
|
||||
</SessionProvider>
|
||||
<Analytics />
|
||||
{/* <Analytics /> */}
|
||||
</body>
|
||||
</html>
|
||||
)
|
||||
|
||||
@@ -247,7 +247,7 @@ export default function MemberProfilePage() {
|
||||
{member.bio ? (
|
||||
<p className="whitespace-pre-line leading-relaxed">{member.bio}</p>
|
||||
) : (
|
||||
<p className="text-muted-foreground italic">暂无生平记录...</p>
|
||||
<p className="text-sm text-foreground font-light tracking-wide text-center py-8">生平待书</p>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -90,11 +90,14 @@ export default function NewMemberPage() {
|
||||
<div className="min-h-screen flex flex-col bg-background">
|
||||
<SiteHeader />
|
||||
<div className="container mx-auto py-8">
|
||||
<div className="mb-6 flex items-center gap-2">
|
||||
<Button variant="ghost" onClick={() => router.back()}>
|
||||
<div className="mb-6">
|
||||
<Button variant="ghost" onClick={() => router.back()} className="mb-4">
|
||||
<ArrowLeft className="mr-2 h-4 w-4" /> 返回
|
||||
</Button>
|
||||
<h1 className="text-2xl font-bold font-serif">新增家族成员</h1>
|
||||
<h1 className="text-3xl font-serif font-bold mb-2">新增家族成员</h1>
|
||||
<p className="text-muted-foreground">
|
||||
填写成员信息,完善家族树
|
||||
</p>
|
||||
</div>
|
||||
<MemberForm initialData={initialData} existingMembers={existingMembers} onSubmit={handleSave} onCancel={() => router.back()} />
|
||||
</div>
|
||||
|
||||
@@ -361,7 +361,7 @@ export default function MembersPage() {
|
||||
return (
|
||||
<div className="min-h-screen bg-background flex flex-col font-sans">
|
||||
<SiteHeader />
|
||||
<main className="container mx-auto py-8 px-4 md:px-6 flex-1">
|
||||
<main className="container mx-auto py-8 px-4 md:px-6 flex-1 flex flex-col">
|
||||
<div className="flex flex-col gap-6 mb-8">
|
||||
<div className="flex flex-col md:flex-row justify-between items-center gap-4">
|
||||
<h1 className="text-3xl font-serif font-bold">家族成员列表</h1>
|
||||
@@ -479,8 +479,13 @@ export default function MembersPage() {
|
||||
</div>
|
||||
|
||||
{filteredMembers.length === 0 ? (
|
||||
<div className="text-center py-12 text-muted-foreground">
|
||||
没有找到匹配的成员。
|
||||
<div className="flex-1 flex items-center justify-center">
|
||||
<div className="text-center space-y-4">
|
||||
<div className="inline-flex items-center justify-center w-16 h-16 text-primary/80">
|
||||
<Search className="h-16 w-16" strokeWidth={1} />
|
||||
</div>
|
||||
<p className="text-base text-foreground font-light tracking-wide">未寻得</p>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-8">
|
||||
|
||||
+150
-48
@@ -2,6 +2,7 @@
|
||||
|
||||
import type React from "react"
|
||||
import Link from "next/link"
|
||||
import Image from "next/image"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
|
||||
import { SiteHeader } from "@/components/site-header"
|
||||
@@ -159,6 +160,122 @@ export default function DashboardPage() {
|
||||
// 按日期排序
|
||||
return anniversaries.sort((a, b) => a.day - b.day).slice(0, 5)
|
||||
}, [treeData])
|
||||
|
||||
// 计算家族迁徙记录
|
||||
const locationGroups = useMemo(() => {
|
||||
const members = Object.values(treeData.members)
|
||||
const groups: Record<string, any[]> = {}
|
||||
|
||||
members.forEach(member => {
|
||||
if (member.ancestralHome) {
|
||||
if (!groups[member.ancestralHome]) {
|
||||
groups[member.ancestralHome] = []
|
||||
}
|
||||
groups[member.ancestralHome].push(member)
|
||||
}
|
||||
})
|
||||
|
||||
return Object.entries(groups).sort((a, b) => b[1].length - a[1].length)
|
||||
}, [treeData])
|
||||
|
||||
// 如果用户没有家族树,显示欢迎页面
|
||||
if (!isLoading && !currentTree) {
|
||||
return (
|
||||
<div className="flex min-h-screen flex-col bg-background font-sans">
|
||||
<SiteHeader />
|
||||
|
||||
<main className="flex-1 flex items-center justify-center px-4 md:px-6 relative">
|
||||
{/* 背景装饰图片 */}
|
||||
<div className="absolute inset-0 pointer-events-none overflow-hidden">
|
||||
{/* 建筑图片 - 左下 */}
|
||||
<div className="absolute left-24 top-[60%] -translate-y-1/2 w-[30rem] h-[30rem] opacity-30 rotate-12">
|
||||
<Image
|
||||
src="/building.png"
|
||||
alt=""
|
||||
fill
|
||||
className="object-contain"
|
||||
priority
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 树图片 - 右上 */}
|
||||
<div className="absolute right-24 top-[40%] -translate-y-1/2 w-[30rem] h-[30rem] opacity-30 -rotate-12">
|
||||
<Image
|
||||
src="/tree.png"
|
||||
alt=""
|
||||
fill
|
||||
className="object-contain"
|
||||
priority
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 内容区域 */}
|
||||
<div className="max-w-3xl mx-auto text-center space-y-12">
|
||||
{/* 图标 */}
|
||||
<div className="inline-flex items-center justify-center w-16 h-16 text-primary/20">
|
||||
<BookOpen className="h-16 w-16" strokeWidth={1} />
|
||||
</div>
|
||||
|
||||
{/* 标题 */}
|
||||
<div className="space-y-6">
|
||||
<h1 className="text-4xl md:text-5xl font-serif font-light text-foreground tracking-wide">
|
||||
华夏家谱
|
||||
</h1>
|
||||
|
||||
{/* 哲理文字 - 滚动显示 */}
|
||||
<div className="h-48 overflow-hidden relative">
|
||||
<div className="space-y-8 text-muted-foreground antialiased" style={{ animation: 'scroll 30s linear infinite' }}>
|
||||
<p className="text-lg md:text-xl font-normal leading-relaxed">
|
||||
家族是根,文化是魂
|
||||
</p>
|
||||
<p className="text-base md:text-lg font-normal leading-relaxed opacity-85">
|
||||
记录过往,传承未来
|
||||
</p>
|
||||
<p className="text-base md:text-lg font-normal leading-relaxed opacity-70">
|
||||
让每一个故事都成为永恒
|
||||
</p>
|
||||
<p className="text-base md:text-lg font-normal leading-relaxed opacity-60">
|
||||
血脉相连,世代相传
|
||||
</p>
|
||||
<p className="text-base md:text-lg font-normal leading-relaxed opacity-50">
|
||||
铭记历史,启迪后人
|
||||
</p>
|
||||
<p className="text-base md:text-lg font-normal leading-relaxed opacity-40">
|
||||
家风永续,德泽绵长
|
||||
</p>
|
||||
{/* 重复内容实现无缝滚动 */}
|
||||
<p className="text-lg md:text-xl font-normal leading-relaxed">
|
||||
家族是根,文化是魂
|
||||
</p>
|
||||
<p className="text-base md:text-lg font-normal leading-relaxed opacity-85">
|
||||
记录过往,传承未来
|
||||
</p>
|
||||
<p className="text-base md:text-lg font-normal leading-relaxed opacity-70">
|
||||
让每一个故事都成为永恒
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 创建按钮 */}
|
||||
<div className="pt-8">
|
||||
<Link href="/trees/new">
|
||||
<Button
|
||||
size="lg"
|
||||
className="gap-2 bg-primary text-primary-foreground hover:bg-primary/90 transition-all duration-300"
|
||||
>
|
||||
开始记录
|
||||
<ArrowRight className="h-4 w-4" />
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex min-h-screen flex-col bg-background font-sans">
|
||||
<SiteHeader />
|
||||
@@ -244,7 +361,9 @@ export default function DashboardPage() {
|
||||
</div>
|
||||
<div className="flex flex-col space-y-1">
|
||||
<div className="flex items-center justify-center gap-3">
|
||||
<span className="text-3xl font-serif font-bold text-primary tracking-tight">1</span>
|
||||
<span className="text-3xl font-serif font-bold text-primary tracking-tight">
|
||||
{stats.maleCount > 0 ? '1' : '0'}
|
||||
</span>
|
||||
<span className="text-2xl font-bold text-muted-foreground">:</span>
|
||||
<span className="text-3xl font-serif font-bold text-primary tracking-tight">
|
||||
{stats.maleCount > 0 ? (stats.femaleCount / stats.maleCount).toFixed(2) : '0'}
|
||||
@@ -323,8 +442,8 @@ export default function DashboardPage() {
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
<div className="text-center text-muted-foreground py-8">
|
||||
暂无修谱记录
|
||||
<div className="text-center py-12">
|
||||
<p className="text-sm text-foreground font-light tracking-wide">静待修谱</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -367,8 +486,8 @@ export default function DashboardPage() {
|
||||
)
|
||||
})
|
||||
) : (
|
||||
<div className="text-center text-muted-foreground py-8 text-sm">
|
||||
本月暂无纪念日
|
||||
<div className="text-center py-12">
|
||||
<p className="text-sm text-foreground font-light tracking-wide">此月无忆</p>
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
@@ -457,8 +576,8 @@ export default function DashboardPage() {
|
||||
)
|
||||
})
|
||||
) : (
|
||||
<div className="col-span-full text-center py-12 text-muted-foreground">
|
||||
未来三个月暂无纪念日
|
||||
<div className="col-span-full text-center py-16">
|
||||
<p className="text-sm text-foreground font-light tracking-wide">来日无期</p>
|
||||
</div>
|
||||
)
|
||||
})()}
|
||||
@@ -481,49 +600,32 @@ export default function DashboardPage() {
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="space-y-6">
|
||||
{useMemo(() => {
|
||||
const members = Object.values(treeData.members)
|
||||
const locationGroups: Record<string, any[]> = {}
|
||||
|
||||
members.forEach(member => {
|
||||
if (member.ancestralHome) {
|
||||
if (!locationGroups[member.ancestralHome]) {
|
||||
locationGroups[member.ancestralHome] = []
|
||||
}
|
||||
locationGroups[member.ancestralHome].push(member)
|
||||
}
|
||||
})
|
||||
|
||||
const sortedLocations = Object.entries(locationGroups)
|
||||
.sort((a, b) => b[1].length - a[1].length)
|
||||
|
||||
return sortedLocations.length > 0 ? (
|
||||
sortedLocations.map(([location, locationMembers]) => (
|
||||
<div key={location} className="border-l-4 border-primary pl-4">
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<h3 className="text-lg font-serif font-bold">{location}</h3>
|
||||
<span className="text-sm text-muted-foreground">
|
||||
{locationMembers.length} 人
|
||||
</span>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-2">
|
||||
{locationMembers.map((member: any) => (
|
||||
<Link href={`/members/${member.id}`} key={member.id}>
|
||||
<div className="px-3 py-2 bg-muted rounded hover:bg-muted/80 transition-colors">
|
||||
<p className="text-sm font-medium truncate">{member.fullName}</p>
|
||||
<p className="text-xs text-muted-foreground">第 {member.generation} 世</p>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
{locationGroups.length > 0 ? (
|
||||
locationGroups.map(([location, locationMembers]) => (
|
||||
<div key={location} className="border-l-4 border-primary pl-4">
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<h3 className="text-lg font-serif font-bold">{location}</h3>
|
||||
<span className="text-sm text-muted-foreground">
|
||||
{locationMembers.length} 人
|
||||
</span>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-2">
|
||||
{locationMembers.map((member: any) => (
|
||||
<Link href={`/members/${member.id}`} key={member.id}>
|
||||
<div className="px-3 py-2 bg-muted rounded hover:bg-muted/80 transition-colors">
|
||||
<p className="text-sm font-medium truncate">{member.fullName}</p>
|
||||
<p className="text-xs text-muted-foreground">第 {member.generation} 世</p>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
<div className="text-center py-12 text-muted-foreground">
|
||||
暂无迁徙记录
|
||||
</div>
|
||||
)
|
||||
}, [treeData])}
|
||||
))
|
||||
) : (
|
||||
<div className="text-center py-16">
|
||||
<p className="text-sm text-foreground font-light tracking-wide">未有迁徙</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
+26
-26
@@ -42,24 +42,24 @@ export default function RelationshipTestPage() {
|
||||
<div className="min-h-screen flex flex-col bg-background">
|
||||
<SiteHeader />
|
||||
|
||||
<main className="flex-1 container mx-auto px-4 py-8">
|
||||
<div className="max-w-4xl mx-auto space-y-6">
|
||||
<main className="flex-1 container mx-auto px-4 py-12">
|
||||
<div className="max-w-4xl mx-auto space-y-8">
|
||||
{/* 标题 */}
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold font-serif mb-2">家族关系计算器</h1>
|
||||
<h1 className="text-3xl font-serif font-bold mb-2">家族关系计算器</h1>
|
||||
<p className="text-muted-foreground">
|
||||
选择两个家族成员,自动计算他们之间的亲属关系
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* 选择成员 */}
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>选择成员</CardTitle>
|
||||
<CardDescription>请选择要计算关系的两个成员</CardDescription>
|
||||
<Card className="border-none shadow-sm bg-card/50 backdrop-blur">
|
||||
<CardHeader className="text-center">
|
||||
<CardTitle className="text-2xl font-serif font-light">选择成员</CardTitle>
|
||||
<CardDescription className="font-light">请选择要计算关系的两个成员</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<CardContent className="space-y-8">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium">成员A</label>
|
||||
<Popover open={openFromCombobox} onOpenChange={setOpenFromCombobox}>
|
||||
@@ -158,7 +158,7 @@ export default function RelationshipTestPage() {
|
||||
<Button
|
||||
onClick={handleCalculate}
|
||||
disabled={!fromId || !toId}
|
||||
className="w-full"
|
||||
className="w-full h-12 bg-primary text-primary-foreground hover:bg-primary/90"
|
||||
>
|
||||
计算关系
|
||||
</Button>
|
||||
@@ -167,23 +167,23 @@ export default function RelationshipTestPage() {
|
||||
|
||||
{/* 计算结果 */}
|
||||
{result && (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>计算结果</CardTitle>
|
||||
<Card className="border-none shadow-sm bg-card/50 backdrop-blur">
|
||||
<CardHeader className="text-center">
|
||||
<CardTitle className="text-2xl font-serif font-light">计算结果</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<div className="flex items-center justify-center gap-4 p-6 bg-muted rounded-lg">
|
||||
<div className="flex items-center justify-center gap-6 p-8 bg-muted/30 rounded-lg">
|
||||
<div className="text-center">
|
||||
<div className="text-2xl font-bold font-serif mb-1">
|
||||
<div className="text-2xl font-serif font-light mb-1">
|
||||
{result.from.fullName}
|
||||
</div>
|
||||
<div className="text-sm text-muted-foreground">
|
||||
<div className="text-sm text-muted-foreground font-light">
|
||||
第{result.from.generation}世
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col items-center gap-2">
|
||||
<Badge variant="default" className="text-lg px-4 py-2">
|
||||
<Badge className="text-lg px-6 py-2 bg-primary text-primary-foreground">
|
||||
{result.relationship.term}
|
||||
</Badge>
|
||||
{result.relationship.path && (
|
||||
@@ -194,19 +194,19 @@ export default function RelationshipTestPage() {
|
||||
</div>
|
||||
|
||||
<div className="text-center">
|
||||
<div className="text-2xl font-bold font-serif mb-1">
|
||||
<div className="text-2xl font-serif font-light mb-1">
|
||||
{result.to.fullName}
|
||||
</div>
|
||||
<div className="text-sm text-muted-foreground">
|
||||
<div className="text-sm text-muted-foreground font-light">
|
||||
第{result.to.generation}世
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{result.relationship.description && (
|
||||
<div className="p-4 bg-blue-50 dark:bg-blue-950 rounded-lg">
|
||||
<div className="text-sm font-medium mb-1">关系说明:</div>
|
||||
<div className="text-muted-foreground">
|
||||
<div className="p-6 bg-primary/5 rounded-lg">
|
||||
<div className="text-sm font-light mb-2 text-center">关系说明</div>
|
||||
<div className="text-muted-foreground font-light text-center">
|
||||
<strong>{result.from.fullName}</strong> 是 <strong>{result.to.fullName}</strong> 的 <strong className="text-primary">{result.relationship.term}</strong>
|
||||
</div>
|
||||
</div>
|
||||
@@ -227,9 +227,9 @@ export default function RelationshipTestPage() {
|
||||
{(fromId || toId) && (
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||
{fromId && (
|
||||
<Card>
|
||||
<Card className="border-none shadow-sm bg-card/50 backdrop-blur">
|
||||
<CardHeader>
|
||||
<CardTitle>
|
||||
<CardTitle className="text-xl font-serif font-light">
|
||||
{treeData.members[fromId]?.fullName} 的直系亲属
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
@@ -311,9 +311,9 @@ export default function RelationshipTestPage() {
|
||||
)}
|
||||
|
||||
{toId && (
|
||||
<Card>
|
||||
<Card className="border-none shadow-sm bg-card/50 backdrop-blur">
|
||||
<CardHeader>
|
||||
<CardTitle>
|
||||
<CardTitle className="text-xl font-serif font-light">
|
||||
{treeData.members[toId]?.fullName} 的直系亲属
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
|
||||
+20
-14
@@ -4,7 +4,7 @@ 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 } from "lucide-react"
|
||||
import { Clock, Map as MapIcon, ArrowRight, Calendar } from "lucide-react"
|
||||
import dynamic from 'next/dynamic'
|
||||
import { useMemo, useEffect, useState } from 'react'
|
||||
import * as echarts from 'echarts'
|
||||
@@ -488,8 +488,13 @@ export default function TimelinePage() {
|
||||
return (
|
||||
<div className="min-h-screen bg-background flex flex-col">
|
||||
<SiteHeader />
|
||||
<div className="flex-1 flex items-center justify-center text-muted-foreground">
|
||||
暂无家族成员数据
|
||||
<div className="flex-1 flex items-center justify-center">
|
||||
<div className="text-center space-y-4">
|
||||
<div className="inline-flex items-center justify-center w-16 h-16 text-primary/80">
|
||||
<Calendar className="h-16 w-16" strokeWidth={1} />
|
||||
</div>
|
||||
<p className="text-base text-foreground font-light tracking-wide">时光未启</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
@@ -600,7 +605,9 @@ export default function TimelinePage() {
|
||||
))}
|
||||
|
||||
{events.length === 0 && (
|
||||
<div className="pl-8 text-muted-foreground italic">暂无时间记录。请完善成员的出生日期信息。</div>
|
||||
<div className="pl-8 py-8">
|
||||
<p className="text-sm text-foreground font-light tracking-wide">时光留白</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</CardContent>
|
||||
@@ -640,11 +647,9 @@ export default function TimelinePage() {
|
||||
</div>
|
||||
))}
|
||||
{migrations.length === 0 && (
|
||||
<p className="text-center text-muted-foreground py-10">
|
||||
暂无迁徙记录。
|
||||
<br />
|
||||
系统会自动分析父子代之间的籍贯/出生地差异来生成迁徙路径。
|
||||
</p>
|
||||
<div className="text-center py-16">
|
||||
<p className="text-sm text-foreground font-light tracking-wide">足迹未显</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</ScrollArea>
|
||||
@@ -665,11 +670,12 @@ export default function TimelinePage() {
|
||||
</div>
|
||||
</div>
|
||||
) : migrations.length === 0 ? (
|
||||
<div className="flex items-center justify-center h-full text-muted-foreground">
|
||||
<div className="text-center">
|
||||
<MapIcon className="h-16 w-16 mx-auto mb-4 opacity-20" />
|
||||
<p>暂无迁徙数据</p>
|
||||
<p className="text-sm mt-2">请先清空数据库重新加载数据</p>
|
||||
<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>
|
||||
) : (
|
||||
|
||||
+9
-2
@@ -16,7 +16,7 @@ import {
|
||||
} from "@/components/ui/dropdown-menu"
|
||||
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { ZoomIn, ZoomOut, Move, Download, LayoutGrid, ChevronDown, Users } from "lucide-react"
|
||||
import { ZoomIn, ZoomOut, Move, Download, LayoutGrid, ChevronDown, Users, Network } from "lucide-react"
|
||||
import { useState, useRef, useEffect, useCallback } from "react"
|
||||
import { useRouter, useSearchParams } from "next/navigation"
|
||||
|
||||
@@ -345,7 +345,14 @@ export default function TreePage() {
|
||||
return (
|
||||
<div className="min-h-screen bg-background flex flex-col">
|
||||
<SiteHeader />
|
||||
<div className="flex-1 flex items-center justify-center text-muted-foreground">暂无家族树数据</div>
|
||||
<div className="flex-1 flex items-center justify-center">
|
||||
<div className="text-center space-y-4">
|
||||
<div className="inline-flex items-center justify-center w-16 h-16 text-primary/80">
|
||||
<Network className="h-16 w-16" strokeWidth={1} />
|
||||
</div>
|
||||
<p className="text-base text-foreground font-light tracking-wide">谱系待续</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
+30
-46
@@ -83,51 +83,36 @@ export default function NewTreePage() {
|
||||
return (
|
||||
<div className="min-h-screen bg-background flex flex-col">
|
||||
<SiteHeader />
|
||||
<main className="container mx-auto py-8 px-4 md:px-6 flex-1">
|
||||
<main className="container mx-auto py-12 px-4 md:px-6 flex-1">
|
||||
<div className="max-w-2xl mx-auto">
|
||||
<div className="mb-6">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
asChild
|
||||
className="mb-4"
|
||||
>
|
||||
<Link href="/">
|
||||
<ArrowLeft className="h-4 w-4 mr-2" />
|
||||
返回首页
|
||||
</Link>
|
||||
</Button>
|
||||
<h1 className="text-3xl font-serif font-bold mb-2">创建新家族树</h1>
|
||||
<p className="text-muted-foreground">
|
||||
开始记录您的家族历史和传承
|
||||
<div className="mb-8 text-center">
|
||||
<h1 className="text-4xl font-serif font-light mb-3 tracking-wide">创建家族树</h1>
|
||||
<p className="text-muted-foreground font-light">
|
||||
记录家族历史,传承家族文化
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<Card>
|
||||
<Card className="border-none shadow-sm bg-card/50 backdrop-blur">
|
||||
<form onSubmit={handleSubmit}>
|
||||
<CardHeader>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex h-12 w-12 items-center justify-center rounded-lg bg-primary text-primary-foreground">
|
||||
<TreePine className="h-6 w-6" />
|
||||
</div>
|
||||
<div>
|
||||
<CardTitle>家族树信息</CardTitle>
|
||||
<CardDescription>
|
||||
填写基本信息以创建您的家族树
|
||||
</CardDescription>
|
||||
</div>
|
||||
<CardHeader className="text-center pb-8">
|
||||
<div className="inline-flex items-center justify-center w-16 h-16 rounded-full bg-primary/10 text-primary mb-4 mx-auto">
|
||||
<TreePine className="h-8 w-8" strokeWidth={1.5} />
|
||||
</div>
|
||||
<CardTitle className="text-2xl font-serif font-light">基本信息</CardTitle>
|
||||
<CardDescription className="font-light">
|
||||
填写家族树的名称和描述
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent className="space-y-6">
|
||||
<CardContent className="space-y-8 px-8">
|
||||
{error && (
|
||||
<Alert variant="destructive">
|
||||
<AlertDescription>{error}</AlertDescription>
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="name">
|
||||
<div className="space-y-3">
|
||||
<Label htmlFor="name" className="text-base font-normal">
|
||||
家族树名称 <span className="text-destructive">*</span>
|
||||
</Label>
|
||||
<Input
|
||||
@@ -137,14 +122,15 @@ export default function NewTreePage() {
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
maxLength={50}
|
||||
required
|
||||
className="h-12"
|
||||
/>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
<p className="text-xs text-muted-foreground font-light">
|
||||
建议使用姓氏+家族/宗谱等命名
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="description">家族树描述(可选)</Label>
|
||||
<div className="space-y-3">
|
||||
<Label htmlFor="description" className="text-base font-normal">家族树描述(可选)</Label>
|
||||
<Textarea
|
||||
id="description"
|
||||
placeholder="简要描述您的家族历史、祖籍地等信息"
|
||||
@@ -152,36 +138,34 @@ export default function NewTreePage() {
|
||||
onChange={(e) => setDescription(e.target.value)}
|
||||
rows={4}
|
||||
maxLength={500}
|
||||
className="resize-none"
|
||||
/>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
<p className="text-xs text-muted-foreground font-light">
|
||||
{description.length}/500 字
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="rounded-lg border bg-muted/50 p-4">
|
||||
<h3 className="font-medium mb-2">💡 温馨提示</h3>
|
||||
<ul className="text-sm text-muted-foreground space-y-1">
|
||||
<li>• 创建后可以随时修改家族树信息</li>
|
||||
<li>• 您可以邀请家族成员共同编辑</li>
|
||||
<li>• 支持导入已有的家族数据</li>
|
||||
</ul>
|
||||
<div className="rounded-lg bg-muted/30 p-6 space-y-2">
|
||||
<p className="text-sm text-muted-foreground font-light leading-relaxed">
|
||||
创建后可以随时修改信息、邀请家族成员协作编辑、导入已有数据
|
||||
</p>
|
||||
</div>
|
||||
</CardContent>
|
||||
|
||||
<CardFooter className="flex gap-3">
|
||||
<CardFooter className="flex gap-4 px-8 pt-8 pb-8">
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
onClick={() => router.back()}
|
||||
disabled={loading}
|
||||
className="flex-1"
|
||||
className="flex-1 h-12"
|
||||
>
|
||||
取消
|
||||
返回
|
||||
</Button>
|
||||
<Button
|
||||
type="submit"
|
||||
disabled={loading || !name.trim()}
|
||||
className="flex-1"
|
||||
className="flex-1 h-12 bg-primary text-primary-foreground hover:bg-primary/90"
|
||||
>
|
||||
{loading ? "创建中..." : "创建家族树"}
|
||||
</Button>
|
||||
|
||||
Reference in New Issue
Block a user