/** * envelope.ts —— mock 信封辅助(academic-mock-plan §4 三条硬要求之一)。 * * 契约来源:unified/03-migration/academic-frontend-contract-v1.md §1.1 / §1.3(冻结)。 * 纪律: * - 信封恒四字段 {success, code, message, data};success 为兼容字段,新代码判 code; * - data 无值时**键不出现**(对齐后端 omitempty),不得为 null/undefined 占位; * - 分页恒 PageData 五字段 {list, total, page, pageSize, pages},空列表 [](非 null); * - pageSize 超 200 由 mock 侧钳制(对齐后端 ParsePage:默认 10 / 上限 200)。 * * 本文件仅在 dev + VITE_API_MOCK 下被加载(http.ts 动态 import 门控),不进 dist。 */ import type { PageData, R } from '@/types/api'; /** 成功信封(data 为 undefined 时键不出现,对齐后端 omitempty)。 */ export function ok(data: T): R; /** 成功信封(无返回数据:data 键不出现)。 */ export function ok(): R; export function ok(data?: T): R { const body: Record = { success: true, code: 200, message: 'ok' }; if (data !== undefined) body.data = data; return body as unknown as R; } /** 失败信封(无 data 键;message 为可直接展示的中文文案)。 */ export function fail(code: number, message: string): R { return { success: false, code, message }; } /** * 分页封装(PageData 五字段全量下发)。 * * 入参: * - list 完整数据集(mock 侧已按筛选条件过滤完毕); * - page 请求页码(缺省 1;<1 按 1 计); * - size 请求每页条数(缺省 10;**>200 钳制为 200**,对齐后端钳制语义)。 * * 出参: * - R>:list 切片(越界页 = [],不报错)/ total = 完整集长度 / pages = ceil(total/size), * size=0 时 pages=0(与后端一致)。 */ export function page(list: T[], pageArg: number, sizeArg: number): R> { const pageSize = Math.min(Math.max(Math.trunc(sizeArg) || 10, 1), 200); const pageNow = Math.max(Math.trunc(pageArg) || 1, 1); const total = list.length; const start = (pageNow - 1) * pageSize; return ok({ list: list.slice(start, start + pageSize), total, page: pageNow, pageSize, pages: pageSize > 0 ? Math.ceil(total / pageSize) : 0, }); }