From 4048aeb6fb2ac50230ab5a244d12190e938c4761 Mon Sep 17 00:00:00 2001 From: andyesfly <35127884@qq.com> Date: Wed, 19 Aug 2026 17:12:29 +0800 Subject: [PATCH] =?UTF-8?q?refactor(system):=20=E5=AE=9E=E7=8E=B0=E8=A1=A8?= =?UTF-8?q?=E6=A0=BC=E8=87=AA=E9=80=82=E5=BA=94=E9=AB=98=E5=BA=A6=E5=B8=83?= =?UTF-8?q?=E5=B1=80=EF=BC=8C=E6=8A=BD=E7=A6=BB=E9=80=9A=E7=94=A8=E6=BB=9A?= =?UTF-8?q?=E5=8A=A8=E5=B7=A5=E5=85=B7hooks?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 新增useTableScroll组合式函数,动态计算表格滚动高度 2. 改造多个系统页面布局为弹性伸缩容器,解决页面滚动问题 3. 统一表格滚动配置,优化页面视觉体验 --- client/src/composables/useTableScroll.ts | 51 ++++++++++++++++++++++++ client/src/layouts/index.vue | 8 +++- client/src/views/log/operation/index.vue | 37 ++++++++++++++++- client/src/views/system/dict/index.vue | 35 ++++++++++++++++ client/src/views/system/menu/index.vue | 37 +++++++++++++++++ client/src/views/system/role/index.vue | 35 ++++++++++++++++ client/src/views/system/user/index.vue | 35 ++++++++++++++++ 7 files changed, 234 insertions(+), 4 deletions(-) create mode 100644 client/src/composables/useTableScroll.ts diff --git a/client/src/composables/useTableScroll.ts b/client/src/composables/useTableScroll.ts new file mode 100644 index 0000000..875ee2e --- /dev/null +++ b/client/src/composables/useTableScroll.ts @@ -0,0 +1,51 @@ +import { ref, onMounted, onBeforeUnmount } from 'vue'; + +/** + * 监听表格父容器高度,动态计算 a-table 的 scroll.y。 + * 自动测量 a-table 内部的分页器高度,从而得到准确的 tbody 高度。 + */ +export function useTableScroll(minHeight = 120) { + const wrapperRef = ref(null); + const tableHeight = ref(minHeight); + let observer: ResizeObserver | null = null; + + function update() { + if (!wrapperRef.value) return; + const wrapperHeight = wrapperRef.value.clientHeight; + + // 动态获取分页器高度(如果存在) + const paginationEl = wrapperRef.value.querySelector('.ant-table-pagination') as HTMLElement | null; + const paginationHeight = paginationEl ? paginationEl.offsetHeight : 0; + + // scroll.y = 容器总高 - 分页器高度(表头由 a-table 自动固定,无需扣除) + const tbodyHeight = wrapperHeight - paginationHeight; + tableHeight.value = Math.max(tbodyHeight, minHeight); + } + + onMounted(() => { + if (!wrapperRef.value) return; + observer = new ResizeObserver(update); + observer.observe(wrapperRef.value); + + // 初始测量 + update(); + + // MutationObserver 用于监听分页器的动态添加/移除 + const mutationObserver = new MutationObserver(() => { + update(); + }); + mutationObserver.observe(wrapperRef.value, { childList: true, subtree: true }); + // 保存以便卸载时使用 + (wrapperRef.value as any).__mutationObserver = mutationObserver; + }); + + onBeforeUnmount(() => { + observer?.disconnect(); + observer = null; + if (wrapperRef.value && (wrapperRef.value as any).__mutationObserver) { + (wrapperRef.value as any).__mutationObserver.disconnect(); + } + }); + + return { wrapperRef, tableHeight }; +} diff --git a/client/src/layouts/index.vue b/client/src/layouts/index.vue index bbb9510..69299cd 100644 --- a/client/src/layouts/index.vue +++ b/client/src/layouts/index.vue @@ -409,13 +409,17 @@ function handleUserMenuClick({ key }: { key: string }) { .content { margin: 0; - min-height: calc(100vh - 64px); + height: calc(100vh - 64px); + overflow: hidden; .view-wrapper { background: #fff; padding: 0; border-radius: 0; - min-height: calc(100vh - 64px); + height: 100%; + display: flex; + flex-direction: column; + overflow: hidden; box-shadow: none; } } diff --git a/client/src/views/log/operation/index.vue b/client/src/views/log/operation/index.vue index 4dff79e..2689618 100644 --- a/client/src/views/log/operation/index.vue +++ b/client/src/views/log/operation/index.vue @@ -63,12 +63,14 @@ +
+
@@ -92,6 +95,9 @@ import { message } from 'ant-design-vue' import { SearchOutlined, ReloadOutlined, DownloadOutlined } from '@ant-design/icons-vue' import dayjs from 'dayjs' import { logApi } from '@/api/log' +import { useTableScroll } from '@/composables/useTableScroll' + +const { wrapperRef, tableHeight } = useTableScroll() const tableLoading = ref(false) const exportLoading = ref(false) @@ -271,19 +277,46 @@ onMounted(() => {