refactor(system): 实现表格自适应高度布局,抽离通用滚动工具hooks

1. 新增useTableScroll组合式函数,动态计算表格滚动高度
2. 改造多个系统页面布局为弹性伸缩容器,解决页面滚动问题
3. 统一表格滚动配置,优化页面视觉体验
This commit is contained in:
andyesfly committed 2026-08-19 17:12:29 +08:00
1 parent cbc0a936b7
commit 4048aeb6fb
7 files changed
+234 -4

No files matched your search

+35 -2
View File
@@ -63,12 +63,14 @@
</a-card>
<a-card :bordered="false" class="table-card">
<div class="table-wrapper" ref="wrapperRef">
<a-table
:columns="columns"
:data-source="logList"
:loading="tableLoading"
:pagination="paginationConfig"
row-key="id"
:scroll="{ x: 'max-content', y: tableHeight }"
@change="handleTableChange"
>
<template #bodyCell="{ column, record }">
@@ -82,6 +84,7 @@
</template>
</template>
</a-table>
</div>
</a-card>
</div>
</template>
@@ -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(() => {
<style scoped lang="less">
.operation-log {
height: 100%;
display: flex;
flex-direction: column;
overflow: hidden;
padding: 20px;
box-sizing: border-box;
.search-card {
flex-shrink: 0;
margin-bottom: 16px;
:deep(.ant-card-body) {
padding-bottom: 4px;
}
}
.table-card {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
min-height: 0;
:deep(.ant-card-body) {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
min-height: 0;
}
.table-wrapper {
flex: 1;
min-height: 0;
overflow: hidden;
}
:deep(.ant-table) {
font-size: 13px;
height: 100%;
}
}
+35
View File
@@ -40,12 +40,14 @@
</a-button>
</div>
<div class="table-wrapper" ref="wrapperRef">
<a-table
:columns="columns"
:data-source="dataSource"
:loading="loading"
:pagination="pagination"
row-key="id"
:scroll="{ x: 'max-content', y: tableHeight }"
@change="handleTableChange"
>
<template #bodyCell="{ column, record }">
@@ -80,6 +82,7 @@
</template>
</template>
</a-table>
</div>
</a-card>
<a-modal
@@ -131,8 +134,11 @@ import {
DeleteOutlined,
} from '@ant-design/icons-vue';
import { dictApi } from '@/api/dict';
import { useTableScroll } from '@/composables/useTableScroll';
import dayjs from 'dayjs';
const { wrapperRef, tableHeight } = useTableScroll();
interface DictItem {
id: number;
dictType: string;
@@ -346,18 +352,47 @@ async function handleDelete(record: DictItem) {
<style scoped>
.dict-management {
height: 100%;
display: flex;
flex-direction: column;
overflow: hidden;
padding: 20px;
box-sizing: border-box;
}
:deep(.ant-card) {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
min-height: 0;
}
:deep(.ant-card-body) {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
min-height: 0;
}
.search-bar {
flex-shrink: 0;
margin-bottom: 16px;
display: flex;
justify-content: flex-end;
gap: 8px;
}
.table-wrapper {
flex: 1;
min-height: 0;
overflow: hidden;
}
:deep(.ant-table) {
font-size: 14px;
height: 100%;
}
:deep(.ant-btn-link) {
+37
View File
@@ -8,12 +8,14 @@
</a-button>
</template>
<div class="table-wrapper" ref="wrapperRef">
<a-table
:columns="columns"
:data-source="menuList"
:loading="loading"
:pagination="false"
row-key="id"
:scroll="{ x: 'max-content', y: tableHeight }"
:expandable="{
defaultExpandAllRows: false,
showExpandColumn: true,
@@ -54,6 +56,7 @@
</template>
</template>
</a-table>
</div>
</a-card>
<a-modal
@@ -131,6 +134,9 @@ import { ref, reactive, onMounted, computed } from 'vue';
import { message } from 'ant-design-vue';
import { PlusOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons-vue';
import { menuApi } from '@/api/menu';
import { useTableScroll } from '@/composables/useTableScroll';
const { wrapperRef, tableHeight } = useTableScroll({ paginationHeight: 0 });
interface MenuItem {
id: number;
@@ -329,12 +335,43 @@ async function handleDelete(record: MenuItem) {
<style scoped lang="less">
.menu-management {
height: 100%;
display: flex;
flex-direction: column;
overflow: hidden;
padding: 20px;
box-sizing: border-box;
:deep(.ant-card) {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
min-height: 0;
}
:deep(.ant-card-body) {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
min-height: 0;
}
.table-wrapper {
flex: 1;
min-height: 0;
overflow: hidden;
}
:deep(.ant-btn-link) {
padding: 0 4px;
}
:deep(.ant-table) {
height: 100%;
}
:deep(.ant-table-row-expand-icon) {
display: inline-flex;
align-items: center;
+35
View File
@@ -21,12 +21,14 @@
</a-input-search>
</div>
<div class="table-wrapper" ref="wrapperRef">
<a-table
:columns="columns"
:data-source="roleList"
:loading="loading"
:pagination="pagination"
row-key="id"
:scroll="{ x: 'max-content', y: tableHeight }"
@change="handleTableChange"
>
<template #bodyCell="{ column, record }">
@@ -68,6 +70,7 @@
</template>
</template>
</a-table>
</div>
</a-card>
<a-modal
@@ -144,8 +147,11 @@ import {
DeleteOutlined,
} from '@ant-design/icons-vue';
import { roleApi, type RoleInfo } from '@/api/role';
import { useTableScroll } from '@/composables/useTableScroll';
import dayjs from 'dayjs';
const { wrapperRef, tableHeight } = useTableScroll();
interface MenuTreeNode {
id: number;
menuName: string;
@@ -400,17 +406,46 @@ onMounted(() => {
<style scoped>
.role-management {
height: 100%;
display: flex;
flex-direction: column;
overflow: hidden;
padding: 20px;
box-sizing: border-box;
}
:deep(.ant-card) {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
min-height: 0;
}
:deep(.ant-card-body) {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
min-height: 0;
}
.search-bar {
flex-shrink: 0;
margin-bottom: 16px;
display: flex;
justify-content: flex-end;
}
.table-wrapper {
flex: 1;
min-height: 0;
overflow: hidden;
}
:deep(.ant-table) {
font-size: 14px;
height: 100%;
}
:deep(.ant-btn-link) {
+35
View File
@@ -38,6 +38,7 @@
</a-button>
</div>
<div class="table-wrapper" ref="wrapperRef">
<a-table
:columns="columns"
:data-source="dataSource"
@@ -45,6 +46,7 @@
:loading="loading"
:pagination="pagination"
row-key="id"
:scroll="{ x: 'max-content', y: tableHeight }"
@change="handleTableChange"
>
<template #bodyCell="{ column, record }">
@@ -89,6 +91,7 @@
<a-empty description="暂无用户数据" />
</template>
</a-table>
</div>
</a-card>
<a-modal
@@ -165,8 +168,11 @@ import {
EditOutlined,
} from '@ant-design/icons-vue';
import { userApi, type UserInfo, type UserQuery, type RoleInfo } from '@/api/user';
import { useTableScroll } from '@/composables/useTableScroll';
import dayjs from 'dayjs';
const { wrapperRef, tableHeight } = useTableScroll();
const loading = ref(false);
const dataSource = ref<UserInfo[]>([]);
const total = ref(0);
@@ -469,18 +475,47 @@ function formatDateTime(dateStr: string) {
<style scoped>
.user-management {
height: 100%;
display: flex;
flex-direction: column;
overflow: hidden;
padding: 20px;
box-sizing: border-box;
}
:deep(.ant-card) {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
min-height: 0;
}
:deep(.ant-card-body) {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
min-height: 0;
}
.search-bar {
flex-shrink: 0;
margin-bottom: 16px;
display: flex;
justify-content: flex-end;
gap: 8px;
}
.table-wrapper {
flex: 1;
min-height: 0;
overflow: hidden;
}
:deep(.ant-table) {
font-size: 14px;
height: 100%;
}
:deep(.ant-btn-link) {