"use client" import dynamic from "next/dynamic" import * as React from "react" import {useCallback, useEffect, useState} from "react" import {toast} from "sonner" import { Activity, Cpu, Database, Download, FileText, HardDrive, Layers, RefreshCw, Server, Terminal, } from "lucide-react" import {Card, CardContent, CardDescription, CardHeader, CardTitle} from "@/components/ui/card" import {Button} from "@/components/ui/button" import {Skeleton} from "@/components/ui/skeleton" import services from "@/lib/services" import type {DBOverview} from "@/lib/services/db-manage" const sectionFallback = (
) const TableBrowser = dynamic( () => import("./components/table-browser").then((mod) => mod.TableBrowser), { loading: () => sectionFallback }, ) const CacheManager = dynamic( () => import("./components/cache-manager").then((mod) => mod.CacheManager), { loading: () => sectionFallback }, ) const SQLConsole = dynamic( () => import("./components/sql-console").then((mod) => mod.SQLConsole), { ssr: false }, ) /** * 格式化数字,每3位加逗号 */ const formatNumber = (num: number | string) => { if (num === undefined || num === null) return "0" return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") } export function DatabasePageClient() { // 核心状态 const [overview, setOverview] = useState(null) const [tables, setTables] = useState([]) const [loadingOverview, setLoadingOverview] = useState(true) const [loadingTables, setLoadingTables] = useState(true) const [exporting, setExporting] = useState(false) // 协调子组件刷新与视图切换状态 const [showConsole, setShowConsole] = useState(false) const [refreshTrigger, setRefreshTrigger] = useState(0) // 1. 获取运行概览 const fetchOverview = useCallback(async (isSilent = false) => { if (!isSilent) setLoadingOverview(true) try { const data = await services.dbManage.getOverview() setOverview(data) } catch (err) { toast.error("获取数据库概览失败", { description: err instanceof Error ? err.message : "未知错误", }) } finally { setLoadingOverview(false) } }, []) // 2. 获取表列表 const fetchTables = useCallback(async () => { setLoadingTables(true) try { const data = await services.dbManage.listTables() setTables(data) } catch (err) { toast.error("获取数据库数据表列表失败", { description: err instanceof Error ? err.message : "未知错误", }) } finally { setLoadingTables(false) } }, []) // 3. 协调刷新 const handleRefreshAll = () => { fetchOverview() fetchTables() setRefreshTrigger((prev) => prev + 1) } // 4. 导出数据库备份 const handleExport = async () => { setExporting(true) try { const { blob, filename } = await services.dbManage.exportDatabase() const url = URL.createObjectURL(blob) const a = document.createElement("a") a.href = url a.download = filename document.body.appendChild(a) a.click() a.remove() URL.revokeObjectURL(url) toast.success("数据库导出成功", { description: `已下载归档文件: ${filename}` }) } catch (err) { toast.error("数据库导出失败", { description: err instanceof Error ? err.message : "导出异常", }) } finally { setExporting(false) } } // 初始化加载 useEffect(() => { fetchOverview() fetchTables() }, [fetchOverview, fetchTables]) // 渲染概览卡片骨架 const renderOverviewSkeleton = () => (
{Array.from({ length: 6 }).map((_, i) => ( ))}
) // 渲染 SQL 查询控台全屏视图 if (showConsole) { return ( setShowConsole(false)} /> ) } // 正常页面排版布局 return (
{/* 顶部控制与标题 */}

数据管理

{/* 1. 概览指标卡片组 */} {loadingOverview ? ( renderOverviewSkeleton() ) : ( overview && (
{/* 卡片1: 数据库类型 */} 数据库类型
{overview.type}
{/* 卡片2: 数据库版本 */} 版本信息
{overview.version.split(" ").slice(0, 2).join(" ")}
{/* 卡片3: 数据库名称 */} 名称/路径
{overview.name.substring(overview.name.lastIndexOf("/") + 1)}
{/* 卡片4: 数据库大小 */} 数据库大小
{overview.size}
{/* 卡片5: 表数量 */} 物理数据表
{formatNumber(overview.table_count)}
{/* 卡片6: 连接数 */} 活跃连接数
{formatNumber(overview.connections)}
) )} {/* 2. 数据表浏览器区块 */} {/* 3. 缓存管理区块 */} {/* 4. 底部功能卡片区 */} 功能区 数据库导出及自定义高级 SQL 执行终端
{/* 功能一: 数据库导出 */}

数据库备份导出

直接导出并下载物理数据库镜像文件(SQLite 导出 .db,PostgreSQL 导出为打包的 .sql 文本文件)

{/* 功能二: SQL 查询终端 */}

SQL 查询控台

打开在线 SQL 控制终端,执行原生的 SQL 进行数据筛选、更新、调试或性能优化

) }