/** 店铺列表筛选与分页(任务 89):店铺 FilterBar 的分组/店铺名筛选与列表查询、分页信息,纯逻辑。 */ import { normalizeShopListParams, SHOP_PAGE_DEFAULT_SIZE, SHOP_PAGE_MAX_SIZE, SHOP_PAGE_MIN_PAGE, toShopManagePageQuery, type ShopManageListParams, type ShopManagePageQuery, } from './shop-dto.ts' /** 店铺列表筛选状态(页面局部)。 */ export interface ShopManageFilter { groupId: number | null shopName: string } export function createShopManageFilter(): ShopManageFilter { return { groupId: null, shopName: '' } } function positiveGroupOrNull(value: unknown): number | null { if (typeof value === 'number') return Number.isFinite(value) && value >= 1 ? Math.floor(value) : null if (typeof value === 'string') { const text = value.trim() if (/^\d+$/.test(text)) { const parsed = Number(text) return parsed >= 1 ? Math.floor(parsed) : null } } return null } function shopNameText(value: unknown): string { return typeof value === 'string' ? value.trim() : '' } /** 由界面输入(分组下拉文本/店铺名输入)归一筛选状态。 */ export function shopManageFilterFromInput(input: { groupId?: string | number | null; shopName?: string }): ShopManageFilter { const shopName = shopNameText(input.shopName) return { groupId: positiveGroupOrNull(input.groupId), shopName: shopName ? shopName : '' } } export function shopManageFilterActive(filter: ShopManageFilter): boolean { return filter.groupId !== null || Boolean(filter.shopName && filter.shopName.trim()) } /** 筛选 + 页码 → 归一化列表参数(供 fetch 与查询序列化复用)。 */ export function toShopManageListParams(page: number, pageSize: number, filter: ShopManageFilter): ShopManageListParams { return normalizeShopListParams({ page, pageSize, groupId: filter.groupId, shopName: filter.shopName.trim() || undefined, }) } /** 筛选 + 页码 → Java 查询参数(camelCase,仅下发非空)。 */ export function toShopManageQuery(page: number, pageSize: number, filter: ShopManageFilter): ShopManagePageQuery { return toShopManagePageQuery(toShopManageListParams(page, pageSize, filter)) } export interface ShopManagePageInfo { page: number pageSize: number total: number totalPages: number from: number to: number hasPrev: boolean hasNext: boolean } function finiteInt(value: unknown): number | null { return typeof value === 'number' && Number.isFinite(value) ? Math.floor(value) : null } /** 由总数与目标分页派生页码信息:页码钳制到 [1, totalPages],空数据视为第 1 页。 */ export function shopManagePageInfo(page: unknown, pageSize: unknown, total: unknown): ShopManagePageInfo { const rawSize = Math.max(finiteInt(pageSize) ?? SHOP_PAGE_DEFAULT_SIZE, SHOP_PAGE_MIN_PAGE) const size = Math.min(rawSize, SHOP_PAGE_MAX_SIZE) const safeTotal = Math.max(finiteInt(total) ?? 0, 0) const totalPages = safeTotal === 0 ? 1 : Math.max(1, Math.ceil(safeTotal / size)) const requested = Math.max(finiteInt(page) ?? SHOP_PAGE_MIN_PAGE, SHOP_PAGE_MIN_PAGE) const safePage = Math.min(requested, totalPages) const from = safeTotal === 0 ? 0 : (safePage - 1) * size + 1 const to = Math.min(safeTotal, safePage * size) return { page: safePage, pageSize: size, total: safeTotal, totalPages, from, to, hasPrev: safePage > 1, hasNext: safePage < totalPages && safeTotal > 0, } }