# 8.3 分页查询规范 :::tip 概述 所有分页接口遵循统一的参数命名和返回结构。分页由 `BaseController::_index()` → `BaseLogic::pageList()` 实现,前端只需传标准参数即可获得分页数据。 ::: ## 请求参数 | 参数 | 类型 | 默认值 | 说明 | |------|------|--------|------| | `pageNo` | number | 1 | 页码(最小为 1) | | `pageSize` | number | 20 | 每页条数(1~100) | | `orderField` | string | - | 排序字段(camelCase,如 `createTime`) | | `orderType` | string | `desc` | 排序方向(`asc` / `desc`) | | `fields` | string | - | 返回字段(逗号分隔,如 `id,username,realname`) | | 其他参数 | - | - | 按 Logic 中配置的 `pageLikeFields` / `pageEqFields` 自动匹配 | ### 分页参数边界限制 | 参数 | 最小值 | 最大值 | 默认值 | 超出处理 | |------|--------|--------|--------|---------| | `pageNo` | 1 | - | 1 | 小于 1 时强制为 1 | | `pageSize` | 1 | 100 | 20 | 超出范围时限制在 1~100 | ## 请求示例 ```bash # 基本分页 GET /api/example/page?pageNo=1&pageSize=10 # 带模糊搜索(LIKE) GET /api/example/page?pageNo=1&pageSize=10&name=测试 # 带精确过滤(=) GET /api/example/page?pageNo=1&pageSize=10&status=1&type=2 # 模糊 + 精确组合 GET /api/example/page?pageNo=1&pageSize=10&name=测试&status=1 # 自定义排序 GET /api/example/page?pageNo=1&pageSize=10&orderField=sort&orderType=asc # 指定返回字段 GET /api/example/page?pageNo=1&pageSize=10&fields=id,name,status # 多条件组合 GET /api/user/page?pageNo=1&pageSize=20&username=admin&status=1&deptId=3&orderField=id&orderType=desc ``` ## 返回结构 ```json { "code": 0, "ok": true, "msg": "操作成功", "data": { "records": [ { "id": 1, "name": "测试", "status": 1, "statusText": "启用", "createTime": "2026-01-01 00:00:00" }, { "id": 2, "name": "示例", "status": 0, "statusText": "禁用", "createTime": "2026-01-02 00:00:00" } ], "total": 100, "size": 10, "current": 1, "pages": 10 } } ``` ### 返回字段 | 字段 | 类型 | 说明 | |------|------|------| | `records` | array | 当前页数据列表 | | `total` | number | 总记录数 | | `size` | number | 每页条数 | | `current` | number | 当前页码 | | `pages` | number | 总页数(`ceil(total / size)`) | ## 查询条件匹配 ### pageLikeFields — 模糊匹配(LIKE) 在 Logic 中配置的字段,前端传参时自动使用 `LIKE '%值%'` 查询: ```php class ExampleLogic extends BaseLogic { protected array $pageLikeFields = ['name', 'title']; } ``` ```bash # name 字段自动使用 LIKE 查询 GET /api/example/page?name=测试 # 生成: WHERE name LIKE '%测试%' ``` ### pageEqFields — 精确匹配(=) 在 Logic 中配置的字段,前端传参时自动使用 `= 值` 查询: ```php class ExampleLogic extends BaseLogic { protected array $pageEqFields = ['status', 'type', 'category_id']; } ``` ```bash # status 和 type 字段自动使用 = 查询 GET /api/example/page?status=1&type=2 # 生成: WHERE status = 1 AND type = 2 ``` ### 条件组合 ```bash # 模糊 + 精确 + 排序 + 分页 GET /api/example/page?pageNo=1&pageSize=20&name=测试&status=1&orderField=sort&orderType=asc # 生成 SQL: # SELECT * FROM think_example # WHERE is_delete = 0 # AND name LIKE '%测试%' # AND status = 1 # ORDER BY sort ASC # LIMIT 20 OFFSET 0 ``` ## 排序 ### 前端传参排序 ```bash # 按创建时间倒序 GET /api/example/page?orderField=createTime&orderType=desc # 按排序字段正序 GET /api/example/page?orderField=sort&orderType=asc ``` ### Logic 默认排序 ```php class ExampleLogic extends BaseLogic { /** * 单字段排序 * * @var array */ protected array $pageOrderBy = ['field' => 'sort', 'type' => 'asc']; /** * 多字段排序 * * @var array */ protected array $pageOrderBy = [ ['field' => 'sort', 'type' => 'asc'], ['field' => 'id', 'type' => 'desc'], ]; } ``` **优先级:** 前端传参 > Logic 默认配置 ## 字段过滤 ### fields 参数 前端可通过 `fields` 参数指定只需要的字段,减少数据传输量: ```bash # 只返回 id、name、status 三个字段 GET /api/example/page?fields=id,name,status ``` **响应:** ```json { "records": [ { "id": 1, "name": "测试", "status": 1 }, { "id": 2, "name": "示例", "status": 0 } ] } ``` **注意:** `id` 字段始终保留,即使未在 `fields` 中指定。 ## 参数转换 前端使用 camelCase,后端自动转换为 snake_case: | 前端参数 | 转换后 | 说明 | |---------|--------|------| | `pageNo` | `pageNo` | 不转换(排除项) | | `pageSize` | `pageSize` | 不转换(排除项) | | `orderField` | `orderField` | 不转换(排除项) | | `orderType` | `orderType` | 不转换(排除项) | | `fields` | `fields` | 不转换(排除项) | | `categoryId` | `category_id` | 自动转换 | | `createTime` | `create_time` | 自动转换 | | `userName` | `user_name` | 自动转换 | ### 排序字段值也自动转换 ```bash # 前端传入 camelCase GET /api/example/page?orderField=createTime # 后端自动转换为 snake_case ORDER BY create_time DESC ``` ## Controller 层实现 ### 使用 _index 快捷方法(推荐) ```php class ExampleController extends BaseController { protected ExampleLogic $logic; protected function initialize(): void { $this->logic = new ExampleLogic(); } #[Permission('sys:example:page', '案例分页')] public function page(): Json { return parent::_index($this->logic); } } ``` ### 带额外查询条件 ```php #[Permission('sys:user:page', '用户分页')] public function page(): Json { // 额外条件:只查启用状态的用户 return parent::_index($this->logic, ['status' => 1]); } ``` ### 带关联查询 ```php #[Permission('sys:article:page', '文章分页')] public function page(): Json { // 预加载分类关联 return parent::_index($this->logic, [], ['category']); } ``` ## Logic 层实现 ```php class ExampleLogic extends BaseLogic { /** * 关联的模型类 * * @var string */ protected string $modelClass = Example::class; /** * LIKE 模糊匹配字段 * * @var array */ protected array $pageLikeFields = ['name', 'title']; /** * 精确匹配字段 * * @var array */ protected array $pageEqFields = ['status', 'type', 'category_id']; /** * 默认排序规则 * * @var array */ protected array $pageOrderBy = ['field' => 'sort', 'type' => 'asc']; /** * 枚举显示名映射 * * @var array */ protected array $serializeMaps = ['status' => 'example_status']; } ``` ## 前端集成 ### API 函数 ```typescript // src/api/tool/example.ts export function getExamplePage(params?) { return http.request({ url: '/example/page', method: 'GET', params }); } ``` ### 组件使用 ```vue ``` ## 常见问题 ### 问题 1:搜索条件不生效 **原因:** 字段名未在 `pageLikeFields` 或 `pageEqFields` 中配置。 **解决:** 在 Logic 中添加对应字段配置。 ### 问题 2:排序不生效 **原因:** `orderField` 传了数据库不存在的字段名。 **解决:** 确保 `orderField` 传的是数据库字段名的 camelCase 形式。 ### 问题 3:分页数据重复 **原因:** 排序字段值相同,导致数据库返回顺序不确定。 **解决:** 排序字段加上唯一字段(如 id)作为第二排序条件。