/* eslint-disable @typescript-eslint/ban-ts-comment */ // src/hooks/usePagination.ts import { computed, ref, Ref, triggerRef } from 'vue'; import { useEffect } from './useEffect'; /** * 分页配置项 */ export interface UsePaginationOptions { /** 当前页码 (支持 v-model 双向绑定) */ current?: number; /** 每页条数 (支持 v-model 双向绑定) */ pageSize?: number; /** 数据总条数 (支持 v-model 双向绑定) */ total?: number; /** 默认页码 (非受控模式下使用) */ defaultCurrent?: number; /** 默认每页条数 (非受控模式下使用) */ defaultPageSize?: number; /** 每页条数切换选项 (用于生成下拉菜单) */ pageSizeOptions?: number[]; /** 是否显示快速跳转 (可选功能) */ showQuickJumper?: boolean; } /** * 分页操作 API */ export interface UsePaginationActions { /** 设置当前页 */ setCurrent: (current: number) => void; /** 设置每页条数 (会自动重置页码为 1) */ setPageSize: (size: number) => void; /** 设置总条数 */ setTotal: (total: number) => void; /** 下一页 */ next: () => void; /** 上一页 */ prev: () => void; /** 跳转到指定页 */ jump: (page: number) => void; /** 重置到初始状态 */ reset: () => void; /** 强制刷新 (用于某些极端响应式场景) */ refresh: () => void; } /** * 分页计算属性 */ export interface UsePaginationComputed { /** 响应式请求参数对象 (给 API 用的) */ params: Ref<{ page: number; pageSize: number }>; /** 总页数 */ totalPages: Ref; /** 是否有上一页 */ hasPrev: Ref; /** 是否有下一页 */ hasNext: Ref; /** 当前页起始索引 (用于显示 "显示 1-10 条") */ startIndex: Ref; /** 当前页结束索引 */ endIndex: Ref; /** 是否为第一页 */ isFirstPage: Ref; /** 是否为最后一页 */ isLastPage: Ref; } export type UsePaginationReturn = UsePaginationOptions & UsePaginationActions & UsePaginationComputed; export function usePagination(options: UsePaginationOptions = {}): UsePaginationReturn { const { defaultCurrent = 1, defaultPageSize = 10, pageSizeOptions = [10, 20, 50, 100] } = options; const currentRef = ref(options.current ?? defaultCurrent); const pageSizeRef = ref(options.pageSize ?? defaultPageSize); const totalRef = ref(options.total ?? 0); useEffect(() => { const val = options.current; if (val !== undefined) currentRef.value = val; }, [() => options.current]); useEffect(() => { const val = options.pageSize; if (val !== undefined) pageSizeRef.value = val; }, [() => options.pageSize]); useEffect(() => { const val = options.total; if (val !== undefined) totalRef.value = val; }, [() => options.total]); const totalPages = computed(() => { const total = totalRef.value; const size = pageSizeRef.value; return size === 0 ? 0 : Math.ceil(total / size); }); const hasPrev = computed(() => currentRef.value > 1); const hasNext = computed(() => currentRef.value < totalPages.value); const isFirstPage = computed(() => currentRef.value === 1); const isLastPage = computed(() => currentRef.value === totalPages.value); const startIndex = computed(() => totalPages.value === 0 ? 0 : (currentRef.value - 1) * pageSizeRef.value + 1, ); const endIndex = computed(() => Math.min(currentRef.value * pageSizeRef.value, totalRef.value)); const params = computed(() => ({ page: currentRef.value, pageSize: pageSizeRef.value, })); const setCurrent = (page: number) => { const safePage = Math.max(1, Math.min(page, totalPages.value || 1)); if (currentRef.value !== safePage) { currentRef.value = safePage; } }; const setPageSize = (size: number) => { if (pageSizeRef.value !== size) { pageSizeRef.value = size; currentRef.value = 1; } }; const setTotal = (total: number) => { totalRef.value = total; const maxPage = Math.max(1, Math.ceil(total / pageSizeRef.value)); if (currentRef.value > maxPage) { currentRef.value = maxPage; } }; const next = () => setCurrent(currentRef.value + 1); const prev = () => setCurrent(currentRef.value - 1); const jump = (page: number) => { if (!Number.isInteger(page) || page < 1) return; setCurrent(page); }; const reset = () => { currentRef.value = defaultCurrent; pageSizeRef.value = defaultPageSize; }; const refresh = () => { triggerRef(currentRef); }; return { // @ts-ignore current: currentRef, // @ts-ignore pageSize: pageSizeRef, // @ts-ignore total: totalRef, pageSizeOptions, params, totalPages, hasPrev, hasNext, isFirstPage, isLastPage, startIndex, endIndex, setCurrent, setPageSize, setTotal, next, prev, jump, reset, refresh, }; } /** 将接口返回的分页 total 同步到 pagination(支持 number / 数字字符串,含 0) */ export function syncPaginationTotal( pagination: Pick, total: unknown, ): void { if (total == null || total === '') return; const n = Number(total); if (Number.isFinite(n)) pagination.setTotal(n); }