# 分页规范 ## 概述 统一使用 `pageNo`/`pageSize` 作为分页参数,`BaseService.get_page()` 封装分页逻辑,返回标准分页结构。 :::tip 分页约定 - 前端传递 `pageNo`(页码,从 1 开始)和 `pageSize`(每页条数) - 后端返回 `{records, total, size, current, pages}` 结构 - 默认每页 10 条(`PAGE_SIZE = 10`) ::: ## 请求参数 | 参数 | 类型 | 必填 | 默认值 | 说明 | |------|------|------|--------|------| | `pageNo` | int | 否 | 1 | 页码,从 1 开始 | | `pageSize` | int | 否 | 10 | 每页条数 | ### 请求示例 ```bash # GET 请求 GET /api/v1/position/page?pageNo=1&pageSize=10 # 带筛选条件 GET /api/v1/position/page?pageNo=1&pageSize=10&name=开发&status=1 ``` ## 响应格式 ```json { "code": 0, "data": { "records": [ { "id": 1, "name": "开发工程师", "status": 1, "statusText": "在用", "sort": 1, "createTime": "2026-01-01 10:00:00" } ], "total": 50, "size": 10, "current": 1, "pages": 5 }, "msg": "操作成功", "ok": true } ``` | 字段 | 类型 | 说明 | |------|------|------| | `records` | array | 当前页数据列表 | | `total` | int | 总记录数 | | `size` | int | 每页条数 | | `current` | int | 当前页码 | | `pages` | int | 总页数 | ## BaseService 实现 ### get_page 方法 ```python def get_page(self, request) -> R: """分页查询""" page, limit = parse_pagination(request) query = self._build_page_query(request) items, total = self.repo.paginate(page, limit, query) # 超页自动回退第 1 页 if page > 1 and not items: page = 1 items, total = self.repo.paginate(page, limit, query) result = [self._serialize(item) for item in items] return R.page(result, total, page, limit) ``` :::tip 超页回退 当请求的页码超过总页数时(如删除数据后前端未刷新),自动回退到第 1 页,避免返回空数据。 ::: ### 分页查询构建 ```python def _build_page_query(self, request): """组装分页查询:声明字段过滤 + 排序""" query = self.repo.filter() query = self._apply_page_filters(query, request) for field_name, direction in self.page_order_by: column = getattr(self.model, field_name) query = query.order_by(column.asc() if direction == 'asc' else column.desc()) return query ``` ### 字段过滤声明 ```python class PositionService(BaseService(Position]): # 模糊查询字段:name LIKE %值% page_like_fields = ('name',) # 等值查询字段:status = 值 page_eq_fields = ('status',) # 排序规则 page_order_by = (('sort', 'asc'),) :::tip 过滤字段说明 - `page_like_fields`:从 query_params 取同名参数,自动应用 `LIKE %值%`,空值跳过 - `page_eq_fields`:从 query_params 取同名参数,自动应用 `=值`,空值跳过 - 两种字段均自动跳过 None/空字符串,无需手动判断 ::: ## Repository 分页实现 ```python def paginate(self, page_no: int = 1, page_size: int = PAGE_SIZE, query=None): """分页查询,返回 (items, total)""" q = query if query is not None else self.db.query(self.model) q = q.filter(self._soft_col() == 0) # 自动软删过滤 total = q.count() items = q.limit(page_size).offset((page_no - 1) * page_size).all() return items, total ``` ## Handler 示例 ```python class PositionPageHandler(BaseHandler): @permission_required("sys:position:list") async def get(self): """获取岗位分页列表""" return await position_service.get_page(self) ``` :::tip 权限标识 分页接口权限标识格式:`sys:{模块名}:page` ::: ## 自定义分页过滤 子类可覆盖 `_apply_page_filters` 添加固定过滤条件: ```python def _apply_page_filters(self, query, request): """添加固定过滤:只显示启用状态的数据""" query = super()._apply_page_filters(query, request) query = query.filter(self.model.status == 1) return query ``` ## 总结 分页规范统一使用 `pageNo`/`pageSize` 参数,通过 `BaseService.get_page()` 自动处理分页逻辑。子类只需声明 `page_like_fields`/`page_eq_fields`/`page_order_by` 即可获得完整的分页能力。响应使用 `R.page()` 封装标准分页结构,前端可直接使用 `records`/`total`/`pages` 渲染列表和分页组件。