feat: 表格分页支持统一配置并记忆各表格每页条数
- 后端新增聚合用户偏好 paginationPrefs(每页条数候选列表与默认每页条数),提供 GET/PUT /api/setting/pagination-prefs,默认候选 [10,20,50,100]、默认每页 20,非法值自动过滤并回退 - 后端新增 /category/page、/tag/page、/channel/page、/email-bill/configs/page、/email-bill/sender-rules/page 分页接口,原全量接口保持不变以免影响下拉、筛选、AI 与导出 - 前端新增共享 composables/usePageSizeOptions.ts 与 useTablePageSize.ts,所有表格统一取用候选列表并记住各自上次选择的每页条数,优先级为表格记忆 > 全局默认 > 20 - 各表格上次选择以聚合偏好 finance.pagination.tablePageSizes 存于本机 localStorage,收支记录页旧的 filterPrefs.pageSize 自动迁移 - 设置页外观设置新增「表格每页条数选项」分组,可增删候选值并配置默认每页条数,保存后全局即时生效 - 路由守卫在已登录时预加载分页偏好,保证表格页首次渲染即使用配置值 - 前端分类、标签、渠道、邮箱配置、发件人规则表格接入后端分页 - 补充中文、英文、日文三语文案
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
// 表格分页偏好:所有表格共用的每页条数候选列表与默认每页条数,统一从后端用户设置读取,未配置时回退默认值
|
||||
import { ref } from 'vue'
|
||||
import { getPaginationPrefs } from '../api/setting'
|
||||
|
||||
/** 默认每页条数候选列表 */
|
||||
export const DEFAULT_PAGE_SIZE_OPTIONS: number[] = [10, 20, 50, 100]
|
||||
|
||||
/** 默认每页条数 */
|
||||
export const DEFAULT_PAGE_SIZE = 20
|
||||
|
||||
// 模块级单例,供所有表格响应式共享
|
||||
const pageSizeOptions = ref<number[]>([...DEFAULT_PAGE_SIZE_OPTIONS])
|
||||
const defaultPageSize = ref<number>(DEFAULT_PAGE_SIZE)
|
||||
let loaded = false
|
||||
|
||||
/** 将后端返回值规范化为升序去重的正整数数组,非法时回退默认 */
|
||||
function normalizeOptions(data: unknown): number[] {
|
||||
if (!Array.isArray(data)) return [...DEFAULT_PAGE_SIZE_OPTIONS]
|
||||
const list = data.map((v) => Number(v)).filter((v) => Number.isInteger(v) && v > 0)
|
||||
return list.length ? Array.from(new Set(list)).sort((a, b) => a - b) : [...DEFAULT_PAGE_SIZE_OPTIONS]
|
||||
}
|
||||
|
||||
/** 规范化默认每页条数:须为候选列表内的正整数,否则回退候选列表首项 */
|
||||
function normalizeDefault(value: unknown, options: number[]): number {
|
||||
const size = Number(value)
|
||||
return Number.isInteger(size) && options.includes(size) ? size : options[0]
|
||||
}
|
||||
|
||||
/**
|
||||
* 从后端加载分页偏好;force 为 true 时强制刷新(设置页保存后调用)。
|
||||
*
|
||||
* :param force: 是否强制重新加载
|
||||
* :returns: 当前的候选列表
|
||||
*/
|
||||
export async function loadPageSizeOptions(force = false): Promise<number[]> {
|
||||
if (loaded && !force) return pageSizeOptions.value
|
||||
try {
|
||||
const res: any = await getPaginationPrefs()
|
||||
const options = normalizeOptions(res?.data?.options)
|
||||
pageSizeOptions.value = options
|
||||
defaultPageSize.value = normalizeDefault(res?.data?.defaultSize, options)
|
||||
loaded = true
|
||||
} catch (e) {
|
||||
// 加载失败时保持默认值
|
||||
}
|
||||
return pageSizeOptions.value
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取共享的分页偏好(候选列表与默认每页条数),首次调用时异步加载。
|
||||
*
|
||||
* :returns: 候选列表 ref 与默认每页条数 ref
|
||||
*/
|
||||
export function usePageSizeOptions() {
|
||||
if (!loaded) {
|
||||
void loadPageSizeOptions()
|
||||
}
|
||||
return { pageSizeOptions, defaultPageSize }
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// 表格每页大小偏好:优先取本机上次选择,其次取全局默认值,变更自动持久化
|
||||
import { ref, watch } from 'vue'
|
||||
import type { Ref } from 'vue'
|
||||
import { usePageSizeOptions } from './usePageSizeOptions'
|
||||
import { readTablePageSize, writeTablePageSize } from '../utils/tablePageSizePrefs'
|
||||
|
||||
/**
|
||||
* 管理指定表格的每页大小:初始化时读取本机偏好(须在候选列表内),否则回退全局默认值,变更自动持久化。
|
||||
*
|
||||
* :param tableKey: 表格唯一键
|
||||
* :returns: 与存储同步的每页大小 ref
|
||||
*/
|
||||
export function useTablePageSize(tableKey: string): Ref<number> {
|
||||
const { pageSizeOptions, defaultPageSize } = usePageSizeOptions()
|
||||
const saved = readTablePageSize(tableKey)
|
||||
const initial = saved !== null && pageSizeOptions.value.includes(saved) ? saved : defaultPageSize.value
|
||||
const size = ref<number>(initial)
|
||||
watch(size, (next) => writeTablePageSize(tableKey, next))
|
||||
return size
|
||||
}
|
||||
Reference in New Issue
Block a user