2025-09-20 00:09:00 +08:00
|
|
|
|
import { useState, useEffect } from "react";
|
2025-10-24 18:34:55 +08:00
|
|
|
|
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card";
|
2025-09-20 00:09:00 +08:00
|
|
|
|
import { Button } from "@/components/ui/button";
|
|
|
|
|
|
import { Badge } from "@/components/ui/badge";
|
|
|
|
|
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
2025-10-24 18:34:55 +08:00
|
|
|
|
import { Alert, AlertDescription } from "@/components/ui/alert";
|
|
|
|
|
|
import { Progress } from "@/components/ui/progress";
|
2025-10-22 17:42:48 +08:00
|
|
|
|
import {
|
2025-10-24 18:34:55 +08:00
|
|
|
|
HardDrive,
|
|
|
|
|
|
RefreshCw,
|
|
|
|
|
|
Info,
|
|
|
|
|
|
CheckCircle2,
|
|
|
|
|
|
AlertCircle,
|
|
|
|
|
|
FolderOpen,
|
|
|
|
|
|
Clock,
|
|
|
|
|
|
AlertTriangle,
|
|
|
|
|
|
TrendingUp,
|
2025-10-26 13:38:17 +08:00
|
|
|
|
Package,
|
|
|
|
|
|
Settings
|
2025-09-20 00:09:00 +08:00
|
|
|
|
} from "lucide-react";
|
2025-11-26 21:11:12 +08:00
|
|
|
|
import { api, dbMode } from "@/shared/config/database";
|
2025-10-24 18:34:55 +08:00
|
|
|
|
import { DatabaseManager } from "@/components/database/DatabaseManager";
|
2025-10-26 13:38:17 +08:00
|
|
|
|
import { SystemConfig } from "@/components/system/SystemConfig";
|
2025-09-20 00:09:00 +08:00
|
|
|
|
import { toast } from "sonner";
|
|
|
|
|
|
|
|
|
|
|
|
export default function AdminDashboard() {
|
2025-10-24 18:34:55 +08:00
|
|
|
|
const [stats, setStats] = useState({
|
|
|
|
|
|
totalProjects: 0,
|
|
|
|
|
|
activeProjects: 0,
|
|
|
|
|
|
totalTasks: 0,
|
|
|
|
|
|
completedTasks: 0,
|
|
|
|
|
|
totalIssues: 0,
|
|
|
|
|
|
resolvedIssues: 0,
|
|
|
|
|
|
storageUsed: '计算中...',
|
|
|
|
|
|
storageQuota: '未知'
|
|
|
|
|
|
});
|
2025-09-20 00:09:00 +08:00
|
|
|
|
const [loading, setLoading] = useState(true);
|
2025-10-24 18:34:55 +08:00
|
|
|
|
const [storageDetails, setStorageDetails] = useState<{
|
|
|
|
|
|
usage: number;
|
|
|
|
|
|
quota: number;
|
|
|
|
|
|
percentage: number;
|
|
|
|
|
|
} | null>(null);
|
2025-09-20 00:09:00 +08:00
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
2025-10-24 18:34:55 +08:00
|
|
|
|
loadStats();
|
2025-09-20 00:09:00 +08:00
|
|
|
|
}, []);
|
|
|
|
|
|
|
2025-10-24 18:34:55 +08:00
|
|
|
|
const loadStats = async () => {
|
2025-09-20 00:09:00 +08:00
|
|
|
|
try {
|
|
|
|
|
|
setLoading(true);
|
2025-10-24 18:34:55 +08:00
|
|
|
|
const projectStats = await api.getProjectStats();
|
2025-09-20 00:09:00 +08:00
|
|
|
|
|
2025-10-24 18:34:55 +08:00
|
|
|
|
// 获取存储使用量(IndexedDB)
|
|
|
|
|
|
let storageUsed = '未知';
|
|
|
|
|
|
let storageQuota = '未知';
|
|
|
|
|
|
let details = null;
|
2025-09-20 00:09:00 +08:00
|
|
|
|
|
2025-10-24 18:34:55 +08:00
|
|
|
|
if ('storage' in navigator && 'estimate' in navigator.storage) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const estimate = await navigator.storage.estimate();
|
|
|
|
|
|
const usedMB = ((estimate.usage || 0) / 1024 / 1024).toFixed(2);
|
|
|
|
|
|
const quotaMB = ((estimate.quota || 0) / 1024 / 1024).toFixed(2);
|
|
|
|
|
|
const percentage = estimate.quota ? ((estimate.usage || 0) / estimate.quota * 100) : 0;
|
2025-09-20 00:09:00 +08:00
|
|
|
|
|
2025-10-24 18:34:55 +08:00
|
|
|
|
storageUsed = `${usedMB} MB`;
|
|
|
|
|
|
storageQuota = `${quotaMB} MB`;
|
2025-09-20 00:09:00 +08:00
|
|
|
|
|
2025-10-24 18:34:55 +08:00
|
|
|
|
details = {
|
|
|
|
|
|
usage: estimate.usage || 0,
|
|
|
|
|
|
quota: estimate.quota || 0,
|
|
|
|
|
|
percentage: Math.round(percentage)
|
|
|
|
|
|
};
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
console.error('Failed to estimate storage:', e);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-20 00:09:00 +08:00
|
|
|
|
|
2025-10-24 18:34:55 +08:00
|
|
|
|
setStats({
|
|
|
|
|
|
totalProjects: projectStats.total_projects || 0,
|
|
|
|
|
|
activeProjects: projectStats.active_projects || 0,
|
|
|
|
|
|
totalTasks: projectStats.total_tasks || 0,
|
|
|
|
|
|
completedTasks: projectStats.completed_tasks || 0,
|
|
|
|
|
|
totalIssues: projectStats.total_issues || 0,
|
|
|
|
|
|
resolvedIssues: projectStats.resolved_issues || 0,
|
|
|
|
|
|
storageUsed,
|
|
|
|
|
|
storageQuota
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
setStorageDetails(details);
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('Failed to load stats:', error);
|
|
|
|
|
|
toast.error("加载统计数据失败");
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
setLoading(false);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
2025-09-20 00:09:00 +08:00
|
|
|
|
|
|
|
|
|
|
if (loading) {
|
|
|
|
|
|
return (
|
|
|
|
|
|
<div className="flex items-center justify-center min-h-screen">
|
2025-10-24 18:34:55 +08:00
|
|
|
|
<div className="space-y-4 text-center">
|
|
|
|
|
|
<div className="animate-spin rounded-full h-16 w-16 border-b-2 border-primary mx-auto"></div>
|
|
|
|
|
|
<p className="text-muted-foreground">加载数据库信息...</p>
|
|
|
|
|
|
</div>
|
2025-09-20 00:09:00 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
2025-10-24 18:34:55 +08:00
|
|
|
|
<div className="space-y-6 pb-8">
|
2025-09-20 00:09:00 +08:00
|
|
|
|
{/* 页面标题 */}
|
|
|
|
|
|
<div className="flex items-center justify-between">
|
|
|
|
|
|
<div>
|
2025-10-24 18:34:55 +08:00
|
|
|
|
<h1 className="text-3xl font-bold text-gray-900 flex items-center gap-3">
|
2025-10-26 13:38:17 +08:00
|
|
|
|
<Settings className="h-8 w-8 text-primary" />
|
|
|
|
|
|
系统管理
|
2025-10-24 18:34:55 +08:00
|
|
|
|
</h1>
|
2025-09-20 00:09:00 +08:00
|
|
|
|
<p className="text-gray-600 mt-2">
|
2025-10-26 13:38:17 +08:00
|
|
|
|
管理系统配置、LLM设置、数据库和存储使用情况
|
2025-09-20 00:09:00 +08:00
|
|
|
|
</p>
|
|
|
|
|
|
</div>
|
2025-10-24 18:34:55 +08:00
|
|
|
|
<Button variant="outline" onClick={loadStats}>
|
|
|
|
|
|
<RefreshCw className="w-4 h-4 mr-2" />
|
|
|
|
|
|
刷新数据
|
|
|
|
|
|
</Button>
|
2025-09-20 00:09:00 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
|
2025-10-24 18:34:55 +08:00
|
|
|
|
{/* 主要内容标签页 */}
|
2025-10-26 13:38:17 +08:00
|
|
|
|
<Tabs defaultValue="config" className="w-full">
|
|
|
|
|
|
<TabsList className="grid w-full grid-cols-5">
|
|
|
|
|
|
<TabsTrigger value="config">系统配置</TabsTrigger>
|
2025-10-24 18:34:55 +08:00
|
|
|
|
<TabsTrigger value="overview">数据概览</TabsTrigger>
|
|
|
|
|
|
<TabsTrigger value="storage">存储管理</TabsTrigger>
|
|
|
|
|
|
<TabsTrigger value="operations">数据操作</TabsTrigger>
|
2025-10-26 13:38:17 +08:00
|
|
|
|
<TabsTrigger value="settings">高级设置</TabsTrigger>
|
2025-09-20 00:09:00 +08:00
|
|
|
|
</TabsList>
|
|
|
|
|
|
|
2025-10-26 13:38:17 +08:00
|
|
|
|
{/* 系统配置 */}
|
|
|
|
|
|
<TabsContent value="config" className="space-y-6">
|
|
|
|
|
|
<SystemConfig />
|
|
|
|
|
|
</TabsContent>
|
|
|
|
|
|
|
2025-10-24 18:34:55 +08:00
|
|
|
|
{/* 数据概览 */}
|
|
|
|
|
|
<TabsContent value="overview" className="space-y-6">
|
|
|
|
|
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
|
|
|
|
|
{/* 任务完成率 */}
|
2025-09-20 00:09:00 +08:00
|
|
|
|
<Card>
|
|
|
|
|
|
<CardHeader>
|
2025-10-24 18:34:55 +08:00
|
|
|
|
<CardTitle className="flex items-center gap-2">
|
|
|
|
|
|
<TrendingUp className="h-5 w-5" />
|
|
|
|
|
|
任务完成率
|
2025-09-20 00:09:00 +08:00
|
|
|
|
</CardTitle>
|
2025-10-24 18:34:55 +08:00
|
|
|
|
<CardDescription>审计任务的完成情况统计</CardDescription>
|
2025-09-20 00:09:00 +08:00
|
|
|
|
</CardHeader>
|
|
|
|
|
|
<CardContent className="space-y-4">
|
2025-10-24 18:34:55 +08:00
|
|
|
|
<div className="space-y-2">
|
|
|
|
|
|
<div className="flex items-center justify-between text-sm">
|
|
|
|
|
|
<span>已完成</span>
|
|
|
|
|
|
<span className="font-medium">
|
|
|
|
|
|
{stats.totalTasks > 0
|
|
|
|
|
|
? Math.round((stats.completedTasks / stats.totalTasks) * 100)
|
|
|
|
|
|
: 0}%
|
|
|
|
|
|
</span>
|
2025-09-20 00:09:00 +08:00
|
|
|
|
</div>
|
2025-10-24 18:34:55 +08:00
|
|
|
|
<Progress
|
|
|
|
|
|
value={stats.totalTasks > 0
|
|
|
|
|
|
? (stats.completedTasks / stats.totalTasks) * 100
|
|
|
|
|
|
: 0
|
|
|
|
|
|
}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div className="grid grid-cols-2 gap-4 pt-4">
|
|
|
|
|
|
<div className="space-y-1">
|
|
|
|
|
|
<p className="text-sm text-muted-foreground">总任务数</p>
|
|
|
|
|
|
<p className="text-2xl font-bold">{stats.totalTasks}</p>
|
2025-09-20 00:09:00 +08:00
|
|
|
|
</div>
|
2025-10-24 18:34:55 +08:00
|
|
|
|
<div className="space-y-1">
|
|
|
|
|
|
<p className="text-sm text-muted-foreground">已完成</p>
|
|
|
|
|
|
<p className="text-2xl font-bold text-green-600">{stats.completedTasks}</p>
|
2025-09-20 00:09:00 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</CardContent>
|
|
|
|
|
|
</Card>
|
|
|
|
|
|
|
2025-10-24 18:34:55 +08:00
|
|
|
|
{/* 问题解决率 */}
|
2025-09-20 00:09:00 +08:00
|
|
|
|
<Card>
|
|
|
|
|
|
<CardHeader>
|
2025-10-24 18:34:55 +08:00
|
|
|
|
<CardTitle className="flex items-center gap-2">
|
|
|
|
|
|
<CheckCircle2 className="h-5 w-5" />
|
|
|
|
|
|
问题解决率
|
2025-09-20 00:09:00 +08:00
|
|
|
|
</CardTitle>
|
2025-10-24 18:34:55 +08:00
|
|
|
|
<CardDescription>代码问题的解决情况统计</CardDescription>
|
2025-09-20 00:09:00 +08:00
|
|
|
|
</CardHeader>
|
|
|
|
|
|
<CardContent className="space-y-4">
|
2025-10-24 18:34:55 +08:00
|
|
|
|
<div className="space-y-2">
|
|
|
|
|
|
<div className="flex items-center justify-between text-sm">
|
|
|
|
|
|
<span>已解决</span>
|
|
|
|
|
|
<span className="font-medium">
|
|
|
|
|
|
{stats.totalIssues > 0
|
|
|
|
|
|
? Math.round((stats.resolvedIssues / stats.totalIssues) * 100)
|
|
|
|
|
|
: 0}%
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<Progress
|
|
|
|
|
|
value={stats.totalIssues > 0
|
|
|
|
|
|
? (stats.resolvedIssues / stats.totalIssues) * 100
|
|
|
|
|
|
: 0
|
|
|
|
|
|
}
|
|
|
|
|
|
className="bg-orange-100"
|
|
|
|
|
|
/>
|
2025-09-20 00:09:00 +08:00
|
|
|
|
</div>
|
2025-10-24 18:34:55 +08:00
|
|
|
|
<div className="grid grid-cols-2 gap-4 pt-4">
|
|
|
|
|
|
<div className="space-y-1">
|
|
|
|
|
|
<p className="text-sm text-muted-foreground">总问题数</p>
|
|
|
|
|
|
<p className="text-2xl font-bold">{stats.totalIssues}</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div className="space-y-1">
|
|
|
|
|
|
<p className="text-sm text-muted-foreground">已解决</p>
|
|
|
|
|
|
<p className="text-2xl font-bold text-green-600">{stats.resolvedIssues}</p>
|
|
|
|
|
|
</div>
|
2025-09-20 00:09:00 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</CardContent>
|
|
|
|
|
|
</Card>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
2025-10-24 18:34:55 +08:00
|
|
|
|
{/* 数据库表统计 */}
|
2025-09-20 00:09:00 +08:00
|
|
|
|
<Card>
|
|
|
|
|
|
<CardHeader>
|
2025-10-24 18:34:55 +08:00
|
|
|
|
<CardTitle className="flex items-center gap-2">
|
|
|
|
|
|
<Package className="h-5 w-5" />
|
|
|
|
|
|
数据库表统计
|
|
|
|
|
|
</CardTitle>
|
|
|
|
|
|
<CardDescription>各数据表的记录数量</CardDescription>
|
2025-09-20 00:09:00 +08:00
|
|
|
|
</CardHeader>
|
|
|
|
|
|
<CardContent>
|
2025-10-24 18:34:55 +08:00
|
|
|
|
<div className="grid grid-cols-2 md:grid-cols-3 gap-4">
|
|
|
|
|
|
<div className="p-4 border rounded-lg">
|
|
|
|
|
|
<div className="flex items-center gap-3">
|
|
|
|
|
|
<FolderOpen className="h-8 w-8 text-primary" />
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<p className="text-sm text-muted-foreground">项目</p>
|
|
|
|
|
|
<p className="text-2xl font-bold">{stats.totalProjects}</p>
|
|
|
|
|
|
</div>
|
2025-09-20 00:09:00 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2025-10-24 18:34:55 +08:00
|
|
|
|
<div className="p-4 border rounded-lg">
|
|
|
|
|
|
<div className="flex items-center gap-3">
|
|
|
|
|
|
<Clock className="h-8 w-8 text-green-600" />
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<p className="text-sm text-muted-foreground">审计任务</p>
|
|
|
|
|
|
<p className="text-2xl font-bold">{stats.totalTasks}</p>
|
|
|
|
|
|
</div>
|
2025-09-20 00:09:00 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2025-10-24 18:34:55 +08:00
|
|
|
|
<div className="p-4 border rounded-lg">
|
|
|
|
|
|
<div className="flex items-center gap-3">
|
|
|
|
|
|
<AlertTriangle className="h-8 w-8 text-orange-600" />
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<p className="text-sm text-muted-foreground">问题</p>
|
|
|
|
|
|
<p className="text-2xl font-bold">{stats.totalIssues}</p>
|
|
|
|
|
|
</div>
|
2025-09-20 00:09:00 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</CardContent>
|
|
|
|
|
|
</Card>
|
|
|
|
|
|
</TabsContent>
|
|
|
|
|
|
|
2025-10-24 18:34:55 +08:00
|
|
|
|
{/* 存储管理 */}
|
|
|
|
|
|
<TabsContent value="storage" className="space-y-6">
|
|
|
|
|
|
<Card>
|
|
|
|
|
|
<CardHeader>
|
|
|
|
|
|
<CardTitle className="flex items-center gap-2">
|
|
|
|
|
|
<HardDrive className="h-5 w-5" />
|
|
|
|
|
|
存储空间使用情况
|
|
|
|
|
|
</CardTitle>
|
|
|
|
|
|
<CardDescription>
|
|
|
|
|
|
浏览器 IndexedDB 存储空间的使用详情
|
|
|
|
|
|
</CardDescription>
|
|
|
|
|
|
</CardHeader>
|
|
|
|
|
|
<CardContent className="space-y-6">
|
|
|
|
|
|
{storageDetails ? (
|
|
|
|
|
|
<>
|
|
|
|
|
|
<div className="space-y-2">
|
|
|
|
|
|
<div className="flex items-center justify-between text-sm">
|
|
|
|
|
|
<span>已使用空间</span>
|
|
|
|
|
|
<span className="font-medium">{storageDetails.percentage}%</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<Progress value={storageDetails.percentage} />
|
|
|
|
|
|
<div className="flex items-center justify-between text-xs text-muted-foreground">
|
|
|
|
|
|
<span>{stats.storageUsed} 已使用</span>
|
|
|
|
|
|
<span>{stats.storageQuota} 总配额</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 pt-4">
|
|
|
|
|
|
<div className="p-4 bg-muted rounded-lg">
|
|
|
|
|
|
<p className="text-sm text-muted-foreground mb-1">已使用</p>
|
|
|
|
|
|
<p className="text-xl font-bold">{stats.storageUsed}</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div className="p-4 bg-muted rounded-lg">
|
|
|
|
|
|
<p className="text-sm text-muted-foreground mb-1">总配额</p>
|
|
|
|
|
|
<p className="text-xl font-bold">{stats.storageQuota}</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div className="p-4 bg-muted rounded-lg">
|
|
|
|
|
|
<p className="text-sm text-muted-foreground mb-1">剩余空间</p>
|
|
|
|
|
|
<p className="text-xl font-bold">
|
|
|
|
|
|
{((storageDetails.quota - storageDetails.usage) / 1024 / 1024).toFixed(2)} MB
|
|
|
|
|
|
</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
{storageDetails.percentage > 80 && (
|
|
|
|
|
|
<Alert variant="destructive">
|
|
|
|
|
|
<AlertCircle className="h-4 w-4" />
|
|
|
|
|
|
<AlertDescription>
|
|
|
|
|
|
存储空间使用率已超过 80%,建议清理不需要的数据或导出备份后清空数据库。
|
|
|
|
|
|
</AlertDescription>
|
|
|
|
|
|
</Alert>
|
|
|
|
|
|
)}
|
|
|
|
|
|
</>
|
|
|
|
|
|
) : (
|
|
|
|
|
|
<Alert>
|
|
|
|
|
|
<Info className="h-4 w-4" />
|
|
|
|
|
|
<AlertDescription>
|
|
|
|
|
|
无法获取存储空间信息。您的浏览器可能不支持 Storage API。
|
|
|
|
|
|
</AlertDescription>
|
|
|
|
|
|
</Alert>
|
|
|
|
|
|
)}
|
|
|
|
|
|
</CardContent>
|
|
|
|
|
|
</Card>
|
|
|
|
|
|
|
|
|
|
|
|
<Card>
|
|
|
|
|
|
<CardHeader>
|
|
|
|
|
|
<CardTitle>存储优化建议</CardTitle>
|
|
|
|
|
|
</CardHeader>
|
|
|
|
|
|
<CardContent className="space-y-3">
|
|
|
|
|
|
<div className="flex items-start gap-3 p-3 bg-muted rounded-lg">
|
|
|
|
|
|
<CheckCircle2 className="h-5 w-5 text-green-600 mt-0.5" />
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<p className="font-medium">定期导出备份</p>
|
|
|
|
|
|
<p className="text-sm text-muted-foreground">
|
|
|
|
|
|
建议定期导出数据为 JSON 文件,防止数据丢失
|
|
|
|
|
|
</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div className="flex items-start gap-3 p-3 bg-muted rounded-lg">
|
|
|
|
|
|
<CheckCircle2 className="h-5 w-5 text-green-600 mt-0.5" />
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<p className="font-medium">清理旧数据</p>
|
|
|
|
|
|
<p className="text-sm text-muted-foreground">
|
|
|
|
|
|
删除不再需要的项目和任务可以释放存储空间
|
|
|
|
|
|
</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div className="flex items-start gap-3 p-3 bg-muted rounded-lg">
|
|
|
|
|
|
<CheckCircle2 className="h-5 w-5 text-green-600 mt-0.5" />
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<p className="font-medium">监控存储使用</p>
|
|
|
|
|
|
<p className="text-sm text-muted-foreground">
|
|
|
|
|
|
定期检查存储使用情况,避免超出浏览器限制
|
|
|
|
|
|
</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</CardContent>
|
|
|
|
|
|
</Card>
|
2025-09-20 00:09:00 +08:00
|
|
|
|
</TabsContent>
|
|
|
|
|
|
|
2025-10-24 18:34:55 +08:00
|
|
|
|
{/* 数据操作 */}
|
|
|
|
|
|
<TabsContent value="operations" className="space-y-6">
|
|
|
|
|
|
<DatabaseManager />
|
|
|
|
|
|
</TabsContent>
|
|
|
|
|
|
|
|
|
|
|
|
{/* 设置 */}
|
|
|
|
|
|
<TabsContent value="settings" className="space-y-6">
|
|
|
|
|
|
<Card>
|
|
|
|
|
|
<CardHeader>
|
|
|
|
|
|
<CardTitle>数据库设置</CardTitle>
|
|
|
|
|
|
<CardDescription>配置数据库行为和性能选项</CardDescription>
|
|
|
|
|
|
</CardHeader>
|
|
|
|
|
|
<CardContent className="space-y-4">
|
|
|
|
|
|
<Alert>
|
|
|
|
|
|
<Info className="h-4 w-4" />
|
|
|
|
|
|
<AlertDescription>
|
2025-11-26 21:11:12 +08:00
|
|
|
|
<strong>当前数据库模式:</strong> {
|
|
|
|
|
|
dbMode === 'api' ? '后端 PostgreSQL 数据库' :
|
2025-11-27 18:01:57 +08:00
|
|
|
|
dbMode === 'local' ? '本地 IndexedDB' :
|
|
|
|
|
|
dbMode === 'supabase' ? 'Supabase 云端(已废弃)' :
|
|
|
|
|
|
'演示模式'
|
2025-11-26 21:11:12 +08:00
|
|
|
|
}
|
2025-10-24 18:34:55 +08:00
|
|
|
|
</AlertDescription>
|
|
|
|
|
|
</Alert>
|
|
|
|
|
|
|
|
|
|
|
|
<div className="space-y-4 pt-4">
|
|
|
|
|
|
<div className="flex items-center justify-between p-4 border rounded-lg">
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<p className="font-medium">自动备份</p>
|
|
|
|
|
|
<p className="text-sm text-muted-foreground">
|
|
|
|
|
|
定期自动导出数据备份(开发中)
|
|
|
|
|
|
</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<Badge variant="outline">即将推出</Badge>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div className="flex items-center justify-between p-4 border rounded-lg">
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<p className="font-medium">数据压缩</p>
|
|
|
|
|
|
<p className="text-sm text-muted-foreground">
|
|
|
|
|
|
压缩存储数据以节省空间(开发中)
|
|
|
|
|
|
</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<Badge variant="outline">即将推出</Badge>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div className="flex items-center justify-between p-4 border rounded-lg">
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<p className="font-medium">数据同步</p>
|
|
|
|
|
|
<p className="text-sm text-muted-foreground">
|
|
|
|
|
|
在多个设备间同步数据(开发中)
|
|
|
|
|
|
</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<Badge variant="outline">即将推出</Badge>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</CardContent>
|
|
|
|
|
|
</Card>
|
|
|
|
|
|
|
|
|
|
|
|
<Card>
|
|
|
|
|
|
<CardHeader>
|
|
|
|
|
|
<CardTitle>关于本地数据库</CardTitle>
|
|
|
|
|
|
</CardHeader>
|
|
|
|
|
|
<CardContent className="space-y-3 text-sm text-muted-foreground">
|
|
|
|
|
|
<p>
|
|
|
|
|
|
本地数据库使用浏览器的 IndexedDB 技术存储数据,具有以下特点:
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<ul className="list-disc list-inside space-y-2 ml-2">
|
|
|
|
|
|
<li>数据完全存储在本地,不会上传到服务器</li>
|
|
|
|
|
|
<li>支持离线访问,无需网络连接</li>
|
|
|
|
|
|
<li>存储容量取决于浏览器和设备</li>
|
|
|
|
|
|
<li>清除浏览器数据会删除所有本地数据</li>
|
|
|
|
|
|
<li>不同浏览器的数据相互独立</li>
|
|
|
|
|
|
</ul>
|
|
|
|
|
|
<p className="pt-2">
|
|
|
|
|
|
<strong>建议:</strong>定期导出数据备份,以防意外数据丢失。
|
|
|
|
|
|
</p>
|
|
|
|
|
|
</CardContent>
|
|
|
|
|
|
</Card>
|
2025-09-20 00:09:00 +08:00
|
|
|
|
</TabsContent>
|
|
|
|
|
|
</Tabs>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
);
|
2025-10-24 18:34:55 +08:00
|
|
|
|
}
|