签入版本

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,279 +1,284 @@
# E. API 接口速查表
:::tip 概述
本表列出所有 API 路由的完整清单,包含 HTTP 方法、路径和所需权限码。
本表列出所有 API 路由的完整清单(自动生成自 `routes/api.php` 与各控制器 `#[Permission]` 注解),包含 HTTP 方法、路径和所需权限码。批量删除统一为 **DELETE**(请求体仍传 ids 数组),其余遵循 REST 习惯。
:::
## 公开接口
## 公开接口(免认证)
定义在 `routes/api.php` 中间件组外,无需携带 Token:
| 方法 | 路径 | 说明 |
|------|------|------|
| POST | `/api/login` | 用户登录 |
| GET | `/api/logout` | 用户登出 |
| POST | `/api/refresh` | 刷新 Token |
| GET | `/api/captcha` | 获取验证码 |
| POST | `/api/oauth2/token` | 刷新 Token |
| DELETE | `/api/oauth2/remove/:token` | 移除 Token |
| GET | `/api/oauth2/check/token` | 检查 Token |
| POST | `/api/oauth2/token` | OAuth2 获取令牌 |
| GET | `/api/oauth2/check/token` | 检查令牌有效性 |
## 首页 / 个人中心
## 认证接口(auth.jwt + tenant + demo + log.operation)
### Auth / Index / Upload
| 方法 | 路径 | 权限码 | 说明 |
|------|------|--------|------|
| POST | `/api/logout` | - | 登出 |
| DELETE | `/api/oauth2/remove/:token` | sys:auth:removeToken | 吊销令牌 |
| GET | `/api/index/getUser` | - | 获取当前用户信息 |
| GET | `/api/index/getMenus` | - | 获取菜单列表 |
| PUT | `/api/index/updatePassword` | - | 修改密码 |
| PUT | `/api/index/updateProfile` | - | 修改个人资料 |
| POST | `/api/upload/uploadFile` | sys:upload:file | 上传文件 |
## 用户管理
### 用户管理(User)
| 方法 | 路径 | 权限码 | 说明 |
|------|------|--------|------|
| GET | `/api/user/page` | sys:user:page | 分页列表 |
| GET | `/api/user/detail/:id` | sys:user:detail | 详情 |
| POST | `/api/user/add` | sys:user:add | 新增 |
| PUT | `/api/user/update` | sys:user:update | 修改 |
| PUT | `/api/user/resetPwd` | sys:user:resetPwd | 重置密码 |
| DELETE | `/api/user/delete/:id` | sys:user:delete | 删除 |
| GET | `/api/user/page` | sys:user:page | 用户分页 |
| GET | `/api/user/detail/:id` | sys:user:detail | 用户详情 |
| POST | `/api/user/add` | sys:user:add | 添加用户 |
| PUT | `/api/user/update` | sys:user:update | 修改用户 |
| DELETE | `/api/user/delete/:id` | sys:user:delete | 删除用户 |
| DELETE | `/api/user/batchDelete` | sys:user:batchDelete | 批量删除 |
| POST | `/api/user/import` | sys:user:import | 导入 |
| GET | `/api/user/export` | sys:user:export | 导出 |
| PUT | `/api/user/resetPwd` | sys:user:resetPwd | 重置密码 |
| GET | `/api/user/export` | sys:user:export | 导出用户 |
| POST | `/api/user/import` | sys:user:import | 导入用户 |
## 角色管理
### 角色管理(Role)
| 方法 | 路径 | 权限码 | 说明 |
|------|------|--------|------|
| GET | `/api/role/page` | sys:role:page | 分页列表 |
| GET | `/api/role/list` | sys:role:list | 全量列表 |
| GET | `/api/role/detail/:id` | sys:role:detail | 详情 |
| POST | `/api/role/add` | sys:role:add | 新增 |
| PUT | `/api/role/update` | sys:role:update | 修改 |
| DELETE | `/api/role/delete/:id` | sys:role:delete | 删除 |
| GET | `/api/role/page` | sys:role:page | 角色分页 |
| GET | `/api/role/list` | sys:role:list | 角色列表 |
| GET | `/api/role/detail/:id` | sys:role:detail | 角色详情 |
| POST | `/api/role/add` | sys:role:add | 添加角色 |
| PUT | `/api/role/update` | sys:role:update | 修改角色 |
| DELETE | `/api/role/delete/:id` | sys:role:delete | 删除角色 |
| DELETE | `/api/role/batchDelete` | sys:role:batchDelete | 批量删除 |
| GET | `/api/role/menu/list/:id` | - | 角色菜单列表 |
| POST | `/api/role/menu/save` | sys:role:authorize | 保存角色菜单 |
| GET | `/api/role/menu/list/:id` | sys:role:getPermission | 查询角色菜单权限 |
| POST | `/api/role/menu/save` | sys:role:savePermission | 授权角色菜单 |
## 菜单管理
### 菜单管理(Menu)
| 方法 | 路径 | 权限码 | 说明 |
|------|------|--------|------|
| GET | `/api/menu/list` | sys:menu:page | 菜单列表(树形) |
| GET | `/api/menu/detail/:id` | sys:menu:detail | 详情 |
| POST | `/api/menu/add` | sys:menu:add | 新增 |
| PUT | `/api/menu/update` | sys:menu:update | 修改 |
| DELETE | `/api/menu/delete/:id` | sys:menu:delete | 删除 |
| GET | `/api/menu/list` | sys:menu:list | 菜单列表 |
| GET | `/api/menu/detail/:id` | sys:menu:detail | 菜单详情 |
| POST | `/api/menu/add` | sys:menu:add | 添加菜单 |
| PUT | `/api/menu/update` | sys:menu:update | 修改菜单 |
| DELETE | `/api/menu/delete/:id` | sys:menu:delete | 删除菜单 |
## 部门管理
### 部门管理(Dept)
| 方法 | 路径 | 权限码 | 说明 |
|------|------|--------|------|
| GET | `/api/dept/list` | sys:dept:page | 部门列表(树形) |
| GET | `/api/dept/detail/:id` | sys:dept:detail | 详情 |
| POST | `/api/dept/add` | sys:dept:add | 新增 |
| PUT | `/api/dept/update` | sys:dept:update | 修改 |
| DELETE | `/api/dept/delete/:id` | sys:dept:delete | 删除 |
| GET | `/api/dept/list` | sys:dept:list | 部门列表 |
| GET | `/api/dept/detail/:id` | sys:dept:detail | 部门详情 |
| POST | `/api/dept/add` | sys:dept:add | 添加部门 |
| PUT | `/api/dept/update` | sys:dept:update | 修改部门 |
| DELETE | `/api/dept/delete/:id` | sys:dept:delete | 删除部门 |
## 岗位管理
### 职级 / 岗位(Level / Position)
| 方法 | 路径 | 权限码 | 说明 |
|------|------|--------|------|
| GET | `/api/position/page` | sys:position:page | 分页列表 |
| GET | `/api/position/list` | sys:position:list | 全量列表 |
| GET | `/api/position/detail/:id` | sys:position:detail | 详情 |
| POST | `/api/position/add` | sys:position:add | 新增 |
| PUT | `/api/position/update` | sys:position:update | 修改 |
| DELETE | `/api/position/delete/:id` | sys:position:delete | 删除 |
| GET | `/api/level/page` | sys:level:page | 职级分页 |
| GET | `/api/level/list` | sys:level:list | 职级列表 |
| GET | `/api/level/detail/:id` | sys:level:detail | 职级详情 |
| POST | `/api/level/add` | sys:level:add | 添加职级 |
| PUT | `/api/level/update` | sys:level:update | 修改职级 |
| DELETE | `/api/level/delete/:id` | sys:level:delete | 删除职级 |
| DELETE | `/api/level/batchDelete` | sys:level:batchDelete | 批量删除 |
| GET | `/api/level/export` | sys:level:export | 导出职级 |
| POST | `/api/level/import` | sys:level:import | 导入职级 |
| GET | `/api/position/page` | sys:position:page | 岗位分页 |
| GET | `/api/position/list` | sys:position:list | 岗位列表 |
| GET | `/api/position/detail/:id` | sys:position:detail | 岗位详情 |
| POST | `/api/position/add` | sys:position:add | 添加岗位 |
| PUT | `/api/position/update` | sys:position:update | 修改岗位 |
| DELETE | `/api/position/delete/:id` | sys:position:delete | 删除岗位 |
| DELETE | `/api/position/batchDelete` | sys:position:batchDelete | 批量删除 |
## 职级管理
### 字典管理(Dict / DictItem)
| 方法 | 路径 | 权限码 | 说明 |
|------|------|--------|------|
| GET | `/api/level/page` | sys:level:page | 分页列表 |
| GET | `/api/level/list` | sys:level:list | 全量列表 |
| GET | `/api/level/detail/:id` | sys:level:detail | 详情 |
| POST | `/api/level/add` | sys:level:add | 新增 |
| PUT | `/api/level/update` | sys:level:update | 修改 |
| DELETE | `/api/level/delete/:id` | sys:level:delete | 删除 |
| DELETE | `/api/level/batchDelete` | sys:level:batchDelete | 批量删除 |
| GET | `/api/level/export` | sys:level:export | 导出 |
| POST | `/api/level/import` | sys:level:import | 导入 |
## 数据字典
| 方法 | 路径 | 权限码 | 说明 |
|------|------|--------|------|
| GET | `/api/dict/page` | sys:dict:page | 分页列表 |
| GET | `/api/dict/detail/:id` | sys:dict:detail | 详情 |
| GET | `/api/dict/refreshCache` | sys:dict:refreshCache | 刷新缓存 |
| POST | `/api/dict/add` | sys:dict:add | 新增 |
| PUT | `/api/dict/update` | sys:dict:update | 修改 |
| DELETE | `/api/dict/delete/:id` | sys:dict:delete | 删除 |
| GET | `/api/dict/page` | sys:dict:page | 字典分页 |
| GET | `/api/dict/detail/:id` | sys:dict:detail | 字典详情 |
| POST | `/api/dict/add` | sys:dict:add | 添加字典 |
| PUT | `/api/dict/update` | sys:dict:update | 修改字典 |
| DELETE | `/api/dict/delete/:id` | sys:dict:delete | 删除字典 |
| DELETE | `/api/dict/batchDelete` | sys:dict:batchDelete | 批量删除 |
| GET | `/api/dict/refreshCache` | sys:dict:update | 刷新字典缓存 |
| GET | `/api/dict/item/page` | sys:dict:page | 字典项分页 |
| GET | `/api/dict/item/detail/:id` | sys:dict:detail | 字典项详情 |
| POST | `/api/dict/item/add` | sys:dict:add | 添加字典项 |
| PUT | `/api/dict/item/update` | sys:dict:update | 修改字典项 |
| DELETE | `/api/dict/item/delete/:id` | sys:dict:delete | 删除字典项 |
| DELETE | `/api/dict/item/batchDelete` | sys:dict:batchDelete | 批量删除字典项 |
| GET | `/api/dict/item/getDictItemList/:code` | - | 按编码查询字典项(前端下拉数据源) |
## 字典项
### 内容管理(Category / Article / Notice / Link)
| 方法 | 路径 | 权限码 | 说明 |
|------|------|--------|------|
| GET | `/api/dict/item/page` | sys:dict:item:page | 分页列表 |
| GET | `/api/dict/item/detail/:id` | sys:dict:item:detail | 详情 |
| GET | `/api/dict/item/getDictItemList/:code` | - | 按编码获取字典项 |
| POST | `/api/dict/item/add` | sys:dict:item:add | 新增 |
| PUT | `/api/dict/item/update` | sys:dict:item:update | 修改 |
| DELETE | `/api/dict/item/delete/:id` | sys:dict:item:delete | 删除 |
| DELETE | `/api/dict/item/batchDelete` | sys:dict:item:batchDelete | 批量删除 |
## 租户管理
| 方法 | 路径 | 权限码 | 说明 |
|------|------|--------|------|
| GET | `/api/tenant/page` | sys:tenant:page | 分页列表 |
| GET | `/api/tenant/detail/:id` | sys:tenant:detail | 详情 |
| GET | `/api/tenant/users/:tenantId` | - | 租户用户列表 |
| POST | `/api/tenant/add` | sys:tenant:add | 新增 |
| POST | `/api/tenant/account` | sys:tenant:add | 创建租户账号 |
| PUT | `/api/tenant/update` | sys:tenant:update | 修改 |
| DELETE | `/api/tenant/delete/:id` | sys:tenant:delete | 删除 |
| DELETE | `/api/tenant/batchDelete` | sys:tenant:batchDelete | 批量删除 |
## 系统配置
| 方法 | 路径 | 权限码 | 说明 |
|------|------|--------|------|
| GET | `/api/config/page` | sys:config:page | 分页列表 |
| GET | `/api/config/list` | sys:config:list | 全量列表 |
| GET | `/api/config/detail/:id` | sys:config:detail | 详情 |
| GET | `/api/config/web/index` | sys:config:web | 网站配置 |
| POST | `/api/config/web/save` | sys:config:web | 保存网站配置 |
| POST | `/api/config/add` | sys:config:add | 新增 |
| PUT | `/api/config/update` | sys:config:update | 修改 |
| DELETE | `/api/config/delete/:id` | sys:config:delete | 删除 |
## 配置项
| 方法 | 路径 | 权限码 | 说明 |
|------|------|--------|------|
| GET | `/api/config/item/page` | sys:config:item:page | 分页列表 |
| GET | `/api/config/item/list` | sys:config:item:list | 全量列表 |
| GET | `/api/config/item/detail/:id` | sys:config:item:detail | 详情 |
| POST | `/api/config/item/add` | sys:config:item:add | 新增 |
| PUT | `/api/config/item/update` | sys:config:item:update | 修改 |
| DELETE | `/api/config/item/delete/:id` | sys:config:item:delete | 删除 |
## 系统参数
| 方法 | 路径 | 权限码 | 说明 |
|------|------|--------|------|
| GET | `/api/param/page` | sys:param:page | 分页列表 |
| GET | `/api/param/list` | sys:param:list | 全量列表 |
| GET | `/api/param/detail/:id` | sys:param:detail | 详情 |
| POST | `/api/param/add` | sys:param:add | 新增 |
| PUT | `/api/param/update` | sys:param:update | 修改 |
| DELETE | `/api/param/delete/:id` | sys:param:delete | 删除 |
## 通知公告
| 方法 | 路径 | 权限码 | 说明 |
|------|------|--------|------|
| GET | `/api/notice/page` | sys:notice:page | 分页列表 |
| GET | `/api/notice/list` | - | 全量列表 |
| GET | `/api/notice/detail/:id` | sys:notice:detail | 详情 |
| POST | `/api/notice/add` | sys:notice:add | 新增 |
| PUT | `/api/notice/update` | sys:notice:update | 修改 |
| DELETE | `/api/notice/delete/:id` | sys:notice:delete | 删除 |
## 城市行政区划
| 方法 | 路径 | 权限码 | 说明 |
|------|------|--------|------|
| GET | `/api/city/list` | sys:city:page | 城市列表 |
| GET | `/api/city/detail/:id` | sys:city:detail | 详情 |
| POST | `/api/city/add` | sys:city:add | 新增 |
| PUT | `/api/city/update` | sys:city:update | 修改 |
| DELETE | `/api/city/delete/:id` | sys:city:delete | 删除 |
| GET | `/api/city/getCityList/:parentCode` | - | 按父编码获取城市 |
## 文章管理
| 方法 | 路径 | 权限码 | 说明 |
|------|------|--------|------|
| GET | `/api/article/page` | sys:article:page | 分页列表 |
| GET | `/api/article/list` | sys:article:list | 全量列表 |
| GET | `/api/article/detail/:id` | sys:article:detail | 详情 |
| POST | `/api/article/add` | sys:article:add | 新增 |
| PUT | `/api/article/update` | sys:article:update | 修改 |
| DELETE | `/api/article/delete/:id` | sys:article:delete | 删除 |
| GET | `/api/category/list` | sys:category:list | 分类列表 |
| GET | `/api/category/page` | sys:category:page | 分类分页 |
| GET | `/api/category/detail/:id` | sys:category:detail | 分类详情 |
| POST | `/api/category/add` | sys:category:add | 添加分类 |
| PUT | `/api/category/update` | sys:category:update | 修改分类 |
| DELETE | `/api/category/delete/:id` | sys:category:delete | 删除分类 |
| DELETE | `/api/category/batchDelete` | sys:category:batchDelete | 批量删除 |
| GET | `/api/article/page` | sys:article:page | 文章分页 |
| GET | `/api/article/list` | sys:article:list | 文章列表 |
| GET | `/api/article/detail/:id` | sys:article:detail | 文章详情 |
| POST | `/api/article/add` | sys:article:add | 添加文章 |
| PUT | `/api/article/update` | sys:article:update | 修改文章 |
| DELETE | `/api/article/delete/:id` | sys:article:delete | 删除文章 |
| DELETE | `/api/article/batchDelete` | sys:article:batchDelete | 批量删除 |
| GET | `/api/notice/page` | sys:notice:page | 通知分页 |
| GET | `/api/notice/list` | sys:notice:list | 通知列表 |
| GET | `/api/notice/detail/:id` | sys:notice:detail | 通知详情 |
| POST | `/api/notice/add` | sys:notice:add | 添加通知 |
| PUT | `/api/notice/update` | sys:notice:update | 修改通知 |
| DELETE | `/api/notice/delete/:id` | sys:notice:delete | 删除通知 |
| DELETE | `/api/notice/batchDelete` | sys:notice:batchDelete | 批量删除 |
| GET | `/api/link/page` | sys:link:page | 友链分页 |
| GET | `/api/link/list` | sys:link:list | 友链列表 |
| GET | `/api/link/detail/:id` | sys:link:detail | 友链详情 |
| POST | `/api/link/add` | sys:link:add | 添加友链 |
| PUT | `/api/link/update` | sys:link:update | 修改友链 |
| DELETE | `/api/link/delete/:id` | sys:link:delete | 删除友链 |
| DELETE | `/api/link/batchDelete` | sys:link:batchDelete | 批量删除 |
## 文章分类
### 行政区划(City)
| 方法 | 路径 | 权限码 | 说明 |
|------|------|--------|------|
| GET | `/api/category/page` | sys:category:page | 分页列表 |
| GET | `/api/category/list` | sys:category:list | 全量列表 |
| GET | `/api/category/detail/:id` | sys:category:detail | 详情 |
| POST | `/api/category/add` | sys:category:add | 新增 |
| PUT | `/api/category/update` | sys:category:update | 修改 |
| DELETE | `/api/category/delete/:id` | sys:category:delete | 删除 |
| GET | `/api/city/list` | sys:city:list | 城市列表 |
| GET | `/api/city/detail/:id` | sys:city:detail | 城市详情 |
| POST | `/api/city/add` | sys:city:add | 添加城市 |
| PUT | `/api/city/update` | sys:city:update | 修改城市 |
| DELETE | `/api/city/delete/:id` | sys:city:delete | 删除城市 |
| DELETE | `/api/city/batchDelete` | sys:city:batchDelete | 批量删除 |
| GET | `/api/city/getCityList/:code` | - | 按编码取下级 |
| GET | `/api/city/getParent/:id` | - | 取上级 |
| GET | `/api/city/findByParentCode` | - | 按父编码查询 |
## 友情链接
### 系统配置(Config / ConfigItem / Param)
| 方法 | 路径 | 权限码 | 说明 |
|------|------|--------|------|
| GET | `/api/link/page` | sys:link:page | 分页列表 |
| GET | `/api/link/detail/:id` | sys:link:detail | 详情 |
| POST | `/api/link/add` | sys:link:add | 新增 |
| PUT | `/api/link/update` | sys:link:update | 修改 |
| DELETE | `/api/link/delete/:id` | sys:link:delete | 删除 |
| GET | `/api/config/page` | sys:config:page | 配置分页 |
| GET | `/api/config/list` | sys:config:list | 配置列表 |
| GET | `/api/config/detail/:id` | sys:config:detail | 配置详情 |
| POST | `/api/config/add` | sys:config:add | 添加配置 |
| PUT | `/api/config/update` | sys:config:update | 修改配置 |
| DELETE | `/api/config/delete/:id` | sys:config:delete | 删除配置 |
| DELETE | `/api/config/batchDelete` | sys:config:batchDelete | 批量删除 |
| GET | `/api/config/web/index` | sys:config:webIndex | 查询网站配置 |
| POST | `/api/config/web/save` | sys:config:update | 保存网站配置 |
| GET | `/api/config/item/page` | sys:config:page | 配置项分页 |
| GET | `/api/config/item/list` | sys:config:list | 配置项列表 |
| GET | `/api/config/item/detail/:id` | sys:config:detail | 配置项详情 |
| POST | `/api/config/item/add` | sys:config:add | 添加配置项 |
| PUT | `/api/config/item/update` | sys:config:update | 修改配置项 |
| DELETE | `/api/config/item/delete/:id` | sys:config:delete | 删除配置项 |
| DELETE | `/api/config/item/batchDelete` | sys:config:batchDelete | 批量删除配置项 |
| GET | `/api/param/page` | sys:param:page | 参数分页 |
| GET | `/api/param/list` | sys:param:list | 参数列表 |
| GET | `/api/param/detail/:id` | sys:param:detail | 参数详情 |
| POST | `/api/param/add` | sys:param:add | 添加参数 |
| PUT | `/api/param/update` | sys:param:update | 修改参数 |
| DELETE | `/api/param/delete/:id` | sys:param:delete | 删除参数 |
| DELETE | `/api/param/batchDelete` | sys:param:batchDelete | 批量删除 |
## 定时任务
### 租户管理(Tenant)
| 方法 | 路径 | 权限码 | 说明 |
|------|------|--------|------|
| GET | `/api/job/page` | sys:job:page | 分页列表 |
| GET | `/api/job/list` | sys:job:list | 全量列表 |
| GET | `/api/job/detail/:id` | sys:job:detail | 详情 |
| GET | `/api/job/runOnce/:id` | sys:job:execute | 手动执行一次 |
| GET | `/api/tenant/page` | sys:tenant:page | 租户分页 |
| GET | `/api/tenant/list` | sys:tenant:list | 租户列表 |
| GET | `/api/tenant/detail/:id` | sys:tenant:detail | 租户详情 |
| POST | `/api/tenant/add` | sys:tenant:add | 添加租户 |
| PUT | `/api/tenant/update` | sys:tenant:update | 修改租户 |
| DELETE | `/api/tenant/delete/:id` | sys:tenant:delete | 删除租户 |
| DELETE | `/api/tenant/batchDelete` | sys:tenant:batchDelete | 批量删除 |
| GET | `/api/tenant/users/:tenantId` | sys:tenant:users | 租户用户 |
| POST | `/api/tenant/account` | sys:tenant:createAccount | 创建管理员账号 |
### 定时任务(Job / JobLog)
| 方法 | 路径 | 权限码 | 说明 |
|------|------|--------|------|
| GET | `/api/job/page` | sys:job:page | 任务分页 |
| GET | `/api/job/list` | sys:job:list | 任务列表 |
| GET | `/api/job/detail/:id` | sys:job:detail | 任务详情 |
| POST | `/api/job/add` | sys:job:add | 添加任务 |
| PUT | `/api/job/update` | sys:job:update | 修改任务 |
| DELETE | `/api/job/delete/:id` | sys:job:delete | 删除任务 |
| DELETE | `/api/job/batchDelete` | sys:job:batchDelete | 批量删除 |
| GET | `/api/job/runOnce/:id` | sys:job:execute | 立即执行任务 |
| POST | `/api/job/status` | sys:job:update | 修改任务状态 |
| GET | `/api/job/pause/:id` | sys:job:pause | 暂停任务 |
| GET | `/api/job/resume/:id` | sys:job:resume | 恢复任务 |
| POST | `/api/job/add` | sys:job:add | 新增 |
| PUT | `/api/job/update` | sys:job:update | 修改 |
| DELETE | `/api/job/delete/:id` | sys:job:delete | 删除 |
| GET | `/api/job/daemonStatus` | - | 守护进程状态 |
| GET | `/api/job/log/page` | sys:job:page | 任务日志分页 |
| GET | `/api/job/log/detail/:id` | sys:job:detail | 任务日志详情 |
| DELETE | `/api/job/log/delete/:id` | sys:job:delete | 删除任务日志 |
| DELETE | `/api/job/log/batchDelete` | sys:job:batchDelete | 批量删除 |
## 任务日志
### 案例演示(Example)
| 方法 | 路径 | 权限码 | 说明 |
|------|------|--------|------|
| GET | `/api/job/log/page` | sys:job:log:page | 分页列表 |
| GET | `/api/job/log/detail/:id` | sys:job:log:detail | 详情 |
| DELETE | `/api/job/log/delete/:id` | sys:job:log:delete | 删除 |
| GET | `/api/example/page` | sys:example:page | 示例分页 |
| GET | `/api/example/list` | sys:example:list | 示例列表 |
| GET | `/api/example/detail/:id` | sys:example:detail | 示例详情 |
| POST | `/api/example/add` | sys:example:add | 添加示例 |
| PUT | `/api/example/update` | sys:example:update | 修改示例 |
| DELETE | `/api/example/delete/:id` | sys:example:delete | 删除示例 |
| DELETE | `/api/example/batchDelete` | sys:example:batchDelete | 批量删除 |
| GET | `/api/example/export` | sys:example:export | 导出示例 |
| POST | `/api/example/import` | sys:example:import | 导入示例 |
## 操作日志
### 文件模板(FileTemplate)
| 方法 | 路径 | 权限码 | 说明 |
|------|------|--------|------|
| GET | `/api/oper/log/page` | sys:oper:log:page | 分页列表 |
| GET | `/api/oper/log/detail/:id` | sys:oper:log:detail | 详情 |
| DELETE | `/api/oper/log/delete/:id` | sys:oper:log:delete | 删除 |
| GET | `/api/file/template/page` | sys:fileTemplate:page | 模板分页 |
| GET | `/api/file/template/detail/:id` | sys:fileTemplate:detail | 模板详情 |
| POST | `/api/file/template/add` | sys:fileTemplate:add | 添加模板 |
| PUT | `/api/file/template/update` | sys:fileTemplate:update | 修改模板 |
| DELETE | `/api/file/template/delete/:id` | sys:fileTemplate:delete | 删除模板 |
| DELETE | `/api/file/template/batchDelete` | sys:fileTemplate:batchDelete | 批量删除 |
| GET | `/api/file/template/getTemplateByCode/:code` | - | 按编码取模板(导入模板下载) |
## 登录日志
### 代码生成(Generator)
| 方法 | 路径 | 权限码 | 说明 |
|------|------|--------|------|
| GET | `/api/login/log/page` | sys:login:log:page | 分页列表 |
| GET | `/api/login/log/detail/:id` | sys:login:log:detail | 详情 |
| DELETE | `/api/login/log/delete/:id` | sys:login:log:delete | 删除 |
| GET | `/api/generator/page` | sys:generator:page | 数据表分页 |
| GET | `/api/generator/preview` | sys:generator:generate | 预览生成代码 |
| POST | `/api/generator/generate` | sys:generator:generate | 一键生成 |
| POST | `/api/generator/batchGenerate` | sys:generator:generate | 批量生成 |
## 文件上传
### 日志查询(LoginLog / OperLog)
| 方法 | 路径 | 权限码 | 说明 |
|------|------|--------|------|
| POST | `/api/upload/uploadFile` | - | 上传文件 |
| GET | `/api/login/log/page` | sys:loginLog:page | 登录日志分页 |
| GET | `/api/login/log/detail/:id` | sys:loginLog:detail | 登录日志详情 |
| DELETE | `/api/login/log/delete/:id` | sys:loginLog:delete | 删除登录日志 |
| DELETE | `/api/login/log/batchDelete` | sys:loginLog:batchDelete | 批量删除 |
| GET | `/api/oper/log/page` | sys:operLog:page | 操作日志分页 |
| GET | `/api/oper/log/detail/:id` | sys:operLog:detail | 操作日志详情 |
| DELETE | `/api/oper/log/delete/:id` | sys:operLog:delete | 删除操作日志 |
| DELETE | `/api/oper/log/batchDelete` | sys:operLog:batchDelete | 批量删除 |
## 代码生成器
| 方法 | 路径 | 权限码 | 说明 |
|------|------|--------|------|
| GET | `/api/generator/page` | sys:generator:page | 可生成表列表 |
| POST | `/api/generator/preview` | sys:generator:preview | 预览生成代码 |
| POST | `/api/generator/generate` | sys:generator:generate | 生成代码 |
| POST | `/api/generator/batchGenerate` | sys:generator:generate | 批量生成 |
:::info 说明
- 权限码取自控制器方法的 `#[Permission]` 注解;`-` 表示该接口仅需登录(无独立权限码)
- 任务日志(jobLog)复用 `sys:job:*` 权限码
- 字典项 / 模板 / 行政区划的 `getDictItemList`、`getTemplateByCode`、`getCityList` 等读取接口免独立权限,登录即可访问
- 路径中 `:id` 为路径参数;查询参数、请求体规范见 [8. 接口规范与对接](/zh/api-spec/response.html)
:::
@@ -0,0 +1,105 @@
# K. Artisan 命令速查
:::tip 概述
本页汇总项目常用的 `php artisan` 命令,分为**项目自定义命令**与**框架高频命令**两部分。完整清单执行 `php artisan list` 查看(当前共 127 条)。
:::
## 项目自定义命令
| 命令 | 说明 |
|------|------|
| `php artisan generate:code {表名}` | 代码生成器 CLI(支持 `--dry-run` 预览、`--output` 导出配置、`--config` 读取配置),详见 [10.2 CLI 命令行使用](/zh/generator/cli.html) |
| `php artisan job:run` | 执行所有待执行的定时任务(配合 crontab 每分钟调用) |
| `php artisan job:daemon` | 定时任务常驻进程调度器(`--stop` 停止,锁文件 `storage/app/job_daemon.lock`) |
| `php artisan db:migrate` | 跨数据库迁移工具(`--src-*` / `--dst-*` 连接参数、`--drop-target-first`、`--tables`),详见 [7.6 数据库迁移工具](/zh/tools/db-migrate.html) |
| `php artisan dict:clear-cache` | 清除全部字典缓存 |
## 开发与调试
| 命令 | 说明 |
|------|------|
| `php artisan serve` | 启动开发服务器(默认 `127.0.0.1:8000`,可加 `--port=8080`) |
| `composer dev` | 并行启动 artisan serve + queue:listen + pail + vite |
| `php artisan tinker` | 交互式 REPL(测试模型、服务、辅助函数) |
| `php artisan pail` | 实时查看应用日志(`storage/logs/`) |
| `php artisan test` | 运行测试(等价 `composer test`,phpunit.xml 使用 sqlite 内存库) |
| `php artisan about` | 显示框架/应用基础信息 |
| `php artisan env` | 显示当前运行环境(APP_ENV) |
| `php artisan config:show [key]` | 查看某个配置项的实际生效值 |
## 缓存与性能
| 命令 | 说明 |
|------|------|
| `php artisan config:cache` | 编译配置缓存(生产) |
| `php artisan config:clear` | 清除配置缓存 |
| `php artisan route:cache` | 编译路由缓存(生产) |
| `php artisan route:clear` | 清除路由缓存 |
| `php artisan view:cache` | 预编译 Blade 视图 |
| `php artisan view:clear` | 清除编译视图 |
| `php artisan cache:clear` | 清除应用缓存 |
| `php artisan optimize` | 一次性缓存框架引导 + 配置 + 元数据 |
| `php artisan optimize:clear` | 清除以上全部缓存 |
:::warning 生产更新流程
更新代码后依次执行:`cache:clear` → `config:clear` → `route:clear` → `view:clear` → `dict:clear-cache`,再按需 `config:cache` / `route:cache` 重建(见 [11.1 部署 Checklist](/zh/deploy/checklist.html))。
:::
## 路由与数据库
| 命令 | 说明 |
|------|------|
| `php artisan route:list` | 列出全部路由(方法、URI、控制器方法) |
| `php artisan migrate` | 执行数据库迁移(**本项目 `database/migrations/` 为空,表结构以 `document/` SQL 导入为准**) |
| `php artisan migrate:status` | 查看迁移执行状态 |
| `php artisan migrate:fresh` | 重建全部表(含迁移的表) |
| `php artisan db:seed` | 执行种子数据(`DatabaseSeeder`) |
| `php artisan db:show` / `db:table {表}` | 查看数据库 / 表结构信息 |
| `php artisan key:generate` | 生成 `APP_KEY` |
## 队列
| 命令 | 说明 |
|------|------|
| `php artisan queue:work` | 消费队列(生产,配合 Supervisor) |
| `php artisan queue:listen` | 监听队列(开发,自动重启) |
| `php artisan queue:failed` | 查看失败任务 |
| `php artisan queue:retry {id}` | 重试失败任务 |
| `php artisan queue:clear` | 清空队列 |
## 定时调度(Laravel Scheduler)
| 命令 | 说明 |
|------|------|
| `php artisan schedule:list` | 查看已注册的调度任务 |
| `php artisan schedule:run` | 执行到期任务(cron 入口,每分钟调用) |
| `php artisan schedule:work` | 本地常驻调度(开发调试) |
:::info 本项目的任务调度
RXThinkCMF 业务定时任务使用自研 `job` 模块(`job:run` / `job:daemon`),Laravel Scheduler 当前仅含框架自带的 `inspire` 演示任务(见 `routes/console.php`)。
:::
## 维护与其它
| 命令 | 说明 |
|------|------|
| `php artisan down` | 进入维护模式(返回 503) |
| `php artisan up` | 退出维护模式 |
| `php artisan storage:link` | 创建上传目录软链接(`public/storage` → `storage/app/public`) |
| `php artisan event:list` | 查看事件与监听器 |
| `php artisan package:discover` | 发现并缓存扩展包(composer post-autoload-dump 自动执行) |
## Composer 脚本
| 命令 | 说明 |
|------|------|
| `composer setup` | 一键初始化(install → 复制 .env → key:generate → migrate → npm install/build) |
| `composer dev` | 开发模式并行启动(server / queue / logs / vite) |
| `composer test` | 清配置缓存 + 运行测试 |
| `./vendor/bin/pint` | 代码风格格式化(提交前执行,`pint --test` 仅检查) |
## 相关文档
- [2.3 后端服务启动](/zh/quickstart/backend-start.html)
- [6.11 定时任务](/zh/modules/job.html)
- [11.4 后端部署](/zh/deploy/backend.html)
@@ -1,40 +1,56 @@
# G. 前端组件速查
:::tip 概述
以下组件定义在 `ui/src/components/` 目录下,可在页面中直接引入使用。
公共组件定义在 `ui/src/components/` 目录下。其中 `PageWrapper`、`PageFooter`、`BasicTable`、`BasicForm`、`NumberInput`、`PriceInput`、`pagination`、`icon` 已在 `ui/src/plugins/customComponents.ts` 中**全局注册**,模板里可直接使用;其余组件按需 import。
:::
## 全局注册组件
以下组件由 `setupCustomComponents(app)` 注册,无需 import:
| 组件 | 来源 | 说明 |
|------|------|------|
| `PageWrapper` / `PageFooter` | `components/Page/` | 页面容器 / 页脚 |
| `BasicTable` | `components/Table/` | 数据表格(通过 props 传数据) |
| `BasicForm` | `components/Form/` | 动态表单(配合 `useForm` 的 register) |
| `NumberInput` | `components/numberInput/` | 数字输入 |
| `PriceInput` | `components/numberInput/` | 价格输入 |
| `pagination` | `components/pagination/` | 分页 |
| `icon` | `components/icon/` | 图标 |
## 数据展示
| 组件 | 路径 | 说明 | 核心 Props |
|------|------|------|-----------|
| BasicTable | `components/Table/` | 数据表格 | `columns`、`dataSource`、`pagination` |
| PageWrapper | `components/Page/` | 页面容器 | `title`、`contentFullHeight` |
| CountTo | `components/CountTo/` | 数字动画 | `startVal`、`endVal`、`duration` |
| Qrcode | `components/Qrcode/` | 二维码 | `value`、`size`、`level` |
| Icon | `components/icon/` | 图标选择器 | `value`、`disabled` |
| 组件 | 路径 | 说明 | 引入方式 |
|------|------|------|---------|
| BasicTable | `components/Table/` | 数据表格(含 TableAction 行操作) | 全局注册 |
| PageWrapper | `components/Page/` | 页面容器 | 全局注册 |
| CountTo | `components/CountTo/` | 数字动画 | 按需 import |
| Qrcode | `components/Qrcode/` | 二维码 | 按需 import |
| TableSelect | `components/TableSelect/` | 表格选择器 | 按需 import |
## 数据录入
| 组件 | 路径 | 说明 | 核心 Props |
|------|------|------|-----------|
| BasicForm | `components/Form/` | 动态表单 | `schemas`、`labelWidth` |
| BasicModal | `components/Modal/` | 弹窗 | `title`、`width`、`okText` |
| BasicUpload | `components/Upload/` | 文件上传 | `action`、`maxCount`、`accept` |
| Editor | `components/Editor/` | 富文本编辑器 | `value`、`height`、`placeholder` |
| Password | `components/Password/` | 密码强度 | `value`、`placeholder` |
| ChinaArea | `components/ChinaArea/` | 省市区联动 | `value`、`placeholder` |
| Region | `components/Region/` | 行政区划 | `value`、`level` |
| Cropper | `components/Cropper/` | 头像裁剪 | `image`、`aspectRatio` |
| NumberInput | `components/numberInput/` | 数字输入 | `value`、`min`、`max` |
| PriceInput | `components/priceInput/` | 价格输入 | `value`、`precision` |
| 组件 | 路径 | 说明 | 引入方式 |
|------|------|------|---------|
| BasicForm | `components/Form/` | 动态表单(`useForm` hook) | 全局注册 |
| BasicSelect | `components/Select/` | 选择器 | 按需 import |
| BasicUpload | `components/Upload/` | 文件上传 | 按需 import |
| UploadImg / UploadImages | `components/Upload/Image.vue`、`Images.vue` | 图片/多图上传(生成页面 edit.vue 使用) | 按需 import |
| Editor | `components/Editor/` | 富文本编辑器(TinyMCE) | 按需 import |
| Password | `components/Password/` | 密码强度 | 按需 import |
| ChinaArea | `components/ChinaArea/` | 省市区联动 | 按需 import |
| Region | `components/Region/` | 行政区划 | 按需 import |
| Cropper | `components/Cropper/` | 头像裁剪 | 按需 import |
| NumberInput / PriceInput | `components/numberInput/`、`priceInput/` | 数字 / 价格输入 | 全局注册 |
## Excel
## Excel 与导入导出
| 组件 | 路径 | 说明 |
|------|------|------|
| ImportExcel | `components/Excel/` | Excel 导入(解析文件) |
| Export2Excel | `components/Excel/` | Excel 导出(生成文件) |
| importFile | `components/importFile/index.vue` | 导入对话框(`api` + `templateCode`,下载模板 + 上传解析一体化) |
| ImpExcel | `components/Excel/` | Excel 导入解析组件 |
| jsonToSheetXlsx / aoaToSheetXlsx | `components/Excel/src/Export2Excel.ts` | Excel 导出(前端生成文件) |
| 导出接口 | `GET /api/{module}/export` | 后端生成文件(`ExcelService`),生成页面统一走此接口 |
## 其他
@@ -44,62 +60,85 @@
| CheckToken | `components/CheckToken/` | Token 校验组件 |
| Lockscreen | `components/Lockscreen/` | 锁屏组件 |
| Websocket | `components/Websocket/` | WebSocket 组件 |
| Render | `components/Render/` | 函数式渲染组件 |
## 使用示例
### BasicTable
### BasicForm(配合 useForm,摘自 `views/tool/example/index.vue`)
```vue
<template>
<BasicTable @register="registerTable" />
<BasicForm @register="register" @submit="handleSubmit" @reset="handleReset" />
</template>
<script setup>
import { BasicTable, useTable } from '@/components/Table';
import { useForm } from '@/components/Form/index';
import { schemas } from './querySchemas';
const [registerTable] = useTable({
api: getExamplePage,
columns: [
{ title: 'ID', field: 'id', width: 80 },
{ title: '名称', field: 'name' },
{ title: '状态', field: 'statusText', width: 100 },
],
const [register, { getFieldsValue }] = useForm({
schemas,
labelWidth: 80,
});
</script>
```
### BasicForm
### BasicTable(props 传数据,摘自 `views/tool/example/index.vue`)
```vue
<template>
<BasicForm @register="registerForm" />
<BasicTable
:columns="columns"
:request="loadDataTable"
:row-key="(row) => row.id"
ref="tableRef"
:actionColumn="actionColumn"
@selection-change="onSelectionChange"
>
<template #tableTitle>
<el-button type="primary" @click="handleAdd" v-perm="['sys:example:add']">
添加案例演示
</el-button>
</template>
</BasicTable>
</template>
<script setup>
import { BasicForm, useForm } from '@/components/Form';
import { TableAction } from '@/components/Table';
import { getExamplePage } from '@/api/tool/example';
import { columns } from './columns';
const [registerForm] = useForm({
schemas: [
{ field: 'name', label: '名称', component: 'Input', required: true },
{ field: 'status', label: '状态', component: 'Select', componentProps: { options: [...] } },
],
});
// 分页请求函数(返回 {records, total, current, size, pages})
const loadDataTable = (params) => getExamplePage(params);
</script>
```
### BasicModal
:::info 没有 useTable hook
本项目 `BasicTable` 通过 `:request` 传入分页请求函数,行操作用 `TableAction` 组件,无需 `useTable` 注册模式。
:::
### 行操作列(TableAction)
```typescript
import { TableAction } from '@/components/Table';
const actionColumn = {
width: 200,
title: '操作',
dataIndex: 'action',
slots: { customRender: 'action' },
};
```
### 导入对话框(importFile)
```vue
<template>
<BasicModal @register="registerModal" @ok="handleSubmit" />
</template>
<fileUpload
v-if="importVisible"
v-model:visible="importVisible"
api="/api/example/import"
templateCode="example_import"
@success="fetchData"
/>
```
<script setup>
import { BasicModal, useModal } from '@/components/Modal';
const [registerModal, { openModal, closeModal }] = useModal();
const handleAdd = () => openModal(true, { isUpdate: false });
const handleSubmit = async () => { /* ... */ closeModal(); };
</script>
```
(`templateCode` 对应文件模板表 `file_template` 中的模板编码,用于提供 Excel 下载模板。)
@@ -3,36 +3,33 @@
## 后端 .env 配置
:::tip 格式说明
`.env` 文件采用 INI 分组格式,`[SECTION]` 表示分组,分组下的 `KEY = value` 对应该分组的配置项。
本项目 `.env` 为**扁平键名**(无分组段),遵循 Laravel 约定;键名与 `config/*.php` 中的 `env()` 读取一一对应。
:::
### 全局变量
### 应用配置
| 变量 | 默认值 | 说明 |
|------|--------|------|
| `APP_ENV` | `local`(示例) | 运行环境(生产设为 `production`) |
| `APP_DEBUG` | `true` | 调试模式(生产环境设为 false) |
| `APP_KEY` | - | 应用密钥(`php artisan key:generate` 生成) |
| `APP_URL` | `http://localhost` | 应用地址 |
| `DEMO_MODE` | `false` | 演示模式开关 |
| `TRUSTED_PROXIES` | (空) | 受信代理 IP(逗号分隔,支持 CIDR),未配置时默认信任 `127.0.0.1` 和 `::1` |
| `DEFAULT_TENANT_ID` | `1` | 默认租户ID,超管操作租户隔离表时自动代入(`config/tenant.php`) |
### 应用配置 `[APP]`
### 数据库配置
| 变量 | 默认值 | 说明 |
|------|--------|------|
| `DEFAULT_TIMEZONE` | `Asia/Shanghai` | 默认时区 |
| `DEMO` | `false` | 演示模式(开启后拦截写操作) |
| `SHOW_ERROR_MSG` | `true` | 显示错误详情(生产环境设为 false) |
### 数据库配置 `[DATABASE]`
| 变量 | 默认值 | 说明 |
|------|--------|------|
| `TYPE` | `mysql` | 数据库类型:mysql / pgsql / sqlsrv / oracle / sqlite |
| `HOSTNAME` | `127.0.0.1` | 数据库主机 |
| `DATABASE` | - | 数据库名(SQLite 为文件路径) |
| `USERNAME` | `root` | 数据库用户 |
| `PASSWORD` | - | 数据库密码 |
| `HOSTPORT` | `3306` | 数据库端口 |
| `CHARSET` | `utf8mb4` | 字符集 |
| `DEBUG` | `true` | 是否开启 SQL 调试 |
| `PREFIX` | `think_` | 表前缀 |
| `DB_CONNECTION` | `sqlite` | 数据库类型:mysql / pgsql / sqlsrv / oracle / sqlite |
| `DB_HOST` | `127.0.0.1` | 数据库主机 |
| `DB_DATABASE` | - | 数据库名(SQLite 为文件路径) |
| `DB_USERNAME` | - | 数据库用户 |
| `DB_PASSWORD` | - | 数据库密码 |
| `DB_PORT` | `3306` | 数据库端口 |
| `DB_CHARSET` | `utf8mb4` | 字符集 |
| `DB_PREFIX` | `laravel_` | 表前缀(**与 SQL 脚本一致,勿改**) |
各数据库默认端口:
@@ -44,50 +41,52 @@
| Oracle | 1521 | - |
| SQLite | - | - |
### JWT 配置 `[JWT]`
### JWT 配置(`config/jwt.php`)
| 变量 | 默认值 | 说明 |
|------|--------|------|
| `SECRET` | 内置默认 | 签名密钥(**生产环境务必修改**) |
| `ACCESS_TTL` | `7200` | access_token 有效期(秒) |
| `REFRESH_TTL` | `604800` | refresh_token 有效期(秒) |
| `ISSUER` | `rxthinkcmf` | 签发者标识 |
| `JWT_SECRET` | (空) | 签名密钥(≥32 字符,**缺失/过短 fail-close**,生产环境务必修改) |
| `JWT_ACCESS_TTL` | `7200` | access_token 有效期(秒) |
| `JWT_REFRESH_TTL` | `604800` | refresh_token 有效期(秒) |
| `JWT_PERMS_TTL` | `7200` | 权限缓存有效期(秒) |
| `JWT_ISSUER` | `rxthinkcmf` | 签发者标识 |
### 文件上传配置 `[FILE]`
### 文件上传配置(`config/file.php`)
| 变量 | 默认值 | 说明 |
|------|--------|------|
| `UPLOAD_DIR` | - | 上传根目录(绝对路径) |
| `DOMAIN_URL` | - | 文件访问域名 |
| `IMAGE_EXT` | `gif,jpg,jpeg,png,bmp,webp,svg` | 图片允许后缀 |
| `FILE_UPLOAD_DIR` | `uploads` | 上传根目录(相对 `public/`) |
| `FILE_DOMAIN_URL` | (空) | 文件访问域名(留空按当前请求域名补全) |
| `FILE_IMAGE_EXT` | `gif,jpg,jpeg,png,bmp,webp` | 图片允许后缀 |
| `FILE_EXT` | 多种后缀 | 文件允许后缀 |
| `MAX_SIZE` | `10` | 最大文件大小(MB) |
| `FILE_MAX_SIZE` | `10` | 最大文件大小(MB) |
### 缓存配置 `[CACHE]`
### 会话 / 缓存 / 队列(Redis 必需)
| 变量 | 默认值 | 说明 |
|------|--------|------|
| `DRIVER` | `file` | 缓存驱动:file / redis |
| `REDIS_HOST` | `127.0.0.1` | Redis 主机(driver=redis 时生效) |
| `REDIS_PORT` | `6379` | Redis 端口(driver=redis 时生效) |
| `REDIS_PASSWORD` | - | Redis 密码 |
| `REDIS_DB` | `0` | Redis 数据库编号 |
| `REDIS_PREFIX` | `rx:` | 缓存键前缀 |
| `SESSION_DRIVER` | `redis` | 会话驱动 |
| `SESSION_LIFETIME` | `120` | 会话过期(分钟) |
| `CACHE_STORE` | `redis` | 缓存驱动 |
| `QUEUE_CONNECTION` | `redis` | 队列驱动 |
| `REDIS_CLIENT` | `phpredis` | Redis PHP 扩展 |
| `REDIS_HOST` | `127.0.0.1` | Redis 主机 |
| `REDIS_PORT` | `6379` | Redis 端口 |
| `REDIS_PASSWORD` | `null` | Redis 密码 |
### CORS 配置 `[CORS]`
### CORS 配置(`config/cors.php`)
| 变量 | 默认值 | 说明 |
|------|--------|------|
| `ALLOW_ORIGIN` | `*` | 允许的跨域来源 |
| `CORS_ALLOW_ORIGIN` | `*` | 允许的跨域来源(生产环境限制为实际域名) |
### API 配置 `[API]`
### API 配置(`config/api.php`)
| 变量 | 默认值 | 说明 |
|------|--------|------|
| `CAMEL_SNAKE_CONVERT` | `true` | 驼峰/下划线自动转换 |
| `PROXY_IPS` | (空) | 受信代理 IP 列表(逗号分隔,支持 CIDR)。部署在 CDN/负载均衡后面时配置,中间件会从 `X-Forwarded-For` / `X-Real-IP` 头提取真实客户端 IP。未配置时默认信任 `127.0.0.1` 和 `::1`。 |
| `API_CAMEL_SNAKE_CONVERT` | `true` | 驼峰/下划线自动转换 |
### 验证码配置 `[CAPTCHA]`
### 验证码配置(`config/captcha.php`)
| 变量 | 默认值 | 说明 |
|------|--------|------|
@@ -95,48 +94,47 @@
| `CAPTCHA_LENGTH` | `6` | 验证码字符长度(4-6位) |
| `CAPTCHA_EXPIRE` | `300` | 过期时间(秒) |
| `CAPTCHA_RATE_WINDOW` | `60` | 防刷窗口期(秒) |
| `CAPTCHA_RATE_LIMIT` | `20` | 窗口期内最大获取次数 |
| `CAPTCHA_RATE_LIMIT` | `10` | 窗口期内最大获取次数 |
| `CAPTCHA_CHARS` | `ABCDEFGHJKLMNPQRSTUVWXYZ2346789` | 字符集 |
| `CAPTCHA_FONT_PATH` | `static/fonts/Vera.ttf` | 字体路径 |
| `CAPTCHA_IMAGE_WIDTH` | `160` | 图片宽度(像素) |
| `CAPTCHA_IMAGE_HEIGHT` | `50` | 图片高度(像素) |
| `CAPTCHA_IMAGE_WIDTH` / `HEIGHT` | `160` / `50` | 图片尺寸(像素) |
| `CAPTCHA_FONT_SIZE` | `28` | 字体大小 |
| `CAPTCHA_NOISE_LINES` | `8` | 干扰线数量 |
| `CAPTCHA_NOISE_DOTS` | `500` | 噪点数量 |
| `CAPTCHA_NOISE_LINES` | `6` | 干扰线数量 |
| `CAPTCHA_NOISE_DOTS` | `300` | 噪点数量 |
### 代码生成器配置 `[GENERATOR]`
### 代码生成器配置(`config/generator.php`)
| 变量 | 默认值 | 说明 |
|------|--------|------|
| `PARENT_MENU_ID` | `189` | 生成模块的父菜单ID |
| `APP_NAME` | `tool` | 模块应用名(路由前缀) |
| `GENERATOR_PARENT_MENU_ID` | `189` | 生成模块的父菜单ID |
| `GENERATOR_APP_NAME` | `tool` | 模块应用名(路由前缀、前端目录) |
### 国际化配置 `[LANG]`
| 变量 | 默认值 | 说明 |
|------|--------|------|
| `default_lang` | `zh-cn` | 默认语言 |
## 前端环境变量
## 前端环境变量(`ui/.env*`)
| 变量 | 说明 |
|------|------|
| `VITE_GLOB_API_URL` | API 基础路径(如 `/api`) |
| `VITE_GLOB_API_URL_PREFIX` | API 前缀 |
| `VITE_GLOB_API_URL` | API 基础路径(留空表示同源) |
| `VITE_GLOB_API_URL_PREFIX` | API 前缀(默认 `/api`) |
| `VITE_GLOB_UPLOAD_URL` | 图片上传地址(跨域部署时配置) |
| `VITE_GLOB_IMG_URL` | 图片前缀地址 |
| `VITE_PORT` | 开发端口(默认 8001) |
| `VITE_DROP_CONSOLE` | 构建时删除 console |
## 配置文件对照
| .env 分组 | 配置文件 | 主要配置键 |
| .env 变量前缀 | 配置文件 | 主要配置键 |
|-----------|---------|-----------|
| `[DATABASE]` | `config/database.php` | `type` / `hostname` / `database` / `username` / `password` |
| `[JWT]` | `config/jwt.php` | `secret` / `access_ttl` / `refresh_ttl` |
| `[FILE]` | `config/file.php` | `upload_dir` / `domain_url` / `max_size` |
| `[CACHE]` | `config/cache.php` | `driver` / `redis_host` / `redis_port` |
| `[CORS]` | `config/cors.php` | `allow_origin` |
| `[API]` | `config/api.php` | `camel_snake_convert` |
| `[CAPTCHA]` | 无配置文件,`CaptchaService` 直接读取 `env()` | `captcha_bypass_code` / `captcha_length` / `captcha_expire` |
| `[LANG]` | `config/lang.php` | `default_lang` |
| — | `config/tenant.php` | `default_tenant_id` |
| `DB_*` | `config/database.php` | `default` / `connections.*` |
| `JWT_*` | `config/jwt.php` | `secret` / `access_ttl` / `refresh_ttl` / `perms_ttl` / `issuer` |
| `FILE_*` | `config/file.php` | `upload_dir` / `domain_url` / `temp_dir` / `image_ext` / `file_ext` / `max_size` |
| `CACHE_STORE` / `REDIS_*` | `config/cache.php`、`config/database.php` | `default` / `stores.redis` |
| `CORS_ALLOW_ORIGIN` | `config/cors.php` | `allow_origin` |
| `API_CAMEL_SNAKE_CONVERT` | `config/api.php` | `camel_snake_convert` / `convert_except_params` |
| `CAPTCHA_*` | `config/captcha.php` | 全部验证码参数 |
| `GENERATOR_*` | `config/generator.php` | `parent_menu_id` / `app_name` / `template_dir` / `backend_outputs` |
| `DEFAULT_TENANT_ID` | `config/tenant.php` | `default_tenant_id` |
| `TRUSTED_PROXIES` | `config/app.php` | `trusted_proxies` |
| `APP_TIMEZONE` | `config/app.php` | `timezone` |
### 租户配置
@@ -2,75 +2,96 @@
## SQL 脚本目录
项目为每种数据库提供了独立的 SQL 脚本:
项目为每种数据库提供了独立的 SQL 脚本(表前缀统一为 `laravel_`):
```text
document/
├── mysql/rxthinkcmf.thinkphp6.elevue.sql # MySQL 版本
├── postgresql/rxthinkcmf.thinkphp6.elevue.sql # PostgreSQL 版本
├── sqlserver/rxthinkcmf.thinkphp6.elevue.sql # SQL Server 版本
├── oracle/rxthinkcmf.thinkphp6.elevue.sql # Oracle 版本
└── sqlite/rxthinkcmf.thinkphp6.elevue.sql # SQLite 版本
├── mysql/rxthinkcmf.laravel13.elevue.sql # MySQL 版本(约 216MB)
├── postgresql/rxthinkcmf.laravel13.elevue.sql # PostgreSQL 版本
├── sqlserver/rxthinkcmf.laravel13.elevue.sql # SQL Server 版本
├── oracle/rxthinkcmf.laravel13.elevue.sql # Oracle 版本
└── sqlite/rxthinkcmf.laravel13.elevue.sql # SQLite 版本
```
各脚本已针对对应数据库的 SQL 语法做了适配,可直接导入使用。
:::info 审计字段说明
除关联表外,绝大多数表都包含统一的审计字段:`create_user`、`create_time`、`update_user`、`update_time`、`is_delete`(下表中略去)。主键统一为 `id`。
:::
## 用户相关
| 表名 | 说明 | 关键字段 |
|------|------|----------|
| think_user | 用户表 | tenant_id, code, username, password, salt, realname, gender, avatar, mobile, email, status, dept_id, level_id, position_id, province_code, city_code, district_code, street_code, city_info, address, intro, note, sort |
| think_user_role | 用户角色关联 | user_id, role_id |
| think_role | 角色表 | tenant_id, name, code, data_scope, sort, note |
| think_role_menu | 角色菜单关联 | role_id, menu_id |
| think_menu | 菜单表 | parent_id, name, permission, type, path, component |
| think_dept | 部门表 | parent_id, name, sort |
| think_position | 岗位表 | name, status, sort |
| think_level | 职级表 | name, status, sort |
| laravel_user | 用户表 | tenant_id, code, username, password, salt, realname, gender, avatar, mobile, email, status, dept_id, level_id, position_id, province_code, city_code, district_code, street_code, city_info, address, intro, sort, note |
| laravel_user_role | 用户角色关联 | user_id, role_id |
| laravel_role | 角色表 | tenant_id, name, code, sort, note |
| laravel_role_menu | 角色菜单关联 | role_id, menu_id |
| laravel_menu | 菜单表 | parent_id, name, icon, icon2, path, component, permission, target, type, status, hide, sort, note |
| laravel_dept | 部门表 | tenant_id, name, type, parent_id, sort, note |
| laravel_position | 岗位表 | tenant_id, name, status, sort |
| laravel_level | 职级表 | tenant_id, name, status, sort |
## 系统配置
| 表名 | 说明 | 关键字段 |
|------|------|----------|
| think_dict | 字典表 | name, code |
| think_dict_item | 字典项 | dict_id, name, value, sort |
| think_config | 配置表 | name, code |
| think_config_item | 配置项 | config_id, name, code, value |
| think_param | 参数表 | name, code, value, status |
| laravel_dict | 字典表 | name, code, sort, note |
| laravel_dict_item | 字典项 | dict_id, name, value, sort, note |
| laravel_config | 系统配置表 | name, code, sort, note |
| laravel_config_item | 配置项表 | config_id, name, code, value, options, type, status, sort, note |
| laravel_param | 系统参数表 | name, code, value, type, status, sort, note |
## 租户
| 表名 | 说明 | 关键字段 |
|------|------|----------|
| think_tenant | 租户表 | name, code, contact, mobile, email, address, status, expire_time, max_user_num, note |
| laravel_tenant | 租户表 | name, code, contact, mobile, email, address, logo, status, expire_time, max_user_num, note |
## 内容
| 表名 | 说明 | 关键字段 |
|------|------|----------|
| think_article | 文章表 | title, category_id, cover, content, status |
| think_category | 分类表 | parent_id, name, sort |
| think_link | 链接表 | name, url, sort |
| think_notice | 公告表 | title, content, status |
| laravel_article | 文章表 | tenant_id, category_id, title, cover, images, intro, content, author, status, click, sort |
| laravel_category | 文章分类表 | tenant_id, category_name, category_code, parent_id, sort, note |
| laravel_link | 友链表 | tenant_id, name, type, url, form, image, status, sort, note |
| laravel_notice | 通知公告表 | tenant_id, title, cover, type, click_num, status, content |
## 日志
| 表名 | 说明 | 关键字段 |
|------|------|----------|
| think_login_log | 登录日志 | username, status, ip, location |
| think_operation_log | 操作日志 | title, type, method, url, param, ip |
| laravel_login_log | 登录日志表 | username, log_type, source, method, request_method, url, param, result, ip, location, os, browser, consume_time, status, error |
| laravel_operation_log | 操作日志表 | title, type, source, method, request_method, url, param, result, ip, location, os, browser, consume_time, status, error |
## 定时任务
| 表名 | 说明 | 关键字段 |
|------|------|----------|
| think_job | 任务表 | job_name, url, cron_expression, status |
| think_job_log | 任务日志 | job_id, status, job_message |
| laravel_job | 定时任务表 | job_name, job_alias, job_group, job_trigger, status, cron_expression, execute_policy, is_sync, url, params, note |
| laravel_job_log | 定时任务日志表 | job_id, job_name, job_group, job_trigger, job_message, cron_expression, status, start_time, end_time, consume_time, exception_info |
## 其他
| 表名 | 说明 | 关键字段 |
|------|------|----------|
| think_city | 城市表 | name, code, parent_code, level |
| think_file_template | 文件模板 | name, code, file_path |
| think_example | 案例演示 | name, type, status, sort, avatar |
| laravel_city | 城市行政区划表 | city_code, area_code, parent_code, zip_code, level, pid, name, short_name, full_name, pinyin, lng, lat |
| laravel_file_template | 文件模板表 | name, code, file_name, file_path, sort, note |
| laravel_example | 案例演示表 | name, avatar, type, status, sort |
## ER 关系速览
```text
laravel_user ──< laravel_user_role >── laravel_role ──< laravel_role_menu >── laravel_menu
│ ▲
└── dept_id ──> laravel_dept │
└── level_id ──> laravel_level parent_id(树形)
└── position_id ──> laravel_position
laravel_dict ──< laravel_dict_item
laravel_config ──< laravel_config_item
laravel_job ──< laravel_job_log
laravel_article >── laravel_category(category_id)
laravel_menu.parent_id 自关联(菜单树)
laravel_dept.parent_id 自关联(部门树)
```
@@ -1,84 +1,114 @@
# I. 前端 Enums 速查
:::tip 概述
前端枚举定义在 `ui/src/enums/` 目录下,用于统一管理常量值。
前端枚举与常量定义在 `ui/src/enums/` 目录下,全局存储键名在 `ui/src/store/mutation-types.ts`。
:::
## httpEnum
**文件**:`enums/httpEnum.ts`
**文件**:`ui/src/enums/httpEnum.ts`
```typescript
// 请求方法
/**
* @description: 请求结果集
*/
export enum ResultEnum {
SUCCESS = 0, // 本项目成功码(统一响应 code=0)
ERROR = 1, // 业务失败
TIMEOUT = 401, // Token 过期
TYPE = 'success',
}
/**
* @description: 请求方法
*/
export enum RequestEnum {
GET = 'GET',
POST = 'POST',
PATCH = 'PATCH',
PUT = 'PUT',
DELETE = 'DELETE',
}
// 响应状态码
export enum ResultEnum {
SUCCESS = 0, // 业务成功
FAIL = 1, // 业务失败
}
// 内容类型
/**
* @description: 常用的 contentType 类型
*/
export enum ContentTypeEnum {
JSON = 'application/json',
FORM_URLENCODED = 'application/x-www-form-urlencoded',
JSON = 'application/json;charset=UTF-8',
TEXT = 'text/plain;charset=UTF-8',
FORM_URLENCODED = 'application/x-www-form-urlencoded;charset=UTF-8',
FORM_DATA = 'multipart/form-data;charset=UTF-8',
}
```
## pageEnum
**文件**:`enums/pageEnum.ts`
**文件**:`ui/src/enums/pageEnum.ts`
```typescript
export enum PageEnum {
// 登录页
// 登录
BASE_LOGIN = '/login',
BASE_LOGIN_NAME = 'Login',
// 重定向
REDIRECT = '/redirect',
REDIRECT_NAME = 'Redirect',
// 首页
BASE_HOME = '/dashboard',
// 错误页
BASE_ERROR_LOG = '/exception/404',
REDIRECT = '/redirect',
// 首页跳转默认路由
BASE_HOME_REDIRECT = '/dashboard/console',
// 错误
ERROR_PAGE_NAME = 'ErrorPage',
}
```
## 其它枚举
| 文件 | 导出 | 说明 |
|------|------|------|
| `avatarEnum.ts` | `avatarEnum` | 默认头像资源路径(avatar-1 ~ 6) |
| `breakpointEnum.ts` | `sizeEnum` / `screenEnum` / `screenMap` | 响应式断点(XS 480 ~ XXL 1600) |
| `cacheEnum.ts` | `TOKEN_KEY`、`USER_INFO_KEY`、`ROLES_KEY` 等 | 本地缓存键名常量 |
| `permissionsEnum.ts` | `PermissionsEnum`(interface) | 权限项类型 `{ value, label }` |
| `roleEnum.ts` | `RoleEnum` | 角色(`admin` / `normal`) |
## store/mutation-types
**文件**:`ui/src/store/mutation-types.ts` — Storage / Pinia 使用的全局键名:
```typescript
export const ACCESS_TOKEN = 'ACCESS-TOKEN'; // 用户 token
export const CURRENT_USER = 'CURRENT-USER'; // 当前用户信息
export const IS_LOCKSCREEN = 'IS-LOCKSCREEN'; // 是否锁屏
export const TABS_ROUTES = 'TABS-ROUTES'; // 标签页
export const FIRST_ROUTE = 'FIRST-ROUTE'; // 菜单第一个路由
```
## 使用示例
```typescript
import { ResultEnum } from '@/enums/httpEnum';
import { PageEnum } from '@/enums/pageEnum';
import { ACCESS_TOKEN } from '@/store/mutation-types';
// 判断响应是否成功
if (response.code === ResultEnum.SUCCESS) {
// 处理成功
}
if (code === ResultEnum.SUCCESS) { ... }
// 跳转登录页
router.push(PageEnum.BASE_LOGIN);
// 判断请求方法
if (method === RequestEnum.POST) {
// POST 请求
}
// 读取 token
const token = storage.get(ACCESS_TOKEN, '');
```
## 自定义枚举
```typescript
// 添加新枚举时,在 enums/ 目录下创建文件
// ui/src/enums/statusEnum.ts
新增业务枚举放在 `ui/src/enums/` 下,文件名以 `Enum` 结尾(如 `statusEnum.ts`),导出 `enum` 或常量对象:
```typescript
// ui/src/enums/statusEnum.ts
export enum UserStatus {
ENABLE = 1,
DISABLE = 2,
}
export enum ArticleStatus {
DRAFT = 0,
PUBLISHED = 1,
}
```
```
@@ -8,12 +8,13 @@
| 问题 | 解决方案 |
|------|----------|
| PHP 版本低于 8.2 | 升级到 PHP 8.2+,项目使用了 8.2 的强类型特性 |
| 缺少 pdo_mysql 扩展 | `apt install php8.2-mysql` 或 `dnf install php-mysqlnd` |
| 缺少 gd 扩展 | `apt install php8.2-gd` 或 `dnf install php-gd` |
| PHP 版本低于 8.3 | 升级到 PHP 8.3+(Laravel 13 要求),项目使用了 8.3 的语言特性 |
| 缺少 pdo_mysql 扩展 | `apt install php8.3-mysql` 或 `dnf install php-mysqlnd` |
| `could not find driver`(`db:migrate` 迁到 PostgreSQL) | php.ini 扩展区启用 `extension=pdo_pgsql`(Windows 自带 `php_pdo_pgsql.dll` + `libpq.dll`,取消注释即可;Linux `apt install php8.3-pgsql`),CLI 重读 php.ini 无需重启 |
| 缺少 gd 扩展 | `apt install php8.3-gd` 或 `dnf install php-gd` |
| 缺少 redis 扩展 | `apt install php8.3-redis` 或 `pecl install redis`(**必需**:缓存/会话/队列/JWT 均依赖) |
| Redis 未安装 | 安装 Redis 6.0+ 并配置密码(本项目 `.env.example` 默认全部 Redis 驱动,不建议改 file) |
| Composer 下载慢 | `composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/` |
| Redis 未安装 | 可选,改用 file 缓存:`.env` 中 `[CACHE]` 下设置 `DRIVER = file` |
| 缺少 redis 扩展 | `pecl install redis` |
| Oracle pdo_oci 加载失败(Windows) | 安装 Oracle Instant Client 19c + VC++ 2015-2022 Redistributable,php.ini 启用 `extension=pdo_oci`,配置系统 PATH 后重启 Apache |
| 命令行有 pdo_oci,浏览器 phpinfo 没有 | Apache 服务启动时 PATH 未刷新,完全停止再启动 Apache 即可 |
| Oracle Instant Client 路径含中文/空格导致加载失败 | 解压到 `C:\oracle\instantclient_19_20` 等固定路径,避免空格与中文 |
@@ -22,36 +23,39 @@
| 问题 | 解决方案 |
|------|----------|
| 端口被占用 | `php think run --port 8080` |
| 数据库连接失败 | 检查 `.env` 中的数据库配置 |
| 401 未授权 | 检查请求头是否携带 `Authorization: Bearer <token>` |
| 端口被占用 | `php artisan serve --port=8080` |
| 数据库连接失败 | 检查 `.env` 中的数据库配置(注意 `DB_PREFIX=laravel_` 与 SQL 脚本一致) |
| 表不存在 | 本项目无 migration 建表,导入 `document/mysql/*.sql`(见 [2.5 数据库初始化](/zh/quickstart/database-init.html)) |
| 401 未授权 | 检查请求头是否携带 `Authorization: Bearer <token>`,确认 `JWT_SECRET` 配置(缺失/过短会 fail-close) |
| 403 禁止访问 | 检查用户权限配置,确认角色已分配菜单 |
| 502 Bad Gateway | 检查 PHP-FPM 是否启动:`systemctl status php8.2-fpm` |
| 502 Bad Gateway | 检查 PHP-FPM 是否启动:`systemctl status php8.3-fpm` |
| 登录失败/缓存不生效 | 检查 Redis 是否运行、`REDIS_*` 配置是否正确(见 [11.10 故障排查手册](/zh/deploy/troubleshooting.html)) |
## 业务问题
| 问题 | 解决方案 |
|------|----------|
| 唯一性校验报错 | 检查数据是否重复,确认 `uniqueFields` 配置 |
| 枚举显示名为空 | 检查字典配置,确认 `serializeMaps` 正确 |
| 文件上传失败 | 检查 `FILE.UPLOAD_DIR` 配置和目录权限 |
| 枚举显示名为空 | 检查字典配置,确认 `serializeMaps` 正确、字典编码已创建 |
| 文件上传失败 | 检查 `FILE_UPLOAD_DIR` / `FILE_MAX_SIZE` 配置和 `public/uploads/` 目录权限 |
| 导入失败 | 检查 Excel 表头是否与 `headerMap` 一致 |
| 排序不生效 | 检查 `pageOrderBy` 配置,或前端 `orderField` 参数 |
| 排序不生效 | 检查 `pageOrderBy` 配置,或前端 `orderField` 是否在白名单(`pageOrderBy` ∪ `orderFieldAllow`)内 |
## 前端问题
| 问题 | 解决方案 |
|------|----------|
| pnpm install 失败 | `rm -rf node_modules pnpm-lock.yaml && pnpm install` |
| API 404 | 检查后端路由注册和 Vite 代理配置 |
| 菜单不显示 | 检查菜单配置、组件路径、角色权限 |
| pnpm install 失败 | `rm -rf node_modules && pnpm install --force`(锁文件 `pnpm-lock.yaml` 保留) |
| API 404 | 检查后端路由注册和 Vite 代理 / Nginx `proxy_pass` 配置 |
| 菜单不显示 | 检查菜单配置、组件路径、角色权限,重新登录刷新动态菜单 |
| 白屏 | 打开 F12 控制台查看错误 |
| Token 频繁过期 | 检查 `JWT.ACCESS_TTL` 配置(默认 7200 秒) |
| Token 频繁过期 | 检查 `JWT_ACCESS_TTL` 配置(默认 7200 秒),或使用 `refresh` 刷新令牌 |
## 定时任务问题
| 问题 | 解决方案 |
|------|----------|
| 任务不执行 | 检查 crontab 配置:`crontab -l` |
| 任务重复执行 | 检查是否有多个 cron 或 daemon 在运行 |
| 任务执行超时 | 检查 PHP `max_execution_time` 配置 |
| 任务不执行 | 检查 crontab 配置:`crontab -l`;手动执行 `php artisan job:run` 验证 |
| 任务重复执行 | 检查是否有多个 `job:run` cron 或 `job:daemon` 守护进程在运行 |
| 任务执行超时 | 检查 PHP `max_execution_time` 配置 |
| 内部任务处理器不存在 | `url` 字段按 `App\Task\{名称}Task` 映射,确认类名与 `run()` 方法存在(见 [6.11 定时任务](/zh/modules/job.html)) |
@@ -1,7 +1,7 @@
# D. 公共函数速查
:::tip 概述
以下函数定义在 `app/common.php` 中,可在任何地方直接调用。
以下函数定义在 `app/Helpers/helpers.php` 中(通过 `composer.json` 的 `autoload.files` 自动加载),可在任何地方直接调用。
:::
## 字符串 / 加密
@@ -9,21 +9,25 @@
| 函数 | 说明 | 签名 |
|------|------|------|
| `random_string($length)` | 生成随机字符串 | `string random_string(int $length = 16)` |
| `encrypt_password($password, $salt)` | 密码加密(bcrypt) | `array encrypt_password(string $password, ?string $salt = null)` |
| `encrypt_password($password, $salt)` | 密码加密(委托 PasswordService) | `array encrypt_password(string $password, ?string $salt = null)` |
| `verify_password($password, $hash, $salt)` | 验证密码 | `bool verify_password(string $password, string $encryptPassword, string $salt)` |
## 文件处理
| 函数 | 说明 | 签名 |
|------|------|------|
| `upload_file($formName, $type)` | 上传文件到临时目录 | `array upload_file(string $formName = 'file', string $type = 'file')` |
| `save_file($fileUrl, $saveDir)` | 临时文件迁移到正式目录 | `string\|false save_file(string $fileUrl, string $saveDir = '')` |
| `save_content(&$content, $saveDir)` | 处理富文本中的媒体文件 | `bool save_content(string &$content, string $saveDir = 'article')` |
| `save_file($fileUrl, $saveDir)` | 临时文件迁移到正式目录 | `save_file(string $fileUrl, string $saveDir = '')` |
| `save_content(&$content, $saveDir)` | 处理富文本中的媒体文件(迁移 + 域名替换) | `bool save_content(string &$content, string $saveDir = 'article')` |
| `save_content_match(...)` | 富文本内单类 URL 匹配迁移(save_content 内部使用) | `void save_content_match(string $content, string $pattern, string $domainUrl, string $saveDir, array &$urlMap)` |
| `get_file_url($path)` | 相对路径转完整 URL | `string get_file_url(string $path)` |
| `create_file_path($saveDir, $ext)` | 生成文件存储路径 | `string create_file_path(string $saveDir = '', string $ext = '')` |
| `save_remote_file($url, $saveDir)` | 保存远程文件 | `string\|false save_remote_file(string $url, string $saveDir = '')` |
| `create_file_path($saveDir, $ext)` | 生成文件存储路径(按日期分目录) | `string create_file_path(string $saveDir = '', string $ext = '')` |
| `save_remote_file($url, $saveDir)` | 保存远程文件 | `save_remote_file(string $url, string $saveDir = '')` |
| `detect_image_ext($content)` | 根据内容检测图片后缀 | `?string detect_image_ext(string $content)` |
:::info 上传入口不在这里
HTTP 文件上传入口是 `POST /api/upload/uploadFile`(见 [7.1 文件上传全流程](/zh/tools/upload.html)),业务层的临时→正式迁移由 `HasFileProcessing` Trait 调用 `save_file()` / `save_content()` 完成。
:::
## 驼峰 / 下划线转换
| 函数 | 说明 | 签名 |
@@ -32,14 +36,18 @@
| `camel_to_snake($str)` | 驼峰转下划线 | `string camel_to_snake(string $str)` |
| `array_snake_to_camel($data)` | 数组键名下划线转驼峰(递归) | `array array_snake_to_camel(array $data)` |
| `array_camel_to_snake($data, $except)` | 数组键名驼峰转下划线(递归) | `array array_camel_to_snake(array $data, array $except = [])` |
| `is_camel_convert_enabled()` | 是否开启转换 | `bool is_camel_convert_enabled()` |
| `is_camel_convert_enabled()` | 是否开启转换(读 `config('api.camel_snake_convert')`) | `bool is_camel_convert_enabled()` |
| `convert_to_camel($data)` | 单条数据转驼峰(受开关控制) | `convert_to_camel($data)` |
| `convert_list_to_camel($list)` | 列表数据转驼峰(受开关控制) | `array convert_list_to_camel(array $list)` |
## 工具函数
| 函数 | 说明 | 签名 |
|------|------|------|
| `get_client_ip()` | 获取客户端 IP | `string get_client_ip()` |
| `format_page_params($params)` | 格式化分页参数 | `array format_page_params(array $params)` |
| `get_client_ip()` | 获取客户端 IP(经 ProxyMiddleware 受信代理解析) | `string get_client_ip()` |
| `is_internal_ip($ip)` | 判断是否内网 / 回环地址 | `bool is_internal_ip(string $ip)` |
| `format_page_params($params)` | 格式化分页参数(pageNo ≥ 1、pageSize 1~100) | `array format_page_params(array $params)` |
| `build_tree($list, $parentId, $parentField)` | 平面列表组装为树 | `array build_tree(array $list, int $parentId = 0, string $parentField = 'parent_id')` |
## 使用示例
@@ -47,20 +55,24 @@
// 生成随机字符串
$str = random_string(32);
// 密码加密
// 密码加密与验证
$result = encrypt_password('123456');
// ['password' => '$2y$12$...', 'salt' => 'xK7pMn3qRt']
// 验证密码
$ok = verify_password('123456', $user->password, $user->salt);
// 文件上传
$result = upload_file('avatar', 'image');
if (isset($result['error'])) {
return Result::fail($result['error']);
// 临时文件迁移到正式目录(HasFileProcessing 内部即这样调用)
$result = save_file($data['avatar'], 'user');
if ($result === false) {
// 保留原值,避免误清空
}
// 相对路径补全域名
$url = get_file_url($data['avatar']);
// 驼峰转换
camel_to_snake('createTime'); // 'create_time'
snake_to_camel('create_time'); // 'createTime'
```
// 平面列表组装为树(树形模块 treeList 使用)
$tree = build_tree($list, 0, 'parent_id');
```
@@ -4,19 +4,20 @@
| 术语 | 全称 | 说明 |
|------|------|------|
| JWT | JSON Web Token | 无状态认证令牌,用于接口认证 |
| JWT | JSON Web Token | 无状态认证令牌,用于接口认证(本项目 Redis 有状态双令牌) |
| RBAC | Role-Based Access Control | 基于角色的访问控制 |
| CORS | Cross-Origin Resource Sharing | 跨域资源共享 |
| ORM | Object-Relational Mapping | 对象关系映射,数据库操作抽象层 |
| ORM | Object-Relational Mapping | 对象关系映射(本项目使用 Laravel Eloquent) |
| CRUD | Create/Read/Update/Delete | 增删改查 |
| API | Application Programming Interface | 应用程序编程接口 |
| bcrypt | - | 密码哈希算法,内置盐值 |
| OPcache | - | PHP 字节码缓存扩展 |
| Redis | - | 内存数据库,用于缓存 |
| Redis | - | 内存数据库,用于缓存/会话/队列/JWT 状态 |
| Nginx | - | Web 服务器 / 反向代理 |
| Composer | - | PHP 依赖管理工具 |
| PSR | PHP Standards Recommendation | PHP 标准推荐 |
| FPM | FastCGI Process Manager | PHP 进程管理器 |
| Artisan | - | Laravel 命令行工具(`php artisan ...`) |
| DNF | Dandified Yum | Rocky Linux / CentOS 包管理器 |
| PECL | PHP Extension Community Library | PHP 扩展安装工具 |
@@ -44,14 +45,14 @@
|------|------|
| 软删除 | 通过 `is_delete` 字段标记删除,不物理删除 |
| 租户隔离 | 通过 `tenant_id` 字段实现多租户数据隔离 |
| 数据权限 | 基于角色的 data_scope 控制数据可见范围 |
| access_token | 访问令牌,短期有效(默认 2 小时) |
| refresh_token | 刷新令牌,长期有效(默认 7 天) |
| 数据权限 | `HasDataScope` 按角色数据范围过滤(当前角色不存储范围字段,默认全部数据) |
| access_token | 访问令牌,短期有效(`JWT_ACCESS_TTL` 默认 7200 秒) |
| refresh_token | 刷新令牌,长期有效(`JWT_REFRESH_TTL` 默认 604800 秒) |
| 驼峰命名 | camelCase,如 `createTime` |
| 下划线命名 | snake_case,如 `create_time` |
| RBAC | 基于角色的访问控制:用户 → 角色 → 菜单/权限 |
| 超级管理员 | uid=1 的用户,跳过所有权限校验 |
| 租户管理员 | tenant_id=0 的用户,不受租户隔离限制 |
| 超级管理员 | uid=1 的用户,跳过权限与租户校验 |
| 平台用户 | `tenant_id = 0` 的用户,不属于任何租户 |
| 声明式 CRUD | 通过属性配置定义行为,无需编写通用代码 |
| 生命周期钩子 | beforeAdd/afterAdd 等,用于注入定制逻辑 |
@@ -59,14 +60,16 @@
| 术语 | 说明 |
|------|------|
| BaseLogic | 业务逻辑基类,提供声明式 CRUD 能力 |
| BaseTenantLogic | 租户逻辑基类,继承 BaseLogic,自动租户隔离 |
| BaseController | 控制器基类,提供统一响应和通用 CRUD 方法 |
| BaseModel | 模型基类,提供软删除和审计字段 |
| Result | 统一响应类,构造标准 JSON 响应 |
| ExceptionHandle | 异常处理类,统一捕获异常并返回 JSON |
| AttributeService | 注解服务,通过反射读取控制器方法注解 |
| DictService | 字典服务,提供字典项读取和缓存 |
| ParamService | 参数服务,提供系统参数读取和缓存 |
| PasswordService | 密码服务,bcrypt 双重加盐加密 |
| JwtService | JWT 服务,签发/刷新/解析令牌 |
| BaseService | 业务服务基类,声明式 CRUD 能力(6 个 Trait 组合) |
| BaseTenantService | 租户服务基类,继承 BaseService,自动租户隔离 |
| Controller 基类 | `App\Http\Controllers\Controller`,提供 success/fail/paginate/_page 等通用方法 |
| Eloquent Model | 模型基类,配合 `SoftDeletesByFlag`(软删除)与 `HasAuditColumns`(审计字段)Trait |
| Result | 统一响应类(`app/Support/Result.php`),构造标准 JSON 响应 |
| Handler | 异常处理类(`app/Exceptions/Handler.php`),统一捕获异常并返回 JSON |
| BizException | 业务异常,`code` 携带业务错误码,转为失败响应 |
| 权限/日志注解 | `#[Permission]` / `#[OperationLog]` / `#[DemoAllow]`(`app/Attributes/`),由中间件反射读取 |
| DictCacheService | 字典服务,提供字典项读取和两级缓存 |
| ParamService | 参数服务,提供系统参数读取(请求级缓存) |
| PasswordService | 密码服务,加盐哈希加密与校验 |
| JwtService | JWT 服务,签发/刷新/解析令牌 |
| FormRequest | Laravel 表单请求验证器(`app/Http/Requests/`),本项目基类 `BaseRequest` |
@@ -1,7 +1,7 @@
# F. 中间件执行顺序
:::tip 概述
本页展示请求在框架中的完整中间件执行流程,包括全局中间件和应用中间件的执行顺序,帮助开发者理解请求处理链路。
本页展示请求在框架中的完整中间件执行流程,包括全局中间件和路由级中间件的执行顺序,帮助开发者理解请求处理链路。注册位置:`bootstrap/app.php`(别名 + API 组)与 `routes/api.php`(路由组)。
:::
## 执行流程图
@@ -11,39 +11,48 @@
│
▼
┌────────────────┐
│ProxyMiddleware │ 全局中间件(最先执行)
│ProxyMiddleware │ API 组前置(最先执行)
│ │ 从代理头提取真实客户端 IP
└──────┬─────────┘
│
▼
┌──────────────┐
│CorsMiddleware│ 全局中间件
│ Cors │ API 组前置
│ │ 处理 OPTIONS 预检 + 跨域响应头
└──────┬───────┘
│
▼
┌──────────────┐ 401
│AuthMiddleware│──────────► 未认证(Token 缺失/无效/过期)
│ │ 403
│ JWT认证 │──────────► 无权限
│ 权限校验 │
└──────┬───────┘
│ 注入 userInfo
▼
┌──────────────┐ 403
│TenantMiddleware│──────────► 租户异常(禁用/过期)
│ │
│ 租户上下文 │
└──────┬───────┘
│ 注入 tenantId, tenantInfo
▼
┌──────────────┐ 403
│DemoMiddleware│──────────► 演示环境禁止写操作
┌──────────────┐
│ForceJson │ API 组前置
│Response │ 强制返回 JSON 响应头
└──────┬───────┘
│
▼
┌──────────────┐ 401
│Authenticate │──────────► 未认证(Token 缺失/无效/过期)
│ (auth.jwt) │ 403
│ JWT认证 │──────────► 无权限
│ 权限校验 │
└──────┬───────┘
│ 注入 userInfo(attributes)
▼
┌──────────────┐ 403
│ResolveTenant │──────────► 租户异常(禁用/过期)
│ (tenant) │
│ 租户上下文 │
└──────┬───────┘
│ 注入 tenantId / isSuperAdmin / tenantInfo
▼
┌──────────────┐ 403
│ demo │──────────► 演示模式下写操作被拦截
│ (demo 别名) │
│ 演示模式拦截 │
└──────┬───────┘
│ 放行:非演示模式 / GET / 有 #[DemoAllow]
▼
┌──────────────┐
│ LogMiddleware│ 记录操作日志(写操作始终记录)
│ LogOperation │ 记录操作日志(terminable,响应后写入)
│(log.operation)│ 写操作始终记录
└──────┬───────┘
│
▼
@@ -52,46 +61,53 @@
└──────────────┘
```
:::info 两种挂载方式
- **API 组前置**(`bootstrap/app.php` → `$middleware->api(prepend:)`):Proxy → Cors → ForceJson,对全部 `/api` 请求生效
- **路由组**(`routes/api.php` → `Route::middleware([...])->group(...)`):`auth.jwt` → `tenant` → `demo` → `log.operation`,仅认证接口组生效;登录、验证码、令牌刷新等公开接口定义在组外,天然免认证
:::
## 中间件职责
| 中间件 | 类型 | 职责 | 配置 |
|--------|------|------|------|
| ProxyMiddleware | 全局 | 代理头解析,提取真实客户端 IP | .env → `[API]` PROXY_IPS |
| CorsMiddleware | 全局 | 跨域处理 | config/cors.php |
| AuthMiddleware | 路由级 | JWT 认证 + 权限校验 | config/middleware.php → auth_except |
| TenantMiddleware | 路由级 | 租户上下文注入 | 内置排除列表 |
| DemoMiddleware | 路由级 | 演示环境拦截 | .env → [APP] DEMO |
| LogMiddleware | 路由级 | 操作日志记录 | config/middleware.php → log_except |
| ProxyMiddleware | API 组前置 | 代理头解析,提取真实客户端 IP | `.env` → `TRUSTED_PROXIES` |
| Cors | API 组前置 | 跨域处理(OPTIONS 预检 + 响应头) | `config/cors.php` → `CORS_ALLOW_ORIGIN` |
| ForceJsonResponse | API 组前置 | 强制 `Content-Type: application/json` | — |
| Authenticate | 路由组(别名 `auth.jwt`) | JWT 认证 + 权限校验(`#[Permission]` 注解) | `config/middleware.php` → `auth_except` |
| ResolveTenant | 路由组(别名 `tenant`) | 租户上下文注入与校验 | 超管(uid=1)跳过校验 |
| LogOperation | 路由组(别名 `log.operation`) | 操作日志记录(terminable,响应后落库) | `config/middleware.php` → `log_except` |
| DemoMiddleware | 路由组(别名 `demo`,tenant 与 log.operation 之间) | 演示模式拦截写操作(无 `#[DemoAllow]` 的写操作返回 403) | `config('app.demo_mode')` |
## 排除配置
```php
// config/middleware.php
return [
// Authenticate::handle() 命中时跳过 JWT 解析与权限校验(公开接口定义在路由组外,此为兜底)
'auth_except' => [
'login',
'captcha',
'oauth2/token',
'oauth2/check/token',
'refresh',
],
// LogOperation::handle() 命中时不写入 OperationLog
// 登录/登出由 LoginLog 单独记录
'log_except' => [
'login',
'logout',
'captcha',
'oauth2',
],
];
```
## 注入内容
| 中间件 | 注入字段 | 说明 |
|--------|---------|------|
| ProxyMiddleware | `$_SERVER['REMOTE_ADDR']` | 覆盖为真实客户端 IP |
| AuthMiddleware | `$request->userInfo` | 用户信息(uid, username, type 等) |
| TenantMiddleware | `$request->tenantId` | 租户 ID(0=超级管理员) |
| TenantMiddleware | `$request->isSuperAdmin` | 是否超级管理员 |
| TenantMiddleware | `$request->tenantInfo` | 租户信息对象 |
| 中间件 | 注入字段 | 读取方式 | 说明 |
|--------|---------|---------|------|
| ProxyMiddleware | `$_SERVER['REMOTE_ADDR']` | `request()->ip()` | 覆盖为真实客户端 IP |
| Authenticate | `userInfo` | `$request->attributes->get('userInfo')` | 解码后的 JWT 载荷(uid、username 等) |
| ResolveTenant | `tenantId` | `$request->attributes->get('tenantId')` | 租户 ID(0=平台用户) |
| ResolveTenant | `isSuperAdmin` | `$request->attributes->get('isSuperAdmin')` | 是否超级管理员(uid=1) |
| ResolveTenant | `tenantInfo` | `$request->attributes->get('tenantInfo')` | 非平台用户时注入租户模型实例 |
## ProxyMiddleware 详解
@@ -106,15 +122,15 @@ return [
X-Real-IP: 真实IP
```
1. 检查 `REMOTE_ADDR` 是否在受信代理列表(`.env` → `PROXY_IPS`)
1. 检查 `REMOTE_ADDR` 是否在受信代理列表(`.env` → `TRUSTED_PROXIES`,支持 CIDR 网段)
2. 如果是,从 `X-Real-IP` 或 `X-Forwarded-For` 头提取真实 IP
3. 覆盖 `$_SERVER['REMOTE_ADDR']`,后续 `request()->ip()` 返回真实 IP
3. 覆盖 `$_SERVER['REMOTE_ADDR']`,后续 `request()->ip()` 与 `get_client_ip()` 返回真实 IP
### 配置
```ini
# .env [API] 段
# .env
# 受信代理 IP(逗号分隔,支持 CIDR 网段)
# 未配置时默认信任 127.0.0.1 和 ::1
PROXY_IPS = 127.0.0.1,::1,101.226.0.0/15,180.101.0.0/16
```
TRUSTED_PROXIES=127.0.0.1,::1,101.226.0.0/15,180.101.0.0/16
```
@@ -1,30 +1,40 @@
# H. 前端 Store 速查
:::tip 概述
前端使用 Pinia 进行全局状态管理,核心 Store 定义在 `ui/src/store/modules/` 目录下。
前端使用 Pinia 进行全局状态管理,核心 Store 定义在 `ui/src/store/modules/` 目录下,入口为 `ui/src/store/index.ts`(`setupStore()` 挂载)。
:::
## userStore
**文件**:`store/modules/user.ts`
**文件**:`ui/src/store/modules/user.ts`(id:`app-user`,token/用户信息持久化到 localStorage)
### 状态
| 字段 | 类型 | 说明 |
|------|------|------|
| `token` | string | JWT Token |
| `token` | string | JWT Token(`ACCESS_TOKEN`) |
| `username` | string | 用户名 |
| `welcome` | string | 欢迎语 |
| `avatar` | string | 头像 URL |
| `permissions` | string[] | 权限列表 |
| `info` | object | 用户信息 |
| `permissions` | any[] | 权限列表 |
| `info` | object | 用户信息(`CURRENT_USER`) |
### Getters
| Getter | 说明 |
|--------|------|
| `getToken` / `getAvatar` / `getNickname` | 取 token / 头像 / 昵称 |
| `getPermissions` | 取权限列表 |
| `getUserInfo` | 取用户信息 |
### Actions
| Action | 说明 | 返回 |
|--------|------|------|
| `login(userInfo)` | 登录 | Promise |
| `GetInfo()` | 获取用户信息 | Promise |
| `logout()` | 登出 | Promise |
| Action | 说明 |
|--------|------|
| `setToken` / `setAvatar` / `setPermissions` / `setUserInfo` | 状态写入 |
| `login(userInfo)` | 登录,成功后写入 `access_token`(7 天过期) |
| `GetInfo()` | 拉取用户信息与权限列表 |
| `logout()` | 登出,清空状态与本地存储 |
### 使用示例
@@ -48,29 +58,23 @@ await userStore.logout();
## asyncRouteStore
**文件**:`store/modules/asyncRoute.ts`
**文件**:`ui/src/store/modules/asyncRoute.ts`(id:`app-async-route`)
### 状态
| 字段 | 类型 | 说明 |
|------|------|------|
| `menus` | array | 菜单列表 |
| `keepAliveComponents` | string[] | 缓存的组件名 |
| `isDynamicAddedRoute` | boolean | 是否已添加动态路由 |
### Actions
| Action | 说明 |
| 字段 / Action | 说明 |
|--------|------|
| `generateRoutes(userInfo)` | 从后端获取菜单并生成路由 |
| `routers` / `getRouters()` | 已生成的动态路由 |
| `menus` / `getMenus()` | 菜单列表(侧边栏渲染源) |
| `isDynamicAddedRoute` / `getIsDynamicAddedRoute()` | 动态路由是否已添加 |
| `setRouters(routers)` / `setMenus(menus)` | 写入路由与菜单 |
| `setDynamicAddedRoute(flag)` | 设置动态路由添加状态 |
| `setKeepAliveComponents(components)` | 设置 keep-alive 组件列表 |
| `removeKeepAliveComponents(compNames)` | 移除指定缓存组件 |
---
## projectSettingStore
**文件**:`store/modules/projectSetting.ts`
**文件**:`ui/src/store/modules/projectSetting.ts`(id:`app-project-setting`)
| 字段 | 说明 |
|------|------|
@@ -83,7 +87,7 @@ await userStore.logout();
## ossConfigStore
**文件**:`store/modules/ossConfig.ts`
**文件**:`ui/src/store/modules/ossConfig.ts`
| 字段 | 说明 |
|------|------|
@@ -95,7 +99,7 @@ await userStore.logout();
## designSettingStore
**文件**:`store/modules/designSetting.ts`
**文件**:`ui/src/store/modules/designSetting.ts`(id:`app-design-setting`)
| 字段 | 说明 |
|------|------|
@@ -106,7 +110,7 @@ await userStore.logout();
## tabsViewStore
**文件**:`store/modules/tabsView.ts`
**文件**:`ui/src/store/modules/tabsView.ts`(id:`app-tabs-view`)
| 字段 | 说明 |
|------|------|
@@ -121,11 +125,22 @@ await userStore.logout();
---
## lockscreenStore
**文件**:`ui/src/store/modules/lockscreen.ts`(id:`app-lockscreen`)
| 字段 | 说明 |
|------|------|
| `isLock` | 是否锁屏 |
| `lockPassWord` | 锁屏密码 |
---
## 在组件外使用
```typescript
// 在 setup 外使用 Store
// 在 setup 外使用 Store(传入 Pinia 实例)
import { useUserStoreWidthOut } from '@/store/modules/user';
const userStore = useUserStoreWidthOut();
```
```