签入版本

This commit is contained in:
2026-09-12 23:12:15 +08:00
commit 91998056ca
1841 changed files with 341325 additions and 0 deletions
@@ -0,0 +1,160 @@
# 分页规范
## 概述
统一使用 `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
```
## Endpoint 示例
```python
@router.get('/page', summary='查询分页数据')
@permission_required("sys:position:page")
def page(request: Request):
"""获取岗位分页列表"""
return position_service.get_page(request)
```
:::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` 渲染列表和分页组件。