ソースを参照

feat(web-admin): viewport-fill list height for system manage menus

Wire 系统信息 lists (tenant/dict/menu/dept/role/user/post/operlog) and
临时存放 CRM lists under 系统管理 to useListTableViewportHeight, with
onActivated recalc for keep-alive pages.

Co-authored-by: Cursor <cursoragent@cursor.com>
zlwu 2 ヶ月 前
親
コミット
506cc7991a

+ 3 - 2
web-admin/graphify-out/.graphify_labels.json

@@ -267,15 +267,18 @@
   "265": "Community 265",
   "266": "crypto.ts",
   "267": "fetchData",
+  "268": "loading.ts",
   "269": "Community 269",
   "270": "Community 270",
   "271": "SettingDrawer.vue",
   "272": "customerPool.ts",
+  "273": "ProcessStatusTag.vue",
   "274": "pl-plan-stop-product-arrange-required.ts",
   "275": "index.js",
   "276": "tabs.ts",
   "277": "handleKeyDown",
   "278": "index.vue",
+  "279": "index.js",
   "280": "Community 280",
   "281": "index.js",
   "283": "Community 283",
@@ -290,7 +293,6 @@
   "294": "menuFavorite.ts",
   "295": "Community 295",
   "296": "Community 296",
-  "297": "index.vue",
   "299": "zh_CN.js",
   "301": "ProcessStatusTag.vue",
   "302": "Community 302",
@@ -302,7 +304,6 @@
   "308": "Community 308",
   "309": "Community 309",
   "310": "Community 310",
-  "311": "handleExportPdf",
   "312": "loadUserOptions",
   "314": "assignmentMatchesFilter",
   "315": "Community 315",

+ 0 - 9
web-admin/graphify-out/2026-09-01/.graphify_labels.json

@@ -267,39 +267,31 @@
   "265": "Community 265",
   "266": "crypto.ts",
   "267": "fetchData",
-  "268": "zh_CN.js",
   "269": "Community 269",
   "270": "Community 270",
   "271": "SettingDrawer.vue",
   "272": "customerPool.ts",
-  "273": "handleConfirmApproval",
   "274": "pl-plan-stop-product-arrange-required.ts",
   "275": "index.js",
   "276": "tabs.ts",
   "277": "handleKeyDown",
   "278": "index.vue",
-  "279": "handleDisburse",
   "280": "Community 280",
   "281": "index.js",
-  "282": "product.ts",
   "283": "Community 283",
   "284": "Community 284",
   "285": "Community 285",
   "286": "Community 286",
-  "287": "view-fields.ts",
   "288": "syncStatsColumnWidths",
   "289": "handleEdit",
   "290": "index.js",
-  "291": "crm-owner-candidates.ts",
   "292": "Community 292",
   "293": "index.vue",
   "294": "menuFavorite.ts",
   "295": "Community 295",
   "296": "Community 296",
   "297": "index.vue",
-  "298": "index.vue",
   "299": "zh_CN.js",
-  "300": "index.vue",
   "301": "ProcessStatusTag.vue",
   "302": "Community 302",
   "303": "Community 303",
@@ -312,7 +304,6 @@
   "310": "Community 310",
   "311": "handleExportPdf",
   "312": "loadUserOptions",
-  "313": "loadUserOptions",
   "314": "assignmentMatchesFilter",
   "315": "Community 315",
   "316": "Community 316",

ファイルの差分が大きいため隠しています
+ 206 - 254
web-admin/graphify-out/2026-09-01/GRAPH_REPORT.md


ファイルの差分が大きいため隠しています
+ 112 - 112
web-admin/graphify-out/2026-09-01/graph.json


ファイルの差分が大きいため隠しています
+ 240 - 219
web-admin/graphify-out/GRAPH_REPORT.md


ファイルの差分が大きいため隠しています
+ 112 - 112
web-admin/graphify-out/graph.json


+ 22 - 3
web-admin/src/views/crm/clue/index.vue

@@ -206,7 +206,10 @@
       </div>
 
       <div class="list-body list-wrap">
-        <ListTable table-key="crm-clue"
+        <div ref="crmClueTableWrapRef" class="table-scroll bx-list-table-wrap">
+          <ListTable
+            ref="crmClueTableRef"
+            :height="tableHeight" table-key="crm-clue"
           class="list-table"
           :data="clueList"
           v-loading="loading"
@@ -401,7 +404,10 @@
           />
         </ListTable>
 
-        <div class="pagination list-pager-bar">
+        
+        </div>
+        <div ref="crmClueBelowRef">
+          <div class="pagination list-pager-bar">
           <div class="list-pager-selected">
             已选 <span class="sel-num">{{ selectedRows.length }}</span> 项
           </div>
@@ -417,6 +423,7 @@
             @current-change="getList"
           />
         </div>
+        </div>
       </div>
 
       <ClueForm ref="clueFormRef" @success="getList" />
@@ -516,6 +523,7 @@
   import ListToolbarEndActions from '@/components/business/list-toolbar-end-actions/index.vue'
   import ListQuickSearchInput from '@/components/business/list-quick-search-input/index.vue'
   import { usePersistedListColumns } from '@/composables/usePersistedListColumns'
+import { useListTableViewportHeight } from '@/composables/useListTableViewportHeight'
 
   const dictStore = useDictStore()
 
@@ -588,6 +596,15 @@
     ]
   })
 
+ const crmClueTableWrapRef = ref<HTMLElement | null>(null)
+ const crmClueBelowRef = ref<HTMLElement | null>(null)
+ const crmClueTableRef = ref<any>(null)
+ const { tableHeight, recalc: recalcTableHeight } = useListTableViewportHeight({
+   tableEl: crmClueTableWrapRef,
+   pagerEl: crmClueBelowRef,
+   tableRef: crmClueTableRef
+ })
+
   const clueExportColumns = computed(() => {
     const cols = [...visibleColumns.value]
     if (!cols.includes('company')) cols.unshift('company')
@@ -891,5 +908,7 @@
 
   onMounted(() => {
     getList()
-  })
+  
+    nextTick(() => recalcTableHeight())
+})
 </script>

+ 21 - 2
web-admin/src/views/crm/customer/pool/RuleIndex.vue

@@ -114,7 +114,10 @@
 
       <!-- 数据表格 -->
       <div class="list-body list-wrap">
-        <ListTable table-key="crm-customer-pool-rule-index"
+        <div ref="crmPoolRuleTableWrapRef" class="table-scroll bx-list-table-wrap">
+          <ListTable
+            ref="crmPoolRuleTableRef"
+            :height="tableHeight" table-key="crm-customer-pool-rule-index"
           class="list-table"
           :data="ruleList"
           v-loading="loading"
@@ -210,7 +213,10 @@
             show-overflow-tooltip
           />
         </ListTable>
-        <div class="pagination list-pager-bar">
+        
+        </div>
+        <div ref="crmPoolRuleBelowRef">
+          <div class="pagination list-pager-bar">
           <div class="list-pager-selected">
             已选 <span class="sel-num">{{ selectedRows.length }}</span> 项
           </div>
@@ -225,6 +231,7 @@
             @current-change="getList"
           />
         </div>
+        </div>
       </div>
 
       <!-- 新增/编辑规则对话框 -->
@@ -239,6 +246,7 @@ import ListExportDropdown from '@/components/business/list-export-dropdown/index
 import ListToolbarEndActions from '@/components/business/list-toolbar-end-actions/index.vue'
 import ListQuickSearchInput from '@/components/business/list-quick-search-input/index.vue'
 import { usePersistedListColumns } from '@/composables/usePersistedListColumns'
+import { useListTableViewportHeight } from '@/composables/useListTableViewportHeight'
 import {
   Plus,
   Close,
@@ -286,6 +294,15 @@ const {
   resetToDefault
 } = usePersistedListColumns('crm_pool_rule_visible_columns', listColumnDefs)
 
+ const crmPoolRuleTableWrapRef = ref<HTMLElement | null>(null)
+ const crmPoolRuleBelowRef = ref<HTMLElement | null>(null)
+ const crmPoolRuleTableRef = ref<any>(null)
+ const { tableHeight, recalc: recalcTableHeight } = useListTableViewportHeight({
+   tableEl: crmPoolRuleTableWrapRef,
+   pagerEl: crmPoolRuleBelowRef,
+   tableRef: crmPoolRuleTableRef
+ })
+
 const poolRuleExportColumns = computed(() => {
   const cols = [...visibleColumns.value]
   if (!cols.includes('poolName')) cols.unshift('poolName')
@@ -463,6 +480,8 @@ const handleBatchExecute = async () => {
 
 onMounted(() => {
   getList()
+
+  nextTick(() => recalcTableHeight())
 })
 
 watchDebounced(

+ 21 - 2
web-admin/src/views/crm/customer/pool/index.vue

@@ -93,7 +93,10 @@
 
       <!-- 数据表格 -->
       <div class="list-body list-wrap">
-        <ListTable table-key="crm-customer-pool"
+        <div ref="crmPoolTableWrapRef" class="table-scroll bx-list-table-wrap">
+          <ListTable
+            ref="crmPoolTableRef"
+            :height="tableHeight" table-key="crm-customer-pool"
           class="list-table"
           :data="customerList"
           v-loading="loading"
@@ -506,7 +509,10 @@
             show-overflow-tooltip
           />
         </ListTable>
-        <div class="pagination list-pager-bar">
+        
+        </div>
+        <div ref="crmPoolBelowRef">
+          <div class="pagination list-pager-bar">
           <div class="list-pager-selected">
             已选 <span class="sel-num">{{ selectedRows.length }}</span> 项
           </div>
@@ -521,6 +527,7 @@
             @current-change="getList"
           />
         </div>
+        </div>
       </div>
 
       <!-- 客户详情抽屉 -->
@@ -549,6 +556,7 @@ import ListExportDropdown from '@/components/business/list-export-dropdown/index
 import ListToolbarEndActions from '@/components/business/list-toolbar-end-actions/index.vue'
 import ListQuickSearchInput from '@/components/business/list-quick-search-input/index.vue'
 import { usePersistedListColumns } from '@/composables/usePersistedListColumns'
+import { useListTableViewportHeight } from '@/composables/useListTableViewportHeight'
 import ClaimDialog from './components/ClaimDialog.vue'
 import AssignDialog from './components/AssignDialog.vue'
 import CustomerDetail from '../CustomerDetailDialog.vue'
@@ -632,6 +640,15 @@ const {
   ]
 })
 
+ const crmPoolTableWrapRef = ref<HTMLElement | null>(null)
+ const crmPoolBelowRef = ref<HTMLElement | null>(null)
+ const crmPoolTableRef = ref<any>(null)
+ const { tableHeight, recalc: recalcTableHeight } = useListTableViewportHeight({
+   tableEl: crmPoolTableWrapRef,
+   pagerEl: crmPoolBelowRef,
+   tableRef: crmPoolTableRef
+ })
+
 const poolExportColumns = computed(() => {
   const cols = [...visibleColumns.value]
   if (!cols.includes('customerName')) cols.unshift('customerName')
@@ -747,5 +764,7 @@ watchDebounced(
 
 onMounted(() => {
   getList()
+
+  nextTick(() => recalcTableHeight())
 })
 </script>

+ 33 - 16
web-admin/src/views/crm/opportunity/index.vue

@@ -156,7 +156,10 @@
       </div>
 
       <div class="list-body list-wrap">
-        <ListTable table-key="crm-opportunity"
+        <div ref="crmOpportunityTableWrapRef" class="table-scroll bx-list-table-wrap">
+          <ListTable
+            ref="crmOpportunityTableRef"
+            :height="tableHeight" table-key="crm-opportunity"
           v-loading="loading"
           class="list-table"
           stripe
@@ -452,22 +455,24 @@
             show-overflow-tooltip
           />
         </ListTable>
+        </div>
+        <div ref="crmOpportunityBelowRef">
+          <div class="pagination list-pager-bar">
+            <div class="list-pager-selected">
+              已选 <span class="sel-num">{{ selectedRows.length }}</span> 项
+            </div>
 
-        <div class="pagination list-pager-bar">
-          <div class="list-pager-selected">
-            已选 <span class="sel-num">{{ selectedRows.length }}</span> 项
+            <el-pagination
+              v-model:current-page="queryParams.pageNum"
+              v-model:page-size="queryParams.pageSize"
+              :total="total"
+              :page-sizes="[10, 20, 100, 500]"
+              layout="total, sizes, prev, pager, next, jumper"
+              background
+              @size-change="getList"
+              @current-change="getList"
+            />
           </div>
-
-          <el-pagination
-            v-model:current-page="queryParams.pageNum"
-            v-model:page-size="queryParams.pageSize"
-            :total="total"
-            :page-sizes="[10, 20, 100, 500]"
-            layout="total, sizes, prev, pager, next, jumper"
-            background
-            @size-change="getList"
-            @current-change="getList"
-          />
         </div>
       </div>
 
@@ -598,6 +603,7 @@
   import ListExportDropdown from '@/components/business/list-export-dropdown/index.vue'
   import ListToolbarEndActions from '@/components/business/list-toolbar-end-actions/index.vue'
   import { usePersistedListColumns } from '@/composables/usePersistedListColumns'
+import { useListTableViewportHeight } from '@/composables/useListTableViewportHeight'
 
   const dictStore = useDictStore()
   const router = useRouter()
@@ -651,6 +657,15 @@
       ]
     })
 
+  const crmOpportunityTableWrapRef = ref<HTMLElement | null>(null)
+  const crmOpportunityBelowRef = ref<HTMLElement | null>(null)
+  const crmOpportunityTableRef = ref<any>(null)
+  const { tableHeight, recalc: recalcTableHeight } = useListTableViewportHeight({
+    tableEl: crmOpportunityTableWrapRef,
+    pagerEl: crmOpportunityBelowRef,
+    tableRef: crmOpportunityTableRef
+  })
+
   // 当前视图
   const activeView = ref('mine')
 
@@ -1059,7 +1074,9 @@
   // 初始化加载数据
   onMounted(() => {
     getList()
-  })
+  
+    nextTick(() => recalcTableHeight())
+})
 </script>
 
 <style scoped lang="scss">

+ 21 - 4
web-admin/src/views/crm/supplier-hazard/index.vue

@@ -29,7 +29,10 @@
       </div>
 
       <div class="list-body list-wrap">
-        <ListTable table-key="crm-supplier-hazard" v-loading="loading" :data="tableData" class="list-table" stripe>
+        <div ref="crmSupplierHazardTableWrapRef" class="table-scroll bx-list-table-wrap">
+          <ListTable
+            ref="crmSupplierHazardTableRef"
+            :height="tableHeight" table-key="crm-supplier-hazard" v-loading="loading" :data="tableData" class="list-table" stripe>
           <el-table-column prop="supplierName" label="主体名称" min-width="200" show-overflow-tooltip />
           <el-table-column prop="supplierCode" label="编码" min-width="100" show-overflow-tooltip />
           <el-table-column label="允许易制毒" min-width="120" align="center">
@@ -61,8 +64,9 @@
           </el-table-column>
           <el-table-column prop="updateTime" label="更新时间" min-width="160" show-overflow-tooltip />
         </ListTable>
-
-        <div class="pagination list-pager-bar">
+        </div>
+        <div ref="crmSupplierHazardBelowRef">
+          <div class="pagination list-pager-bar">
           <el-pagination
             v-model:current-page="pagination.page"
             v-model:page-size="pagination.pageSize"
@@ -74,6 +78,7 @@
             @current-change="loadData"
           />
         </div>
+        </div>
       </div>
     </section>
   </div>
@@ -82,6 +87,7 @@
 <script setup lang="ts">
   import { RefreshLeft, Search } from '@element-plus/icons-vue'
   import { ElMessage } from 'element-plus'
+  import { useListTableViewportHeight } from '@/composables/useListTableViewportHeight'
   import {
     listSupplierInfo,
     updateSupplierInfo,
@@ -154,7 +160,18 @@
     }
   }
 
+  const crmSupplierHazardTableWrapRef = ref<HTMLElement | null>(null)
+  const crmSupplierHazardBelowRef = ref<HTMLElement | null>(null)
+  const crmSupplierHazardTableRef = ref<any>(null)
+  const { tableHeight, recalc: recalcTableHeight } = useListTableViewportHeight({
+    tableEl: crmSupplierHazardTableWrapRef,
+    pagerEl: crmSupplierHazardBelowRef,
+    tableRef: crmSupplierHazardTableRef
+  })
+
   onMounted(() => {
     loadData()
-  })
+  
+    nextTick(() => recalcTableHeight())
+})
 </script>

+ 27 - 6
web-admin/src/views/system/dept/index.vue

@@ -88,7 +88,10 @@
       </div>
 
       <div class="list-body list-wrap">
-        <ListTable table-key="system-dept"
+        <div ref="sysDeptTableWrapRef" class="table-scroll bx-list-table-wrap">
+          <ListTable
+            ref="sysDeptTableRef"
+            :height="tableHeight" table-key="system-dept"
           ref="tableRef"
           :key="listTableKey"
           class="list-table"
@@ -165,12 +168,13 @@
             header-align="center"
           />
         </ListTable>
-      </div>
-
-      <div class="pagination list-pager-bar">
+        </div>
+        <div ref="sysDeptBelowRef">
+          <div class="pagination list-pager-bar">
         <div class="list-pager-selected">
           已选 <span class="sel-num">{{ selectedRows.length }}</span> 项
         </div>
+        </div>
       </div>
 
       <el-dialog
@@ -316,7 +320,8 @@ import ListToolbarEndActions from '@/components/business/list-toolbar-end-action
 import ListExportDropdown from '@/components/business/list-export-dropdown/index.vue'
 import ListQuickSearchInput from '@/components/business/list-quick-search-input/index.vue'
 import { usePersistedListColumns } from '@/composables/usePersistedListColumns'
-  import { ref, reactive, computed, watch, onMounted, nextTick } from 'vue'
+import { useListTableViewportHeight } from '@/composables/useListTableViewportHeight'
+  import { ref, reactive, computed, watch, onMounted, nextTick , onActivated } from 'vue'
   import { canDeleteByCreator, filterDeletableByCreator, allRowsDeletableByCreator, CREATOR_DELETE_TIP } from '@/utils/creator-delete'
   import { syncViewRowFromTree } from '@/utils/view-dialog-refresh'
   import { ElMessage, ElMessageBox } from 'element-plus'
@@ -360,6 +365,15 @@ const {
   resetToDefault
 } = usePersistedListColumns('system-dept-list-columns', listColumnDefs)
 
+const sysDeptTableWrapRef = ref<HTMLElement | null>(null)
+const sysDeptBelowRef = ref<HTMLElement | null>(null)
+const sysDeptTableRef = ref<any>(null)
+const { tableHeight, recalc: recalcTableHeight } = useListTableViewportHeight({
+  tableEl: sysDeptTableWrapRef,
+  pagerEl: sysDeptBelowRef,
+  tableRef: sysDeptTableRef
+})
+
 /** 可选列显隐变化时重建树表,避免 EP 树表与 v-if 列不同步导致错位 */
 const listTableKey = computed(() => visibleColumns.value.join('|'))
 
@@ -871,7 +885,14 @@ const dictStore = useDictStore()
     loadData()
     loadDeptTreeForSelect()
     loadDictOptions()
-  })
+  
+    nextTick(() => recalcTableHeight())
+})
+
+onActivated(() => {
+  nextTick(() => recalcTableHeight())
+})
+
 </script>
 
 <style scoped lang="scss">

+ 28 - 4
web-admin/src/views/system/dict/index.vue

@@ -94,7 +94,10 @@
       </div>
 
       <div class="list-body list-wrap">
-        <ListTable table-key="system-dict"
+        <div ref="sysDictTableWrapRef" class="table-scroll bx-list-table-wrap">
+          <ListTable
+            ref="sysDictTableRef"
+            :height="tableHeight" table-key="system-dict"
           class="list-table"
           :data="tableData"
           v-loading="loading"
@@ -148,7 +151,10 @@
             header-align="center"
           />
         </ListTable>
-        <div class="pagination list-pager-bar">
+        
+        </div>
+        <div ref="sysDictBelowRef">
+          <div class="pagination list-pager-bar">
           <div class="list-pager-selected">
             已选 <span class="sel-num">{{ selectedRows.length }}</span> 项
           </div>
@@ -163,6 +169,7 @@
             @current-change="(val) => ((pagination.page = val), loadData())"
           />
         </div>
+        </div>
       </div>
 
       <el-dialog
@@ -526,7 +533,8 @@ import ListToolbarEndActions from '@/components/business/list-toolbar-end-action
 import ListExportDropdown from '@/components/business/list-export-dropdown/index.vue'
 import ListQuickSearchInput from '@/components/business/list-quick-search-input/index.vue'
 import { usePersistedListColumns } from '@/composables/usePersistedListColumns'
-  import { ref, reactive, onMounted, computed } from 'vue'
+import { useListTableViewportHeight } from '@/composables/useListTableViewportHeight'
+  import { ref, reactive, onMounted, computed , onActivated } from 'vue'
   import { canDeleteByCreator, filterDeletableByCreator, allRowsDeletableByCreator, CREATOR_DELETE_TIP } from '@/utils/creator-delete'
   import { syncViewRowFromFlatList } from '@/utils/view-dialog-refresh'
   import { ElMessage, ElMessageBox } from 'element-plus'
@@ -571,6 +579,15 @@ import { usePersistedListColumns } from '@/composables/usePersistedListColumns'
     resetToDefault
   } = usePersistedListColumns('system-dict-list-columns', listColumnDefs)
 
+ const sysDictTableWrapRef = ref<HTMLElement | null>(null)
+ const sysDictBelowRef = ref<HTMLElement | null>(null)
+ const sysDictTableRef = ref<any>(null)
+ const { tableHeight, recalc: recalcTableHeight } = useListTableViewportHeight({
+   tableEl: sysDictTableWrapRef,
+   pagerEl: sysDictBelowRef,
+   tableRef: sysDictTableRef
+ })
+
   const dictDataListColumnDefs = [
     { prop: 'dictValue', label: '数据值' },
     { prop: 'tagType', label: '标签颜色' },
@@ -981,7 +998,14 @@ import { usePersistedListColumns } from '@/composables/usePersistedListColumns'
 
   onMounted(() => {
     loadData()
-  })
+  
+    nextTick(() => recalcTableHeight())
+})
+
+onActivated(() => {
+  nextTick(() => recalcTableHeight())
+})
+
 </script>
 
 <style scoped lang="scss">

+ 27 - 6
web-admin/src/views/system/menu/index.vue

@@ -87,7 +87,10 @@
       </div>
 
       <div class="list-body list-wrap">
-        <ListTable table-key="system-menu"
+        <div ref="sysMenuTableWrapRef" class="table-scroll bx-list-table-wrap">
+          <ListTable
+            ref="sysMenuTableRef"
+            :height="tableHeight" table-key="system-menu"
           ref="tableRef"
           class="list-table"
           :data="tableData"
@@ -199,12 +202,13 @@
             </template>
           </el-table-column>
         </ListTable>
-      </div>
-
-      <div class="pagination list-pager-bar">
+        </div>
+        <div ref="sysMenuBelowRef">
+          <div class="pagination list-pager-bar">
         <div class="list-pager-selected">
           已选 <span class="sel-num">{{ selectedRows.length }}</span> 项
         </div>
+        </div>
       </div>
 
       <el-dialog
@@ -326,7 +330,8 @@ import ListToolbarEndActions from '@/components/business/list-toolbar-end-action
 import ListExportDropdown from '@/components/business/list-export-dropdown/index.vue'
 import ListQuickSearchInput from '@/components/business/list-quick-search-input/index.vue'
 import { usePersistedListColumns } from '@/composables/usePersistedListColumns'
-  import { ref, reactive, computed, onMounted, nextTick } from 'vue'
+import { useListTableViewportHeight } from '@/composables/useListTableViewportHeight'
+  import { ref, reactive, computed, onMounted, nextTick , onActivated } from 'vue'
   import { canDeleteByCreator, filterDeletableByCreator, allRowsDeletableByCreator, CREATOR_DELETE_TIP } from '@/utils/creator-delete'
   import { syncViewRowFromTree } from '@/utils/view-dialog-refresh'
   import { ElMessage, ElMessageBox } from 'element-plus'
@@ -363,6 +368,15 @@ import { usePersistedListColumns } from '@/composables/usePersistedListColumns'
     resetToDefault
   } = usePersistedListColumns('system-menu-list-columns', listColumnDefs)
 
+  const sysMenuTableWrapRef = ref<HTMLElement | null>(null)
+  const sysMenuBelowRef = ref<HTMLElement | null>(null)
+  const sysMenuTableRef = ref<any>(null)
+  const { tableHeight, recalc: recalcTableHeight } = useListTableViewportHeight({
+    tableEl: sysMenuTableWrapRef,
+    pagerEl: sysMenuBelowRef,
+    tableRef: sysMenuTableRef
+  })
+
   const dictStore = useDictStore()
 
   const searchForm = reactive<{ keyword: string }>({ keyword: '' })
@@ -694,7 +708,14 @@ import { usePersistedListColumns } from '@/composables/usePersistedListColumns'
 
   onMounted(() => {
     loadData()
-  })
+  
+    nextTick(() => recalcTableHeight())
+})
+
+onActivated(() => {
+  nextTick(() => recalcTableHeight())
+})
+
 </script>
 
 <style scoped lang="scss">

+ 26 - 2
web-admin/src/views/system/operlog/index.vue

@@ -82,7 +82,10 @@
       </div>
 
       <div class="list-body list-wrap">
-        <ListTable table-key="system-operlog"
+        <div ref="sysOperlogTableWrapRef" class="table-scroll bx-list-table-wrap">
+          <ListTable
+            ref="sysOperlogTableRef"
+            :height="tableHeight" table-key="system-operlog"
           class="list-table"
           :data="tableData"
           stripe
@@ -166,7 +169,10 @@
           />
         </ListTable>
 
-        <div class="pagination list-pager-bar">
+        
+        </div>
+        <div ref="sysOperlogBelowRef">
+          <div class="pagination list-pager-bar">
           <div class="list-pager-selected">
             已选 <span class="sel-num">{{ selectedRows.length }}</span> 项
           </div>
@@ -181,6 +187,7 @@
             @current-change="fetchList"
           />
         </div>
+        </div>
       </div>
     </section>
 
@@ -248,6 +255,7 @@ import ListToolbarEndActions from '@/components/business/list-toolbar-end-action
 import ListExportDropdown from '@/components/business/list-export-dropdown/index.vue'
 import ListQuickSearchInput from '@/components/business/list-quick-search-input/index.vue'
 import { usePersistedListColumns } from '@/composables/usePersistedListColumns'
+import { useListTableViewportHeight } from '@/composables/useListTableViewportHeight'
 import { RefreshLeft, Search, View } from '@element-plus/icons-vue'
 import { list as listOperLog, exportOperLog, detail as getOperLogDetail } from '@/api/monitor/operlog'
 import type { OperLogVO, OperLogQuery } from '@/api/monitor/operlog/types'
@@ -274,6 +282,15 @@ const {
   resetToDefault
 } = usePersistedListColumns('system-operlog-list-columns', listColumnDefs)
 
+ const sysOperlogTableWrapRef = ref<HTMLElement | null>(null)
+ const sysOperlogBelowRef = ref<HTMLElement | null>(null)
+ const sysOperlogTableRef = ref<any>(null)
+ const { tableHeight, recalc: recalcTableHeight } = useListTableViewportHeight({
+   tableEl: sysOperlogTableWrapRef,
+   pagerEl: sysOperlogBelowRef,
+   tableRef: sysOperlogTableRef
+ })
+
 const loading = ref(false)
 const tableData = ref<OperLogVO[]>([])
 const selectedRows = ref<OperLogVO[]>([])
@@ -388,7 +405,14 @@ watchDebounced(
 
 onMounted(() => {
   fetchList()
+
+  nextTick(() => recalcTableHeight())
 })
+
+onActivated(() => {
+  nextTick(() => recalcTableHeight())
+})
+
 </script>
 
 <style scoped lang="scss">

+ 28 - 4
web-admin/src/views/system/post/index.vue

@@ -95,7 +95,10 @@
       </div>
 
       <div class="list-body list-wrap">
-        <ListTable table-key="system-post"
+        <div ref="sysPostTableWrapRef" class="table-scroll bx-list-table-wrap">
+          <ListTable
+            ref="sysPostTableRef"
+            :height="tableHeight" table-key="system-post"
           class="list-table"
           :data="tableData"
           v-loading="loading"
@@ -155,7 +158,10 @@
             header-align="center"
           />
         </ListTable>
-        <div class="pagination list-pager-bar">
+        
+        </div>
+        <div ref="sysPostBelowRef">
+          <div class="pagination list-pager-bar">
           <div class="list-pager-selected">
             已选 <span class="sel-num">{{ selectedRows.length }}</span> 项
           </div>
@@ -170,6 +176,7 @@
             @current-change="(val) => ((pagination.page = val), loadData())"
           />
         </div>
+        </div>
       </div>
 
       <el-dialog
@@ -365,7 +372,8 @@ import ListToolbarEndActions from '@/components/business/list-toolbar-end-action
 import ListExportDropdown from '@/components/business/list-export-dropdown/index.vue'
 import ListQuickSearchInput from '@/components/business/list-quick-search-input/index.vue'
 import { usePersistedListColumns } from '@/composables/usePersistedListColumns'
-  import { ref, reactive, computed, onMounted, nextTick } from 'vue'
+import { useListTableViewportHeight } from '@/composables/useListTableViewportHeight'
+  import { ref, reactive, computed, onMounted, nextTick , onActivated } from 'vue'
   import { canDeleteByCreator, filterDeletableByCreator, allRowsDeletableByCreator, CREATOR_DELETE_TIP } from '@/utils/creator-delete'
   import { syncViewRowFromFlatList } from '@/utils/view-dialog-refresh'
   import { ElMessage, ElMessageBox } from 'element-plus'
@@ -414,6 +422,15 @@ import { useDictStore } from '@/store/modules/dict'
     resetToDefault
   } = usePersistedListColumns('system-post-list-columns', listColumnDefs)
 
+ const sysPostTableWrapRef = ref<HTMLElement | null>(null)
+ const sysPostBelowRef = ref<HTMLElement | null>(null)
+ const sysPostTableRef = ref<any>(null)
+ const { tableHeight, recalc: recalcTableHeight } = useListTableViewportHeight({
+   tableEl: sysPostTableWrapRef,
+   pagerEl: sysPostBelowRef,
+   tableRef: sysPostTableRef
+ })
+
   const dictStore = useDictStore()
 
   const searchForm = reactive<{ keyword: string }>({ keyword: '' })
@@ -869,7 +886,14 @@ import { useDictStore } from '@/store/modules/dict'
   onMounted(() => {
     loadData()
     loadDictOptions()
-  })
+  
+    nextTick(() => recalcTableHeight())
+})
+
+onActivated(() => {
+  nextTick(() => recalcTableHeight())
+})
+
 </script>
 
 <style scoped lang="scss">

+ 41 - 18
web-admin/src/views/system/role/index.vue

@@ -107,7 +107,10 @@
       </div>
 
       <div class="list-body list-wrap">
-        <ListTable
+        <div ref="sysRoleTableWrapRef" class="table-scroll bx-list-table-wrap">
+          <ListTable
+            ref="sysRoleTableRef"
+            :height="tableHeight"
           table-key="system-role"
           class="list-table"
           :data="tableData"
@@ -172,22 +175,25 @@
             header-align="center"
           />
         </ListTable>
-        <div class="pagination list-pager-bar">
-          <div class="list-pager-selected">
-            已选 <span class="sel-num">{{ selectedRows.length }}</span> 项
-          </div>
+        </div>
+        <div ref="sysRoleBelowRef">
+          <div class="pagination list-pager-bar">
+            <div class="list-pager-selected">
+              已选 <span class="sel-num">{{ selectedRows.length }}</span> 项
+            </div>
 
-          <el-pagination
-            :current-page="pagination.page"
-            :page-size="pagination.pageSize"
-            :total="pagination.total"
-            :page-sizes="[10, 20, 100, 500]"
-            layout="total, sizes, prev, pager, next"
-            @size-change="
-              (val: number) => ((pagination.page = 1), (pagination.pageSize = val), loadData())
-            "
-            @current-change="(val: number) => ((pagination.page = val), loadData())"
-          />
+            <el-pagination
+              :current-page="pagination.page"
+              :page-size="pagination.pageSize"
+              :total="pagination.total"
+              :page-sizes="[10, 20, 100, 500]"
+              layout="total, sizes, prev, pager, next"
+              @size-change="
+                (val: number) => ((pagination.page = 1), (pagination.pageSize = val), loadData())
+              "
+              @current-change="(val: number) => ((pagination.page = val), loadData())"
+            />
+          </div>
         </div>
       </div>
 
@@ -202,7 +208,8 @@
   import ListQuickSearchInput from '@/components/business/list-quick-search-input/index.vue'
   import RoleManageDialogs from '@/components/business/role-manage-dialogs/index.vue'
   import { usePersistedListColumns } from '@/composables/usePersistedListColumns'
-  import { ref, reactive, onMounted, computed } from 'vue'
+import { useListTableViewportHeight } from '@/composables/useListTableViewportHeight'
+  import { ref, reactive, onMounted, computed , onActivated } from 'vue'
   import {
     canDeleteByCreator,
     filterDeletableByCreator,
@@ -234,6 +241,15 @@
   const { visibleColumns, checkAll, isIndeterminate, isColumnVisible, resetToDefault } =
     usePersistedListColumns('system-role-list-columns', listColumnDefs)
 
+  const sysRoleTableWrapRef = ref<HTMLElement | null>(null)
+  const sysRoleBelowRef = ref<HTMLElement | null>(null)
+  const sysRoleTableRef = ref<any>(null)
+  const { tableHeight, recalc: recalcTableHeight } = useListTableViewportHeight({
+    tableEl: sysRoleTableWrapRef,
+    pagerEl: sysRoleBelowRef,
+    tableRef: sysRoleTableRef
+  })
+
   const dictStore = useDictStore()
   const dataScopeLabel = (code: string) => dictStore.getLabel('sys_data_scope', code)
 
@@ -377,5 +393,12 @@
 
   onMounted(() => {
     loadData()
-  })
+  
+    nextTick(() => recalcTableHeight())
+})
+
+onActivated(() => {
+  nextTick(() => recalcTableHeight())
+})
+
 </script>

+ 28 - 4
web-admin/src/views/system/tenant/index.vue

@@ -97,7 +97,10 @@
       </div>
 
       <div class="list-body list-wrap">
-        <ListTable table-key="system-tenant"
+        <div ref="sysTenantTableWrapRef" class="table-scroll bx-list-table-wrap">
+          <ListTable
+            ref="sysTenantTableRef"
+            :height="tableHeight" table-key="system-tenant"
           class="list-table"
           :data="tableData"
           v-loading="loading"
@@ -177,7 +180,10 @@
             header-align="center"
           />
         </ListTable>
-        <div class="pagination list-pager-bar">
+        
+        </div>
+        <div ref="sysTenantBelowRef">
+          <div class="pagination list-pager-bar">
           <div class="list-pager-selected">
             已选 <span class="sel-num">{{ selectedRows.length }}</span> 项
           </div>
@@ -192,6 +198,7 @@
             @current-change="(val) => ((pagination.page = val), loadData())"
           />
         </div>
+        </div>
       </div>
 
       <el-dialog
@@ -286,7 +293,8 @@ import ListToolbarEndActions from '@/components/business/list-toolbar-end-action
 import ListExportDropdown from '@/components/business/list-export-dropdown/index.vue'
 import ListQuickSearchInput from '@/components/business/list-quick-search-input/index.vue'
 import { usePersistedListColumns } from '@/composables/usePersistedListColumns'
-  import { ref, reactive, onMounted, computed } from 'vue'
+import { useListTableViewportHeight } from '@/composables/useListTableViewportHeight'
+  import { ref, reactive, onMounted, computed , onActivated } from 'vue'
 import { canDeleteByCreator, filterDeletableByCreator, allRowsDeletableByCreator, CREATOR_DELETE_TIP } from '@/utils/creator-delete'
 import { syncViewRowFromFlatList } from '@/utils/view-dialog-refresh'
   import { ElMessage, ElMessageBox } from 'element-plus'
@@ -330,6 +338,15 @@ import { syncViewRowFromFlatList } from '@/utils/view-dialog-refresh'
     resetToDefault
   } = usePersistedListColumns('system-tenant-list-columns', listColumnDefs)
 
+ const sysTenantTableWrapRef = ref<HTMLElement | null>(null)
+ const sysTenantBelowRef = ref<HTMLElement | null>(null)
+ const sysTenantTableRef = ref<any>(null)
+ const { tableHeight, recalc: recalcTableHeight } = useListTableViewportHeight({
+   tableEl: sysTenantTableWrapRef,
+   pagerEl: sysTenantBelowRef,
+   tableRef: sysTenantTableRef
+ })
+
   const searchForm = reactive<{ keyword: string }>({ keyword: '' })
   const quickSearchKeyword = ref('')
   const tableData = ref<Api.Tenant.TenantItem[]>([])
@@ -595,7 +612,14 @@ import { syncViewRowFromFlatList } from '@/utils/view-dialog-refresh'
 
   onMounted(() => {
     loadData()
-  })
+  
+    nextTick(() => recalcTableHeight())
+})
+
+onActivated(() => {
+  nextTick(() => recalcTableHeight())
+})
+
 </script>
 
 <style scoped lang="scss">

+ 40 - 18
web-admin/src/views/system/user/index.vue

@@ -118,7 +118,10 @@
           </div>
 
           <div class="list-body list-wrap">
-            <ListTable
+            <div ref="sysUserTableWrapRef" class="table-scroll bx-list-table-wrap">
+              <ListTable
+                ref="sysUserTableRef"
+                :height="tableHeight"
               table-key="system-user"
               class="list-table"
               :data="tableData"
@@ -228,23 +231,25 @@
                 header-align="center"
               />
             </ListTable>
+            </div>
+            <div ref="sysUserBelowRef">
+              <div class="pagination list-pager-bar">
+                <div class="list-pager-selected">
+                  已选 <span class="sel-num">{{ selectedRows.length }}</span> 项
+                </div>
 
-            <div class="pagination list-pager-bar">
-              <div class="list-pager-selected">
-                已选 <span class="sel-num">{{ selectedRows.length }}</span> 项
+                <el-pagination
+                  :current-page="pagination.page"
+                  :page-size="pagination.pageSize"
+                  :total="pagination.total"
+                  :page-sizes="[10, 20, 100, 500]"
+                  layout="total, sizes, prev, pager, next"
+                  @size-change="
+                    (val: number) => ((pagination.page = 1), (pagination.pageSize = val), loadData())
+                  "
+                  @current-change="(val: number) => ((pagination.page = val), loadData())"
+                />
               </div>
-
-              <el-pagination
-                :current-page="pagination.page"
-                :page-size="pagination.pageSize"
-                :total="pagination.total"
-                :page-sizes="[10, 20, 100, 500]"
-                layout="total, sizes, prev, pager, next"
-                @size-change="
-                  (val: number) => ((pagination.page = 1), (pagination.pageSize = val), loadData())
-                "
-                @current-change="(val: number) => ((pagination.page = val), loadData())"
-              />
             </div>
           </div>
         </div>
@@ -388,7 +393,7 @@
 </template>
 
 <script setup lang="ts">
-  import { ref, reactive, computed, onMounted, watch } from 'vue'
+  import { ref, reactive, computed, onMounted, watch , onActivated } from 'vue'
   import {
     canDeleteByCreator,
     filterDeletableByCreator,
@@ -414,6 +419,7 @@
   import ListQuickSearchInput from '@/components/business/list-quick-search-input/index.vue'
   import ListExportDropdown from '@/components/business/list-export-dropdown/index.vue'
   import { usePersistedListColumns } from '@/composables/usePersistedListColumns'
+import { useListTableViewportHeight } from '@/composables/useListTableViewportHeight'
   import {
     fetchUserList,
     fetchExportUsers,
@@ -497,6 +503,15 @@
   const { visibleColumns, checkAll, isIndeterminate, isColumnVisible, resetToDefault } =
     usePersistedListColumns('system-user-list-columns', listColumnDefs)
 
+  const sysUserTableWrapRef = ref<HTMLElement | null>(null)
+  const sysUserBelowRef = ref<HTMLElement | null>(null)
+  const sysUserTableRef = ref<any>(null)
+  const { tableHeight, recalc: recalcTableHeight } = useListTableViewportHeight({
+    tableEl: sysUserTableWrapRef,
+    pagerEl: sysUserBelowRef,
+    tableRef: sysUserTableRef
+  })
+
   function getUserExportFilterParams() {
     const quickKeyword = quickSearchKeyword.value?.trim()
     return {
@@ -867,7 +882,14 @@
     loadDeptTree()
     loadData()
     loadRoleOptions()
-  })
+  
+    nextTick(() => recalcTableHeight())
+})
+
+onActivated(() => {
+  nextTick(() => recalcTableHeight())
+})
+
 </script>
 
 <style scoped lang="scss">

この差分においてかなりの量のファイルが変更されているため、一部のファイルを表示していません