From fd78993b9105519dfeb8a7a0a3bf925a8f15e3b3 Mon Sep 17 00:00:00 2001 From: IanShaw027 <131567472+IanShaw027@users.noreply.github.com> Date: Sat, 27 Dec 2025 20:01:36 +0800 Subject: [PATCH 1/8] =?UTF-8?q?feat(frontend):=20DataTable=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=E5=A2=9E=E5=BC=BA=20-=20=E6=93=8D=E4=BD=9C=E5=88=97?= =?UTF-8?q?=E5=AE=BD=E5=BA=A6=E8=87=AA=E9=80=82=E5=BA=94=E5=92=8C=E5=88=97?= =?UTF-8?q?=E6=95=B0=E8=87=AA=E9=80=82=E5=BA=94padding?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增功能: 1. 操作列宽度自适应 - checkActionsColumnWidth 方法:智能检测操作按钮是否超出列宽 - 临时展开所有按钮测量实际宽度 - 计算包含gap的总宽度 - 与可用宽度对比,自动显示/隐藏"展开"按钮 - 新增 actionsCount prop: - 用于快速判断是否需要展开功能 - 避免DOM查询带来的性能开销 2. 列数自适应padding - getAdaptivePaddingClass 方法:根据列数动态调整内边距 - ≥10列 → px-2 (8px) - ≥7列 → px-3 (12px) - ≥5列 → px-4 (16px) - <5列 → px-6 (24px,原始值) - 让表格在列数较多时更紧凑,提升空间利用率 --- frontend/src/components/common/DataTable.vue | 79 ++++++++++++++++---- 1 file changed, 63 insertions(+), 16 deletions(-) diff --git a/frontend/src/components/common/DataTable.vue b/frontend/src/components/common/DataTable.vue index 2dae2d4c..52029119 100644 --- a/frontend/src/components/common/DataTable.vue +++ b/frontend/src/components/common/DataTable.vue @@ -15,7 +15,8 @@ :key="column.key" scope="col" :class="[ - 'sticky-header-cell px-6 py-3 text-left text-xs font-medium uppercase tracking-wider text-gray-500 dark:text-dark-400', + 'sticky-header-cell py-3 text-left text-xs font-medium uppercase tracking-wider text-gray-500 dark:text-dark-400', + getAdaptivePaddingClass(), { 'cursor-pointer hover:bg-gray-100 dark:hover:bg-dark-700': column.sortable }, getStickyColumnClass(column, index) ]" @@ -81,7 +82,7 @@ - +
@@ -92,7 +93,7 @@
@@ -128,7 +129,8 @@ v-for="(column, colIndex) in columns" :key="column.key" :class="[ - 'whitespace-nowrap px-6 py-4 text-sm text-gray-900 dark:text-gray-100', + 'whitespace-nowrap py-4 text-sm text-gray-900 dark:text-gray-100', + getAdaptivePaddingClass(), getStickyColumnClass(column, colIndex) ]" > @@ -165,24 +167,46 @@ const checkScrollable = () => { const checkActionsColumnWidth = () => { if (!tableWrapperRef.value) return - // 查找操作列的表头单元格 - const actionsHeader = tableWrapperRef.value.querySelector('th:has(button[title*="Expand"], button[title*="展开"])') - if (!actionsHeader) return - // 查找第一行的操作列单元格 const firstActionCell = tableWrapperRef.value.querySelector('tbody tr:first-child td:last-child') if (!firstActionCell) return - // 获取操作列内容的实际宽度 - const actionsContent = firstActionCell.querySelector('div') - if (!actionsContent) return + // 查找操作列内容的容器div + const actionsContainer = firstActionCell.querySelector('div') + if (!actionsContainer) return - // 比较内容宽度和单元格宽度 - const contentWidth = actionsContent.scrollWidth - const cellWidth = (firstActionCell as HTMLElement).clientWidth + // 临时展开以测量完整宽度 + const wasExpanded = actionsExpanded.value + actionsExpanded.value = true - // 如果内容宽度超过单元格宽度,说明需要展开 - actionsColumnNeedsExpanding.value = contentWidth > cellWidth + // 等待DOM更新 + nextTick(() => { + // 测量所有按钮的总宽度 + const buttons = actionsContainer.querySelectorAll('button') + if (buttons.length <= 2) { + actionsColumnNeedsExpanding.value = false + actionsExpanded.value = wasExpanded + return + } + + // 计算所有按钮的总宽度(包括gap) + let totalWidth = 0 + buttons.forEach((btn, index) => { + totalWidth += (btn as HTMLElement).offsetWidth + if (index < buttons.length - 1) { + totalWidth += 4 // gap-1 = 4px + } + }) + + // 获取单元格可用宽度(减去padding) + const cellWidth = (firstActionCell as HTMLElement).clientWidth - 32 // 减去左右padding + + // 如果总宽度超过可用宽度,需要展开功能 + actionsColumnNeedsExpanding.value = totalWidth > cellWidth + + // 恢复原来的展开状态 + actionsExpanded.value = wasExpanded + }) } // 监听尺寸变化 @@ -219,6 +243,7 @@ interface Props { stickyFirstColumn?: boolean stickyActionsColumn?: boolean expandableActions?: boolean + actionsCount?: number // 操作按钮总数,用于判断是否需要展开功能 } const props = withDefaults(defineProps(), { @@ -268,6 +293,12 @@ const sortedData = computed(() => { // 检查是否有可展开的操作列 const hasExpandableActions = computed(() => { + // 如果明确指定了actionsCount,使用它来判断 + if (props.actionsCount !== undefined) { + return props.expandableActions && props.columns.some((col) => col.key === 'actions') && props.actionsCount > 2 + } + + // 否则使用原来的检测逻辑 return ( props.expandableActions && props.columns.some((col) => col.key === 'actions') && @@ -312,6 +343,22 @@ const getStickyColumnClass = (column: Column, index: number) => { return classes.join(' ') } + +// 根据列数自适应调整内边距 +const getAdaptivePaddingClass = () => { + const columnCount = props.columns.length + + // 列数越多,内边距越小 + if (columnCount >= 10) { + return 'px-2' // 8px + } else if (columnCount >= 7) { + return 'px-3' // 12px + } else if (columnCount >= 5) { + return 'px-4' // 16px + } else { + return 'px-6' // 24px (原始值) + } +}