'use client'; import * as React from 'react'; import { useCallback, useEffect, useState } from 'react'; import { toast } from 'sonner'; import { Layers, RefreshCw } from 'lucide-react'; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from '@/components/ui/card'; import { Skeleton } from '@/components/ui/skeleton'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@/components/ui/table'; import { Button } from '@/components/ui/button'; import type { TableDataResponse } from '@/lib/services/db-manage'; import { DbManageService } from '@/lib/services/db-manage'; /** * 格式化数字,每3位加逗号 */ const formatNumber = (num: number | string) => { if (num === undefined || num === null) return '0'; return num.toString().replace(/\B(?=(\d{3})+(?!\B))/g, ','); }; /** * 格式化表格单元格内容 */ const formatCellValue = (val: unknown): string => { if (val === null || val === undefined) return '-'; if (typeof val === 'boolean') return val ? 'true' : 'false'; if (typeof val === 'object') { try { return JSON.stringify(val); } catch { return '[Object]'; } } return String(val); }; interface TableBrowserProps { tables: string[]; loadingTables: boolean; refreshTrigger: number; } export function TableBrowser({ tables, loadingTables, refreshTrigger, }: TableBrowserProps) { const [selectedTable, setSelectedTable] = useState(''); const [tableData, setTableData] = useState(null); const [page, setPage] = useState(1); const [loadingData, setLoadingData] = useState(false); const pageSize = 10; // 获取具体表数据 const fetchTableData = useCallback( async (tableName: string, targetPage: number, size: number) => { if (!tableName) return; setLoadingData(true); try { const data = await DbManageService.getTableData({ table: tableName, page: targetPage, pageSize: size, }); setTableData(data); } catch (err) { toast.error(`获取数据表 ${tableName} 数据失败`, { description: err instanceof Error ? err.message : '未知错误', }); } finally { setLoadingData(false); } }, [], ); // 默认选择第一张表 useEffect(() => { if (tables.length > 0 && !selectedTable) { setSelectedTable(tables[0]); } }, [tables, selectedTable]); // 当选中的表、页码或外部刷新触发器改变时获取数据 useEffect(() => { if (selectedTable) { fetchTableData(selectedTable, page, pageSize); } }, [selectedTable, page, pageSize, refreshTrigger, fetchTableData]); // 处理页码改变 const handlePageChange = (newPage: number) => { setPage(newPage); }; // 处理表切换 const handleTableChange = (value: string) => { setSelectedTable(value); setPage(1); // 切换表重置为第一页 }; return (
数据表浏览器 浏览数据库中的物理数据表详情及内容
{loadingTables ? ( ) : ( )}
{loadingData && !tableData ? (
) : tableData && tableData.columns.length > 0 ? (
{/* 数据表格区域 */}
{loadingData && (
)} {tableData.columns.map((col) => ( {col} ))} {tableData.results && tableData.results.length > 0 ? ( tableData.results.map((row, rIndex) => ( {tableData.columns.map((col) => ( {formatCellValue(row[col])} ))} )) ) : ( 表中无记录数据 )}
{/* 分页控制 */}
总行数:{' '} {formatNumber(tableData.total)} {' '} 条记录
第 {page} /{' '} {Math.max(1, Math.ceil(tableData.total / pageSize))} 页
) : (
未选择数据表或表结构无法加载
)}
); }