From 4eede0714219c861168a9b309d9319f6fc1fa098 Mon Sep 17 00:00:00 2001 From: t8y2 <1156263951@qq.com> Date: Fri, 1 May 2026 12:43:05 +0800 Subject: [PATCH] feat: add transpose functionality to DataGrid and update localization --- src/components/grid/DataGrid.vue | 78 +++++++++++++++++++++++++++++++- src/i18n/locales/en.ts | 1 + src/i18n/locales/zh-CN.ts | 1 + 3 files changed, 79 insertions(+), 1 deletion(-) diff --git a/src/components/grid/DataGrid.vue b/src/components/grid/DataGrid.vue index 03c739b515..64a53f37cc 100644 --- a/src/components/grid/DataGrid.vue +++ b/src/components/grid/DataGrid.vue @@ -7,7 +7,7 @@ const globalDdlOpen = ref(false); import { computed, nextTick, onUnmounted, watch } from "vue"; import { useElementSize } from "@vueuse/core"; import { useI18n } from "vue-i18n"; -import { ArrowUp, ArrowDown, Download, Plus, Trash2, Save, ChevronLeft, ChevronRight, Search, Inbox, SearchX, Code2, Copy, Loader2, X, Undo2, WrapText, Info } from "lucide-vue-next"; +import { ArrowUp, ArrowDown, Download, Plus, Trash2, Save, ChevronLeft, ChevronRight, Search, Inbox, SearchX, Code2, Copy, Loader2, X, Undo2, WrapText, Info, Rows3 } from "lucide-vue-next"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { @@ -120,6 +120,8 @@ const selectionFocus = ref(null); const isSelectingCells = ref(false); const detailCell = ref<{ rowIndex: number; col: number } | null>(null); const showCellDetail = ref(false); +const transposeRowIndex = ref(null); +const showTranspose = ref(false); const sortCol = ref(null); const sortDir = ref<"asc" | "desc">("asc"); const searchText = ref(""); @@ -655,6 +657,7 @@ function beginCellSelection(rowIndex: number, colIndex: number, event: MouseEven event.preventDefault(); selectSingleCell(rowIndex, colIndex); isSelectingCells.value = true; + if (showTranspose.value) transposeRowIndex.value = rowIndex; document.addEventListener("mouseup", finishCellSelection); } @@ -717,10 +720,39 @@ function copyDetailSqlCondition() { copyText(condition); } +const transposeData = computed(() => { + if (transposeRowIndex.value === null) return null; + const item = displayItems.value[transposeRowIndex.value]; + if (!item) return null; + return props.result.columns.map((col, i) => ({ + column: col, + type: columnTypeMap.value.get(col) || "", + value: item.data[i], + display: formatCell(item.data[i]), + isNull: item.data[i] === null, + })); +}); + +function openTranspose(rowIndex: number) { + transposeRowIndex.value = rowIndex; + showTranspose.value = true; + showCellDetail.value = false; +} + +function transposeNav(delta: number) { + if (transposeRowIndex.value === null) return; + const next = transposeRowIndex.value + delta; + if (next >= 0 && next < displayItems.value.length) { + transposeRowIndex.value = next; + } +} + watch(() => props.result, () => { clearCellSelection(); showCellDetail.value = false; detailCell.value = null; + showTranspose.value = false; + transposeRowIndex.value = null; }); // --- Copy/Export --- @@ -1172,6 +1204,46 @@ function escapeAndHighlightKeywords(s: string): string { + +
+
+ + {{ t('grid.transpose') }} + {{ t('grid.rowNumber') }} {{ (transposeRowIndex ?? 0) + 1 }} + + + + +
+
+ + + + + + + +
+
{{ field.column }}
+
{{ field.type }}
+
+ {{ field.display }} +
+
+
@@ -1181,6 +1253,10 @@ function escapeAndHighlightKeywords(s: string): string { {{ t('grid.copyRow') }} {{ t('grid.copyAll') }} + + {{ t('grid.transpose') }} + +