# 分页规范 ## 概述 项目统一使用 `pageNo` / `pageSize` 作为分页参数,通过 `BaseService.get_page()` → `Repository.page()` → `BaseRepository.find_page()` 链路完成分页查询,返回标准分页结构。 :::tip 分页约定 - 前端传递 `pageNo`(页码,从 1 开始)和 `pageSize`(每页条数) - 后端返回分页数据字典,包含 `items` / `total` / `page` / `pageSize` / `pages` 等字段 - 默认每页 10 条(`PAGE_SIZE = 10`) ::: ## 分页流程 ``` 前端请求 GET /api/v1/position/page?pageNo=1&pageSize=10&name=工程师 ↓ Router 层:R.ok(data=position.get_position_page(request.args)) ↓ Service 层:BaseService.get_page(params) ↓ Repository 层:PositionRepository.page(params) ↓ BaseRepository.find_page(page, page_size, filters, like_filters, order_by) ↓ 返回 (items, total, pages) ↓ build_page_data 构建分页数据字典 ``` ## Repository 层实现 ```python # src/modules/system/position/repository.py from src.common.base_repository import BaseRepository from src.common.constants.common import PAGE_SIZE from src.modules.system.position.models import Position class PositionRepository(BaseRepository): model = Position @classmethod def page(cls, params: dict): """ 岗位分页查询 Args: params: 查询参数字典 - pageNo: 当前页码 - pageSize: 每页记录数 - name: 岗位名称(模糊匹配) - status: 状态(精确匹配) Returns: tuple: (items, total, pages) """ return cls.find_page( page=int(params.get('pageNo', 1)), page_size=int(params.get('pageSize', PAGE_SIZE)), filters={'status': params.get('status')}, like_filters={'name': params.get('name')}, order_by='sort', ) ``` ## Service 层调用 ```python # src/common/base_service.py from src.common.utils.model_utils import build_page_data class BaseService: @classmethod def get_page(cls, params: dict) -> dict: """分页查询""" page = int(params.get("pageNo", 1)) page_size = int(params.get("pageSize", PAGE_SIZE)) items, total, pages = cls.repository.page(params) return build_page_data( items, total, page, page_size, pages, enrich=cls._enrich_page_records, ) ``` ## Router 层调用 ```python # src/modules/system/position/router.py @position_blue.route('/page', methods=["GET"]) @check_permission("sys:position:page") def page(): """查询岗位分页数据""" return R.ok(data=position.get_position_page(request.args)) ``` ## 分页参数说明 | 参数 | 类型 | 说明 | 默认值 | |:---|:---|:---|:---| | `pageNo` | int | 当前页码(从 1 开始) | 1 | | `pageSize` | int | 每页记录数 | 10 | ## 筛选参数说明 | 筛选类型 | Repository 参数 | 说明 | SQL 效果 | |:---|:---|:---|:---| | 等值匹配 | `filters={'status': 1}` | 精确匹配 | `WHERE status = 1` | | 模糊匹配 | `like_filters={'name': '工程师'}` | 模糊匹配 | `WHERE name LIKE '%工程师%'` | | 范围匹配 | `range_filters={'create_time': (start, end)}` | 范围匹配 | `WHERE create_time BETWEEN start AND end` | :::tip 空值跳过 所有筛选条件自动跳过 `None` 和空字符串 `''`,前端不传某参数时不会影响查询结果。 ::: ## 前端调用示例 ```typescript // ui/src/api/system/position/index.ts export const getPositionPageApi = (params: any) => { return http.request('get', '/position/page', { params }); }; // 使用 const { data } = await getPositionPageApi({ pageNo: 1, pageSize: 10, name: '工程师' }); // data.items = [...] // data.total = 100 // data.pages = 10 ``` ## 开发要点 1. **分页参数统一使用 `pageNo` / `pageSize`**:前端和后端保持一致 2. **Repository 的 `page(params)` 方法必须实现**:Service 的 `get_page` 依赖此方法 3. **使用 `find_page` 构建查询**:传入 `filters` / `like_filters` / `range_filters` / `order_by` 4. **空值自动跳过**:前端不传的参数不会影响查询条件 5. **软删除自动过滤**:`find_page` 自动添加 `is_delete = 0` 条件 ## 总结 分页查询通过 `Service.get_page(params)` → `Repository.page(params)` → `BaseRepository.find_page(...)` 链路完成。筛选条件通过 `filters`(等值)、`like_filters`(模糊)、`range_filters`(范围)三类参数传入,空值自动跳过,软删除自动过滤。