0.0.8.0
This commit is contained in:
+47
-35
@@ -14,6 +14,7 @@ import { useSession } from "next-auth/react"
|
||||
import { Avatar, AvatarFallback } from "@/components/ui/avatar"
|
||||
import { ChangePassword } from "@/components/settings/change-password"
|
||||
import { useDialog } from "@/components/ui/alert-dialog-custom"
|
||||
import { permissions } from "@/lib/permissions"
|
||||
|
||||
interface UserProfile {
|
||||
id: string
|
||||
@@ -30,7 +31,8 @@ interface UserProfile {
|
||||
}
|
||||
|
||||
export default function SettingsPage() {
|
||||
const { treeData, loadData, resetData } = useFamily()
|
||||
const { treeData, currentTree, loadData, resetData } = useFamily()
|
||||
const role = currentTree?.currentUserRole
|
||||
const { data: session } = useSession()
|
||||
const { showAlert, showConfirm } = useDialog()
|
||||
const [importStatus, setImportStatus] = useState<string>("")
|
||||
@@ -147,7 +149,8 @@ export default function SettingsPage() {
|
||||
<p className="text-sm font-medium text-destructive mb-2 flex items-center gap-2">
|
||||
<AlertTriangle className="h-4 w-4" /> 危险区域
|
||||
</p>
|
||||
<Button
|
||||
{permissions.canClearData(role) && (
|
||||
<Button
|
||||
variant="destructive"
|
||||
size="sm"
|
||||
className="w-full"
|
||||
@@ -157,10 +160,11 @@ export default function SettingsPage() {
|
||||
await resetData()
|
||||
await showAlert("数据已重置为演示状态。", "成功")
|
||||
}
|
||||
}}
|
||||
>
|
||||
重置所有数据
|
||||
</Button>
|
||||
}}
|
||||
>
|
||||
重置所有数据
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
@@ -185,8 +189,9 @@ export default function SettingsPage() {
|
||||
<Download className="h-4 w-4" /> 数据备份
|
||||
</h3>
|
||||
<p className="text-sm text-muted-foreground">将家族数据导出为 JSON 文件进行本地保存。</p>
|
||||
<Button
|
||||
onClick={() => {
|
||||
{permissions.canExport(role) && (
|
||||
<Button
|
||||
onClick={() => {
|
||||
const dataStr = JSON.stringify(treeData, null, 2)
|
||||
const blob = new Blob([dataStr], { type: "application/json" })
|
||||
const url = URL.createObjectURL(blob)
|
||||
@@ -196,10 +201,11 @@ export default function SettingsPage() {
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
document.body.removeChild(link)
|
||||
}}
|
||||
>
|
||||
导出数据 (Export JSON)
|
||||
</Button>
|
||||
}}
|
||||
>
|
||||
导出数据 (Export JSON)
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="border-t" />
|
||||
@@ -213,8 +219,9 @@ export default function SettingsPage() {
|
||||
<p className="text-sm text-muted-foreground mt-1">从 JSON 备份文件恢复数据。这将覆盖当前数据。</p>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-4">
|
||||
<input
|
||||
{permissions.canImport(role) && (
|
||||
<div className="flex items-center gap-4">
|
||||
<input
|
||||
type="file"
|
||||
ref={fileInputRef}
|
||||
className="hidden"
|
||||
@@ -244,12 +251,13 @@ export default function SettingsPage() {
|
||||
}
|
||||
reader.readAsText(file)
|
||||
}}
|
||||
/>
|
||||
<Button variant="outline" onClick={() => fileInputRef.current?.click()}>
|
||||
选择备份文件...
|
||||
</Button>
|
||||
<span className="text-sm text-muted-foreground">{importStatus}</span>
|
||||
</div>
|
||||
/>
|
||||
<Button variant="outline" onClick={() => fileInputRef.current?.click()}>
|
||||
选择备份文件...
|
||||
</Button>
|
||||
<span className="text-sm text-muted-foreground">{importStatus}</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
@@ -263,10 +271,11 @@ export default function SettingsPage() {
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<div className="flex flex-col gap-4">
|
||||
<Button
|
||||
variant="outline"
|
||||
className="justify-start"
|
||||
onClick={() => {
|
||||
{permissions.canExport(role) && (
|
||||
<Button
|
||||
variant="outline"
|
||||
className="justify-start"
|
||||
onClick={() => {
|
||||
const gedcomText = exportToGedcom(treeData)
|
||||
const blob = new Blob([gedcomText], { type: "text/plain;charset=utf-8" })
|
||||
const url = URL.createObjectURL(blob)
|
||||
@@ -275,14 +284,16 @@ export default function SettingsPage() {
|
||||
link.download = `family_tree_${new Date().toISOString().split("T")[0]}.ged`
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
document.body.removeChild(link)
|
||||
}}
|
||||
>
|
||||
<Download className="mr-2 h-4 w-4" />
|
||||
导出 GEDCOM
|
||||
</Button>
|
||||
document.body.removeChild(link)
|
||||
}}
|
||||
>
|
||||
<Download className="mr-2 h-4 w-4" />
|
||||
导出 GEDCOM
|
||||
</Button>
|
||||
)}
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
{permissions.canImport(role) && (
|
||||
<div className="flex items-center gap-2">
|
||||
<input
|
||||
type="file"
|
||||
ref={gedcomInputRef}
|
||||
@@ -310,10 +321,11 @@ export default function SettingsPage() {
|
||||
/>
|
||||
<Button variant="outline" className="justify-start" onClick={() => gedcomInputRef.current?.click()}>
|
||||
<Upload className="mr-2 h-4 w-4" />
|
||||
导入 GEDCOM
|
||||
</Button>
|
||||
{gedcomStatus && <span className="text-sm text-muted-foreground">{gedcomStatus}</span>}
|
||||
</div>
|
||||
导入 GEDCOM
|
||||
</Button>
|
||||
{gedcomStatus && <span className="text-sm text-muted-foreground">{gedcomStatus}</span>}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
Reference in New Issue
Block a user