From a097d96380a9211e0867eb22aa9df8420b0d9b62 Mon Sep 17 00:00:00 2001 From: wjm Date: Wed, 18 Mar 2026 11:05:44 +0800 Subject: [PATCH] =?UTF-8?q?=E6=89=B9=E9=87=8F=E8=A1=A8=E6=93=8D=E4=BD=9C?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E6=B8=85=E7=A9=BA=E6=95=B0=E6=8D=AE.=20mysql?= =?UTF-8?q?=20/=20mongodb?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/Sidebar.tsx | 99 +++++++++++++++++++++++++++++ internal/app/methods_file.go | 53 +++++++++++++++ 2 files changed, 152 insertions(+) diff --git a/frontend/src/components/Sidebar.tsx b/frontend/src/components/Sidebar.tsx index 0ba9a08..f764beb 100644 --- a/frontend/src/components/Sidebar.tsx +++ b/frontend/src/components/Sidebar.tsx @@ -107,6 +107,7 @@ const Sidebar: React.FC<{ onEditConnection?: (conn: SavedConnection) => void }> const tableSortPreference = useStore(state => state.tableSortPreference); const recordTableAccess = useStore(state => state.recordTableAccess); const setTableSortPreference = useStore(state => state.setTableSortPreference); + const addSqlLog = useStore(state => state.addSqlLog); const darkMode = theme === 'dark'; const resolvedAppearance = resolveAppearanceValues(appearance); const opacity = normalizeOpacityForPlatform(resolvedAppearance.opacity); @@ -1809,6 +1810,95 @@ const Sidebar: React.FC<{ onEditConnection?: (conn: SavedConnection) => void }> } }; + const handleBatchClear = async () => { + const selectedObjects = batchTables.filter(t => checkedTableKeys.includes(t.key)); + if (selectedObjects.length === 0) { + message.warning('请至少选择一个对象'); + return; + } + + const { conn, dbName } = batchDbContext; + const objectNames = selectedObjects.map(t => t.objectName); + + const ok = await new Promise((resolve) => { + Modal.confirm({ + title: '确认清空选中表', + content: `清空选中表会永久删除表中所有数据,操作不可逆,是否继续?\r\n\r\n连接: ${conn.name}\n数据库: ${dbName}`, + okText: '继续', + cancelText: '取消', + onOk: () => resolve(true), + onCancel: () => resolve(false), + }); + }); + if (!ok) return; + + setIsBatchModalOpen(false); + const hide = message.loading(`正在清空选中表 (${objectNames.length})...`, 0); + const startTime = Date.now(); + try { + const app = (window as any).go.app.App; + const res = await app.TruncateTables(normalizeConnConfig(conn.config), dbName, objectNames); + const duration = Date.now() - startTime; + hide(); + if (res.success) { + message.success('清空成功'); + // 构造 SQL 日志 + let logSql = `/* Truncate Tables (${objectNames.length} tables) */\n`; + if (res.data && res.data.executedSQLs && Array.isArray(res.data.executedSQLs)) { + logSql += res.data.executedSQLs.join(';\n') + ';'; + } else { + logSql += objectNames.map(name => name).join('; '); + } + addSqlLog({ + id: Date.now().toString(), + timestamp: Date.now(), + sql: logSql, + status: 'success', + duration, + message: res.message, + dbName, + affectedRows: res.data?.count || 0 + }); + } else if (res.message !== 'Cancelled') { + message.error('清空失败: ' + res.message); + // 记录失败的日志 + const duration = Date.now() - startTime; + let logSql = `/* Truncate Tables (${objectNames.length} tables) - FAILED */\n`; + if (res.data && res.data.executedSQLs && Array.isArray(res.data.executedSQLs)) { + logSql += res.data.executedSQLs.join(';\n') + ';'; + } else { + logSql += objectNames.map(name => name).join('; '); + } + addSqlLog({ + id: Date.now().toString(), + timestamp: Date.now(), + sql: logSql, + status: 'error', + duration, + message: res.message, + dbName + }); + } + } catch (e: any) { + const duration = Date.now() - startTime; + hide(); + const errMsg = e?.message || String(e); + message.error('清空失败: ' + errMsg); + // 记录异常的日志 + let logSql = `/* Truncate Tables (${objectNames.length} tables) - ERROR */\n`; + logSql += objectNames.map(name => name).join('; '); + addSqlLog({ + id: Date.now().toString(), + timestamp: Date.now(), + sql: logSql, + status: 'error', + duration, + message: errMsg, + dbName + }); + } + }; + const handleCheckAll = (checked: boolean) => { if (batchSelectionScope === 'all') { setCheckedTableKeys(checked ? allBatchObjectKeys : []); @@ -3717,6 +3807,15 @@ const Sidebar: React.FC<{ onEditConnection?: (conn: SavedConnection) => void }> 取消 +