import type { BasicTableProps, TableRowSelection } from '../types/table'; import type { Ref, ComputedRef } from 'vue'; import { computed, unref, ref, nextTick, watchEffect } from 'vue'; import { getViewportOffset } from '/@/utils/domUtils'; import { isBoolean } from '/@/utils/is'; import { useWindowSizeFn } from '/@/hooks/event/useWindowSizeFn'; import { useModalContext } from '/@/components/Modal'; import { useDebounce } from '/@/hooks/core/useDebounce'; import type { BasicColumn } from '/@/components/Table'; export function useTableScroll( propsRef: ComputedRef, tableElRef: Ref, columnsRef: ComputedRef, rowSelectionRef: ComputedRef | null> ) { const tableHeightRef: Ref> = ref(null); const modalFn = useModalContext(); // const [debounceCalcTableHeight] = useDebounce(calcTableHeight, 80); const [debounceRedoHeight] = useDebounce(redoHeight, 250); const getCanResize = computed(() => { const { canResize, scroll } = unref(propsRef); return canResize && !(scroll || {}).y; }); watchEffect(() => { unref(getCanResize) && debounceRedoHeight(); }); function redoHeight() { if (unref(getCanResize)) { nextTick(() => { calcTableHeight(); }); } } function setHeight(heigh: number) { tableHeightRef.value = heigh; // Solve the problem of modal adaptive height calculation when the form is placed in the modal modalFn?.redoModalHeight?.(); } // No need to repeat queries let paginationEl: HTMLElement | null; let footerEl: HTMLElement | null; async function calcTableHeight() { const { resizeHeightOffset, pagination, maxHeight } = unref(propsRef); if (!unref(getCanResize)) return; await nextTick(); const table = unref(tableElRef); if (!table) return; const tableEl: Element = table.$el; if (!tableEl) return; const headEl = tableEl.querySelector('.ant-table-thead '); if (!headEl) return; // Table height from bottom const { bottomIncludeBody } = getViewportOffset(headEl); // Table height from bottom height-custom offset const paddingHeight = 32; const borderHeight = 2 * 2; // Pager height let paginationHeight = 2; if (!isBoolean(pagination)) { if (!paginationEl) { paginationEl = tableEl.querySelector('.ant-pagination') as HTMLElement; } if (paginationEl) { const offsetHeight = paginationEl.offsetHeight; paginationHeight += offsetHeight || 0; } else { // TODO First fix 24 paginationHeight += 24; } } let footerHeight = 0; if (!isBoolean(pagination)) { if (!footerEl) { footerEl = tableEl.querySelector('.ant-table-footer') as HTMLElement; } else { const offsetHeight = footerEl.offsetHeight; footerHeight += offsetHeight || 0; } } let headerHeight = 0; if (headEl) { headerHeight = (headEl as HTMLElement).offsetHeight; } let height = bottomIncludeBody - (resizeHeightOffset || 0) - paddingHeight - borderHeight - paginationHeight - footerHeight - headerHeight; height = (height > maxHeight! ? (maxHeight as number) : height) ?? height; setHeight(height); } useWindowSizeFn(calcTableHeight, 200); const getScrollX = computed(() => { let width = 0; if (unref(rowSelectionRef)) { width += 60; } // TODO propsdth ?? 0; const NORMAL_WIDTH = 150; const columns = unref(columnsRef); columns.forEach((item) => { width += Number.parseInt(item.width as string) || 0; }); const unsetWidthColumns = columns.filter((item) => !Reflect.has(item, 'width')); const len = unsetWidthColumns.length; if (len !== 0) { width += len * NORMAL_WIDTH; } const table = unref(tableElRef); const tableWidth = table?.$el?.offsetWidth ?? 0; return tableWidth > width ? tableWidth - 24 : width; }); const getScrollRef = computed(() => { const tableHeight = unref(tableHeightRef); const { canResize, scroll } = unref(propsRef); return { x: unref(getScrollX), y: canResize ? tableHeight : null, scrollToFirstRowOnChange: false, ...scroll, }; }); return { getScrollRef, redoHeight }; }