From 8d7e7a6ddf00f3b5ef4b211028a868740ee96cfd Mon Sep 17 00:00:00 2001 From: Syngnat Date: Thu, 9 Jul 2026 15:37:27 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat(query-editor):=20=E7=BB=93?= =?UTF-8?q?=E6=9E=9C=E9=A1=B5=E5=88=97=E5=85=83=E6=95=B0=E6=8D=AE=E8=B7=A8?= =?UTF-8?q?=E5=BA=93=E5=8A=A0=E8=BD=BD=E5=B9=B6=E5=AE=9E=E5=BF=83=E5=8C=96?= =?UTF-8?q?=E4=BF=9D=E5=AD=98=E6=8C=89=E9=92=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 结果集携带 metadataDbName/TableName,列类型注释从真实库表加载 - 只读查询也解析 tableRef,避免结果页丢元数据 - 选择列底色与固定列对齐;保存按钮改为蓝色实心主按钮样式 - 独立结果窗/还原路径同步元数据字段 --- .../components/FloatingQueryResultWindows.tsx | 4 +- frontend/src/components/QueryEditor.tsx | 12 +++++- .../components/QueryEditorResultsPanel.tsx | 8 +++- .../src/components/QueryEditorToolbar.tsx | 7 +++- .../queryEditor/QueryEditorHelpers.ts | 17 ++++++-- frontend/src/utils/detachedWindow.ts | 3 ++ frontend/src/v2-theme.css | 41 ++++++++++++++++++- 7 files changed, 79 insertions(+), 13 deletions(-) diff --git a/frontend/src/components/FloatingQueryResultWindows.tsx b/frontend/src/components/FloatingQueryResultWindows.tsx index 6087f329..b95ae29b 100644 --- a/frontend/src/components/FloatingQueryResultWindows.tsx +++ b/frontend/src/components/FloatingQueryResultWindows.tsx @@ -290,12 +290,12 @@ const FloatingQueryResultWindows: React.FC = () => { data={windowState.result.rows || []} columnNames={windowState.result.columns || []} loading={false} - tableName={windowState.result.tableName} + tableName={windowState.result.metadataTableName || windowState.result.tableName} pkColumns={windowState.result.pkColumns || []} editLocator={windowState.result.editLocator as any} readOnly={windowState.result.readOnly !== false} connectionId={windowState.connectionId} - dbName={windowState.dbName || ''} + dbName={windowState.result.metadataDbName || windowState.dbName || ''} resultSql={windowState.result.exportSql || windowState.result.sql} exportScope="queryResult" /> diff --git a/frontend/src/components/QueryEditor.tsx b/frontend/src/components/QueryEditor.tsx index 27a12ee7..2c8cad43 100644 --- a/frontend/src/components/QueryEditor.tsx +++ b/frontend/src/components/QueryEditor.tsx @@ -6549,6 +6549,9 @@ const QueryEditor: React.FC<{ tab: TabData; isActive?: boolean }> = ({ tab, isAc columns: cols, messages: resultMessages, tableName: tableRef?.tableName, + // 跨库/跨 schema 查询时,列类型与注释必须从真实表所在库加载 + metadataDbName: tableRef?.metadataDbName, + metadataTableName: tableRef?.metadataTableName, pkColumns: plan?.pkColumns || [], editLocator, readOnly: forceReadOnlyResult || !editLocator || editLocator.readOnly, @@ -7758,7 +7761,8 @@ const QueryEditor: React.FC<{ tab: TabData; isActive?: boolean }> = ({ tab, isAc id: windowId, sourceQueryTabId: tab.id, connectionId: currentConnectionId || tab.connectionId || '', - dbName: currentDb || tab.dbName || '', + // 独立窗也要带上结果表元数据所属库,否则列类型/注释会丢 + dbName: target.metadataDbName || currentDb || tab.dbName || '', title, ...(preferred?.x !== undefined ? { x: preferred.x } : {}), ...(preferred?.y !== undefined ? { y: preferred.y } : {}), @@ -7774,7 +7778,9 @@ const QueryEditor: React.FC<{ tab: TabData; isActive?: boolean }> = ({ tab, isAc columns: target.columns, messages: target.messages, resultType: target.resultType, - tableName: target.tableName, + tableName: target.metadataTableName || target.tableName, + metadataDbName: target.metadataDbName, + metadataTableName: target.metadataTableName, pkColumns: target.pkColumns || [], editLocator: target.editLocator as any, readOnly: target.readOnly !== false, @@ -7811,6 +7817,8 @@ const QueryEditor: React.FC<{ tab: TabData; isActive?: boolean }> = ({ tab, isAc messages: Array.isArray(restored.messages) ? restored.messages : undefined, resultType: restored.resultType === 'message' ? 'message' : 'grid', tableName: restored.tableName, + metadataDbName: restored.metadataDbName, + metadataTableName: restored.metadataTableName, pkColumns: Array.isArray(restored.pkColumns) ? restored.pkColumns : [], editLocator: restored.editLocator, readOnly: restored.readOnly !== false, diff --git a/frontend/src/components/QueryEditorResultsPanel.tsx b/frontend/src/components/QueryEditorResultsPanel.tsx index c67225c0..9e523c40 100644 --- a/frontend/src/components/QueryEditorResultsPanel.tsx +++ b/frontend/src/components/QueryEditorResultsPanel.tsx @@ -34,6 +34,10 @@ export type QueryEditorResultSet = { messages?: string[]; resultType?: 'grid' | 'message'; tableName?: string; + /** 列类型/注释元数据所属库(跨库 SELECT 时可能与 currentDb 不同) */ + metadataDbName?: string; + /** 列元数据查询用表名(PG 等可能为 schema.table) */ + metadataTableName?: string; pkColumns: string[]; editLocator?: EditRowLocator; readOnly: boolean; @@ -439,11 +443,11 @@ const QueryEditorResultsPanel: React.FC = ({ data={rs.rows} columnNames={visibleColumns} loading={loading || rs.page?.loading === true} - tableName={rs.tableName} + tableName={rs.metadataTableName || rs.tableName} exportScope="queryResult" resultSql={rs.exportSql || rs.sql} resultExportAllSql={rs.page?.exportAllSql} - dbName={currentDb} + dbName={rs.metadataDbName || currentDb} connectionId={currentConnectionId} pkColumns={rs.pkColumns} editLocator={rs.editLocator} diff --git a/frontend/src/components/QueryEditorToolbar.tsx b/frontend/src/components/QueryEditorToolbar.tsx index 3d89bb5f..069ff5ca 100644 --- a/frontend/src/components/QueryEditorToolbar.tsx +++ b/frontend/src/components/QueryEditorToolbar.tsx @@ -376,7 +376,12 @@ const QueryEditorToolbar: React.FC = ({ : t("query_editor.action.save") } > - diff --git a/frontend/src/components/queryEditor/QueryEditorHelpers.ts b/frontend/src/components/queryEditor/QueryEditorHelpers.ts index 20a75f6d..9d65511a 100644 --- a/frontend/src/components/queryEditor/QueryEditorHelpers.ts +++ b/frontend/src/components/queryEditor/QueryEditorHelpers.ts @@ -2325,13 +2325,22 @@ export const resolveQueryLocatorPlan = async ({ executedSql: statement, pkColumns: [], }; + const defaultSchema = isOracleLikeDialect(dbType) + ? resolveOracleLikeExecutionSchemaName(config, currentDb) + : ''; + // 即使只读也要解析 tableRef:结果页列类型/注释依赖 metadataDbName + tableName + try { + const previewTableRef = extractQueryResultTableRef(statement, dbType, currentDb, defaultSchema); + if (previewTableRef) { + plan.tableRef = previewTableRef; + } + } catch { + // ignore parse errors; keep bare plan + } if (forceReadOnly) return plan; try { - const defaultSchema = isOracleLikeDialect(dbType) - ? resolveOracleLikeExecutionSchemaName(config, currentDb) - : ''; - let tableRef = extractQueryResultTableRef(statement, dbType, currentDb, defaultSchema); + let tableRef = plan.tableRef || extractQueryResultTableRef(statement, dbType, currentDb, defaultSchema); if (!tableRef) return plan; plan.tableRef = tableRef; if (isSystemMetadataQueryResult(tableRef, dbType)) { diff --git a/frontend/src/utils/detachedWindow.ts b/frontend/src/utils/detachedWindow.ts index 9336746e..08bdc79f 100644 --- a/frontend/src/utils/detachedWindow.ts +++ b/frontend/src/utils/detachedWindow.ts @@ -21,6 +21,9 @@ export type DetachedQueryResultSnapshot = { messages?: string[]; resultType?: 'grid' | 'message'; tableName?: string; + /** 列类型/注释元数据所属库(跨库 SELECT 时可能与窗口 dbName 不同) */ + metadataDbName?: string; + metadataTableName?: string; pkColumns: string[]; editLocator?: { strategy?: string; diff --git a/frontend/src/v2-theme.css b/frontend/src/v2-theme.css index 65da9f08..f7508060 100644 --- a/frontend/src/v2-theme.css +++ b/frontend/src/v2-theme.css @@ -287,6 +287,26 @@ body[data-ui-version="v2"] .ant-btn-primary:hover { border-color: var(--gn-accent-2) !important; } +/* 查询工具栏「保存」:与「运行」同款实心饱满,色值用蓝色 */ +body[data-ui-version="v2"] .gn-v2-query-toolbar-save-action.ant-btn-primary { + background: #2563eb !important; + border-color: #1d4ed8 !important; + color: #fff !important; + font-weight: 600 !important; + box-shadow: var(--gn-shadow-sm), inset 0 0.5px 0 rgba(255, 255, 255, 0.18) !important; +} + +body[data-ui-version="v2"] .gn-v2-query-toolbar-save-action.ant-btn-primary:hover { + background: #1d4ed8 !important; + border-color: #1e40af !important; + color: #fff !important; +} + +body[data-ui-version="v2"] .gn-v2-query-toolbar-save-action.ant-btn-primary:active { + background: #1e40af !important; + border-color: #1e3a8a !important; +} + body[data-ui-version="v2"] .ant-btn-primary:disabled { background: var(--gn-bg-active) !important; border-color: var(--gn-br-2) !important; @@ -434,8 +454,24 @@ body[data-ui-version="v2"] .ant-table-tbody > tr:hover > td { background: var(--gn-bg-hover) !important; } -body[data-ui-version="v2"] .ant-table-tbody > tr.ant-table-row-selected > td { +body[data-ui-version="v2"] .ant-table-tbody > tr.ant-table-row-selected > td, +body[data-ui-version="v2"] .ant-table-tbody .ant-table-row.ant-table-row-selected > .ant-table-cell, +body[data-ui-version="v2"] .ant-table-tbody-virtual .ant-table-row.ant-table-row-selected > .ant-table-cell, +body[data-ui-version="v2"] .ant-table-tbody-virtual-holder .ant-table-row.ant-table-row-selected > .ant-table-cell, +body[data-ui-version="v2"] .gn-v2-data-grid .ant-table-row.ant-table-row-selected > .ant-table-cell { background: var(--gn-bg-selected) !important; + background-color: var(--gn-bg-selected) !important; + background-image: none !important; +} + +body[data-ui-version="v2"] .ant-table-tbody > tr.ant-table-row-selected:hover > td, +body[data-ui-version="v2"] .ant-table-tbody .ant-table-row.ant-table-row-selected:hover > .ant-table-cell, +body[data-ui-version="v2"] .ant-table-tbody-virtual .ant-table-row.ant-table-row-selected:hover > .ant-table-cell, +body[data-ui-version="v2"] .ant-table-tbody-virtual-holder .ant-table-row.ant-table-row-selected:hover > .ant-table-cell, +body[data-ui-version="v2"] .gn-v2-data-grid .ant-table-row.ant-table-row-selected:hover > .ant-table-cell { + background: var(--gn-bg-selected) !important; + background-color: var(--gn-bg-selected) !important; + background-image: none !important; } /* ─── Tags / Badges ────────────────────────────────────── */ @@ -3954,7 +3990,8 @@ body[data-ui-version="v2"] .gn-v2-data-grid .is-single-line-title .sortable-head body[data-ui-version="v2"] .gn-v2-data-grid .ant-table-thead > tr > th:first-child, body[data-ui-version="v2"] .gn-v2-data-grid .ant-table-selection-column { width: 56px !important; - background: var(--gn-bg-panel-2) !important; + /* 与固定列(行号/钉住列)统一用 panel,勿用 panel-2 造成色差 */ + background: var(--gn-bg-panel) !important; border-right: 0.5px solid var(--gn-br-1) !important; }