Просмотр исходного кода

feat(web-admin): viewport-fill list height for bx reimbursement menus

Wire remaining报销管理列表(审批/发放/付款/发票夹/费用项/流程/视图)to
useListTableViewportHeight so table body scrolls with sticky header and
pager stays ~10px above the content viewport bottom.

Co-authored-by: Cursor <cursoragent@cursor.com>
zlwu 2 месяцев назад
Родитель
Сommit
7ed3f26f9c

+ 0 - 6
web-admin/graphify-out/.graphify_labels.json

@@ -193,9 +193,7 @@
   "191": "formatYmd",
   "192": "prepareLineAliasAndBrandForSubmit",
   "193": "crm-product-display.ts",
-  "194": "index.ts",
   "195": "Community 195",
-  "196": "Community 196",
   "197": "v2.4.2.1 - 2025-06-16",
   "198": "fetchRoleOptions",
   "199": "colors.ts",
@@ -209,7 +207,6 @@
   "208": "index.vue",
   "209": "Community 209",
   "210": "Community 210",
-  "211": "navigation.ts",
   "212": "index.js",
   "213": "Community 213",
   "214": "Community 214",
@@ -263,14 +260,12 @@
   "269": "Community 269",
   "270": "Community 270",
   "271": "SettingDrawer.vue",
-  "274": "index.vue",
   "275": "index.js",
   "276": "tabs.ts",
   "277": "handleKeyDown",
   "278": "index.vue",
   "280": "Community 280",
   "281": "index.js",
-  "282": "fetchData",
   "283": "Community 283",
   "284": "Community 284",
   "285": "Community 285",
@@ -380,7 +375,6 @@
   "551": "Community 551",
   "552": "Community 552",
   "553": "Community 553",
-  "555": "Community 555",
   "556": "Community 556",
   "557": "Community 557",
   "559": "Community 559",

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

@@ -206,7 +206,6 @@
   "204": "DbCrmCustomerSelect.vue",
   "205": "loadDefaultCustomerOptions",
   "206": "onDrop",
-  "207": "SettingDrawer.vue",
   "208": "index.vue",
   "209": "Community 209",
   "210": "Community 210",
@@ -219,7 +218,6 @@
   "217": "index.js",
   "218": "price-letter.ts",
   "219": "applyBrandSelectChange",
-  "220": "detail.vue",
   "221": "index.js",
   "222": "index.vue",
   "223": "Community 223",
@@ -231,10 +229,8 @@
   "229": "useClientColumnFilters.ts",
   "230": "customerPool.ts",
   "231": "handlePublish",
-  "232": "handleConfirmApproval",
   "233": "Community 233",
   "234": "Community 234",
-  "235": "colors.ts",
   "236": "handleEdit",
   "237": "handleDisburse",
   "238": "ViewKvTableCell.vue",
@@ -243,13 +239,11 @@
   "241": "handleExportPdf",
   "242": "Community 242",
   "243": "Community 243",
-  "244": "v2.4.2.3 - 2025-06-18",
   "245": "index.js",
   "246": "fetchData",
   "247": "Community 247",
   "248": "Community 248",
   "249": "SettingItem.vue",
-  "250": "loadDefaultCustomerOptions",
   "251": "handleDisburse",
   "252": "index.js",
   "253": "Community 253",
@@ -262,23 +256,18 @@
   "260": "Community 260",
   "261": "Community 261",
   "262": "index.js",
-  "263": "canPreview",
   "264": "syncStatsColumnWidths",
   "265": "Community 265",
   "266": "crypto.ts",
   "267": "fetchData",
-  "268": "index.vue",
   "269": "Community 269",
   "270": "Community 270",
   "271": "SettingDrawer.vue",
-  "272": "index.vue",
-  "273": "canDeleteByCreator",
   "274": "index.vue",
   "275": "index.js",
   "276": "tabs.ts",
   "277": "handleKeyDown",
   "278": "index.vue",
-  "279": "fetchData",
   "280": "Community 280",
   "281": "index.js",
   "282": "fetchData",
@@ -294,7 +283,6 @@
   "294": "menuFavorite.ts",
   "295": "Community 295",
   "296": "Community 296",
-  "298": "index.vue",
   "299": "zh_CN.js",
   "300": "form.vue",
   "301": "ProcessStatusTag.vue",
@@ -308,7 +296,6 @@
   "309": "Community 309",
   "310": "Community 310",
   "311": "handleExportPdf",
-  "312": "index.vue",
   "314": "assignmentMatchesFilter",
   "315": "Community 315",
   "316": "Community 316",
@@ -346,7 +333,6 @@
   "355": "Community 355",
   "362": "Community 362",
   "367": "Community 367",
-  "372": "detail.vue",
   "377": "Community 377",
   "379": "Community 379",
   "380": "Community 380",

Разница между файлами не показана из-за своего большого размера
+ 203 - 229
web-admin/graphify-out/2026-09-01/GRAPH_REPORT.md


Разница между файлами не показана из-за своего большого размера
+ 120 - 110
web-admin/graphify-out/2026-09-01/graph.json


Разница между файлами не показана из-за своего большого размера
+ 192 - 249
web-admin/graphify-out/GRAPH_REPORT.md


Разница между файлами не показана из-за своего большого размера
+ 112 - 112
web-admin/graphify-out/graph.json


+ 31 - 16
web-admin/src/views/bx/advance/apply/index.vue

@@ -117,8 +117,11 @@
 
       <div class="list-body list-wrap">
         <div ref="advanceApplyTableWrapRef" class="table-scroll bx-list-table-wrap">
-          <ListTable table-key="bx-advance-apply"
+          <ListTable
+            ref="advanceApplyTableRef"
+            table-key="bx-advance-apply"
             class="list-table"
+            :height="tableHeight"
             :data="rows"
             v-loading="loading"
             stripe
@@ -241,6 +244,8 @@
               </template>
             </el-table-column>
           </ListTable>
+        </div>
+        <div ref="advanceApplyBelowRef">
           <ListColumnStatsRow
             ref="advanceApplyStatsRowRef"
             storage-key="bx-advance-apply-column-stats"
@@ -248,22 +253,22 @@
             :data="rows"
             :table-wrap-el="advanceApplyTableWrapRef"
           />
-        </div>
 
-        <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> 项
+            </div>
 
-          <span class="list-range">{{ rangeText }}</span>
-          <el-pagination
-            v-model:current-page="currentPage"
-            v-model:page-size="pageSize"
-            :total="total"
-            layout="total, sizes, prev, pager, next"
-            :page-sizes="[10, 20, 100, 500]"
-            @size-change="onSizeChange"
-          />
+            <span class="list-range">{{ rangeText }}</span>
+            <el-pagination
+              v-model:current-page="currentPage"
+              v-model:page-size="pageSize"
+              :total="total"
+              layout="total, sizes, prev, pager, next"
+              :page-sizes="[10, 20, 100, 500]"
+              @size-change="onSizeChange"
+            />
+          </div>
         </div>
       </div>
     </section>
@@ -445,8 +450,9 @@ import ListExportDropdown from '@/components/business/list-export-dropdown/index
 import ListColumnStatsRow from '@/components/business/list-column-stats-row/index.vue'
 import { useDbInstantSearch } from '@/composables/useDbInstantSearch'
 import { usePersistedListColumns } from '@/composables/usePersistedListColumns'
+import { useListTableViewportHeight } from '@/composables/useListTableViewportHeight'
 import ListQuickSearchInput from '@/components/business/list-quick-search-input/index.vue'
-import { reactive, ref, computed, onMounted } from 'vue'
+import { reactive, ref, computed, onMounted, nextTick } from 'vue'
 import { ElMessage, ElMessageBox } from 'element-plus'
 import type { FormInstance } from 'element-plus'
 import {
@@ -522,8 +528,16 @@ const {
 const ADVANCE_APPLY_MONEY_PROPS = new Set(['amount', 'actualAmount', 'offsetAmount'])
 
 const advanceApplyTableWrapRef = ref<HTMLElement | null>(null)
+const advanceApplyBelowRef = ref<HTMLElement | null>(null)
+const advanceApplyTableRef = ref<any>(null)
 const advanceApplyStatsRowRef = ref<{ resync?: () => void } | null>(null)
 
+const { tableHeight, recalc: recalcTableHeight } = useListTableViewportHeight({
+  tableEl: advanceApplyTableWrapRef,
+  pagerEl: advanceApplyBelowRef,
+  tableRef: advanceApplyTableRef
+})
+
 /** 列顺序与表头一致:selection、index、可选 applyTime、固定 applyCode、其余可选列 */
 const advanceApplyStatsRowColumns = computed((): StatsRowColumn[] => {
   const cols: StatsRowColumn[] = [
@@ -621,6 +635,7 @@ async function refreshList() {
 
 onMounted(() => {
   refreshList()
+  nextTick(() => recalcTableHeight())
 })
 
 function buildSearchQuery() {

+ 31 - 8
web-admin/src/views/bx/advance/approve/index.vue

@@ -91,7 +91,7 @@
 
             <div class="list-body list-wrap">
               <div ref="pendingTableWrapRef" class="table-scroll bx-list-table-wrap">
-                <ListTable table-key="bx-advance-approve"
+                <ListTable ref="pendingTableRef" :height="pendingTableHeight" table-key="bx-advance-approve"
                   class="list-table"
                   :data="pendingRows"
                   v-loading="pendingLoading"
@@ -171,6 +171,8 @@
                     </template>
                   </el-table-column>
                 </ListTable>
+              </div>
+              <div ref="pendingBelowRef">
                 <ListColumnStatsRow
                   ref="pendingStatsRowRef"
                   storage-key="bx-advance-approve-pending-column-stats"
@@ -178,9 +180,8 @@
                   :data="pendingRows"
                   :table-wrap-el="pendingTableWrapRef"
                 />
-              </div>
 
-              <div class="pagination list-pager-bar">
+                <div class="pagination list-pager-bar">
           <div class="list-pager-selected">
             已选 <span class="sel-num">{{ selectedRows.length }}</span> 项
           </div>
@@ -195,6 +196,7 @@
                   @size-change="onPendingSizeChange"
                 />
               </div>
+              </div>
             </div>
           </el-tab-pane>
 
@@ -274,7 +276,7 @@
 
             <div class="list-body list-wrap">
               <div ref="approvedTableWrapRef" class="table-scroll bx-list-table-wrap">
-                <ListTable table-key="bx-advance-approve-2"
+                <ListTable ref="approvedTableRef" :height="approvedTableHeight" table-key="bx-advance-approve-2"
                   class="list-table"
                   :data="approvedRows"
                   v-loading="approvedLoading"
@@ -366,6 +368,8 @@
                     </template>
                   </el-table-column>
                 </ListTable>
+              </div>
+              <div ref="approvedBelowRef">
                 <ListColumnStatsRow
                   ref="approvedStatsRowRef"
                   storage-key="bx-advance-approve-approved-column-stats"
@@ -373,9 +377,8 @@
                   :data="approvedRows"
                   :table-wrap-el="approvedTableWrapRef"
                 />
-              </div>
 
-              <div class="pagination list-pager-bar">
+                <div class="pagination list-pager-bar">
                 <span class="list-range">{{ approvedRangeText }}</span>
                 <el-pagination
                   v-model:current-page="approvedPage"
@@ -386,6 +389,7 @@
                   @size-change="onApprovedSizeChange"
                 />
               </div>
+              </div>
             </div>
           </el-tab-pane>
         </el-tabs>
@@ -494,7 +498,8 @@
 </template>
 
 <script setup lang="ts">
-import { reactive, ref, computed, onMounted } from 'vue'
+import { reactive, ref, computed, onMounted, nextTick} from 'vue'
+import { useListTableViewportHeight } from '@/composables/useListTableViewportHeight'
 import ListToolbarEndActions from '@/components/business/list-toolbar-end-actions/index.vue'
 import ListExportDropdown from '@/components/business/list-export-dropdown/index.vue'
 import ListColumnStatsRow from '@/components/business/list-column-stats-row/index.vue'
@@ -543,8 +548,27 @@ const {
   resetToDefault
 } = usePersistedListColumns('bx-advance-approve-list-columns', listColumnDefs)
 
+const activeTab = ref('pending')
 const pendingTableWrapRef = ref<HTMLElement | null>(null)
+const pendingBelowRef = ref<HTMLElement | null>(null)
+const pendingTableRef = ref<any>(null)
+const { tableHeight: pendingTableHeight, recalc: recalcPendingHeight } = useListTableViewportHeight({
+  tableEl: pendingTableWrapRef,
+  pagerEl: pendingBelowRef,
+  tableRef: pendingTableRef,
+  enabled: computed(() => activeTab.value === 'pending')
+})
+
 const approvedTableWrapRef = ref<HTMLElement | null>(null)
+const approvedBelowRef = ref<HTMLElement | null>(null)
+const approvedTableRef = ref<any>(null)
+const { tableHeight: approvedTableHeight, recalc: recalcApprovedHeight } = useListTableViewportHeight({
+  tableEl: approvedTableWrapRef,
+  pagerEl: approvedBelowRef,
+  tableRef: approvedTableRef,
+  enabled: computed(() => activeTab.value === 'approved')
+})
+
 const pendingStatsRowRef = ref<{ resync?: () => void } | null>(null)
 const approvedStatsRowRef = ref<{ resync?: () => void } | null>(null)
 
@@ -641,7 +665,6 @@ const advanceApproveExportColumns = computed(() => {
   return cols
 })
 
-const activeTab = ref('pending')
 
 const pendingQuickSearchKeyword = ref('')
 const approvedQuickSearchKeyword = ref('')

+ 31 - 8
web-admin/src/views/bx/advance/issue/index.vue

@@ -86,7 +86,7 @@
 
             <div class="list-body list-wrap">
               <div ref="pendingIssueTableWrapRef" class="table-scroll bx-list-table-wrap">
-                <ListTable table-key="bx-advance-issue"
+                <ListTable ref="pendingIssueTableRef" :height="pendingIssueTableHeight" table-key="bx-advance-issue"
                   class="list-table"
                   :data="rows"
                   v-loading="loading"
@@ -186,6 +186,8 @@
                     show-overflow-tooltip
                   />
                 </ListTable>
+              </div>
+              <div ref="pendingIssueBelowRef">
                 <ListColumnStatsRow
                   ref="pendingIssueStatsRowRef"
                   storage-key="bx-advance-issue-pending-column-stats"
@@ -193,9 +195,8 @@
                   :data="rows"
                   :table-wrap-el="pendingIssueTableWrapRef"
                 />
-              </div>
 
-              <div class="pagination list-pager-bar">
+                <div class="pagination list-pager-bar">
           <div class="list-pager-selected">
             已选 <span class="sel-num">{{ selectedRows.length }}</span> 项
           </div>
@@ -210,6 +211,7 @@
                   @size-change="onSizeChange"
                 />
               </div>
+              </div>
             </div>
           </el-tab-pane>
 
@@ -288,7 +290,7 @@
 
             <div class="list-body list-wrap">
               <div ref="issuedTableWrapRef" class="table-scroll bx-list-table-wrap">
-                <ListTable table-key="bx-advance-issue-2"
+                <ListTable ref="issuedTableRef" :height="issuedTableHeight" table-key="bx-advance-issue-2"
                   class="list-table"
                   :data="rows"
                   v-loading="loading"
@@ -393,6 +395,8 @@
                     header-align="center"
                   />
                 </ListTable>
+              </div>
+              <div ref="issuedBelowRef">
                 <ListColumnStatsRow
                   ref="issuedStatsRowRef"
                   storage-key="bx-advance-issue-issued-column-stats"
@@ -400,9 +404,8 @@
                   :data="rows"
                   :table-wrap-el="issuedTableWrapRef"
                 />
-              </div>
 
-              <div class="pagination list-pager-bar">
+                <div class="pagination list-pager-bar">
                 <span class="list-range">{{ rangeText }}</span>
                 <el-pagination
                   v-model:current-page="currentPage"
@@ -413,6 +416,7 @@
                   @size-change="onSizeChange"
                 />
               </div>
+              </div>
             </div>
           </el-tab-pane>
         </el-tabs>
@@ -543,7 +547,8 @@ import ListColumnStatsRow from '@/components/business/list-column-stats-row/inde
 import { useDbInstantSearch } from '@/composables/useDbInstantSearch'
 import { usePersistedListColumns } from '@/composables/usePersistedListColumns'
 import ListQuickSearchInput from '@/components/business/list-quick-search-input/index.vue'
-import { reactive, ref, computed, onMounted } from 'vue'
+import { reactive, ref, computed, onMounted, nextTick} from 'vue'
+import { useListTableViewportHeight } from '@/composables/useListTableViewportHeight'
 import { ElMessage } from 'element-plus'
 import { Check, Download, Close, Search, RefreshLeft } from '@element-plus/icons-vue'
 import { paymentApi, advanceApi } from '@/api/bx'
@@ -585,8 +590,27 @@ const {
 
 const ISSUE_MONEY_PROPS = new Set(['amount', 'actualAmount', 'offsetAmount'])
 
+const activeTab = ref('pending')
 const pendingIssueTableWrapRef = ref<HTMLElement | null>(null)
+const pendingIssueBelowRef = ref<HTMLElement | null>(null)
+const pendingIssueTableRef = ref<any>(null)
+const { tableHeight: pendingIssueTableHeight, recalc: recalcPendingIssueHeight } = useListTableViewportHeight({
+  tableEl: pendingIssueTableWrapRef,
+  pagerEl: pendingIssueBelowRef,
+  tableRef: pendingIssueTableRef,
+  enabled: computed(() => activeTab.value === 'pending')
+})
+
 const issuedTableWrapRef = ref<HTMLElement | null>(null)
+const issuedBelowRef = ref<HTMLElement | null>(null)
+const issuedTableRef = ref<any>(null)
+const { tableHeight: issuedTableHeight, recalc: recalcIssuedHeight } = useListTableViewportHeight({
+  tableEl: issuedTableWrapRef,
+  pagerEl: issuedBelowRef,
+  tableRef: issuedTableRef,
+  enabled: computed(() => activeTab.value === 'issued')
+})
+
 const pendingIssueStatsRowRef = ref<{ resync?: () => void } | null>(null)
 const issuedStatsRowRef = ref<{ resync?: () => void } | null>(null)
 
@@ -629,7 +653,6 @@ const dialogs = reactive<Record<DialogKey, boolean>>({
   view: false
 })
 
-const activeTab = ref('pending')
 
 const { applicantOptions, loadApplicantOptions } = useApplicantOptions()
 

+ 16 - 4
web-admin/src/views/bx/expense-item/index.vue

@@ -105,9 +105,12 @@
       </div>
 
       <div class="list-body list-wrap">
-        <ListTable table-key="bx-expense-item"
+        <div ref="expenseItemTableWrapRef" class="list-table-viewport-anchor">
+        <ListTable
+          table-key="bx-expense-item"
           ref="tableRef"
           class="list-table"
+          :height="tableHeight"
           :data="filteredTree"
           v-loading="loading"
           stripe
@@ -181,9 +184,9 @@
             </template>
           </el-table-column>
         </ListTable>
-      </div>
+        </div>
 
-      <div class="pagination list-pager-bar">
+      <div ref="expenseItemPagerRef" class="pagination list-pager-bar">
           <div class="list-pager-selected">
             已选 <span class="sel-num">{{ selectedRows.length }}</span> 项
           </div>
@@ -374,7 +377,8 @@ import ListExportDropdown from '@/components/business/list-export-dropdown/index
 import ListQuickSearchInput from '@/components/business/list-quick-search-input/index.vue'
 import { useDbInstantSearch } from '@/composables/useDbInstantSearch'
 import { usePersistedListColumns } from '@/composables/usePersistedListColumns'
-import { reactive, ref, onMounted, computed, watch } from 'vue'
+import { useListTableViewportHeight } from '@/composables/useListTableViewportHeight'
+import { reactive, ref, onMounted, computed, watch, nextTick } from 'vue'
 import { ElMessage, ElMessageBox } from 'element-plus'
 import type { FormInstance } from 'element-plus'
 import {
@@ -686,6 +690,13 @@ async function handleDelete(row: any) {
 }
 
 const tableRef = ref()
+const expenseItemTableWrapRef = ref<HTMLElement | null>(null)
+const expenseItemPagerRef = ref<HTMLElement | null>(null)
+const { tableHeight, recalc: recalcTableHeight } = useListTableViewportHeight({
+  tableEl: expenseItemTableWrapRef,
+  pagerEl: expenseItemPagerRef,
+  tableRef: tableRef
+})
 
 function expandAll() {
   const table = tableRef.value
@@ -770,5 +781,6 @@ watch(
 
 onMounted(() => {
   loadTree()
+  nextTick(() => recalcTableHeight())
 })
 </script>

+ 29 - 14
web-admin/src/views/bx/invoice-wallet/admin/index.vue

@@ -53,9 +53,12 @@
 
       <div class="list-body list-wrap">
         <div ref="walletAdminTableWrapRef" class="bx-list-table-wrap">
-          <ListTable table-key="bx-invoice-wallet-admin"
+          <ListTable
+            ref="walletAdminTableRef"
+            table-key="bx-invoice-wallet-admin"
             v-loading="loading"
             class="list-table"
+            :height="tableHeight"
             :data="rows"
             stripe
             @row-dblclick="openDetail"
@@ -88,6 +91,8 @@
               </template>
             </el-table-column>
           </ListTable>
+        </div>
+        <div ref="walletAdminBelowRef">
           <ListColumnStatsRow
             ref="walletAdminStatsRowRef"
             storage-key="bx-invoice-wallet-admin-column-stats"
@@ -95,18 +100,18 @@
             :data="rows"
             :table-wrap-el="walletAdminTableWrapRef"
           />
-        </div>
-        <div class="pagination list-pager-bar">
-          <el-pagination
-            v-model:current-page="page"
-            v-model:page-size="pageSize"
-            :total="total"
-            :page-sizes="[10, 20, 100, 500]"
-            layout="total, sizes, prev, pager, next"
-            background
-            @size-change="handleSearch"
-            @current-change="loadList"
-          />
+          <div class="pagination list-pager-bar">
+            <el-pagination
+              v-model:current-page="page"
+              v-model:page-size="pageSize"
+              :total="total"
+              :page-sizes="[10, 20, 100, 500]"
+              layout="total, sizes, prev, pager, next"
+              background
+              @size-change="handleSearch"
+              @current-change="loadList"
+            />
+          </div>
         </div>
       </div>
     </section>
@@ -282,7 +287,8 @@
 </template>
 
 <script setup lang="ts">
-  import { computed, onMounted, reactive, ref } from 'vue'
+  import { computed, onMounted, reactive, ref, nextTick } from 'vue'
+  import { useListTableViewportHeight } from '@/composables/useListTableViewportHeight'
   import {
     Search,
     RefreshLeft,
@@ -317,8 +323,16 @@ import ListToolbarEndActions from '@/components/business/list-toolbar-end-action
   const pageSize = ref(10)
 
   const walletAdminTableWrapRef = ref<HTMLElement | null>(null)
+  const walletAdminBelowRef = ref<HTMLElement | null>(null)
+  const walletAdminTableRef = ref<any>(null)
   const walletAdminStatsRowRef = ref<{ resync?: () => void } | null>(null)
 
+  const { tableHeight, recalc: recalcTableHeight } = useListTableViewportHeight({
+    tableEl: walletAdminTableWrapRef,
+    pagerEl: walletAdminBelowRef,
+    tableRef: walletAdminTableRef
+  })
+
   const walletAdminStatsRowColumns = computed((): StatsRowColumn[] => [
     { key: '__index', interactive: false },
     { key: 'ownerUserName', interactive: true, prop: 'ownerUserName' },
@@ -568,6 +582,7 @@ import ListToolbarEndActions from '@/components/business/list-toolbar-end-action
   onMounted(() => {
     loadList()
     loadApplicantOptions()
+    nextTick(() => recalcTableHeight())
   })
 </script>
 

+ 33 - 2
web-admin/src/views/bx/invoice-wallet/mine/index.vue

@@ -73,9 +73,12 @@
         <el-tab-pane label="发票列表" name="invoices">
           <div class="list-body list-wrap">
             <div ref="invoiceTableWrapRef" class="bx-list-table-wrap">
-              <ListTable table-key="bx-invoice-wallet-mine"
+              <ListTable
+                ref="invoiceTableRef"
+                table-key="bx-invoice-wallet-mine"
                 v-loading="loading"
                 class="list-table"
+                :height="invoiceTableHeight"
                 :data="filteredInvoiceRows"
                 stripe
                 @row-dblclick="openInvoiceView"
@@ -107,6 +110,8 @@
                 </el-table-column>
                 <el-table-column prop="createTime" label="上传时间" min-width="140" />
               </ListTable>
+            </div>
+            <div ref="invoiceBelowRef">
               <ListColumnStatsRow
                 ref="invoiceStatsRowRef"
                 storage-key="bx-invoice-wallet-mine-invoices-column-stats"
@@ -121,9 +126,11 @@
           <div class="list-body list-wrap">
             <div ref="ledgerTableWrapRef" class="bx-list-table-wrap">
               <ListTable
+                ref="ledgerTableRef"
                 table-key="bx-invoice-wallet-mine-2"
                 v-loading="ledgerLoading"
                 class="list-table"
+                :height="ledgerTableHeight"
                 :data="filteredLedgerRows"
                 stripe
                 @header-dragend="() => ledgerStatsRowRef?.resync?.()"
@@ -144,6 +151,8 @@
                   <template #default="{ row }">{{ row.remark || '-' }}</template>
                 </el-table-column>
               </ListTable>
+            </div>
+            <div ref="ledgerBelowRef">
               <ListColumnStatsRow
                 ref="ledgerStatsRowRef"
                 storage-key="bx-invoice-wallet-mine-ledgers-column-stats"
@@ -257,12 +266,13 @@
 </template>
 
 <script setup lang="ts">
-  import { computed, onMounted, reactive, ref } from 'vue'
+  import { computed, onMounted, reactive, ref, nextTick } from 'vue'
   import { Upload, Close, Check, Search, RefreshLeft, View } from '@element-plus/icons-vue'
   import { ElMessage } from 'element-plus'
   import ListQuickSearchInput from '@/components/business/list-quick-search-input/index.vue'
   import ListToolbarEndActions from '@/components/business/list-toolbar-end-actions/index.vue'
   import ListColumnStatsRow from '@/components/business/list-column-stats-row/index.vue'
+  import { useListTableViewportHeight } from '@/composables/useListTableViewportHeight'
   import type { StatsRowColumn } from '@/utils/list-column-stats'
   import BxInvoiceFileSelect from '@/components/bx/base/BxInvoiceFileSelect.vue'
   import BxAttachmentReadonly from '@/components/bx/base/BxAttachmentReadonly.vue'
@@ -289,9 +299,26 @@
   const summary = ref<any>(null)
 
   const invoiceTableWrapRef = ref<HTMLElement | null>(null)
+  const invoiceBelowRef = ref<HTMLElement | null>(null)
+  const invoiceTableRef = ref<any>(null)
   const invoiceStatsRowRef = ref<{ resync?: () => void } | null>(null)
+  const { tableHeight: invoiceTableHeight, recalc: recalcInvoiceHeight } = useListTableViewportHeight({
+    tableEl: invoiceTableWrapRef,
+    pagerEl: invoiceBelowRef,
+    tableRef: invoiceTableRef,
+    enabled: computed(() => activeTab.value === 'invoices')
+  })
+
   const ledgerTableWrapRef = ref<HTMLElement | null>(null)
+  const ledgerBelowRef = ref<HTMLElement | null>(null)
+  const ledgerTableRef = ref<any>(null)
   const ledgerStatsRowRef = ref<{ resync?: () => void } | null>(null)
+  const { tableHeight: ledgerTableHeight, recalc: recalcLedgerHeight } = useListTableViewportHeight({
+    tableEl: ledgerTableWrapRef,
+    pagerEl: ledgerBelowRef,
+    tableRef: ledgerTableRef,
+    enabled: computed(() => activeTab.value === 'ledgers')
+  })
 
   const invoiceStatsRowColumns = computed((): StatsRowColumn[] => [
     { key: '__index', interactive: false },
@@ -546,6 +573,10 @@
 
   onMounted(() => {
     reloadAll()
+    nextTick(() => {
+      recalcInvoiceHeight()
+      recalcLedgerHeight()
+    })
   })
 </script>
 

+ 31 - 8
web-admin/src/views/bx/payment/index.vue

@@ -91,7 +91,7 @@
 
             <div class="list-body list-wrap">
               <div ref="pendingPaymentTableWrapRef" class="table-scroll bx-list-table-wrap">
-                <ListTable table-key="bx-payment"
+                <ListTable ref="pendingPaymentTableRef" :height="pendingPaymentTableHeight" table-key="bx-payment"
                   class="list-table"
                   :data="rows"
                   v-loading="loading"
@@ -182,6 +182,8 @@
                     </template>
                   </el-table-column>
                 </ListTable>
+              </div>
+              <div ref="pendingPaymentBelowRef">
                 <ListColumnStatsRow
                   ref="pendingPaymentStatsRowRef"
                   storage-key="bx-payment-pending-column-stats"
@@ -190,9 +192,8 @@
                   :table-wrap-el="pendingPaymentTableWrapRef"
                   :get-cell-value="getPaymentStatCellValue"
                 />
-              </div>
 
-              <div class="pagination list-pager-bar">
+                <div class="pagination list-pager-bar">
           <div class="list-pager-selected">
             已选 <span class="sel-num">{{ selectedRows.length }}</span> 项
           </div>
@@ -207,6 +208,7 @@
                   @size-change="onSizeChange"
                 />
               </div>
+              </div>
             </div>
           </el-tab-pane>
 
@@ -296,7 +298,7 @@
 
             <div class="list-body list-wrap">
               <div ref="processedPaymentTableWrapRef" class="table-scroll bx-list-table-wrap">
-                <ListTable table-key="bx-payment-2"
+                <ListTable ref="processedPaymentTableRef" :height="processedPaymentTableHeight" table-key="bx-payment-2"
                   class="list-table"
                   :data="processedRows"
                   v-loading="processedLoading"
@@ -410,6 +412,8 @@
                     </template>
                   </el-table-column>
                 </ListTable>
+              </div>
+              <div ref="processedPaymentBelowRef">
                 <ListColumnStatsRow
                   ref="processedPaymentStatsRowRef"
                   storage-key="bx-payment-processed-column-stats"
@@ -418,9 +422,8 @@
                   :table-wrap-el="processedPaymentTableWrapRef"
                   :get-cell-value="getPaymentStatCellValue"
                 />
-              </div>
 
-              <div class="pagination list-pager-bar">
+                <div class="pagination list-pager-bar">
                 <span class="list-range">{{ processedRangeText }}</span>
                 <el-pagination
                   v-model:current-page="processedCurrentPage"
@@ -431,6 +434,7 @@
                   @size-change="processedOnSizeChange"
                 />
               </div>
+              </div>
             </div>
           </el-tab-pane>
         </el-tabs>
@@ -714,7 +718,8 @@ import ListColumnStatsRow from '@/components/business/list-column-stats-row/inde
 import { useDbInstantSearch } from '@/composables/useDbInstantSearch'
 import { usePersistedListColumns } from '@/composables/usePersistedListColumns'
 import ListQuickSearchInput from '@/components/business/list-quick-search-input/index.vue'
-import { reactive, ref, computed, onMounted } from 'vue'
+import { reactive, ref, computed, onMounted, nextTick} from 'vue'
+import { useListTableViewportHeight } from '@/composables/useListTableViewportHeight'
 import { ElMessage, ElMessageBox } from 'element-plus'
 import {
   View,
@@ -764,8 +769,27 @@ const {
 
 const PAYMENT_MONEY_PROPS = new Set(['amount', 'offsetAmount', 'payAmount'])
 
+const activeTab = ref('pending')
 const pendingPaymentTableWrapRef = ref<HTMLElement | null>(null)
+const pendingPaymentBelowRef = ref<HTMLElement | null>(null)
+const pendingPaymentTableRef = ref<any>(null)
+const { tableHeight: pendingPaymentTableHeight, recalc: recalcPendingPaymentHeight } = useListTableViewportHeight({
+  tableEl: pendingPaymentTableWrapRef,
+  pagerEl: pendingPaymentBelowRef,
+  tableRef: pendingPaymentTableRef,
+  enabled: computed(() => activeTab.value === 'pending')
+})
+
 const processedPaymentTableWrapRef = ref<HTMLElement | null>(null)
+const processedPaymentBelowRef = ref<HTMLElement | null>(null)
+const processedPaymentTableRef = ref<any>(null)
+const { tableHeight: processedPaymentTableHeight, recalc: recalcProcessedPaymentHeight } = useListTableViewportHeight({
+  tableEl: processedPaymentTableWrapRef,
+  pagerEl: processedPaymentBelowRef,
+  tableRef: processedPaymentTableRef,
+  enabled: computed(() => activeTab.value === 'processed')
+})
+
 const pendingPaymentStatsRowRef = ref<{ resync?: () => void } | null>(null)
 const processedPaymentStatsRowRef = ref<{ resync?: () => void } | null>(null)
 
@@ -925,7 +949,6 @@ const paymentExportColumns = computed(() => {
   return cols
 })
 
-const activeTab = ref('pending')
 const tabLoaded = reactive({ pending: true, processed: false })
 
 const processedFilterForm = reactive({

+ 31 - 8
web-admin/src/views/bx/reimburse/approve/index.vue

@@ -118,7 +118,7 @@
 
             <div class="list-body list-wrap">
               <div ref="pendingTableWrapRef" class="table-scroll bx-list-table-wrap">
-                <ListTable table-key="bx-reimburse-approve"
+                <ListTable ref="pendingTableRef" :height="pendingTableHeight" table-key="bx-reimburse-approve"
                   class="list-table"
                   :data="pendingRows"
                   v-loading="pendingLoading"
@@ -219,6 +219,8 @@
                     </template>
                   </el-table-column>
                 </ListTable>
+              </div>
+              <div ref="pendingBelowRef">
                 <ListColumnStatsRow
                   ref="pendingStatsRowRef"
                   storage-key="bx-reimburse-approve-pending-column-stats"
@@ -227,9 +229,8 @@
                   :table-wrap-el="pendingTableWrapRef"
                   :get-cell-value="getReimburseApproveStatCellValue"
                 />
-              </div>
 
-              <div class="pagination list-pager-bar">
+                <div class="pagination list-pager-bar">
           <div class="list-pager-selected">
             已选 <span class="sel-num">{{ selectedRows.length }}</span> 项
           </div>
@@ -244,6 +245,7 @@
                   @size-change="onPendingSizeChange"
                 />
               </div>
+              </div>
             </div>
           </el-tab-pane>
 
@@ -350,7 +352,7 @@
 
             <div class="list-body list-wrap">
               <div ref="approvedTableWrapRef" class="table-scroll bx-list-table-wrap">
-                <ListTable table-key="bx-reimburse-approve-2"
+                <ListTable ref="approvedTableRef" :height="approvedTableHeight" table-key="bx-reimburse-approve-2"
                   class="list-table"
                   :data="approvedRows"
                   v-loading="approvedLoading"
@@ -463,6 +465,8 @@
                     </template>
                   </el-table-column>
                 </ListTable>
+              </div>
+              <div ref="approvedBelowRef">
                 <ListColumnStatsRow
                   ref="approvedStatsRowRef"
                   storage-key="bx-reimburse-approve-approved-column-stats"
@@ -471,9 +475,8 @@
                   :table-wrap-el="approvedTableWrapRef"
                   :get-cell-value="getReimburseApproveStatCellValue"
                 />
-              </div>
 
-              <div class="pagination list-pager-bar">
+                <div class="pagination list-pager-bar">
                 <span class="list-range">{{ approvedRangeText }}</span>
                 <el-pagination
                   v-model:current-page="approvedPage"
@@ -484,6 +487,7 @@
                   @size-change="onApprovedSizeChange"
                 />
               </div>
+              </div>
             </div>
           </el-tab-pane>
         </el-tabs>
@@ -630,12 +634,13 @@
 </template>
 
 <script setup lang="ts">
-import { reactive, ref, computed, onMounted } from 'vue'
+import { reactive, ref, computed, onMounted, nextTick} from 'vue'
 import ListToolbarEndActions from '@/components/business/list-toolbar-end-actions/index.vue'
 import ListExportDropdown from '@/components/business/list-export-dropdown/index.vue'
 import ListColumnStatsRow from '@/components/business/list-column-stats-row/index.vue'
 import { useDbInstantSearch } from '@/composables/useDbInstantSearch'
 import { usePersistedListColumns } from '@/composables/usePersistedListColumns'
+import { useListTableViewportHeight } from '@/composables/useListTableViewportHeight'
 import ListQuickSearchInput from '@/components/business/list-quick-search-input/index.vue'
 import { ElMessage } from 'element-plus'
 import {
@@ -691,8 +696,27 @@ const {
   resetToDefault
 } = usePersistedListColumns('bx-reimburse-approve-list-columns', listColumnDefs)
 
+const activeTab = ref('pending')
 const pendingTableWrapRef = ref<HTMLElement | null>(null)
+const pendingBelowRef = ref<HTMLElement | null>(null)
+const pendingTableRef = ref<any>(null)
+const { tableHeight: pendingTableHeight, recalc: recalcPendingHeight } = useListTableViewportHeight({
+  tableEl: pendingTableWrapRef,
+  pagerEl: pendingBelowRef,
+  tableRef: pendingTableRef,
+  enabled: computed(() => activeTab.value === 'pending')
+})
+
 const approvedTableWrapRef = ref<HTMLElement | null>(null)
+const approvedBelowRef = ref<HTMLElement | null>(null)
+const approvedTableRef = ref<any>(null)
+const { tableHeight: approvedTableHeight, recalc: recalcApprovedHeight } = useListTableViewportHeight({
+  tableEl: approvedTableWrapRef,
+  pagerEl: approvedBelowRef,
+  tableRef: approvedTableRef,
+  enabled: computed(() => activeTab.value === 'approved')
+})
+
 const pendingStatsRowRef = ref<{ resync?: () => void } | null>(null)
 const approvedStatsRowRef = ref<{ resync?: () => void } | null>(null)
 
@@ -802,7 +826,6 @@ const reimburseApproveExportColumns = computed(() => {
   return cols
 })
 
-const activeTab = ref('pending')
 const menuStore = useMenuStore()
 
 const viewData = ref<Record<string, any>>({})

+ 26 - 12
web-admin/src/views/bx/view/all/index.vue

@@ -106,8 +106,10 @@
       <div class="list-body list-wrap">
         <div ref="allTableWrapRef" class="table-scroll bx-list-table-wrap">
           <ListTable
+            ref="allTableRef"
             table-key="bx-view-all"
             class="list-table"
+            :height="tableHeight"
             :data="pager.pagedRows.value"
             v-loading="loading"
             stripe
@@ -220,6 +222,8 @@
               </template>
             </el-table-column>
           </ListTable>
+        </div>
+        <div ref="allBelowRef">
           <ListColumnStatsRow
             ref="allStatsRowRef"
             storage-key="bx-view-all-column-stats"
@@ -227,18 +231,18 @@
             :data="pager.pagedRows.value"
             :table-wrap-el="allTableWrapRef"
           />
-        </div>
 
-        <div class="pagination list-pager-bar">
-          <span class="list-range">{{ pager.rangeText.value }}</span>
-          <el-pagination
-            v-model:current-page="pager.currentPage.value"
-            v-model:page-size="pager.pageSize.value"
-            :total="pager.total.value"
-            layout="total, sizes, prev, pager, next"
-            :page-sizes="[10, 20, 100, 500]"
-            @size-change="pager.onSizeChange"
-          />
+          <div class="pagination list-pager-bar">
+            <span class="list-range">{{ pager.rangeText.value }}</span>
+            <el-pagination
+              v-model:current-page="pager.currentPage.value"
+              v-model:page-size="pager.pageSize.value"
+              :total="pager.total.value"
+              layout="total, sizes, prev, pager, next"
+              :page-sizes="[10, 20, 100, 500]"
+              @size-change="pager.onSizeChange"
+            />
+          </div>
         </div>
       </div>
     </section>
@@ -388,7 +392,8 @@ import ListExportDropdown from '@/components/business/list-export-dropdown/index
   import type { StatsRowColumn } from '@/utils/list-column-stats'
   import { useDbInstantSearch } from '@/composables/useDbInstantSearch'
   import { usePersistedListColumns } from '@/composables/usePersistedListColumns'
-  import { computed, onMounted, reactive, ref } from 'vue'
+  import { useListTableViewportHeight } from '@/composables/useListTableViewportHeight'
+  import { computed, onMounted, reactive, ref, nextTick } from 'vue'
   import { ElMessage } from 'element-plus'
   import { Search, RefreshLeft } from '@element-plus/icons-vue'
   import { advanceApi, paymentApi, reimburseApi } from '@/api/bx'
@@ -488,8 +493,16 @@ const selectedRows = ref<any[]>([])
     usePersistedListColumns('bx-view-all-list-columns', listColumnDefs)
 
   const allTableWrapRef = ref<HTMLElement | null>(null)
+  const allBelowRef = ref<HTMLElement | null>(null)
+  const allTableRef = ref<any>(null)
   const allStatsRowRef = ref<{ resync?: () => void } | null>(null)
 
+  const { tableHeight, recalc: recalcTableHeight } = useListTableViewportHeight({
+    tableEl: allTableWrapRef,
+    pagerEl: allBelowRef,
+    tableRef: allTableRef
+  })
+
   const allStatsRowColumns = computed((): StatsRowColumn[] => {
     const cols: StatsRowColumn[] = [
       { key: '__selection', interactive: false },
@@ -877,6 +890,7 @@ const selectedRows = ref<any[]>([])
   onMounted(() => {
     loadApplicantOptions()
     loadData()
+    nextTick(() => recalcTableHeight())
   })
 </script>
 

+ 30 - 15
web-admin/src/views/bx/view/todo/index.vue

@@ -120,8 +120,10 @@
       <div class="list-body list-wrap">
         <div ref="todoTableWrapRef" class="table-scroll bx-list-table-wrap">
           <ListTable
+            ref="todoTableRef"
             table-key="bx-view-todo"
             class="list-table"
+            :height="tableHeight"
             :data="pagedRows"
             v-loading="tableLoading"
             stripe
@@ -220,6 +222,8 @@
               </template>
             </el-table-column>
           </ListTable>
+        </div>
+        <div ref="todoBelowRef">
           <ListColumnStatsRow
             ref="todoStatsRowRef"
             storage-key="bx-view-todo-column-stats"
@@ -227,22 +231,22 @@
             :data="pagedRows"
             :table-wrap-el="todoTableWrapRef"
           />
-        </div>
 
-        <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> 项
+            </div>
 
-          <span class="list-range">{{ rangeText }}</span>
-          <el-pagination
-            v-model:current-page="currentPage"
-            v-model:page-size="pageSize"
-            :total="filteredTotal"
-            layout="total, sizes, prev, pager, next"
-            :page-sizes="[10, 20, 100, 500]"
-            @size-change="onSizeChange"
-          />
+            <span class="list-range">{{ rangeText }}</span>
+            <el-pagination
+              v-model:current-page="currentPage"
+              v-model:page-size="pageSize"
+              :total="filteredTotal"
+              layout="total, sizes, prev, pager, next"
+              :page-sizes="[10, 20, 100, 500]"
+              @size-change="onSizeChange"
+            />
+          </div>
         </div>
       </div>
     </section>
@@ -453,8 +457,9 @@ import ListExportDropdown from '@/components/business/list-export-dropdown/index
   import type { StatsRowColumn } from '@/utils/list-column-stats'
   import { useDbInstantSearch } from '@/composables/useDbInstantSearch'
   import { usePersistedListColumns } from '@/composables/usePersistedListColumns'
+  import { useListTableViewportHeight } from '@/composables/useListTableViewportHeight'
   import ListQuickSearchInput from '@/components/business/list-quick-search-input/index.vue'
-  import { computed, onActivated, onMounted, reactive, ref } from 'vue'
+  import { computed, onActivated, onMounted, reactive, ref, nextTick } from 'vue'
   import { ElMessage } from 'element-plus'
   import { Check, Close, Search, RefreshLeft } from '@element-plus/icons-vue'
   import { advanceApi, paymentApi, reimburseApi } from '@/api/bx'
@@ -515,8 +520,16 @@ import ListExportDropdown from '@/components/business/list-export-dropdown/index
     usePersistedListColumns('bx-view-todo-list-columns', listColumnDefs)
 
   const todoTableWrapRef = ref<HTMLElement | null>(null)
+  const todoBelowRef = ref<HTMLElement | null>(null)
+  const todoTableRef = ref<any>(null)
   const todoStatsRowRef = ref<{ resync?: () => void } | null>(null)
 
+  const { tableHeight, recalc: recalcTableHeight } = useListTableViewportHeight({
+    tableEl: todoTableWrapRef,
+    pagerEl: todoBelowRef,
+    tableRef: todoTableRef
+  })
+
   const todoStatsRowColumns = computed((): StatsRowColumn[] => {
     const cols: StatsRowColumn[] = [
       { key: '__selection', interactive: false },
@@ -1014,10 +1027,12 @@ const selectedRows = ref<any[]>([])
   onMounted(() => {
     loadApplicantOptions()
     loadData()
+    nextTick(() => recalcTableHeight())
   })
 
   onActivated(() => {
     loadData()
+    nextTick(() => recalcTableHeight())
   })
 </script>
 

+ 19 - 4
web-admin/src/views/bx/workflow/advance/index.vue

@@ -64,8 +64,12 @@
       </div>
 
       <div class="list-body list-wrap">
-        <ListTable table-key="bx-workflow-advance"
+        <div ref="wfAdvanceTableWrapRef" class="list-table-viewport-anchor">
+        <ListTable
+          ref="wfAdvanceTableRef"
+          table-key="bx-workflow-advance"
           class="list-table"
+          :height="tableHeight"
           :data="filteredNodes"
           v-loading="loading"
           stripe
@@ -113,9 +117,9 @@
             </template>
           </el-table-column>
         </ListTable>
-      </div>
+        </div>
 
-      <div class="pagination list-pager-bar">
+      <div ref="wfAdvancePagerRef" class="pagination list-pager-bar">
           <div class="list-pager-selected">
             已选 <span class="sel-num">{{ selectedRows.length }}</span> 项
           </div>
@@ -223,10 +227,11 @@
 </template>
 
 <script setup lang="ts">
-import { reactive, ref, computed, onMounted } from 'vue'
+import { reactive, ref, computed, onMounted, nextTick } from 'vue'
 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 { canDeleteByCreator, filterDeletableByCreator, allRowsDeletableByCreator, CREATOR_DELETE_TIP } from '@/utils/creator-delete'
 import { ElMessage, ElMessageBox } from 'element-plus'
 import type { FormInstance } from 'element-plus'
@@ -268,6 +273,15 @@ const {
   isColumnVisible,
   resetToDefault
 } = usePersistedListColumns('bx-workflow-advance-list-columns', listColumnDefs)
+
+const wfAdvanceTableWrapRef = ref<HTMLElement | null>(null)
+const wfAdvancePagerRef = ref<HTMLElement | null>(null)
+const wfAdvanceTableRef = ref<any>(null)
+const { tableHeight, recalc: recalcTableHeight } = useListTableViewportHeight({
+  tableEl: wfAdvanceTableWrapRef,
+  pagerEl: wfAdvancePagerRef,
+  tableRef: wfAdvanceTableRef
+})
 const loading = ref(false)
 const selectedRows = ref<Record<string, any>[]>([])
 const wfDef = ref<Record<string, any>>({})
@@ -339,6 +353,7 @@ async function loadWfDef() {
 onMounted(() => {
   loadWfDef()
   loadUsers()
+  nextTick(() => recalcTableHeight())
 })
 
 function onSelectionChange(rows: Record<string, any>[]) {

+ 19 - 4
web-admin/src/views/bx/workflow/reimburse/index.vue

@@ -64,8 +64,12 @@
       </div>
 
       <div class="list-body list-wrap">
-        <ListTable table-key="bx-workflow-reimburse"
+        <div ref="wfReimburseTableWrapRef" class="list-table-viewport-anchor">
+        <ListTable
+          ref="wfReimburseTableRef"
+          table-key="bx-workflow-reimburse"
           class="list-table"
+          :height="tableHeight"
           :data="filteredNodes"
           v-loading="loading"
           stripe
@@ -113,9 +117,9 @@
             </template>
           </el-table-column>
         </ListTable>
-      </div>
+        </div>
 
-      <div class="pagination list-pager-bar">
+      <div ref="wfReimbursePagerRef" class="pagination list-pager-bar">
           <div class="list-pager-selected">
             已选 <span class="sel-num">{{ selectedRows.length }}</span> 项
           </div>
@@ -223,10 +227,11 @@
 </template>
 
 <script setup lang="ts">
-import { reactive, ref, computed, onMounted } from 'vue'
+import { reactive, ref, computed, onMounted, nextTick } from 'vue'
 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 { canDeleteByCreator, filterDeletableByCreator, allRowsDeletableByCreator, CREATOR_DELETE_TIP } from '@/utils/creator-delete'
 import { ElMessage, ElMessageBox } from 'element-plus'
 import type { FormInstance } from 'element-plus'
@@ -268,6 +273,15 @@ const {
   isColumnVisible,
   resetToDefault
 } = usePersistedListColumns('bx-workflow-reimburse-list-columns', listColumnDefs)
+
+const wfReimburseTableWrapRef = ref<HTMLElement | null>(null)
+const wfReimbursePagerRef = ref<HTMLElement | null>(null)
+const wfReimburseTableRef = ref<any>(null)
+const { tableHeight, recalc: recalcTableHeight } = useListTableViewportHeight({
+  tableEl: wfReimburseTableWrapRef,
+  pagerEl: wfReimbursePagerRef,
+  tableRef: wfReimburseTableRef
+})
 const loading = ref(false)
 const selectedRows = ref<Record<string, any>[]>([])
 const wfDef = ref<Record<string, any>>({})
@@ -339,6 +353,7 @@ async function loadWfDef() {
 onMounted(() => {
   loadWfDef()
   loadUsers()
+  nextTick(() => recalcTableHeight())
 })
 
 function onSelectionChange(rows: Record<string, any>[]) {

Некоторые файлы не были показаны из-за большого количества измененных файлов