From cc96e2c38bc9f7e7d4b2df373226c3fe65af5738 Mon Sep 17 00:00:00 2001 From: t8y2 <1156263951@qq.com> Date: Mon, 18 May 2026 12:27:44 +0800 Subject: [PATCH] feat(grid): preview image URLs in cell details --- apps/desktop/src/components/grid/DataGrid.vue | 59 ++++++++++++++++++- apps/desktop/src/i18n/locales/en.ts | 1 + apps/desktop/src/i18n/locales/es.ts | 1 + apps/desktop/src/i18n/locales/zh-CN.ts | 1 + apps/desktop/src/lib/cellImageUrl.ts | 27 +++++++++ packages/app-tests/cellImageUrl.test.ts | 32 ++++++++++ 6 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 apps/desktop/src/lib/cellImageUrl.ts create mode 100644 packages/app-tests/cellImageUrl.test.ts diff --git a/apps/desktop/src/components/grid/DataGrid.vue b/apps/desktop/src/components/grid/DataGrid.vue index 4700ae1cac..722b36b718 100644 --- a/apps/desktop/src/components/grid/DataGrid.vue +++ b/apps/desktop/src/components/grid/DataGrid.vue @@ -91,6 +91,7 @@ import { } from "@/lib/dataGridTranspose"; import { matchesRowStatusFilter, type RowStatus, type RowStatusFilter } from "@/lib/gridRowStatus"; import { displayCellValue, type CellValue } from "@/lib/cellValue"; +import { cellImagePreviewUrl } from "@/lib/cellImageUrl"; import { applyColumnFormatter, buildColumnFormatterKey, @@ -253,6 +254,8 @@ function typeColorClass(t: string): string { const contextCell = ref<{ rowId: number; rowIndex: number; col: number } | null>(null); const detailCell = ref<{ rowIndex: number; col: number } | null>(null); const showCellDetail = ref(false); +const detailWidth = ref(320); +const isResizingDetail = ref(false); const transposeRowIndex = ref(null); const showTranspose = ref(false); const transposeScrollRef = ref(); @@ -1596,6 +1599,7 @@ const activeCellDetail = computed(() => { value, rawValue, displayValue, + imagePreviewUrl: cellImagePreviewUrl(value), length: value === null ? 0 : String(value).length, formattedJson, isEditable: canEditCellItem(item, cell.col), @@ -2143,6 +2147,8 @@ const ddlWrap = ref(true); const isResizingDdl = ref(false); let ddlResizeStartX = 0; let ddlResizeStartWidth = 0; +let detailResizeStartX = 0; +let detailResizeStartWidth = 0; const indexes = ref([]); const indexesLoaded = ref(false); const indexesLoading = ref(false); @@ -2160,6 +2166,10 @@ const ddlDrawerStyle = computed(() => ({ width: `${ddlWidth.value}px`, })); +const detailDrawerStyle = computed(() => ({ + width: `${detailWidth.value}px`, +})); + const tableInfoTabs = computed( () => [ @@ -2325,6 +2335,28 @@ function onDdlResizeEnd() { window.removeEventListener("mouseup", onDdlResizeEnd); } +function onDetailResizeStart(event: MouseEvent) { + isResizingDetail.value = true; + detailResizeStartX = event.clientX; + detailResizeStartWidth = detailWidth.value; + document.body.classList.add("select-none", "cursor-col-resize"); + window.addEventListener("mousemove", onDetailResizeMove); + window.addEventListener("mouseup", onDetailResizeEnd); +} + +function onDetailResizeMove(event: MouseEvent) { + if (!isResizingDetail.value) return; + const nextWidth = detailResizeStartWidth + detailResizeStartX - event.clientX; + detailWidth.value = Math.min(Math.max(nextWidth, 260), 900); +} + +function onDetailResizeEnd() { + isResizingDetail.value = false; + document.body.classList.remove("select-none", "cursor-col-resize"); + window.removeEventListener("mousemove", onDetailResizeMove); + window.removeEventListener("mouseup", onDetailResizeEnd); +} + const loadingElapsed = ref(0); let _loadingTimer: ReturnType | undefined; let _loadingStart = 0; @@ -2346,6 +2378,7 @@ watch( onUnmounted(() => { cleanupFrames(); onDdlResizeEnd(); + onDetailResizeEnd(); finishCellSelection(); clearTimeout(_searchTimer); clearInterval(_loadingTimer); @@ -3537,8 +3570,14 @@ defineExpose({
+
{{ t("grid.cellDetails") }} @@ -3582,6 +3621,24 @@ defineExpose({
{{ t("grid.cellValue") }}
+
+
{{ t("grid.imagePreview") }}
+ + + +