签入版本

This commit is contained in:
2026-10-08 17:50:29 +08:00
parent 809750b47e
commit e213a9b31d
444 changed files with 39366 additions and 37533 deletions
@@ -1,7 +1,7 @@
# 12.1 API 响应规范
:::tip 概述
所有接口返回统一的 JSON 结构,前端可据此判断请求结果。成功响应 `code=0`,失败响应 `code=1`(或 401/403/404/422)。
所有接口返回统一的 JSON 结构,前端可据此判断请求结果。成功响应 `code=0`,失败响应 `code=1`(或 401/403/404/422/500)。HTTP 状态码默认 200,仅 403 例外。详细机制见 [8.1 统一响应格式](/zh/api-spec/response.html)。
:::
## 统一格式
@@ -67,7 +67,7 @@ interface ApiResponse {
| `code` | number | 状态码,0=成功 |
| `ok` | boolean | 是否成功 |
| `msg` | string | 提示信息 |
| `data` | any | 响应数据,失败时通常为 null |
| `data` | any | 响应数据,失败时通常为 null 或错误明细 |
| `data.records` | array | 分页数据列表 |
| `data.total` | number | 总记录数 |
| `data.size` | number | 每页条数 |
@@ -84,32 +84,33 @@ interface ApiResponse {
| `user_name` | `userName` |
| `is_delete` | `isDelete` |
可通过 `config/api.php` 的 `camel_snake_convert` 配置关闭。
可通过 `config/api.php` 的 `camel_snake_convert`(环境变量 `API_CAMEL_SNAKE_CONVERT`)关闭;需要单个接口原样返回时用 `Result::success($data, $msg, true)`。
## 后端构造方式
```php
// Controller 中
return $this->success($data, '操作成功'); // 成功
return $this->success(['id' => $id], '添加成功'); // 成功(带数据)
return $this->fail('用户名已存在'); // 失败
return $this->_page($result); // 分页
// Controller 中(基类方法,推荐)
return $this->success($data, '操作成功'); // 成功
return $this->success(['id' => $id], '添加成功'); // 成功(带数据)
return $this->fail('用户名已存在'); // 失败(code 默认 1)
return $this->paginate($pageListResult); // 分页(records/total/current/size/pages)
return $this->_page($service, $where); // 分页(直接传 Service,内部调用 pageList)
```
```php
// Result 类直接调用
// Result 类直接调用(app/Support/Result.php)
Result::success($data, $msg);
Result::page($records, $total, $current, $size);
Result::page($records, $total, $current, $size, $pages = null); // 分页响应
Result::fail($msg, $code);
Result::unauthorized($msg); // 401
Result::forbidden($msg); // 403
Result::unauthorized($msg); // 401(HTTP 200 + body code)
Result::forbidden($msg); // 403(HTTP 403)
Result::notFound($msg); // 404
Result::validateError($errors); // 422 参数验证失败
```
### validateError 示例
`Result::validateError()` 用于参数验证失败场景,HTTP 状态码为 422,`data` 字段返回具体错误明细,便于前端逐字段提示:
`Result::validateError()` 用于参数验证失败场景,`code=422`,`data` 字段返回具体错误明细,便于前端逐字段提示:
```php
// 直接传字符串
@@ -117,8 +118,8 @@ return Result::validateError('用户名不能为空');
// 传数组,包含多个字段错误
return Result::validateError([
'username' => '用户名不能为空',
'email' => '邮箱格式不正确',
'username' => ['用户名不能为空'],
'email' => ['邮箱格式不正确'],
]);
```
@@ -128,8 +129,8 @@ return Result::validateError([
"ok": false,
"msg": "参数验证失败",
"data": {
"username": "用户名不能为空",
"email": "邮箱格式不正确"
"username": ["用户名不能为空"],
"email": ["邮箱格式不正确"]
}
}
```
```
@@ -1,30 +1,42 @@
# 12.6 后端编码规范
:::tip 概述
本节定义后端 PHP 代码的编写规范,包括 Model、Logic、Controller、Validate 各层的命名和结构规范,确保团队代码风格统一。
本节定义后端 PHP 代码的编写规范,包括 Model、Service、Controller、FormRequest 各层的命名和结构规范,确保团队代码风格统一。代码风格以 Laravel Pint(`./vendor/bin/pint`)为准。
:::
## Model 层规范
```php
// 继承 BaseModel
class Example extends BaseModel
// 继承 Eloquent Model(app/Models/Example.php)
class Example extends Model
{
// 软删除(is_delete)+ 审计字段(create_user/create_time/update_user/update_time)
use HasAuditColumns, SoftDeletesByFlag;
/**
* 对应数据库表名(不含前缀)
* 对应数据库表名
*
* @var string
*/
protected $name = 'example';
protected $table = 'example';
/**
* 批量赋值白名单
*
* @var array<int, string>
*/
protected $fillable = ['name', 'avatar', 'type', 'status', 'sort'];
}
```
## Logic 层规范
## Service 层规范
```php
// 系统共享模块继承 BaseLogic
class ExampleLogic extends BaseLogic
// 系统共享模块继承 BaseService
class ExampleService extends BaseService
{
use HasCrudOperations, HasQueryScopes, HasSerializeMaps;
/**
* 关联的模型类
*
@@ -58,63 +70,65 @@ class ExampleLogic extends BaseLogic
}
}
// 租户模块继承 BaseTenantLogic
class UserLogic extends BaseTenantLogic { ... }
// 租户模块继承 BaseTenantService(含 tenant_id 的业务表)
class UserService extends BaseTenantService { ... }
```
可用生命周期钩子(`HasCrudOperations`):`beforeAdd` / `afterAdd` / `beforeUpdate` / `afterUpdate` / `beforeDelete` / `afterDelete` / `beforeBatchDelete` / `afterBatchDelete` / `afterDetail` / `afterPageList`。
## Controller 层规范
```php
class ExampleController extends BaseController
class ExampleController extends Controller
{
protected ExampleLogic $logic;
protected function initialize(): void
{
$this->logic = new ExampleLogic();
}
// 构造函数注入 Service(不在 initialize 中手动 new)
public function __construct(protected ExampleService $exampleService) {}
// 使用注解
#[Log('模块-操作', Log::TYPE_ADD)]
#[Permission('sys:example:add', '添加')]
public function add(): Json
#[OperationLog('示例管理-新增', OperationLog::TYPE_ADD)]
#[Permission('sys:example:add', '新增示例')]
public function add(ExampleRequest $request): JsonResponse
{
return parent::_add($this->logic, $this->getJsonBody());
return $this->_add($this->exampleService, $request->validated());
}
}
```
## Validate 层规范
:::tip 瘦控制器
Controller 只做三件事:参数获取(FormRequest)→ 调用 Service → 返回 JSON。业务规则一律写在 Service,不在控制器写 if/else 业务判断。
:::
## FormRequest 层规范
```php
class ExampleValidate extends Validate
class ExampleRequest extends BaseRequest
{
protected $rule = [
'name' => 'require',
'categoryId' => 'require', // ✅ 驼峰命名
// 'category_id' => 'require', // ❌ 禁止下划线
];
public function rules(): array
{
return [
'name' => 'required|string|max:255', // ✅ 驼峰命名
'categoryId' => 'required|integer', // ✅ 驼峰命名
// 'category_id' => 'required', // ❌ 禁止下划线
];
}
protected $message = [
'name.require' => '名称不能为空',
'categoryId.require' => '分类不能为空',
];
protected $scene = [
'add' => ['name', 'categoryId'],
'update' => ['name'],
];
public function messages(): array
{
return [
'name.required' => '名称不能为空',
'categoryId.required' => '分类不能为空',
];
}
}
```
:::warning 字段名必须使用驼峰
Validate 中的字段名必须使用 camelCase(驼峰),与前端传参一致。
因为校验发生在 `BaseLogic::beforeAdd` 之后、`array_camel_to_snake` 转换之前,
此时数据键名还是驼峰形式。使用下划线会导致校验规则匹配不到字段。
FormRequest 中的字段名必须使用 camelCase(驼峰),与前端传参一致——使用下划线会导致校验规则匹配不到字段。控制器以 `validated()` 取数原样传递,键名转换由 Service 写入入口(doAdd/doUpdate)统一完成。
:::
## 注解规范
- 所有写操作(POST/PUT/DELETE)必须标注 `#[Log]`
- 所有写操作(POST/PUT/DELETE)必须标注 `#[OperationLog('模块-操作', OperationLog::TYPE_XXX)]`
- 所有需要权限控制的接口必须标注 `#[Permission]`
- 权限码格式:`sys:{模块名}:{操作}`
- 权限码格式:`sys:{模块名}:{操作}`
- 演示环境放行的只读接口标注 `#[DemoAllow]`
@@ -8,40 +8,49 @@
### Model 层
- [ ] 继承 `BaseModel`
- [ ] 表名 `$name` 配置正确
- [ ] 继承 Eloquent `Model`(业务模型位于 `app/Models/`)
- [ ] `protected $table` 显式指定表名(含前缀或与 `DB_PREFIX` 推导一致)
- [ ] 引入 `SoftDeletesByFlag`(is_delete 软删除)与 `HasAuditColumns`(审计字段)Trait
- [ ] `$fillable` 白名单完整(批量赋值字段)
- [ ] 关联关系定义正确(如有)
- [ ] 无硬编码的数据库前缀
### Logic 层
### Service 层
- [ ] 继承正确的基类(`BaseLogic` 或 `BaseTenantLogic`)
- [ ] 继承正确的基类(`BaseService` 或 `BaseTenantService`,树形模块不参与租户隔离)
- [ ] `$modelClass` 配置正确
- [ ] Trait 组合按需(`HasCrudOperations` / `HasQueryScopes` / `HasSerializeMaps` / `HasUniqueCheck` / `HasFileProcessing`)
- [ ] 查询条件配置合理(`pageLikeFields` / `pageEqFields`)
- [ ] 排序配置合理(`pageOrderBy`)
- [ ] 排序配置合理(`pageOrderBy` / `orderFieldAllow` 白名单)
- [ ] 唯一性校验配置(`uniqueFields`)
- [ ] 枚举映射配置(`serializeMaps`)
- [ ] 文件字段配置(`fileFields` / `fileSaveDir`)
- [ ] 钩子方法中无 SQL 注入风险
- [ ] 事务使用正确(`startTrans` / `commit` / `rollback`)
- [ ] 钩子方法中无 SQL 注入风险(使用查询构造器参数绑定)
- [ ] 写操作在事务中执行(`HasCrudOperations` 已用 `DB::transaction` 包裹,自定义逻辑需补充)
### Controller 层
- [ ] 继承 `BaseController`
- [ ] `initialize()` 中实例化 Logic
- [ ] 位于 `app/Http/Controllers/Api/`,瘦控制器(参数获取 → 调 Service → 返回 JSON)
- [ ] 通过构造函数注入 Service(不手动 new)
- [ ] 所有接口标注 `#[Permission]` 注解
- [ ] 所有写操作标注 `#[Log]` 注解
- [ ] 所有写操作标注 `#[OperationLog]` 注解
- [ ] 权限码格式正确(`sys:模块名:操作`)
- [ ] 异常处理完善(try-catch)
- [ ] 参数校验充分
- [ ] 返回值类型为 `JsonResponse`,使用基类 `success/fail/paginate/_page` 等方法
- [ ] 参数格式校验由 FormRequest 完成(不在控制器手写校验)
### FormRequest
- [ ] 继承 `BaseRequest`(`failedValidation` 统一抛出 `code=1` 响应)
- [ ] `rules()` 覆盖全部必填与格式字段
- [ ] 场景区分(add / update)
### 安全
- [ ] 无 SQL 注入风险(使用 ORM 参数绑定)
- [ ] 无 SQL 注入风险(使用 ORM / 查询构造器参数绑定)
- [ ] 无 XSS 风险(输出转义)
- [ ] 敏感数据不暴露(password、salt)
- [ ] 文件上传有类型和大小限制
- [ ] 权限校验覆盖所有接口
- [ ] 敏感数据不暴露(password、salt 不在响应字段中)
- [ ] 文件上传有类型和大小限制(`config/file.php` + FormRequest)
- [ ] 权限校验覆盖所有接口(`#[Permission]`)
## 前端审查清单
@@ -50,7 +59,7 @@
- [ ] 函数命名规范(`getXxxPage` / `xxxAdd` / `xxxUpdate` / `xxxDelete`)
- [ ] HTTP 方法正确(GET/POST/PUT/DELETE)
- [ ] 参数传递方式正确(params / data)
- [ ] 错误处理完善
- [ ] 错误处理完善(响应拦截器统一处理,业务代码不重复 catch)
### 页面组件
@@ -63,8 +72,8 @@
### 权限
- [ ] 按钮级权限使用 `v-perm` 指令
- [ ] 权限码与后端一致
- [ ] 按钮级权限使用 `v-perm` 指令(如 `v-perm="['sys:example:add']"`,多权限全满足用 `v-perms`)
- [ ] 权限码与后端 `#[Permission]` 注解一致
### 性能
@@ -74,7 +83,8 @@
## Git 提交审查
- [ ] commit message 格式正确
- [ ] commit message 格式正确(见 [12.3 Git 提交规范](/zh/standards/git.html))
- [ ] 一个 commit 只做一件事
- [ ] 无调试代码残留(console.log、dump)
- [ ] 无敏感信息泄露(密码、密钥)
- [ ] 无调试代码残留(console.log、dd、dump)
- [ ] 无敏感信息泄露(密码、密钥、.env)
- [ ] 通过 `vendor/bin/pint --test`(后端风格)与 `pnpm lint:eslint`(前端风格)
@@ -3,7 +3,7 @@
## 软删除约定
:::tip 核心原则
所有业务数据统一使用软删除机制,通过 `is_delete` 字段标记记录状态,不物理删除数据。
所有业务数据统一使用软删除机制,通过 `is_delete` 字段标记记录状态,不物理删除数据(`SoftDeletesByFlag` Trait + `SoftDeleteFlagScope` 全局范围,不使用 `deleted_at`)。
:::
| is_delete 值 | 含义 |
@@ -24,11 +24,11 @@ DELETE /api/{module}/delete/{id}
### Controller 示例
```php
#[Log('案例演示-删除记录', Log::TYPE_DELETE, '删除案例演示ID:{id}')]
#[Permission('sys:example:delete', '删除案例演示')]
public function delete(int $id): Json
#[OperationLog('案例演示-删除', OperationLog::TYPE_DELETE, '删除案例ID:{id}')]
#[Permission('sys:example:delete', '删除案例')]
public function delete(int $id): JsonResponse
{
return parent::_remove($this->logic, $id);
return $this->_delete($this->exampleService, $id);
}
```
@@ -38,17 +38,17 @@ public function delete(int $id): Json
Controller::delete($id)
│
▼
BaseController::_remove($logic, $id)
Controller 基类::_delete($service, $id)
│
▼
BaseLogic::delete($id)
│
├─ beforeDelete($id) 钩子(抛异常可拦截)
Service::delete($id) → HasCrudOperations::doDelete($id)
│ (DB::transaction 包裹)
├─ beforeDelete($id) 钩子(抛异常可拦截,事务回滚)
│
├─ $model->find($id)
│ └─ 不存在 → return false
│
├─ $model->save(['is_delete' => 1])
├─ $model->softDelete() → UPDATE SET is_delete = 1
│
└─ afterDelete($id) 钩子
```
@@ -67,12 +67,12 @@ Content-Type: application/json
### Controller 示例
```php
#[Log('案例演示-批量删除', Log::TYPE_DELETE)]
#[Permission('sys:example:delete', '删除案例演示')]
public function batchDelete(): Json
#[OperationLog('案例演示-批量删除', OperationLog::TYPE_DELETE)]
#[Permission('sys:example:batchDelete', '批量删除案例')]
public function batchDelete(): JsonResponse
{
$ids = $this->getJsonBody()['ids'] ?? [];
return parent::_batchRemove($this->logic, $ids);
return $this->_batchDelete($this->exampleService, $ids);
}
```
@@ -82,13 +82,13 @@ public function batchDelete(): Json
Controller::batchDelete()
│
▼
BaseController::_batchRemove($logic, $ids)
Controller 基类::_batchDelete($service, $ids)
│
├─ ids 为空 → 返回失败 "请选择要删除的数据"
│
▼
BaseLogic::batchDelete($ids)
│
Service::batchDelete($ids) → HasCrudOperations::doBatchDelete($ids)
│ (DB::transaction 包裹)
├─ beforeBatchDelete($ids) 钩子(整体校验)
│
├─ 逐条 beforeDelete($id) 校验
@@ -99,12 +99,16 @@ BaseLogic::batchDelete($ids)
└─ afterBatchDelete($ids) 钩子
```
:::info 权限码区别
单条删除权限为 `sys:{模块}:delete`,批量删除权限为 `sys:{模块}:batchDelete`(代码生成器创建菜单时分别生成),前端按钮需分别控制显隐。
:::
## 删除前校验(beforeDelete 钩子)
在 Logic 中重写 `beforeDelete` 方法,抛异常可拦截删除:
在 Service 中重写 `beforeDelete` 方法,抛异常可拦截删除(事务自动回滚):
```php
class UserLogic extends BaseTenantLogic
class DeptService extends BaseTenantService
{
protected function beforeDelete(int $id): void
{
@@ -123,11 +127,13 @@ class UserLogic extends BaseTenantLogic
}
```
可用钩子(均在 `HasCrudOperations` 中声明):`beforeDelete($id)`、`afterDelete($id)`、`beforeBatchDelete($ids)`、`afterBatchDelete($ids)`。
## 何时可物理删除
| 场景 | 方式 | 说明 |
|------|------|------|
| 日志数据清理 | 定时任务 | CleanLogTask 清理 N 天前的日志 |
| 日志数据清理 | 定时任务 | 通过「定时任务」模块(job 表)配置清理 N 天前的日志 |
| 临时数据 | 定时任务 | 清理过期的临时文件 |
| 其它 | 审批 | 需经过管理员审批 |
@@ -153,4 +159,4 @@ class UserLogic extends BaseTenantLogic
>
批量删除 ({{ selectedIds.length }})
</el-button>
```
```
@@ -1,7 +1,7 @@
# 12.7 前端编码规范
:::tip 概述
前端编码规范涵盖 Vue 组件、TypeScript、API 模块、样式和代码风格等方面。
前端编码规范涵盖 Vue 组件、TypeScript、API 模块、样式和代码风格等方面。前端工程位于 `ui/` 目录(Vue3 + TypeScript + ElementPlus + Pinia)。
:::
## Vue 组件规范
@@ -60,13 +60,13 @@ interface User {
status: number;
}
// 枚举定义
// 枚举定义(统一放 ui/src/enums/ 下,如 pageEnum.ts、httpEnum.ts)
enum UserStatus {
ENABLE = 1,
DISABLE = 2,
}
// API 响应类型
// API 响应类型(分页结构见 12.1/12.2)
interface PageResult<T> {
records: T[];
total: number;
@@ -110,21 +110,26 @@ export function userDelete(id: number) {
}
```
:::info 路径前缀
API 函数中 `url` 不带 `/api` 前缀——由 `ui/.env.production` 的 `VITE_GLOB_API_URL_PREFIX=/api` 在请求层统一拼接。
:::
## 命名规范
| 类型 | 规范 | 示例 |
|------|------|------|
| 组件文件 | PascalCase | `BasicTable.vue` |
| API 文件 | camelCase | `user.ts` |
| API 文件 | camelCase,按模块分目录(`ui/src/api/{模块}/`) | `system/user.ts` |
| API 函数 | camelCase | `getUserPage` |
| Store 文件 | camelCase | `user.ts` |
| Store 文件 | camelCase(`ui/src/store/modules/`) | `user.ts` |
| 枚举文件 | camelCase + Enum 后缀(`ui/src/enums/`) | `pageEnum.ts` |
| 常量 | UPPER_SNAKE_CASE | `ACCESS_TOKEN` |
| CSS 类 | kebab-case | `page-container` |
## 代码风格
```bash
# ESLint 检查
# ESLint 检查(脚本自带 --fix)
pnpm lint:eslint
# Prettier 格式化
@@ -132,6 +137,9 @@ pnpm lint:prettier
# Stylelint 检查
pnpm lint:stylelint
# TypeScript 类型检查
pnpm type:check
```
:::warning 禁止事项
@@ -139,4 +147,4 @@ pnpm lint:stylelint
- 不要使用 `console.log`(生产环境)
- 不要在模板中写复杂逻辑(提取为 computed 或方法)
- 不要在 `setup` 外使用 Composition API
:::
:::
@@ -1,7 +1,7 @@
# 12.3 Git 提交规范
:::tip 概述
统一的 Git 提交规范有助于代码审查、版本管理和自动化工具集成。
统一的 Git 提交规范有助于代码审查、版本管理和自动化工具集成。前端工程提供了 commitlint 配置(`ui/commitlint.config.js`,依赖中含 husky / lint-staged),按其规范提交可通过自动化校验。
:::
## Commit Message 格式
@@ -12,18 +12,31 @@
<body>
```
:::info 中文友好
`ui/commitlint.config.js` 的 `headerPattern` 支持中文 type、全角括号与全角冒号,如 `新增(用户): 导入导出功能` 也可通过校验;建议仍统一使用下述标准 type。头部最长 108 字符。
:::
## Type 类型
以 `ui/commitlint.config.js` 的 `type-enum` 为准:
| type | 说明 | 示例 |
|------|------|------|
| `feat` | 新功能 | `feat(user): 新增用户导入导出功能` |
| `fix` | 修复 Bug | `fix(login): 修复验证码过期后仍可使用的问题` |
| `docs` | 文档 | `docs: 更新 API 接口文档` |
| `style` | 代码格式(不影响功能) | `style: 统一代码缩进` |
| `refactor` | 重构 | `refactor(logic): 优化分页查询性能` |
| `perf` | 性能优化 | `perf(dict): 增加字典缓存减少数据库查询` |
| `style` | 代码格式(不影响功能) | `style: 统一代码缩进` |
| `docs` | 文档 | `docs: 更新 API 接口文档` |
| `test` | 测试 | `test: 添加用户模块单元测试` |
| `chore` | 构建/工具 | `chore: 更新 Composer 依赖` |
| `refactor` | 重构 | `refactor(service): 优化分页查询性能` |
| `build` | 构建 | `build: 升级 Vite 构建配置` |
| `ci` | CI 配置 | `ci: 补充后端 Pint 检查步骤` |
| `chore` | 杂项/工具 | `chore: 更新 Composer 依赖` |
| `revert` | 回滚 | `revert: 回滚 feat(user) 导入功能` |
| `wip` | 进行中 | `wip(user): 导入导出开发中` |
| `workflow` | 工作流 | `workflow: 调整分支保护规则` |
| `types` | 类型定义 | `types: 补充前端 API 类型声明` |
| `release` | 发版 | `release: v1.2.0` |
## Scope 范围
@@ -62,7 +75,7 @@ git commit -m "docs: 补充多数据库部署文档"
# -----------------------------------------------------------------------------
# 重构(refactor)
# -----------------------------------------------------------------------------
git commit -m "refactor(logic): 统一删除前校验逻辑"
git commit -m "refactor(service): 统一删除前校验逻辑"
# -----------------------------------------------------------------------------
# 性能优化(perf)
@@ -73,45 +86,60 @@ git commit -m "perf(dict): 增加请求级缓存减少重复查询"
## 注意事项
:::warning 禁止事项
- 不要提交调试代码(`console.log`、`dump`、`var_dump`)
- 不要提交敏感信息(密码、密钥、Token)
- 不要提交调试代码(`console.log`、`dd()`、`dump`、`var_dump`)
- 不要提交敏感信息(密码、密钥、Token、`.env`)
- 不要提交 IDE 配置文件(`.idea/`、`.vscode/`)
- 一个 commit 只做一件事
:::
## .gitignore
项目根目录 `.gitignore` 关键规则:
```gitignore
# =============================================================================
# .gitignore — Git 版本控制忽略规则
# .gitignore — Git 版本控制忽略规则(摘自项目根目录,含说明)
# =============================================================================
# 匹配的文件不会被 git track(不会提交到仓库)
# =============================================================================
# -----------------------------------------------------------------------------
# 运行时目录(ThinkPHP 缓存、日志、编译模板 — 自动生成,无需版本控制)
# -----------------------------------------------------------------------------
runtime/
vendor/
# -----------------------------------------------------------------------------
# 环境配置(包含数据库密码等敏感信息 — 绝不能提交)
# 环境配置与备份(包含数据库密码、JWT 密钥等敏感信息 — 绝不能提交)
# -----------------------------------------------------------------------------
.env
.env.backup
.env.production
# -----------------------------------------------------------------------------
# IDE 配置文件(每个开发者的 IDE 设置不同 — 不应互相影响)
# 运行时与依赖(自动生成/体积庞大,通过 composer install、npm install 重建)
# -----------------------------------------------------------------------------
.idea/
.vscode/
/vendor
/node_modules
/storage/*.key
/storage/pail
/public/build
/public/hot
# -----------------------------------------------------------------------------
# 临时上传文件(用户上传的临时文件 — 不属于代码)
# IDE 与系统文件(每个开发者的环境不同 — 不应互相影响)
# -----------------------------------------------------------------------------
uploads/temp/
/.idea
/.vscode
/.fleet
/.nova
/.zed
.DS_Store
Thumbs.db
# -----------------------------------------------------------------------------
# 前端依赖(node_modules 体积庞大 — 通过 pnpm install 重新安装即可)
# 测试与工具缓存
# -----------------------------------------------------------------------------
ui/node_modules/
*.log
/.phpunit.cache
.phpunit.result.cache
.phpactor.json
```
:::info 前端依赖
前端依赖忽略规则由 `ui/node_modules`(`.gitignore` 中 `/node_modules` 对应各前端包目录)覆盖,`pnpm-lock.yaml` **必须提交**(保证依赖版本一致)。
:::
@@ -1,7 +1,7 @@
# 12.2 分页查询规范
:::tip 概述
所有分页接口遵循统一的参数命名和返回结构,确保前后端一致性。
所有分页接口遵循统一的参数命名和返回结构,确保前后端一致性。详细机制见 [8.3 分页查询规范](/zh/api-spec/pagination.html)。
:::
## 请求参数
@@ -9,11 +9,11 @@
| 参数 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `pageNo` | number | 1 | 页码(最小为 1) |
| `pageSize` | number | 20 | 每页条数(1~100) |
| `pageSize` | number | 20 | 每页条数(1~100,超出自动限制) |
| `orderField` | string | - | 排序字段(camelCase,如 `createTime`) |
| `orderType` | string | `desc` | 排序方向(`asc` / `desc`) |
| `fields` | string | - | 返回字段(逗号分隔,如 `id,username,status`) |
| 其他参数 | - | - | 按 Logic 中 pageLikeFields / pageEqFields 自动匹配 |
| 其他参数 | - | - | 按 Service 中 pageLikeFields / pageEqFields 自动匹配 |
## 请求示例
@@ -62,4 +62,8 @@ GET /api/example/page?pageNo=1&pageSize=10&fields=id,name,status
| 前端传参 | 后端处理 | SQL |
|---------|---------|-----|
| `orderField=createTime&orderType=desc` | 转为 `create_time` | `ORDER BY create_time DESC` |
| 不传 | 使用 Logic 默认排序 | 按 `pageOrderBy` 配置 |
| 不传 | 使用 Service 默认排序 | 按 `pageOrderBy` 配置 |
:::warning 排序白名单
`orderField` 只在 **`pageOrderBy` 默认字段 ∪ `orderFieldAllow`** 的并集内生效,不在白名单内的字段直接忽略(防 SQL 注入)。开放新排序字段请配置 `orderFieldAllow`。
:::