'use client'; import * as React from 'react'; import { useRef, useState } from 'react'; import { useTheme } from 'next-themes'; import CodeMirror from '@uiw/react-codemirror'; import { sql } from '@codemirror/lang-sql'; import { toast } from 'sonner'; import { ArrowLeft, Play, RefreshCw, Terminal, Trash2 } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@/components/ui/table'; import type { ExecuteSQLResponse } from '@/lib/services/db-manage'; import { DbManageService } from '@/lib/services/db-manage'; /** * 格式化表格单元格内容 */ 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 SQLConsoleProps { dbType?: string; // "postgres" | "sqlite" onClose: () => void; } export function SQLConsole({ dbType, onClose }: SQLConsoleProps) { // SQL 控制台状态 const [sqlQuery, setSqlQuery] = useState(''); const [executingSQL, setExecutingSQL] = useState(false); const [sqlResult, setSqlResult] = useState(null); const [sqlError, setSqlError] = useState(null); // 拖拽与主题状态 const containerRef = useRef(null); const [editorHeight, setEditorHeight] = useState(240); const { resolvedTheme } = useTheme(); const cmTheme = resolvedTheme === 'dark' ? 'dark' : 'light'; const handleMouseDown = (e: React.MouseEvent) => { e.preventDefault(); const startY = e.clientY; const startHeight = editorHeight; const handleMouseMove = (moveEvent: MouseEvent) => { if (!containerRef.current) return; const deltaY = moveEvent.clientY - startY; const containerHeight = containerRef.current.getBoundingClientRect().height; const newHeight = startHeight + deltaY; // Limit editor height between 80px and containerHeight - 80px if (newHeight > 80 && newHeight < containerHeight - 80) { setEditorHeight(newHeight); } }; const handleMouseUp = () => { document.removeEventListener('mousemove', handleMouseMove); document.removeEventListener('mouseup', handleMouseUp); }; document.addEventListener('mousemove', handleMouseMove); document.addEventListener('mouseup', handleMouseUp); }; // 执行 SQL 查询 const handleExecuteSQL = async () => { if (!sqlQuery.trim()) return; setExecutingSQL(true); setSqlResult(null); setSqlError(null); try { const result = await DbManageService.executeSQL(sqlQuery); setSqlResult(result); toast.success('SQL 执行成功'); } catch (err) { setSqlError(err instanceof Error ? err.message : '未知执行错误'); toast.error('SQL 执行失败'); } finally { setExecutingSQL(false); } }; // Preset SQL 选择器 const handlePresetSQLChange = (query: string) => { setSqlQuery(query); }; const handleClose = () => { setSqlResult(null); setSqlError(null); onClose(); }; return (
{/* 顶部控制与标题 */}

SQL 查询终端

{dbType === 'postgres' ? 'PostgreSQL Connected' : 'SQLite Connected'}
{/* 类似于 VS Code 的单个整体编辑器+结果区域,固定高度,有分水岭拖拽调整大小 */}
{/* 顶部编辑工具栏 */}
SQL 编辑器
{/* 快速模板 */}
快速模板:
{/* 控制按钮 */}
{/* 上半区:编辑器输入框 */}
setSqlQuery(value)} className='h-full text-xs font-mono' basicSetup={{ lineNumbers: true, foldGutter: true, dropCursor: true, allowMultipleSelections: false, indentOnInput: true, }} />
{/* 拖动分割线 */}
{/* 下半区:查看结果 (可滑动查看) */}
{/* 结果栏工具提示 */}
执行输出 {sqlResult && ( 类型: {sqlResult.type.toUpperCase()} | 耗时:{' '} {sqlResult.execution_time_ms} ms )}
{/* 滚动结果内容 */}
{executingSQL && (
正在在数据库执行查询,请稍候...
)} {sqlError && (

SQL 执行报错 (Error):

{sqlError}
)} {sqlResult && (
{sqlResult.type === 'select' && sqlResult.columns && sqlResult.columns.length > 0 && (
{sqlResult.columns.map((col) => ( {col} ))} {sqlResult.results && sqlResult.results.length > 0 ? ( sqlResult.results.map((row, rIndex) => ( {sqlResult.columns!.map((col) => ( {formatCellValue(row[col])} ))} )) ) : ( 查询结果为空 )}
)} {sqlResult.type === 'exec' && (

SQL 执行成功

受影响行数: {sqlResult.affected_rows} 行,耗时{' '} {sqlResult.execution_time_ms} 毫秒。

)}
)} {!executingSQL && !sqlResult && !sqlError && (
编辑器就绪,请在上方编写 SQL 并运行查看结果
)}
); }