From f8834aee09b1393501a0d4fe94127c028584260b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E4=B8=AB=E8=AE=B2=E6=A2=B5?= Date: Tue, 9 Jun 2026 12:02:45 +0800 Subject: [PATCH] =?UTF-8?q?feat(grid):=20=E6=B7=BB=E5=8A=A0=E5=A4=9A?= =?UTF-8?q?=E8=A1=8C=E8=BD=AC=E7=BD=AE=E5=8A=9F=E8=83=BD=E5=92=8C=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E7=95=8C=E9=9D=A2=E6=94=AF=E6=8C=81=20(#909)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增多行转置状态管理 - 更新转置记录索引计算逻辑 - 增加多行转置切换开关及提示信息 - 更新国际化文件以支持多语言 --- apps/desktop/src/components/grid/DataGrid.vue | 67 ++++++++++++++++--- .../src/components/layout/ContentArea.vue | 30 ++++++++- .../src/components/ui/LightTooltip.vue | 9 ++- apps/desktop/src/i18n/locales/en.ts | 5 ++ apps/desktop/src/i18n/locales/es.ts | 5 ++ apps/desktop/src/i18n/locales/it.ts | 5 ++ apps/desktop/src/i18n/locales/pt-BR.ts | 5 ++ apps/desktop/src/i18n/locales/zh-CN.ts | 4 ++ apps/desktop/src/i18n/locales/zh-TW.ts | 4 ++ apps/desktop/src/lib/dataGridTranspose.ts | 14 ++++ packages/app-tests/dataGridTranspose.test.ts | 37 ++++++++++ 11 files changed, 172 insertions(+), 13 deletions(-) diff --git a/apps/desktop/src/components/grid/DataGrid.vue b/apps/desktop/src/components/grid/DataGrid.vue index a488cfb297..dd2e7c2513 100644 --- a/apps/desktop/src/components/grid/DataGrid.vue +++ b/apps/desktop/src/components/grid/DataGrid.vue @@ -105,6 +105,7 @@ import { nextKeyboardTransposeState, nextTransposeState, nextTransposeStateForRecordCount, + transposeRecordIndexesForMode, transposeFieldWidth, transposeScrollLeftForRecord, visibleTransposeRecordWindow, @@ -460,6 +461,7 @@ const previewDialogOpen = ref(false); const previewDialogConfig = shallowRef<{ component: any; props: Record } | null>(null); const transposeRowIndex = ref(null); const showTranspose = ref(false); +const multiRowTranspose = ref(false); const preserveTransposeOnNextResult = ref(false); const transposeScrollRef = ref(); const transposeScrollLeft = ref(0); @@ -4836,22 +4838,37 @@ const visibleTransposeRecordIndexes = computed(() => { const window = transposeRecordWindow.value; return Array.from({ length: window.end - window.start }, (_, offset) => window.start + offset); }); +const activeTransposeRecordIndexes = computed(() => + transposeRecordIndexesForMode({ + multiRow: multiRowTranspose.value, + activeRecordIndex: transposeRowIndex.value, + totalRecords: displayRowCount.value, + visibleRecordIndexes: visibleTransposeRecordIndexes.value, + }), +); +const transposeBeforeSpacerWidth = computed(() => + multiRowTranspose.value ? transposeRecordWindow.value.beforeWidth : 0, +); +const transposeAfterSpacerWidth = computed(() => + multiRowTranspose.value ? transposeRecordWindow.value.afterWidth : 0, +); const transposeRows = computed(() => { return buildVisibleTransposeRows({ columns: visibleColumns.value, records: displayRowRefs.value.map((_, index) => displayItemAt(index)?.data ?? []), - recordIndexes: visibleTransposeRecordIndexes.value, + recordIndexes: activeTransposeRecordIndexes.value, valueIndexes: visibleColumnIndexes.value, typeByColumn: columnTypeMap.value, displayValue: (value, _column, index) => formatCellCached(value, visibleColumnIndexes.value[index]), }); }); const isTransposeMode = computed(() => showTranspose.value && transposeRows.value.length > 0); -const transposeTotalWidth = computed( - () => - transposePinnedWidth.value + - Array.from({ length: displayRowCount.value }, (_, i) => getTransposeRecordWidth(i)).reduce((sum, w) => sum + w, 0), -); +const transposeTotalWidth = computed(() => { + const recordIndexes = multiRowTranspose.value + ? Array.from({ length: displayRowCount.value }, (_, i) => i) + : activeTransposeRecordIndexes.value; + return transposePinnedWidth.value + recordIndexes.reduce((sum, i) => sum + getTransposeRecordWidth(i), 0); +}); function transposeScrollElement(): HTMLElement | undefined { const raw = transposeScrollRef.value; @@ -4888,6 +4905,26 @@ function scrollTransposeRecordIntoView(rowIndex: number) { }); } +function setMultiRowTranspose(value: boolean) { + multiRowTranspose.value = value; + if (!showTranspose.value) return; + nextTick(updateTransposeViewport); + if (value && transposeRowIndex.value !== null) { + scrollTransposeRecordIntoView(transposeRowIndex.value); + } else { + nextTick(() => { + const el = transposeScrollElement(); + if (!el) return; + el.scrollLeft = 0; + updateTransposeViewport(); + }); + } +} + +function toggleMultiRowTranspose() { + setMultiRowTranspose(!multiRowTranspose.value); +} + function applyTransposeState(next: { showTranspose: boolean; transposeRowIndex: number | null }) { showTranspose.value = next.showTranspose; transposeRowIndex.value = next.transposeRowIndex; @@ -5624,6 +5661,9 @@ defineExpose({ toggleDdl: toggleTableInfo, showTableInfo, toggleTableInfo, + multiRowTranspose, + setMultiRowTranspose, + toggleMultiRowTranspose, focusSearch, visibleColumnCount, displayableColumnCount, @@ -6436,6 +6476,11 @@ const gridContextMenuItems = computed(() => { {{ t("grid.rowNumber") }} {{ (transposeRowIndex ?? 0) + 1 }} + + {{ multiRowTranspose ? t("grid.transposeMultiRow") : t("grid.transposeSingleRow") }} +