--- url: /docs/api/intro.md --- # 🕶️ 介绍 这是关于 `CatchAdmin` **v3** 版本的接口开发文档。这里会有关于 `CatchAdmin` 后台管理系统的所有的接口信息。除了开发模块的`代码生成`。针对每个接口会以这样格式进行输出。 * `标题` * `头信息` * `请求信息` * `响应信息` ## 默认头信息 |参数|必选|类型|说明 | ---- | ---- |----|----- |Authorization|是|String|认证 Token |Request-From|是|String|默认值: Dashboard, 标记请求属于后台 :::info 在不做特殊说明下,每个请求将会默认带有两个默认值头信息 ::: ## 公共响应格式 在 `CatchAdmin` 中,一般都是响应 `200 http code`,如果程序有异常,也不会返回 `500` 之类的 `http code`,它将会错误信息包裹到自定义响应数据中,下面是 `CatchAdmin` 的响应格式,请务必看下。 :::info 如果接口文档对响应内容没有做出特殊说明,只有`默认响应`,那么说明接口响应的数据是空数据。 ::: :::info 没有做出特殊说明的情况下, 接口文档中响应参数中的字段说明都是 `data` 中的字段说明 ::: ### 成功响应(分页格式) | 字段 | 类型 |说明 | ---- | ---- |---- | code | int |返回码 | data | Array|返回数据 | limit | int|每页显示数量 | message | string |返回信息 | total | int |总数 ### 成功响应(非分页) | 字段 | 类型 |说明 | ---- | ---- |---- | code | int |返回码 | data | Object|Array |返回数据 | message | string |返回信息 ### 错误响应 | 字段 | 类型 |说明 | ---- | ---- |---- | code | int |返回码 | message | string |返回信息 ### 公共错误码 | code | 类型 |说明 | ---- | ---- |---- | 10000 | int |成功返回 | 10001 | int |登录失效 | 10002 | int |验证错误 | 10003 | int |权限禁止 | 10004 | int |登录失败 | 10005 | int |操作失败 | 10006 | int |登录失效 | 10007 | int |黑名单 | 10008 | int |账户被禁 --- --- url: /docs/api/auth/login.md --- # 登录 ### 接口地址 * `api/login` ### 请求方式 * `POST` ### 请求参数 |参数|必选|类型|说明 | ---- | ---- |----|---- |email|是|string|登录账户邮箱📮 |password|是|string|登录账户的密码 |remember|否|bool|记住账户 ### 响应 |参数|类型|说明 | ---- | ---- |---- |token|string|登录成功后的认证 Token --- --- url: /docs/api/auth/logout.md --- # 登出 ### 接口地址 * `api/logout` ### 请求方式 * `POST` ### 请求参数 无 ### 响应 `默认响应` --- --- url: /docs/api/user.md --- # 列表 ### 接口地址 * `api/users` ### 请求方式 * `GET` ### Query 参数 |参数|必选|类型|说明| |----|----|----|----| |username|否|string|用户名| |email|否|string|邮箱| |status|否|number|状态| |department\_id|否|number|部门ID| |limit|是|number|每页数量| |page|是|number|页码| ### 响应 |参数|类型|说明| |----|----|----| |id|number|用户名| |username|string|用户名| |email|string|邮箱| |avatar|number|用户头像| |department\_id|number|部门ID| |creator\_id|number|创建人ID| |creator|string|创建人名称| |jobs|array|用户拥有岗位ID集合| |roles|array|用户拥有角色ID集合| |status|number|状态 1 正常 2 禁用| |created\_at|number|创建时间| --- --- url: /docs/api/user/store.md --- # 新增 ### 接口地址 * `api/users` ### 请求方式 * `post` ### Body参数 |参数|必选|类型|说明| |----|----|----|----| |username|是|string|用户名| |email|是|string|邮箱| |password|是|number|密码| |roles|是|array|角色ID集合| |department\_id|否|number|部门ID| |jobs|否|array|岗位ID集合| ### 响应 `默认响应` --- --- url: /docs/api/user/update.md --- # 更新 ### 接口地址 * `api/users/{id}` ### 请求方式 * `put` ### Body参数 |参数|必选|类型|说明| |----|----|----|----| |username|是|string|用户名| |email|是|string|邮箱| |password|否|number|密码,如果密码不填,则不更新密码| |roles|是|array|角色ID集合| |department\_id|否|number|部门ID| |jobs|否|array|岗位ID集合| ### 响应 `默认响应` --- --- url: /docs/api/user/delete.md --- # 删除 ### 接口地址 * `api/users/{id}` ### 请求方式 * `delete` ### 请求参数 无 ### 响应 `默认响应` --- --- url: /docs/api/user/online.md --- # 更新在线用户信息 ### 接口地址 * `api/user/online` ### 请求方式 * `post` ### Body参数 |参数|必选|类型|说明| |----|----|----|----| |username|是|string|用户名| |email|是|string|邮箱| |password|否|string|密码,如果密码不填,则不更新密码| |avatar|否|string|头像| ### 响应 `默认响应` --- --- url: /docs/api/user/operatelog.md --- # 操作日志 ### 接口地址 * `api/user/operate/log` ### 请求方式 * `GET` ### Query参数 |参数|必选|类型|说明| |----|----|----|----| |limit|是|number|每页数量| |page|是|number|页码| |scope|是|string|范围数据 `self:本人数据 all:全部数据`| ### 响应 |参数|类型|说明| |----|----|----| |id|number|ID| |action|string|操作 action,格式`controller@action`| |http\_code|number|http状态码| |http\_method|string|http请求方式| |ip|string|IP| |module|string|模块| |params|string|请求参数| |start\_at|string|请求开始时间| |time\_taken|number|请求耗时| |creator\_id|number|创建人ID| |creator|string|创建人昵称 | --- --- url: /docs/api/user/loginlog.md --- # 登录日志 ### 接口地址 * `api/user/login/log` ### 请求方式 * `GET` ### Query参数 |参数|必选|类型|说明| |----|----|----|----| |limit|是|number|每页数量| |page|是|number|页码| ### 响应 |参数|类型|说明| |----|----|----| |id|number|ID| |account|string|账户邮箱| |location|string|登录地址| |login\_at|string|登录时间| |login\_ip|string|登录IP| |platform|string|平台 windows/macos/linux| |status|number|登录状态 `1 成功 2 失败`| --- --- url: /docs/api/permission/role.md --- # 列表 ### 接口地址 * `api/permissions/roles` ### 请求方式 * `GET` ### Query 参数 |参数|必选|类型|说明| |----|----|----|----| |role\_name|否|string|角色名称| ### 响应 |参数|类型|说明| |----|----|----| |id|number|ID| |role\_name|string|角色名称| |identify|string|角色标识| |parent\_id|number|父级ID| |permissions|Array|角色权限| |creator|string|创建人| |description|string|描述| |data\_range|number|数据权限`1 全部数据 2 自定义数据 3 本人数据 4 部门数据 5 部门及以下数据`| |created\_at|string|创建时间| --- --- url: /docs/api/permission/role/store.md --- # 新增 ### 接口地址 * `api/permissions/roles` ### 请求方式 * `post` ### Body参数 |参数|必选|类型|说明| |----|----|----|----| |role\_name|是|string|角色名称 |parent\_id|否|number|角色父级 |identify|是|string|角色标识 |description|否|string|角色描述 |data\_range|否|string|角色数据权限`1 全部数据 2 自定义数据 3 本人数据 4 部门数据 5 部门及以下数据`| |departments|否|string|当数据权限等于`2`时,可以自定义部门 |permissions|否|array|角色名称 ### 响应 `默认响应` --- --- url: /docs/api/permission/role/update.md --- # 更新 ### 接口地址 * `api/permissions/roles/{id}` ### 请求方式 * `put` ### Body参数 |参数|必选|类型|说明| |----|----|----|----| |role\_name|是|string|角色名称 |parent\_id|否|number|角色父级 |identify|是|string|角色标识 |description|否|string|角色描述 |data\_range|否|string|角色数据权限`1 全部数据 2 自定义数据 3 本人数据 4 部门数据 5 部门及以下数据`| |departments|否|string|当数据权限等于`2`时,可以自定义部门 |permissions|否|array|角色名称 ### 响应 `默认响应` --- --- url: /docs/api/permission/role/delete.md --- # 删除 ### 接口地址 * `api/permissions/roles/{id}` ### 请求方式 * `delete` ### 请求参数 无 ### 响应 `默认响应` --- --- url: /docs/api/permission/permissions.md --- # 列表 ### 接口地址 * `api/permissions/permissions` ### 请求方式 * `GET` ### Query 参数 |参数|必选|类型|说明| |----|----|----|----| |username|否|string|用户名| |email|否|string|邮箱| |status|否|number|状态| |department\_id|否|number|部门ID| |limit|是|number|每页数量| |page|是|number|页码| ### 响应 |参数|类型|说明| |----|----|----| |id|number|用户名| |username|string|用户名| |email|string|邮箱| |avatar|number|用户头像| |department\_id|number|部门ID| |creator\_id|number|创建人ID| |creator|string|创建人名称| |jobs|array|用户拥有岗位ID集合| |roles|array|用户拥有角色ID集合| |status|number|状态 1 正常 2 禁用| |created\_at|number|创建时间| --- --- url: /docs/api/permission/permissions/store.md --- # 新增 ### 接口地址 * `api/permissions/permissions` ### 请求方式 * `post` ### Body参数 :::info 该接口既可以除了添加菜单之外,还可以批量添加 `action` ::: #### 添加菜单(模式1) |参数|必选|类型|说明| |----|----|----|----| |type|是|number|类型 `1 目录 2 菜单 3 按钮`| |parent\_id|是|string|父级ID| |permission\_name|是|number|菜单名称| |icon|是|array|菜单 Icon| |module|否|number|所属模块| |route|否|array|前端路由 path| |hidden|否|array|是否隐藏| |redirect|否|array|前端 redirect 属性| |Keepalive|否|array|前端 keepalive(目前没有作用,预留)| |active\_menu|否|array|激活菜单 `当从A菜单跳转到B内页时,需要激活 A 菜单时,这里填写A菜单路由`| |permission\_mark|否|array|菜单权限标识| |sort|否|array|排序| |is\_inner|否|array|是否是内页(预留)| #### 批量添加 action(模式二) :::info 模式二添加,可以菜单列表中看到,当你添加完一个`菜单类型`之后,权限标识列会出现一个`+`号标记,可通过它点击生成actions ::: |参数|必选|类型|说明| |----|----|----|----| |actions|是|bool|默认 true| |parent\_id|是|number|action 的父级ID| ### 响应 `默认响应` --- --- url: /docs/api/permission/permissions/update.md --- # 更新 ### 接口地址 * `api/permissions/permissions/{id}` ### 请求方式 * `put` ### Body参数 |参数|必选|类型|说明| |----|----|----|----| |type|是|number|类型 `1 目录 2 菜单 3 按钮`| |parent\_id|是|string|父级ID| |permission\_name|是|number|菜单名称| |permission\_mark|否|array|菜单权限标识| |icon|是|array|菜单 Icon| |module|否|number|所属模块| |route|否|array|前端路由 path| |hidden|否|array|是否隐藏| |redirect|否|array|前端 redirect 属性| |Keepalive|否|array|前端 keepalive(目前没有作用,预留)| |active\_menu|否|array|激活菜单 `当从A菜单跳转到B内页时,需要激活 A 菜单时,这里填写A菜单路由`| |sort|否|array|排序| |is\_inner|否|array|是否是内页(预留)| ### 响应 `默认响应` --- --- url: /docs/api/permission/permissions/delete.md --- # 删除 ### 接口地址 * `api/permissions/permissions/{id}` ### 请求方式 * `delete` ### 请求参数 无 ### 响应 `默认响应` --- --- url: /docs/api/permission/department.md --- # 列表 ### 接口地址 * `api/permissions/departments` ### 请求方式 * `GET` ### Query 参数 |参数|必选|类型|说明| |----|----|----|----| |department\_name|否|string|部门名称| ### 响应 |参数|类型|说明| |----|----|----| |id|number|ID| |department\_name|string|部门名称| |parent\_id|string|父级ID| |sort|number|排序| |status|number|状态`1 启用 2 禁用`| |creator|string|创建人| |created\_at|string|创建时间| |children|array|部门下级集合| --- --- url: /docs/api/permission/department/store.md --- # 新增 ### 接口地址 * `api/permissions/departments` ### 请求方式 * `post` ### Body参数 |参数|必选|类型|说明| |----|----|----|----| |parent\_id|是|string|父级ID| |department\_name|是|string|部门名称| |principal|string|number|部门联系人| |email|是|string|邮箱| |mobile|否|string|手机号| |sort|否|number|排序| ### 响应 `默认响应` --- --- url: /docs/api/permission/department/update.md --- # 更新 ### 接口地址 * `api/permissions/departments/{id}` ### 请求方式 * `put` ### Body参数 |参数|必选|类型|说明| |----|----|----|----| |parent\_id|是|string|父级ID| |department\_name|是|string|部门名称| |principal|string|number|部门联系人| |email|是|string|邮箱| |mobile|否|string|手机号| |sort|否|number|排序| ### 响应 `默认响应` --- --- url: /docs/api/permission/department/delete.md --- # 删除 ### 接口地址 * `api/permissions/departments/{id}` ### 请求方式 * `delete` ### 请求参数 无 ### 响应 `默认响应` --- --- url: /docs/api/permission/job.md --- # 列表 ### 接口地址 * `api/permissions/jobs` ### 请求方式 * `GET` ### Query 参数 |参数|必选|类型|说明| |----|----|----|----| |job\_name|否|string|岗位名称| |limit|是|number|每页数量| |page|是|number|页码| ### 响应 |参数|类型|说明| |----|----|----| |job\_name|string|岗位名称| |coding|string|岗位编码| |description|string|岗位描述| |sort|number|排序| |status|number|状态 `1 启用 2 禁用`| --- --- url: /docs/api/permission/job/store.md --- # 新增 ### 接口地址 * `api/permissions/jobs` ### 请求方式 * `post` ### Body参数 |参数|必选|类型|说明| |----|----|----|----| |job\_name|是|string|岗位名称| |coding|是|string|岗位编码| |description|否|string|岗位描述| |sort|否|number|排序| |status|否|number|状态 `1 启用 2 禁用`| ### 响应 `默认响应` --- --- url: /docs/api/permission/job/update.md --- # 更新 ### 接口地址 * `api/permissions/jobs/{id}` ### 请求方式 * `put` ### Body参数 |参数|必选|类型|说明| |----|----|----|----| |job\_name|是|string|岗位名称| |coding|是|string|岗位编码| |description|否|string|岗位描述| |sort|否|number|排序| |status|否|number|状态 `1 启用 2 禁用`| ### 响应 `默认响应` --- --- url: /docs/api/permission/job/delete.md --- # 删除 ### 接口地址 * `api/permissions/jobs/{id}` ### 请求方式 * `delete` ### 请求参数 无 ### 响应 `默认响应` --- --- url: /docs/intro.md --- # 介绍 ## 看云册子(付费) 这是和文档不相关的付费册子,里面包含了 tp6 源码解析,还有一些开发的解决方案。所以感兴趣的可以购买 [Thinkphp 6.0 企业级后台管理开发&源码分析](https://www.kancloud.cn/akasishikelu/thinkphp6) ## 功能 * ☑️ `用户管理` 后台用户管理 * ☑️ `部门管理` 配置公司的部门结构,支持树形结构 * ☑️ `岗位管理` 配置后台用户的职务 * ☑️ `菜单管理` 配置系统菜单,按钮等等 * ☑️ `角色管理` 配置用户担当的角色,分配权限 * ☑️ `数据字典` 管理后台表结构 * ☑️ `操作日志` 后台用户操作记录 * ☑️ `登录日志` 后台系统用户的登录记录 * ☑️ `代码生成` 生成 API 端的 CURD 操作 * ☑️ `敏感词` 支持敏感词配置 * ☑️ `附件管理` 可管理上传的文件 * ☑️ `微信管理` ## 项目地址 * [github 地址](https://github.com/yanwenwu/catch-admin) * [gitee 地址](https://gitee.com/jaguarjack/catchAdmin) * [前端 Vue 项目地址](https://github.com/yanwenwu/catch-admin-vue) ## 预览 ## 环境要求 * php7.1+ (需以下扩展) * ☑️ mbstring * ☑️ json * ☑️ openssl * ☑️ xml * ☑️ pdo * nginx * mysql #### 下载项目 * 通过 Git 下载(推荐) ```shell git clone https://gitee.com/jaguarjack/catchAdmin && cd catchAdmin curl -sS https://install.phpcomposer.com/installer | php composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/ composer install ``` * composer 安装 ```shell composer create-project jaguarjack/catchadmin:dev-master ``` #### 安装 下载完成之后通过命令来进行安装, 一键安装 🚀 ```shell php think catch:install ``` ## 体验地址 [体验地址](https://demo.catchadmin.com) * 账号: `catch@admin.com` * 密码: `catchadmin` ## 支持创作 如果项目对你有帮助,可以订阅支持我 ❤️。你的每一份支持是对我最大的鼓励。开源不易,感谢支持。可以通过使用 [**🎉 爱发电**](https://afdian.net/@jaguarjack)订阅支持创作。 ## 系列文章 如果是刚开始使用 `thinkphp6`, 以下文章可能会对你有些许帮助,文章基于 RC3 版本。整体架构是不变的。 * [Tp6 启动分析](https://www.kancloud.cn/akasishikelu/thinkphp6/1129385) * [Tp6 Request 解析](https://www.kancloud.cn/akasishikelu/thinkphp6/1134496) * [TP6 应用初始化](https://www.kancloud.cn/akasishikelu/thinkphp6/1130427) * [Tp6 中间件分析](https://www.kancloud.cn/akasishikelu/thinkphp6/1136616) * [Tp6 请求流程](https://www.kancloud.cn/akasishikelu/thinkphp6/1136608) ## 讨论 * [论坛讨论](https://bbs.catchadmin.com) * 可以提 `ISSUE`,请按照 `issue` 模板提问 * 加入 Q 群 `302266230` 暗号 `catchadmin`。 ## 感谢 🙏 > 排名不分先后 * [top-think/think](https://github.com/top-think/think) * [element-admin](https://panjiachen.gitee.io/vue-element-admin-site/zh/) * [jaguarjack/think-filesystem-cloud](https://github.com/yanwenwu/think-filesystem-cloud) * [overtrue/wechat](https://github.com/overtrue/wechat) * [jaguarjack/migration-generator](https://github.com/yanwenwu/migration-generator) * [phpoffice/phpspreadsheet](https://github.com/PHPOffice/PhpSpreadsheet) --- --- url: /docs/catchadmin/install.md --- # 项目安装 ## 环境要求 `CatchAdmin` 要求以下环境: * PHP >= 7.1.0 * Mysql >= 5.5.0 * PDO Extension * MBstring Extension * CURL Extension * ZIP Extension * Composer :::tip 一共需要安装两个项目,一是 `PHP` 的项目,二是 `VUE` 项目,请跟着下面的步骤走。 ::: ## 安装 PHP 项目 目前项目托管在`gitee`上,可以前往 [CatchAdmin](https://gitee.com/jaguarjack/catchAdmin) 下载。 或者可以使用`git`(推荐使用) clone 代码,方便及时更新代码。 ```sh git clone https://gitee.com/jaguarjack/catchAdmin.git ``` 或者 ``` composer create-project jaguarjack/catchadmin:dev-master catchAdmin ``` 进入到`CatchAdmin`目录,该项目不提供`Web install`方式,请使用命令行方式安装。使用以下几个命令即可安装成功。 保证已经保证了`composer`包管理器。`MAC`以及`LINUX`可使用下面的命令, `windows`直接下载`exe`安装 ```sh curl -sS http://install.phpcomposer.com/installer | php // 由于某种原因,下载包会非常慢,所以需要修改镜像来加速,推荐阿里镜像。 composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/ // 安装 composer 扩展 composer install --ignore-platform-reqs // 安装后台, 按照提示输入对应信息即可 php think catch:install // 启动后台 php think run ``` ::: warning 注意不能直接访问 PHP 项目,导致 Exception,前后端分离,需要通过 API 接口形式访问,所以你需要安装 VUE 项目后台,看到数据的展示 ::: :::tip 如果你是第一次使用 VUE,建议先去看看 VUE 文档,了解一下。 ::: ## 下载 vue 项目 在使用前端项目之前,你需要安装前端管理器,这个不多做解释了。推荐使用`yarn` 安装,首先你需要安装 `yarn` 管理器。使用淘宝镜像。 ```sh yarn config set registry https://registry.npm.taobao.org/ ``` #### 下载项目 ```sh git clone https://github.com/yanwenwu/catch-admin-vue.git ``` #### 进入目录,使用 yarn 安装 ```sh yarn install ``` #### 配置接口地址,找到 vue 项目下的 * `.env.development` 文件是配置开发环境的 API 接口地址 (实际上就是 PHP 项目的地址) #### 启动开发模式 请先在前端项目根目录下的`.env.development` 文件设置 `VUE_APP_BASE_API`开发环境的 API 请求地址 ```sh # just a flag ENV = 'development' # base api VUE_APP_BASE_API = 'http://127.0.0.1:9090' ``` 然后启动项目 ```sh npm run dev ``` :::tip vue 后台使用了是 `element admin` [文档地址](https://panjiachen.gitee.io/vue-element-admin-site/zh/) ::: ## 重新初始化项目 有时候因为更新而导致数据不一致,最近改动的比较频繁,你需要重新安装项目的话,可以使用下面的命令 ``` php think catch:install -r ``` ## 打包前端项目 打包前请先配置正是环境 API 地址。在项目的根目录下的`.env.production`文件配置 ``` # just a flag ENV = 'production' # base api VUE_APP_BASE_API = '正式环境的 API 地址' ``` 然后进行打包 ``` npm run build:prod ``` :::tip 前端项目配置最好开启 `Gzip`,可以加速前端项目访问速度。 ::: #### 推荐配置 ```sh http { include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; #tcp_nopush on; keepalive_timeout 65; #gzip 配置 gzip on; gzip_min_length 1k; gzip_comp_level 4; gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript ; gzip_static on; gzip_vary on; gzip_buffers 8 16k; include /etc/nginx/conf.d/*.conf; } ``` --- --- url: /docs/catchadmin/project-intro.md --- # 项目目录 使用 `tp6` 开发,可以脱离 `app` 目录,本项目就是很好的例子,如果你的思维局限在 `app` 目录下,这将会给你一个很好范例,重新认识 `Tp`。而且在开发该项目时,弱化了多应用,取而代之是路由。 ## 目录结构 ```sh |-- app |-- ExceptionHandle.php // 异常捕获 |-- service.php // 核心服务注入 |-- catch // 核心目录 |-- config |-- catch.php // 配置文件 |-- extend |-- catcher // 扩展库目录 |-- public |-- catch-admin // 资源目录 |-- runtime |-- route |-- vendor |-- view ``` ## 核心目录 该目录是真正的开发目录,当然如果你不喜欢在此开发,也可以在 `app` 下开发,并没有什么影响。下面来说明目录结构。以`permissions`目录为例 (关于在 `app` 目录下进行多应用的开发, 请查看[tp 多应用开发](https://www.kancloud.cn/manual/thinkphp6_0/1297876)) ```sh |-- catch |-- permissions |-- controller |-- model |-- database |-- migrations |-- seeds |-- request |-- module.json |-- route.php ``` * `controller` 目录存放控制器文件 * `model` 目录存放模型文件 * `database/migrations` 目录存放数据库迁移的,就是表结构 * `database/seeds` 目录存在数据库默认数据 * `request` 目录存在表单请求,验证规则可以写在这里 * `route.php` 路由文件,路由规则需要写在里面 * `module.json` 保存模块信息 ## 公共库 公共库 `extend\cacher` 目录, 里面主要存放封装的类库。来看一下目录。 ``` |-- extend |-- catcher |-- base |-- command |-- event |-- exceptions |-- traits |-- validates |-- CatchAdmin.php |-- CatchForm.php |-- CatchResponse.php |-- Tree.php |-- Code.php |-- Utils.php |-- CatchQuery.php |-- CatchAuth.php ``` 接着来说明一下各个目录的作用。 * `base` 目录存在一些基类 * `command` 目录存在 console 命令 * `event` 目录存在事件 * `exceptions` 目录存放自定义异常类 * `exceptions` 目录存放自定义 facade 门面 * `generate` 目录存放文件生成功能 * `library` 目录存放插件 * client Http 客户端 * crontab 定时任务功能 * excel Excel 功能 * rate 接口速率限制 * BackupDatabase 备份数据库 * composer 解析 composer.json 文件 * Compress 打包工具 * Error 定义错误 * FileSystem 文件处理类 * InstallCatchMoudle 模块安装 * PraseClass 解析类 * ProgressBar Cli 模式下的进度条 * ScheduleKernel 定时任务调度器 * `traits` 目录复用类库 * `validates` 目录存在自定义的验证器 * `middlewares` 目录存在自定义的中间件 * `CatchAdmin.php` 获取 catchAdmin 的目录信息 * `CatchForm.php` 快速生成表单 (前后端项目无用) * `CatchResponse.php` 响应 * `Tree.php` 树结构生成 * `Code.php` 集合项目的 code * `Utils.php` 工具集合 * `CatchQuery.php` 替代内置的 Query,可实现自己的一些查询操作 * `CatchAuth.php` 认证 --- --- url: /docs/catchadmin/console.md --- # 命令介绍 命令行请务必看一下,对于你开发会有很大的帮助,提升你的开发效率。`CatchAdmin` 提供了很多有用的命令,在你的开发使用熟练的话,将会大大增加你的开发效率。 ## 安装框架 ``` php think catch:install ``` #### 参数列表 * 可选参数 `-r`,重置数据库 :::warning 使用该选项参数, 通过 migration 的生成的表将会被回滚删除,然后重新添加初始化数据. ::: ## 备份数据 ``` php think backup:data ``` #### 参数列表 * 必选参数 `tables`, 多个表需要使用 , 分隔开 * 可选参数 `-z`, 是否压缩成 zip 格式 #### 事例 ``` php think backup:data users,roles -z ``` ## 创建模块 如果你想使用模块式开发,请使用下面命令生成模块 ``` php think create:module moduleName ``` #### 参数 * moduleName 模块名称 该命令会在 catch 目录下生成模块文件夹,默认有三个文件加上若干文件夹 * moduleService.php // 服务启动文件 * route.php // 路由文件 * module.json // 模块信息描述文件 这样基本的模块就创建完毕了。 ## 创建表 在创建完`migrations`,需要设计表结构。可以在官方文档上看到如何使用[数据迁移](https://www.kancloud.cn/manual/thinkphp6_0/1118028),当你设计完结构之后,如果还有默认数据的话,需要使用 seeds 进行填充。在做完这些工作之后,使用以下命令 ``` php think catch-migrate:run module ``` :::tip 该命令可以生成对应的表结构 ::: ``` php think catch-seed:run module ``` :::tip 该命令可以填充对应的表数据 ::: ## 创建 Migration ``` php think catch-migrate:create ``` #### 参数 * 必选参数 module, 模块名称 * 必选参数 MigrationName,驼峰法命名 #### 实例 ``` php think catch-migrate:create permissions RoleHasPermissions ``` ## 创建模型 当你创建表成功后,还需要生成对应的模型,如果你是自己创建模型的话,还要填充表字段将会很浪费时间,所以才会有该命令的产生。 ``` php think create:model moduleName modelName ``` ##### 参数 * moduelName 模块名称 * modelName 模型名称 * 可选参数 --softDelete 值:SOFTDELETE 软删除参数之后,使用的模型会有区别,请注意 `模型名称`和`模块名`称都是必须的,模型名称还必须是驼峰规则,不然会找不到表,例如你的表名是`user_role`,那么你的模型名称就应该是 `UserRole` 这样的驼峰命名,这是约定。 ## 模块禁用 如果不想使用某个模块了,可以使用下面的命令。 ``` php think disable:module moduleName ``` :::warning 该命令使用之后会将相关菜单全部删除。 ::: ## 模块启用 如果想继续使用某个模块了,可以使用下面的命令。 ``` php think enable:module moduleName ``` :::tip 该命令使用之后会将相关删除菜单全部恢复。 ::: ## 打包模块 :::tip 这是预留命令,目前来看没有任何作用 ::: ``` php think package:zip module ``` 该命令会将文件夹压缩成 ZIP 包。 ## 模块服务发现 在 catchAdmin 中使用多模块的时候,必须使用服务发现,保证模块的可用 ``` php think catch-service:discover ``` ## 导出菜单 目前 CatchAdmin 由于模块独立,所以安装模块的时候对于权限菜单也是独立的,所以当你开发完独立的模块之后,应该是需要单独导出菜单的。所以提供了很简单的命令,支持树状导出。 ```sh php think export permissions -p parent_id -m system ``` * permissions 就是权限表,根据实际填写 * `-p` 树状的父级标识,CatchAdmin permissions 表使用 `parent` * `-m` 导出的模块名称 ## 执行 migrate 项目有时候需要更新,新增字段,借助 migration,可以很好的管理表字段的版本。 ```sh php think catch-migrate:run moduleName ``` 可以很好更新模块下的 migration ## 填充数据 如果模块有初始化数据需要填充,那么就需要下面的命令 ```sh php think catch-seed:run moduleName ``` 这个命令是更新模块下所有 seed,因为 seed 是没有版本控制的,所以你不能每次都去执行模块下所有的 seeder,你可以指定执行某个 seeder. ```sh php think catch-seed:run moduleName -s SeederClass ``` ## 缓存敏感词 ```sh php think cache:sensitiveWord ``` --- --- url: /docs/catchadmin/request.md --- # 请求介绍 `CatchAdmin`后台管理封装了自己的 `CatchRequest`,该 `Request `提供了请求前的验证校验。可大大提供你的开发效率。无需在 Controller 声明验证规则在校验捕获异常,该 Request 全部封装好了。在进入 Controller 之前进行校验,将验证和 Controller 分离。保证了代码简洁和可读性。 :::tip 如果你需要使用 Creator\_id 字段,那么会在请求里面自动添加进去。随时获得 creator\_id 无需你手动添加。 ::: 下面提供了简单案列使用 ## 验证 :::tip 由于官方提供的案例,用起来其实还是挺不方便的,所以`CatchAdmin`对请求做了一丢丢的改变,当然在使用上和文档没有任何区别。但是更加简单简洁,只需要定义规则后,在需要的验证的方法中注入即可 ::: 如果你不喜欢这种方法,可以直接使用 `Validate` 验证方式。 ## 使用 使用方法其实和 Validate 区别不大,以创建用户为例,在 user 模块的 request 目录创建 CreateUserRequest.php. 内容如下: ```php class CreateRequest extends CatchRequest { protected function rules(): array { // TODO: Implement rules() method. return [ 'username|用户名' => 'require|max:20', 'password|密码' => 'require|min:5|max:12', 'passwordConfirm|密码' => 'confirm:password', 'email|邮箱' => 'require|email|unique:'.Users::class, ]; } protected function message(): array { // TODO: Implement message() method. } } ``` 就是这么简单,另外基类还提供了两个属性。 * $needCreatorId 属性是否添加 creator\_id,默认 true * $batch 是否批量验证 (不建议) 默认 false 在 User 控制中直接注入到方法,就可以完美验证表单了。 ``` public function save(CreateRequest $request) ``` ## 自定义验证 以项目中的 `sometimes` 验证为例,只需要实现 `ValidateInterface` 接口即可。 ```php namespace catcher\validates; class Sometimes implements ValidateInterface { public function type(): string { // TODO: Implement type() method. return 'sometimes'; } public function verify($value): bool { // TODO: Implement verify() method. if ($value) { return true; } return false; } public function message(): string { // TODO: Implement message() method. return ''; } } ``` #### 注入新验证 在实现完新规则之后,只需要在 config\catch.php 里面配置就可以了。 ```php 'validates' => [ \catcher\validates\Sometimes::class, ], ``` ### 获取登陆用户信息 `request` 还提供了获取登陆用户信息的功能,如果你想获取登陆用户的信息,那么你可以这么使用. ``` $request->user() ``` --- --- url: /docs/catchadmin/model.md --- # 模型介绍 在日常开发中,和我们打交道最多的就是数据库了。所以经常会使用到模型。`CatchAdmin`也提供非常便利的 `CURD` 操作。如果你想使用这些操作,必须使用`CatchModel`类。继承它,会让你的 `CURD`更加迅速稳定。 看看他是如何定义的?在此之前的呢,先看一下模型如何定义的。 ```php class Attachments extends CatchModel { protected $name = 'attachments'; protected $field = [ 'id', // 'path', // 附件存储路径 'url', // 资源地址 'mime_type', // 资源mimeType 'file_ext', // 资源后缀 'file_size', // 资源大小 'filename', // 资源名称 'driver', // local,oss,qcloud,qiniu 'created_at', // 创建时间 'updated_at', // 更新时间 'deleted_at', // 删除时间 ]; } ``` 像这样的形式的模型,都是通过命令生成的。无需你手动填写。所以 `CatchAdmin` 中所有的模型拥有`Field` 属性,它就是表字段的映射,这在之后的 `CURD` 中很有必要。 ## CatchModel ```php abstract class CatchModel extends \think\Model { // 除了 softDelete 其他三个 trait 都是 catchadmin 中使用的。你可以用到任何你想用的地方 use SoftDelete, TransTrait, BaseOptionsTrait, ScopeTrait; // 自定义创建时间字段 protected $createTime = 'created_at'; // 自定义更新时间字段 protected $updateTime = 'updated_at'; // 自定义删除字段 protected $deleteTime = 'deleted_at'; // 默认删除的值 protected $defaultSoftDelete = 0; // 自动写入时间戳 protected $autoWriteTimestamp = true; public const LIMIT = 10; // 开启 public const ENABLE = 1; // 禁用 public const DISABLE = 2; } ``` 一目了然。他使用软删除。所以如果你不想使用软删除,可以直接继承 `\think\Model`。他还使用了三个`trait`,这三个`trait`就是 `CURD` 操作的保证。 #### BaseOptionsTrait 看一下它所提供的有哪些方法,在下面会一一说明。 ```php // 列表查询方法 public function getList(){} // 新增单条数据 public function storeBy(array $data){} // 循环插入数据时使用 public function createBy(array $data){} // 更新数据 public function updateBy($id, $data, $field = ''): bool{} // 查找数据 // 第一个是 id // 第二个是查询的字段 // 第三个 true 可查询软删除的数据 public function findBy($id, array $field = ['*'], $trash = false){} // 删除数据 // force true 可物理删除数据 public function deleteBy($id, $force = false){} // 批量插入数据 public function insertAllBy(array $data){} // 软删除恢复 public function recover($id){} // 获取删除字段 public function getDeleteAtField(){} // 别名字段 自动添加当前模型的表名 public function aliasField($field): string{} // 禁用/启用 如果表里面有 status 字段默认使用,当然也可以自定义字段 public function disOrEnable($id, $field='status'){} ``` #### TransTrait 这是关于事务操作的方法,轻松使用模型操作,丢弃 `Db::startTrans`, 这种不是很便利的操作。使用方法和文档是一样的,无需担心。 ```php // 开启事务 public function startTrans(){} // 提交事务 public function commit(){} // 回滚事务 public function rollback(){} // 事务组的操作 public function transaction(\Closure $function){} ``` 在继承`CatchModel`之后你可以直接在模型里面使用,eg.而且有非常友好的提示。 ```php $this->startTrans(); ``` #### ScopeTrait 范围查询只提供了创建者查询。非常方便。 ```php public function scopeCreator($query); ``` 使用有很好的案例,例如 ```php $this->catchSearch() ->field('*') ->catchOrder() ->creator() ->paginate(); ``` :::warning 当你使用范围查询的 creator 方法时候,必须放在 field 方法之后,而且不能单独使用,必须强制使用 field 方法进行查询。 ::: #### 搜索 `catchadmin` 默认使用框架的搜索器,所以你只需要使用搜索器就好了,搜索的参数被`CatchAdmin`过滤了。具体搜索器的用法可以看[框架文档](https://www.kancloud.cn/manual/thinkphp6_0/1037590) ## CatchQeury `CatchQuery`在框架起到了很重要的作用,它继承了框架 `Query`, 并且新写了很多方法,这些方法在开发中起到很大的作用。所以将这些方法运用到你的开发之中,会事半功倍。 #### 重写的方法 ```php // model Join 的模型 // oinField join 模型的字段 // currentJoinField 当前模型的关联的字段 // field 需要 join 的模型查询的字段 public function catchJoin(string $model, string $joinField, string $currentJoinField, array $field = [], string $type = 'INNER', array $bind = []): CatchQuery // 这个方法很常用 // 例如你表里有 10 个字段,但是偏偏有一字段你不需要,那么这个方法可以帮你过滤掉该字段 // !注意 是主表的字段 public function withoutField($field, $needAlias = false) // 调用它 配合搜索器完美实现搜索 public function catchSearch($params = []): CatchQuery // 获取 alias 字段 public function getAlias() // like 查询 默认 both %% // option => left %xxx // option => right xxx% public function whereLike(string $field, $condition, string $logic = 'AND', $option ='both'): Query // 增加额外字段 在有必要的时候可以添加 public function addFields($fields): CatchQuery // 分页 public function paginate($listRows = null, $simple = false): Paginator // 排序 // 如果你使用了它,并且存在 sort 字段 那么最后的结果就是这样的 // order('sort')->order('id') 很方便有么有 public function catchOrder($order = 'desc') // 添加子查询 public function addSelectSub(callable $callable, string $as) // 字段自增 public function increment($field, $amount = 1) // 字段自减 public function decrement($field, $amount = 1) ``` --- --- url: /docs/catchadmin/data-scope.md --- # 权限介绍 * GET 请求是默认不经过权限控制,如果需要验证权限 * 需要在方法注释中加入 `@CatchAuth` 标识 * 超级管理员不经过权限控制,后台默认安装的用户 ### 数据权限 关于数据权限的概念,很简单,就是要标记数据的所有者。所以 > 如果你需要数据权限的时候,那么表结构需要默认的 `creator_id`字段,用来标记数据的所有者。 一旦使用了数据权限,那么可以使用`CatchRequest`,使用它可以无缝获取`creator_id`,这是无感知的。 当你使用: ```php $request->param() or $request->post() ``` 就可以轻松获取到。 ## 使用 `CatchAdmin` 封装了可用 `trait` 来帮助开发者处理数据权限数据,引入 `trait` ```php use catchAdmin\permissions\model\DataRangScopeTrait ``` 在`模型`中使用 `dataRange` 方法,该方法接受一个 `roles` 对象数组,如果不传,则获取当前登录用户的角色组。 以用户列表为例 ```php $this->dataRange() ->withoutField(['updated_at'], true) ->catchSearch() ->catchLeftJoin(Department::class, 'id', 'department_id', ['department_name']) ->order($this->aliasField('id'), 'desc') ->paginate(); ``` :::tip dataRange 因为它不是`Query` 方法,所以它必须放在最前面。而又因为它返回`Query` 对象,所以它可以正常使用 Query 的方法。 ::: 数据权限并没有提供全局的方法,所以可以在你需要权限管理的地方引入它。 --- --- url: /docs/catchadmin/extend.md --- # 项目扩展 在开发项目的时候你会发现很多的不同,一些基础的方法之类的,但还是无法使用。这里着重介绍一些后台的隐藏功能。 ## 配置 后台项目配置保存在 `config\catch.php` 文件中。都有哪些配置呢?下面一一介绍。 * domain 设置之后只能使用该域名访问后台 * permission * is\_allow\_get 允许所有 get 请求,不做权限校验 * `super_admin_id` 默认 `1`,对于用户`ID=1`的用户不做权限校验 * auth 认证 * default 使用哪个门面。默认 admin * guard 门面 * dirver 驱动,默认 admin 使用 jwt * provider 认证服务 * providers 服务提供 * driver orm 默认使用, 建议都使用他 * model 用户模型来进行认证 * validate 自定义规则 * upload 上传服务校验 * route\_middleware 权限认证中间件 * event 后台事件 ## 基类 存储目录 `extend\catcher\base` 目录下, 一共提供四个基础类使用 * CatchController 非必选 可以不用 * CatchModel 非必选 如果你不使用软删除的话可以不用该类 * CatchRequest 必选 对于 Request 尽量使用它 * CatchValidate 非必选 可不用 ## command 存储目录 `extend\catcher\command` 目录下, 一共提供四个基础类使用 文档中提到过的命令都存储在这里,有兴趣的可以看看。 ## event 目前只提供了路由加载事件 ## exceptions * CatchException 异常基类 后台所有异常都是继承 * FailedException 失败异常 * LoginFailedException 登陆失败 * PermissionsForbiddenException 权限禁止 * ValidateFailedException 验证失败 ## generate 代码生成器,这个没啥好说的了 ## library 目前提供了两个工具 * compress 打包解包 * Http 客户端 ## traits 只提供了 db 两个 trait 功能 * db * baseoptiontrait CURD 基础操作 * transtrait 事务操作 ## validates 自定义验证规则的文件可以放在这里。 ## 其他 * catchAdmin 基础后台的文件创建,路由文件缓存等功能 * CatchAdminService 核心,后台功能入口点 * CatchAuth 用户认证 * CatchCatchKeys 缓存 KEY 管理 * CatchExceptionHandle 后台异常接管,不在使用 app\ExceptionHandle * CatchUpoload 上传支持 七牛,oss,腾讯云,和本地 * Code 异常码管理类 * Tree 树状结构生成类 * Utils 小工具类 * CatchQuery 这个类要着重说一下,因为打交道最多的就是 Model 了 --- --- url: /docs/catchadmin/http.md --- # Http 客户端 :::tip CatchAdmin 提供了一个简洁的 Http 客户端以帮助用户进行 Curl 请求操作。 ::: 先来看一个简单的例子, 请求 `CatchAdmin` 的用户列表 ```php $response = Http::token('token')->get('http://127.0.0.1:9090/users'); return $response->json(); ``` 通过简单的接口便可以返回请求数据. ## 头部信息 你可以使用 `headers` 方法来设置头部信息,接受一个 array 参数 ```php Http::headers([ 'token' => 'token' ]) ``` ## Body 如果你希望设置 Body 信息。请使用 `body` 方法,它接受一个 string ```php Http::body(‘body’) ``` ## 超时时间 你可以通过 `timeout` 方法,设置一个 `number` 类型的参数 ``` Http::timeout(‘body’) ``` ## token 令牌 如果你想要为你的请求添加 `Authorization Token` 令牌请求头,你可以使用`token`方法 ```php Http::token('token'); ``` ## json `json` 方法选项用来轻松将`JSON`数据当成主体上传, 如果没有设置`Content-Type`头信息的时候会设置成 `application/json` 。他接受一个 array 参数 ```php Http::json([ ]) ``` ## 异步请求 使用 `async` ``` $promise = Http::asynac()->get() ``` 这样就是生成一个异步请求,返回 Promise 对象,所以你不可以直接使用 Response 的响应, 继续使用代码如下 ```php $promise->then( function (ResponseInterface $res) { echo $res->getStatusCode() . "\n"; }, function (RequestException $e) { echo $e->getMessage() . "\n"; echo $e->getRequest()->getMethod(); } ); ``` ## Form 请求 使用 `form` 方法进行请求, 以请求 CatchAdmin 登陆为例,代码实现 ```php $response = Http::form([ 'email' => 'admin@gmail.com', 'password' => 'admin' ])->post('http://127.0.0.1:9090/login'); dd($response['data']['token']); ``` 你可以直接把响应当作数组来使用,因为它实现了 ArrayAccess 接口,具体可以查看源代码实现。 ## Query 请求 如果你在使用 Get 时,可以使用该方法提供 Query 参数 ```php $response = Http::token('token') ->query([ 'limit' => 20 ]) ->get('http://127.0.0.1:9090/users'); return $response->json(); ``` ## 上传附件 如果你需要单独上传文件附件,可以使用 attach 方法,它接受三个参数,name,文件资源路径,文件名称,看一下代码 ```php $response = Http::token('token') ->attach('image', fopen(root_path() . DIRECTORY_SEPARATOR . 'logo.png', 'r+'), 'logo.png') ->post('http://127.0.0.1:9090/upload/image'); return $response; ``` ## Response 响应 响应提供以下几个方法,可以使用 * `ok` * `successful` * `failed` * `headers` 响应头信息 * `then` 异步响应需要使用 * `status` 响应状态码 * `body` 响应 Body * `json` Api 数据格式化 --- --- url: /docs/catchadmin/export-excel.md --- # 导出 Excel ## 导出 :::tip `CatchAdmin` 提供一套简单易使用的导出工具,可以轻松完成导出功能,只需要简单的实现。便能完成。下面来看一下如何使用吧。 ::: 来看一个简单的例子,导出 `Users` 表的数据 ```php namespace catcher\library\excel; use think\facade\Db; class Users implements ExcelContract { public function headers(): array { // TODO: Implement headers() method. return [ '用户名', '邮箱' ]; } public function sheets() { // TODO: Implement sheets() method. return Db::name('user')->field(['username', 'email'])->limit(100)->cursor(); } } ``` 首先你要实现的 `catcher\library\excel\ExcelContract` 接口,只需要实现两个方法 * headers * `headers` 方法用于设置 excel 头部栏目显示的数据名称 * sheets * `sheets` 方法用于查询处理数据 除了接口必须实现的方法外,还提供了其他可用的方法 ## 设置对应的数据值 示例的数据只有两个字段 `username` 和 `email`, 一一对应`用户名`和`邮箱`。如果查询是这样的话. ```php Db::name('user')->field(['email', 'username'])->limit(100)->cursor(); ``` 那么数据就会是相反的,不会一一对应其设置的 `headers`,所以此时提供了新的方法。 ```php public function keys(): array { // TODO: Implement keys() method. return [ 'username', 'email' ]; } ``` ## 设置标题 有时候需要在 `excel` 顶部设置标题,可以使用 `setTitle` 方法 ```php public function setTitle() { return [ 'A1:G1', '测试', Alignment::HORIZONTAL_CENTER ]; } ``` 返回的一个数组 * 第一个元素 占用的列 * 第二个元素 标题 * 第三个元素 位置(使用`PhpOffice\PhpSpreadsheet\Style\Alignment`提供的位置常量设置) ## 设置开始列 如果开始列不是从 `A` 列开始的话,可以通过该方法进行设置 ```php public function start() { return 'B'; } ``` ## 设置行 如果你设置了 `title`,那么一定需要设置开始行了。因为默认是从 `A1`,所以有必要进行开始行的设置。 ```php public function setRow() { return 2; } ``` ## 设置对应列的宽度 如果你需要设置列的宽度,那么可以用`setWidth`方法进行设置 ```php public function setWidth() { return [ 'A' => 50, ]; } ``` ## 获取活动的列 如果你需要一些自定义列的需求,那么可以通过该方法`getWorksheet`获取当前激活的 `sheet` 来处理 ```php public function getWorksheet($sheet) { return $sheet; } ``` ## before 处理 获取当前活动列之后,通过该方法你就可以自定义处理数据前的准备工作 ```php public function before() { // todo } ``` ## 内存溢出 如果是因为数据量太大,导致内存溢出。提供了 `memory` 属性设置运行时所需内存。 ```php public $memory = '1024M'; ``` ## 新增模型导出 注意模型导出提供的功能很有限,适用于简单导出,如果你需要更加完善的导出,还是按照上面的文档来,提供一个导出用户例子 ```php Users::field(['id', 'username', 'email', 'status', 'created_at'])->select() ->each(function (&$item, $key){ $item->status = $item->status == Users::ENABLE ? '启用' : '停用'; })->export(['id', '用户名', '邮箱', '状态', '创建日期']) ``` --- --- url: /docs/catchadmin/sensitive-word.md --- # 敏感词 最近国内对敏感词管理还是很严格,很多后台管理中都未提供该功能,所以 `CatchAdmin` 后台就增加了这个功能模块, 采用了常见 `DFA` 算法提高查找性能。 ### 如何使用 在后台管理中,系统模块下的敏感词模块添加所需要屏蔽的敏感词。但并不是说非得使用库的形式,下面会提到为什么不需要这么做。 `CatchAdmin` 提供了 `catcher\library\Trie` 扩展来增加你的敏感词库。来看一下代码。 ``` $words = SensitiveWord::cursor(); $trie = new Trie(); foreach ($words as $word) { $trie->add($word->word); } // 获取 trie tree $trie->getTries(); // 缓存 $trie->cached(); ``` 从词库里面获取到敏感词之后,添加到 `Trie Tree` 里面。`CatchAdmin` 已经封装好了好了整个过程。所以可以轻松使用。 ::: warning `trie` 缓存使用的是 `Redis`,无法切换,所以请使用 `cached` 方法时请链接 `Redis`,否则请自己选择使用 Cache 进行缓存 ::: ### 获取内容敏感词 `getSensitiveWords` 方法可以获取到内容里面存在的敏感词汇 ``` $tire->getSensitiveWords($trieTree, $content); ``` ### 替换 `replace` 方法可以替换到内容里面存在的敏感词。 ``` $tire->replace($words, $content); ``` ### 验证 `CatchAdmin` 还提供了验证器`sensitive_word`,可以验证提交内容中是否存在敏感词. ``` [ 'word' => 'sensitive_word', ] ``` ### 命令 针对敏感词库,`Catchadmin` 提供了缓存命令,也是使用 Redis 缓存 ``` php think cache:sensitiveWord ``` --- --- url: /docs/catchadmin/crontab.md --- # 定时任务 旧版在使用上有一些困难,很多人不熟悉多进程管理这块,在这块业务上耦合也比较严重,所以有问题,难于调试。新版本在使用上变得更加简单,只需要定义 `Command`即可。也不需要之前定义 `Task` 之类的单独类了。 第一步就是在后台添加定时执行的 `command` 指令,如下: ```php declare (strict_types=1); namespace catchAdmin\monitor\command; class TestCommand extends Command { protected $pid; protected function configure() { // 指令配置 $this->setName('testTow') ->setDescription('test command'); } protected function execute(Input $input, Output $output) {} } ``` [![whcbXd.jpg](https://s1.ax1x.com/2020/09/18/whcbXd.jpg)](https://imgchr.com/i/whcbXd) 首先按照上图开启你的系统监控模块 在后台添加 `command` 指令即可,目前 `command` 支持在 `catch` 目录下的模块中 `command` 文件夹下自动载入 [![whg0ud.jpg](https://s1.ax1x.com/2020/09/18/whg0ud.jpg)](https://imgchr.com/i/whg0ud) ## 调度 设置每分钟调度一次,注意这里**必须是每分钟** ```shell * * * * * cd /path-to-your-project && php think catch:schedule >> /dev/null 2>&1 ``` ## 自动载入 commands 在 CatchAdmin 中,command 都是支持自动载入的,只需要这这样实现就可以了. 继承 catcher\ModuleService, 实现 loadCommands 返回 NAMESPACE 和 存放 commands 的文件目录即可. ```php namespace app\admin; use catcher\ModuleService; class AppService extends ModuleService { public function loadRouteFrom() { // TODO: Implement loadRouteFrom() method. } public function loadCommands() { return [__NAMESPACE__, __DIR__ . DIRECTORY_SEPARATOR . 'command']; } } ``` ## cron 的表达式 ``` // cron 表达式 * * * * * - - - - - | | | | | | | | | | | | | | +----- day of week (0 - 6) (Sunday=0) | | | +---------- month (1 - 12) | | +--------------- day of month (1 - 31) | +-------------------- hour (0 - 23) +------------------------- min (0 - 59) ``` 调用的任务类设置 `TestTask` 就完成了。感兴趣的话,就赶快试一试吧。 ### 常用 Crontab 表达式示例 * `*/5 * * * *` 每 5 分钟执行一次 * `30 21 * * *` 每晚 21:30 执行一次 * `* 12-23 * * *` 下午每分钟执行一次 * `0 */2 * * *` 每 2 小时执行一次 * `* */2 * * *` 偶数小时每分钟执行一次 * `0 * * * *` 每小时执行一次 * `0 0 * * *` 每天执行一次 * `0 0 0 * *` 每月执行一次 * `0 0 0 0 1` 每个星期一执行一次 cron 表达式详细说明 --- --- url: /docs/catchadmin/catch-table.md --- # 表格组件 :::warning 表格组件目前可以完成正常的 85% 的操作,部分需求请回归正常的页面开发。再使用之前,请熟悉 element table 组件。 目前基础模块有大量案例可供参考。具体查看代码。有问题请去[`论坛提问`](https://bbs.catchadmin.com),请不要在群里问,重复的问题太多 ::: ## 后端 `Table` 组件目前由下面`Table`本身,`Search` 组件和表格 `Header` 还有 `Actions` 组成。后端返回 `Json` 数据,给前端渲染页面表格。 所以这个要配合前端 `table` 是实现操作。在看视频介绍之前,一定要先看文档。[视频介绍](https://www.bilibili.com/video/BV1Py4y1x7q5/)记得三连 + ## Table ### 设置表格头部 ```php table->header(array $header) ``` :::tip $header 是 HeaderItem 集合,具体请看 HeaderItem 说明 ::: ### 设置表格操作 ```php table->withActions(array $actions) ``` :::tip $actions 是 Actions 集合,具体请看 Actions 说明 ::: ### 设置搜索 ```php table->withSearch(array $search) ``` :::tip $search 是由 Search 集合,具体请看 Search 说明 ::: ### 设置表格事件,具体查看 [Element Table Events](https://element.eleme.cn/#/zh-CN/component/table) ```php table->withEvents(array $events) ``` ### 设置默认搜索参数 ```php table->withDefaultQueryParams(array $params) ``` ### 设置搜索参数 ```php table->withFilterParams(array $filterParams) ``` ### 设置隐藏分页 ```php table->withHiddenPaginate() ``` ### 设置表格列表路由 ```php table->withApiRoute(string $apiRoute) ``` ### 设置表单弹出层的宽度 ```php table->withDialogWidth(string $width) ``` ### 设置导入路由 ```php table->withImportRoute(string $route) ``` ### 设置导出路由 ```php table->withExportRoute(string $route) ``` ### 设置树状列表,具体查看 Element Tree Table ```php table->toTreeTable(string $rowKey = 'id', array $props = []) ``` ### 设置树状列表展开 ```php $table->expandAll(bool $expand=true) ``` ### 固定表头 ```php $table->withHeight(int $height) ``` ### 斑马纹 ```php $table->withStripe() ``` ### 绑定模式 ```php $table->withBind() ``` :::tip 使用该方法之后,前端 `catch-table` 可以更加简洁的使用。注意看之后前端的说明 ::: ### 设置强制更新组件 ```php table->forceUpdate() ``` ### 快捷导入导出,只支持单模型导入导出 ```php table->withUsedModelAndExcel(string $usedModel, array $excel) ``` ### usedModel 必须使用的模型,例如 Users::class ```php $excel 是 Excel 对象 集合,具体看下面的 Excel 组件 ``` ## Search 搜索组件 ### 设置 label ```php Search::label(string $label) ``` :::warning label 设置是静态属性,所以每次都需要单独调用一次,不然下次调用会使用上一次的结果 ::: ### 设置 text,文本搜索 ```php Search::text($name, $placeholder) ``` ### 设置 select ```php Search::select($name, $placeholder, $options) ``` ### 设置 name, 默认 name 搜索 ```php Search::name() ``` ### 设置 status, 默认 status 状态搜索 ```php Search::status() ``` ### 设置 startAt, 默认 start\_at 开始时间搜索 ```php Search::startAt() ``` ### 设置 endAt, 默认 end\_at 结束时间搜索 ```php Search::endAt() ``` :::tip `Form` 组件的方法, `Search` 组件一样可以使用。根本上来说,`Search` 组件是由 `Form` 组件包装的 ::: ## HeaderItem 表格列组件 ### 设置 label ```php HeaderItem::label(string $label) ``` ### 设置 prop ```php HeaderItem::prop(string $prop) ``` ### 设置宽度 ```php HeaderItem::width(string $width) ``` ### 设置操作 ```php HeaderItem::actions(array $actions) ``` :::tip $actions 是 Actions 对象集合 ::: ### 设置排序 ```php HeaderItem::sortable() ``` ### 设置多选, 用在列表第一列,配合 table 的 selectChange 事件使用 ```php HeaderItem::selection() ``` ### 列设置不导出 ```php HeaderItem::dontExport() ``` ### 列设置不导入 ```php HeaderItem::dontImport() ``` ### 固定列 ```php HeaderItem::fixed($fixed = true) ``` :::tip fixed 支持 bool,或者字符串 left 和 right ::: ### 展开行 ```php HeaderItem::expand() ``` ## table 列的插槽 这些组件提供了列的数据可动态操作,除了内置的组件,自己也可以自定义列的插槽组件 ### switch 组件 ```php HeaderItem::withSwitchComponent(array $options = [], $updateFields = null) ``` :::tip 可以使用 Form::options()->add('文字', 1)->render() ::: ### edit 组件 ```php HeaderItem::withEditComponent($updateFields = null) ``` ### eidtNumber 组件 ```php HeaderItem::withEditNumberComponent($updateFields = null) ``` ### select 组件 ```php HeaderItem::withSelectComponent(array $options, $updateFields = null) ``` ### preview 组件(预览组件) ```php HeaderItem::withPreviewComponent($field = null) ``` ### component 组件 ```php HeaderItem::component(string $name, string $updateField = '', $options = []) ``` ### 下载 组件 ```php HeaderItem::withDownloadComponent($field = null) ``` ## Actions 组件 :::tip Actions 会创建对应的按钮操作 ::: ### 普通按钮 ```php Actions::normal(string $text, $type = '', string $event = null) ``` * text:按钮显示的文字 * type:按钮的类型,具体查看 Element button (opens new window)的 type * event:按钮的 click 事件,设置之后需要在前端实现该事件 ### 创建操作 ```php Actions::create() ``` ### 更新操作 ```php Actions::update() ``` ### 删除操作 ```php Actions::delete() ``` ### 查看操作 ```php Actions::view() ``` ### 导出操作,配合 table 的 exportRoute 使用 ```php Actions::export() ``` ### 导入操作, 配合 table 的 importRoute 使用 ```php Actions::import() ``` ### 路由跳转 ```php Actions::to(string $router) ``` ## Excel 组件 ### 设置 label ```php Excel::label(string $label) ``` ### 设置 prop ```php Excel::prop(string $prop) ``` ### 设置 options ```php Excel::options(array $options) ``` :::tip 提供字段枚举值的转换,例如表的 status 字段,1 代表 启用 2 代表禁用,那么可以按照下面的例子设置 ::: ```php [ [ 'label' => '启用', 'value' => 1, ], [ 'label' => '禁用', 'value' => 2, ] ] ``` 正确设置之后,导入导出才可以正确转换。 ### 设置导入 ```php Excel::import(bool $import) ``` 一般来说,你设置了字段都会在导入导出中使用,但是如果你不需要的,可以通过这个方法设置为 false,下面的 export 同理 ### 设置导出 ```php Excel::export(bool $export) ``` ## 前端 一般模式下前端 `props` 需要配合后端填充就可以了。 ```javascript ``` 绑定模式下的操作更加简洁 ```javascript ``` ## 表单组件 表单组件前端基于 [form-create](http://www.form-create.com/v2/guide/), 后端基于其 [PHP 扩展包](http://php.form-create.com/docs/2.0/README)。请在使用前阅读其文档。Form 在其基础上做了适配后台的非过度封装。 下面是新增的 Form 组件。 ### 图片上传 ```php Form::image(string $title, string $value = '') ``` ### 多图上传 ```php Form::images(string $title, string $value = '') ``` ### 文件上传 ```php Form::file(string $title, string $value = '') ``` ### 多文件上传 ```php Form::files(string $title, string $value = '') ``` ### 编辑器 ```php Form::editor($field, $title, $value = '') ``` :::tip 编辑器需要在 Dialog 中初始化,否则在第二次打开无法使用。具体请看[论坛解决方案](https://bbs.catchadmin.com/post/13) ### 省市区 :::tip 在使用省区市组件之前,也要使用 php think region 命令获取省市区数据,之后在使用组件 ::: ```php Form::area($field, $title, $props = []) ``` ## 额外支持的表单验证 ### 正则验证 ```php Form::validatePattern(string $pattern) ``` ### 纯数字验证 ```php Form::validateAlpha() ``` ### 支持字母和数字 ```php Form::validateAlphaNum() ``` ### 字母和数字,下划线\_及破折号- ```php Form::validateAlphaDash() ``` ### 手机号 ```php Form::validateMobile() ``` ### 身份证 ```php Form::validateIdCard() ``` ### 邮政编码 ```php Form::validateZip() ``` ### IP 地址 ```php Form::validateIp() ``` ### 座机 ```php Form::validateLandLine() ``` ### 密码 ```php Form::validatePassword() ``` ### 强密码 ```php Form::validateStrongPassword() ``` ### 纯汉字 ```php Form::validateChineseCharacter() ``` ## Form 的最佳实践 `CatchAdmin` 是模块化的,那么模块只管理模块的 `Form` 就好了。因为每个模块的 `Form` 只是渲染页面,而不涉及数据操作。所以针对每个模块使用 `Factory` 来管理,那么针对所有模块则使用了抽象工厂。下面来看看如何做的。 首先在任意模块创建 `form` 文件夹,然后创建 `Factory.php` 文件 ```php use catcher\library\form\FormFactory; class Factory extends FormFactory { public static function from(): string { return __NAMESPACE__; } } ``` 继承 `FormFactory` 抽象工厂,实现 `from `方法,返回当前的 `Namespace` 就可以。 创建一个 `From.php` 文件。继承 `Form` 之后,实现 `fields `方法。 ```php use catcher\library\form\Form; class Form extends Form { public function fields(): array { // TODO: Implement fields() method. return [ self::input('job_name', '岗位名称')->required(), self::input('coding', '岗位编码'), self::radio('status', '状态')->value(1)->options( self::options()->add('启用', 1)->add('禁用', 2)->render() ), self::number('sort', '排序')->value(1)->min(1)->max(10000), ]; } } ``` 最后创建使用工厂生产 `Form` ```php Factory::create('form'); ``` --- --- url: /docs/catchadmin/front.md --- # 前端开发 ## 非常重要的更新 前端模块也需要单独安装自己的组件 例如 `permissions` 模块下面就有 `router.js` ```javascript export default { users: () => import('@/views/permission/users'), roles: () => import('@/views/permission/roles'), rules: () => import('@/views/permission/rules'), departments: () => import('@/views/permission/departments'), jobs: () => import('@/views/permission/jobs') } ``` 如果是老项目,那么就需要你切割 `config/componentsMap.js` 到每个模块下的 `router.js`。 新项目就按照当前模式开发就可以了 ## 去除动画效果 找到 `@/layout/components/AppMain.vue` 这里在 `app-main` 外部包了一层 `keep-alive` 主要是为了缓存 `router-view` 的,配合页面的 `tabs-view` 标签导航使用,如不需要可自行去除。 其中`transition` 定义了页面之间切换动画,可以根据自己的需求,自行修改转场动画。相关文档。默认提供了`fade`和`fade-transform`两个转场动画,具体 `css`实现见`transition.scss`。如果需要调整可在`AppMain.vue`中调整 `transition` 的 `name`。 ## keep-alive 找到 `@/layout/components/AppMain.vue` 以下代码 ```javascript ``` 去除 `include` 和 `key `即可。 :::warning 目前缓存的方案对于某些业务是不适合的,比如文章详情页这种 /article/1 /article/2,他们的路由不同但对应的组件却是一样的,所以他们的组件 name 就是一样的,就如前面提到的,keep-alive 的 include 只能根据组件名来进行缓存,所以这样就出问题了。目前有两种解决方案: 不使用 keep-alive 的 include 功能 ,直接是用 keep-alive 缓存所有组件,这样子是支持前面所说的业务情况的。当然直接使用 keep-alive 也是有弊端的,他并不能动态的删除缓存,你最多只能帮它设置一个最大缓存实例的个数 limit。 ::: ## Diglog 拖拽 引入拖拽指令 ```javascript import elDragDialog from '@/directive/el-drag-dialog' export default { directives: { elDragDialog } } ``` 在 Dialog 上使用指令 ```javascript ``` ## 表格操作(请采用 catch-table 组件,后期会废除) 下面的操作基于 引入 mixins, ```javascript import formOperate from '@/layout/mixin/formOperate' export default { mixins: [formOperate] } ``` ### 参数 * formName: string | 表名 * formFieldsData: object | 表单对象 * queryParam: object | 搜索参数 * defaultQueryParam: array | 默认搜索参数 * refreshRoute: bool | 刷新路由(一般用不到) * url: string | 请求的操作的 URL ### 新增 * beforeCreate: function | 新增前 * handleCreate: function ### 更新 * beforeUpdate: function | 更新前 * handleUpdate: function ### 删除 * beforeDelete: function | 删除前 * handleDelete: functio ### 批量删除 * handleSelectMulti: function | 批量选择 * beforeMultiDelete: function | 批量删除前 * handleMultiDelete: function ### 提交 * beforeSubmit: function | 提交前 * handleSubmit: function ### 取消 * handleCancel: function * afterCancel: function | 取消后 ### 搜索 * handleSearch ### 刷新 * handleRefresh ### 分页 ```javascript ``` --- --- url: /docs/faq.md --- # 常见问题 ## 为什么项目安装成功之后无法访问 * 安装项目之后,打开 DEBUG,将 `.env` 的 `debug` 设置为 `true`. * 不要直接访问 PHP 项目,即使你在配置完域名之后. ## 为什么权限添加之后没有生效 CatchAdmin 在用户登录之后,会将登录用户的权限信息缓存起来。所以需要刷新一下后台重新拉取信息。 ## 常见错误 Cloud not Create token :strpos() expect parameter 1 to be string. array give 请检查 .env 文件是否生成了 jwt 密钥。如果没有,请执行 ``` php think jwt:create ``` :::tip 如果还是不行,请检查是否有 .env 文件 ::: ``` There are no commands defined in the "jwt" namespace. ``` 解决方案有两个,均由于 Composer 升级导致的。 * 降低 composer 版本, composer self-update --rollback * 升级 tp 核心版本,composer update 即可 :::tip 目前推荐第一种,防止有其他包没有做适配工作。激进点可以选择第二种,毕竟 composer2 太香了。 ::: ## 为什么找不到 CatchAdmin 的 SQL 文件 `CatchAdmin` 摒弃了 `SQL` 形式的安装,采用了 `Migration` 建立数据表,数据表在每个模块都是独立。 具体可以查看模块下的 `database` 文件下的 `migration`可以清晰看到每个模块的数据表的迭代情况 ## 如何获取登录用户的信息 `CatchAdmin` 可以全局获取登录用户信息 ```php request()->user() // 获取用户角色 request()->user()->getRoles() ``` ## composer install 安装报错 如果遇到了 `think service:discover handling the post-autoload-dump event returned with error code 255 错误`。 * 如果存在 composer.lock, 删除 `vendor` 文件夹以及删除 `composer.lock` 文件,之后 `composer install`。 * 直接 composer update 即可 ## 上线部署 优化自动加载的时候要去除 `require-dev` 的加载目录 ``` composer dump-autoload --no-dev ``` ## 出现权限问题 ``` chmod(): Operation not permitted ``` 需要改变运行用户, 找到 fpm 运行的用户组,然后使用下面命令,`fpm` 默认是 `www-data`, 如果修改了用户,根据实际情况修改即可。 ``` chown -R www-data:www-data catch/ ``` ## 出现路由未定义 * 检查 `runtime\catch` 目录下是否有缓存 * 检查对应的模块是否开启, module.json 文件 `enable` 字段 ## 定义日期类型错误 ``` Incorrect date value: ‘0000-00-00 00:00:00‘ for column ‘xxxx‘ at row 1 ``` 查看 `sql_mode`变量 ```php show variables like '%sql_mode%' ``` 如果含有 `NO_ZERO_IN_DATE, NO_ZERO_DATE`, 则去除。 ``` set @@sql_mode='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION' ``` 变量最好配置 mysql 的 `my.cnf` 中,否则重启会失效 ## 模型注释无法生成 首先移除 ``` composer remove jaguarjack/file-generate --ignore-platform-reqs ``` 在重新安装 ``` composer require jaguarjack/file-generate:dev-master --ignore-platform-reqs ``` --- --- url: /docs/3.0/intro.md --- # CatchAdmin 介绍 - 专业的 PHP Laravel 后台管理系统 :::info 如果你正在关注 `CatchAdmin` 或者准备使用,可以查看[新的 v5 版本](/docs/5.0/start/project_intro.md), v5 是一个新结构而且强大的版本,也即将支持 vue 免编译。 ::: > 基于 Laravel 12.x 和 Element Plus 的现代化 php 开源后台管理 解决方案 `CatchAdmin`是一款基于[Laravel 12.x](https://laravel.com)和[Element Plus](https://element-plus.org)二次开发而成的 PHP 开源后台管理系统。`Laravel` 社区也有许多非常优秀的后台管理系统,例如 `Nova`, 官方出品,当然是收费的,免费的有基于 `Livewire` 的 `Filament`,还有不得不说的 `Laravel Admin`。`CatchAdmin` 还是采用传统的前后端分离策略,`Laravel` 框架仅仅作为 `Api` 输出。将管理系统模块之间的耦合降到了最低限度。每个模块之间都有独立的控制器,路由,模型,数据表。在开发上尽可能将模块之间的影响降到最低,降低了开发上的难度。基于 `CatchAdmin `可以开发 `CMS`,`CRM`,\` ## 为什么选择 CatchAdmin? 作为一款专业的 **laravel admin** 解决方案,CatchAdmin 在众多 **PHP 后台开源管理系统** 中脱颖而出: ### 🚀 技术优势 * **现代化架构**: 基于 Laravel 12.x 最新版本,充分利用 PHP 8+ 特性 * **前后端分离**: Vue 3 + Element Plus 前端,Laravel RESTful API 后端 * **模块化设计**: 每个业务模块完全独立,支持按需加载和扩展 * **开箱即用**: 内置完整的权限管理、用户管理、日志系统 ### 💼 适用场景 * **企业后台管理**: 适合中小企业快速搭建内部管理系统 * **SaaS 平台**: 为 SaaS 产品提供标准化的管理后台基础 * **内容管理**: CMS、博客、新闻等内容管理系统 * **电商后台**: 商品管理、订单处理、客户服务等电商场景 * **项目管理**: OA 办公、CRM 客户关系管理等企业应用 ## 架构特性 `CatchAdmin` 聚焦于 PHP Laravel 后台管理 的工程实践,保持前后端分离,让 `Laravel` 只负责标准化的 `RESTful API` 和权限校验,前端则依赖 `Element Plus` 提供可扩展的 UI 组件。这样的模块化设计确保核心业务逻辑与界面层完全解耦,在迭代时能够快速响应复杂的企业需求。 * 灵活的模块拆分:控制器、路由、模型与数据表保持独立,便于按需组合或裁剪,实现面向领域的 laravel 后台 规划。 * 完整的扩展生态:基于 `Laravel` 既有能力和 `CatchAdmin` 封装的工具集,可以平滑接入第三方服务,减少 php 后台管理 项目常见的重复开发成本。 * 企业级运维友好:标准化的接口设计与日志体系便于团队在容器化环境下部署和监控,为长期维护 laravel admin 项目提供保障。 ## 其他新版本 * [ThinkPHP8.0 版本](https://gitee.com/catchamin/catchadmin-tp) * [Webman 高性能版本](https://gitee.com/catchamin/catchadmin-webman) ## 讨论区 [CatchAdmi 讨论区](https://catchadmin.com/forum) ## 专业版 [专业版本官方地址](https://gitee.com/link?target=https%3A%2F%2Flicense.catchadmin.com) 首先感谢一直以来对 CatchAdmin 开源项目的支持和使用。作为一名开源工作者,我一直致力于开发出功能强大且易于使用的后台管理系统,以帮助您简化业务流程和提升工作效率。然而,由于某些原因,我不得不做出一些调整。为了能够继续开发和维护这个项目,我将推出一款付费的后台管理系统,以确保我能够持续为您提供高质量的服务和支持。 专业版本不会在开源版本做一些破坏性变更,所以当您从开源版本切换到专业版本,不会有任何开发心智负担。但是使用专业版本会有新的组件来配合您的工作。 我深信,付费后台管理系统将为您带来更多的价值和便利,帮助您提升工作效率 ## 功能 * ☑️ **用户管理** - 完整的后台用户管理,支持用户信息维护、状态管理、批量操作 * ☑️ **部门管理** - 配置公司的部门结构,支持树形结构,无限层级嵌套 * ☑️ **岗位管理** - 配置后台用户的职务,支持多岗位绑定,灵活的组织架构 * ☑️ **菜单管理** - 可视化菜单配置,支持按钮级权限控制,动态路由生成 * ☑️ **角色管理** - 基于 RBAC 的角色权限体系,细粒度权限分配 * ☑️ **操作日志** - 详细的用户操作记录,支持日志查询、导出、统计分析 * ☑️ **登录日志** - 完整的登录行为追踪,IP 地理位置、设备信息记录 * ☑️ **代码生成** - 智能化 CRUD 代码生成,提升开发效率 80% * ☑️ **Schema 管理** - 可视化数据库表结构管理,支持在线修改 * ☑️ **模块管理** - 插件化模块系统,支持热插拔,便于系统扩展 ### 📊 核心功能详解 **权限管控**: CatchAdmin 采用业界标准的 RBAC (Role-Based Access Control) 权限模型,支持: * 多角色授权、角色继承 * 菜单权限、按钮权限、数据权限三级管控 * 部门数据隔离、个人数据权限 * API 接口权限验证 **开发效率**: 作为专业的 **laravel 后台** 框架,内置多种开发加速工具: * 一键 CRUD 生成,减少重复代码编写 * 标准化 API 接口规范 * 完整的前端组件库 * 详细的开发文档和示例代码 ## 业务场景 `CatchAdmin` 已在多种业务中验证:以 `CMS` 内容平台为例,团队可以通过可视化菜单与权限配置快速建立内容审核流程;在 `CRM` 或销售管理场景中,借助灵活的岗位与角色绑定,实现跨部门协同;针对内部 `OA` 系统,配合操作日志、登录日志等模块,帮助管理者洞察关键行为。这些功能让开发者无需从零搭建 PHP Laravel 后台管理 基座,即可交付稳定的 laravel 后台 产品,并持续在现有 laravel admin 生态中迭代。 ## 额外模块 * [CMS 模块](https://github.com/catch-admin/cms) ## 项目地址 * [github 地址](https://github.com/jaguarjack/catch-admin) * [gitee 地址](https://gitee.com/jaguarjack/catchAdmin) ## 预览 ![laravel admin catchadmin 介绍](/docs/assets/intro/catchadmin-intro.png) ![laravel admin catchadmin 介绍](/docs/assets/intro/catchadmin-intro1.png) ![laravel admin catchadmin 介绍](/docs/assets/intro/catchadmin-intro2.png) ![laravel admin catchadmin 介绍](/docs/assets/intro/catchadmin-intro3.png) ## 体验地址 [demo 地址](https://v3.catchadmin.com) * 账户: `catch@admin.com` * 密码: `catchadmin` ## 讨论 * [论坛讨论](https://catchadmin.vip/forum) * 可以提 `ISSUE`,请按照 `issue` 模板提问 ### 加入微信群 添加微信好友进群 ## 赞助 如果项目对你有帮助,或者在工作上帮你节省了开发时间。在力所能及的情况下,可以支持下`Catchadmin`项目, 非常感谢 🙏 ## 🛠️ 技术栈 ### 后端技术 * **PHP 8.2+**: 利用最新 PHP 特性,性能提升显著 * **Laravel 12.x**: 最新版本的 Laravel 框架,稳定可靠 * **MySQL**: 支持主流关系型数据库 * **Redis**: 缓存和会话存储,提升系统性能 * **Composer**: PHP 依赖管理工具 ### 前端技术 * **Vue 3**: 现代化的前端框架,响应式开发 * **Element Plus**: 企业级 UI 组件库,开箱即用 * **TypeScript**: 类型安全,提升代码质量 * **Vite**: 快速的构建工具,热更新支持 * **Pinia**: 状态管理,替代 Vuex ## 📚 学习资源 ### 快速入门 1. [安装指南](./start/install.md) - 详细的安装步骤和环境配置 2. [项目介绍](./start/project_intro.md) - 了解项目结构和核心概念 3. [视频教程](./video.md) - 可视化学习,快速上手 ### 进阶开发 * [模块开发](./server/modules.md) - 学习如何开发自定义模块 * [权限管理](./server/permission.md) - 深入理解权限体系 * [前端组件](./front/intro.md) - 前端开发指南和组件使用 ### 部署运维 * [部署指南](./deploy.md) - 生产环境部署最佳实践 * [常见问题](./faq.md) - 问题排查和解决方案 ## 🏆 成功案例 CatchAdmin 已成功应用于多个行业: * **教育行业**: 某知名在线教育平台使用 CatchAdmin 构建学员管理系统 * **电商领域**: 多家电商企业基于 CatchAdmin 开发商家后台管理 * **政企服务**: 政府部门采用 CatchAdmin 搭建内部办公管理系统 * **医疗健康**: 医疗机构使用 CatchAdmin 开发患者管理和医生工作站 ## 感谢 🙏 > 排名不分先后 * [Laravel](https://laravel.com) * [Vue](https://cn.vuejs.org/) * [ElementPlus](https://element-plus.org) * [Vitepress](https://vitepress.dev/) * [JetBrains](https://www.jetbrains.com/) --- --- url: /docs/3.0/start/install.md --- # 项目安装 ## 环境要求 * PHP >= 8.2+ * Nginx * Mysql >= 5.7 ## 安装 ### 准备 在安装这个软件之前,您需要准备一些必要的工具,包括: * [git 代码管理](https://git-scm.com/downloads) * [composer PHP 包管理器](https://getcomposer.org/download/) * [nodejs >= 22 ](https://nodejs.org/zh-cn/) * [yarn 前端包管理器](https://yarn.bootcss.com/) * [vite](https://cn.vitejs.dev/) :::tip 如果你是第一次使用或者需要一个完整的集成环境,CatchAdmin 官方也提供了一个 Laravel 入门教程,目前正在完善中。 可以尝试使用该文档 [Laragon 集成环境安装](https://laravel-study.catchadmin.com/hello-laravel.html#%E7%8E%AF%E5%A2%83%E5%87%86%E5%A4%87) ::: ## composer 安装 :::info 如果已经安装 请跳过该步骤 ::: 请确保已经安装了 `composer` 包管理器。如果您使用的是 `Mac OS` 或者 `Linux`,可以在终端输入以下命令安装 `composer` ```shell // mac os brew install composer // linux sudo apt-get install composer ``` 如果您使用的是 `Windows` 系统,可以从 [composer](https://docs.phpcomposer.com/) 的官方网站下载 exe 安装文件进行安装。 ## 第一种方式: 安装器安装 CatchAdmin 项目 安装器只是为了简化安装项目过程,如果遇到问题(一般是网络问题)。请使用下面的 `下载项目` 的步骤 ```shell composer global -W require catchadmin/installer # MacOs 系统需要添加环境变量 export PATH="$HOME/.composer/vendor/bin:$PATH" ``` 安装成功之后使用下面的命令 ```shell catch new catchadmin ``` 会看到如图所示的 ![catchadmin 快速安装](https://image.catchadmin.com/202504191018871.png) 可以选择对应的项目,默认是 Laravel 版本的。按照命令行提示输入即可。最后安装完成后会出现下面的提示 ![catchadmin 快速安装](https://image.catchadmin.com/202504191022429.png) ## 第二种方式: 手动安装 ### 下载项目 :::info 目前最新代码在 Gitee,Github 网络越来越不好了。Gitee 比较流畅 ::: 接下来,您需要下载 CatchAdmin 项目。您可以前往该项目在 [CatchAdmin](https://gitee.com/jaguarjack/catchAdmin) 上的页面进行下载,也可以使用 `git` clone 命令将代码克隆到本地,这样就能及时获取代码更新。 ```sh git clone https://gitee.com/catchadmin/catchAdmin.git ``` 当然你也可以使用 [Github](https://github.com/JaguarJack/catch-admin), 有可能会同步不及时。 请注意,该项目不提供 Web 安装方式,因此您需要使用命令行方式进行安装。接下来您可以进入 `CatchAdmin` 项目所在的目录,并运行以下命令进行安装: ```shell # 请一定使用代理安装依赖,据目前所知,国内的 composer 镜像不是不更新了就是更新延后 # 配置完镜像使用 composer 安装 composer install ``` 然后使用下面的命令安装 ```shell // 安装后台, 按照提示输入对应信息即可 php artisan catch:install // 上传显示图片需要软连接 php artisan storage:link // 启动后台 php artisan serve ``` :::info 当你使用 catch:install, 会自动下载前端项目,他们会被下载到根目录的 `web 目录` ::: ### 手动安装前端项目 如果使用 `catch:install` 安装前端项目失败,那么你可以手动安装它。[前端项目仓库](https://gitee.com/catchadmin/catch-admin-vue.git) ```shell git clone https://gitee.com/catchadmin/catch-admin-vue.git web cd web # 安装完 nodejs 之后,再安装 yarn npm install --global yarn # 在安装前记得,一定要配置镜像。否则会下载失败(一定必须) yarn config set registry https://registry.npmmirror.com # 安装完成之后,使用 yarn install cp .env.example .env # 然后添加下面的内容 .env 配置,根据实际情况修改后端访问的 api 地址 VITE_BASE_URL=PHP项目域名/api # 启动前端项目 yarn dev ``` 这样就可以安装所有需要的依赖包了。依赖安装完成之后,还需要安装项目的基本信息,如下 :::warning 注意不能直接访问 PHP 项目,会出现异常或者路由找不到。CatchAdmin 是前后端分离项目,你需要通过通过 API 接口形式访问。所以你需要安装好 VUE 项目后台,通过后台管理来访问 ::: ## 启动 ### 手动启动 打开一个 CMD 窗口,然后到项目根目录 使用下面的命令 ```shell php artisan serve ``` 新打开一个 CMD 窗口然后继续进入到 web 目录 ```shell cd web yarn dev ``` ### 快捷启动 既可以用上面的两个命令分别启动项目,也可以使用下面的命令启动两个项目。 ```shell composer run dev ``` :::tip 如果你是第一次使用 Vue,建议先去看看 [Vue](https://cn.vuejs.org/) 文档,了解一下 vue 后台使用了是 `element Plus` [文档地址](https://element-plus.org) ::: --- --- url: /docs/3.0/start/project_intro.md --- # 项目介绍 Catchcadmin V3 是一个开源的后台管理系统,它提供了一组完整的解决方案,可以帮助开发者快速构建各种类型的管理后台,例如 CMS、ERP、CRM、OA 等。Catchcadmin V3 版本的改动非常大,它采用了 Laravel 12.X、Vue3 和 ElementPlus 等最新的技术,以及更加优秀的代码组织方式,以更好地满足开发者的需求。 * typescript * vue3 * tailwindcss(css 组件库) * Laravel (之前使用 tp6 的话,用起来应该没有压力) ### 目录结构 `Catchadmin` V3 版本服务端和前端放在一个项目中,这样会更方便开发。 :::warning 目前 catchadmin 已经使用 `server` 分支开发,也作为默认分支。`server` 分支是完全分离的项目 ::: ``` ├─app ├─bootstrap ├─config(配置目录) ├─database(migration和seed存放目录) ├─lang(多语言目录) ├─public(运行目录 ├─modules(模块目录) ├─web (前端目录) │ ├─src (前端目录) │ │ ├─assets | | ├─compoents (组件) | | ├─enum (枚举) | | ├─layout (前端布局) | | ├─router (前端路由) | | ├─store (pinia目录) | | ├─styles (样式目录) | | ├─support (助手方法) | | ├─types (类型目录) | | ├─views (前端视图目录) | | | App.vue | | | app.ts | | | env.d.ts │ │ │ └─依赖文件 ├─routes ├─storage ├─tests │ .env-example(env配置示例) │ .gitattributes │ .gitignore │ .travis.yml │ composer.json │ .php-cs-fixer.dist.php | package.json │ phpunit.xml │ postcss.config.js │ tailwind.config.js │ tsconfig.json │ tsconfig.node.json │ vite.config.js └─ artisan(命令行入口文件) ``` 这里可以先熟悉目录结构,在后续将介绍系统内具体的一些方法和配置。 和之前 2.x 相比,最大的变化就是将核心目录已经独立出去,使用单独的 `composer` 加载,如果遇到任何问题或者 bug 可以到[catchadmin/core](https://github.com/catch-admin/core)仓库提交 issue! ## 视频介绍 [catchadmin 新版本安装,视频作为了解,已经很老了](https://www.bilibili.com/video/BV1eY411v71J/) --- --- url: /docs/3.0/deploy.md --- # CatchAdmin 部署指南 > 详细的 CatchAdmin 生产环境部署教程和最佳实践 :::warning 很多开发者在部署 CatchAdmin 时遇到问题,这里提供了完整详细的部署文档。本文档包含了从前端构建到服务器配置的全部步骤,基本涵盖了所有部署场景。 请仔细阅读文档,大部分问题都能在这里找到解决方案。如果遇到特殊情况确实需要协助,目前提供付费部署支持服务,收费标准为 `100` 元/次。先付费后服务,感谢理解 🙏 ::: ## 前端项目 在构建 CatchAdmin 前端项目前,需要先配置生产环境的 API 地址。在前端项目根目录下创建或编辑 `.env.production` 文件: ``` # base api // 例如 https://api.catchadmin.com/api/ VITE_BASE_URL = '正式环境的 API 地址' ``` 配置完成后,使用以下命令构建 CatchAdmin 前端项目: ```bash yarn run build # 或者使用 npm npm run build ``` ### 打包出现报错 如果打包出现 ts 过多的类型错误,而你对类型又不太敏感的话,对应用没有影响。一个快速的解决办法就是修改 `package.json 文件` build 命令 ```json { "scripts": { "dev": "vite", "build": "vue-tsc --noEmit && vite build", // [!code --] "build": "vite build", // [!code ++] "preview": "vite preview" } } ``` 构建完成后,前端项目根目录会生成 `dist` 目录,这是 CatchAdmin 前端的生产版本,包含经过优化的静态资源文件,可直接部署到 Web 服务器。 :::tip 性能优化建议 1. 建议在 Web 服务器上启用 `Gzip` 压缩,可显著提升页面加载速度 2. 配置静态资源缓存策略,提升用户体验 3. 使用 CDN 加速静态资源访问 ::: ## 后端 CatchAdmin 后端基于 PHP 开发,部署相对简单。将 PHP 项目代码上传到服务器即可。 **推荐部署方式**: 1. 上传源代码到服务器,不包含 `vendor` 目录 2. 在服务器上执行 `composer install --no-dev` 安装生产环境依赖 3. 配置正确的文件权限和目录结构 如果遇到依赖安装的网络问题,请参考 [使用镜像](./faq.md#镜像) 解决方案。 :::warning 重要提醒 如果使用了 CatchAdmin 脚手架初始化项目,部署时需要注意: * **排除 `web` 目录**:这是前端开发目录,不需要与后端一起上传 * **前端部署**:只需要上传构建后的 `dist` 目录 * **分离部署**:前后端建议分开部署,便于维护和扩展 ::: ### 上线注意点 * `.env` 环境文件是否配置好? * 数据库表是否同步? * 数据表的数据是否同步,主要是**权限菜单**表`permissions`里是否同步 * 模块是否开启? 模块如果没有开启,整个项目都会无法正常运行 (`这个步骤只针对 Laravel 主项目`) :::tip 一定要检查线上项目`storage/app/modules.json` 是否存在。如果不存在,要将本地项目`storage/app/modules.json`上传到服务器 ::: * 模块如果正常开启的状态下,路由还是无法正常工作 (`这个步骤只针对 Laravel 主项目`) :::tip * 首先是用 php artian route:clear * 然后查看路由 php artisan route:list * 最后缓存路由 php artisan route:cache ::: ## 部署 :::warning 如果你使用的是宝塔相关的,一定不要完全复制下面的配置。因为宝塔有很多预配置项,例如 https ssl 配置是不需要你自己手动配置 ::: ### 分开部署(双域名) 推荐的 CatchAdmin 部署方式是前后端分离部署,分别使用不同的域名或子域名: **部署架构示例**: * 前端项目:`admin.yourdomain.com` → `/www/admin` 目录 * 后端 API:`api.yourdomain.com` → `/www/api` 目录 :::tip 部署建议 * 目录路径可根据实际服务器环境调整 * 分离部署便于独立维护和扩容 * 支持前后端独立更新,降低部署风险 ::: * `/www/admin` 上传 `dist` 目录内容到 admin 目录中 * `/www/api` 上传后端项目到 api 目录中 ::: code-group ```php [前端项目] server { listen 80; server_name admin.catchadmin.com; return 301 https://admin.catchadmin.com$request_uri; } server { listen 443 ssl http2; server_name admin.catchadmin.com; index.html index.php index.htm default.php default.htm default.html; ssl_certificate # pem文件的路径 ssl_certificate_key # key文件的路径 # ssl验证相关配置 ssl_session_timeout 5m; #缓存有效期 ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; root /www/admin; location / { try_files $uri $uri/ /index.html =404; } } ``` ```php [后端项目] server { listen 80; server_name api.catchadmin.com; return 301 https://api.catchadmin.com$request_uri; } server { listen 443 ssl http2; server_name api.catchadmin.com; index index.html index.php index.htm default.php default.htm default.html; root /www/api/public; ssl_certificate /etc/nginx/acme/catchadmin.com/catchadmin.com.cer; # pem文件的路径 ssl_certificate_key /etc/nginx/acme/catchadmin.com/catchadmin.com.key; # key文件的路径 ssl_session_timeout 5m; #缓存有效期 ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; location / { if (!-e $request_filename) { rewrite ^(.*)$ /index.php?s=/$1 last; break; } } # PHP 支持 location ~ \.php$ { try_files $uri /index.php =404; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } ## nginx log 自己配置 access_log; error_log; } ``` ::: ### 合并部署(单域名) 如果只有一个域名或希望简化部署架构,可以将 CatchAdmin 前后端部署在同一域名下: **部署结构**: * 后端项目:`yourdomain.com/api` → PHP 项目根目录 * 前端项目:`yourdomain.com/` → 放置在后端项目的 `public/admin` 目录下 这种方式适合小型项目或资源有限的场景。 ```php server { listen 80; server_name api.catchadmin.com; return 301 https://api.catchadmin.com$request_uri; } server { listen 443 ssl http2; server_name api.catchadmin.com; index index.html index.php index.htm default.php default.htm default.html; root /www/api/public; ssl_certificate # pem文件的路径 ssl_certificate_key # key文件的路径 ssl_session_timeout 5m; #缓存有效期 ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; # 因为接口都是以 api.catchadmin.com/api 开头,所以可以很好的使用 location # 如果访问 api.catchadmin.com/api 目录 则用 php 解释下 location /api { if (!-e $request_filename) { rewrite ^(.*)$ /index.php?s=/$1 last; break; } } # 如果访问根目录 api.catchadmin.com/, 则直接访问前端项目 location / { root /www/api/public/admin; try_files $uri $uri/ /index.html; } # 上传的静态目录 location location /uploads/ { alias /www/api/storage/uploads/; autoindex on; } #PHP 支持 location ~ \.php$ { try_files $uri /index.php =404; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } } ``` 如果使用宝塔部署,`location` 配置静态目录的可能会无法工作,这是由于宝塔的预配置导致的,目前我个人使用下面如图得方法解决了 ![宝塔单域名部署](https://image.catchadmin.com/202411280949472.png) ### Octane 高性能部署 对于需要高性能的 CatchAdmin 项目,可以使用 Laravel Octane 提升并发处理能力: **Octane 优势**: * 显著提升 API 响应速度 * 更好的内存利用率 * 支持 WebSocket 等高级特性 **适用场景**:高并发访问、实时数据处理、大量 API 调用的企业级应用 ```php map $http_upgrade $connection_upgrade { default upgrade; '' close; } server { listen 80; server_name api.catchadmin.com; return 301 https://api.catchadmin.com$request_uri; } server { listen 443 ssl http2; server_name api.catchadmin.com; index index.html index.php index.htm default.php default.htm default.html; root /www/api/public; ssl_certificate # pem文件的路径 ssl_certificate_key # key文件的路径 ssl_session_timeout 5m; #缓存有效期 ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; # 因为接口都是以 api.catchadmin.com/api 开头,所以可以很好的使用 location # 如果访问 api.catchadmin.com/api 目录 则用 php 解释下 location /api { if (!-e $request_filename) { rewrite ^(.*)$ /index.php?s=/$1 last; break; } } # 如果访问根目录 api.catchadmin.com/, 则直接访问前端项目 location / { root /www/api/public/admin; try_files $uri $uri/ /index.html; } # 上传的静态目录 location location /uploads/ { alias /www/api/public/storage/uploads/; autoindex on; } location @octane { set $suffix ""; if ($uri = /index.php) { set $suffix ?$query_string; } proxy_http_version 1.1; proxy_set_header Host $http_host; proxy_set_header Scheme $scheme; proxy_set_header SERVER_PORT $server_port; proxy_set_header REMOTE_ADDR $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_pass http://172.18.0.2:9800$suffix; } } ``` --- --- url: /docs/3.0/start/thinkphp.md --- # ThinkPHP 版本安装 ## 环境要求 * PHP >= 8.0+ * Nginx * Mysql >= 5.7 ## 安装 ### 准备 在安装这个软件之前,您需要准备一些必要的工具,包括: * [git 代码管理](https://git-scm.com/downloads) * [composer PHP 包管理器](https://getcomposer.org/download/) * [nodejs >= 18.8.0](https://nodejs.org/zh-cn/) * [yarn 前端包管理器](https://yarn.bootcss.com/) * [vite](https://cn.vitejs.dev/) ### 下载项目 接下来,您需要下载 CatchAdmin 项目。您可以前往该项目的托管仓库 [CatchAdmin](https://gitee.com/catchamin/catchadmin-tp) 上的页面进行下载,也可以使用 `git` clone 命令将代码克隆到本地,这样就能及时获取代码更新。 ```sh git clone https://gitee.com/catchamin/catchadmin-tp.git ``` 请注意,该项目不提供 Web 安装方式,因此您需要使用命令行方式进行安装。在安装之前,请确保已经安装了 `composer` 包管理器。如果您使用的是 `Mac OS` 或者 `Linux`,可以在终端输入以下命令安装 `composer` ```shell // mac os brew install composer // linux sudo apt-get install composer ``` 如果您使用的是 `Windows` 系统,可以从 [composer](https://docs.phpcomposer.com/) 的官方网站下载 exe 安装文件进行安装。一旦您已经安装了 `composer`,接下来您可以进入 `CatchAdmin` 项目所在的目录,并运行以下命令进行安装: ```shell composer install ``` 这个命令会自动下载并安装`CatchAdmin`项目所需要的 PHP 包。 除了 PHP 包之外,该项目还需要一些前端包。您可以使用以下命令安装这些包: ```shell // 安装完 nodejs 之后,再安装 yarn npm install --global yarn ``` :::tip 一定要安装好 yarn 和 Git 工具 ::: ### 命令安装 :::tip 安装的时候输入 ::: ```shell // 安装后台, 按照提示输入对应信息即可 php think catch:install ``` 命令会自动安装前端项目,并且自动下载前端依赖。所以在这个命令执行完之后,可以直接使用下面的命令启动前端项目。在根目录下 ```sh cd web && yarn dev ``` :::warning 注意不能直接访问 PHP 项目,导致 Exception,前后端分离,需要通过 API 接口形式访问,所以你需要安装 VUE 项目后台,看到数据的展示 ::: :::tip 如果你是第一次使用 Vue,建议先去看看 [Vue](https://cn.vuejs.org/) 文档,了解一下 vue 后台使用了是 `element Plus` [文档地址](https://element-plus.org) ::: ## 代码生成 :::warning Laravel 和 tp 的代码生成功能是不一样的,默认项目使用 Laravel 的,如果需要开启 tp 的,则需要在前端项目的 `.env` 配置文件加上下面的配置 ::: ```javascript VITE_GENERATE = true ``` 因为是前后端分离,所以整个项目是分为两个项目存在的。 框架默认将前端项目安装在根目录的 `web` 目录,如果你要移动前端目录到其他目录,注意一定要设置下面的配置 * web\_path 前端项目录 * views\_path 前端项目 views 目录 找到 `config/catch.php` 配置文件,切换成实际的前端项目目录即可 ```php return [ // 前端项目目录 'web_path' => root_path('web'), // 前端视图目录 'views_path' => root_path('web').DIRECTORY_SEPARATOR.'src'.DIRECTORY_SEPARATOR.'views'.DIRECTORY_SEPARATOR, ]; ``` ### 打包前端项目 打包前请先配置正是环境 API 地址。在项目的根目录下的`.env.production`文件配置 ``` # base api VITE_BASE_URL = '正式环境的 API 地址' ``` 然后进行打包 ``` yarn run build ``` :::tip 前端项目配置最好开启 `Gzip`,可以加速前端项目访问速度。 ::: --- --- url: /docs/3.0/start/webman.md --- # Webman 版本安装 ## 环境要求 * PHP >= 8.0+ * Nginx * Mysql >= 5.7 ## 安装 ### 准备 在安装这个软件之前,您需要准备一些必要的工具,包括: * [git 代码管理](https://git-scm.com/downloads) * [composer PHP 包管理器](https://getcomposer.org/download/) * [nodejs >= 20.0](https://nodejs.org/zh-cn/) * [yarn 前端包管理器](https://yarn.bootcss.com/) * [vite](https://cn.vitejs.dev/) ### 下载项目 接下来,您需要下载 CatchAdmin 项目。您可以前往该项目的托管仓库 [CatchAdmin](https://gitee.com/catchamin/catchadmin-webman) 上的页面进行下载,也可以使用 `git` clone 命令将代码克隆到本地,这样就能及时获取代码更新。 ```sh git clone https://gitee.com/catchamin/catchadmin-webman.git ``` 请注意,该项目不提供 Web 安装方式,因此您需要使用命令行方式进行安装。在安装之前,请确保已经安装了 `composer` 包管理器。如果您使用的是 `Mac OS` 或者 `Linux`,可以在终端输入以下命令安装 `composer` ```shell // mac os brew install composer // linux sudo apt-get install composer ``` 如果您使用的是 `Windows` 系统,可以从 [composer](https://docs.phpcomposer.com/) 的官方网站下载 exe 安装文件进行安装。一旦您已经安装了 `composer`,接下来您可以进入 `CatchAdmin` 项目所在的目录,并运行以下命令进行安装: ```shell composer install ``` 这个命令会自动下载并安装`CatchAdmin`项目所需要的 PHP 包。 除了 PHP 包之外,该项目还需要一些前端包。您可以使用以下命令安装这些包: ```shell // 安装完 nodejs 之后,再安装 yarn npm install --global yarn ``` :::tip 一定要安装好 yarn 和 Git 工具 ::: ### 命令安装 ```shell // 安装后台, 按照提示输入对应信息即可 php webman catch:install ``` 命令会自动安装前端项目,并且自动下载前端依赖。所以在这个命令执行完之后,可以直接使用下面的命令启动前端项目。在根目录下 ```sh cd web && yarn dev ``` :::warning 注意不能直接访问 PHP 项目,导致 Exception,前后端分离,需要通过 API 接口形式访问,所以你需要安装 VUE 项目后台,看到数据的展示 ::: :::tip 如果你是第一次使用 Vue,建议先去看看 [Vue](https://cn.vuejs.org/) 文档,了解一下 vue 后台使用了是 `element Plus` [文档地址](https://element-plus.org) ::: ## 代码生成 :::warning Laravel 和 webman 的代码生成功能是不一样的,默认项目使用 Laravel 的,如果需要开启 webman 的,则需要在前端项目的 `.env` 配置文件加上下面的配置 ::: ```javascript VITE_GENERATE = true ``` 因为是前后端分离,所以整个项目是分为两个项目存在的。 框架默认将前端项目安装在根目录的 `web` 目录,如果你要移动前端目录到其他目录,注意一定要设置下面的配置 * web\_path 前端项目录 * views\_path 前端项目 views 目录 找到 `config/catch.php` 配置文件,切换成实际的前端项目目录即可 ```php return [ // 前端项目目录 'web_path' => root_path('web'), // 前端视图目录 'views_path' => root_path('web').DIRECTORY_SEPARATOR.'src'.DIRECTORY_SEPARATOR.'views'.DIRECTORY_SEPARATOR, ]; ``` ### 打包前端项目 打包前请先配置正是环境 API 地址。在项目的根目录下的`.env.production`文件配置 ``` # base api VITE_BASE_URL = '正式环境的 API 地址' ``` 然后进行打包 ``` yarn run build ``` :::tip 前端项目配置最好开启 `Gzip`,可以加速前端项目访问速度。 ::: --- --- url: /docs/3.0/server/config.md --- # CatchAdmin 配置详解 > 系统配置和模块配置的使用指南 CatchAdmin 提供了灵活的配置机制,支持系统级和模块级的配置管理。首先了解系统的核心配置文件: ```php title="config/catch.php" return [ /* |-------------------------------------------------------------------------- | catch-admin super admin id |-------------------------------------------------------------------------- | | where you can set super admin id | */ 'super_admin' => 1, /* |-------------------------------------------------------------------------- | catch-admin module setting |-------------------------------------------------------------------------- | | the root where module generate | the namespace is module root namespace | the default dirs is module generate default dirs */ 'module' => [ 'root' => 'modules', 'namespace' => 'Modules', 'default' => ['develop', 'user', 'permission'], 'default_dirs' => [ 'Http'.DIRECTORY_SEPARATOR, 'Http'.DIRECTORY_SEPARATOR.'Requests'.DIRECTORY_SEPARATOR, 'Http'.DIRECTORY_SEPARATOR.'Controllers'.DIRECTORY_SEPARATOR, 'Models'.DIRECTORY_SEPARATOR, 'views'.DIRECTORY_SEPARATOR, ], // storage module information // which driver should be used? 'driver' => [ // currently, catchadmin support file and database // the default is driver 'default' => 'file', // use database driver 'table_name' => 'admin_modules' ], /** * module routes collection * */ 'routes' => [], ], /* |-------------------------------------------------------------------------- | catch-admin response |-------------------------------------------------------------------------- */ 'response' => [ // it's a controller middleware, it's set in CatchController // if you not need json response, don't extend CatchController 'always_json' => \Catch\Middleware\JsonResponseMiddleware::class, // response listener // it listens [RequestHandled] event, if you don't need this // you can change this config 'request_handled_listener' => \Catch\Listeners\RequestHandledListener::class ], /* |-------------------------------------------------------------------------- | catch-admin auth setting |-------------------------------------------------------------------------- */ 'auth' => [ 'guards' => [ 'admin' => [ 'driver' => 'jwt', 'provider' => 'admin_users', ], ], 'providers' => [ 'admin_users' => [ 'driver' => 'eloquent', 'model' => \Modules\User\Models\User::class ] ] ], /* |-------------------------------------------------------------------------- | database sql log |-------------------------------------------------------------------------- */ 'listen_db_log' => true, /* |-------------------------------------------------------------------------- | route config |-------------------------------------------------------------------------- */ 'route' => [ 'prefix' => 'api', 'middlewares' => [ \Catch\Middleware\AuthMiddleware::class, \Catch\Middleware\JsonResponseMiddleware::class ] ], ]; ``` ## 配置项详解 ### 超级管理员配置 * `super_admin`:设置超级管理员的用户 ID,默认为 1。超级管理员不受任何权限限制 ### 模块系统配置 * `module` 模块相关的核心配置 * `root`:模块存放的根目录,默认为 `modules` * `namespace`:模块的根命名空间,默认为 `Modules` * `default`:系统默认模块列表,包含 `develop`、`user`、`common` 三个基础模块 * `default_dirs`:新建模块时自动生成的默认目录结构 * `driver`:模块信息存储驱动,支持 `file` 和 `database` 两种方式 * `routes`:模块路由集合配置 ### 响应机制配置 * `response` API 响应相关配置 * `always_json`:强制 JSON 响应输出的中间件 * `request_handled_listener`:请求处理监听器,用于统一响应格式 ### 认证系统配置 * `auth` 认证相关配置 * `guards`:认证守卫配置,定义了 `admin` 守卫使用 JWT 驱动 * `providers`:用户提供者配置,指定用户模型 ### 开发调试配置 * `listen_db_log`:是否开启数据库 SQL 查询日志监听,便于开发调试 ### 路由系统配置 * `route` 全局路由配置 * `prefix`:API 路由前缀,默认为 `api` * `middlewares`:默认应用的中间件列表 :::tip 配置建议 项目有定制化需求时,优先检查这些配置选项,大多数需求可以通过配置调整来满足,无需修改源码。 ::: ## 模块配置 除了系统级配置,CatchAdmin 还支持模块级的独立配置。每个模块的配置相互独立,互不影响,提高了模块的可移植性。 ### 默认配置方式 模块需要配置时,直接在模块目录下创建 `config` 目录,系统会自动发现并加载配置文件: ``` modules/YourModule/ ├── config/ │ ├── database.php │ └── services.php └── ... ``` ### 自定义配置路径 如果需要自定义配置文件位置,可以在模块的服务提供者中重写 `configPath` 方法: ```php title="modules/Test/Providers/TestServiceProvider" namespace Modules\Test\Providers; use Catch\CatchAdmin; use Catch\Providers\CatchModuleServiceProvider; class TestServiceProvider extends CatchModuleServiceProvider { public function confitPath(): string { return config_path; } } ``` ### 配置文件结构 以权限模块为例,典型的模块配置结构如下: ``` Permissions/ └── config/ ├── database.php └── permissions.php ``` ### 配置读取方式 模块配置的读取需要包含模块名称作为前缀: ```php // 错误方式:直接读取配置文件名 config('database') // ❌ 会读取系统的数据库配置 // 正确方式:模块名.配置文件名.配置键 config('permissions.database.connection') // ✅ 读取权限模块的数据库配置 config('permissions.permissions.default_role') // ✅ 读取权限模块的权限配置 ``` ### 配置命名规范 * **模块名**:使用小写,与模块目录名一致 * **配置文件名**:使用小写,语义明确 * **配置键名**:使用下划线命名法 这种设计避免了模块间配置冲突,同时保持了良好的命名空间隔离。 --- --- url: /docs/3.0/server/promise.md --- # CatchAdmin 开发约定 > 约定大于配置 - CatchAdmin 开发规范和最佳实践指南 **约定大于配置**是现代框架设计的核心理念。通过统一的约定,开发者能够快速理解项目结构,减少配置复杂度,提升开发效率。CatchAdmin 遵循这一理念,制定了一套简洁而实用的开发约定。 掌握这些约定将帮助你: * **快速上手**:无需大量配置即可开始开发 * **团队协作**:统一的代码组织方式便于团队协作 * **维护便捷**:标准化的结构降低维护成本 * **扩展灵活**:约定化的架构支持功能快速扩展 ## 📁 目录结构约定 ### 后端模块位置 **约定**:所有后台业务功能模块统一放置在 `modules` 目录下 ``` project/ ├── modules/ │ ├── User/ # 用户管理模块 │ ├── Permissions/ # 权限管理模块 │ └── YourModule/ # 自定义模块 ``` **设计理念**: * 模块化开发,业务逻辑清晰分离 * 便于模块的独立开发、测试和维护 * 支持模块间的松耦合设计 ### 前端页面位置 **约定**:模块对应的前端页面放置在 `web/src/views` 目录下 ``` web/src/views/ ├── user/ # 用户模块页面 ├── permissions/ # 权限模块页面 └── your-module/ # 自定义模块页面 ``` **最佳实践**: * 前端目录名与后端模块名保持一致(小写) * 页面组件按功能分组,保持结构清晰 * 遵循 Vue 3 单文件组件规范 ## 🏷️ 枚举类型约定 ### 枚举接口实现 **约定**:所有枚举类型必须实现 `Catch\Enums\Enum` 接口 ```php '正常', self::INACTIVE => '禁用', self::BANNED => '封禁', }; } } ``` :::info PHP 版本支持 CatchAdmin 要求 PHP 8.1+,因此可以充分利用 PHP 8.1 新增的枚举类型(enum)特性,提供类型安全和更好的代码提示。 ::: ### 枚举值约定 **约定**:整型枚举值从 `1` 开始 ```php enum OrderStatus: int implements Enum { case PENDING = 1; // ✅ 从 1 开始 case CONFIRMED = 2; case SHIPPED = 3; case DELIVERED = 4; } ``` :::info 为什么从 1 开始? 这个约定有重要的技术原因: 1. **弱类型问题**:PHP 中 `0`、`null`、`""` 在弱类型比较时相等 2. **查询逻辑**:枚举常用于数据库查询条件,从 1 开始避免了 `WHERE status = 0` 的歧义 3. **前端处理**:JavaScript 中也存在类似的类型转换问题 4. **API 设计**:RESTful API 中,0 值容易与空值混淆 **示例对比**: ```php // 不推荐:从 0 开始可能导致逻辑错误 if ($status) { /* 当 status = 0 时,此条件为 false */ } // 推荐:从 1 开始,逻辑清晰 if ($status) { /* 所有有效状态都会执行 */ } ``` ::: ## 🔧 公共功能约定 ### Common 模块设计 **约定**:通用功能统一放置在内置的 `Common` 模块中 **包含功能**: * **文件上传**:统一的文件上传接口和处理逻辑 * **枚举接口**:为前端提供枚举值集合的 API 接口 * **通用工具**:跨模块使用的工具类和辅助方法 * **系统配置**:全局配置项的管理和读取 **设计优势**: ```php // Common 模块提供统一的上传服务 Route::post('/upload', [UploadController::class, 'handle']); // 统一的枚举接口 Route::get('/enums/{enum}', [EnumController::class, 'get']); ``` 这种设计避免了: * 重复的上传逻辑在各模块中实现 * 枚举接口的分散管理 * 公共代码的冗余和不一致 ## 🛣️ 路由管理约定 ### 静态路由配置 **约定**:不使用动态菜单时,前端路由文件命名为 `route.js` 并放置在模块 `views` 目录下 ``` web/src/views/user/ ├── components/ # 组件目录 ├── pages/ # 页面目录 │ ├── index.vue │ └── detail.vue └── route.js # 路由配置文件 ``` **路由文件示例**: ```javascript // web/src/views/user/route.js export default { path: '/user', name: 'User', component: () => import('./pages/index.vue'), meta: { title: '用户管理', requiresAuth: true }, children: [ { path: 'detail/:id', name: 'UserDetail', component: () => import('./pages/detail.vue') } ] } ``` **适用场景**: * 模块路由相对固定,不需要动态配置 * 追求更好的类型提示和开发体验 * 需要精确控制路由的加载时机 :::info 参考示例 可以参考以下模块的实现: * `develop` 模块:开发工具相关路由 * `user` 模块:用户管理路由配置 * 这些模块展示了静态路由的标准实现方式 ::: ## 💡 约定的价值 遵循 CatchAdmin 的开发约定能够: 1. **提升开发效率**:标准化的结构减少决策时间 2. **降低学习成本**:统一的模式便于新人快速上手 3. **保证代码质量**:约定化避免了常见的设计陷阱 4. **促进团队协作**:一致的代码风格提升协作效率 5. **便于项目维护**:清晰的结构降低维护复杂度 记住:约定不是限制,而是为了让开发变得更加简单和高效! --- --- url: /docs/3.0/server/modules.md --- # CatchAdmin 模块化开发 > CatchAdmin 模块化架构详解,让业务功能开发更高效、更灵活 在使用 CatchAdmin 进行项目开发前,首先需要了解系统最核心的设计理念——`模块化架构`。CatchAdmin 将所有业务功能都拆分为独立的功能模块,每个模块具有完整的 MVC 结构,支持独立开发、测试和部署。这种设计让开发者能够: * **高效协作**:不同开发者可以并行开发不同模块 * **代码复用**:开发完成的模块可以在项目间共享 * **维护便捷**:模块间解耦,降低维护成本 * **扩展灵活**:根据业务需求随时添加或移除模块 :::info 重要提醒 CatchAdmin 的模块信息统一存储在 `storage/app/modules.json` 配置文件中。如果遇到以下问题,请首先检查此文件: * 模块路由无法访问 * 模块功能突然失效 * 模块在管理界面中消失 该文件是模块系统的核心配置,务必妥善备份和维护。 ::: ### CatchAdmin 模块工作原理 CatchAdmin 采用类似 Laravel Package 的模块管理机制。所有模块都存放在项目的 **modules** 目录下,每个模块都是一个独立的功能单元。 **模块安装**:通过 Artisan 命令快速安装模块 ```shell php artisan catch:module:install ``` **安装流程**: 1. 命令执行后在 `storage/app` 目录生成 `modules.json` 配置文件 2. 系统自动注册模块的服务提供者、路由和其他资源 3. 模块立即可用,无需重启应用 CatchAdmin 的模块系统借鉴了 Laravel 社区的成熟设计理念,从 2.x 到 3.x 版本保持了良好的兼容性,让有经验的开发者能够快速上手。 ![模块架构图](https://z3.ax1x.com/2021/04/26/gSrLz6.png) ### 实战:开发新模块 以下通过创建一个实际模块来演示 CatchAdmin 模块开发的完整流程。 **第一步:创建模块** CatchAdmin 提供了可视化的模块创建界面,让模块初始化变得简单直观: ![pSlN1y9.md.png](https://s1.ax1x.com/2023/01/16/pSlN1y9.md.png) 1. 进入 CatchAdmin 后台管理界面 2. 导航到"开发工具" → "模块管理" 3. 点击"新建模块",填写模块基本信息: * 模块名称(如:test) * 模块描述 * 模块关键词 * 开发者信息 4. 点击"创建"按钮 系统将自动生成完整的模块文件结构,以 **test** 模块为例: ![pSlN2Y8.md.png](https://s1.ax1x.com/2023/01/16/pSlN2Y8.md.png) ![pSlNv6J.png](https://s1.ax1x.com/2023/01/16/pSlNv6J.png) **生成的模块结构分析**: ``` modules/Test/ ├── Http/ # 控制器层:处理 HTTP 请求和响应 ├── Models/ # 数据模型层:数据库交互和业务逻辑 ├── database/ # 数据库相关 │ ├── migrations/ # 数据库迁移文件 │ └── seeds/ # 数据填充文件 ├── Providers/ # 服务提供者:模块的核心注册点 └── route.php # 路由定义文件 ``` **核心组件说明**: * **Http 目录**:存放控制器和中间件,处理业务逻辑 * **Models 目录**:数据模型,定义数据结构和关系 * **database 目录**:数据库相关文件,支持版本控制 * **Providers 目录**:服务提供者,类似 Laravel Package 的核心机制 * **route.php**:模块路由定义,支持 RESTful API 设计 **深入理解服务提供者(Provider)** 服务提供者是 CatchAdmin 模块的核心,负责模块的初始化和资源注册: ```php namespace Modules\Test\Providers; use Catch\CatchAdmin; use Catch\Providers\CatchModuleServiceProvider; class TestServiceProvider extends CatchModuleServiceProvider { public function moduleName(): string|array { return 'common'; } } ``` **Provider 功能特性**: CatchAdmin 的服务提供者继承自 `CatchModuleServiceProvider`,默认自动加载模块路由。同时提供以下扩展功能: **1. 事件系统集成** CatchAdmin 支持模块级别的事件监听,与 Laravel 事件系统完全兼容。通过 `$events` 数组注册模块专属事件: ```php class TestServiceProvider extends CatchModuleServiceProvider { protected $events = []; } ``` **2. 中间件支持** 模块可以注册中间件,用于权限验证、数据过滤等场景。实现 `middlewares` 方法即可: ```php class TestServiceProvider extends CatchModuleServiceProvider { protected function middlewares(): array { return []; } } ``` :::warning 中间件注意事项 通过 Provider 注册的中间件会作用于整个应用,而非仅当前模块。因此在注册全局中间件时需要谨慎考虑其影响范围,避免对其他模块造成不必要的限制。 **建议**:优先在路由级别使用中间件,只在确实需要全局作用时才在 Provider 中注册。 ::: ### 模块分发与安装器 :::info 模块共享 如果开发的模块仅供当前项目使用,可以跳过此部分。 以下内容适用于希望将模块贡献给 CatchAdmin 社区或在多个项目间复用的场景。 ::: **为什么需要安装器?** CatchAdmin 的模块安装器(Installer)是实现模块标准化分发的关键组件。它解决了以下问题: * 模块依赖管理(Composer 包) * 数据库结构同步(migrations) * 配置文件处理 * 权限菜单导入 **安装器实现** 安装器通常放置在模块根目录下,以权限模块为例: ```php namespace Modules\Permissions; use Catch\Support\Module\Installer as ModuleInstaller; class Installer extends ModuleInstaller { protected function info(): array { // TODO: Implement info() method. return [ 'title' => '权限管理', 'name' => 'permissions', 'path' => 'permissions', 'keywords' => '权限, 角色, 部门', 'description' => '权限管理模块', 'provider' => PermissionsServiceProvider::class ]; } protected function requirePackages(): void { // TODO: Implement requirePackages() method. } protected function removePackages(): void { // TODO: Implement removePackages() method. } } ``` **安装器核心方法说明**: 1. **info() 方法**:定义模块基本信息,包括名称、描述、关键词等 2. **requirePackages() 方法**:处理模块依赖的 Composer 包 3. **removePackages() 方法**:卸载时清理相关依赖 **依赖包管理示例**: ```php protected function requirePackages(): void { // TODO: Implement requirePackages() method. $this->composer()->require('package/name') } ``` **权限菜单导出** 对于包含后台管理功能的模块,CatchAdmin 提供了菜单导出命令,自动生成权限相关的 seed 文件: ```shell php artisan catch:export:menu ``` * table 可选参数,默认是 `permissions` 表 **使用场景**: * 模块包含后台管理界面 * 需要自定义权限控制 * 计划分发给其他开发者使用 **示例**:导出权限模块的完整菜单结构 ```php php artisan catch:export:menu permissions ``` **模块分发流程总结**: 1. ✅ 完善模块功能开发 2. ✅ 创建标准化安装器 3. ✅ 导出权限菜单(如需要) 4. ✅ 编写模块使用文档 5. ✅ 测试安装和卸载流程 完成以上步骤后,你的模块就可以与 CatchAdmin 社区分享了!👏 **社区贡献**:欢迎开发者将优质模块贡献给社区,共同构建更强大的 CatchAdmin 生态系统。 --- --- url: /docs/3.0/server/model.md --- # CatchAdmin 模型 > 基于 Laravel Eloquent 的增强模型基类和实用方法 在后台管理系统中,绝大多数业务逻辑都围绕数据模型展开。CatchAdmin 在 Laravel Eloquent 基础上进行了深度封装,提供了更适合后台开发的模型基类 `CatchModel`。 所有 CatchAdmin 的业务模型都继承自 `CatchModel`,这个基类集成了常用的后台操作方法,可以显著提升开发效率。 :::info 重要提醒 建议仔细阅读本文档,掌握 CatchModel 的特性将让你的开发效率倍增! ::: ## CatchModel 基类 CatchModel 是 CatchAdmin 所有业务模型的基类,通过多个 Trait 扩展了 Laravel Eloquent 的功能: ```php abstract class CatchModel extends Model { use BaseOperate, Trans, SoftDeletes, ScopeTrait; /** * unix timestamp * * @var string */ protected $dateFormat = 'U'; /** * paginate limit */ protected $perPage = 10; /** * @var string[] */ protected array $defaultCasts = [ 'created_at' => 'datetime:Y-m-d H:i:s', 'updated_at' => 'datetime:Y-m-d H:i:s', ]; protected array $defaultHidden = ['deleted_at']; public function __construct(array $attributes = []) { parent::__construct($attributes); $this->init(); } /** * init */ protected function init() { $this->makeHidden($this->defaultHidden); $this->mergeCasts($this->defaultCasts); } // 修改软删除的查询条件 public static function bootSoftDeletes(): void { static::addGlobalScope(new SoftDelete()); } } ``` ### 时间戳处理 CatchAdmin 所有数据表的 `created_at` 和 `updated_at` 字段都采用 Unix 时间戳(int 类型)存储。为了向前端返回可读的日期格式,CatchModel 通过 `defaultCasts` 属性进行自动转换: ```php protected array $defaultCasts = [ 'created_at' => 'datetime:Y-m-d H:i:s', 'updated_at' => 'datetime:Y-m-d H:i:s', ]; ``` > 这里有人肯定会有疑问?为什么要非要加一个 `defaultCasts` 属性呢?为什么不直接用 `casts`? :::tip 设计考虑 使用 `defaultCasts` 而非 `casts` 属性的原因: 1. **避免覆盖冲突**:所有模型都继承自 CatchModel,使用 `casts` 可能被子类覆盖 2. **通用性保证**:日期转换几乎每个模型都需要,独立属性确保功能稳定 3. **一致性维护**:`defaultHidden` 属性也遵循同样的设计理念 ::: ## 软删除 ### 软删除机制 CatchAdmin 的软删除设计与 Laravel 默认实现不同:软删除字段 `deleted_at` 的默认值是 **0**(而非 null)。因此需要自定义软删除的查询条件: ```php class SoftDelete extends SoftDeletingScope { public function apply(Builder $builder, Model $model) { $builder->where($model->getQualifiedDeletedAtColumn(), '=', 0); } } ``` ## 取消软删 ### 取消软删除 某些业务场景不需要软删除功能,比如操作日志等记录型数据。此时可以继承 Laravel 原生的 `Model` 类,同时引入 CatchAdmin 的功能 Trait: ```php namespace Modules\User\Models; use Catch\CatchAdmin; // 添加以下三个 trait 操作 use Catch\Traits\DB\BaseOperate; // 基本操作 use Catch\Traits\DB\ScopeTrait; // scope trait use Catch\Traits\DB\Trans; // 事务操作 use Illuminate\Database\Eloquent\Model; class LogOperate extends Model { use BaseOperate, Trans, ScopeTrait; } ``` ## 属性 ### 扩展属性 CatchModel 新增了多个实用属性,简化常见的后台开发需求: ```php // 树状结构的父级字段,建议使用默认值 // CatchAdmin 的树组件统一使用此字段 protected string $parentIdColumn = 'parent_id'; // 排序字段,默认使用 sort protected string $sortField = 'sort'; // 排序规则 protected bool $sortDesc = true; // 列表的数据返回是否以树状结构返回 protected bool $asTree = false; // 列表查询的默认字段 protected array $fields = []; // 列表是否是分页 // 默认分页 protected bool $isPaginate = true; // 创建和更新数据提交的字段 // form 字段 protected array $form = []; // 表单关联关系配置 // 示例:用户与角色的多对多关系 // 在 User 模型中设置:['roles'] // 对应模型中的 roles() 关联方法 protected array $formRelations = []; ``` ## 模型方法 CatchModel 提供了丰富的便捷方法,覆盖后台开发的常见场景。 ## 列表查询 ```php public function getList(): miexed ``` ### 支持自定义查询 `getList()` 方法默认针对单表查询。如需复杂查询(如 join、with 关联等),可以使用查询钩子进行自定义: ```php // 示例:添加排序条件 $model->setBeforeGetList(function ($query) { return $query->orderByDesc('sort'); })->getList(); ``` ```php // 示例:联表查询 $model->setBeforeGetList(function ($query) { return $query->join('some_table', 'condition'); })->getList(); ``` ```php // 示例:预加载关联关系 $model->setBeforeGetList(function ($query) { return $query->with('someRelations'); })->getList(); ``` ## 数据保存 ### 单条保存 ```php public function storeBy(array $data): bool ``` 用于保存单条记录,支持表单关联关系自动处理。 ### 批量保存 ```php public function createBy(array $data): mixed ``` 支持批量插入数据,适用于导入、初始化等场景。 :::info 方法区别 * `storeBy`:适合表单提交的单条数据保存 * `createBy`:适合批量数据插入,性能更好 ::: ## 更新数据 ```php public function updateBy($id, array $data): mixed ``` ## 查询数据 ```php public function firstBy($value, $field = null, array $columns = ['*']): ?Model ``` `$field` 参数默认为 `id`,支持按任意字段查询。 ## 删除数据 ```php public function deleteBy($id, bool $force = false): ?bool ``` 默认按 `id` 进行软删除,`$force` 参数为 `true` 时执行物理删除。 ## 状态切换 ```php public function toggleBy($id, string $field = 'status'): bool ``` 常用于启用/禁用功能,通过 ID 切换指定字段的状态(0/1)。 ## 处理树状数据的下级数据 ```php public function updateChildren(mixed $parentId, string $field, mixed $value): void ``` ## 字段别名 ```php public function aliasField(string|array $fields): string|array ``` ## 设置 ceator\_id ```php public function setCreatorId() ``` ## 创建人字段 CatchAdmin 默认自动填充创建人字段 `creator_id`。如需取消此功能: ```php $model->fillCreatorId(false)->storeBy($data); ``` ## 获取创建人 ```php public function scopeCreator(); ``` 这是一个查询作用域,可以链式调用: ```php Model::select('*')->creator()->get(); ``` **注意**:使用前请确保数据表包含 `creator_id` 字段。 ## 模糊查询 ```php public function whereLike($field, $value) ``` ## 快速查询 ```php public function quickSearch(array $params = []) ``` 通过配置模型的 `searchable` 属性,自动根据请求参数生成查询条件: ```php protected array $searchable = [ 'status' => '=', 'nickname' => 'like' ] ``` 配置后,系统会自动生成相应的查询条件,实现动态搜索: ```php Model::select('*') ->where('status', $request->get('status')) ->whereLike('nickname', $request->get('nickname')) ->get(); ``` ## 事务操作 CatchModel 集成了事务操作,无需再引入 DB 门面: ```php // 传统方式 DB::beginTransaction(); // CatchModel 方式 $this->beginTransaction(); ``` 支持所有 Laravel 事务方法:`beginTransaction()`、`commit()`、`rollback()`。 --- --- url: /docs/3.0/server/permission.md --- # CatchAdmin 权限管理 > 基于 RBAC 模型的权限系统介绍 CatchAdmin 采用业界成熟的 `RBAC`(基于角色的访问控制)权限模型,即用户一对多角色,角色一对多权限的设计。这种模式通过角色作为中间层,实现了灵活的权限分配和管理。 如果对 `RBAC` 权限模型需要深入了解,建议参考 [Oracle 官方文档:基于角色的访问控制](https://docs.oracle.com/cd/E19253-01/819-7061/rbac-38/index.html)。 ## 基本约定 * **超级管理员免检**:超级管理员不受任何权限控制,拥有系统全部操作权限 * **GET 请求放行**:所有 `GET` 请求默认放行,不受权限限制(查询操作通常不涉及数据变更) ## 权限约定 ## 权限模块 CatchAdmin 为保持系统轻量化,默认不开启权限模块和动态菜单功能。如果项目需要权限控制,第一步需要安装权限模块: ```php php artisan catch:module:install permissions ``` :::info 开启之后如果没有权限菜单,可以刷新一下 ::: ### 中间件 权限模块提供了权限控制的中间件,实现自动的权限验证: ```php title="modules/Permissions/Middlewares/PermissionGate.php" class PermissionGate { public function handle(Request $request, \Closure $next) { // GET 请求全部通过(遵循基本约定) if ($request->isMethod('get')) { return $next($request); } /* @var User $user */ $user = $request->user(getGuardName()); // 权限验证失败则拦截请求 if (! $user->can()) { throw new PermissionForbidden(); } return $next($request); } } ``` ### 添加权限 权限配置是系统的核心功能。由于 CatchAdmin 采用前后端分离架构,权限配置相比传统项目略为复杂,需要同时考虑前端路由和后端 API 的权限控制。 建议先熟悉 [Vue Router](https://router.vuejs.org/) 的基本概念。配置入口:**权限管理/菜单管理** → **新增**: ![pSl4dVP.png](https://s1.ax1x.com/2023/01/16/pSl4dVP.png) CatchAdmin 将权限分为三种层级类型: * **目录**:构建导航结构的一级菜单容器,用于功能分组 * **菜单**:对应具体的功能页面,关联前端路由组件 * **按钮**:页面内的具体操作功能,每个按钮对应后端控制器的一个 `action` 方法(这是后端权限控制的关键) * 路由 `Path` 对应前端 `vue` 路由的 `path` * 组件 对应前端 `vue` 路由的 `component` * 目录类型一般都是选择 Layout 组件 * 菜单类型则是选择对应页面的组件 **前后端分离的权限控制特点**: 传统 Laravel 项目中,页面和数据都由 PHP 控制。CatchAdmin 采用前后端分离后: * **前端负责**:页面渲染、菜单显示、路由跳转 * **后端负责**:API 接口访问控制、数据操作权限 因此,CatchAdmin 的 RBAC 权限重点在于**控制 API 访问**。后端需要为每个控制器的 `action` 方法配置对应的权限,确保数据操作的安全性。 ### 权限判断 基于 CatchAdmin 的模块化架构,权限标识采用统一格式: ``` module@controller@action // 模块名称@控制器名称@控制器方法名称 ``` **示例说明**:权限模块的角色列表功能,位于权限模块(Permissions)的角色控制器(RolesController)的 `index` 方法,其权限标识为: ```php Modules\Permissions\Http\Controller\RolesController@index ``` **权限验证失败排查**:当遇到权限认证失败时,通常是权限配置问题。请检查数据库 `permissions` 表中的配置: ![catchadmin 权限-laravel admin](https://image.catchadmin.com/202405220926755.png) 确认 `module` 和 `permission_mark` 字段是否符合 `module@controller@action` 的格式规则。 #### 当前用户是否有权限 ```php Auth::user()->can(string $permission = null); ``` * `$permission` 参数:权限标识,格式为 `module@controller@action`,例如 `Permissions@Roles@index` #### 用户的权限 ```php /*@var Model\Roles $user*/ $user->withPermissions()->permissions; ``` #### 角色权限 ```php /*@var Model\Roles $role*/ $role->getPermissions() ``` ## 取消权限中间件验证 下面是示例代码,使用`withoutMiddleware(\Modules\Permissions\Middlewares\PermissionGate::class)` ```php Route::withoutMiddleware(\Modules\Permissions\Middlewares\PermissionGate::class) ->group(function(){ Route::prefix('official')->group(function (){ Route::get('sign', [OfficialAccountController::class, 'sign']); }); //next }); ``` --- --- url: /docs/3.0/server/data_permission.md --- # CatchAdmin 数据权限 > 基于角色的细粒度数据访问控制系统 ## 数据权限介绍 数据权限是企业级权限管理的重要组成部分,用于控制用户只能访问和操作特定范围内的数据。由于并非所有项目都需要这种细粒度的数据控制,CatchAdmin 默认不启用数据权限功能。 **应用场景**: * **企业多部门**:不同部门只能访问自己部门的数据 * **层级管理**:上级可以查看下级的数据,但下级不能查看上级数据 * **个人数据隔离**:用户只能查看自己创建的数据 CatchAdmin 的数据权限与角色系统紧密集成,通过角色配置实现灵活的数据访问控制: ![pSlzXdO.png](https://s1.ax1x.com/2023/01/16/pSlzXdO.png) ## 数据权限类型 CatchAdmin 提供五种数据权限级别,覆盖不同的业务需求: ### 1. 全部数据权限 * **权限范围**:可以访问系统中的所有数据 * **适用角色**:系统管理员、超级用户 * **使用场景**:数据统计分析、系统维护 ### 2. 自定义数据权限 * **权限范围**:可以自定义指定特定的数据范围 * **适用角色**:特殊权限的管理角色 * **使用场景**:跨部门项目负责人、特定业务管理员 ### 3. 部门数据权限 * **权限范围**:只能访问本部门的数据 * **适用角色**:部门普通成员 * **使用场景**:销售部门只看销售数据、技术部门只看技术数据 ### 4. 部门及以下数据权限 * **权限范围**:可以访问本部门及其下级部门的数据 * **适用角色**:部门主管、中层管理者 * **使用场景**:部门经理管理整个部门体系的数据 ### 5. 仅本人数据权限 * **权限范围**:只能访问自己创建的数据 * **适用角色**:普通员工、实习生 * **使用场景**:个人工作记录、私人数据管理 ## 使用约定 ### 数据表要求 要使用数据权限功能,数据表必须满足以下结构要求: 1. **creator\_id 字段**:必需字段,用于标识数据的创建者 ```sql `creator_id` int(11) NOT NULL DEFAULT 0 COMMENT '创建者ID' ``` 2. **部门关联**:如果使用部门相关权限,用户表需要包含部门信息 ```sql `dept_id` int(11) NOT NULL DEFAULT 0 COMMENT '所属部门ID' ``` ### 字段说明 * **creator\_id**:CatchAdmin 统一使用此字段标识数据归属 * **自动填充**:CatchModel 会自动填充 creator\_id 字段 * **权限过滤**:系统根据此字段进行数据权限过滤 ## 配置步骤 ### 前置条件 使用数据权限前,请确保满足以下条件: 1. **权限模块已启用**:数据权限依赖权限管理模块 2. **角色数据权限配置**:为角色设置合适的数据权限范围 3. **用户部门设置**:使用部门权限时,用户必须设置所属部门 4. **数据表结构**:确保相关表包含 `creator_id` 字段 ### 配置流程 1. **角色配置**:在角色管理中设置数据权限类型 2. **用户分配**:为用户分配对应的角色 3. **部门设置**:为用户设置所属部门(如需要) 4. **模型配置**:在相关模型中启用数据权限 ## 代码实现 ### 模型中启用数据权限 在需要数据权限控制的模型中引入 `DataRange` trait: ```php title="modules/Permissions/Models/Traits/DataRange.php" use Modules\Permissions\Models\Traits\DataRange; class UserModel extends CatchModel { use DataRange; // 其他模型代码... } ``` ### 自动权限过滤 引入 `DataRange` trait 后,模型的列表查询会自动应用数据权限过滤: ```php // 自动应用当前用户的数据权限 $users = UserModel::getList(); ``` ### 手动权限查询 如需在特定查询中单独使用数据权限,可以使用 `dataRange` 作用域: ```php // 手动应用数据权限 $filteredData = UserModel::select('*') ->dataRange() ->where('status', 1) ->get(); ``` ### 权限检查方法 ```php // 检查当前用户对特定数据的访问权限 if ($model->hasDataPermission($dataId)) { // 有权限访问 return $model->find($dataId); } else { // 无权限访问 throw new PermissionDenied('无权限访问此数据'); } ``` ## 使用注意事项 1. **性能考虑**:数据权限会在查询中添加额外的 WHERE 条件,大数据量时建议添加相关索引 2. **权限调试**:开发时可通过日志查看生成的 SQL 语句,确认权限过滤是否正确 3. **角色变更**:用户角色变更后,数据权限会立即生效,无需重新登录 4. **数据一致性**:确保所有相关表都正确设置了 `creator_id` 字段 --- --- url: /docs/3.0/server/generate.md --- # CatchAdmin 代码生成器 > 智能化 CRUD 代码生成,提升开发效率的利器 :::warning 该文档是 Laravel 版本的代码生成。因为其他两个版本没有模块的概念,直接使用即可 ::: 在现代后台管理系统开发中,**代码生成器** 已成为提升开发效率的必备工具。CatchAdmin 的代码生成器主要用于自动创建标准的 CRUD(增删改查)功能,大幅减少重复性开发工作。 **代码生成的价值**: * **效率提升**:自动生成完整的增删改查功能,节省 80% 的基础开发时间 * **标准化**:确保代码风格和结构的一致性 * **减少错误**:避免手工编写重复代码时的常见错误 **重要提醒**:由于 CatchAdmin 采用前后端分离架构,代码生成后需要额外配置菜单才能在前端看到页面。具体分为两种情况: * **动态菜单模式**:如果开启了权限管理模块,需要在权限管理中添加相应的菜单配置 * **静态路由模式**:如果未使用权限管理,需要手动添加前端路由配置 :::info 视频教程地址[catchadmin 之快速开发,时间久远,以文档为主](https://www.bilibili.com/video/BV1Qh4y1J7eB/) ::: ## 使用指南 CatchAdmin 的代码生成基于模块化架构,遵循"模块 → Schema → 代码生成"的标准流程。 ### 第一步:创建模块 基于 CatchAdmin 的模块化设计,首先需要创建业务模块: ![pS1rbgP.png](https://s1.ax1x.com/2023/01/17/pS1rbgP.png) **操作步骤**: 1. 进入"开发工具" → "模块管理" 2. 点击"新增"按钮 3. 填写模块基本信息(名称、描述、关键词等) 4. 点击"创建模块"完成模块初始化 ### 第二步:创建 Schema 模块创建完成后,需要设计数据表结构(Schema): ![pS128NF.png](https://s1.ax1x.com/2023/01/17/pS128NF.png) **表基本信息配置**: * **表名称**:遵循数据库命名规范,建议使用下划线分隔 * **表注释**:用于生成代码注释和文档 * **所属模块**:选择对应的业务模块 ![pS12dnx.png](https://s1.ax1x.com/2023/01/17/pS12dnx.png) **字段配置要点**: * **字段名称**:使用标准的数据库字段命名 * **字段类型**:根据数据特点选择合适的数据类型 * **字段长度**:设置合理的字段长度限制 * **默认值**:为字段设置合适的默认值 * **注释说明**:详细的字段说明,用于生成表单 label ![pS12s4e.png](https://s1.ax1x.com/2023/01/17/pS12s4e.png) ### 第三步:代码生成 Schema 创建完成后,即可进行代码生成。点击对应 Schema 的"生成代码"按钮: ![pS12ggA.png](https://s1.ax1x.com/2023/01/17/pS12ggA.png) ### 代码生成参数详解 #### 基础配置 * **模块**:必选项,选择代码生成的目标模块 * **控制器名称**:必填项,控制器的类名(如:UserController) * **模型名称**:默认使用表名,可自定义模型类名 #### 字段配置 * **表单 Label**:对应前端表单的字段显示名称 * **列表显示**:勾选后该字段会在列表页面中展示 * **表单字段**:勾选后该字段会在表单中显示,同时写入模型的 `form` 属性 * **搜索字段**:勾选后该字段支持列表页面的搜索功能 * **验证规则**:后端字段验证规则,遵循 Laravel 验证规则语法 #### 生成内容 代码生成器会自动创建: * **后端文件**:Controller、Model、Request、Migration * **前端文件**:Vue 组件、API 接口、路由配置(如需要) ### 生成文件结构 **后端文件位置**: ``` modules/ModuleName/ ├── Http/Controllers/ # 控制器 ├── Models/ # 模型 ├── Requests/ # 表单验证 └── database/migrations/ # 数据库迁移 ``` **前端文件位置**: ``` web/src/views/module-name/ ├── index.vue # 列表页面 ├── form.vue # 表单页面 └── api.js # API 接口 ``` ### 重要提醒 :::info 页面访问配置 代码生成完成后,还需要进行以下配置才能在前端看到页面: **方式一:动态菜单**(推荐) * 进入"权限管理" → "菜单管理" * 添加对应的菜单项和权限配置 **方式二:静态路由** * 在前端项目中手动添加路由配置 * 适用于不使用权限管理的场景 ::: ### 使用技巧 1. **合理规划字段**:生成前仔细考虑字段的展示和搜索需求 2. **验证规则**:充分利用 Laravel 验证规则,提升数据质量 3. **模块命名**:使用清晰的模块和控制器命名,便于后期维护 4. **批量生成**:可以为同一模块创建多个 Schema,实现快速开发 --- --- url: /docs/3.0/server/command.md --- # CatchAdmin 命令行工具 > 强大的 Artisan 命令集,简化开发和维护工作 CatchAdmin 提供了丰富的命令行工具,所有自定义命令都以 **catch** 为前缀,便于识别和使用。 **查看所有 CatchAdmin 命令**: ```shell php artisan | grep catch ``` 这些命令覆盖了项目安装、模块管理、数据库操作、代码生成等常见开发场景,显著提升开发效率。 ## 🔧 基础命令 ### 查看版本号 ```shell php artisan catch:version ``` 显示当前 CatchAdmin 的版本信息,用于版本确认和问题排查。 ### 项目安装 ```shell php artisan catch:install ``` **用途**:全新项目的初始化安装 **功能**: * 创建基础数据表结构 * 生成默认配置文件 * 初始化系统基础数据 * 设置默认管理员账户 ## 📦 模块管理 ### 模块安装 ```shell php artisan catch:module:install ``` **参数说明**: * ``:必需参数,模块名称 **功能**: * 注册模块到系统 * 执行模块的数据库迁移 * 初始化模块配置 * 生成模块路由缓存 **示例**: ```shell # 安装权限管理模块 php artisan catch:module:install permissions # 安装用户管理模块 php artisan catch:module:install users ``` ## 🗄️ 数据库操作 ### 创建迁移文件 ```shell php artisan catch:make:migration ``` **参数说明**: * ``:目标模块名称 * ``:迁移文件名称 **功能**:在指定模块下创建数据库迁移文件,遵循 Laravel 迁移文件规范。 ### 创建数据填充文件 ```shell php artisan catch:make:seeder ``` **参数说明**: * ``:目标模块名称 * ``:数据填充文件名称 **功能**:创建模块专属的数据填充文件,用于初始化测试数据或基础配置数据。 ### 执行数据库迁移 ```shell php artisan catch:migrate ``` **功能**:执行指定模块的数据库迁移文件,创建或更新模块相关的表结构。 **示例**: ```shell # 执行权限模块的数据库迁移 php artisan catch:migrate permissions ``` ### 执行数据填充 ```shell php artisan catch:db:seed ``` **功能**:执行指定模块的数据填充文件,为模块添加初始化数据。 **示例**: ```shell # 执行权限模块的数据填充 php artisan catch:db:seed permissions ``` **注意**:确保先执行迁移命令创建表结构,再执行数据填充。 ## 🔄 模块分发 ### 导出模块菜单 ```shell php artisan catch:export:menu ``` **参数说明**: * ``:必需参数,模块名称 * ``:可选参数,权限表名,默认为 `permissions` **功能**: * 导出模块的菜单权限配置 * 生成对应的 seed 文件 * 便于模块在不同项目间分发 **使用场景**: * 模块开发完成后的打包分发 * 跨项目模块迁移 * 开源模块的标准化发布 **示例**: ```shell # 导出权限模块的菜单配置 php artisan catch:export:menu permissions ``` :::tip 适用范围 此命令主要用于模块分发场景。如果模块仅在当前项目使用,通常不需要执行此命令。 ::: ## ⚡ 代码生成 ### 生成模型文件 ```shell php artisan catch:make:model ``` **参数说明**: * ``:目标模块名称 * ``:模型类名称 * ``:可选参数,对应的数据表名 **功能**: * 在指定模块下生成模型文件 * 自动继承 CatchModel 基类 * 根据表结构生成 fillable 属性 * 遵循 CatchAdmin 模型规范 **示例**: ```shell # 在权限模块下生成 Users 模型 php artisan catch:make:model permissions Users ``` **生成的模型内容**: ```php namespace Modules\Permissions\Models; use Catch\Base\CatchModel as Model; class Users extends Model { protected $table = 'users'; protected $fillable = [ 'id', 'username', 'password', 'email', 'avatar', 'remember_token', 'department_id', 'creator_id', 'status', 'login_ip', 'login_at', 'created_at', 'updated_at', 'deleted_at', ]; } ``` --- --- url: /docs/3.0/server/tips.md --- # CatchAdmin 开发小技巧 > 实用的开发技巧和经验分享 这里收集了 CatchAdmin 后台管理系统和 Laravel 框架的实用开发技巧,帮助开发者更好地适应框架开发。这些技巧来源于实际项目经验,能够有效提升开发效率。也 👏 欢迎开发者补充更多实用技巧 ## 取消路由中间件 CatchAdmin 后台路由默认注册了四个核心中间件: ```php Catch\Middleware\AuthMiddleware // 用户认证中间件 Catch\Middleware\JsonResponseMiddleware // JSON 响应中间件 Modules\User\Middlewares\OperatingMiddleware // 操作日志记录中间件 Modules\Permissions\Middlewares\PermissionGate // 权限验证中间件 ``` 模块中的路由通常会**全局**应用这些中间件,但某些场景下(如微信公众号验证、第三方回调接口等)并不需要这些中间件。可以使用以下技巧进行灵活控制: ### 取消后台所有公共的中间件 使用 `withoutMiddleware(config('catch.route.middlewares'))` 可以取消所有默认中间件: ```php Route::withoutMiddleware(config('catch.route.middlewares')) ->prefix('wechat') ->group(function(){ Route::prefix('official')->group(function (){ Route::get('sign', [OfficialAccountController::class, 'sign']); }); //next }); ``` ### 取消某个中间件 如果只需要取消特定中间件(如权限验证),可以这样操作: ```php Route::withoutMiddleware(\Modules\Permissions\Middlewares\PermissionGate::class) ->prefix('wechat') ->group(function(){ Route::prefix('official')->group(function (){ Route::get('sign', [OfficialAccountController::class, 'sign']); }); //next }); ``` ## 响应自定义 CatchAdmin 默认使用统一的响应结构,格式如下: ```php return [ 'message' => '', 'data' => '', 'code' => '' ] ``` 某些场景下需要自定义响应结构(如第三方 API 对接),可以使用 `ResponseBuilder` 实现灵活的响应格式: ```php return ResponseBuilder::code(10000) ->with('hello', 'world') ->with('hi', 'world') ->data($data) ->message('Hello world'); ``` ## 验证属性遇到第一个错误直接返回 Laravel 默认会验证所有规则后再返回错误,这在包含数据库查询的验证规则时会造成性能浪费。例如即使基础验证失败,仍会执行数据库验证: ```php $request->validate([ 'code' => [ 'required', 'size:6', function (string $attribute, mixed $value, \Closure $fail) use ($request) { // 这里是数据验证 code 码,例如手机验证码 }] ]); ``` 为了提升性能,可以使用 `bail` 规则让验证遇到第一个错误就停止: ```php $request->validate([ 'code' => [ 'bail', // 添加这个属性即可 'required', 'size:6', function (string $attribute, mixed $value, \Closure $fail) use ($request) { // 这里是数据验证 code 码,例如手机验证码 }] ]); ``` 如果使用 `FormRequest` 进行验证,可以通过设置 `stopOnFirstFailure` 属性实现全局的"遇错即停": ```php protected $stopOnFirstFailure = true; ``` :::info 通过将 stopOnFirstFailure 属性添加到请求类,一旦发生单个验证失败,它应该停止验证所有属性 ::: ## 如何单独显示菜单 不用菜单下拉 :::info 如果是二级菜单,并且只有`一个`二级菜单的情况下,那么只会显示二级菜单。 ::: 找到前端项目的文件 `src/layout/components/Menu/index.vue`,找到 `filterMenus` 方法,找到下面的代码 ```js menus?.forEach((m) => { if (m.meta?.hidden) { return false } newMenus.push(m) /** if (isHasOnlyChild(m) && m.children?.length) { newMenus.push( Object.assign({ path: m.children[0].path, meta: m.children[0].meta, name: m.name }) ) } else { newMenus.push(m) }*/ }) return newMenus ``` 打开注释即可 ## 前端支持 Keepalive `KeepAlive` 功能可以保持标签页面状态,切换时不重新加载,提升用户体验: ![使用菜单配置页面是否生效](https://image.catchadmin.com/202509130914783.png) :::info 配置完之后记得刷新后台才能生效 ::: --- --- url: /docs/3.0/front/intro.md --- # CatchAdmin 前端开发 > Vue 3 + TypeScript + Element Plus 的现代化前端架构 CatchAdmin 前端采用现代化的技术栈构建,基于 Vue 3 生态系统。在开始前端开发前,建议先熟悉以下核心技术: ## 核心技术栈 ### 框架基础 * **Vue 3** [官方文档](https://cn.vuejs.org/) - 项目的核心框架,提供响应式数据绑定和组件化开发 * **TypeScript** [官方文档](https://www.tslang.cn/docs/home.html) - 提供类型安全和更好的开发体验 ### UI 和样式 * **Element Plus** [官网地址](https://element-plus.org/) - 企业级 UI 组件库,提供丰富的后台管理组件 * **Tailwind CSS** [官网地址](https://tailwindcss.com/) - 原子化 CSS 框架,快速构建自定义样式 * **Hero Icons** [官网地址](https://heroicons.com/) - 精美的 SVG 图标库 ### 状态管理和工具 * **Pinia** [官网地址](https://pinia.vuejs.org/) - Vue 3 推荐的状态管理方案,替代 Vuex 这些技术构成了 CatchAdmin 前端的技术基础,建议在开发前充分了解。 ## Vite 构建配置 CatchAdmin 使用 Vite 作为构建工具,提供快速的开发体验和优化的生产构建。以下是详细的配置说明: ```js title="vite.config.js" // rootPath 项目根目录 const rootPath = resolve(__dirname) export default defineConfig(({ command, mode }) => { const env = loadEnv(mode, process.cwd(), '') return { plugins: [ vue(), vueJsx(), createHtmlPlugin({ minify: true, // 调整入口文件,入口文件放到了 public 下 template: 'public/admin.html' }), // 路径别名配置,简化导入路径 alias({ entries: [ { find: '/admin', replacement: resolve(rootPath, 'resources/admin') }, { find: '@/module', replacement: resolve(rootPath, 'modules') } ] }), // 自动导入 Vue API,无需手动 import AutoImport({ imports: ['vue', 'vue-router', 'pinia', '@vueuse/core'] // resolvers: [ ElementPlusResolver({importStyle: 'sass'}) ] }), // 自动导入组件,无需手动注册 Components({ dirs: ['resources/admin/components/', 'resources/admin/layout/'], extensions: ['vue'], deep: true, dts: true, include: [/\.vue$/, /\.vue\?vue/], exclude: [/[\\/]node_modules[\\/]/, /[\\/]\.git[\\/]/, /[\\/]\.nuxt[\\/]/] // resolvers: [ ElementPlusResolver({ importStyle: 'sass'}) ] }), // 图标自动导入和编译 Icons({ compiler: 'vue3', autoInstall: true }) ], publicDir: false, // 全局常量定义 define: { BASE_URL: env.BASE_URL // API 基础地址 }, preprocessorOptions: { scss: { // additionalData: `@use "@/assets/styles/element.scss" as *;`, } }, // 开发服务器配置 server: { host: '127.0.0.1', port: 8000, open: true, // 自动打开浏览器 cors: true, // 允许跨域请求 strictPort: false, // 端口占用时尝试其他端口 hmr: true, // 热模块替换 fs: { allow: ['./'] // 文件系统访问权限 } }, // 生产构建配置 build: { chunkSizeWarningLimit: 2000, // 包体积警告阈值 minify: 'terser', // 使用 terser 压缩 terserOptions: { compress: { drop_console: false, // 保留 console pure_funcs: ['console.log', 'console.info'], // 移除指定 console 方法 drop_debugger: true // 移除 debugger } }, outDir: 'public/admin', // 构建输出目录 assetsDir: 'assets', // 静态资源目录 rollupOptions: { input: './public/admin.html', output: { chunkFileNames: 'assets/js/[name]-[hash].js', entryFileNames: 'assets/js/[name]-[hash].js', assetFileNames: 'assets/[ext]/[name]-[hash].[ext]' } } } } }) ``` ## 环境变量配置 ### 开发环境配置 CatchAdmin 的前端项目默认安装在根目录的 `web` 目录,前端相关的环境变量配置在 `.env`: ```bash title=".env" # 这个配置在 CatchAdmin 安装时已自动生成 VITE_BASE_URL=${APP_URL}/api/ ``` :::info Vite 环境变量规则 * 所有前端环境变量必须以 `VITE_` 前缀开头 * 在 `vite.config.js` 中可以直接通过 `env.BASE_URL` 访问 * 在 Vue 组件中通过 `import.meta.env.VITE_BASE_URL` 访问 ::: ### 生产环境配置 生产构建时需要创建 `.env.production` 文件: ```bash title=".env.production" # 生产环境 API 接口地址 VITE_BASE_URL=https://your-api-domain.com/api/ ``` **注意事项**: * 生产环境的 API 地址需要替换为实际的服务器地址 * 确保 API 地址末尾包含 `/api/` 路径 * HTTPS 环境下建议使用 HTTPS 协议的 API 地址 --- --- url: /docs/3.0/front/entry.md --- # 入口 前端项目放置在 `resource/admin` 目录,关于 admin 各个目录的作用就不做多介绍了,可以到[项目介绍](/docs/3.0/start/project_intro)中查看。`app.ts` 即项目的入口 ```javascript title="resource/admin/app.ts" import '/admin/styles/index.scss' import CatchAdmin from './support/catchAdmin' // 首先引入的是 catchadmin 对象 const admin = new CatchAdmin() // 启动项目 admin.bootstrap() ``` 进入到 `CatchAdmin` 对象中,可以看到项目引入了哪些全局组件 ```javascript title="resource/admin/support/catchAdmin.ts" import { createApp } from 'vue' import type { App as app } from 'vue' import App from '/admin/App.vue' import router, { bootstrapRouter } from '/admin/router' import ElementPlus from 'element-plus' import zh from 'element-plus/es/locale/lang/zh-cn' import { bootstrapStore } from '/admin/stores' import Cache from './cache' import { bootstrapI18n } from '/admin/i18n' import guard from '/admin/router/guard' /** * catchadmin */ export default class CatchAdmin { protected app: app protected element: string /** * construct * * @param ele */ constructor(ele: string = '#app') { this.app = createApp(App) this.element = ele } /** * admin boot */ bootstrap(): void { this.useElementPlus().usePinia().useI18n().useRouter().mount() } /** * 挂载节点 * * @returns */ protected mount(): void { this.app.mount(this.element) } /** * 加载路由 * * @returns */ protected useRouter(): CatchAdmin { // 拦截路由 guard(router) bootstrapRouter(this.app) return this } /** * ui * * @returns */ protected useElementPlus(): CatchAdmin { this.app.use(ElementPlus, { locale: Cache.get('language') === 'zh' && zh, }) return this } /** * use pinia */ protected usePinia(): CatchAdmin { bootstrapStore(this.app) return this } /** * use i18n */ protected useI18n(): CatchAdmin { bootstrapI18n(this.app) return this } } ``` 主要使用了以下几个组件 * ElementPlus * Vue Router * Pinia * I18n 其实总结就是一句话,向 `Vue` 注入组件,最后挂载到 `#app` **dom** 上 ```javascript this.useElementPlus().usePinia().useI18n().useRouter().mount() ``` --- --- url: /docs/3.0/front/layout.md --- # 布局 不管是否进行二次开发,在开始之前都需要了解一下后台的页面布局。这对于认识前端系统非常重要。 布局文件放在 `resource/admin/layout` 下,这个差不多是标准了。看到 **layout** 文件夹,默认就是布局所在 ``` ├─components │ ├─header (头部组件) │ │ ├─index.vue | | ├─lang.vue (多语言组件) | | ├─logo.vue (logo 组件) | | ├─menuSearch.vue (菜单搜索组件) | | ├─notification.vue (通知组件) | | ├─profile.vue (个人组件) | | ├─theme.vue (主题组件/暗黑模式) | ├─ Menu(头部组件) │ │ ├─index.vue | | ├─item.vue (菜单 item 组件) | | ├─mask.vue (mask 组件) | | ├─menus.vue (菜单组件) | | │ └─content.vue 主题内容 │ └─sider.vue 侧边栏 ├─index.vue ``` ![pS3JQy9.png](https://s1.ax1x.com/2023/01/18/pS3JQy9.png) 采用的是传统的双栏布局,即左侧是 **Sider** 右侧是内容。可以从 `layout/index.vue` 看出布局 ```html title="resource/admin/layout/index.vue" ``` 内容区域分为`Header` 和 `router-view`,可以在 `layout/components/content.vue` 中 ```html title="resource/admin/layout/components/content.vue" ``` 所以当在 `vue router` 使用 `Layout` 组件是,组件的内容便会展示在 `layout` 内容组件的 `router-view` 中。譬如说 ```javascript title="resource/layout/index.ts" import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router' import type { App } from 'vue' export const constantRoutes: RouteRecordRaw[] = [ { path: '/dashboard', component: () => import('/admin/layout/index.vue'), children: [ { path: '', name: 'Dashboard', meta: { title: 'Dashboard', icon: 'home', hidden: false }, component: () => import('/admin/views/dashboard/index.vue') } ] } ] ``` `dashboard` 组件,也就是首页。使用的是 vue 路由嵌套的规则,Dashboard 组件被插入到内容组件的 `` 区域,这跟插槽有点类似了 ``` /layout/index /layout/index +------------------+ +-----------------+ | Layout | | Layout | | +--------------+ | | +-------------+ | | | Dashboard | | +------------> | | Develop | | | | | | | | | | | +--------------+ | | +-------------+ | +------------------+ +-----------------+ ``` :::info 如果不了解 vue router,可以先去[vue-router](https://router.vuejs.org/zh/guide/)看下文档 ::: --- --- url: /docs/3.0/front/side-menu.md --- # 侧边栏&路由 路由和侧边栏是组织起一个后台应用的关键骨架。 项目侧边栏和路由是绑定在一起的,`resource/admin/router/index.ts` 是整个路由的入口文件,如果是按正常顺序文档看下来,应该知道本项目的路由分为两种情况 * 动态生成的路由,也就是权限管理打开后,菜单管理的数据 * 每个模块的**views**目录下的 `router.js` 配置静态路由 所以一般情况下不用管`resource/admin/router/index.ts`路由这个入口文件。 ## 类型 对于权限和菜单,系统定义了两种类型,查看 `resource/admin/types` ### 权限类型 ```js title="resource/admin/types/Permissions.ts" export interface Permission { id: number // id parent_id: number // 父级 ID permission_name: string // 权限名称 type: number // 类型 icon: string // icon 图标 component: string // 组件 module: string // 模块 permission_mark: string // 权限标识 route: string // 路由,对应的是 vue route 的 path redirect: string keepAlive: boolean hidden: boolean // 是否隐藏 is_inner: boolean // 是否是内页 } ``` ### 菜单类型 菜单类型,最终都是由权限类型转换而来,所以一旦是动态生成的路由,那么元数据都是由菜单数据提供 ```js title="resource/admin/types/Menu.ts" import { Component } from 'vue' import { RouteRecordRaw } from 'vue-router' // meta 元数据 // 在记录上附加自定义数据。 // 这个数据将会附着在 vue route 上 export interface Meta { title: string icon: string // icon roles?: string[] // 哪些角色可以访问页面,未实现,保留 cache?: boolean // 页面缓存,未实现,保留 hidden: boolean // 是否隐藏,当设置成 true 时,菜单则不会在侧边栏显示。例如内页编辑页面啊,Login,页面 404 页面啊 keepalive?: boolean // 是否 keepalive 目前未实现,保留数据结构 is_inner?: boolean // 是否是内页 } // @ts-ignore // Menu 类型和 Vue Route 类型一样了 export interface Menu extends Omit { path: string // path 访问路径 name: string // name 菜单名称 meta?: Meta // meta,路由附着的额外数据 redirect?: string component?: Component // 页面组件 children?: Menu[] // 子菜单 } ``` 在了解完这两个相关类型之后,再来看动态菜单和权限如何实现的,静态菜单就不做介绍了。首先找到`resource/admin/route/guard/index.ts` 文件,从这里开始,这里是路由导航守卫。下面直接通过代码来注解如何实现 ```js title="resource/admin/route/guard/index.ts" const guard = (router: Router) => { // white list const whiteList: string[] = [WhiteListPage.LOGIN_PATH, WhiteListPage.NOT_FOUND_PATH] router.beforeEach(async (to, from, next) => { // set page title setPageTitle(to.meta.title as unknown as string) // page start progress.start() // 获取用户的 token const authToken = getAuthToken() // 如果 token 存在 if (authToken) { // 如果进入 /login 页面,重定向到首页 if (to.path === WhiteListPage.LOGIN_PATH) { next({ path: '/' }) } else { const userStore = useUserStore() // 获取用户ID if (userStore.getId) { next() } else { try { // 阻塞获取用户信息 // ⚠️ 用户信息已经包含了该用户所有可用权限,在 `permissions` 里 await userStore.getUserInfo() // 如果后端没有返回 permissions,前台则只使用静态路由 if (userStore.getPermissions !== undefined) { // 挂载路由(实际是从后端获取用户的权限) const permissionStore = usePermissionsStore() // 动态路由挂载,这里是主要实现动态路由菜单的地方 const asyncRoutes = permissionStore.getAsyncMenusFrom(toRaw(userStore.getPermissions)) // 在这里使用 addRoute 动态挂在路由 asyncRoutes.forEach((route: Menu) => { router.addRoute(route as unknown as RouteRecordRaw) }) } next({ ...to, replace: true }) } catch (e) { removeAuthToken() next({ path: `${WhiteListPage.LOGIN_PATH}?redirect=/${to.path}` }) } } } progress.done() } else { // 如果不在白名单 if (whiteList.indexOf(to.path) !== -1) { next() } else { next({ path: WhiteListPage.LOGIN_PATH }) } progress.done() } }) router.afterEach(() => { progress.done() }) } export default guard ``` ## 侧边栏 上面经过路由导航守卫之后,动态权限就已经转化为动态菜单了。主要通过这个方法来实现转换 ```js const asyncRoutes = permissionStore.getAsyncMenusFrom(toRaw(userStore.getPermissions)) ``` 这里就不细说里面的实现了,是通过递归实现无限极菜单。但是这里一个非常重要的点,就是权限是通过`pinia` 进行保存的,因为 `pinia` 是响应式的。找到 `resource/admin/store/user/permissions.ts`,看下 `permissionStore` 的定义 ```js title="resource/admin/store/user/permissions.ts" interface Permissions { menus: Menu[] // 菜单 asyncMenus: Menu[] // 动态菜单 permissions: Permission[] // 权限 menuPathMap: Map // menu 和 path 的 MAP 数据 } export const usePermissionsStore = defineStore('PermissionsStore', { // state 里面定义的几个数据都是响应式的 state: (): Permissions => { return { menus: [], asyncMenus: [], permissions: [], menuPathMap: new Map(), } }, } ``` 既然菜单都是响应式的,那就好办了呀!菜单的数据就直接从 `store` 获取就可以了。 侧边栏的实现是在 `layout/components/Menu`,侧边栏的菜单也是基于`ElementPlus` 的 `el-menu` 实现的。因为是动态菜单,所以这里的用到了`vue` 的[渲染函数](https://cn.vuejs.org/guide/extras/render-function.html#creating-vnodes)。源码在 `layout/components/Menu/index.vue` 中 --- --- url: /docs/3.0/front/permissions.md --- # 权限认证 上面其实也讲到了权限相关的,用户在通过认证之后,后端在用户信息中其实已经加入了该用户所有权限。可以通过 `resource/admin/store/user/index.ts` 的 `UserStore`获取 ```typescript const userHasPermissions = userStore.getPermissions ``` ## 权限指令 权限指令是使用 `vue`的 `directive` 实现一个前端操作控制的指令,例如新增,更新等等操作。如果你需要页面级别的权限操作,那么这个指令可以很好的帮助你实现该功能 例如控制权限模块的角色更新功能,你可以使用 `v-action` 进行控制,如果登录人员没有改操作权限,那么此操作按钮将不再页面展示。 ```javascript ``` 权限指令要求的格式和后端相似,格式如下 ```javascript module.controller.action or module@controller@action ``` ### 实现方案 众所周知,后端是模块的,为了防止模块之间的路由会发生冲突,所以权限标识是由**模块** + **controller@action** 组合 :::info 后端路由即 controller@action,权限标识也是这样定义 ::: 所以权限检测可以这么写, 伪代码如下 ```typescript function hasPermission(string mark) { // mark 是这样的形式 module + '@' + 'controller@action' // 当然也可以定义其他形式的 const userHasPermissions = userStore.getPermissions userHasPermissions.each(item => { if (permissions === (item.module + '@' + item.permission_mark)) { return true } }) return false } ``` 这样就是检测权限了,那么再将其引入到自定义指令中,这里代码仅提供思路,正确性未知 ```typescript app.directive('permission', (el, binding) => { const hasPermission = hasPermission(binding.value) if (!hasPermission) { el.style.display = none } }) ``` 在项目中这么使用 ```html ``` 具体实现可到前端项目的`directives`目录下的 action 查看 --- --- url: /docs/3.0/front/style.md --- # 样式 样式存在 `resource/admin/style` 目录下,结构如下 ``` ├─theme | ├─dark.scss // 暗黑主题 | ├─index.scss | ├─light.css // 默认主题 ├─element.scss // Element 样式 ├─index.scss // scss 入口 ├─tailwind.css // tailwindcss ├─var.scss // 自定义变量 ``` 样式上好像并没有什么可以说的了, style 目录的样式都是全局样式。 还有一点就是目前后台的样式是响应式的,基于 `tailwindcss` 做的,tailwindcss 还是很方便的。 :::info 其实用到全局样式的地方不是很多,一般还是在 vue 文件中使用 scope 来改样式 ::: --- --- url: /docs/3.0/front/request.md --- # 请求 前端请求默认使用的是 `axios`,但是为了方便,后台提供了 `Http` 对象快速发起请求 ```typescript title="resource/admin/support/http.ts" import Http from '/admin/support/http' // GET 请求 http.get(path: string, params: object = {}) // POST 请求 http.post(path: string, data: object = {}) // PUT 请求 http.put(path: string, data: object = {}) // DELETE 请求 http.delete(path: string) ``` ## 设置超时 ```typescript Http.timeout(5).get() ``` ## 设置 BASEURL ```typescript Http.setBaseUrl('https://api.com').get() ``` ## 设置 header ```typescript Http.setHeader(key:string, value:string).get() ``` ## 表单请求 表单请求则使用了 `vue3` 的新特性 `hooks`,也称为[组合式函数](https://cn.vuejs.org/guide/reusability/composables.html)。查看 `resource/admin/composables/curd`,总共提供六个操作。 ## GetList `getList` 请求列表数据 ```typescript const { data, query, search, reset, loading } = useGetList(api) // 接口返回的数据必须 computed 才具备响应 const tableData = computed(() => data.value?.data) ``` * data 接口返回的数据 * query:{} 查询数据 * search() 搜索方法 * reset() 重制方法 * loading:boolean 列表请求 loading ## Create **create** 其实包含两个操作,创建和更新,当 **props.primary** 是 **null** 的时候,就是创建数据不为空时,则是更新数据 ```typescript const { formData, form, loading, submitForm, close } = useCreate(props.api, props.primary) // 更新的 ID if (props.primary) { useShow(props.api, props.primary, formData) } // 关闭弹窗 const emit = defineEmits(['close']) close(() => emit('close')) ``` * formData 提交的 Form 数据 * form 表单 ref * loading 提交数据表单 loading * submitForm(form) 点击提交表单的方法, 参数就是 `form` * close 关闭弹窗 ## Destroy ```typescript const { destroy, deleted } = useDestroy() onMounted(() => { // 观察数据是否删除,删除之后刷新列表 deleted(reset) }) ``` * destory(path: string, id: string | number) 删除数据的方法,一般都是用于列表删除数据 * deleted(callback: Function) 观测数据是否删除,参数删除后的回调操作 ## Enabled `enabled` 作用就是请求状态切换 ```typescript const { enabled, success, loading, afterEnabled } = useEnabled() ``` * enabled(path: string, id: string | number, data: object = {}) 请求切换 * success(callback: Function) 参数成功后的回调函数 * loading 请求时 loading * afterEnabled 请求完成之后的操作, 只有设置成方法才会被调用 ```typescript afterEnabled.value = () => {} ``` ## Open 打开 `Dialog` 弹窗,一般用于通过`Dialog` **创建/更新**数据的时候 ```typescript const { open, close, title, visible, id } = useOpen() ``` * open(primary: any = null) 显示`Dialog` * close(callback: Function) 关闭 `Dialog` callback 关闭后的回调方法 * title: string Dialog 标题 * visible: boolean Dialog 状态 * id 数据的 ID ## Show show 方法就是拉取更新时的数据,填充表单 ```typescript if (props.primary) { useShow(props.api, props.primary, formData) } ``` --- --- url: /docs/3.0/front/catch-table.md --- # 🥇 动态表格 `catch table` 组件旨在快速减少后台开发中表格的重复编写,动态表格的实现将会大大提高效率,并且极易扩展 :::tip 如果你需要服务端组件,可以支持购买[动态表格](/docs/forms/table/index) ::: ## 基础用法 一个简单的表格,只需要在组件上添加, 这里就以用户管理页面作为例子, 一步一步实现 ![](https://www.hualigs.cn/image/646311f57c899.jpg) 代码如下 ```javascript ``` ## 表格搜索 ![](https://www.hualigs.cn/image/6463130b546c9.jpg) 只需要新增 `search-form` 属性即可 ```javascript ``` ok,这样一个完整的表格页面就创建完成了。 ## 新增数据 从上图可以看出,一般情况下表格都是带有增删改查的,那么如何新增数据呢?高级版本中,只需要在 `catchtable` 使用 `slot` 即可 ![](https://www.hualigs.cn/image/64631573c61bc.jpg) ```javascript ``` 这里需要注意两点的是,一般情况下 Create 组件都是由代码自动生成功能生成的 * `Create` 组件是自带 `primary` props 的,用于更新 * `Create` 组件是自带 `api` props 的,api 主要用于接口提交 ## 隐藏分页 一般列表都是需要分页的,但是某种场景下,需要隐藏分页的话,可以使用下面的代码 ```javascript ``` ## 树形表格 要使用树形表格,在 `catch-table` 中也是非常简单的,只需要 ```javascript ``` > {info} > 注意在 `catchtable` 中,树形表格都是自动隐藏分页的 ## 空数据显示的文本 如果表格没有数据,需要友好的提示的话,那么可以使用下面的代码,默认使用`暂无数据` ```javascript ``` ## 隐藏操作 表格默认一个新增操作,如果不需要的话,可以使用 ```javascript ``` ## 隐藏工具栏 在表格右上角,有三个默认工具栏操作,分别是 `刷新`,`表格栏目`, `搜索`, 如果不需要的话,可以使用 ```javascript ``` ## 默认参数 有这么一个场景,例如后台的字典管理,每个字典都需要管理字典值。而每个字典值列表则需要字典的 ID。这个时候 每个请求列表的 api 都是需要默认参数 `字典ID`。这个时候就需要添加默认参数 ```javascript ``` ## 曝露方法 表格对外有几个可以直接调用的方法,调用方法之前需要先设置 table ref,在获取整个`catchadmin`对象 ref 之后,才可以使用 ```javascript // js 代码 // ⚠️如果你对 vue 不熟悉的话,注意 ref="catchadmin" 这里 ref 的名称需要和 const [catchtable] 相同 ``` ## 搜索 在某些操作之后,需要搜索刷新列表 ```javascript ``` ## 重置 在某些操作之后,需要重置列表,也可以叫做刷新吧 ```javascript ``` ## 打开弹出层 ```javascript ``` ### 关闭弹出层 ```javascript ``` ### 删除 某些场景需要访问删除接口时候,就可以使用它 ```javascript ``` ### 设置默认搜索参数 这个方法在某些特定场景下会有用到,比如一个表格列表的访问他的子列表,子列表需要父列表的某个条件才能访问到。这个时候就需要给子列表设置一个默认参数。`字典管理`列表就是一个很好的例子 ```javascript ``` ## 获取表格多选 ID 目前 `catchadmin` 已经内置了多选删除。如果需要做其他多选操作的时候,可以使用它获取多选数据 ```javascript ``` ## 表格插槽 为了让表格更加灵活点,`catchtable` 内置了几个插槽,来让用户自定义操作 ### 表格操作插槽 `catchtable` 默认只有新增操作,如果你需要添加其他的操作,那么你可以使用以下代码,新增表格的操作 ```vue ``` ![](https://s2.xptou.com/2023/05/24/646d9eff36fed.png) ### 批量操作插槽 目前表格内置了`批量删除`操作。当表格需要额外的批量操作时,可以使用该插槽。 ```vue ``` 光是这样的是不够的,还要获取批量选择 ID,请查看[获取表格多选 ID](#获取表格多选id),获取到多选 ID 之后进行操作 ![](https://s2.xptou.com/2023/05/24/646da1251a841.png) ### 栏目操作插槽 表格栏目支持`更新`和`删除`操作,如果还需要额外的操作,那么可以使用 ```vue // 通过 scope 你可以获取行数据 ``` ![](https://s2.xptou.com/2023/05/24/646da22bba7ff.png) ### 弹窗插槽 弹窗插槽是每个表格都需要的,目前只服务于表单数据。 ```vue ``` ## 表格栏目 对于表格栏目,可以通过表格类型窥探一二。看下表格栏目是如何定义的 ```javascript export type columnType = 'expand' | 'selection' | 'index' | 'operate' export type fixed = 'fiexed' | 'right' | 'left' export interface Column { type?: columnType // 类型 expand select index label?: string prop?: string 'min-width'?: string | number width?: number | string slot?: 'string' header: 'string' // 表头插槽名称 align?: string fixed?: fixed sortable?: boolean | string 'sort-method'?: Function 'sort-by'?: Function resizable?: boolean formatter?: Function // function(row, column, cellValue, index) 'header-align'?: string 'class-name'?: string selectable?: Function // function(row, index) show: boolean index?: number | Function // 如果设置了 type=index,可以通过传递 index 属性来自定义索引 children?: Array // 多级表头 filter?:Function, ellipsis?:boolean|number, // 当文字太多时,可以使用省略文字 switch: false, // swith 字段状态切换 // 操作 update?: boolean, // 编辑操作 destroy?: boolean // 删除操作 } ``` ### 栏目类型 `type` 字段 * `expand` 展开类型,树形结构的表格,规定哪个栏目展开 * `selection` 多选类型,一般用于表格多选操作。一般都是用于主键字段 * `index` 可以自定义索引 * `operate` 最后一行操作栏目 ### 栏目固定 `fiexed` 字段 * fixed 默认固定 * right 固定在右侧 * left 固定在左侧 ### 插槽 如果栏目是需要自定义,那么肯定是需要用插槽这个功能。只需要设置 `slot` 字段,例如插槽名称设置为 ```javascript { label: '你好', slot: 'hello' } ``` 那么此时只需要在`catchtable`组件如下设置 ```javascript ``` ### 格式化字段 有时候并不需要插槽,例如当后台的接口中的性别字段(gender)返回 1, 2。其中 1 代表男 2 代表女,这个时候需要实现格式化方法即可 ```javascript { label: '性别', prop: 'gender', filter: (value) => { return value === 1 ? '男' : '女' } } ``` ### 自定义索引 当栏目的 type 设置成 `index` 时,则需要自定义索引,一般通过 `index` 来设置 ```javascript { type: 'index', prop: 'gender', index: () => {} } ``` ### 多级表头 当然,catchtable 也支持多集表头,只要一个简单的配置即可 ```javascript { prop: 'job_name', label: '岗位名称', children: [ { prop: 'coding', label: '岗位编码' }, { label: '状态', prop: 'status', switch: true, align: 'center' } ] } ``` ![](https://s2.xptou.com/2023/05/24/646da4af1bc11.png) ### 字段太长,省略号 ```javascript { prop: 'description', label: '岗位描述', ellipsis: true // 添加该字段 }, ``` ![](https://s2.xptou.com/2023/05/24/646d451b3e49d.png) ### 字段状态切换 某些场景下,业务中只需要在表格中做某些字段的状态切换,这个时候就可以使用下面的代码 ```javascript { prop: 'status', // 设置字段,这里仅做演示 label: '状态', switch: true // 添加该字段 }, ``` `catchadmin`在后端通常使用 `enable` 方法做字段切换的路由, 你可以根据实际改动。代码如下 ```php public function enable($id, Request $request) { return $this->model->toggleBy($id, $request->get('field')); } ``` ![](https://s2.xptou.com/2023/05/24/646d4672500a6.png) ### 图片预览 如果表格中需要进行图片预览,那么可以使用下面的配置,只需要使用 `image` 属性 ```javascript { label: '内容', prop: 'content', image: true, }, ``` 如果你是想要预览,如果是单图的话,你需要使用 `filter` 转换成多图数组 ```javascript { label: '内容', prop: 'content', image: true, preview: true, filter: (value: any) => { return [value] } }, ``` ### 链接 如果表格中需要某个字段需要链接,那么可以使用下面的配置, 也是非常简单,只需要配置 `link` 属性 ```javascript { label: '链接', prop: 'url', link: true }, ``` ### 标签展示 如果表格中需要某个字段需要标签,那么可以使用下面的配置, 也是非常简单,只需要配置 `tags` 属性,单个标签 ```javascript { label: '类型', prop: 'type', tags: true }, ``` 多个标签一般都是配合枚举值,`catchadmin` 枚举一般使用 number,并且从数字`1`开始,数组可以很好配合使用 ```javascript { label: '类型', prop: 'type', tags: ['danger', 'info', 'success'], filter: (value: number) => { return value === 1 ? '轮播图' : value === 2 ? '友情链接' : '广告' } }, ``` ### 排序 某些场景下,业务中只需要在表格中做某个字段排序。通常来说,elementPlus 只是在前端列表单独一页排序,但是使用下面的代码,可以直接进行后端排序,不需要写任何一行代码,都是自动完成的 ```javascript { prop: 'sort', label: '排序', sortable: true } ``` ![](https://s2.xptou.com/2023/05/24/646d476c4962a.png) --- --- url: /docs/3.0/front/catch-form.md --- # 🔮 动态表单 经过一段时间调研和开发,最终还是推出了全新动态表单的功能,不仅支持 JSON 配置,还支持的动态解析和动态调用,相较于前一个版本,提高了非常多 :::tip 示例都是基于整个后台框架的,不要单独拎出去使用 ::: :::tip 如果你需要服务端组件,可以支持购买[动态表单](/docs/forms/intro) ::: ## 基本使用 先来看一个简单的表单示例,表单包含一个`input` 框架 ```vue ``` 使用 `CatchForm` 组件,这里非常简单,包含一个 props 和一个提交方法 * `schema` 是 form 的数据结构,就是存放 form 组件的对象 * `onSubmit` 是 form 提交方法 再来看下 schema 的结构 ```js type schema = { labelWidth: number // label 宽度 labelAlign: string // label 位置 size: string // 表单大小 footer: Object // 表单底部 class?: string // 表单 class 支持 tailwindcss disabled?: boolean // 是否禁用 labelBold?: boolean // label 文字是否粗体 items: formItemsType // 表单字段 } ``` 所以回到刚才的 `form` 数据,看看结构,里面只包含 `items`,也就是表单的字段集合。再来看看表单字段的结构 ```typescript { name: 'name', // 字段 name props: { // 组件对应的 props,可以参考 ElementPlus 对应组件的 props clearable: true }, label: '姓名', // label 值 component: 'input', // 组件 class: 'mt-4', // 组件 class,支持 tailwindcss required: true // 是否必选 } ``` 再来看看字段的定义, 包含全部 ```js interface formItemType { label?: string // label 值 name: string // 字段 name component: string // 字段组件 required?: boolean // 是否必填 props?: object // // 组件对应的 props,可以参考 ElementPlus 对应组件的 props initialValue?: any // 默认值 children?: formItemType[] // 支持子组件,例如 grid 组件 hidden?: boolean | string // 是否隐藏 hideLabel?: boolean // 是否隐藏 label rules?: any[] // 表单验证规则 class?: string // 组件 class,支持 tailwindcss style?: any // 行内样式 change?: changeItemType[] // change 方法 } ``` ## 表单组件 :::warning 所有组件的 `name` 都是必须的 动态组件内的 props 属性,都是和 ElementPlus 组件内的 `props`, 由于篇幅限制这里就不再展示,请到官方文档查看 ::: ### 辅助组件 #### Alert 组件 [Alert 组件 props](https://element-plus.org/zh-CN/component/alert.html#alert-api) ```typescript { name: 'alert', props: { title: "Hello Alert" }, component: 'alert', // 组件 } ``` #### button 组件 [button 组件 props](https://element-plus.org/zh-CN/component/button.html#button-api) ```typescript { name: 'button', props: { name: '提交', clickEvent: 'submitForm' // 点击提交事件 }, component: 'button', // 组件 } ``` #### 分割线组件 [分割线组件 props](https://element-plus.org/zh-CN/component/divider.html#api) ```typescript { name: 'divider', props: { title: '分割线组件' }, component: 'divider', // 组件 } ``` ### Layout 组件 #### Grid 组件 Grid 两栏 ```typescript { component: 'grid', children: [ { label: '名称', component: 'input', props: { placeholder: '请输入名称' }, name: 'name' }, { label: '名称1', component: 'input', props: { placeholder: '请输入名称1' }, name: 'name1' } ], props: { columns: 2, // 栏目数量 'column-gap': 20, // 栏目间距 'row-gap': 20 // 行间距 }, name: 'grid' } ``` #### Card 组件 `Card` 和 `Grid` 可以通过 `children`属性 组合使用 ```js { component: 'card', children: [ { label: '名称', component: 'input', props: { placeholder: '请输入名称' }, name: 'name' } ], props: { header: '卡片' }, name: 'card' } ``` #### Inline 行内组件 ```js { component: 'inline', children: [ { label: '名称', component: 'input', props: { placeholder: '请输入名称' }, name: 'name' }, { label: '名称1', component: 'input', props: { placeholder: '请输入名称' }, name: 'name1' } ], props: { align: 'left', gap: 20 }, name: 'inline' } ``` ### 表单字段组件 #### Switch 组件 [switch 组件 props](https://element-plus.org/zh-CN/component/switch.html#api) ```js { label: '开关', component: 'switch', props: { 'inline-prompt': false }, name: 'status' } ``` #### Input 组件 [Input 组件 props](https://element-plus.org/zh-CN/component/input.html#api) ```js { label: '名称', component: 'input', props: { placeholder: '请输入名称' }, name: 'name' } ``` #### Password 组件 [Input 组件 props](https://element-plus.org/zh-CN/component/input.html#api) ```js { label: '密码', component: 'password', props: { placeholder: '请输入密码' }, name: 'password' } ``` #### Select 组件 [Select 组件 props](https://element-plus.org/zh-CN/component/select.html#select-api) ```js { label: '下拉选择框', component: 'select', props: { options: [ { label: '选项1', value: 'value1' }, { label: '选项2', value: 'value2' }, { label: '选项3', value: 'value3' } ], placeholder: '请选择...', labelKey: 'label', valueKey: 'value' }, name: 'select' } ``` #### Cascader 组件 [Cascader 组件 props](https://element-plus.org/zh-CN/component/cascader.html#cascader-api) ```js { label: '级联选择器', component: 'cascader', props: { placeholder: '请选择...', labelKey: 'label', valueKey: 'value', options: [ { label: '选项1', value: 'value1', children: [ { label: '选项1-1', value: 'value1-1' }, { label: '选项1-2', value: 'value1-2' }, { label: '选项1-3', value: 'value1-2' } ] }, { label: '选项2', value: 'value2', children: [ { label: '选项2-1', value: 'value2-1' }, { label: '选项2-2', value: 'value2-2' }, { label: '选项2-3', value: 'value2-2' } ] }, { label: '选项3', value: 'value3' } ] }, name: 'cascader' } ``` #### Checkbox 组件 [Checkbox 组件 props](https://element-plus.org/zh-CN/component/checkbox.html#checkbox-api) ```js { label: '多选框组', component: 'checkbox', props: { placeholder: '请选择...', options: [ { label: '选项1', value: 'value1' }, { label: '选项2', value: 'value2' }, { label: '选项3', value: 'value3' } ], labelKey: 'label', valueKey: 'value' }, name: 'checkbox' } ``` #### ColorPicker 组件 [ColorPicker 组件 props](https://element-plus.org/zh-CN/component/color-picker.html#api) ```js { label: '颜色选择器', component: 'color_picker', name: 'colorPicker' } ``` #### 日期组件 [日期组件 props](https://element-plus.org/zh-CN/component/date-picker.html#api) ```js { label: '日期选择器', component: 'date_picker', props: { type: 'datetime', placeholder: '请选择日期', clearable: false }, name: 'DatePicker' } ``` #### 图标选择器 #### 数字组件 [数字组件 props](https://element-plus.org/zh-CN/component/input-number.html#api) ```js { label: '数字组件', initialValue: 1, component: 'input_number', name: 'input_number' } ``` #### Radio 组件 [Radio 组件 props](https://element-plus.org/zh-CN/component/radio.html#radio-api) ```js { label: '单选框组', component: 'radio', props: { options: [ { label: '选项1', value: 'value1' }, { label: '选项2', value: 'value2' }, { label: '选项3', value: 'value3' } ], labelKey: 'label', valueKey: 'value', optionType: 'circle', direction: 'horizontal', }, name: 'radio' } ``` #### Rate 评分组件 [Rate 评分组件 props](https://element-plus.org/zh-CN/component/rate.html#api) ```js { label: '评分', component: 'rate', name: 'rate' } ``` #### 滑块组件 [滑块组件 props](https://element-plus.org/zh-CN/component/slider.html#api) ```js { label: '滑块', component: 'slider', name: 'slider' } ``` #### Transfer 组件 [Transfer 组件 props](https://element-plus.org/zh-CN/component/transfer.html#api) ```js { label: '穿梭框', component: 'transfer', props: { options: [ { label: '选项1', value: 'value1' }, { label: '选项2', value: 'value2' }, { label: '选项3', value: 'value3' } ], labelKey: 'label', valueKey: 'value' }, name: 'transfer' } ``` #### 上传组件 ##### 单图上传 ```js import { getAuthToken, env } from '/admin/support/helper' const form = { items: [ { label: '单图上传', props: { action: env('VITE_BASE_URL') + 'upload/image', name: 'image', token: 'Bearer ' + getAuthToken() }, component: 'upload_image', name: 'image' } ] } ``` ##### 多图上传 ```js import { getAuthToken, env } from '/admin/support/helper' const form = { items: [ { label: '多图上传', props: { action: env('VITE_BASE_URL') + 'upload/image', name: 'image', token: 'Bearer ' + getAuthToken() }, component: 'upload_images', name: 'image' } ] } ``` ##### 单文件上传 ```js import { getAuthToken, env } from '/admin/support/helper' const form = { items: [ { label: '单文件上传', props: { action: env('VITE_BASE_URL') + 'upload/file', name: 'image', token: 'Bearer ' + getAuthToken() }, component: 'upload_file', name: 'file' } ] } ``` ##### 多文件上传 ```js import { getAuthToken, env } from '/admin/support/helper' const form = { items: [ { label: '多文件上传', props: { action: env('VITE_BASE_URL') + 'upload/file', name: 'image', token: 'Bearer ' + getAuthToken() }, component: 'upload_files', name: 'file' } ] } ``` #### Tree 组件 [Tree 组件 props](https://element-plus.org/zh-CN/component/tree.html#%E5%B1%9E%E6%80%A7) ```js { label: '树形结构', props: { 'show-checkbox': true, options: [ { label: '选项1', value: 'value1', children: [ { label: '选项1-1', value: 'value1-1' }, { label: '选项1-2', value: 'value1-2' }, { label: '选项1-3', value: 'value1-2' } ] }, { label: '选项2', value: 'value2', children: [ { label: '选项2-1', value: 'value2-1' }, { label: '选项2-2', value: 'value2-2' }, { label: '选项2-3', value: 'value2-2' } ] }, { label: '选项3', value: 'value3' } ], }, component: 'tree', name: 'tree' } ``` #### 自增表单 ```js { label: '动态配置', props: { children: [ { name: 'name', label: '名称', component: 'input', props: { clearable: true, placeholder: '请输入名称' } }, { name: 'name1', label: '名称1', component: 'input', props: { clearable: true, placeholder: '请输入名称1' } } ] }, component: 'form_list', name: 'hello' } ``` --- --- url: /docs/3.0/video.md --- # 视频教程 `CatchAdmin` 是一款基于 `Laravel` 开发的 PHP 开源后台管理框架系统,为用户提供了丰富的后台管理功能。在这个视频教程系列中,我将带您深入了解 `CatchAdmin` 的各个方面,包括但不限于: * 安装和配置 CatchAdmin * 使用 CatchAdmin 的各种功能,如用户管理、角色管理、权限管理、菜单管理等 * 开发自定义模块和扩展 我的视频教程将以实际项目为例,并结合实用的案例和示例,帮助您快速上手和使用 `CatchAdmin`。此外,我还将与您分享最佳实践和技巧,帮助您在使用 `CatchAdmin` 中更加高效和便捷。 我的视频教程将持续更新,以反映 `CatchAdmin` 的最新版本和最佳实践。如果您想获得最新的 `CatchAdmin` 视频教程,请订阅我的频道并打开通知。 ## laravel 版本 * [项目安装](https://www.bilibili.com/video/BV1eY411v71J) * [catchadmin 模块创建](https://www.bilibili.com/video/BV1jP41127aW/) * [catchadmin 快速开发](https://www.bilibili.com/video/BV1Qh4y1J7eB/) ## thinkphp 版本 * [项目安装](https://www.bilibili.com/video/BV1bD4y1R72m/) * [编写模块](https://www.bilibili.com/video/BV1Pk4y1y7no) * [catch-table 介绍](https://www.bilibili.com/video/BV1Py4y1x7q5/) --- --- url: /docs/3.0/faq.md --- # CatchAdmin 常见问题 > 使用 CatchAdmin 过程中的常见问题和解决方案 ## 依赖问题 由于 `Laravel12` 刚发布,CatchAdmin 的依赖可能无法正常安装。这通常是由于镜像更新慢导致的,建议取消使用镜像,直接从官方源下载。如果网络条件不佳,可以使用'魔法'工具(懂得吧)来提升下载速度。 ### 镜像 这是目前维护中的可用的 composer 镜像,使用下面的命令安装 ```shell composer config -g repos.packagist composer https://packagist.pages.dev ``` ## 路由未找到 遇到 CatchAdmin 路由访问问题时,首先检查路由是否存在: ```bash php artisan route:list ``` 如果接口路由不在路由表中,通常是因为相关模块未启用。请检查 `storage/app/modules.json` 文件中的模块状态,以权限模块为例: ```json { "title": "权限管理", "name": "permissions", "path": "permissions", "keywords": "权限, 角色, 部门", "description": "权限管理模块", "provider": "\\Modules\\Permissions\\Providers\\PermissionsServiceProvider", "version": "1.0.0", "enable": true // 该字段是否开启 } ``` ## 模块路由命名重复 在 CatchAdmin 开发中,当多个模块存在同名控制器时可能出现路由冲突。例如 CMS 模块和 SHOP 模块都有名为 `CategoryController` 的控制器。正常情况下,通过路由分组就能解决: ```php // cms 分类路由 Route::prefix('cms')->group(function () { Route::apiResource('category', CategoryController::class); }); // shop 分类路由 Route::prefix('shop')->group(function () { Route::apiResource('category', CategoryController::class); }); ``` 但是这里会出现一个问题,当使用 ```sh php artisan route:cache ``` 的时候,会提示一个错误 ```shell Unable to prepare route [api/shop/category] for serialization. Another route has already been assigned name [category.index]. ``` 这个问题就是两个路由的 `name` 重复了, 无法进行缓存了。这里就需要设置成这样,只改 shop 的路由即可 ```php // shop 分类路由 Route::prefix('shop')->group(function () { Route::apiResource('category', CategoryController::class)->names('shop_category') }); ``` ## 打包出现报错 在构建 CatchAdmin 前端项目时,如果出现过多的 TypeScript 类型错误,但你对类型检查不太敏感,这些错误通常不会影响应用正常运行。 快速解决方法是修改 `package.json` 文件中的 build 命令,跳过类型检查: ```json { "scripts": { "dev": "vite", "build": "vue-tsc --noEmit && vite build", // [!code --] "build": "vite build", // [!code ++] "preview": "vite preview" } } ``` --- --- url: /docs/forms/intro.md --- # 介绍 目前 CatchAdmin 专业版已有一个基于 JSON 的 CatchTable,但是目前是基于 Vue 文件的。如果上线的话,需要重新打包才能看到效果。在 V2 版本,依据 form-create 提供了一个 PHP 生成 Vue 表单的组件。现在在专业版依然通过 [form-create](https://form-create.com/v3/guide/) 提供一个动态表单组件,但是组件更加丰富,语法更加语义化。使用更加方便,更加易于扩展 ## 组件 新的动态表单提供了以下新的组件 ### 基础组件 * [Boolean 组件](./components/boolean.md) * [Button 组件](./components/button.md) * [Cascader 组件](./components/cascader.md) * [Checkbox 组件](./components/checkbox.md) * [Col 组件](./components/col.md) * [ColorPicker 组件](./components/colorPicker.md) * [Date 组件](./components/date.md) * [DatePicker 组件](./components/datePicker.md) * [DateRange 组件](./components/dateRange.md) * [Dates 组件](./components/dates.md) * [Datetime 组件](./components/datetime.md) * [DatetimeRange 组件](./components/datetimeRange.md) * [Email 组件](./components/email.md) * [Group 组件](./components/group.md) * [Hidden 组件](./components/hidden.md) * [IconSelect 组件](./components/iconSelect.md) * [Month 组件](./components/month.md) * [Number 组件](./components/number.md) * [Password 组件](./components/password.md) * [Radio 组件](./components/radio.md) * [Rate 组件](./components/rate.md) * [RichText 组件](./components/richText.md) * [Row 组件](./components/row.md) * [Select 组件](./components/select.md) * [SelectOptions 组件](./components/selectOptions.md) * [Slider 组件](./components/slider.md) * [SubForm 组件](./components/subForm.md) * [Text 组件](./components/text.md) * [Textarea 组件](./components/textarea.md) * [TimePicker 组件](./components/timePicker.md) * [Tree 组件](./components/tree.md) * [Upload 组件](./components/upload.md) * [Url 组件](./components/url.md) * [Week 组件](./components/week.md) * [Year 组件](./components/year.md) ### 基本方法 #### 设置表单显示样式 ```php public function inline() ``` #### label 宽度 ```php public function labelWidth(int $width) ``` #### label 位置 因为默认位置是在左侧,所以这里只提供右侧 ```php public function labelRightPosition() ``` #### 设置提交按钮文案 ```php public function submitButton(string $text) ``` #### 隐藏提交按钮 ```php public function hideSubmitButton() ``` #### 设置重置按钮文案 ```php public function resetButton(string $text) ``` #### 显示重置按钮 ```php public function showResetButton() ``` #### 设置表单默认值 该设置的默认值,表单值不是响应式 ```php public function setFormDefaultValues(array $formData) ``` #### 禁用表单 ```php public function disabled() ``` #### 设置表单尺寸 目前支持以下三个尺寸 ```php public function small(); public function mini(); public function large(); ``` ### 表单支持组件的方法 ```php public function boolean(string $name, string $label = ''); public function text(string $name, string $label = ''); public function password(string $name, string $label = ''); public function number(string $name, string $label = ''); public function datePicker(string $name, string $label = ''); public function timePicker(string $name, string $label = ''); public function slider(string $name, string $label = ''); public function select(string $name, string $label = ''); public function rate(string $name, string $label = ''); public function cascader(string $name, string $label = ''); public function checkbox(string $name, string $label = ''); public function textarea(string $name, string $label = ''); public function hidden(string $name, string $label = ''); public function url(string $name, string $label = ''); public function tree(string $name, string $label = ''); public function group(string $name, string $label = '', $callback); public function colorPicker(string $name, string $label = ''); public function button(string $name, string $label = ''); public function email(string $name, string $label = ''); public function year(string $name, string $label = ''); public function month(string $name, string $label = ''); public function week(string $name, string $label = ''); public function date(string $name, string $label = ''); public function datetime(string $name, string $label = ''); public function datetimeRange(string $name, string $label = ''); public function dateRange(string $name, string $label = ''); public function dates(string $name, string $label = ''); public function subForm(string $name, string $label = '', $callback); public function upload(string $name, string $label = ''); public function iconSelect(string $name, string $label = ''); public function richText(string $name, string $label = ''); public function grid($callback); public function flex($callback); public function row($callback); public function col($callback); public function radio(string $name, string $label = ''); public function selectOptions(string $name, string $label = ''); ``` ## 安装 ```shell composer require catchadmin/form ``` --- --- url: /docs/forms/component.md --- # 表单基类组件 基类组件是所有组件的基础,组件内一些方法,适合所有子类组件使用 以下是将你提供的 PHP 代码转换为 Markdown 格式的介绍文档: ## 基本方法 ### 设置信息提示 ```php public function info(string $info, string $position = 'left'): static ``` 设置信息提示。 * **参数** * `string $info`: 信息内容。 * `string $position`: 信息位置(默认为 'left')。 * **返回**: 当前实例。 *** ### 设置前缀 ```php public function prefix(string|array $prefix): static ``` 设置前缀。 * **参数** * `string|array $prefix`: 前缀内容。 * **返回**: 当前实例。 *** ### 设置后缀 ```php public function suffix(string|array $suffix): static ``` 设置后缀。 * **参数** * `string|array $suffix`: 后缀内容。 * **返回**: 当前实例。 *** ### 启用组件缓存 ```php public function cache(): static ``` 启用组件缓存。 * **返回**: 当前实例。 *** ### 设置标签宽度 ```php public function labelWidth(int $width): static ``` 设置标签宽度。 * **参数** * `int $width`: 标签宽度(单位为像素)。 * **返回**: 当前实例。 *** ### 设置组件样式 ```php public function style(array $style): static ``` 设置组件样式。 * **参数** * `array $style`: 样式数组。 * **返回**: 当前实例。 *** ### 设置默认值 ```php public function defaultValue(mixed $value): static ``` 设置组件的默认值。 * **参数** * `mixed $value`: 默认值。 * **返回**: 当前实例。 *** ### 设置为原生组件 ```php public function native(): static ``` 设置组件为原生生成,不嵌套在 `FormItem` 中。 * **返回**: 当前实例。 *** ### 设置 CSS 类 ```php public function class(array|string $class): static ``` 设置组件的 CSS 类。 * **参数** * `array|string $class`: CSS 类名。 * **返回**: 当前实例。 *** ### 设置插槽名称 ```php public function slot(string $slot): static ``` 设置插槽名称。 * **参数** * `string $slot`: 插槽名称。 * **返回**: 当前实例。 *** ### 设置为必填项 ```php public function required(): static ``` 设置组件为必填项。 * **返回**: 当前实例。 *** ### 隐藏组件 ```php public function hide(): static ``` 隐藏组件。 * **返回**: 当前实例。 *** ### 显示组件 ```php public function show(): static ``` 显示组件。 * **返回**: 当前实例。 *** ### 设置双向绑定属性 ```php public function sync(string|array $sync): static ``` 设置需要双向绑定的属性名称。 * **参数** * `string|array $sync`: 属性名称或名称数组。 * **返回**: 当前实例。 *** ### 设置事件名称 ```php public function emits(string|array $emits): static ``` 设置组件发出的事件名称。 * **参数** * `string|array $emits`: 事件名称或名称数组。 * **返回**: 当前实例。 *** ### emit Change 事件 ```php public function emitChange(): static ``` 发出 `change` 事件。 * **返回**: 当前实例。 *** ### emit 点击事件 ```php public function emitClick(): static ``` 发出 `click` 事件。 * **返回**: 当前实例。 *** ### emit 焦点事件 ```php public function emitBlur(): static ``` 发出 `blur` 事件。 * **返回**: 当前实例。 *** ### 自定义事件前缀 ```php public function emitPrefix(string $prefix): static ``` 自定义组件 `emit` 事件的前缀。 * **参数** * `string $prefix`: 前缀字符串。 * **返回**: 当前实例。 *** ### 设置为组件 ```php public function asComponent(): static ``` 将当前实例设置为组件。 * **返回**: 当前实例。 *** ### 配置字段变化触发更新 ```php public function link(string|array $link): static ``` 配置哪些字段变化时会触发当前组件的更新回调。 * **参数** * `string|array $link`: 字段名称或名称数组。 * **返回**: 当前实例。 *** ### 设置属性 ```php public function prop(string $key, mixed $value): static ``` 设置组件的 `props` 属性。 * **参数** * `string $key`: 属性名。 * `mixed $value`: 属性值。 * **返回**: 当前实例。 *** ### 批量设置属性 ```php public function props(array $props): static ``` 批量设置组件的 `props` 属性。 * **参数** * `array $props`: 属性数组。 * **返回**: 当前实例。 *** ### 指定选项填充目标 ```php public function optionsTo(string $to = 'data'): static ``` 指定选项填充到 `props` 字段。 * **参数** * `string $to`: 目标字段(默认为 'data')。 * **返回**: 当前实例。 *** ### 禁用组件 ```php public function disable(): static ``` 禁用组件。 * **返回**: 当前实例。 *** ### 加载数据 ```php public function loadData(string $attr, string $to): static ``` 设置加载数据的属性和目标。 * **参数** * `string $attr`: 数据属性。 * `string $to`: 目标字段。 * **返回**: 当前实例。 *** ## 组件验证规则 详细规则请查看[验证规则](./rules.md) ```php public function validates(string|array|ValidateInterface $validate): static ``` ## 联动控制 ## 当等于 ```php public function whenEqual(mixed $value, callable $callback): static ``` * **参数**: * `mixed $value`: 要比较的值。 * `callable $callback`: 当条件满足时调用的回调函数。 * **返回**: `static` - 返回当前对象实例。 * **描述**: 当当前值等于指定值时,执行回调函数。 *** ## 当不等于 ```php public function whenNotEqual(mixed $value, callable $callback): static ``` * **参数**: * `mixed $value`: 要比较的值。 * `callable $callback`: 当条件满足时调用的回调函数。 * **返回**: `static` - 返回当前对象实例。 * **描述**: 当当前值不等于指定值时,执行回调函数。 *** ## 当小于 ```php public function whenLt(mixed $value, callable $callback): static ``` * **参数**: * `mixed $value`: 要比较的值。 * `callable $callback`: 当条件满足时调用的回调函数。 * **返回**: `static` - 返回当前对象实例。 * **描述**: 当当前值小于指定值时,执行回调函数。 *** ## 当小于或等于 ```php public function whenLte(mixed $value, callable $callback): static ``` * **参数**: * `mixed $value`: 要比较的值。 * `callable $callback`: 当条件满足时调用的回调函数。 * **返回**: `static` - 返回当前对象实例。 * **描述**: 当当前值小于或等于指定值时,执行回调函数。 *** ## 当大于 ```php public function whenGt(mixed $value, callable $callback): static ``` * **参数**: * `mixed $value`: 要比较的值。 * `callable $callback`: 当条件满足时调用的回调函数。 * **返回**: `static` - 返回当前对象实例。 * **描述**: 当当前值大于指定值时,执行回调函数。 *** ## 当大于或等于 ```php public function whenGte(mixed $value, callable $callback): static ``` * **参数**: * `mixed $value`: 要比较的值。 * `callable $callback`: 当条件满足时调用的回调函数。 * **返回**: `static` - 返回当前对象实例。 * **描述**: 当当前值大于或等于指定值时,执行回调函数。 *** ## 当在集合中 ```php public function whenIn(mixed $value, callable $callback): static ``` * **参数**: * `mixed $value`: 要检查的值。 * `callable $callback`: 当条件满足时调用的回调函数。 * **返回**: `static` - 返回当前对象实例。 * **描述**: 当当前值在指定的集合中时,执行回调函数。 *** ## 当不在集合中 ```php public function whenNotIn(mixed $value, callable $callback): static ``` * **参数**: * `mixed $value`: 要检查的值。 * `callable $callback`: 当条件满足时调用的回调函数。 * **返回**: `static` - 返回当前对象实例。 * **描述**: 当当前值不在指定的集合中时,执行回调函数。 *** ## 当在数组中 ```php public function whenInArray(mixed $value, callable $callback): static ``` * **参数**: * `mixed $value`: 要检查的值。 * `callable $callback`: 当条件满足时调用的回调函数。 * **返回**: `static` - 返回当前对象实例。 * **描述**: 当当前值在指定的数组中时,执行回调函数。 *** ## 当不在数组中 ```php public function whenNotInArray(mixed $value, callable $callback): static ``` * **参数**: * `mixed $value`: 要检查的值。 * `callable $callback`: 当条件满足时调用的回调函数。 * **返回**: `static` - 返回当前对象实例。 * **描述**: 当当前值不在指定的数组中时,执行回调函数。 *** ## 当在范围内 ```php public function whenBetween(mixed $value, callable $callback): static ``` * **参数**: * `mixed $value`: 要检查的值。 * `callable $callback`: 当条件满足时调用的回调函数。 * **返回**: `static` - 返回当前对象实例。 * **描述**: 当当前值在指定的范围之间时,执行回调函数。 *** ## 当不在范围内 ```php public function whenNotBetween(mixed $value, callable $callback): static ``` * **参数**: * `mixed $value`: 要检查的值。 * `callable $callback`: 当条件满足时调用的回调函数。 * **返回**: `static` - 返回当前对象实例。 * **描述**: 当当前值不在指定的范围之间时,执行回调函数。 *** ## 当为空 ```php public function whenEmpty(callable $callback): static ``` * **参数**: * `callable $callback`: 当条件满足时调用的回调函数。 * **返回**: `static` - 返回当前对象实例。 * **描述**: 当当前值为空时,执行回调函数。 *** ## 当不为空 ```php public function whenNotEmpty(callable $callback): static ``` * **参数**: * `callable $callback`: 当条件满足时调用的回调函数。 * **返回**: `static` - 返回当前对象实例。 * **描述**: 当当前值不为空时,执行回调函数。 *** ## 当满足条件 ```php public function when(string $condition, mixed $value, $callback): static ``` * **参数**: * `string $condition`: 条件字符串。 * `mixed $value`: 要比较的值。 * `$callback`: 当条件满足时调用的回调函数。 * **返回**: `static` - 返回当前对象实例。 * **描述**: 根据指定条件创建一个控制规则,并执行回调函数。 --- --- url: /docs/forms/rules.md --- # 表单规则 动态表单内置了多种表单验证规则,具体有以下规则和说明 ## 示例 ```php // 必须验证 array 类型和包含字母和数字 $form->text('test', 'test') ->maxlength(30)->showWordLimit() ->validates(['alpha_num', 'arr']); ``` ```php // 包含字母和数字 $form->text('test', 'test') ->maxlength(30)->showWordLimit() ->validates('alpha_num'); ``` ```php // 包含字母和数字 $form->text('test', 'test') ->maxlength(30)->showWordLimit() ->validates(['alpha_num' => '自定义错误信息']); ``` ```php // 使用正则自定义规则 $form->text('test', 'test') ->maxlength(30)->showWordLimit() ->validates([Pattern::make('只允许数字')->pattern('^[\d]+$')]); ``` ```php // 使用正则自定义规则 $form->text('test', 'test') ->maxlength(30)->showWordLimit() ->validates(Pattern::make('只允许数字')->pattern('^[\d]+$')); ``` ## 内置规则 ### alpha 只包含字母 ### alpha\_dash 只包含字母、数字、破折号( - )和下划线( \_ ) ### alpha\_num 包含字母和数字 ### arr 只允许数组类型 ### boolean 只允许 bool 类型 ### date 只允许 date 类型 ### decimal 只允许浮点类型 ### enum 只允许枚举类型 ### str 只允许字符类型 ### url 只允许 URL 类型 ### email 邮箱格式不正确 ### integer 数据只能是整型 ### ip ip 地址格式不正确 ### ipv4 ipv4 地址格式不正确 ### numeric 必须是数字 ### mobile 手机号格式不正确 ### chinese\_character 只允许中文 ### strong\_password 必须包含大小写字母和数字的组合,不能使用特殊字符,长度在 8-20 之间 ### password 以字母开头,长度在 6~18 之间,只能包含字母、数字和下划线 ### idcard 身份证格式不正确 ### pattern 自定义验证规则,支持正则 ```php $form->text('test', 'test')->maxlength(30)->showWordLimit() ->validates([ Pattern::make('只允许数字')->pattern('^[\d]+$') ]); ``` --- --- url: /docs/forms/develop.md --- # 开发 为了更好的介绍,文档将如何开发提到最前面,组件详细使用可以在对应组件页面了解到。目前开发一些案列正在进行中,后续继续补充 ## 入门 首先创建一个简单的角色表单 ```php use CatchForm\Components\Form; class RoleForm { public function form() { return Form::make(function (Form $form) { $form->text('role_name', '角色名称')->required(); $form->text('identify', '角色显示名称')->required(); $form->text('description', '角色描述')->required(); }); } } ``` * 使用 `Form` 组件创建 `$form` 对象 * 使用 `make` 方法 * 接受一个`匿名函数`,里面是对应表单的内容 ## 创建添加权限表单 ```php public function form() { return Form::make(function (Form $form){ $form->row(function (Form $form){ $form->col( function (Form $form){ $form->radio('type', '菜单类型')->required()->asButton()->options(MenuType::class) ->defaultValue(1) // 目录 ->whenEqual(MenuType::Top->value(), function (Control $control){ $control->show([ 'permission_name', 'icon', 'module', 'component', 'route', 'hidden', 'redirect', 'sort', 'keepalive' ]); }) ->whenNotEqual(MenuType::Top->value(), function (Control $control){ $control->hide(['parent_id', 'redirect']); }) ->whenEqual(MenuType::Top->value(), function (Control $control){ $control->required(['permission_name', 'module', 'route']); }) // 菜单操作 ->whenEqual(MenuType::Menu->value(), function (Control $control){ $control->show([ 'permission_name', 'icon', 'module', 'component', 'route', 'hidden', 'redirect', 'sort', 'keepalive', 'select_permission_mark', 'active_menu' ]); }) ->whenEqual(MenuType::Menu->value(), function (Control $control){ $control->required([ 'permission_name', 'module', 'route', 'select_permission_mark', 'component', 'parent_id' ]); }) // 按钮操作 ->whenEqual(MenuType::Action->value(), function (Control $control){ $control->show(['permission_name', 'text_permission_mark']); }) ->whenEqual(MenuType::Action->value(), function (Control $control){ $control->required(['permission_name', 'text_permission_mark', 'parent_id']); }) ->emitChange(); $form->text('permission_name', '菜单名称')->maxlength(30)->showWordLimit(); $form->select('module', '所属模块')->options((new Modules())->get())->emitChange(); $form->text('route', '路由Path')->maxlength(30)->showWordLimit()->required(); $form->text('redirect', 'Redirect')->maxlength(50)->showWordLimit(); $form->number('sort', '排序')->min(0)->max(999999)->defaultValue(1); })->span12(); $form->col(function (Form $form){ $form->cascader('parent_id', '上级菜单')->optionsTo('options')->options( \Modules\Permissions\Models\Permissions::query() ->whereIn('type', [ MenuType::Menu->value, MenuType::Top->value ])->get(['id as value', 'permission_name as label', 'parent_id'])->toTree(id: 'value') )->checkStrictly(); $form->selectOptions('permission_mark', '权限标识') ->alias('select_permission_mark') ->api('controllers'); $form->text('permission_mark', '权限标识')->alias('text_permission_mark'); $form->iconSelect('icon', '选择icon')->class('w-full'); $form->selectOptions('component', '所属组件')->api('components'); $form->radio('hidden', 'Hidden')->options(Status::class)->defaultValue(Status::Enable->value()); $form->radio('keepalive', 'Keepalive')->options(Status::class)->defaultValue(Status::Enable->value()); })->span12(); }); $form->text('active_menu', '激活菜单') ->info('如果是访问内页的菜单路由,例如创建文章 create/post, 虽然它隶属于文章列表,但实际上并不会嵌套在文章列表路由里 而是单独的一个路由,并且是不显示在左侧菜单的。所以在访问它的时候,需要左侧菜单高亮,则需要设置该参数'); }); } ``` ### 前端表单生成代码 ```vue ``` 如下图显示 ![laravel admin catchadmin 动态表单](https://image.catchadmin.com/202412221242490.png) ## 分栏布局 有时候表单需要分栏布局,显示双栏布局 ```php return Form::make(function (Form $form){ $form->row(function (Form $form){ $form->col( function (Form $form){ $form->text('left', '左栏目')->maxlength(30)->showWordLimit(); })->span12(); $form->col(function (Form $form){ $form->text('right', '右栏目')->alias('text_permission_mark'); }) // span 12 ->span12(); }); }); ``` 显示效果如下 ![laravel admin catchadmin 动态表单 分栏布局](https://image.catchadmin.com/202412221246076.png) ### 三栏布局 ```php return Form::make(function (Form $form){ $form->row(function (Form $form){ $form->col( function (Form $form){ $form->text('left', '左栏目')->maxlength(30)->showWordLimit(); })->span8(); $form->col(function (Form $form){ $form->text('middle', '中间栏')->alias('text_permission_mark'); })->span8(); $form->col(function (Form $form){ $form->text('right', '右栏目')->alias('text_permission_mark'); })->span8(); }); }); ``` ## 表单条件 有时候表单元素之间需要一些状态条件联动,举个简单的示例,还是以上面的示例为例 ```php return Form::make(function (Form $form){ $form->row(function (Form $form){ $form->col( function (Form $form){ $form->text('left', '左栏目')->maxlength(30)->showWordLimit() // 当输入是 `middle` 的时候才会显示中间栏目 ->whenEqual('middle', function (Control $control){ $control->show(['middle']); }); }); $form->col(function (Form $form){ $form->text('middle', '中间栏')->alias('text_permission_mark'); }); $form->col(function (Form $form){ $form->text('right', '右栏目')->alias('text_permission_mark'); }); }); }); ``` > 当输入是 `middle` 的时候才会显示中间栏目 ![laravel admin catchadmin 动态表单 分栏布局](https://image.catchadmin.com/202412221252759.png) ## 表单验证 表单组件内部内置了很多可用规则,下面演示个只允许字母的规则。 ```php return Form::make(function (Form $form){ $form->text('text', '测试')->validates('alpha'); }); ``` ![laravel admin catchadmin 动态表单](https://image.catchadmin.com/202412221255519.png) ### 可用规则 [可用规则,请查看可用规则验证列表](./rules.md) --- --- url: /docs/forms/components/boolean.md --- # Boolean 组件 该组件实际就是 [`Switch` 组件](https://element-plus.org/zh-CN/component/switch.html) 好的,以下是将方法名替换为中文说明后的 `Switches` 类方法文档: ## 方法 ### 设置禁用状态 ```php $this->disabled(true); ``` **参数说明**: * `bool $disabled`: 如果为 `true`,则禁用开关;如果为 `false`,则启用开关。 *** ### 设置宽度 ```php $this->width(100); ``` **参数说明**: * `float $width`: 指定开关的宽度,以像素为单位。 *** ### 设置打开时图标类名 ```php $this->activeIconClass('icon-active'); ``` **参数说明**: * `string $activeIconClass`: 开关打开时的图标类名。设置此项会忽略 `active-text`。 *** ### 设置关闭时图标类名 ```php $this->inactiveIconClass('icon-inactive'); ``` **参数说明**: * `string $inactiveIconClass`: 开关关闭时的图标类名。设置此项会忽略 `inactive-text`。 *** ### 设置打开时文字描述 ```php $this->activeText('开启'); ``` **参数说明**: * `string $activeText`: 开关打开状态时显示的文字。 *** ### 设置关闭时文字描述 ```php $this->inactiveText('关闭'); ``` **参数说明**: * `string $inactiveText`: 开关关闭状态时显示的文字。 *** ### 设置打开时的值 ```php $this->activeValue('on'); ``` **参数说明**: * `string $activeValue`: 开关打开状态时的值。 *** ### 设置关闭时的值 ```php $this->inactiveValue('off'); ``` **参数说明**: * `string $inactiveValue`: 开关关闭状态时的值。 *** ### 设置打开时背景色 ```php $this->activeColor('#00FF00'); ``` **参数说明**: * `string $activeColor`: 开关打开状态时的背景颜色。 *** ### 设置关闭时背景色 ```php $this->inactiveColor('#FF0000'); ``` **参数说明**: * `string $inactiveColor`: 开关关闭状态时的背景颜色。 *** ### 设置 name 属性 ```php $this->name('switch_name'); ``` **参数说明**: * `string $name`: 开关的 `name` 属性值。 --- --- url: /docs/forms/components/cascader.md --- # Cascader 组件 对应 ElementPlus [Cascader 级联组件](https://element-plus.org/zh-CN/component/cascader.html) 级联组件目前主要在后台用于父级组件,例如权限菜单选择等功能上,下面的功能演示主要使用 `permissions` 权限菜单表作为数据源演示 好的,以下是去掉方法说明后面参数类型的中文文档: # 方法 ### 配置选项 ```php $this->props(['key' => 'value']); ``` 配置选项,具体见下表。 *** ### 设置选项分隔符 ```php $this->separator(','); ``` 选项分隔符。 *** ### 自定义浮层类名 ```php $this->popperClass('custom-class'); ``` 自定义浮层类名。 *** ### 设置输入框占位文本 ```php $this->placeholder('请输入内容'); ``` 输入框占位文本。 *** ### 设置禁用状态 ```php $this->disabled(true); ``` 是否禁用。 *** ### 是否支持清空选项 ```php $this->clearable(true); ``` 是否支持清空选项。 *** ### 设置次级菜单的展开方式 ```php $this->expandTrigger('click'); ``` 次级菜单的展开方式。 *** ### 是否显示选中值的完整路径 ```php $this->showAllLevels(true); ``` 输入框中是否显示选中值的完整路径。 *** ### 是否可搜索选项 ```php $this->filterable(true); ``` 是否可搜索选项。 *** ### 设置去抖延迟 ```php $this->debounce(300.0); ``` 搜索关键词输入的去抖延迟,毫秒。 *** ### 设置尺寸 ```php $this->size('medium'); ``` --- --- url: /docs/forms/components/checkbox.md --- # Checkbox 组件 Element Plus [Checkbox 多选框组件](https://element-plus.org/zh-CN/component/checkbox.html) 好的,以下是去掉方法说明后面参数类型的中文文档: # 方法说明 ### 设置尺寸 ```php $this->size('medium'); ``` 多选框组尺寸,仅对按钮形式的 Checkbox 或带有边框的 Checkbox 有效,可选值: medium / small / mini。 *** ### 设置禁用状态 ```php $this->disabled(true); ``` 是否禁用,默认值: false。 *** ### 设置最小可勾选数量 ```php $this->min(1); ``` 可被勾选的 checkbox 的最小数量。 *** ### 设置最大可勾选数量 ```php $this->max(5); ``` 可被勾选的 checkbox 的最大数量。 *** ### 设置文本颜色 ```php $this->textColor('#ff0000'); ``` 按钮形式的 Checkbox 激活时的文本颜色。 *** ### 设置填充色 ```php $this->fill('#00ff00'); ``` 按钮形式的 Checkbox 激活时的填充色和边框色。 --- --- url: /docs/forms/components/col.md --- # Col 组件 ## 概述 `Col` 类用于创建表单中的列布局。它继承自 `FormComponent`,并提供了不同的列宽度设置。 ## 使用方法 ### 设置列宽度 * **设置宽度为 4** ```php public function span4(): static ``` 返回当前实例,设置列宽度为 4。 * **设置宽度为 6** ```php public function span6(): static ``` 返回当前实例,设置列宽度为 6。 * **设置宽度为 8** ```php public function span8(): static ``` 返回当前实例,设置列宽度为 8。 * **设置宽度为 12** ```php public function span12(): static ``` 返回当前实例,设置列宽度为 12。 ### 设置列的具体宽度 ```php protected function span(int $span): static ``` * **参数**: * `int $span`: 列宽度值。 * **返回**: 返回当前实例。 ## 示例 ```php $col = new Col(function($form) { // 在这里定义表单项 }); $col->span4(); // 设置列宽为 4 ``` ## 说明 * `Col` 类通过回调函数构造表单,并允许用户设置不同的列宽度,以便灵活控制表单布局。 * 使用 `span` 方法可以设置列的具体宽度,支持的值通常为 4, 6, 8, 和 12。 --- --- url: /docs/forms/components/colorPicker.md --- # ColorPicker 组件 ElementPlus [颜色选择组件](https://element-plus.org/zh-CN/component/color-picker.html) 以下是去掉方法说明后面参数类型的中文文档: # 方法说明 ### 设置尺寸 ```php $this->size('medium'); ``` 尺寸,可选值: medium / small / mini。 *** ### 设置禁用状态 ```php $this->disabled(true); ``` 是否禁用,默认值: false。 *** ### 设置是否支持透明度选择 ```php $this->showAlpha(true); ``` 是否支持透明度选择,默认值: false。 *** ### 设置颜色格式 ```php $this->colorFormat('hex'); ``` 写入 v-model 的颜色的格式,可选值: hsl / hsv / hex / rgb。 *** ### 设置下拉框类名 ```php $this->popperClass('custom-class'); ``` 下拉框的类名。 *** ### 设置预定义颜色 ```php $this->predefine(['#ff0000', '#00ff00']); ``` 预定义颜色。 --- --- url: /docs/forms/components/date.md --- # 日期 继承 [DatePicker 组件](./datePicker.md) ```php Date::make('date', '时间组件') ``` --- --- url: /docs/forms/components/datePicker.md --- # DatePicker 组件 [ElementPlus DatePicker 组件](https://element-plus.org/zh-CN/component/date-picker.html) 以下是去掉方法说明后面参数类型的中文文档,方法标题不使用反引号: # 方法说明 ### 设置只读 ```php $this->readonly(true); ``` 只读。 *** ### 设置禁用状态 ```php $this->disabled(true); ``` 禁用。 *** ### 设置可编辑状态 ```php $this->editable(true); ``` 文本框可输入。 *** ### 设置是否显示清除按钮 ```php $this->clearable(true); ``` 是否显示清除按钮。 *** ### 设置输入框尺寸 ```php $this->size('medium'); ``` 输入框尺寸。 *** ### 设置占位内容 ```php $this->placeholder('请输入内容'); ``` 非范围选择时的占位内容。 *** ### 设置开始日期占位内容 ```php $this->startPlaceholder('开始日期'); ``` 范围选择时开始日期的占位内容。 *** ### 设置结束日期占位内容 ```php $this->endPlaceholder('结束日期'); ``` 范围选择时结束日期的占位内容。 *** ### 设置显示类型 ```php $this->type('date'); ``` 显示类型。 *** ### 设置输入框格式 ```php $this->format('YYYY-MM-DD'); ``` 显示在输入框中的格式。 *** ### 设置对齐方式 ```php $this->align('center'); ``` 对齐方式。 *** ### 设置下拉框类名 ```php $this->popperClass('custom-class'); ``` DatePicker 下拉框的类名。 *** ### 设置选择器特有的选项 ```php $this->pickerOptions($options); ``` 当前时间日期选择器特有的选项。 *** ### 设置范围选择分隔符 ```php $this->rangeSeparator('至'); ``` 选择范围时的分隔符。 *** ### 设置默认值 ```php $this->defaultValue('2023-01-01'); ``` 可选,选择器打开时默认显示的时间。 *** ### 设置范围选择时的默认时间 ```php $this->defaultTime(['12:00', '18:00']); ``` 范围选择时选中日期所使用的当日内具体时刻。 *** ### 设置绑定值的格式 ```php $this->valueFormat('YYYY-MM-DD'); ``` 可选,绑定值的格式。不指定则绑定值为 Date 对象。 *** ### 设置原生属性 ```php $this->name('date-picker'); ``` 原生属性。 *** ### 设置取消联动 ```php $this->unlinkPanels(true); ``` 在范围选择器里取消两个日期面板之间的联动。 *** ### 设置自定义头部图标类名 ```php $this->prefixIcon('custom-icon'); ``` 自定义头部图标的类名。 *** ### 设置自定义清空图标类名 ```php $this->clearIcon('custom-clear-icon'); ``` 自定义清空图标的类名。 *** ### 设置是否触发表单校验 ```php $this->validateEvent(true); ``` 输入时是否触发表单的校验。 --- --- url: /docs/forms/components/dateRange.md --- # 时间区间组件 继承 [DatePicker 组件](./datePicker.md) ```php DateRange::make('daterange', '时间区间组件') ``` --- --- url: /docs/forms/components/dates.md --- # 多选日期 继承 [DatePicker 组件](./datePicker.md) ```php Dates::make('Dates', 'Dates 组件') ``` --- --- url: /docs/forms/components/datetime.md --- # Datetime 组件 继承 [DatePicker 组件](./datePicker.md) ```php Datetime::make('datetime', 'Datetime 组件') ``` --- --- url: /docs/forms/components/datetimeRange.md --- # 时间区间组件 继承 [DatePicker 组件](./datePicker.md) ```php DatetimeRange::make('datetime_range', '时间区间组件') ``` --- --- url: /docs/forms/components/email.md --- # 邮件组件 邮件组件时间是由文本组件包装而来 ## 使用 ```php Email::make('email', '邮箱组件') ``` 其他用法请查看 [文本组件](text.md) --- --- url: /docs/forms/components/group.md --- # 子表单组件 以下是去掉方法说明后面参数类型的中文文档,方法标题不使用反引号: # 方法说明 ### 设置禁用状态 ```php $this->disabled(true); ``` 是否禁用。 *** ### 设置字段 ```php $this->field('field-name'); ``` 只获取子表单中此字段。 *** ### 设置默认展开项数 ```php $this->expand(3); ``` 子表单默认展开几项。 *** ### 设置子表单选项配置 ```php $this->options($options); ``` 子表单的 option 配置。 *** ### 设置操作按钮显示状态 ```php $this->button(true); ``` 是否显示操作按钮。 *** ### 设置最多添加项数 ```php $this->max(5); ``` 最多添加几项。 *** ### 设置最少添加项数 ```php $this->min(1); ``` 最少添加几项。 *** ### 设置子表单的值 ```php $this->modelValue($values); ``` 子表单的值。 *** ### 设置新增子表单的默认值 ```php $this->defaultValue($default); ``` 设置新增子表单的默认值。 *** ### 设置顺序调整按钮显示状态 ```php $this->sortBtn(true); ``` 是否显示顺序调整按钮。 --- --- url: /docs/forms/components/hidden.md --- # Hidden 组件 ```php Hidden::make('hidden', '隐藏组件') ``` --- --- url: /docs/forms/components/iconSelect.md --- # 图标选择器 ## 基本使用 ```php IconSelect::make('icon', '选择icon')->class('w-full'); ``` --- --- url: /docs/forms/components/month.md --- # 月份组件 继承 [DatePicker 组件](./datePicker.md) ```php Month::make('month', '月份组件'); ``` --- --- url: /docs/forms/components/number.md --- # 数字组件 [ElementPlus Input Number 组件](https://element-plus.org/zh-CN/component/input-number.html) 以下是去掉方法说明后面参数类型的中文文档,方法标题不使用反引号: # 方法说明 ### 设置尺寸 ```php $this->size('medium'); ``` 尺寸,可选值: medium / small / mini。 *** ### 设置禁用状态 ```php $this->disabled(true); ``` 是否禁用,默认值: false。 *** ### 设置控制按钮使用状态 ```php $this->controls(true); ``` 是否使用控制按钮,默认值: true。 *** ### 设置控制按钮位置 ```php $this->controlsPosition('right'); ``` 控制按钮位置,默认值: right。 *** ### 设置原生属性 ```php $this->name('input-name'); ``` 原生属性。 *** ### 设置输入框关联的 label 文字 ```php $this->label('输入标签'); ``` 输入框关联的 label 文字。 *** ### 设置计数器允许的最小值 ```php $this->min(0); ``` 设置计数器允许的最小值。 *** ### 设置计数器允许的最大值 ```php $this->max(100); ``` 设置计数器允许的最大值。 *** ### 设置计数器步长 ```php $this->step(1); ``` 计数器步长。 *** ### 设置数值精度 ```php $this->precision(2); ``` 数值精度。 *** ### 设置输入框占位文本 ```php $this->placeholder('请输入内容'); ``` 输入框占位文本。 --- --- url: /docs/forms/components/password.md --- # Password 组件 密码组件也是有 Input 包装而来 ## 基础使用 ```php $form = new Form(); return $form->make(new Roles(), function (Form $form) { $form->password('password', '密码'); })->labelWidth(120); ``` ## 强度密码 ```php $form = new Form(); return $form->make(new Roles(), function (Form $form) { $form->password('password', '密码')->stronger(); })->labelWidth(120); ``` ## 显示密码 ```php $form = new Form(); return $form->make(new Roles(), function (Form $form) { $form->password('password', '密码')->stronger() ->show(); })->labelWidth(120); ``` --- --- url: /docs/forms/components/radio.md --- # Radio 组件 [ElementPlus Radio 组件](https://element-plus.org/zh-CN/component/radio.html) 以下是去掉方法说明后面参数类型的中文文档,方法标题不使用反引号: # 方法说明 ### 设置多选框组尺寸 ```php $this->size('medium'); ``` 多选框组尺寸,仅对按钮形式的 Radio 或带有边框的 Radio 有效,可选值: medium / small / mini。 *** ### 设置禁用状态 ```php $this->disabled(true); ``` 是否禁用,默认值: false。 *** ### 设置激活时的文本颜色 ```php $this->textColor('#ff0000'); ``` 按钮形式的 Radio 激活时的文本颜色。 *** ### 设置激活时的填充色和边框色 ```php $this->fill('#00ff00'); ``` 按钮形式的 Radio 激活时的填充色和边框色。 --- --- url: /docs/forms/components/rate.md --- # Rate 评分组件 [ElementPlus 评分组件](https://element-plus.org/zh-CN/component/rate.html) 以下是去掉方法说明后面参数类型的中文文档,方法标题不使用反引号: # 方法说明 ### 设置最大分值 ```php $this->max(5); ``` 最大分值,默认值: 5。 *** ### 设置只读状态 ```php $this->disabled(true); ``` 是否为只读,默认值: false。 *** ### 设置是否允许半选 ```php $this->allowHalf(true); ``` 是否允许半选,默认值: false。 *** ### 设置低分和中等分数的界限值 ```php $this->lowThreshold(2); ``` 低分和中等分数的界限值,值本身被划分在低分中,默认值: 2。 *** ### 设置高分和中等分数的界限值 ```php $this->highThreshold(4); ``` 高分和中等分数的界限值,值本身被划分在高分中,默认值: 4。 *** ### 设置 icon 的颜色 ```php $this->colors(['#F7BA2A', '#F7BA2A', '#F7BA2A']); ``` icon 的颜色。若传入数组,共有 3 个元素,为 3 个分段所对应的颜色;若传入对象,可自定义分段,键名为分段的界限值,键值为对应的颜色,默认值: \['#F7BA2A', '#F7BA2A', '#F7BA2A']。 *** ### 设置未选中 icon 的颜色 ```php $this->voidColor('#C6D1DE'); ``` 未选中 icon 的颜色,默认值: #C6D1DE。 *** ### 设置只读时未选中 icon 的颜色 ```php $this->disabledVoidColor('#EFF2F7'); ``` 只读时未选中 icon 的颜色,默认值: #EFF2F7。 *** ### 设置 icon 的类名 ```php $this->iconClasses(['el-icon-star-on', 'el-icon-star-on', 'el-icon-star-on']); ``` icon 的类名。若传入数组,共有 3 个元素,为 3 个分段所对应的类名;若传入对象,可自定义分段,键名为分段的界限值,键值为对应的类名,默认值: \['el-icon-star-on', 'el-icon-star-on', 'el-icon-star-on']。 *** ### 设置未选中 icon 的类名 ```php $this->voidIconClass('el-icon-star-off'); ``` 未选中 icon 的类名,默认值: el-icon-star-off。 *** ### 设置只读时未选中 icon 的类名 ```php $this->disabledVoidIconClass('el-icon-star-on'); ``` 只读时未选中 icon 的类名,默认值: el-icon-star-on。 *** ### 设置是否显示辅助文字 ```php $this->showText(true); ``` 是否显示辅助文字,若为真,则会从 texts 数组中选取当前分数对应的文字内容,默认值: false。 *** ### 设置是否显示当前分数 ```php $this->showScore(true); ``` 是否显示当前分数,show-score 和 show-text 不能同时为真,默认值: false。 *** ### 设置辅助文字的颜色 ```php $this->textColor('#1F2D3D'); ``` 辅助文字的颜色,默认值: #1F2D3D。 *** ### 设置辅助文字数组 ```php $this->texts(['极差', '失望', '一般', '满意', '惊喜']); ``` 辅助文字数组,默认值: \['极差', '失望', '一般', '满意', '惊喜']。 *** ### 设置分数显示模板 ```php $this->scoreTemplate('{value}'); ``` 分数显示模板,默认值: {value}。 --- --- url: /docs/forms/components/richText.md --- # 富文本 富文本组件 ```php RichText::make('description', '菜单描述'); ``` --- --- url: /docs/forms/components/row.md --- # Row 组件 --- --- url: /docs/forms/components/select.md --- # Select 组件 [ElementPlus Select 组件](https://element-plus.org/zh-CN/component/select.html) 以下是去掉方法说明后面参数类型的中文文档,方法标题不使用反引号: # 方法说明 ### 设置是否多选 ```php $this->multiple(true); ``` 是否多选。 *** ### 设置禁用状态 ```php $this->disabled(true); ``` 是否禁用,默认值: false。 *** ### 设置唯一标识的键名 ```php $this->valueKey('id'); ``` 作为 value 唯一标识的键名,绑定值为对象类型时必填。 *** ### 设置输入框尺寸 ```php $this->size('medium'); ``` 输入框尺寸,可选值: medium / small / mini。 *** ### 设置是否可以清空选项 ```php $this->clearable(true); ``` 是否可以清空选项,默认值: false。 *** ### 设置多选模式下是否折叠 Tag ```php $this->collapseTags(true); ``` 多选模式下是否折叠 Tag,默认值: false。 *** ### 设置多选时用户最多可以选择的项目数 ```php $this->multipleLimit(5); ``` 多选时用户最多可以选择的项目数,为 0 则不限制。 *** ### 设置 select input 的 name 属性 ```php $this->name('mySelect'); ``` select input 的 name 属性。 *** ### 设置 select input 的 autocomplete 属性 ```php $this->autocomplete('on'); ``` select input 的 autocomplete 属性。 *** ### 设置占位符 ```php $this->placeholder('请选择'); ``` 占位符。 *** ### 设置是否可搜索 ```php $this->filterable(true); ``` 是否可搜索,默认值: false。 *** ### 设置是否允许用户创建新条目 ```php $this->allowCreate(true); ``` 是否允许用户创建新条目,需配合 filterable 使用,默认值: false。 *** ### 设置是否为远程搜索 ```php $this->remote(true); ``` 是否为远程搜索,默认值: false。 *** ### 设置是否正在从远程获取数据 ```php $this->loading(true); ``` 是否正在从远程获取数据,默认值: false。 *** ### 设置远程加载时显示的文字 ```php $this->loadingText('加载中...'); ``` 远程加载时显示的文字。 *** ### 设置搜索条件无匹配时显示的文字 ```php $this->noMatchText('无匹配结果'); ``` 搜索条件无匹配时显示的文字。 *** ### 设置选项为空时显示的文字 ```php $this->noDataText('无可选项'); ``` 选项为空时显示的文字。 *** ### 设置 Select 下拉框的类名 ```php $this->popperClass('custom-class'); ``` Select 下拉框的类名。 *** ### 设置多选且可搜索时是否保留当前的搜索关键词 ```php $this->reserveKeyword(true); ``` 多选且可搜索时,是否在选中一个选项后保留当前的搜索关键词,默认值: false。 *** ### 设置在输入框按下回车选择第一个匹配项 ```php $this->defaultFirstOption(true); ``` 在输入框按下回车,选择第一个匹配项。需配合 filterable 或 remote 使用,默认值: false。 *** ### 设置是否将弹出框插入至 body 元素 ```php $this->popperAppendToBody(false); ``` 是否将弹出框插入至 body 元素。在弹出框的定位出现问题时,可将该属性设置为 false,默认值: true。 *** ### 设置是否在输入框获得焦点后自动弹出选项菜单 ```php $this->automaticDropdown(true); ``` 对于不可搜索的 Select,是否在输入框获得焦点后自动弹出选项菜单,默认值: false。 --- --- url: /docs/forms/components/selectOptions.md --- # 远程 Select Options 组件 此组件数据,对应 `Common` 模块的 `Repository/Options` 目录的数据 ```php SelectOptions::make('permission_mark', '权限标识')->alias('select_permission_mark')->api('controllers'); ``` --- --- url: /docs/forms/components/slider.md --- # 滑块组件 [ElementPlus 滑块组件](https://element-plus.org/zh-CN/component/slider.html) 以下是去掉方法说明后面参数类型的中文文档,方法标题不使用反引号: # 滑块组件方法说明 ### 设置最小值 ```php $this->min(0); ``` 最小值。 *** ### 设置最大值 ```php $this->max(100); ``` 最大值,默认值: 100。 *** ### 设置禁用状态 ```php $this->disabled(true); ``` 是否禁用,默认值: false。 *** ### 设置步长 ```php $this->step(1); ``` 步长,默认值: 1。 *** ### 设置是否显示输入框 ```php $this->showInput(true); ``` 是否显示输入框,仅在非范围选择时有效,默认值: false。 *** ### 设置输入框控制按钮 ```php $this->showInputControls(true); ``` 在显示输入框的情况下,是否显示输入框的控制按钮,默认值: true。 *** ### 设置输入框的尺寸 ```php $this->inputSize('small'); ``` 输入框的尺寸,可选值: large / medium / small / mini,默认值: small。 *** ### 设置是否显示间断点 ```php $this->showStops(true); ``` 是否显示间断点,默认值: false。 *** ### 设置是否显示 tooltip ```php $this->showTooltip(true); ``` 是否显示 tooltip,默认值: true。 *** ### 设置格式化 tooltip message ```php $this->formatTooltip(function($value) { return "当前值: " . $value; }); ``` 格式化 tooltip message。 *** ### 设置是否为范围选择 ```php $this->range(true); ``` 是否为范围选择,默认值: false。 *** ### 设置是否竖向模式 ```php $this->vertical(true); ``` 是否竖向模式,默认值: false。 *** ### 设置 Slider 高度 ```php $this->height('300px'); ``` Slider 高度,竖向模式时必填。 *** ### 设置屏幕阅读器标签 ```php $this->label('滑块'); ``` 屏幕阅读器标签。 *** ### 设置输入时的去抖延迟 ```php $this->debounce(300); ``` 输入时的去抖延迟,毫秒,仅在 show-input 等于 true 时有效,默认值: 300。 *** ### 设置 tooltip 的自定义类名 ```php $this->tooltipClass('custom-tooltip'); ``` tooltip 的自定义类名。 --- --- url: /docs/forms/components/subForm.md --- --- --- url: /docs/forms/components/text.md --- # 文本组件 [ElementPlus Input 组件](https://element-plus.org/zh-CN/component/input.html) 表单组件这个组件用的是最多的 以下是去掉方法说明后面参数类型的中文文档,方法标题不使用反引号: # 输入框组件方法说明 ### 设置最大输入长度 ```php $this->maxlength(100); ``` 原生属性,最大输入长度。 *** ### 设置最小输入长度 ```php $this->minlength(1); ``` 原生属性,最小输入长度。 *** ### 设置占位文本 ```php $this->placeholder('请输入内容'); ``` 输入框占位文本。 *** ### 设置是否可清空 ```php $this->clearable(true); ``` 是否可清空,默认值: false。 *** ### 设置禁用状态 ```php $this->disabled(true); ``` 禁用,默认值: false。 *** ### 设置输入框尺寸 ```php $this->size('medium'); ``` 输入框尺寸,只在 type!="textarea" 时有效,可选值: medium / small / mini。 *** ### 设置输入框头部图标 ```php $this->prefixIcon('icon-prefix'); ``` 输入框头部图标。 *** ### 设置输入框尾部图标 ```php $this->suffixIcon('icon-suffix'); ``` 输入框尾部图标。 *** ### 设置输入框行数 ```php $this->rows(2); ``` 输入框行数,只对 type="textarea" 有效。 *** ### 设置自适应内容高度 ```php $this->autosize(true); ``` 自适应内容高度,只对 type="textarea" 有效,默认值: false。 *** ### 设置自动补全 ```php $this->autocomplete('off'); ``` 原生属性,自动补全,默认值: off。 *** ### 设置输入框的 name 属性 ```php $this->name('inputName'); ``` 原生属性。 *** ### 设置是否只读 ```php $this->readonly(true); ``` 原生属性,是否只读,默认值: false。 *** ### 设置最大值 ```php $this->max(100); ``` 原生属性,设置最大值。 *** ### 设置最小值 ```php $this->min(0); ``` 原生属性,设置最小值。 *** ### 设置输入字段的合法数字间隔 ```php $this->step(1); ``` 原生属性,设置输入字段的合法数字间隔。 *** ### 设置是否能被用户缩放 ```php $this->resize('none'); ``` 控制是否能被用户缩放,可选值: none, both, horizontal, vertical。 *** ### 设置自动获取焦点 ```php $this->autofocus(true); ``` 原生属性,自动获取焦点,默认值: false。 *** ### 设置表单属性 ```php $this->form('myForm'); ``` 原生属性。 *** ### 设置输入框关联的 label 文字 ```php $this->label('输入框标签'); ``` 输入框关联的 label 文字。 *** ### 设置输入框的 tabindex ```php $this->tabindex(1); ``` 输入框的 tabindex。 *** ### 设置输入时是否触发表单的校验 ```php $this->validateEvent(true); ``` 输入时是否触发表单的校验,默认值: true。 --- --- url: /docs/forms/components/textarea.md --- # Textarea `Textarea` 使用 `text 组件` 包装 ## 基础使用 ```php Textarea::make('component', '组件')->rows(10); ``` --- --- url: /docs/forms/components/timePicker.md --- # TimePicker 组件 # 时间选择器组件方法 ### 设置完全只读 ```php $this->readonly(true); ``` 完全只读,默认值: false。 *** ### 设置禁用状态 ```php $this->disabled(true); ``` 禁用,默认值: false。 *** ### 设置文本框可输入 ```php $this->editable(true); ``` 文本框可输入,默认值: true。 *** ### 设置是否显示清除按钮 ```php $this->clearable(true); ``` 是否显示清除按钮,默认值: true。 *** ### 设置输入框尺寸 ```php $this->size('medium'); ``` 输入框尺寸,可选值: medium / small / mini。 *** ### 设置非范围选择时的占位内容 ```php $this->placeholder('请选择时间'); ``` 非范围选择时的占位内容。 *** ### 设置范围选择时开始日期的占位内容 ```php $this->startPlaceholder('开始时间'); ``` 范围选择时开始日期的占位内容。 *** ### 设置范围选择时结束日期的占位内容 ```php $this->endPlaceholder('结束时间'); ``` 范围选择时结束日期的占位内容。 *** ### 设置是否为时间范围选择 ```php $this->isRange(true); ``` 是否为时间范围选择,仅对 `` 有效,默认值: false。 *** ### 设置是否使用箭头进行时间选择 ```php $this->arrowControl(true); ``` 是否使用箭头进行时间选择,仅对 `` 有效,默认值: false。 *** ### 设置对齐方式 ```php $this->align('left'); ``` 对齐方式,可选值: left / center / right,默认值: left。 *** ### 设置 TimePicker 下拉框的类名 ```php $this->popperClass('custom-popper'); ``` TimePicker 下拉框的类名。 *** ### 设置当前时间日期选择器特有的选项 ```php $this->pickerOptions(['option1' => 'value1']); ``` 当前时间日期选择器特有的选项,默认值: {}。 *** ### 设置选择范围时的分隔符 ```php $this->rangeSeparator('-'); ``` 选择范围时的分隔符,默认值: '-'。 *** ### 设置绑定值的格式 ```php $this->valueFormat('HH:mm:ss'); ``` 可选,仅在 TimePicker 时可用,绑定值的格式。不指定则绑定值为 Date 对象。 *** ### 设置选择器打开时默认显示的时间 ```php $this->defaultValue('12:00'); ``` 可选,选择器打开时默认显示的时间。 *** ### 设置原生属性 name ```php $this->name('timePickerName'); ``` 原生属性。 *** ### 设置自定义头部图标的类名 ```php $this->prefixIcon('el-icon-time'); ``` 自定义头部图标的类名,默认值: el-icon-time。 *** ### 设置自定义清空图标的类名 ```php $this->clearIcon('el-icon-circle-close'); ``` 自定义清空图标的类名,默认值: el-icon-circle-close。 --- --- url: /docs/forms/components/tree.md --- # Tree 组件 [ElementPlus tree 组件](https://element-plus.org/zh-CN/component/tree.html) 以下是去掉方法说明后面参数类型的中文文档,方法标题不使用反引号: # 树型组件方法说明 ### 设置内容为空时展示的文本 ```php $this->emptyText('暂无数据'); ``` 内容为空的时候展示的文本。 *** ### 设置每个树节点的唯一标识属性 ```php $this->nodeKey('id'); ``` 每个树节点用来作为唯一标识的属性,整棵树应该是唯一的。 *** ### 设置配置选项 ```php $this->props(['label' => 'name', 'children' => 'children']); ``` 配置选项,具体看下表。 *** ### 设置是否在第一次展开某个树节点后渲染其子节点 ```php $this->renderAfterExpand(true); ``` 是否在第一次展开某个树节点后才渲染其子节点,默认值: true。 *** ### 设置加载子树数据的方法 ```php $this->load(function ($node, $resolve) { // 加载子树数据的逻辑 }); ``` 加载子树数据的方法,仅当 lazy 属性为 true 时生效。 *** ### 设置树节点内容区的渲染函数 ```php $this->renderContent(function ($h, $context) { // 自定义渲染逻辑 }); ``` 树节点的内容区的渲染函数。 *** ### 设置是否高亮当前选中节点 ```php $this->highlightCurrent(true); ``` 是否高亮当前选中节点,默认值: false。 *** ### 设置是否默认展开所有节点 ```php $this->defaultExpandAll(true); ``` 是否默认展开所有节点,默认值: false。 *** ### 设置点击节点时的展开或收缩行为 ```php $this->expandOnClickNode(true); ``` 是否在点击节点的时候展开或者收缩节点,默认值: true。 *** ### 设置点击节点时的选中行为 ```php $this->checkOnClickNode(true); ``` 是否在点击节点的时候选中节点,默认值: false。 *** ### 设置展开子节点时是否自动展开父节点 ```php $this->autoExpandParent(true); ``` 展开子节点的时候是否自动展开父节点,默认值: true。 *** ### 设置默认展开的节点的 key 数组 ```php $this->defaultExpandedKeys(['key1', 'key2']); ``` 默认展开的节点的 key 的数组。 *** ### 设置节点是否可被选择 ```php $this->showCheckbox(true); ``` 节点是否可被选择,默认值: false。 *** ### 设置复选框的选中行为 ```php $this->checkStrictly(true); ``` 在显示复选框的情况下,是否严格遵循父子不互相关联的做法,默认值: false。 *** ### 设置默认勾选的节点的 key 数组 ```php $this->defaultCheckedKeys(['key1', 'key2']); ``` 默认勾选的节点的 key 的数组。 *** ### 设置当前选中的节点 ```php $this->currentNodeKey('selectedKey'); ``` 当前选中的节点。 *** 对树节点进行筛选时执行的方法,返回 true 表示这个节点可以显示,返回 false 则表示这个节点会被隐藏。 *** ### 设置是否每次只打开一个同级树节点展开 ```php $this->accordion(true); ``` 是否每次只打开一个同级树节点展开,默认值: false。 *** ### 设置相邻级节点间的水平缩进 ```php $this->indent(16); ``` 相邻级节点间的水平缩进,单位为像素,默认值: 16。 *** ### 设置自定义树节点的图标 ```php $this->iconClass('custom-icon'); ``` 自定义树节点的图标。 *** ### 设置是否懒加载子节点 ```php $this->lazy(true); ``` 是否懒加载子节点,需与 load 方法结合使用,默认值: false。 *** ### 设置是否开启拖拽节点功能 ```php $this->draggable(true); ``` 是否开启拖拽节点功能,默认值: false。 --- --- url: /docs/forms/components/upload.md --- # 上传组件 上传组件分为四组方法,对应前端四种上传组件。区分开,可以很好知道业务功能的作用。 ## 上传图片 ```php \CatchForm\Components\Upload::make('上传图片')->image(); ``` ## 上传文件 ```php \CatchForm\Components\Upload::make('上传图片')->files() ``` ## 附件上传 ```php \CatchForm\Components\Upload::make('上传图片')->attach() ``` ## OSS 上传 ```php \CatchForm\Components\Upload::make('上传图片')->oss() ``` ## COS 上传 ```php \CatchForm\Components\Upload::make('上传图片')->cos() ``` --- --- url: /docs/forms/components/url.md --- # 链接组件 ## 基础使用 ```php $form = new Form(); return $form->make(new Roles(), function (Form $form) { $form->url('url', 'URL')->required(); })->labelWidth(120); ``` --- --- url: /docs/forms/components/week.md --- # 时间周组件 继承 [DatePicker 组件](./datePicker.md) ```php Week::make('week', 'week 组件') ``` --- --- url: /docs/forms/components/year.md --- # 时间年份组件 继承 [DatePicker 组件](./datePicker.md) ```php Year::make('week', 'week 组件') ``` --- --- url: /docs/forms/table.md --- # CatchTable 构建 ## 创建表格 要创建一个表格,请使用 API 端点实例化 `Table` 类: ```php use CatchForm\Table\Table; $table = new Table('https://api.example.com/data'); ``` ## 配置表格属性 您可以使用流畅的方法配置表格的各种属性。以下是一些常见的配置示例: ### 设置表格高度 ```php $table->height('400px'); // 设置表格的高度。 ``` ### 设置表格边框 ```php $table->border('1px solid #ccc'); // 设置表格的边框样式。 ``` ### 设置分页 ```php $table->pagination(true) // 启用分页。 ->limit(10) // 设置每页的项目数量。 ->page(1); // 设置当前页码。 ``` ### 设置尺寸 ```php $table->size('large'); // 设置表格的尺寸(例如:'large'、'small')。 ``` ## 添加列 您可以使用 `column` 方法在表格中定义列: ```php $table->column('姓名', 'name') // 添加一个标签为 '姓名',属性为 'name' 的列。 ->column('邮箱', 'email'); // 添加一个标签为 '邮箱',属性为 'email' 的列。 ``` ## 搜索功能 表单构建器允许您为表格添加搜索功能: ```php $table->isShowSearch(true); // 启用搜索功能。 $table->input('按姓名搜索', 'name'); // 添加一个用于按姓名搜索的输入框。 $table->select('按状态过滤', 'status'); // 添加一个用于按状态过滤的选择框。 ``` ## JSON 序列化 `Table` 类实现了 `JsonSerializable` 接口,允许您轻松将表格配置转换为 JSON 格式: ```php $json = json_encode($table); // 将表格配置转换为 JSON 格式。 ``` ## 可用方法 | 方法 | 描述 | | ----------------------------------------------------- | ------------------------------------------ | | `height(string $height)` | 设置表格的高度。 | | `border(string $border)` | 设置表格的边框样式。 | | `size(string $size)` | 设置表格的尺寸(例如:'large'、'small')。 | | `pagination(bool $pagination)` | 启用或禁用分页。 | | `limit(int $limit)` | 设置每页的项目数量。 | | `page(int $page)` | 设置当前页码。 | | `layout(string $layout)` | 设置表格的布局。 | | `sort(array $sort)` | 设置表格的排序选项。 | | `showOperation(bool $isShow)` | 显示或隐藏表格中的操作。 | | `showTools(bool $isShow)` | 显示或隐藏工具栏。 | | `primaryName(string $name)` | 设置主键名称。 | | `rowKey(string $key)` | 设置表格的行键。 | | `defaultParams(array $params)` | 设置表格的默认参数。 | | `destroyConfirm(string $text)` | 设置删除操作的确认文本。 | | `dialog($width, string $height)` | 设置对话框的宽度和高度。 | | `export(string $url, bool $isShow)` | 配置导出功能。 | | `isShowSearch(bool $isShow)` | 显示或隐藏搜索功能。 | | `columns(Closure $fn)` | 使用闭包定义列。 | | `filter(Closure $fn)` | 使用闭包定义过滤器。 | | `jsonSerialize()` | 将表格属性序列化为 JSON。 | | `column(string $label, string $props = '')` | 向表格添加列。 | | `search(string $label)` | 创建一个搜索输入框。 | | `input(string $label, string $name)` | 添加一个输入搜索字段。 | | `select(string $label, string $name)` | 添加一个选择搜索字段。 | | `number(string $label, string $name)` | 添加一个数字搜索字段。 | | `date(string $label, string $name)` | 添加一个日期搜索字段。 | | `datetime(string $label, string $name)` | 添加一个日期时间搜索字段。 | | `range(string $label, string $name, array $children)` | 添加一个范围搜索字段。 | ## 示例 以下是如何创建一个具有各种配置的表格的完整示例: ```php use CatchForm\Table\Table; $table = new Table('https://api.example.com/data'); $table->height('400px') // 设置表格的高度。 ->border('1px solid #ccc') // 设置表格的边框样式。 ->pagination(true) // 启用分页。 ->limit(10) // 设置每页的项目数量。 ->page(1) // 设置当前页码。 ->size('large') // 设置表格的尺寸。 ->showTools(true) // 显示工具栏。 ->primaryName('id') // 设置主键名称。 ->isShowSearch(true) // 启用搜索功能。 ->input('按姓名搜索', 'name') // 添加一个用于按姓名搜索的输入框。 ->select('按状态过滤', 'status') // 添加一个用于按状态过滤的选择框。 ->column('姓名', 'name') // 添加一个标签为 '姓名' 的列。 ->column('邮箱', 'email'); // 添加一个标签为 '邮箱' 的列。 $json = json_encode($table); // 将表格配置转换为 JSON 格式。 ``` --- --- url: /docs/forms/table/column.md --- # CatchTable 表单栏目类文档 ## 概述 `Column` 类是 CatchTable 构建器中的一个核心组件,用于定义表格中的列。该类实现了 `JsonSerializable` 接口,允许将列的配置转换为 JSON 格式。 ## 类定义 ```php namespace CatchForm\Table; use JsonSerializable; class Column implements JsonSerializable { protected array $column = []; public function __construct(string $label, string $props = '') { $this->column['label'] = $label; if ($props) { $this->column['props'] = $props; } } } ``` ## 构造函数 ### `__construct(string $label, string $props = '')` * **参数**: * `label`: 列的标签。 * `props`: 列的属性(可选)。 ## 可用方法 | 方法 | 描述 | | ---------------------------------------------- | -------------------------------------------------- | -------------------- | | `selection(): static` | 设置列为选择列。 | | `type(string $type): static` | 设置列的类型。 | | `expand(): static` | 设置列为扩展列。 | | `width(int | string $width): static` | 设置列的宽度。 | | `slot(string $slot): static` | 设置列的插槽名称。 | | `header(string $header): static` | 设置列的表头。 | | `align(string $align): static` | 设置列的对齐方式。 | | `fixed(string $fixed): static` | 设置列的固定位置(如:'fixed'、'right'、'left')。 | | `sortable(bool | string $sortable = true): static` | 设置列是否可排序。 | | `resizable(bool $resizable): static` | 设置列是否可调整大小。 | | `headerAlign(int | string $align): static` | 设置表头的对齐方式。 | | `show(bool $show): static` | 设置列是否显示。 | | `children(array $columns): static` | 设置子列。 | | `index($index): static` | 设置列的索引。 | | `switch(bool $switch = true): static` | 设置列是否为开关。 | | `ellipsis(bool $ellipsis = true): static` | 设置列是否使用省略文字。 | | `image(bool $image = true): static` | 设置列是否为图片预览。 | | `preview(bool $preview = true): static` | 设置列是否为预览。 | | `tags(bool | array $tag): static` | 设置列的标签。 | | `link(bool $isLink, string $linkText): static` | 设置列为链接。 | | `update(bool $update = true): static` | 设置列是否可更新。 | | `destroy(bool $destroy = true): static` | 设置列是否可删除。 | | `column(string $key, mixed $value): static` | 设置列的属性。 | | `jsonSerialize(): array` | 将列的配置序列化为 JSON 格式。 | ## 示例 以下是使用 `Column` 类的示例: ```php use CatchForm\Table\Column; $column = new Column('姓名', 'name'); $column->width(150) // 设置列宽度 ->sortable(true) // 使列可排序 ->align('center') // 设置列内容居中 ->show(true) // 显示该列 ->tags(['重要', '用户']); // 添加标签 $json = json_encode($column); // 将列配置转换为 JSON 格式 ``` ## JSON 序列化 `jsonSerialize()` 方法实现了 `JsonSerializable` 接口,允许将列的配置序列化为 JSON 格式: ```php public function jsonSerialize(): array { return $this->column; } ``` --- --- url: /docs/forms/table/search.md --- # CatchTable 搜索组件 ## 概述 `Search` 类是 CatchTable 搜索组件,用于定义搜索项。该类实现了 `JsonSerializable` 接口,允许将搜索项的配置转换为 JSON 格式。 ## 类定义 ```php namespace CatchForm\Table; use JsonSerializable; class Search implements JsonSerializable { protected array $item = []; public function __construct(string $label) { $this->item['label'] = $label; } } ``` ## 构造函数 ### `__construct(string $label)` * **参数**: * `label`: 搜索项的标签。 ## 可用方法 | 方法 | 描述 | | ---------------------------------------------- | ------------------------------------ | | `input(string $name): static` | 定义一个文本输入框类型的搜索项。 | | `select(string $name): static` | 定义一个下拉选择框类型的搜索项。 | | `number(string $name): static` | 定义一个数字输入框类型的搜索项。 | | `date(string $name): static` | 定义一个日期选择器类型的搜索项。 | | `datetime(string $name): static` | 定义一个日期时间选择器类型的搜索项。 | | `range(string $name, array $children): static` | 定义一个范围搜索项,并添加子项。 | | `type(string $type, string $name): static` | 设置搜索项的类型和名称。 | | `api(string $api): static` | 设置搜索项的 API 地址。 | | `placeholder(string $placeholder): static` | 设置搜索项的占位符文本。 | | `default(mixed $default): static` | 设置搜索项的默认值。 | | `options(array $options): static` | 设置下拉选择框的选项。 | | `show(array $show): static` | 设置搜索项的显示条件。 | | `props(array $props): static` | 设置搜索项的其他属性。 | | `children(array $children): static` | 设置搜索项的子项。 | | `jsonSerialize(): array` | 将搜索项配置序列化为 JSON 格式。 | ## 示例 以下是使用 `Search` 类的示例: ```php use CatchForm\Table\Search; $search = new Search('姓名'); $search->input('name') // 定义一个输入框搜索项 ->placeholder('请输入姓名') // 设置占位符 ->default('张三') // 设置默认值 ->api('/api/search'); // 设置 API 地址 $json = json_encode($search); // 将搜索配置转换为 JSON 格式 ``` ## JSON 序列化 `jsonSerialize()` 方法实现了 `JsonSerializable` 接口,允许将搜索项的配置序列化为 JSON 格式: ```php public function jsonSerialize(): array { return $this->item; } ``` --- --- url: /docs/5.0/intro.md --- # CatchAdmin V5 介绍 - 专业的 PHP Laravel 后台管理系统 > 基于 Laravel 12.x 和 Element Plus 的现代化 php 开源后台管理 解决方案 `CatchAdmin`是一款基于[Laravel 12.x](https://laravel.com)和[Element Plus](https://element-plus.org)二次开发而成的 PHP 开源后台管理系统。`Laravel` 社区也有许多非常优秀的后台管理系统,例如 `Nova`, 官方出品,当然是收费的,免费的有基于 `Livewire` 的 `Filament`,还有不得不说的 `Laravel Admin`。它采用前后端分离架构,CatchAdmin 集成了 Token 鉴权、权限管理、动态路由、动态表格、分页封装、资源权限、上传下载、代码生成器支持一键导出导入,数据回收站,附件管理的一款模块化框架。`Laravel` 框架仅仅作为 `Api` 输出。将管理系统模块之间的耦合降到了最低限度。每个模块之间都有独立的控制器,路由,模型,数据表。在开发上尽可能将模块之间的影响降到最低,降低了开发上的难度。基于 `CatchAdmin `可以开发 `CMS`,`CRM`,`OA` 等 等系统。也封装了很多实用的工具,提升开发体验。 作为一款专业的 **laravel admin** 解决方案,CatchAdmin 在众多 **PHP 后台开源管理系统** 中脱颖而出: ## 🚀 技术优势 * **现代化架构**: 基于 Laravel 12.x 最新版本,充分利用 PHP 8+ 特性 * **前后端分离**: Vue 3 + Element Plus 前端,Laravel RESTful API 后端 * **模块化设计**: 每个业务模块完全独立,支持按需加载和扩展 * **开箱即用**: 内置完整的权限管理、用户管理、日志系统 ## 快速开始 极速安装项目,五分钟即可构建。详细[安装文档](./start/install.md) ```shell composer create catchadmin/catchadmin cd catchadmin php artisan catch:install ``` ## 功能 * ☑️ **用户管理**:支持用户新增/编辑/删除/禁用、密码重置与基础信息维护;不同用户登录后台可呈现不同首页与可见功能模块 * ☑️ **部门管理**:支持公司/部门/小组多级组织架构配置与维护,树形结构展示,支持层级调整与人员归属管理 * ☑️ **岗位管理**:岗位(职务)统一维护与分配,支持主岗位/多岗位配置,为权限控制与业务流程提供身份基础 * ☑️ **角色管理**:树结构角色体系,支持角色菜单权限、按钮级权限分配与数据权限配置,满足精细化授权需求 * ☑️ **菜单管理**:可视化配置系统菜单、路由与按钮资源,支持排序/层级/隐藏等管理,实现前后端一致的权限控制 * ☑️ **字典管理**:集中维护枚举/状态/类型等基础数据,支持分组与启用禁用,便于统一复用并减少硬编码 * ☑️ **系统配置**:系统常用参数集中管理,支持分类维护与动态读取,配置调整可快速生效,降低运维与二开成本 * ☑️ **操作日志**:记录关键操作与变更轨迹,支持按用户/模块/时间多维检索,便于审计追溯与问题定位 * ☑️ **登录日志**:记录登录历史与访问信息(如时间/IP/设备等,按实现为准),支持查询统计与异常排查 * ☑️ **文件上传**:统一上传能力,支持 `本地`、`七牛云`、`阿里云`、`腾讯云` 等存储方式,按配置灵活切换 * ☑️ **附件管理**:对系统上传的文件/图片等资源集中管理,支持检索、预览与清理维护,避免资源冗余 * ☑️ **数据表维护**:支持数据表碎片清理与优化,并提供数据回收与销毁管理能力,保障系统长期稳定运行 * ☑️ **代码生成**:一键生成前后端代码(`php`、`vue`)及数据库迁移文件,支持直接生成到模块,显著提升开发效率 * ☑️ **支持 Vue 即时渲染**:支持前端 Vue 即时渲染,无需编译即可生效,加快开发调试与迭代速度 * ☑️ **支持插件系统**:插件即 Composer 包,深度融入 Composer 生态,支持模块化扩展与快速集成 * 文档:[CatchAdmin 插件快速开始](https://doc.catchadmin.com/docs/5.0/plugin/quickstart) ## 体验地址 [v5 demo 地址](https://v5.catchadmin.com) \[超管账户] * 账户: `catch@admin.com` * 密码: `catchadmin` \[测试账户] * 账户: `test@admin.com` * 密码: `Testadmin1` ## 💼 适用场景 * **企业后台管理**: 适合中小企业快速搭建内部管理系统 * **SaaS 平台**: 为 SaaS 产品提供标准化的管理后台基础 * **内容管理**: CMS、博客、新闻等内容管理系统 * **电商后台**: 商品管理、订单处理、客户服务等电商场景 * **项目管理**: OA 办公、CRM 客户关系管理等企业应用 ## 架构特性 `CatchAdmin` 聚焦于 PHP Laravel 后台管理 的工程实践,保持前后端分离,让 `Laravel` 只负责标准化的 `RESTful API` 和权限校验,前端则依赖 `Element Plus` 提供可扩展的 UI 组件。这样的模块化设计确保核心业务逻辑与界面层完全解耦,在迭代时能够快速响应复杂的企业需求。 * 灵活的模块拆分:控制器、路由、模型与数据表保持独立,便于按需组合或裁剪,实现面向领域的 laravel 后台 规划。 * 完整的扩展生态:基于 `Laravel` 既有能力和 `CatchAdmin` 封装的工具集,可以平滑接入第三方服务,减少 php 后台管理 项目常见的重复开发成本。 * 企业级运维友好:标准化的接口设计与日志体系便于团队在容器化环境下部署和监控,为长期维护 laravel admin 项目提供保障。 ## 专业版 [专业版本官方地址](https://gitee.com/link?target=https%3A%2F%2Flicense.catchadmin.com) 首先感谢一直以来对 CatchAdmin 开源项目的支持和使用。作为一名开源工作者,我一直致力于开发出功能强大且易于使用的后台管理系统,以帮助您简化业务流程和提升工作效率。然而,由于某些原因,我不得不做出一些调整。为了能够继续开发和维护这个项目,我将推出一款付费的后台管理系统,以确保我能够持续为您提供高质量的服务和支持。 专业版本不会在开源版本做一些破坏性变更,所以当您从开源版本切换到专业版本,不会有任何开发心智负担。但是使用专业版本会有新的组件来配合您的工作。 我深信,付费后台管理系统将为您带来更多的价值和便利,帮助您提升工作效率 ### 📊 核心功能详解 **权限管控**: CatchAdmin 采用业界标准的 RBAC (Role-Based Access Control) 权限模型,支持: * 多角色授权、角色继承 * 菜单权限、按钮权限、数据权限三级管控 * 部门数据隔离、个人数据权限 * API 接口权限验证 **开发效率**: 作为专业的 **laravel 后台** 框架,内置多种开发加速工具: * 一键 CRUD 生成,减少重复代码编写 * 标准化 API 接口规范 * 完整的前端组件库 * 详细的开发文档和示例代码 ## 业务场景 `CatchAdmin` 已在多种业务中验证:以 `CMS` 内容平台为例,团队可以通过可视化菜单与权限配置快速建立内容审核流程;在 `CRM` 或销售管理场景中,借助灵活的岗位与角色绑定,实现跨部门协同;针对内部 `OA` 系统,配合操作日志、登录日志等模块,帮助管理者洞察关键行为。这些功能让开发者无需从零搭建 PHP Laravel 后台管理 基座,即可交付稳定的 laravel 后台 产品,并持续在现有 laravel admin 生态中迭代。 ## 项目地址 * [github 地址](https://github.com/jaguarjack/catch-admin) * [gitee 地址](https://gitee.com/jaguarjack/catchAdmin) ## 项目预览 | | | |----------------------------------------------------------------------|----------------------------------------------------------------| | ![登录](https://image.catchadmin.com/202512151142046.png) | ![控制台](https://image.catchadmin.com/202512150841525.png) | | ![权限](https://image.catchadmin.com/202512151143109.png) | ![布局](https://image.catchadmin.com/202512151144233.png) | | ![上传](https://image.catchadmin.com/202601101535082.png) | ![代码生成](https://image.catchadmin.com/202601101536072.png) | | ![菜单](https://image.catchadmin.com/202601101537583.png) | ![模板](https://image.catchadmin.com/202601101538807.png) | ### 加入微信群 添加微信好友进群 ## 赞助 如果项目对你有帮助,或者在工作上帮你节省了开发时间。在力所能及的情况下,可以支持下`Catchadmin`项目, 非常感谢 🙏 ## 🛠️ 技术栈 ### 后端技术 * **PHP 8.2+**: 利用最新 PHP 特性,性能提升显著 * **Laravel 12.x**: 最新版本的 Laravel 框架,稳定可靠 * **MySQL**: 支持主流关系型数据库 * **Redis**: 缓存和会话存储,提升系统性能 * **Composer**: PHP 依赖管理工具 ### 前端技术 * **Vue 3**: 现代化的前端框架,响应式开发 * **Element Plus**: 企业级 UI 组件库,开箱即用 * **TypeScript**: 类型安全,提升代码质量 * **Vite**: 快速的构建工具,热更新支持 * **Pinia**: 状态管理,替代 Vuex ## 📚 学习资源 ### 快速入门 1. [安装指南](./start/install.md) - 详细的安装步骤和环境配置 2. [项目介绍](./start/project_intro.md) - 了解项目结构和核心概念 3. [视频教程](./video.md) - 可视化学习,快速上手 ### 进阶开发 * [模块开发](./server/modules.md) - 学习如何开发自定义模块 * [权限管理](./server/permission.md) - 深入理解权限体系 * [前端组件](./front/intro.md) - 前端开发指南和组件使用 ### 部署运维 * [部署指南](./deploy.md) - 生产环境部署最佳实践 * [常见问题](./faq.md) - 问题排查和解决方案 ### 插件开发 * [快速入门](./plugin/quickstart.md) - 插件快速入门开发 ## 🏆 成功案例 CatchAdmin 已成功应用于多个行业: * **教育行业**: 某知名在线教育平台使用 CatchAdmin 构建学员管理系统 * **电商领域**: 多家电商企业基于 CatchAdmin 开发商家后台管理 * **政企服务**: 政府部门采用 CatchAdmin 搭建内部办公管理系统 * **医疗健康**: 医疗机构使用 CatchAdmin 开发患者管理和医生工作站 ## 感谢 🙏 > 排名不分先后 * [Laravel](https://laravel.com) * [Vue](https://cn.vuejs.org/) * [ElementPlus](https://element-plus.org) * [Vitepress](https://vitepress.dev/) * [JetBrains](https://www.jetbrains.com/) --- --- url: /docs/5.0/upgrade.md --- # 更新日志 :::info CatchAdmin v5 版本更新日志 ::: ## v5.3.1 版本功能 * 后台前端样式全面升级至 Tailwind CSS v4 与 Vite 8,打包耗时降至 10 秒以内 * 修复数据更新时所有者的归属问题 * 修复部门及以下层级的数据问题 * 优化核心包树形组件的性能 * 修复 TinyMCE 组件的加载异常 * 更多细节修复持续完善中 ## v5.3.0 版本功能 * 新增 AGENTS 指引,CatchAdmin 开发最佳实践 * 新增 9 个 AI Skills,包含安装,代码生成,SQL to CURD,前端等等。支持多平台 `codex/claude/cursor/windsurf...` 等等 * 优化了整个核心包的稳定性 * 更多... 使用下面的命令发布 CatchAdmin 命令发布 skills ```shell php artisan catch:publish:skills ``` 如果没有,`catchadmin/core` 需要更新到 `1.3.1` ```shell composer update catchadmin/core ``` ## v5.0 版本功能 * 优化模块数据库驱动配置错误 * 优化登录失效异常类,新增 LostLoginException 特定异常类 * 优化 Admin 组件 支持 fallback 从数据库获取用户信息 * 优化后台布局配置,支持配置持久化 * 优化后台 tab,支持刷新后也可保持当前的 tab 页 * 优化代码生成 支持多选支持字典枚举 联动 Model 的修改器 * 优化系统模块路由命名 防止冲突 * 优化后台动态配置 主动缓存 * 更多... ## v5-beta.2 版本功能 * 继续优化 SFC 远程加载,提高渲染速度 * 优化插件开发和使用体验 * 优化后台样式 * 优化了部分性能问题,提示应用加载更加流畅 * 更多... ## v5-beta.1 版本功能 * 核心增强导入功能 * 核心增强导出功能 * 核心支持只获取当前类的方法功能 * 优化了安装启动 更加流畅 * 优化了插件安装 * 优化了插件安装页面 * 增强了插件安装 Hook 功能 * 支持插件系统 * 支持左侧菜单自动更新 * 优化 SFC 远程加载,提高渲染速度 * 更多... ## v5-beta 版本功能 * 全新的后端架构 * 增强核心包 * 全新 UI 前端 * 全新的UI前端组件 * 更加健壮的后端功能 * 支持插件系统 * 支持动态页面渲染 * 增强代码生成 * 支持本地阿里云/腾讯云 COS/七牛云上传 * 更多... --- --- url: /docs/5.0/start/install.md --- # 项目安装 ## 环境要求 * PHP >= 8.2+ * Nginx * Mysql >= 5.7 ## 安装 ### 准备 在安装这个软件之前,您需要准备一些必要的工具,包括: * [git 代码管理](https://git-scm.com/downloads) * [composer PHP 包管理器 >= 2.x](https://getcomposer.org/download/) * [nodejs >= 22 ](https://nodejs.org/zh-cn/) * [yarn 前端包管理器](https://yarn.bootcss.com/) * [vite](https://cn.vitejs.dev/) :::tip 如果你是第一次使用或者需要一个完整的集成环境,CatchAdmin 官方也提供了一个 Laravel 入门教程,目前正在完善中。 可以尝试使用该文档 [Laragon 集成环境安装](https://laravel-study.catchadmin.com/hello-laravel.html#%E7%8E%AF%E5%A2%83%E5%87%86%E5%A4%87) ::: :::warning 可以使用下面的`第一种方式 安装器`快速体验 `v5` 版本。如果在使用过程中您有宝贵得意见,可以提 ISSUE ::: ## composer 安装 :::info 如果已经安装 请跳过该步骤 ::: 请确保已经安装了 `composer` 包管理器。如果您使用的是 `Mac OS` 或者 `Linux`,可以在终端输入以下命令安装 `composer` ```shell // mac os brew install composer // linux sudo apt-get install composer ``` 如果您使用的是 `Windows` 系统,可以从 [composer](https://docs.phpcomposer.com/) 的官方网站下载 exe 安装文件进行安装。 ## 通过 composer 创建项目 :::code-group ```shell [Composer 创建项目] composer create-project catchadmin/catchadmin cd catchadmin php artisan catch:install ``` ::: ## 通过全局安装器安装 CatchAdmin 项目 安装器只是为了简化安装项目过程,如果遇到问题(一般是网络问题)。请使用下面的 `下载项目` 的步骤 :::code-group ```shell [安装器安装] composer global -W require catchadmin/installer:1.0.3 # MacOs 系统需要添加环境变量 export PATH="$HOME/.composer/vendor/bin:$PATH" # 安装成功之后使用下面的命令 catch new catchadmin ``` ::: 会看到如图所示的 ![catchadmin 快速安装](https://image.catchadmin.com/202504191018871.png) 可以选择对应的项目,默认是 Laravel 版本的。按照命令行提示输入即可。最后安装完成后会出现下面的提示 ![catchadmin 快速安装](https://image.catchadmin.com/202504191022429.png) ## 通过 AI 安装项目 在使用 `composer install` 安装完项目依赖之后,然后使用 `php artisan catch:publish:skills` 发布对应 skills,目前支持 `codex/claude/cursor...` 等等,根据实际的使用安装对应平台得 `skills`,然后在对话框发送下面的信息 ```shell 安装项目,数据库配置是 B_DATABASE=数据库名称 DB_USERNAME=用户名 DB_PASSWORD=密码 ``` ## 通过下载项目手动安装 ### 下载项目 :::info 目前最新代码在 Gitee,Github 网络越来越不好了。Gitee 比较流畅 ::: 接下来,您需要下载 CatchAdmin 项目。您可以前往该项目在 [CatchAdmin](https://gitee.com/jaguarjack/catchAdmin) 上的页面进行下载,也可以使用 `git` clone 命令将代码克隆到本地,这样就能及时获取代码更新。 ```sh git clone -b v5 https://gitee.com/catchadmin/catchAdmin.git ``` 当然你也可以使用 [Github](https://github.com/JaguarJack/catch-admin), 有可能会同步不及时。 请注意,该项目不提供 Web 安装方式,因此您需要使用命令行方式进行安装。接下来您可以进入 `CatchAdmin` 项目所在的目录,并运行以下命令进行安装: ```shell # 请一定使用代理安装依赖,据目前所知,国内的 composer 镜像不是不更新了就是更新延后 # 配置完镜像使用 composer 安装 composer install ``` 然后使用下面的命令安装 ```shell // 安装后台, 按照提示输入对应信息即可 php artisan catch:install // 上传显示图片需要软连接 php artisan storage:link // 启动后台 php artisan serve ``` :::info 当你使用 catch:install, 会自动下载前端项目,他们会被下载到根目录的 `web 目录` ::: ### 手动安装前端项目 如果使用 `catch:install` 安装前端项目失败,那么你可以手动安装它。[前端项目仓库](https://gitee.com/catchadmin/catch-admin-vue.git) ```shell git clone -b v5 https://gitee.com/catchadmin/catch-admin-vue.git web cd web # 安装完 nodejs 之后,再安装 yarn npm install --global yarn # 在安装前记得,一定要配置镜像。否则会下载失败(一定必须) yarn config set registry https://registry.npmmirror.com # 安装完成之后,使用 yarn install cp .env.example .env # 然后添加下面的内容 .env 配置,根据实际情况修改后端访问的 api 地址 VITE_BASE_URL=PHP项目域名/api # 启动前端项目 yarn dev ``` 这样就可以安装所有需要的依赖包了。依赖安装完成之后,还需要安装项目的基本信息,如下 :::warning 注意不能直接访问 PHP 项目,会出现异常或者路由找不到。CatchAdmin 是前后端分离项目,你需要通过通过 API 接口形式访问。所以你需要安装好 VUE 项目后台,通过后台管理来访问 ::: ## 启动 ### 手动启动 打开一个 CMD 窗口,然后到项目根目录 使用下面的命令 ```shell php artisan serve ``` 新打开一个 CMD 窗口然后继续进入到 web 目录 ```shell cd web yarn dev ``` ### 快捷启动 既可以用上面的两个命令分别启动项目,也可以使用下面的命令启动两个项目。 ```shell composer run dev ``` :::tip 如果你是第一次使用 Vue,建议先去看看 [Vue](https://cn.vuejs.org/) 文档,了解一下 vue 后台使用了是 `element Plus` [文档地址](https://element-plus.org) ::: --- --- url: /docs/5.0/start/project_intro.md --- # 项目介绍 CatchAdmin V5 是一个开源的后台管理系统,它提供了一组完整的解决方案,可以帮助开发者快速构建各种类型的管理后台,例如 CMS、ERP、CRM、OA 等。CatchAdmin V5 版本的改动非常大,它采用了 Laravel 12.X、Vue3 和 ElementPlus 等最新的技术,以及更加优秀的代码组织方式,以更好地满足开发者的需求。 * typescript * vue3 * tailwindcss(css 组件库) * Laravel (之前使用 tp6 的话,用起来应该没有压力) ### 目录结构 `CatchAdmin` V5 版本服务端和前端放在一个项目中,这样会更方便开发。 :::warning 目前 catchadmin 已经使用 `server` 分支开发,也作为默认分支。`server` 分支是完全分离的项目 ::: ``` ├─app ├─bootstrap ├─config(配置目录) ├─database(migration和seed存放目录) ├─lang(多语言目录) ├─public(运行目录 ├─modules(模块目录) ├─web (前端目录) │ ├─src (前端目录) │ │ ├─assets | | ├─compoents (组件) | | ├─enum (枚举) | | ├─layout (前端布局) | | ├─router (前端路由) | | ├─store (pinia目录) | | ├─styles (样式目录) | | ├─support (助手方法) | | ├─types (类型目录) | | ├─views (前端视图目录) | | | App.vue | | | app.ts | | | env.d.ts │ │ │ └─依赖文件 ├─routes ├─storage ├─tests │ .env-example(env配置示例) │ .gitattributes │ .gitignore │ .travis.yml │ composer.json │ .php-cs-fixer.dist.php | package.json │ phpunit.xml │ postcss.config.js │ tailwind.config.js │ tsconfig.json │ tsconfig.node.json │ vite.config.js └─ artisan(命令行入口文件) ``` 这里可以先熟悉目录结构,在后续将介绍系统内具体的一些方法和配置。 和之前 3.x 相比,最大的变化就是将核心目录已经独立出去,使用单独的 `composer` 加载,如果遇到任何问题或者 bug 可以到[catchadmin/core](https://github.com/catch-admin/core)仓库提交 issue! ## 视频介绍 [catchadmin 新版本安装,视频作为了解,已经很老了](https://www.bilibili.com/video/BV1eY411v71J/) --- --- url: /docs/5.0/deploy.md --- # CatchAdmin 部署指南 > 详细的 CatchAdmin 生产环境部署教程和最佳实践 :::warning 很多开发者在部署 CatchAdmin 时遇到问题,这里提供了完整详细的部署文档。本文档包含了从前端构建到服务器配置的全部步骤,基本涵盖了所有部署场景。 请仔细阅读文档,大部分问题都能在这里找到解决方案。如果遇到特殊情况确实需要协助,目前提供付费部署支持服务,收费标准为 `100` 元/次。先付费后服务,感谢理解 🙏 ::: ## 前端项目 在构建 CatchAdmin 前端项目前,需要先配置生产环境的 API 地址。在前端项目根目录下创建或编辑 `.env.production` 文件: ``` # base api // 例如 https://api.catchadmin.com/api/ VITE_BASE_URL = '正式环境的 API 地址' ``` 配置完成后,使用以下命令构建 CatchAdmin 前端项目: ```bash yarn run build # 或者使用 npm npm run build ``` ### 打包出现报错 如果打包出现 ts 过多的类型错误,而你对类型又不太敏感的话,对应用没有影响。一个快速的解决办法就是修改 `package.json 文件` build 命令 ```json { "scripts": { "dev": "vite", "build": "vue-tsc --noEmit && vite build", // [!code --] "build": "vite build", // [!code ++] "preview": "vite preview" } } ``` 构建完成后,前端项目根目录会生成 `dist` 目录,这是 CatchAdmin 前端的生产版本,包含经过优化的静态资源文件,可直接部署到 Web 服务器。 :::tip 性能优化建议 1. 建议在 Web 服务器上启用 `Gzip` 压缩,可显著提升页面加载速度 2. 配置静态资源缓存策略,提升用户体验 3. 使用 CDN 加速静态资源访问 ::: ## 后端 CatchAdmin 后端基于 PHP 开发,部署相对简单。将 PHP 项目代码上传到服务器即可。 **推荐部署方式**: 1. 上传源代码到服务器,不包含 `vendor` 目录 2. 在服务器上执行 `composer install --no-dev` 安装生产环境依赖 3. 配置正确的文件权限和目录结构 如果遇到依赖安装的网络问题,请参考 [使用镜像](./faq.md#镜像) 解决方案。 :::warning 重要提醒 如果使用了 CatchAdmin 脚手架初始化项目,部署时需要注意: * **排除 `web` 目录**:这是前端开发目录,不需要与后端一起上传 * **前端部署**:只需要上传构建后的 `dist` 目录 * **分离部署**:前后端建议分开部署,便于维护和扩展 ::: ### 上线注意点 * `.env` 环境文件是否配置好? * 数据库表是否同步? * 数据表的数据是否同步,主要是**权限菜单**表`permissions`里是否同步 * 模块如果正常开启的状态下,路由还是无法正常工作 (`这个步骤只针对 Laravel 主项目`) :::tip * 首先是用 php artian route:clear * 然后查看路由 php artisan route:list * 最后缓存路由 php artisan route:cache ::: ## 部署 :::warning 如果你使用的是宝塔相关的,一定不要完全复制下面的配置。因为宝塔有很多预配置项,例如 https ssl 配置是不需要你自己手动配置 ::: ### 分开部署(双域名) 推荐的 CatchAdmin 部署方式是前后端分离部署,分别使用不同的域名或子域名: **部署架构示例**: * 前端项目:`admin.yourdomain.com` → `/www/admin` 目录 * 后端 API:`api.yourdomain.com` → `/www/api` 目录 :::tip 部署建议 * 目录路径可根据实际服务器环境调整 * 分离部署便于独立维护和扩容 * 支持前后端独立更新,降低部署风险 ::: * `/www/admin` 上传 `dist` 目录内容到 admin 目录中 * `/www/api` 上传后端项目到 api 目录中 ::: code-group ```php [前端项目] server { listen 80; server_name admin.catchadmin.com; return 301 https://admin.catchadmin.com$request_uri; } server { listen 443 ssl http2; server_name admin.catchadmin.com; index.html index.php index.htm default.php default.htm default.html; ssl_certificate # pem文件的路径 ssl_certificate_key # key文件的路径 # ssl验证相关配置 ssl_session_timeout 5m; #缓存有效期 ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; root /www/admin; location / { try_files $uri $uri/ /index.html =404; } } ``` ```php [后端项目] server { listen 80; server_name api.catchadmin.com; return 301 https://api.catchadmin.com$request_uri; } server { listen 443 ssl http2; server_name api.catchadmin.com; index index.html index.php index.htm default.php default.htm default.html; root /www/api/public; ssl_certificate /etc/nginx/acme/catchadmin.com/catchadmin.com.cer; # pem文件的路径 ssl_certificate_key /etc/nginx/acme/catchadmin.com/catchadmin.com.key; # key文件的路径 ssl_session_timeout 5m; #缓存有效期 ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; location / { if (!-e $request_filename) { rewrite ^(.*)$ /index.php?s=/$1 last; break; } } # PHP 支持 location ~ \.php$ { try_files $uri /index.php =404; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } ## nginx log 自己配置 access_log; error_log; } ``` ::: ### 合并部署(单域名) 如果只有一个域名或希望简化部署架构,可以将 CatchAdmin 前后端部署在同一域名下: **部署结构**: * 后端项目:`yourdomain.com/api` → PHP 项目根目录 * 前端项目:`yourdomain.com/` → 放置在后端项目的 `public/admin` 目录下 这种方式适合小型项目或资源有限的场景。 ```php server { listen 80; server_name api.catchadmin.com; return 301 https://api.catchadmin.com$request_uri; } server { listen 443 ssl http2; server_name api.catchadmin.com; index index.html index.php index.htm default.php default.htm default.html; root /www/api/public; ssl_certificate # pem文件的路径 ssl_certificate_key # key文件的路径 ssl_session_timeout 5m; #缓存有效期 ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; # gzip 压缩 一定要开 gzip on; gzip_min_length 1k; gzip_buffers 4 16k; gzip_http_version 1.1; gzip_comp_level 6; # 建议 6 更均衡 gzip_vary on; gzip_proxied any; gzip_types text/plain text/css text/xml application/json application/javascript text/javascript application/xml image/svg+xml; gzip_disable "MSIE [1-6]\."; # 因为接口都是以 api.catchadmin.com/api 开头,所以可以很好的使用 location # 如果访问 api.catchadmin.com/api 目录 则用 php 解释下 location /api { if (!-e $request_filename) { rewrite ^(.*)$ /index.php?s=/$1 last; break; } } # 如果访问根目录 api.catchadmin.com/, 则直接访问前端项目 location / { root /www/api/public/admin; try_files $uri $uri/ /index.html; } # 上传的静态目录 location location /uploads/ { alias /www/api/storage/uploads/; autoindex on; } #PHP 支持 location ~ \.php$ { try_files $uri /index.php =404; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } } ``` 如果使用宝塔部署,`location` 配置静态目录的可能会无法工作,这是由于宝塔的预配置导致的,目前我个人使用下面如图得方法解决了 ![宝塔单域名部署](https://image.catchadmin.com/202411280949472.png) ### Octane 高性能部署 对于需要高性能的 CatchAdmin 项目,可以使用 Laravel Octane 提升并发处理能力: **Octane 优势**: * 显著提升 API 响应速度 * 更好的内存利用率 * 支持 WebSocket 等高级特性 **适用场景**:高并发访问、实时数据处理、大量 API 调用的企业级应用 ```php map $http_upgrade $connection_upgrade { default upgrade; '' close; } server { listen 80; server_name api.catchadmin.com; return 301 https://api.catchadmin.com$request_uri; } server { listen 443 ssl http2; server_name api.catchadmin.com; index index.html index.php index.htm default.php default.htm default.html; root /www/api/public; ssl_certificate # pem文件的路径 ssl_certificate_key # key文件的路径 ssl_session_timeout 5m; #缓存有效期 ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; # gzip 压缩 一定要开 gzip on; gzip_min_length 1k; gzip_buffers 4 16k; gzip_http_version 1.1; gzip_comp_level 6; # 建议 6 更均衡 gzip_vary on; gzip_proxied any; gzip_types text/plain text/css text/xml application/json application/javascript text/javascript application/xml image/svg+xml; gzip_disable "MSIE [1-6]\."; # 因为接口都是以 api.catchadmin.com/api 开头,所以可以很好的使用 location # 如果访问 api.catchadmin.com/api 目录 则用 php 解释下 location /api { if (!-e $request_filename) { rewrite ^(.*)$ /index.php?s=/$1 last; break; } } # 如果访问根目录 api.catchadmin.com/, 则直接访问前端项目 location / { root /www/api/public/admin; try_files $uri $uri/ /index.html; } # 上传的静态目录 location location /uploads/ { alias /www/api/public/storage/uploads/; autoindex on; } location @octane { set $suffix ""; if ($uri = /index.php) { set $suffix ?$query_string; } proxy_http_version 1.1; proxy_set_header Host $http_host; proxy_set_header Scheme $scheme; proxy_set_header SERVER_PORT $server_port; proxy_set_header REMOTE_ADDR $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_pass http://172.18.0.2:9800$suffix; } } ``` --- --- url: /docs/5.0/server/config.md --- # 框架配置 ## catchadmin 配置 首先先了解`catchadmin` 的项目相关配置 :::code-group ```php [config/catch.php] return [ /* |-------------------------------------------------------------------------- | catch-admin 超级管理员 |-------------------------------------------------------------------------- | | 可以设置超级管理的用户 ID | 支持数组 | |-------------------------------------------------------------------------- */ 'super_admin' => 1, /* |-------------------------------------------------------------------------- | catch-admin 请求允许 |-------------------------------------------------------------------------- | | 默认允许 GET 请求通过 RBAC 权限 | |-------------------------------------------------------------------------- */ 'request_allowed' => true, /* |-------------------------------------------------------------------------- | catch-admin 模块设置 |-------------------------------------------------------------------------- | | 设置模块根目录 | 设置模块的根命名空间 | 设置模块默认生成的文件夹 | |-------------------------------------------------------------------------- */ 'module' => [ 'root' => 'modules', 'namespace' => 'Modules', /** * 默认启动的模块 */ 'default' => ['develop', 'user', 'common'], 'default_dirs' => [ 'Http'.DIRECTORY_SEPARATOR, 'Http'.DIRECTORY_SEPARATOR.'Requests'.DIRECTORY_SEPARATOR, 'Http'.DIRECTORY_SEPARATOR.'Controllers'.DIRECTORY_SEPARATOR, 'Models'.DIRECTORY_SEPARATOR, ], // 模块存储驱动 // 默认使用文件驱动 'driver' => [ // currently, catchadmin support file and database // the default is driver 'default' => 'file', // use database driver 'table_name' => 'admin_modules', ], /** * 模块路由集合 */ 'routes' => [], /** * 模块是否自动加载 * * 如果设置成 true,模块会自动全部加载 */ 'autoload' => env('CATCH_MODULE_AUTOLOAD', false), ], /* |-------------------------------------------------------------------------- | catch-admin 响应 |-------------------------------------------------------------------------- */ 'response' => [ // JSON 响应, 保证响应数据都是 json 'always_json' => \Catch\Middleware\JsonResponseMiddleware::class, // 响应监听者 // 监听[RequestHandled]事件 'request_handled_listener' => \Catch\Listeners\RequestHandledListener::class, ], /* |-------------------------------------------------------------------------- | 数据库 SQL 日志 |-------------------------------------------------------------------------- */ 'listen_db_log' => env('APP_DEBUG', true), /* |-------------------------------------------------------------------------- | 管理员授权认证模型 |-------------------------------------------------------------------------- */ 'auth_model' => \Modules\User\Models\User::class, /* |-------------------------------------------------------------------------- | 管理员授权 Guard |-------------------------------------------------------------------------- */ 'auth' => 'admin', /* |-------------------------------------------------------------------------- | 路由配置 |-------------------------------------------------------------------------- */ 'route' => [ 'prefix' => 'api', 'middlewares' => [ \Catch\Middleware\AuthMiddleware::class, \Catch\Middleware\JsonResponseMiddleware::class, ], ], /* |-------------------------------------------------------------------------- | 前端 Vue 视图文件夹路径 | | 如果不设置,将不会生成相关的 Vue 文件 |-------------------------------------------------------------------------- */ 'views_path' => base_path('web'.DIRECTORY_SEPARATOR.'src'.DIRECTORY_SEPARATOR.'views'.DIRECTORY_SEPARATOR), /* |-------------------------------------------------------------------------- | 开启系统接口日志分析 | | 接口日志依赖 Redis,提高性能 |-------------------------------------------------------------------------- */ 'system_api_log' => env('CATCH_SYSTEM_API_LOG', false), /* |-------------------------------------------------------------------------- | 图片处理 | | 默认使用 GD |-------------------------------------------------------------------------- */ 'image' => [ 'driver' => env('CATCH_IMAGE_DRIVER', 'gd'), 'options' => [ ], /** * 默认读取磁盘 */ 'read_from' => env('CATCH_IMAGE_READ_FROM', 'uploads'), ], /* |-------------------------------------------------------------------------- | 后台缓存统一管理 | | 配置后台缓存前缀,便于清理后台管理的缓存 |-------------------------------------------------------------------------- */ 'admin_cache_key' => env('CATCH_ADMIN_CACHE_KEY', 'admin_dashboard_'), /* |-------------------------------------------------------------------------- | 模型相关配置 | | 配置模型的配置 |-------------------------------------------------------------------------- */ 'model' => [ // created_at & updated_at format 'date_format' => 'Y-m-d H:i:s', // update creator id 'change_creator_id' => (bool) env('CATCH_CHANGE_CREATOR_ID', false), ], /* |-------------------------------------------------------------------------- | Excel 配置 |-------------------------------------------------------------------------- */ 'excel' => [ /** * 导出路径, 相对于 storage 目录得相对路径 */ 'export_path' => 'excel/export', ], ]; ``` ::: * `super_admin` 配置 **super admin** 的 **ID**,默认 `1`, 支持数组配置`[1,2,3]` * `module` 模块相关配置 * `root` 配置模块的根目录 * `namespace` 模块根命名空间 * `default` 默认模块,初始化 `develop`, `use`, `common` 三个模块 * `default_dirs` 默认生成默认的目录 * `driver` 模块配置驱动 默认是 file * `routes` 模块路由集合 * `response` 响应配置 * `always_json` 响应输出 `Json` * `request_handled_listener `响应数据格式配置 * `auth` 认证相关配置 * `listen_db_log` 是否监听 **DB SQL** * `route` 路由配置 * `prefix` 路由前缀 * `middlewares` 路由默认路由 * `views_path` 配置前端项目 views 路径 * `system_api_log` 是否开启系统接口日志分析 * `images` 图片处理配置 * `admin_cache_key` 后台缓存 `key` 统一前缀 项目有定制需求,一定要看看这些配置 ## 模块配置 除了整个系统的配置以外,系统还提供了模块化的配置,模块的配置也是相互独立的。如果模块需要配置,那么可以直接在模块目录下添加 `config` 目录,系统会自动加载配置文件。当然非要客制化下,也没问题。只需要在模块的`Provider` 下实现 `configPath` 这个方法即可 ```php title="modules/Test/Providers/TestServiceProvider" namespace Modules\Test\Providers; use Catch\CatchAdmin; use Catch\Providers\CatchModuleServiceProvider; class TestServiceProvider extends CatchModuleServiceProvider { public function confitPath(): string { return config_path; } } ``` 最终模块的配置如下结构 * Permissions * config * one.php * two.php 那么如何获取呢?按照 `Laravel` 的模式,应该还用下面的代码获取配置内容 ```php config('one') ``` 但是因为是模块化独立的,所以获取上一定要加入模块的名称,最终应该是这么获取 ```php config('permissions.one.some_key') ``` --- --- url: /docs/5.0/server/promise.md --- # CatchAdmin 开发约定 > 约定大于配置 - CatchAdmin 开发规范和最佳实践指南 **约定大于配置**是现代框架设计的核心理念。通过统一的约定,开发者能够快速理解项目结构,减少配置复杂度,提升开发效率。CatchAdmin 遵循这一理念,制定了一套简洁而实用的开发约定。 掌握这些约定将帮助你: * **快速上手**:无需大量配置即可开始开发 * **团队协作**:统一的代码组织方式便于团队协作 * **维护便捷**:标准化的结构降低维护成本 * **扩展灵活**:约定化的架构支持功能快速扩展 ## 📁 目录结构约定 ### 后端模块位置 **约定**:所有后台业务功能模块统一放置在 `modules` 目录下 ``` project/ ├── modules/ │ ├── User/ # 用户管理模块 │ ├── Permissions/ # 权限管理模块 │ └── YourModule/ # 自定义模块 ``` **设计理念**: * 模块化开发,业务逻辑清晰分离 * 便于模块的独立开发、测试和维护 * 支持模块间的松耦合设计 ### 前端页面位置 **约定**:模块对应的前端页面放置在 `web/src/views` 目录下 ``` web/src/views/ ├── user/ # 用户模块页面 ├── permissions/ # 权限模块页面 └── your-module/ # 自定义模块页面 ``` **最佳实践**: * 前端目录名与后端模块名保持一致(小写) * 页面组件按功能分组,保持结构清晰 * 遵循 Vue 3 单文件组件规范 ## 🏷️ 枚举类型约定 ### 枚举接口实现 **约定**:所有枚举类型必须实现 `Catch\Enums\Enum` 接口 ```php '正常', self::INACTIVE => '禁用', self::BANNED => '封禁', }; } } ``` :::info PHP 版本支持 CatchAdmin 要求 PHP 8.1+,因此可以充分利用 PHP 8.1 新增的枚举类型(enum)特性,提供类型安全和更好的代码提示。 ::: ### 枚举值约定 **约定**:整型枚举值从 `1` 开始 ```php enum OrderStatus: int implements Enum { case PENDING = 1; // ✅ 从 1 开始 case CONFIRMED = 2; case SHIPPED = 3; case DELIVERED = 4; } ``` :::info 为什么从 1 开始? 这个约定有重要的技术原因: 1. **弱类型问题**:PHP 中 `0`、`null`、`""` 在弱类型比较时相等 2. **查询逻辑**:枚举常用于数据库查询条件,从 1 开始避免了 `WHERE status = 0` 的歧义 3. **前端处理**:JavaScript 中也存在类似的类型转换问题 4. **API 设计**:RESTful API 中,0 值容易与空值混淆 **示例对比**: ```php // 不推荐:从 0 开始可能导致逻辑错误 if ($status) { /* 当 status = 0 时,此条件为 false */ } // 推荐:从 1 开始,逻辑清晰 if ($status) { /* 所有有效状态都会执行 */ } ``` ::: ## 🔧 公共功能约定 ### Common 模块设计 **约定**:通用功能统一放置在内置的 `Common` 模块中 **包含功能**: * **文件上传**:统一的文件上传接口和处理逻辑 * **枚举接口**:为前端提供枚举值集合的 API 接口 * **通用工具**:跨模块使用的工具类和辅助方法 * **系统配置**:全局配置项的管理和读取 **设计优势**: ```php // Common 模块提供统一的上传服务 Route::post('/upload', [UploadController::class, 'handle']); // 统一的枚举接口 Route::get('/enums/{enum}', [EnumController::class, 'get']); ``` 这种设计避免了: * 重复的上传逻辑在各模块中实现 * 枚举接口的分散管理 * 公共代码的冗余和不一致 ## 🛣️ 路由管理约定 ### 静态路由配置 **约定**:不使用动态菜单时,前端路由文件命名为 `route.js` 并放置在模块 `views` 目录下 ``` web/src/views/user/ ├── components/ # 组件目录 ├── pages/ # 页面目录 │ ├── index.vue │ └── detail.vue └── route.js # 路由配置文件 ``` **路由文件示例**: ```javascript // web/src/views/user/route.js export default { path: '/user', name: 'User', component: () => import('./pages/index.vue'), meta: { title: '用户管理', requiresAuth: true }, children: [ { path: 'detail/:id', name: 'UserDetail', component: () => import('./pages/detail.vue') } ] } ``` **适用场景**: * 模块路由相对固定,不需要动态配置 * 追求更好的类型提示和开发体验 * 需要精确控制路由的加载时机 :::info 参考示例 可以参考以下模块的实现: * `develop` 模块:开发工具相关路由 * `user` 模块:用户管理路由配置 * 这些模块展示了静态路由的标准实现方式 ::: ## 💡 约定的价值 遵循 CatchAdmin 的开发约定能够: 1. **提升开发效率**:标准化的结构减少决策时间 2. **降低学习成本**:统一的模式便于新人快速上手 3. **保证代码质量**:约定化避免了常见的设计陷阱 4. **促进团队协作**:一致的代码风格提升协作效率 5. **便于项目维护**:清晰的结构降低维护复杂度 记住:约定不是限制,而是为了让开发变得更加简单和高效! --- --- url: /docs/5.0/server/modules.md --- # CatchAdmin 模块化开发 > CatchAdmin 模块化架构详解,让业务功能开发更高效、更灵活 :::info v5.0 引入了插件机制,完全可以通过把模块打包放到插件市场共享给其他客户。目前 v5 还是保留了模块得概念,主要针对后台模块。 ::: 在使用 CatchAdmin 进行项目开发前,首先需要了解系统最核心的设计理念——`模块化架构`。CatchAdmin 将所有业务功能都拆分为独立的功能模块,每个模块具有完整的 MVC 结构,支持独立开发、测试和部署。这种设计让开发者能够: * **高效协作**:不同开发者可以并行开发不同模块 * **代码复用**:开发完成的模块可以在项目间共享 * **维护便捷**:模块间解耦,降低维护成本 * **扩展灵活**:根据业务需求随时添加或移除模块 ### CatchAdmin 模块工作原理 CatchAdmin 采用类似 Laravel Package 的模块管理机制。所有模块都存放在项目的 **modules** 目录下,每个模块都是一个独立的功能单元。 **模块安装**:通过 Artisan 命令快速安装模块 ```shell php artisan catch:module:install ``` **安装流程**: CatchAdmin 的模块系统借鉴了 Laravel 社区的成熟设计理念,从 2.x 到 5.x 版本保持了良好的兼容性,让有经验的开发者能够快速上手。 ![模块架构图](https://z3.ax1x.com/2021/04/26/gSrLz6.png) ### 实战:开发新模块 以下通过创建一个实际模块来演示 CatchAdmin 模块开发的完整流程。 **第一步:创建模块** CatchAdmin 提供了可视化的模块创建界面,让模块初始化变得简单直观: ![pSlN1y9.md.png](https://s1.ax1x.com/2023/01/16/pSlN1y9.md.png) 1. 进入 CatchAdmin 后台管理界面 2. 导航到"开发工具" → "模块管理" 3. 点击"新建模块",填写模块基本信息: * 模块名称(如:test) * 模块描述 * 模块关键词 * 开发者信息 4. 点击"创建"按钮 系统将自动生成完整的模块文件结构,以 **test** 模块为例: ![pSlN2Y8.md.png](https://s1.ax1x.com/2023/01/16/pSlN2Y8.md.png) ![pSlNv6J.png](https://s1.ax1x.com/2023/01/16/pSlNv6J.png) **生成的模块结构分析**: ``` modules/Test/ ├── Http/ # 控制器层:处理 HTTP 请求和响应 ├── Models/ # 数据模型层:数据库交互和业务逻辑 ├── database/ # 数据库相关 │ ├── migrations/ # 数据库迁移文件 │ └── seeds/ # 数据填充文件 ├── Providers/ # 服务提供者:模块的核心注册点 └── route.php # 路由定义文件 ``` **核心组件说明**: * **Http 目录**:存放控制器和中间件,处理业务逻辑 * **Models 目录**:数据模型,定义数据结构和关系 * **database 目录**:数据库相关文件,支持版本控制 * **Providers 目录**:服务提供者,类似 Laravel Package 的核心机制 * **route.php**:模块路由定义,支持 RESTful API 设计 **深入理解服务提供者(Provider)** 服务提供者是 CatchAdmin 模块的核心,负责模块的初始化和资源注册: ```php namespace Modules\Test\Providers; use Catch\CatchAdmin; use Catch\Providers\CatchModuleServiceProvider; class TestServiceProvider extends CatchModuleServiceProvider { public function moduleName(): string|array { return 'common'; } } ``` **Provider 功能特性**: CatchAdmin 的服务提供者继承自 `CatchModuleServiceProvider`,默认自动加载模块路由。同时提供以下扩展功能: **1. 事件系统集成** CatchAdmin 支持模块级别的事件监听,与 Laravel 事件系统完全兼容。通过 `$events` 数组注册模块专属事件: ```php class TestServiceProvider extends CatchModuleServiceProvider { protected $events = []; } ``` **2. 中间件支持** 模块可以注册中间件,用于权限验证、数据过滤等场景。实现 `middlewares` 方法即可: ```php class TestServiceProvider extends CatchModuleServiceProvider { protected function middlewares(): array { return []; } } ``` :::warning 中间件注意事项 通过 Provider 注册的中间件会作用于整个应用,而非仅当前模块。因此在注册全局中间件时需要谨慎考虑其影响范围,避免对其他模块造成不必要的限制。 **建议**:优先在路由级别使用中间件,只在确实需要全局作用时才在 Provider 中注册。 ::: ### 模块分发与安装器 :::info 模块共享 如果开发的模块仅供当前项目使用,可以跳过此部分。 以下内容适用于希望将模块贡献给 CatchAdmin 社区或在多个项目间复用的场景。 ::: **为什么需要安装器?** CatchAdmin 的模块安装器(Installer)是实现模块标准化分发的关键组件。它解决了以下问题: * 模块依赖管理(Composer 包) * 数据库结构同步(migrations) * 配置文件处理 * 权限菜单导入 **安装器实现** 安装器通常放置在模块根目录下,以权限模块为例: ```php namespace Modules\Permissions; use Catch\Support\Module\Installer as ModuleInstaller; class Installer extends ModuleInstaller { protected function info(): array { // TODO: Implement info() method. return [ 'title' => '权限管理', 'name' => 'permissions', 'path' => 'permissions', 'keywords' => '权限, 角色, 部门', 'description' => '权限管理模块', 'provider' => PermissionsServiceProvider::class ]; } protected function requirePackages(): void { // TODO: Implement requirePackages() method. } protected function removePackages(): void { // TODO: Implement removePackages() method. } } ``` **安装器核心方法说明**: 1. **info() 方法**:定义模块基本信息,包括名称、描述、关键词等 2. **requirePackages() 方法**:处理模块依赖的 Composer 包 3. **removePackages() 方法**:卸载时清理相关依赖 **依赖包管理示例**: ```php protected function requirePackages(): void { // TODO: Implement requirePackages() method. $this->composer()->require('package/name') } ``` **权限菜单导出** 对于包含后台管理功能的模块,CatchAdmin 提供了菜单导出命令,自动生成权限相关的 seed 文件: ```shell php artisan catch:export:menu ``` * table 可选参数,默认是 `permissions` 表 **使用场景**: * 模块包含后台管理界面 * 需要自定义权限控制 * 计划分发给其他开发者使用 **示例**:导出权限模块的完整菜单结构 ```php php artisan catch:export:menu permissions ``` **模块分发流程总结**: 1. ✅ 完善模块功能开发 2. ✅ 创建标准化安装器 3. ✅ 导出权限菜单(如需要) 4. ✅ 编写模块使用文档 5. ✅ 测试安装和卸载流程 完成以上步骤后,你的模块就可以与 CatchAdmin 社区分享了!👏 **社区贡献**:欢迎开发者将优质模块贡献给社区,共同构建更强大的 CatchAdmin 生态系统。 --- --- url: /docs/5.0/server/auth.md --- # 用户认证 > CatchAdmin 如何获取登录用户信息? 获取当前登录人信息的完整指南 CatchAdmin 提供了 `Admin` Facade 来处理后台用户认证相关的操作,包括获取当前登录用户、获取登录人信息、用户 ID、退出登录等功能。本文将详细介绍如何在 CatchAdmin 后台管理系统中获取和操作登录用户信息。 ## 快速开始 在 CatchAdmin 中获取当前登录用户非常简单,只需要引入 `Admin` Facade 即可: ```php use Catch\Facade\Admin; // 获取当前登录用户 $user = Admin::currentLoginUser(); // 获取当前登录用户 ID $userId = Admin::id(); ``` ## 获取当前登录用户 在控制器或其他业务逻辑中,可以通过 `Admin::currentLoginUser()` 获取当前登录的用户模型。这是 CatchAdmin 中获取登录人信息最常用的方法: ```php use Catch\Facade\Admin; // 获取当前登录用户 $user = Admin::currentLoginUser(); // 获取用户信息 $username = $user->username; $email = $user->email; ``` :::tip `currentLoginUser()` 返回的是 `Modules\User\Models\User` 模型实例,可以直接访问用户的所有属性和关联关系。 ::: ## 获取当前登录用户 ID 如果只需要获取用户 ID,可以使用更简洁的方式: ```php use Catch\Facade\Admin; // 获取当前登录用户 ID $userId = Admin::id(); ``` ## 用户认证 `Admin::auth()` 方法用于验证用户身份,通常在中间件中调用。如果你需要手动进行用户认证,可以这样使用: ```php use Catch\Facade\Admin; try { $user = Admin::auth(); // 认证成功,继续业务逻辑 } catch (\Illuminate\Auth\AuthenticationException $e) { // 认证失败处理 } ``` :::info 一般情况下,不需要手动调用 `auth()` 方法,CatchAdmin 的 `AuthMiddleware` 中间件会自动处理用户认证。 ::: ## 退出登录 用户退出登录时,调用 `logout()` 方法: ```php use Catch\Facade\Admin; Admin::logout(); ``` 该方法会: * 清除用户的个人令牌缓存 * 删除数据库中的 Token 记录 ## 清理缓存 ### 清理指定用户令牌缓存 ```php use Catch\Facade\Admin; // 清理当前用户的令牌缓存 Admin::clearUserPersonalToken(); // 清理指定 tokenId 的缓存 Admin::clearUserPersonalToken($tokenId); ``` ### 清理所有缓存用户 ```php use Catch\Facade\Admin; Admin::clearAllCachedUsers(); ``` :::warning `clearAllCachedUsers()` 会清理所有已缓存的用户信息,请谨慎使用。 ::: ## 使用示例 ### 在控制器中使用 ```php $user->id, 'username' => $user->username, 'email' => $user->email, ]; } /** * 更新当前用户信息 */ public function update(Request $request) { $user = Admin::currentLoginUser(); $user->update($request->only(['username', 'email'])); return $user; } } ``` ### 在服务类中使用 ```php group(function () { Route::adminResource('pay/order/refunds', PayOrderRefundsController::class); Route::adminResource('admin/users', AdminUsersController::class); //next }); ``` ```php [Installer.php] // 模块安装器,在[模块化]章节有详细介绍 class Installer extends ModuleInstaller { protected function info(): array { // TODO: Implement info() method. return [ 'title' => '测试', 'name' => 'test', 'path' => 'Test', 'keywords' => 'test', 'description' => 'test', 'provider' => TestServiceProvider::class, ]; } protected function requirePackages(): void { // TODO: Implement requirePackages() method. } protected function removePackages(): void { // TODO: Implement removePackages() method. } } ``` ::: 模块创建完成之后,然后在创建 `Schema`,这里所谓的 `schema` 就是数据库的表,支持新建表,也支持已有表创建。 ### 新建表 ![CatchAdmin 代码生成 - Laravel Admin](https://image.catchadmin.com/202512071101828.png) 按照提示填写表信息,然后点击下一步 ![CatchAdmin 代码生成 - Laravel Admin](https://image.catchadmin.com/202512071102650.png) 如图,需要在这里添加表字段,完成之后,点击创建即可。如下图 ![CatchAdmin 代码生成 - Laravel Admin](https://image.catchadmin.com/202512071103790.png) ### 已有表创建 从已有表里面创建对应生成表记录 ![CatchAdmin 代码生成 - Laravel Admin](https://image.catchadmin.com/202506091622871.png) ## 代码生成 在 `schema` 管理页面的点击对应记录生成代码按钮之后,进入到生成代码的页面 ![CatchAdmin 代码生成 - Laravel Admin](https://image.catchadmin.com/202506111042294.png) ### 参数 生成代码页面有几个比较重要的参数 * `模块` 是必选的,这保证代码生成到某个模块中 * `控制器` 名称是必填的,会在模块的 `Http` 目录下 `Controller` 文件 * `模型名称` 是默认根据表名称生成模型名称,是大驼峰的命名方式 * `菜单名称` 填写了菜单名称会自动生成权限管理的菜单,不填则不生成 * `模型关联关系` 支持生成模型关联关系 * `操作` * 分页是否支持分页 * 是否生成表单 * 是否使用动态表单,动态表单相关[文档](https://form-builder.catchadmin.vip) ### 表格和表单生成 :::info 注意代码生成的字段是支持拖拽的,你可以拖拽到合适的位置 ::: ### 表单组件 普通的自带组件这里就不多做解释了。来看看 catchadmin 新增的和后台强制绑定的组件 #### 字典组件 ![CatchAdmin 代码生成 字典组件 - Laravel Admin](https://image.catchadmin.com/202506091650123.png) 生成的效果如下 ![CatchAdmin 代码生成 字典组件 - Laravel Admin](https://image.catchadmin.com/202506091714665.png) #### 附件上传组件 ![CatchAdmin 代码生成 附件上传组件 - Laravel Admin](https://image.catchadmin.com/202506091725566.png) #### 单图/多图上传组件 ![CatchAdmin 代码生成 单图/多图上传组件 - Laravel Admin](https://image.catchadmin.com/202506091726558.png) #### 单文件/多文件上传组件 ![CatchAdmin 代码生成 单文件/多文件上传组件 - Laravel Admin](https://image.catchadmin.com/202506091725907.png) #### 远程级联组件 远程组件需要选择数据源,如下图,其他远程组件类似,如果需要支持树形的话,要选择父级字段。 ![CatchAdmin 代码生成 远程级联组件 - Laravel Admin](https://image.catchadmin.com/202506091654120.png) 生成后的效果 ![CatchAdmin 代码生成 远程级联组件 - Laravel Admin](https://image.catchadmin.com/202506091715773.png) #### 远程下拉组件 ![CatchAdmin 代码生成 远程下拉组件 - Laravel Admin](https://image.catchadmin.com/202506091724707.png) #### 远程树形组件 ![CatchAdmin 代码生成 远程下拉组件 - Laravel Admin](https://image.catchadmin.com/202506091724974.png) #### 远程树形下拉组件 ![CatchAdmin 代码生成 远程树形下拉组件 - Laravel Admin](https://image.catchadmin.com/202506091729938.png) #### 图标选择组件 ![CatchAdmin 代码生成 图标选择组件 - Laravel Admin](https://image.catchadmin.com/202506091714910.png) #### 下拉 类似这种下拉选项的可以支持动态添加,例如 radio checkbox 等 ![CatchAdmin 代码生成 下拉 - Laravel Admin](https://image.catchadmin.com/202506091706997.png) ### 验证规则 :::info 验证规则是 Laravel 内置的验证规则,只支持部分前端规则 ::: #### 以下是前端验证的规则 * `required` 必须填写 * `string` 必须是字符串类型 * `url` URL 格式不正确 * `number` 必须是数字类型 * `email` 邮箱格式不正确 * `boolean` 必须是布尔类型 * `date` 日期格式 验证规则会生成在,如下图 ![CatchAdmin 代码生成 - Laravel Admin](https://image.catchadmin.com/202506091647938.png) ## 后端 ### 枚举 如果你使用的是下拉选项之类的,就是包含`options`选项的组件,后端会自动识别,并且生成文本返回。 例如状态字段,它的 options 选项如下 ```json [ { "label": "正常", "value": "1" }, { "label": "禁用", "value": "2" } ] ``` 那么模型会生成如下面的代码 ```php /** * status 字段转换器 * * @return Attribute */ public function statusText(): Attribute { $text = [2 => '禁用', 1 => '正常']; return Attribute::make(get: fn ($value) => $text[$this->status] ?? ''); } ``` 前端的状态字段也会自动使用`status_text`字段来渲染 ### 图片 多图的情况下,会自动生成下面的代码,这里使用`avatar`字段演示 ```php /** * avatar 转换 * * @return Attribute */ public function avatar(): Attribute { return Attribute::make( get: fn ($value) => ! $value ? [] : array_map(fn ($item) => $item ? url($item) : '', json_decode($value, true)), set: fn ($value) => json_encode(array_map(fn ($value) => remove_app_url($value), $value)) ); } ``` ![CatchAdmin 代码生成,前端会自动生成图片展示 - Laravel Admin](https://image.catchadmin.com/202506091831480.png) ### Switch 组件 首先会在前端表格内生成一个`switch`组件,用于字段值切换 ![CatchAdmin 代码生成,Switch 组件 - Laravel Admin](https://image.catchadmin.com/202506091835857.png) 还会在对应的控制器生成如下代码,因为是 `status` 字段,所以生成下面的默认代码 ```php public function enable(mixed $id): mixed { return $this->model->toggleBy($id); } ``` 如果是其他非`status`字段则生成如下代码 ```php public function enable(mixed $id, Request $request): mixed { $field = $request->get('field'); return $this->model->toggleBy($id, $field); } ``` :::warning 这里需要注意的是,系统内置的状态切换的值,并不是 0 和 1。而是 `1 是` 和 `2 否`,如果不是这么做的,需要你自己再模型重写 `toggleBy` 方法 ::: ### 导出 如图,选择你需要导出的字段 ![CatchAdmin 代码生成,导出 组件 - Laravel Admin](https://image.catchadmin.com/202506111045226.png) 最终代码生成一个导出得文件 `modules/Test/Excel/Export/xxxxExport.php`,文件内容如下 ```php /** * 导出数据 * * * @class Excel\Export\AdminUsersExport */ class AdminUsersExport extends Export { protected array $header = [ 'id', '字典选择器', '图标选择', '远程树形', '文件上传', '但附件', '多附件上传', '图片上传', '多图片上传', '创建时间', '更新时间', ]; /** * @return array */ public function array(): array { return AdminUsers::query()->get()->select([ 'id', 'username', 'password', 'avatar', 'remember_token', 'department_id', 'status_text', 'login_ip', 'login_at', 'created_at', 'updated_at', ])->toArray(); } } ``` 这里主要注意的是。代码生成器会在转换上面的枚举值,将对应的枚举值转换成中文说明 ### 导入 跟导出是一样的,选择字段进行导入 ![CatchAdmin 代码生成,导入 组件 - Laravel Admin](https://image.catchadmin.com/202506111049536.png) 最终代码生成一个导出得文件 `modules/Test/Excel/Export/xxxxImport.php`,文件内容如下 ```php /** * 导入数据 * * * @class Excel\Import\AdminUsersImport */ class AdminUsersImport extends Import { /** * 导入数据 * * * @param Collection $rows * @return void */ public function collection(Collection $rows): void { $rows->each(function ($row) { $model = new AdminUsers; $model->id = $row[0]; $model->username = $row[1]; $model->password = $row[2]; $model->mobile = $row[3]; $model->email = $row[4]; $model->save(); }); } } ``` CatchAdmin 还自动生成了一个模板文件,根据选择字段`label`值。模板文件存放在`storage/static/importTemplates/xxxx导入模板.xlsx`。 :::warning 实际导入业务比较复杂,可以自行修改导入类 ::: --- --- url: /docs/5.0/server/model.md --- # CatchModel 模型介绍 在后台项目开发中,大部分业务逻辑都与数据模型操作和数据库交互相关。为了简化开发流程并提供统一的数据操作接口,`CatchAdmin` 框架提供了功能强大的模型基类 `CatchModel`。所有业务模型都继承自 `CatchModel`,从而获得丰富的数据操作功能和内置特性。 ::: tip 重要提示 建议仔细阅读本文档,全面掌握 CatchModel 的数据操作功能将显著提升开发效率 ::: ## CatchModel 核心类 `CatchModel` 是 `CatchAdmin` 框架的核心模型基类,基于 Laravel Eloquent ORM 进行扩展,继承自 Laravel 的 `Model` 类,并集成了多个高级功能特性: ```php abstract class CatchModel extends Model { use BaseOperate, Trans, SoftDeletes, ScopeTrait; /** * 使用 Unix 时间戳格式 * @var string */ protected $dateFormat = 'U'; /** * 默认分页数量 */ protected $perPage = 10; /** * 关闭 Laravel 自动时间戳管理 * @var bool */ public $timestamps = false; /** * 默认类型转换配置 * @var array */ protected array $defaultCasts = [ 'created_at' => 'datetime:Y-m-d H:i:s', 'updated_at' => 'datetime:Y-m-d H:i:s', ]; /** * 默认隐藏字段 * @var array */ protected array $defaultHidden = ['deleted_at']; public function __construct(array $attributes = []) { parent::__construct($attributes); $this->init(); } /** * 初始化模型配置 */ protected function init() { $this->makeHidden($this->defaultHidden); $this->mergeCasts($this->defaultCasts); } /** * 自定义软删除启动方法 */ public static function bootSoftDeletes(): void { static::addGlobalScope(new SoftDelete()); } /** * 覆盖恢复方法,使用自定义的软删除逻辑 */ public function restore(): bool { if ($this->fireModelEvent('restoring') === false) { return false; } $this->{$this->getDeletedAtColumn()} = 0; $this->exists = true; $result = $this->save(); $this->fireModelEvent('restored', false); return $result; } } ``` ### 时间戳处理机制 `CatchAdmin` 框架中所有数据表的 `created_at` 和 `updated_at` 时间字段都采用 Unix 时间戳(`int` 类型)进行存储,这种设计提升了数据库查询效率。为了在 API 返回给前端时提供用户友好的日期格式,框架内置了数据类型转换配置: ```php protected array $defaultCasts = [ 'created_at' => 'datetime:Y-m-d H:i:s', 'updated_at' => 'datetime:Y-m-d H:i:s', ]; ``` ::: info 为什么 CatchModel 使用 `defaultCasts` 而不是 `casts`? 由于所有业务模型都继承自 `CatchModel`,而日期类型转换是每个数据模型都需要的基础功能。如果直接使用 Laravel 的 `casts` 属性,在子类中定义自己的 `casts` 时可能会覆盖基类的配置。`CatchModel` 使用 `defaultCasts` 可以确保基础转换不被意外覆盖。`defaultHidden` 属性也采用了同样的设计理念。 ::: ### 软删除机制 `CatchModel` 采用了自定义的软删除机制,与 Laravel Eloquent 默认的 `null` 值不同,使用 `0` 数值作为数据未删除状态。这种设计更符合数据库索引优化的需求,能够提升大数据量场景下的查询性能。 ::: tip `CatchModel` 的软删除使用方式与 Laravel 原生 SoftDelete 功能保持一致,无需额外配置。 ::: ```php class SoftDelete extends SoftDeletingScope { public function apply(Builder $builder, Model $model) { $builder->where($model->getQualifiedDeletedAtColumn(), '=', 0); } } ``` ## 模型属性配置 `CatchModel` 提供了丰富的模型属性配置选项,用于精细控制数据模型的 CRUD 操作行为、查询逻辑和数据处理特性: ### 数据结构相关属性 ```php // 树形结构父级字段,建议使用默认值 protected string $parentIdColumn = 'parent_id'; // 排序字段配置 protected string $sortField = 'sort'; protected bool $sortDesc = true; // 默认倒序 // 列表数据返回格式 protected bool $asTree = false; // 是否以树形结构返回 protected bool $isPaginate = true; // 是否启用分页 ``` ### 查询和表单相关属性 ```php // 列表查询默认字段 protected array $fields = []; // 表单提交字段配置 protected array $form = []; // 关联关系处理(如用户与角色的多对多关系) protected array $formRelations = []; ``` ### 权限控制属性 ```php // 数据权限控制 protected bool $dataRange = false; // 字段权限控制 protected bool $columnAccess = false; // 创建人自动填充 protected bool $isFillCreatorId = true; ``` ### 数据处理属性 ```php // 空值自动转换 protected bool $autoNull2EmptyString = true; // 动态排序参数 protected string $dynamicQuerySortField = 'sortField'; protected string $dynamicQuerySortOrder = 'order'; ``` ## 模型方法详解 ### 数据查询方法 #### 获取列表数据 ```php public function getList(): mixed ``` 该方法是 `CatchModel` 的核心数据查询方法,集成了多种高级数据检索功能: * 字段权限过滤 * 创建人信息关联 * 快速搜索支持 * 数据权限控制 * 自定义排序规则 * 动态排序支持 * 分页/树形结构返回 #### 列表查询自定义扩展 通过 `CatchModel` 的 `setBeforeGetList` 方法可以在数据查询执行前添加自定义逻辑: ::: code-group ```php [排序示例] // 添加自定义排序规则 $model->setBeforeGetList(function ($query) { return $query->orderByDesc('sort'); })->getList(); ``` ```php [联表查询] // 添加表连接 $model->setBeforeGetList(function ($query) { return $query->join('some_table', 'table.id', '=', 'some_table.table_id'); })->getList(); ``` ```php [关联加载] // 添加关联关系加载 $model->setBeforeGetList(function ($query) { return $query->with('someRelations'); })->getList(); ``` ::: ### 数据保存方法 #### 保存数据(单条记录) ```php public function storeBy(array $data): mixed ``` `CatchModel` 的数据保存方法,用于处理单条数据记录的数据库存储,支持 Laravel 关联关系的智能处理。操作成功返回主键 ID,失败返回 `false`。 #### 创建数据(批量操作) ```php public function createBy(array $data): mixed ``` ::: tip `createBy` 方法适用于循环批量创建数据的业务场景,而 `storeBy` 更适合单条数据 CRUD 操作。它会每次创建模型实例,并且触发模型事件 ::: 示例如下,每次都是新的模型实例,每次创建都会触发模型事件 ```php foreach($data as $item) { $model->createBy($item); } ``` #### 更新数据 ```php public function updateBy($id, array $data): mixed ``` `CatchModel` 的数据更新方法,根据主键 ID 更新数据记录,支持 Laravel 关联关系的同步更新。 #### 批量更新 ```php public function batchUpdate(string $field, array $condition, array $data): bool ``` **参数说明:** | 参数 | 类型 | 说明 | | ------------ | -------- | ---------------------------- | | `$field` | `string` | 更新条件字段(如 `id`) | | `$condition` | `array` | 条件值数组(如 `[1, 2, 3]`) | | `$data` | `array` | 更新数据键值对 | ::: warning CatchModel 批量更新注意事项 * 该方法不会触发 Laravel 模型事件 * 数据条件数量必须与更新数据数量一致 ::: **使用示例:** ```php $model = new SomeModel(); $model->batchUpdate('id', [1, 2, 3], [ 'name' => ['小明', '小隋', '小书'], 'age' => [12, 13, 14] ]); ``` ### 数据查询方法 #### 单条数据查询 ```php public function firstBy($value, $field = null, array $columns = ['*']): ?Model ``` `CatchModel` 的单条数据查询方法,根据指定数据库字段查询单条记录,默认使用主键 `id` 字段。支持数据权限和字段权限过滤。 ### 数据删除方法 #### 删除数据 ```php public function deleteBy($id, bool $force = false, bool $softForce = false): ?bool ``` `CatchModel` 的数据删除方法,根据主键 ID 删除数据记录,默认采用安全的软删除机制。当 `$force` 参数设置为 `true` 时进行永久物理删除。 #### 删除软删除数据 ```php public function deleteTrash($id): mixed ``` 彻底删除已被 `CatchModel` 软删除标记的数据记录,执行永久性数据库删除操作。 #### 批量删除 ```php public function deletesBy(array|string $ids, bool $force = false, ?Closure $callback = null): bool ``` `CatchModel` 的批量删除方法,支持同时处理正常数据和软删除数据的批量删除操作。`$ids` 参数支持灵活的数据格式,可以是 PHP 数组或逗号分隔的字符串(如 `"1,2,3,4,5"`)。 `$callback` 参数可用于处理删除后的回调逻辑: ```php $ids = [1, 2, 3]; $this->deletesBy($ids, false, function($ids) { // $ids [1, 2, 3] // 这里处理删除后的逻辑 }); ``` #### 恢复数据 ```php public function restoreBy(array|string $ids): true ``` 配合 CatchAdmin 后台管理系统的数据回收站功能,用于恢复 `CatchModel` 软删除的数据记录。 ### 辅助功能方法 #### 排序功能 通过设置 `sortField` 属性可以指定默认排序字段: ```php protected string $sortField = 'sort'; ``` 默认使用倒序排序,如需正序排序可设置: ```php protected bool $sortDesc = false; ``` #### 状态切换 ```php public function toggleBy($id, string $field = 'status'): bool ``` 通过主键 ID 进行状态字段的切换,默认操作 `status` 字段。 #### 处理树状数据的子级更新 ```php public function updateChildren(mixed $parentId, string $field, mixed $value): void ``` 递归更新树形结构中指定父级下所有子级的字段值。 #### 字段别名处理 ```php public function aliasField(string|array $fields): string|array ``` 为字段添加表名前缀,避免联表查询时的字段冲突。 #### 创建人相关方法 ```php // 设置创建人 ID public function setCreatorId() // 获取创建人信息(Scope 查询) public function scopeCreator() ``` 使用创建人查询 Scope: ```php Model::select('*')->creator()->get(); ``` ::: info 使用条件 使用该查询需要数据表包含 `creator_id` 字段,否则无效果。 ::: #### 模糊查询 ```php public function whereLike($field, $value) ``` 提供便捷的模糊查询方法。 #### 快速搜索 ```php public function quickSearch(array $params = []) ``` 该方法通过模型的 `searchable` 属性配合请求参数进行动态搜索: ```php protected array $searchable = [ 'status' => '=', 'nickname' => 'like' ]; ``` 在 `CatchModel` 中配置 `searchable` 属性后,框架会自动生成相应的数据库查询条件: ```php Model::select('*') ->where('status', $request->get('status')) ->whereLike('nickname', $request->get('nickname')) ->get(); ``` `CatchModel` 的快速搜索支持数据库别名字段,特别适用于多表 `JOIN` 联查询场景。例如当 A 和 B 两张表都包含 `status` 字段时,可以精确指定查询目标 ```php // 在 CatchModel 中可以指定使用 A 表的 status 字段进行精确查询 protected array $searchable = [ 'A.status' => '=', ]; ``` ### CatchModel 数据库事务处理 `CatchModel` 在模型类中内置集成了 Laravel 数据库事务处理方法,无需额外引入 `DB` Facade: ```php // 开启事务 $this->beginTransaction(); // 提交事务 $this->commit(); // 回滚事务 $this->rollback(); // 事务闭包 $this->transaction(function() { // 事务内的操作 }); ``` ::: tip CatchModel 事务处理便捷性 相比传统的 `DB::beginTransaction()` 方式,`CatchModel` 直接在模型中调用事务方法更加便捷,提升了 PHP 开发效率。 ::: --- --- url: /docs/5.0/server/permission.md --- # CatchAdmin 权限管理 > 基于 RBAC 模型的权限系统介绍 CatchAdmin 采用业界成熟的 `RBAC`(基于角色的访问控制)权限模型,即用户一对多角色,角色一对多权限的设计。这种模式通过角色作为中间层,实现了灵活的权限分配和管理。 如果对 `RBAC` 权限模型需要深入了解,建议参考 [Oracle 官方文档:基于角色的访问控制](https://docs.oracle.com/cd/E19253-01/819-7061/rbac-38/index.html)。 ## 基本约定 * **超级管理员免检**:超级管理员不受任何权限控制,拥有系统全部操作权限 * **GET 请求放行**:所有 `GET` 请求默认放行,不受权限限制(查询操作通常不涉及数据变更) ## 权限约定 ## 权限模块 CatchAdmin 为保持系统轻量化,默认不开启权限模块和动态菜单功能。如果项目需要权限控制,第一步需要安装权限模块: ```php php artisan catch:module:install permissions ``` :::info 开启之后如果没有权限菜单,可以刷新一下 ::: ### 中间件 权限模块提供了权限控制的中间件,实现自动的权限验证: ```php title="modules/Permissions/Middlewares/PermissionGate.php" class PermissionGate { public function handle(Request $request, \Closure $next) { // GET 请求全部通过(遵循基本约定) if ($request->isMethod('get')) { return $next($request); } /* @var User $user */ $user = $request->user(getGuardName()); // 权限验证失败则拦截请求 if (! $user->can()) { throw new PermissionForbidden(); } return $next($request); } } ``` ### 添加权限 权限配置是系统的核心功能。由于 CatchAdmin 采用前后端分离架构,权限配置相比传统项目略为复杂,需要同时考虑前端路由和后端 API 的权限控制。 建议先熟悉 [Vue Router](https://router.vuejs.org/) 的基本概念。配置入口:**权限管理/菜单管理** → **新增**: ![pSl4dVP.png](https://s1.ax1x.com/2023/01/16/pSl4dVP.png) CatchAdmin 将权限分为三种层级类型: * **目录**:构建导航结构的一级菜单容器,用于功能分组 * **菜单**:对应具体的功能页面,关联前端路由组件 * **按钮**:页面内的具体操作功能,每个按钮对应后端控制器的一个 `action` 方法(这是后端权限控制的关键) * 路由 `Path` 对应前端 `vue` 路由的 `path` * 组件 对应前端 `vue` 路由的 `component` * 目录类型一般都是选择 Layout 组件 * 菜单类型则是选择对应页面的组件 **前后端分离的权限控制特点**: 传统 Laravel 项目中,页面和数据都由 PHP 控制。CatchAdmin 采用前后端分离后: * **前端负责**:页面渲染、菜单显示、路由跳转 * **后端负责**:API 接口访问控制、数据操作权限 因此,CatchAdmin 的 RBAC 权限重点在于**控制 API 访问**。后端需要为每个控制器的 `action` 方法配置对应的权限,确保数据操作的安全性。 ### 权限判断 基于 CatchAdmin 的模块化架构,权限标识采用统一格式: ``` module@controller@action // 模块名称@控制器名称@控制器方法名称 ``` **示例说明**:权限模块的角色列表功能,位于权限模块(Permissions)的角色控制器(RolesController)的 `index` 方法,其权限标识为: ```php Modules\Permissions\Http\Controller\RolesController@index ``` **权限验证失败排查**:当遇到权限认证失败时,通常是权限配置问题。请检查数据库 `permissions` 表中的配置: ![catchadmin 权限-laravel admin](https://image.catchadmin.com/202405220926755.png) 确认 `module` 和 `permission_mark` 字段是否符合 `module@controller@action` 的格式规则。 #### 当前用户是否有权限 ```php Auth::user()->can(string $permission = null); ``` * `$permission` 参数:权限标识,格式为 `module@controller@action`,例如 `Permissions@Roles@index` #### 用户的权限 ```php /*@var Model\Roles $user*/ $user->withPermissions()->permissions; ``` #### 角色权限 ```php /*@var Model\Roles $role*/ $role->getPermissions() ``` ## 取消权限中间件验证 下面是示例代码,使用`withoutMiddleware(\Modules\Permissions\Middlewares\PermissionGate::class)` ```php Route::withoutMiddleware(\Modules\Permissions\Middlewares\PermissionGate::class) ->group(function(){ Route::prefix('official')->group(function (){ Route::get('sign', [OfficialAccountController::class, 'sign']); }); //next }); ``` --- --- url: /docs/5.0/server/data_permission.md --- # CatchAdmin 数据权限 > 基于角色的细粒度数据访问控制系统 ## 数据权限介绍 数据权限是企业级权限管理的重要组成部分,用于控制用户只能访问和操作特定范围内的数据。由于并非所有项目都需要这种细粒度的数据控制,CatchAdmin 默认不启用数据权限功能。 **应用场景**: * **企业多部门**:不同部门只能访问自己部门的数据 * **层级管理**:上级可以查看下级的数据,但下级不能查看上级数据 * **个人数据隔离**:用户只能查看自己创建的数据 CatchAdmin 的数据权限与角色系统紧密集成,通过角色配置实现灵活的数据访问控制: ![pSlzXdO.png](https://s1.ax1x.com/2023/01/16/pSlzXdO.png) ## 数据权限类型 CatchAdmin 提供五种数据权限级别,覆盖不同的业务需求: ### 1. 全部数据权限 * **权限范围**:可以访问系统中的所有数据 * **适用角色**:系统管理员、超级用户 * **使用场景**:数据统计分析、系统维护 ### 2. 自定义数据权限 * **权限范围**:可以自定义指定特定的数据范围 * **适用角色**:特殊权限的管理角色 * **使用场景**:跨部门项目负责人、特定业务管理员 ### 3. 部门数据权限 * **权限范围**:只能访问本部门的数据 * **适用角色**:部门普通成员 * **使用场景**:销售部门只看销售数据、技术部门只看技术数据 ### 4. 部门及以下数据权限 * **权限范围**:可以访问本部门及其下级部门的数据 * **适用角色**:部门主管、中层管理者 * **使用场景**:部门经理管理整个部门体系的数据 ### 5. 仅本人数据权限 * **权限范围**:只能访问自己创建的数据 * **适用角色**:普通员工、实习生 * **使用场景**:个人工作记录、私人数据管理 ## 使用约定 ### 数据表要求 要使用数据权限功能,数据表必须满足以下结构要求: 1. **creator\_id 字段**:必需字段,用于标识数据的创建者 ```sql `creator_id` int(11) NOT NULL DEFAULT 0 COMMENT '创建者ID' ``` 2. **部门关联**:如果使用部门相关权限,用户表需要包含部门信息 ```sql `dept_id` int(11) NOT NULL DEFAULT 0 COMMENT '所属部门ID' ``` ### 字段说明 * **creator\_id**:CatchAdmin 统一使用此字段标识数据归属 * **自动填充**:CatchModel 会自动填充 creator\_id 字段 * **权限过滤**:系统根据此字段进行数据权限过滤 ## 配置步骤 ### 前置条件 使用数据权限前,请确保满足以下条件: 1. **权限模块已启用**:数据权限依赖权限管理模块 2. **角色数据权限配置**:为角色设置合适的数据权限范围 3. **用户部门设置**:使用部门权限时,用户必须设置所属部门 4. **数据表结构**:确保相关表包含 `creator_id` 字段 ### 配置流程 1. **角色配置**:在角色管理中设置数据权限类型 2. **用户分配**:为用户分配对应的角色 3. **部门设置**:为用户设置所属部门(如需要) 4. **模型配置**:在相关模型中启用数据权限 ## 代码实现 ### 模型中启用数据权限 在需要数据权限控制的模型中引入 `DataRange` trait: ```php title="modules/Permissions/Models/Traits/DataRange.php" use Modules\Permissions\Models\Traits\DataRange; class UserModel extends CatchModel { use DataRange; // 其他模型代码... } ``` ### 自动权限过滤 引入 `DataRange` trait 后,模型的列表查询会自动应用数据权限过滤: ```php // 自动应用当前用户的数据权限 $users = UserModel::getList(); ``` ### 手动权限查询 如需在特定查询中单独使用数据权限,可以使用 `dataRange` 作用域: ```php // 手动应用数据权限 $filteredData = UserModel::select('*') ->dataRange() ->where('status', 1) ->get(); ``` ### 权限检查方法 ```php // 检查当前用户对特定数据的访问权限 if ($model->hasDataPermission($dataId)) { // 有权限访问 return $model->find($dataId); } else { // 无权限访问 throw new PermissionDenied('无权限访问此数据'); } ``` ## 使用注意事项 1. **性能考虑**:数据权限会在查询中添加额外的 WHERE 条件,大数据量时建议添加相关索引 2. **权限调试**:开发时可通过日志查看生成的 SQL 语句,确认权限过滤是否正确 3. **角色变更**:用户角色变更后,数据权限会立即生效,无需重新登录 4. **数据一致性**:确保所有相关表都正确设置了 `creator_id` 字段 --- --- url: /docs/5.0/server/upload.md --- # 文件上传功能 CatchAdmin 提供了完整的文件上传解决方案,支持本地上传、OSS 云存储、COS 云存储等多种上传方式。系统基于 Laravel Filesystem 构建,为开发者提供了灵活且强大的文件管理能力。 本文档将详细介绍各种上传组件的使用方法,包括图片上传、单文件上传、多文件上传、大文件分片上传等功能。除特殊说明外,所有组件默认基于本地存储。 ## 后端本地上传配置 CatchAdmin 基于 Laravel Filesystem 提供了两个预配置的本地存储磁盘(disk),满足不同的文件存储需求: * **uploads**: 用于存储用户上传的文件,支持公开访问,适合图片、文档等需要直接访问的文件 * **static**: 用于存储系统内部文件,私有访问,适合配置文件、日志等敏感文件 以下是系统内置的磁盘配置,开发者可以根据项目需求添加自定义的 disk 配置: ```php // config/filesystem.php [ 'disks' => [ // 公共上传目录 - 用户上传的文件存储 'uploads' => [ 'driver' => 'local', // 使用本地存储驱动 'root' => storage_path('uploads'), // 存储根目录:storage/uploads 'url' => env('APP_URL').'/uploads', // 公开访问URL前缀 'visibility' => 'public', // 文件可公开访问 'throw' => false, // 操作失败时不抛出异常 ], // 私有静态文件目录 - 系统内部文件存储 'static' => [ 'driver' => 'local', // 使用本地存储驱动 'root' => storage_path('static'), // 存储根目录:storage/static 'visibility' => 'private', // 文件私有访问 'directory_visibility' => 'private', // 目录私有访问 'throw' => false, // 操作失败时不抛出异常 ], ] ] ``` ### 磁盘配置参数说明 | 参数 | 说明 | uploads 配置 | static 配置 | | ---------------------- | ----------------- | ----------------------------- | ----------------------------- | | `driver` | 存储驱动类型 | local(本地存储) | local(本地存储) | | `root` | 文件存储根目录 | storage/uploads | storage/static | | `url` | 公开访问 URL 前缀 | /uploads | 无(私有访问) | | `visibility` | 文件访问权限 | public(公开) | private(私有) | | `directory_visibility` | 目录访问权限 | 继承文件权限 | private(私有) | | `throw` | 错误处理方式 | false(返回错误而不抛出异常) | false(返回错误而不抛出异常) | ### 前端组件配置参数 前端上传组件通过 `props` 属性来指定使用哪个存储磁盘和存储路径。所有上传组件都支持以下通用配置参数: ```ts { // 指定存储磁盘,对应后端 filesystem 配置中的 disk 名称 disk: { type: String, default: 'uploads' // 默认使用 uploads 磁盘(公开访问) }, // 指定存储子目录,相对于磁盘根目录的路径 path: { type: String, default: 'attachments' // 默认存储在 attachments 文件夹下 } } ``` **参数说明:** * `disk`: 选择后端配置的存储磁盘,如 `uploads`(公开)或 `static`(私有) * `path`: 文件存储的子目录,最终存储路径为 `{disk.root}/{path}/filename` ## 前端上传组件 CatchAdmin 提供了多种上传组件,满足不同的业务场景需求。 ### 图片上传组件 (UploadImage) 用于上传单张图片文件,支持图片预览和格式限制。 **基础使用:** ```vue ``` **自定义存储配置:** ```vue ``` **组件属性:** | 属性 | 类型 | 默认值 | 说明 | | ----------------- | ------ | -------------------------- | -------------------------- | | `v-model` | String | - | 绑定上传后的文件路径 | | `class` | String | - | CSS 样式类名,设置组件尺寸 | | `file-extensions` | Array | `['.jpg', '.png', '.gif']` | 允许上传的文件扩展名 | | `disk` | String | `'uploads'` | 存储磁盘名称 | | `path` | String | `'images'` | 存储子目录路径 | | `max-size` | Number | `2048` | 最大文件大小(KB) | ### 单文件上传组件 (UploadFile) 用于上传单个文件,支持多种文件格式,适合文档、表格等文件上传。 **基础使用:** ```vue ``` **自定义存储配置:** ```vue ``` **组件属性:** | 属性 | 类型 | 默认值 | 说明 | | ----------------- | ------------- | -------------------------- | ------------------------------ | | `v-model` | String/Object | - | 绑定上传后的文件信息 | | `file-extensions` | Array | `['.txt', '.doc', '.pdf']` | 允许上传的文件扩展名 | | `disk` | String | `'uploads'` | 存储磁盘名称 | | `path` | String | `'files'` | 存储子目录路径 | | `max-size` | Number | `10240` | 最大文件大小(KB) | | `accept` | String | - | HTML accept 属性,文件类型限制 | ### 多文件上传组件 (UploadFiles) 用于同时上传多个文件,支持批量文件处理,适合需要上传多个文档的场景。 **基础使用:** ```vue ``` **自定义存储配置:** ```vue ``` **组件属性:** | 属性 | 类型 | 默认值 | 说明 | | ----------------- | ------- | -------------------------- | ---------------------- | | `v-model` | Array | `[]` | 绑定上传后的文件列表 | | `file-extensions` | Array | `['.txt', '.doc', '.pdf']` | 允许上传的文件扩展名 | | `disk` | String | `'uploads'` | 存储磁盘名称 | | `path` | String | `'files'` | 存储子目录路径 | | `max-files` | Number | `5` | 最大上传文件数量 | | `max-size` | Number | `10240` | 单个文件最大大小(KB) | | `multiple` | Boolean | `true` | 是否支持多选文件 | ### 大文件分片上传组件 (ChunkUpload) 专为大文件(GB 级别)设计的分片上传组件,支持断点续传和上传进度显示。适用于视频、大型文档等文件上传。 **基础使用:** ```vue ``` **自定义分片配置:** ```vue ``` **组件属性:** | 属性 | 类型 | 默认值 | 说明 | | --------------- | ------------- | ------------------------ | ------------------------------ | | `v-model` | String/Object | - | 绑定上传后的文件信息 | | `action` | String | `'/upload/chunk'` | 分片上传接口地址 | | `chunk-size` | Number | `2 * 1024 * 1024` | 分片大小(字节),默认 2MB | | `max-file-size` | Number | `2 * 1024 * 1024 * 1024` | 最大文件大小(字节),默认 2GB | | `auto-upload` | Boolean | `true` | 是否自动开始上传 | | `retry-count` | Number | `3` | 分片上传失败重试次数 | **配置示例:** ```vue ``` ### 附件上传组件 (AttachUpload) 通用附件上传组件,支持各种文件类型的上传,可配置单文件或多文件模式。 **基础使用(单文件):** ```vue ``` **多文件上传:** ```vue ``` **组件属性:** | 属性 | 类型 | 默认值 | 说明 | | ----------- | ------------ | --------------- | ---------------------------------------- | | `v-model` | String/Array | - | 单文件模式绑定字符串,多文件模式绑定数组 | | `class` | String | - | CSS 样式类名 | | `multi` | Boolean | `false` | 是否支持多文件上传 | | `disk` | String | `'uploads'` | 存储磁盘名称 | | `path` | String | `'attachments'` | 存储子目录路径 | | `max-files` | Number | `5` | 多文件模式下最大文件数量 | | `max-size` | Number | `10240` | 最大文件大小(KB) | ## 云存储上传 CatchAdmin 支持主流云存储服务,提供更高的可靠性和 CDN 加速能力。 ### 阿里云 OSS 上传组件 (OssUpload) 集成阿里云对象存储服务,支持直传和服务端签名上传,提供高可用的文件存储方案。 **前提条件:** 需要在后台管理系统中配置 OSS 相关参数(AccessKey、SecretKey、Bucket 等)。 ![ 上传-OSS上传](https://image.catchadmin.com/202505120832848.png) **基础使用:** ```vue ``` **组件属性:** | 属性 | 类型 | 默认值 | 说明 | | ---------- | ------ | ----------- | -------------------- | | `v-model` | String | - | 绑定上传后的文件 URL | | `class` | String | - | CSS 样式类名 | | `path` | String | `'uploads'` | OSS 存储路径前缀 | | `max-size` | Number | `10240` | 最大文件大小(KB) | ### 腾讯云 COS 上传组件 (CosUpload) 集成腾讯云对象存储服务,提供稳定的云端文件存储和访问能力。 **前提条件:** 需要在后台管理系统中配置 COS 相关参数(SecretId、SecretKey、Bucket、Region 等)。 ![ 上传-cos上传](https://image.catchadmin.com/202505120832297.png) **基础使用:** ```vue ``` **组件属性:** | 属性 | 类型 | 默认值 | 说明 | | ---------- | ------ | ----------- | -------------------- | | `v-model` | String | - | 绑定上传后的文件 URL | | `class` | String | - | CSS 样式类名 | | `path` | String | `'uploads'` | COS 存储路径前缀 | | `max-size` | Number | `10240` | 最大文件大小(KB) | --- --- url: /docs/5.0/server/route.md --- # Laravel 路由扩展 ## 介绍 在后台开发中,处理表格(`table`)是常见的任务。基本的单页表格通常包括列表、数据新增、数据编辑以及行删除这四个主要操作。为此,`Laravel` 提供了一个便捷的 `resource` 路由方法,可以一次性注册相关路由。例如,针对用户管理,我们可以这样定义路由: ```php // CatchAdmin 专业版采用 API 接口开发模式,使用 apiResource 注册路由 Route::apiResource('users', UsesController::class); ``` 此方法自动生成符合 RESTful 规范的五条 API 路由: * `GET` `users` - 显示列表数据 -> `index` 方法 * `POST` `users` - 新增数据 -> `store` 方法 * `PUT` `users/{id}` - 更新数据 -> `update` 方法 * `GET` `users/{id}` - 请求单条数据 -> `show` 方法 * `DELETE` `users/{id}` - 删除数据 -> `destroy` 方法 这样的设计确实很方便,不过如果某个方法不再需要,比如我们不希望保留删除路由,该如何处理呢?这时可以通过 `except` 方法排除掉不需要的路由: ```php Route::apiResource('users', UsesController::class)->except(['destroy']); ``` 后台管理系统中,数据导入导出是常见需求,传统做法需要手动添加额外路由: ```php Route::apiResource('users', UsesController::class)->except(['destroy']); // 手动添加数据导入路由 Route::post('users/import', [UsesController::class, 'import']); ``` 频繁修改路由文件确实不够高效,CatchAdmin 专业版提供了更智能的路由管理解决方案。 ## adminResource CatchAdmin 专业版提供了 `adminResource` 方法来解决这个问题,它是对 Laravel `apiResource` 的智能化扩展。使用方式如下: ```php // 使用 adminResource 智能注册后台管理路由 Route::adminResource('users', UsesController::class); ``` 使用 `adminResource` 后,除了标准的 RESTful 路由外,还自动注册以下后台管理专用路由: * `PUT` `users/enable/{id}` - 状态更改 -> `enable` 方法 * `GET` `export/users` - 导出数据 -> `export` 方法 * `POST` `import/users` - 导入数据 -> `import` 方法 * `PUT` `users/restore/{id}` - 恢复数据 -> `restore` 方法 * `GET` `form/users` - 动态表单 -> `form` 方法 * `GET` `table/users` - 动态表格 -> `table` 方法 CatchAdmin 专业版还对路由注册机制进行了智能化优化。与 Laravel 原生 `apiResource` 不同,后者无论控制器是否包含对应方法都会注册全部五条路由。例如 `UsesController` 仅有 `index` 方法时,仍需要通过 `except` 方法手动排除不需要的路由。 `adminResource` 则采用智能检测机制:只有当控制器中存在对应的 `public` 方法时,才会注册相应路由。这种设计实现了真正的自动化路由管理,生成的路由表更加精简高效。 :::warning 生产环境部署时,建议执行 `php artisan route:cache` 命令缓存路由配置以提升性能。 ::: --- --- url: /docs/5.0/server/response.md --- # 响应 CatchAdmin 为了统一整个后台的响应格式,对后台的响应数据格式做了代码层面的劫持,所有的响应数据以固定的格式进行输出,如下 ### 成功响应(非分页) | 字段 | 类型 | 说明 | | ------- | ------------- | -------- | | code | int | 返回码 | | data | Object|Array | 返回数据 | | message | string | 返回信息 | ### 错误响应 | 字段 | 类型 | 说明 | | ------- | ------ | -------- | | code | int | 返回码 | | message | string | 返回信息 | ### 成功响应(分页格式) | 字段 | 类型 | 说明 | | ------- | ------ | ------------ | | code | int | 返回码 | | data | Array | 返回数据 | | limit | int | 每页显示数量 | | message | string | 返回信息 | | total | int | 总数 | 使用者一般在控制器的方法返回结果就可以了,例如下面这样的 ```php public function index() { return ['hello' => 'world']; } ``` 在控制器返回都是返回 success 的响应状态给前端,如果你需要错误响应,那么就需要使用异常 ```php public function index() { throw new FaileException('处理异常'); } ``` 具体实现可以参考我写的[博客文章-另辟蹊径!如何在 Laravel 更优雅的响应 JSON 数据 ](https://catchadmin.com/post/2024-03/laravel-unified-response),利用 `Illuminate\Foundation\Http\Events\RequestHandled` 事件来 hook 整个响应内容实现,虽然有些绕口,但是在使用起来真的方便太多了。 ## 自定义 从个人开发经验来说,一般来说,后台的响应格式不会有什么变化,除非出现特殊需求,需要特定的响应格式。CatchAdmin 提供了一个非常易用的操作来实现特定的响应格式 ```php use Catch\Support\ResponseBuilder; public function index() { return ResponseBuilder::success()->with('hello', 'world'); } ``` 最后的响应的内容如下 ![CatchAdmin 响应](https://image.catchadmin.com/202409131350017.png) 还可以这么使用,先使用 `code` 静态方法,然后再进行链式调用 ```php public function index() { return ResponseBuilder::code(10000) ->with('hello', 'world') ->with('hi', 'world') ->data($data) ->message('Hello world'); } ``` 这样就可以轻而易举的实现自定义响应内容了,一般没有特殊的数据格式,建议使用 CatchAdmin 默认的响应即可 --- --- url: /docs/5.0/server/lang.md --- # 国际化 在 `v4.2.5` 版本中,专业版已经将后台语言数据使用后端提供,使用 laravel 框架的多语言功能。在根目录下`lang`目录。目前包含两个语言 * zh * en 目录结构如下 ```php ├─lang │ ├─zh (中文) │ | generate.php | | login.php │ | module.php │ | register.php │ | system.php │ ├─en (英文) │ | generate.php | | login.php │ | module.php │ | register.php │ | system.php ``` 规定以文件名作为某个功能模块的 key 使用,所以具体实现如下 ```php public function translate($lang) { //return admin_cache('lang_'.$lang, 300, function () use ($lang) { $translations = []; $files = File::allFiles(lang_path($lang)); foreach ($files as $file) { $translations[$file->getFilenameWithoutExtension()] = require $file->getRealPath(); } return $translations; // }); } ``` :::warning 默认是不使用缓存的,如果需要,你可以打开缓存,毕竟文件查找得过程是需要耗费时间,尤其是数据多了之后得情况下 ::: 前端还是在`i18n`目录下,跟之前的有所区别,但区别不大,只是加入异步加载得功能,具体实现如下 ```js import Cache from '@/support/cache' import { createI18n } from 'vue-i18n' import type { App } from 'vue' import http from '@/support/http' // 语言包缓存的键名 const LANG_CACHE_KEY = 'cached_lang_pack_' // 创建i18n实例 const i18n = createI18n({ locale: Cache.get('language') || 'zh', fallbackLocale: 'zh', globalInjection: true, legacy: false, messages: {} // 初始化为空对象,语言包将从后端加载 }) // 扩展 i18n 类型 declare module 'vue-i18n' { interface I18n { loadLanguage: (lang: string) => Promise } } /** * 从后端加载语言包 * @param locale 语言代码 * @returns Promise 加载是否成功 */ const loadTranslations = async (locale: string): Promise => { // 如果没有缓存,从后端获取语言包 try { const response = await http.get(`/lang/${locale}`) if (response.data && response.data.data) { // 设置语言包 i18n.global.setLocaleMessage(locale, response.data.data) // 更新当前语言 i18n.global.locale.value = locale // 保存语言设置到缓存 Cache.set('language', locale) // 缓存语言包数据 Cache.set(`${LANG_CACHE_KEY}${locale}`, response.data.data) return true } return false } catch (error) { // 如果是默认语言且没有缓存,则失败 if (locale === 'zh') { return false } return loadTranslations('zh') } } // 将 loadLanguage 方法挂载到 i18n 对象上 i18n.loadLanguage = loadTranslations /** * 初始化i18n * @param app Vue应用实例 */ export async function bootstrapI18n(app: App): Promise { // 加载默认语言包 const defaultLocale = Cache.get('language') || 'zh' try { // 尝试加载默认语言包 const success = await loadTranslations(defaultLocale) // 如果默认语言加载失败且不是中文,尝试加载中文 if (!success && defaultLocale !== 'zh') { await loadTranslations('zh') } } catch (error) { // 如果加载失败,创建一个空的语言包以避免应用崩溃 i18n.global.setLocaleMessage('zh', {}) i18n.global.locale.value = 'zh' } // 注册i18n插件 app.use(i18n) } export default i18n ``` 当然这整个过程还是需要前后端配合的,前端依旧使用 `t` 函数进行多语言翻译。所以整个开发过程中,前后端需要定义好翻译的 key,前端使用 ```js // t 函数进行翻译 t('generate.code.xxxx.xxxx') ``` 这样就可以使用后端来输出翻译数据给前端,即使修改了数据则不需要重新打包 --- --- url: /docs/5.0/server/command.md --- # CatchAdmin 命令行工具 > 强大的 Artisan 命令集,简化开发和维护工作 CatchAdmin 提供了丰富的命令行工具,所有自定义命令都以 **catch** 为前缀,便于识别和使用。 **查看所有 CatchAdmin 命令**: ```shell php artisan | grep catch ``` 这些命令覆盖了项目安装、模块管理、数据库操作、代码生成等常见开发场景,显著提升开发效率。 ## 🔧 基础命令 ### 查看版本号 ```shell php artisan catch:version ``` 显示当前 CatchAdmin 的版本信息,用于版本确认和问题排查。 ### 项目安装 ```shell php artisan catch:install ``` **用途**:全新项目的初始化安装 **功能**: * 创建基础数据表结构 * 生成默认配置文件 * 初始化系统基础数据 * 设置默认管理员账户 ## 📦 模块管理 ### 模块安装 ```shell php artisan catch:module:install ``` **参数说明**: * ``:必需参数,模块名称 **功能**: * 注册模块到系统 * 执行模块的数据库迁移 * 初始化模块配置 * 生成模块路由缓存 **示例**: ```shell # 安装权限管理模块 php artisan catch:module:install permissions # 安装用户管理模块 php artisan catch:module:install users ``` ## 🗄️ 数据库操作 ### 创建迁移文件 ```shell php artisan catch:make:migration ``` **参数说明**: * ``:目标模块名称 * ``:迁移文件名称 **功能**:在指定模块下创建数据库迁移文件,遵循 Laravel 迁移文件规范。 ### 创建数据填充文件 ```shell php artisan catch:make:seeder ``` **参数说明**: * ``:目标模块名称 * ``:数据填充文件名称 **功能**:创建模块专属的数据填充文件,用于初始化测试数据或基础配置数据。 ### 执行数据库迁移 ```shell php artisan catch:migrate ``` **功能**:执行指定模块的数据库迁移文件,创建或更新模块相关的表结构。 **示例**: ```shell # 执行权限模块的数据库迁移 php artisan catch:migrate permissions ``` ### 执行数据填充 ```shell php artisan catch:db:seed ``` **功能**:执行指定模块的数据填充文件,为模块添加初始化数据。 **示例**: ```shell # 执行权限模块的数据填充 php artisan catch:db:seed permissions ``` **注意**:确保先执行迁移命令创建表结构,再执行数据填充。 ## 🔄 模块分发 ### 导出模块菜单 ```shell php artisan catch:export:menu ``` **参数说明**: * ``:必需参数,模块名称 * ``:可选参数,权限表名,默认为 `permissions` **功能**: * 导出模块的菜单权限配置 * 生成对应的 seed 文件 * 便于模块在不同项目间分发 **使用场景**: * 模块开发完成后的打包分发 * 跨项目模块迁移 * 开源模块的标准化发布 **示例**: ```shell # 导出权限模块的菜单配置 php artisan catch:export:menu permissions ``` :::tip 适用范围 此命令主要用于模块分发场景。如果模块仅在当前项目使用,通常不需要执行此命令。 ::: ## ⚡ 代码生成 ### 生成模型文件 ```shell php artisan catch:make:model ``` **参数说明**: * ``:目标模块名称 * ``:模型类名称 * ``:可选参数,对应的数据表名 **功能**: * 在指定模块下生成模型文件 * 自动继承 CatchModel 基类 * 根据表结构生成 fillable 属性 * 遵循 CatchAdmin 模型规范 **示例**: ```shell # 在权限模块下生成 Users 模型 php artisan catch:make:model permissions Users ``` **生成的模型内容**: ```php namespace Modules\Permissions\Models; use Catch\Base\CatchModel as Model; class Users extends Model { protected $table = 'users'; protected $fillable = [ 'id', 'username', 'password', 'email', 'avatar', 'remember_token', 'department_id', 'creator_id', 'status', 'login_ip', 'login_at', 'created_at', 'updated_at', 'deleted_at', ]; } ``` --- --- url: /docs/5.0/server/tips.md --- # CatchAdmin 开发小技巧 > 实用的开发技巧和经验分享 这里收集了 CatchAdmin 后台管理系统和 Laravel 框架的实用开发技巧,帮助开发者更好地适应框架开发。这些技巧来源于实际项目经验,能够有效提升开发效率。也 👏 欢迎开发者补充更多实用技巧 ## 获取最新代码 使用下面的命令 ``` composer run latest ``` ## 取消路由中间件 CatchAdmin 后台路由默认注册了四个核心中间件: ```php Catch\Middleware\AuthMiddleware // 用户认证中间件,校验用户是否过期/账户是否有效 Catch\Middleware\JsonResponseMiddleware // JSON 响应中间件,使用返回 JSON 数据 Modules\User\Middlewares\OperatingMiddleware // 操作日志记录中间件,记录请求操作记录 Modules\Permissions\Middlewares\PermissionGate // 权限验证中间件,校验用户是否有对应的操作权限 ``` 模块中的路由通常会**全局**应用这些中间件,但某些场景下(如微信公众号验证、第三方回调接口等)并不需要这些中间件。可以使用以下技巧进行灵活控制: ### 取消后台所有公共的中间件 使用 `withoutMiddleware(config('catch.route.middlewares'))` 可以取消所有默认中间件: ```php Route::withoutMiddleware(config('catch.route.middlewares')) ->prefix('wechat') ->group(function(){ Route::prefix('official')->group(function (){ Route::get('sign', [OfficialAccountController::class, 'sign']); }); //next }); ``` ### 取消某个中间件 如果只需要取消特定中间件(如权限验证),可以这样操作: ```php Route::withoutMiddleware(\Modules\Permissions\Middlewares\PermissionGate::class) ->prefix('wechat') ->group(function(){ Route::prefix('official')->group(function (){ Route::get('sign', [OfficialAccountController::class, 'sign']); }); //next }); ``` ## 响应自定义 CatchAdmin 默认使用统一的响应结构,格式如下: ```php return [ 'message' => '', 'data' => '', 'code' => '' ] ``` 某些场景下需要自定义响应结构(如第三方 API 对接),可以使用 `ResponseBuilder` 实现灵活的响应格式: ```php return ResponseBuilder::code(10000) ->with('hello', 'world') ->with('hi', 'world') ->data($data) ->message('Hello world'); ``` ## 验证属性遇到第一个错误直接返回 Laravel 默认会验证所有规则后再返回错误,这在包含数据库查询的验证规则时会造成性能浪费。例如即使基础验证失败,仍会执行数据库验证: ```php $request->validate([ 'code' => [ 'required', 'size:6', function (string $attribute, mixed $value, \Closure $fail) use ($request) { // 这里是数据验证 code 码,例如手机验证码 }] ]); ``` 为了提升性能,可以使用 `bail` 规则让验证遇到第一个错误就停止: ```php $request->validate([ 'code' => [ 'bail', // 添加这个属性即可 'required', 'size:6', function (string $attribute, mixed $value, \Closure $fail) use ($request) { // 这里是数据验证 code 码,例如手机验证码 }] ]); ``` 如果使用 `FormRequest` 进行验证,可以通过设置 `stopOnFirstFailure` 属性实现全局的"遇错即停": ```php protected $stopOnFirstFailure = true; ``` :::info 通过将 stopOnFirstFailure 属性添加到请求类,一旦发生单个验证失败,它应该停止验证所有属性 ::: ## 如何单独显示菜单 不用菜单下拉 :::info 如果是二级菜单,并且只有`一个`二级菜单的情况下,那么只会显示二级菜单。 ::: 找到前端项目的文件 `src/layout/components/Menu/index.vue`,找到 `filterMenus` 方法,找到下面的代码 ```js menus?.forEach((m) => { if (m.meta?.hidden) { return false } newMenus.push(m) /** if (isHasOnlyChild(m) && m.children?.length) { newMenus.push( Object.assign({ path: m.children[0].path, meta: m.children[0].meta, name: m.name }) ) } else { newMenus.push(m) }*/ }) return newMenus ``` 打开注释即可 ## 前端支持 Keepalive `KeepAlive` 功能可以保持标签页面状态,切换时不重新加载,提升用户体验: ![使用菜单配置页面是否生效](https://image.catchadmin.com/202509130914783.png) :::info 配置完之后记得刷新后台才能生效 ::: --- --- url: /docs/5.0/plugin/quickstart.md --- # 插件快速入门 > 🚀 本章帮助你快速了解 CatchAdmin 插件系统,并在 **5 分钟内**创建你的第一个插件。 ## 什么是 CatchAdmin 插件? CatchAdmin 插件是一种基于 **Composer 包管理机制**的扩展系统,允许开发者以模块化的方式为 CatchAdmin 添加功能。 :::tip 💡 好消息 CatchAdmin 并没有发明新的插件规范——只要你会开发 Composer 包,就已经会开发 CatchAdmin 插件了! 如果你还不熟悉 Composer 包开发,通过本教程学习 CatchAdmin 插件开发,也能同时掌握 Composer 包的开发技能,一举两得! ::: ## 第一步:创建插件 使用 CatchAdmin 提供的初始化命令,可以快速创建一个标准的 Composer 包结构。 在项目根目录执行: ```shell php artisan catch:plugin-init ``` 命令会引导你输入以下信息: | 输入项 | 说明 | 示例 | |--------|------|------| | 插件标题 | 插件的显示名称(建议中文) | `测试插件` | | 包名 | 符合 Composer 规范的包名 | `test/test` | | 描述 | 插件功能说明 | `这是一个测试插件` | | 版本号 | 语义化版本号(默认 1.0.0) | `1.0.0` | | 作者名称 | 系统会自动提取 Git 配置 | `JoJo ` | | PSR-4 命名空间 | 插件的根命名空间 | `Test\Test` | 按提示输入完成后,看到以下信息说明初始化成功: ![CatchAdmin 创建一个新插件包](https://image.catchadmin.com/202512151517370.png) ## 插件目录结构 插件会在项目根目录的 `packages` 目录下生成,例如 `packages/test/test`: ![CatchAdmin 插件结构](https://image.catchadmin.com/202512151521606.png) 初始化后的目录结构非常简洁: ``` ├─test/ │ ├─src/ # 源代码目录 │ │ └─ ... # 你的业务代码 │ ├─hook.php # 插件生命周期钩子 │ ├─composer.json # Composer 配置文件 │ └─README.md # 说明文档 ``` > 📌 关于 `hook.php` 的详细用法,请参考 [生命周期钩子](./hook.md) :::tip 📂 关于目录结构 这只是最基础的结构,后续可以根据需要添加 `routes/`、`migrations/`、`config/` 等目录。详见 [插件开发实战](./practice.md)。 ::: ## 第二步:编写代码 在正式安装插件之前,让我们先添加一些代码来验证插件是否正常工作。 ### 创建测试类 在 `src` 目录下创建 `Hello.php` 文件: ```php plugin() ``` 输出结果: ![运行插件](https://image.catchadmin.com/202512160747863.png) 🎉 **恭喜!** 看到 `hello catchadmin plugin!!! 😀` 说明你的第一个插件已经成功运行了! ## 卸载插件 卸载插件与标准 Composer 操作完全一致: ```shell composer remove test/test --ignore-platform-reqs ``` ## 打包插件 如果你想将插件发布到 CatchAdmin 插件市场,需要先打包。 ### 执行打包命令 ```shell php artisan catch:plugin-pack ``` 按提示输入插件名称(如 `test/test`): ![打包插件](https://image.catchadmin.com/202512160753425.png) 打包完成后,会在 `packages/` 目录生成 `testtest-1.0.0.zip` 文件。 ## 下一步 恭喜你完成了第一个插件的创建!🎊 接下来,你可以继续学习 [插件开发实战](./practice.md),了解如何开发一个完整的后台模块插件,包括: * 数据库迁移 * 模型与控制器 * 路由配置 * Vue 前端页面 * [生命周期钩子](./hook.md) :::info 💬 加入社区 如果你有兴趣为 CatchAdmin 插件生态做贡献,欢迎添加微信 `catchadmin`,我们将手把手指导你解决开发中遇到的问题。 添加好友时请备注 `插件` ::: --- --- url: /docs/5.0/plugin/practice.md --- # 插件开发实战 > 在上一篇 [快速入门](./quickstart.md) 中,我们已经成功搭建了一个基础插件并完成安装。本章将带你**从零开始**,通过一个完整的实战案例,手把手教你开发一个功能完善的 CatchAdmin 后台模块插件。 ## 开始之前 在开始开发之前,请确保你已经: * 完成了 [快速入门](./quickstart.md) 的学习 * 熟悉 Laravel 的基本概念(路由、控制器、模型) * 了解 Vue.js 的基础知识(可选,用于前端页面开发) ## 目录结构约定 开发一个完整的后台模块插件时,我们推荐遵循以下**约定的目录结构**: ``` ├─test # 插件根目录 │ ├─resource # 资源目录(可选) │ │ └─views # Vue 视图文件目录 │ ├─config # 配置文件目录(可选) │ ├─migrations # 数据库迁移目录(可选) │ ├─routes # 路由定义目录(可选) │ ├─src # 源代码目录(核心) │ │ ├─Http # HTTP 层 │ │ │ ├─Controllers # 控制器 │ │ │ └─Requests # 表单验证(可选) │ │ └─Models # 数据模型(可选) │ ├─hook.php # 生命周期钩子 │ ├─composer.json # Composer 配置 │ └─README.md # 说明文档 ``` ### 目录说明 | 目录/文件 | 必需 | 说明 | |-----------|------|------| | `src/` | | 存放插件的核心源代码 | | `composer.json` | | 定义插件的依赖和元信息 | | `hook.php` | | 插件生命周期钩子,详见 [钩子文档](./hook.md) | | `routes/` | 可选 | 定义插件的 API 路由 | | `migrations/` | 可选 | 数据库迁移文件 | | `resource/views/` | 可选 | Vue 前端页面文件 | | `config/` | 可选 | 插件配置文件 | :::tip 什么时候需要这些目录? * **开发完整后台模块**:上述所有目录基本都需要用到 * **开发简单功能插件**:根据实际需求选择性添加 * **开发 API 接口**:必须按照约定的目录结构进行开发 CatchAdmin 的插件本质上就是一个 **Composer 包**,因此你可以根据实际需求灵活组织代码结构。 ::: 接下来,我们将使用上一篇创建的 `test/test` 插件,一步步开发一个完整的后台模块。 ## 第一步:创建数据迁移 大多数插件都需要存储数据,因此我们首先创建数据库迁移文件。 ### 生成迁移文件 执行以下命令,在插件目录中创建迁移文件: ```shell php artisan make:migration CreateUser --path=packages\test\test\migrations ``` 命令执行后,会在 `packages/test/test/migrations` 目录下生成一个迁移文件: ![创建数据迁移](https://image.catchadmin.com/202512161431000.png) :::tip 📚 不熟悉数据迁移? 如果你对 Laravel 的数据迁移不太了解,可以先阅读官方文档:[Laravel 数据迁移](https://laravel-docs.catchadmin.com/docs/12/database/migrations) ::: ### 编写迁移文件 打开生成的迁移文件,添加表结构定义: ```php id(); $table->string('name')->comment('名称'); $table->string('mobile')->comment('手机号'); $table->string('avatar')->nullable()->comment('头像'); $table->timestamps(); }); } /** * Reverse the migrations. */ public function down(): void { Schema::dropIfExists('test_user'); } }; ``` ### 执行迁移 运行以下命令创建数据表: ```shell php artisan migrate --path=packages\test\test\migrations\ ``` 执行成功后,使用数据库客户端(如 Navicat)查看,可以看到 `test_user` 表已创建: ![数据表](https://image.catchadmin.com/202512161504294.png) ## 第二步:创建模型 数据表创建完成后,我们需要创建对应的 Eloquent 模型来操作数据。 ### 生成模型文件 执行 Laravel 的模型生成命令: ```shell php artisan make:model TestUser ``` 该命令会在 `app/Models` 目录下生成模型文件: ![创建模型](https://image.catchadmin.com/202512161509504.png) ### 移动到插件目录 将生成的模型文件移动到插件的 `src/Models` 目录下(如果目录不存在,请先手动创建): ![创建模型](https://image.catchadmin.com/202512161514146.png) :::warning ⚠️ 注意命名空间 移动文件后,**必须修改命名空间**以匹配新的目录位置!详见 [常见问题 - 命名空间相关](./faq.md#命名空间相关) ::: 修改后的模型内容如下: ```php 'has no users']; } } ``` ## 第四步:配置路由 控制器创建完成后,还需要配置路由才能访问。 ### 创建路由文件 在插件根目录创建 `routes` 目录,并在其中创建 `api.php` 文件: ![创建路由](https://image.catchadmin.com/202512161529395.png) 在 `api.php` 中添加路由定义: ```php \Illuminate\Support\Facades\Route::get('/test/user', [\Test\Test\Http\Controllers\TestUserController::class, 'index']); ``` ### 重新安装插件 :::warning ⚠️ 重要步骤 每次修改插件的路由、配置等文件后,都需要**重新安装插件**才能生效!详见 [常见问题 - 安装相关](./faq.md#安装相关) ::: ```shell # 先卸载旧版本 composer remove test/test --ignore-platform-reqs # 再安装新版本 composer require test/test:* --ignore-platform-reqs ``` ### 启动开发服务器 ```shell php artisan serve ``` ### 验证接口 打开浏览器访问 `http://127.0.0.1:8000/test/user`: ![访问接口链接](https://image.catchadmin.com/202512161545982.png) 🎉 **恭喜!** 如果看到返回的 JSON 数据,说明接口已经成功运行了! ## 第五步:集成 CatchAdmin 功能 到目前为止,我们已经有了一个可以访问的基础接口。接下来,我们将让插件与 CatchAdmin 深度集成,实现: * ✅ 身份认证 * ✅ 权限控制 * ✅ Vue 前端页面 * ✅ 自动生成菜单 ### 5.1 添加身份认证 为了让插件接口需要登录才能访问,我们需要添加身份认证中间件。 修改 `routes/api.php` 文件: ```php \Illuminate\Support\Facades\Route::prefix(config('catch.route.prefix')) ->middleware([ \Catch\Middleware\AuthMiddleware::class // 身份认证中间件 ]) ->group(function(){ \Illuminate\Support\Facades\Route::get('test/user', [\Test\Test\Http\Controllers\TestUserController::class, 'index']); }); ``` 重新安装插件后,访问 `http://127.0.0.1:8000/api/test/user`: ![出现身份认证失效:Unauthenticated.](https://image.catchadmin.com/202512161559134.png) 看到 `Unauthenticated` 提示,说明身份认证中间件已生效!🔐 ### 5.2 添加权限控制 在身份认证的基础上,我们还可以添加权限控制,确保只有拥有相应权限的用户才能访问接口。 继续修改 `routes/api.php`: ```php \Illuminate\Support\Facades\Route::prefix(config('catch.route.prefix')) ->middleware([ \Catch\Middleware\AuthMiddleware::class, // 身份认证 \Modules\Permissions\Middlewares\PermissionGate::class // 权限控制 ]) ->group(function(){ \Illuminate\Support\Facades\Route::get('test/user', [\Test\Test\Http\Controllers\TestUserController::class, 'index']); }); ``` ### 5.3 添加 Vue 前端页面 CatchAdmin 使用 Vue 作为前端框架。好消息是,插件的 Vue 页面**无需编译**,可以实现即插即用! #### 创建视图目录 在插件根目录创建以下目录结构: ``` resource/ └─views/ └─user/ └─index.vue ``` ![添加 Vue 页面](https://image.catchadmin.com/202512161607495.png) #### 编写 Vue 页面 在 `index.vue` 中添加内容: ```vue ``` #### 访问 Vue 页面 安装插件后,可以通过以下 URL 访问 Vue 文件内容: ``` http://127.0.0.1:8000/api/plugins/test/test/user/index ``` :::tip 📝 URL 规则说明 | 部分 | 说明 | |------|------| | `api/plugins` | 固定前缀 | | `test/test` | 插件包名 | | `user/index` | 对应 `resource/views/user/index.vue` | **注意**:必须先安装插件,URL 才能生效! ::: ![访问 Vue 页面](https://image.catchadmin.com/202512161617416.png) ### 5.4 使用钩子自动创建菜单 最后一步,我们使用插件钩子在安装时自动创建后台菜单。更多钩子用法请参考 [生命周期钩子](./hook.md)。 #### 编辑钩子文件 找到插件根目录的 `hook.php` 文件: ![钩子自动创建菜单](https://image.catchadmin.com/202512181501555.png) 在 `afterInstall` 方法中添加菜单创建代码: ```php public function afterInstall(array $context): void { Plugin::createMenus([ Plugin::createMenu('测试插件', '/test', 'Test\Test', children: [ Plugin::createMenu('测试用户', 'user', 'Test\Test', controller: 'TestUser', controllerMethod: 'index', type: 2, component: Plugin::view('test/test', 'user.index') ) ]) ]); } ``` :::warning ⚠️ module 参数说明 `module` 参数必须填写插件的**根命名空间**(如 `Test\Test`),这用于标识菜单归属于哪个插件。 ![module](https://image.catchadmin.com/202512161633975.png) ::: #### 重新安装并查看效果 ```shell composer remove test/test --ignore-platform-reqs composer require test/test:* --ignore-platform-reqs ``` 刷新后台页面,你将看到新创建的菜单: ![CatchAdmin 插件测试页面](https://image.catchadmin.com/202512181524897.png) 🎉 **大功告成!** 你已经成功开发了一个完整的 CatchAdmin 后台模块插件! ## 卸载插件 卸载插件非常简单,只需执行以下命令: ```shell composer remove test/test --ignore-platform-reqs ``` ### 使用钩子清理数据 为了在卸载时自动清理插件创建的菜单等数据,可以在 `hook.php` 的 `afterUninstall` 方法中添加清理逻辑: ```php public function afterUninstall(array $context): void { // 删除该插件创建的所有菜单 Permissions::where('module', $context['namespace'])->delete(); } ``` :::tip 💡 提示 * `$context['namespace']` 会自动获取插件的根命名空间 * 上述代码会删除该插件的**所有菜单**,你可以根据实际需求调整删除逻辑 ::: ## 总结 通过本教程,你已经学会了: 1. **目录结构约定** - 插件的标准目录组织方式 2. **数据库迁移** - 在插件中创建和管理数据表 3. **模型与控制器** - 编写业务逻辑代码 4. **路由配置** - 定义 API 接口 5. **中间件集成** - 添加身份认证和权限控制 6. **Vue 页面开发** - 创建无需编译的前端页面 7. **[生命周期钩子](./hook.md)** - 在安装/卸载时执行自定义逻辑 遇到问题?请查看 [常见问题](./faq.md)。 现在,你可以根据实际需求,开发更复杂的插件功能了!🚀 --- --- url: /docs/5.0/plugin/vue-component.md --- # Vue 单页组件开发 > 🎨 本章介绍如何在插件中开发 Vue 单页组件,以及远程组件可以使用的框架模块。 ## 概述 CatchAdmin 插件系统支持**远程加载 Vue 单文件组件(SFC)**,让你可以在插件中编写独立的 Vue 页面,并且能够复用主应用的 stores、composables 和 UI 组件。 :::tip 💡 核心特性 * **按需加载**:组件只在访问时才会加载,不影响主应用性能 * **模块共享**:可直接使用主应用的 Pinia stores、composables 和 UI 组件 * **熟悉的语法**:使用标准的 `@/` 路径别名,与主应用开发体验一致 ::: ## ⚠️ 重要限制 远程 SFC 组件是在**运行时**通过 [vue3-sfc-loader](https://github.com/FranckFreiburger/vue3-sfc-loader) 加载的,与主应用的编译时处理不同,因此存在以下限制: :::warning 必须了解的限制 ### 1. 必须显式导入组件 主应用使用 `unplugin-vue-components` 实现组件自动导入,但远程组件**不经过 Vite 编译**,所以: ```vue ``` ### 2. 不支持 TypeScript 类型检查 远程组件在运行时编译,不会进行 TypeScript 类型检查。建议: * 在开发时使用 `// @ts-nocheck` 注释 * 或确保代码逻辑正确,类型问题不会在运行时报错 ### 3. 不支持 Vite 特性 以下 Vite 特性在远程组件中**不可用**: * `import.meta.env` 环境变量 * `import.meta.glob` 动态导入 * CSS 预处理器(如 SCSS、Less)的高级特性 * 自动 CSS 注入 ### 4. 调试相对困难 * 运行时错误堆栈可能不够清晰 * 无法使用 Vue DevTools 的完整功能 * 建议使用 `console.log` 进行调试 ::: ### 适用场景 | 适合 | 不适合 | |------|--------| | 插件的后台管理页面 | 核心业务逻辑 | | CRUD 操作界面 | 高性能要求的页面 | | 配置管理页面 | 复杂的交互动画 | | 简单的数据展示 | 需要类型安全的场景 | ## 快速开始 ### 创建 Vue 组件 在插件的 `resource/view` 目录下创建 Vue 组件: ``` packages/your-plugin/ ├─resource/ │ └─view/ │ └─user/ │ ├─index.vue # 列表页 │ ├─create.vue # 创建/编辑表单 │ └─components/ # 子组件目录 │ └─department.vue ``` ### 编写组件代码 ```vue ``` ## 可用模块一览 ### 核心库(预加载) 这些模块在应用启动时就已加载,可直接使用: | 模块 | 导入方式 | 说明 | |------|----------|------| | Vue | `import { ref, computed } from 'vue'` | Vue 3 核心 | | Vue Router | `import { useRouter } from 'vue-router'` | 路由 | | Pinia | `import { storeToRefs } from 'pinia'` | 状态管理 | | Element Plus | `import { ElMessage } from 'element-plus'` | UI 组件库 | | Element Plus Icons | `import { Edit } from '@element-plus/icons-vue'` | 图标 | | Heroicons | `import { UserIcon } from '@heroicons/vue/24/outline'` | 图标 | ### Stores(状态管理) | 模块 | 导入方式 | 说明 | |------|----------|------| | App Store | `import { useAppStore } from '@/stores/modules/app'` | 应用配置 | | User Store | `import { useUserStore } from '@/stores/modules/user'` | 用户信息 | | Permissions Store | `import { usePermissionsStore } from '@/stores/modules/user/permissions'` | 权限管理 | | Tabs Store | `import { useNavTabStore } from '@/stores/modules/tabs'` | 标签页 | **示例:** ```vue ``` ### Composables(组合式函数) #### CURD 操作 | 模块 | 导入方式 | 说明 | |------|----------|------| | useCreate | `import { useCreate } from '@/composables/curd/useCreate'` | 创建操作 | | useShow | `import { useShow } from '@/composables/curd/useShow'` | 查看详情 | | useDestroy | `import { useDestroy } from '@/composables/curd/useDestroy'` | 删除操作 | | useEnabled | `import { useEnabled } from '@/composables/curd/useEnabled'` | 启用/禁用 | | useGetList | `import { useGetList } from '@/composables/curd/useGetList'` | 获取列表 | | useOpen | `import { useOpen } from '@/composables/curd/useOpen'` | 打开弹窗 | | useRestore | `import { useRestore } from '@/composables/curd/useRestore'` | 恢复删除 | | useFormSubmit | `import { useFormSubmit } from '@/composables/curd/useFormSubmit'` | 表单提交 | | useExcelDownload | `import { useExcelDownload } from '@/composables/curd/useExcelDownload'` | Excel 导出 | **示例:** ```vue ``` #### 其他 Composables | 模块 | 导入方式 | 说明 | |------|----------|------| | useSse | `import { useSse } from '@/composables/useSse'` | SSE 实时通信 | | useUpload | `import { useUpload } from '@/composables/useUpload'` | 文件上传 | | useChunkUpload | `import { useChunkUpload } from '@/composables/useChunkUpload'` | 分片上传 | | useDynamic | `import { useDynamic } from '@/composables/useDynamic'` | 动态组件 | | useGetRemoteTableData | `import { useGetRemoteTableData } from '@/composables/useGetRemoteTableData'` | 远程表格数据 | ### Support 工具模块 | 模块 | 导入方式 | 说明 | |------|----------|------| | http | `import http from '@/support/http'` | HTTP 请求 | | helper | `import { isUndefined, isEmpty } from '@/support/helper'` | 辅助函数 | | message | `import Message from '@/support/message'` | 消息提示 | | cache | `import Cache from '@/support/cache'` | 缓存管理 | | request | `import request from '@/support/request'` | 原始请求 | **示例:** ```vue ``` ### UI 组件 所有 `@/components` 目录下的组件都可以导入使用: | 组件 | 导入方式 | 说明 | |------|----------|------| | CatchTable | `import CatchTable from '@/components/catchTable/index.vue'` | 数据表格 | | CatchForm | `import CatchForm from '@/components/catchForm/index.vue'` | 动态表单 | | Cavatar | `import Cavatar from '@/components/admin/avatar/cavatar.vue'` | 头像组件 | | Dialog | `import Dialog from '@/components/admin/dialog/index.vue'` | 弹窗组件 | | Upload | `import Upload from '@/components/admin/upload/index.vue'` | 上传组件 | | Icon | `import Icon from '@/components/icon/index.vue'` | 图标组件 | | Cascader | `import Cascader from '@/components/admin/cascader/index.vue'` | 级联选择 | | Select | `import Select from '@/components/admin/select/index.vue'` | 下拉选择 | | Area | `import Area from '@/components/admin/area/index.vue'` | 地区选择 | | Editor | `import Editor from '@/components/editor/index.vue'` | 富文本编辑器 | | Code | `import Code from '@/components/code/index.vue'` | 代码编辑器 | :::warning ⚠️ 注意 远程组件中使用的所有组件都必须**显式导入**,不能依赖主应用的自动导入功能。 ::: ### 第三方库(懒加载) | 模块 | 导入方式 | 说明 | |------|----------|------| | VueUse | `import { useMouse } from '@vueuse/core'` | Vue 工具集 | | Echarts | `import * as echarts from 'echarts'` | 图表库 | | Vue Echarts | `import VChart from 'vue-echarts'` | Vue 图表组件 | | Moment | `import moment from 'moment'` | 日期处理 | | Vue I18n | `import { useI18n } from 'vue-i18n'` | 国际化 | ## 路径格式说明 支持多种路径格式,以下写法等效: ```javascript // 以下导入方式都是有效的 import { useUserStore } from '@/stores/modules/user' import { useUserStore } from '@/stores/modules/user/index' import { useUserStore } from '@/stores/modules/user/index.ts' import { useCreate } from '@/composables/curd/useCreate' import { useCreate } from '@/composables/curd/useCreate.ts' import CatchTable from '@/components/catchTable/index.vue' import CatchTable from '@/components/catchTable/index' ``` ## 不支持的特性 在开发远程组件前,请了解以下**不支持**的特性: ### ❌ 不支持的语法和特性 | 特性 | 说明 | 替代方案 | |------|------|----------| | ` ``` ### 表单页 (create.vue) ```vue ``` ## 性能最佳实践 ### 1. 保持组件简单 远程组件在运行时编译,首次加载会有编译开销。建议: ```vue ``` ### 2. 合理拆分组件 将复杂页面拆分为多个小组件,每个组件职责单一: ``` view/user/ ├─index.vue # 主页面(简单) ├─create.vue # 表单(简单) └─components/ ├─filter.vue # 筛选器 └─stats.vue # 统计卡片 ``` ### 3. 避免重复导入 同一模块只导入一次: ```vue ``` ## 样式处理 ### Tailwind CSS 主应用已加载 Tailwind,远程组件可**直接使用**: ```vue ``` ### Scoped 样式 ` ``` ### 行内样式 行内样式正常工作: ```vue ``` :::warning 注意 不支持 SCSS/Less 等 CSS 预处理器语法。 ::: ## 调试技巧 ### 1. 使用 console.log 最可靠的调试方式: ```vue ``` ### 2. 检查网络请求 打开浏览器开发者工具 → Network 面板: * 检查 `.vue` 文件是否正确加载 * 检查 API 请求是否正常 ### 3. 查看控制台错误 常见错误类型: * `Failed to resolve component` → 未导入组件 * `Module not found` → 模块路径错误 * `xxx is not defined` → 变量/函数未定义 ### 4. 使用 Vue DevTools 虽然功能受限,但仍可用于: * 查看组件树结构 * 检查 props 和 data * 查看 Pinia store 状态 ## Inject/Provide ### 使用主应用提供的内容 CatchTable 组件提供了 `closeDialog`: ```vue ``` ### 在子组件间共享数据 ```vue ``` ## 常见问题 ### 组件无法解析 **问题**:模板中使用的组件报 `Failed to resolve component` 错误 **解决**:确保在 ` ``` ### 模块未找到 **问题**:导入的模块报 `Module not found` 错误 **解决**:检查模块路径是否正确,确保使用 `@/` 开头的路径别名 ```javascript // ✅ 正确 import { useUserStore } from '@/stores/modules/user' // ❌ 错误 import { useUserStore } from 'stores/modules/user' import { useUserStore } from './stores/modules/user' ``` ### Store 状态不共享 **问题**:插件中的 store 与主应用的 store 状态不同步 **解决**:这是正常的——远程组件共享主应用的 Pinia 实例,store 状态是共享的。如果发现不同步,请检查是否正确导入了 store。 ## 下一步 * 了解 [插件生命周期钩子](./hook.md) * 查看 [插件开发实战](./practice.md) * 遇到问题?查看 [常见问题](./faq.md) --- --- url: /docs/5.0/plugin/commands.md --- # Artisan 命令 > 本文介绍 CatchAdmin 插件系统提供的 Artisan 命令。 ## 命令一览 | 命令 | 说明 | |------|------| | `catch:plugin-init` | 初始化一个新的插件项目 | | `catch:plugin-install` | 安装插件系统 | | `catch:plugin-pack` | 将插件打包为 zip 文件 | | `plugin:optimize` | 优化插件记录 | | `plugin:clear` | 清除插件记录文件 | ## catch:plugin-init 初始化一个新的插件项目,交互式创建插件骨架代码。 ### 使用方法 ```shell php artisan catch:plugin-init ``` ### 交互流程 命令会依次询问以下信息: | 输入项 | 说明 | 示例 | |--------|------|------| | 插件标题 | 插件的显示名称 | `我的插件` | | 包名 | vendor/package 格式 | `catch/my-plugin` | | 描述 | 插件功能描述 | `这是一个测试插件` | | 版本号 | 语义化版本 | `1.0.0` | | 作者 | 作者信息 | `张三 ` | | PSR-4 命名空间路径 | 自动加载路径 | `src/` | ### 生成结果 命令执行后会在 `packages/` 目录下生成插件骨架: ``` packages/catch/my-plugin/ ├─src/ ├─hook.php ├─composer.json └─README.md ``` :::tip 💡 提示 * 包名必须符合 `vendor/package` 格式 * 如果检测到 Git 配置,会自动填充作者信息 * 生成后需要执行 `composer require` 安装插件 ::: ## catch:plugin-install 安装插件系统,创建插件管理菜单。 ### 使用方法 ```shell php artisan catch:plugin-install ``` ### 可选参数 | 参数 | 说明 | |------|------| | `--view` | 发布插件管理视图文件 | ### 功能说明 此命令会: 1. 发布插件管理视图(如果使用 `--view` 参数) 2. 创建「插件管理」后台菜单 :::warning ⚠️ 注意 此命令通常只需要在初次安装 CatchAdmin 时执行一次。 ::: ## catch:plugin-pack 将插件打包为 zip 文件,用于发布或分发。 ### 使用方法 ```shell php artisan catch:plugin-pack ``` ### 交互流程 1. 列出所有可用插件 2. 选择要打包的插件 3. 自动打包并输出结果 ### 输出示例 ``` 📦 CatchAdmin 插件打包 插件: 测试插件 版本: 1.0.0 文件: 15 个 大小: 12.5 KB 输出: packages/.dist/test-test-1.0.0.zip ``` ### 打包规则 * **输出目录**:`packages/.dist/` * **文件命名**:`{包名}-{版本号}.zip` * **排除文件**:根据 `config/plugin.php` 中的 `pack_excludes` 配置排除 ### 配置排除文件 在 `config/plugin.php` 中配置: ```php 'pack_excludes' => [ '.git', '.gitignore', 'node_modules', 'vendor', '.idea', '.vscode', ], ``` :::tip 💡 提示 打包前请确保: * `composer.json` 中有正确的 `version` 字段 * 已清理不需要的临时文件 ::: ## plugin:optimize 扫描插件目录并更新插件记录文件。 ### 使用方法 ```shell php artisan plugin:optimize ``` ### 功能说明 此命令会: 1. 扫描 `packages/` 目录下所有已安装的插件 2. 读取每个插件的 `composer.json` 3. 更新 `storage/packages/plugins.json` 记录 ### 使用场景 * 手动添加插件目录后同步记录 * 插件记录文件损坏后重建 * 批量更新插件版本信息 ### 输出示例 ``` 优化完成,共 3 个插件 ``` ## plugin:clear 清除插件记录文件。 ### 使用方法 ```shell php artisan plugin:clear ``` ### 功能说明 删除 `storage/packages/plugins.json` 文件,清空所有插件安装记录。 :::warning ⚠️ 注意 此命令**不会删除插件文件**,只会清除记录。清除后可以使用 `plugin:optimize` 重建记录。 ::: ### 输出示例 ``` 插件记录已清除 ``` ## 常用工作流 ### 开发新插件 ```shell # 1. 初始化插件 php artisan catch:plugin-init # 2. 安装插件 composer require vendor/package:* --ignore-platform-reqs # 3. 开发... # 4. 打包发布 php artisan catch:plugin-pack ``` ### 修复插件记录 ```shell # 清除旧记录 php artisan plugin:clear # 重新扫描 php artisan plugin:optimize ``` --- --- url: /docs/5.0/plugin/hook.md --- # 插件生命周期钩子 > 钩子(Hook)是插件与 CatchAdmin 系统交互的桥梁,让你可以在插件安装、更新、卸载的各个阶段执行自定义逻辑。 ## 钩子文件 每个插件根目录下都有一个 `hook.php` 文件,包含一个 `Hook` 类: ```php 'test/test', // 包名 'version' => '1.0.0', // 版本号 'path' => 'vendor/.../test', // 安装路径 'namespace' => 'Test\Test', // 根命名空间 ]; ``` ## 常见应用场景 ### 1. 安装时自动创建菜单 ```php public function afterInstall(array $context): void { Plugin::createMenus([ Plugin::createMenu('我的插件', '/my-plugin', $context['namespace'], children: [ Plugin::createMenu('用户管理', 'users', $context['namespace'], controller: 'UserController', controllerMethod: 'index', type: 2, component: Plugin::view('my/plugin', 'users.index') ) ]) ]); } ``` ### 2. 卸载时清理菜单 ```php public function afterUninstall(array $context): void { // 删除该插件创建的所有菜单 Permissions::where('module', $context['namespace'])->delete(); } ``` ### 3. 安装前检查条件 ```php public function beforeInstall(array $context): void { // 检查 PHP 版本 if (version_compare(PHP_VERSION, '8.1', '<')) { throw new \RuntimeException('此插件需要 PHP 8.1 或更高版本'); } // 检查依赖扩展 if (!extension_loaded('redis')) { throw new \RuntimeException('此插件需要 Redis 扩展'); } } ``` ### 4. 安装后初始化数据 ```php public function afterInstall(array $context): void { // 执行数据库迁移 Artisan::call('migrate', [ '--path' => $context['path'] . '/migrations' ]); // 发布配置文件 Artisan::call('vendor:publish', [ '--tag' => 'my-plugin-config' ]); // 初始化默认数据 \DB::table('settings')->insert([ 'key' => 'my_plugin_enabled', 'value' => 'true' ]); } ``` ### 5. 更新前备份数据 ```php public function beforeUpdate(array $context): void { // 备份配置 $config = config('my-plugin'); file_put_contents( storage_path('backups/my-plugin-config.json'), json_encode($config) ); } ``` ### 6. 卸载前确认并备份 ```php public function beforeUninstall(array $context): void { // 导出用户数据 $users = \DB::table('my_plugin_users')->get(); file_put_contents( storage_path('backups/my-plugin-users.json'), json_encode($users) ); } ``` ## 注意事项 :::warning ⚠️ 重要提示 1. **钩子中可以使用 Laravel 功能**:包括 Eloquent、Artisan、配置、日志等 2. **beforeInstall 抛出异常可阻止安装**:用于环境检查 3. **afterUninstall 时包文件仍存在**:可以访问插件的静态资源 4. **钩子方法是实例方法**:不是静态方法 ::: ## 下一步 * 了解如何开发完整插件:[插件开发实战](./practice.md) * 从零开始创建插件:[快速入门](./quickstart.md) --- --- url: /docs/5.0/plugin/helper.md --- # Plugin 辅助方法 > `Plugin` 类提供了一系列静态方法,帮助你在插件开发中快速完成常见任务,如创建菜单、执行迁移、发布资源等。 ## 引入方式 ```php use Catch\Plugin\Support\Plugin; ``` ## 菜单相关 ### createMenus - 批量创建菜单 批量导入菜单数据到系统。 ```php Plugin::createMenus([ Plugin::createMenu('插件名称', '/route', 'Namespace', children: [ // 子菜单... ]) ]); ``` ### createMenu - 创建单个菜单 创建菜单数据结构,通常与 `createMenus` 配合使用。 ```php Plugin::createMenu( name: '菜单名称', // 菜单显示名称 frontRoute: '/path', // 前端路由 module: 'Test\Test', // 模块命名空间 icon: 'icon-name', // 图标(可选) controller: 'UserController', // 控制器名(可选) controllerMethod: 'index', // 控制器方法(可选) type: 1, // 类型:1=目录 2=菜单 3=按钮 component: '', // Vue 组件路径(可选) activeMenu: '', // 激活菜单(可选) children: [], // 子菜单(可选) extra: [ 'hidden' => 2 // 额外数据(可选) ] ); ``` :::tip 🎨 关于图标 菜单图标使用 [Heroicons](https://heroicons.com/),这是一套由 Tailwind CSS 团队设计的精美 SVG 图标库。 使用方式:直接填写图标名称(无需前缀),例如: * `home` - 首页图标 * `users` - 用户图标 * `cog-6-tooth` - 设置图标 * `document-text` - 文档图标 访问 https://heroicons.com/ 浏览所有可用图标。 ::: **完整示例:** ```php public function afterInstall(array $context): void { Plugin::createMenus([ Plugin::createMenu( name: '系统管理', frontRoute: '/system', module: 'system', icon: 'server-stack', children: [ Plugin::createMenu( name: '定时任务', frontRoute: 'cron/tasks', module: 'system', controller: 'cronTasks', type: 2, component: Plugin::view('modules/system-cron', 'cronTasks.index') ), Plugin::createMenu( name: '定时任务日志', frontRoute: 'cron/log', module: 'system', controller: 'cronTasksLog', type: 2, component: Plugin::view('modules/system-cron', 'cronTasksLog.index'), extra: ['hidden' => 2] ), ] ), ]); } ``` ## 视图相关 ### view - 生成插件视图 URL 生成插件 Vue 页面的访问路径。 ```php Plugin::view('vendor/plugin', 'users.index'); // 返回: api/plugins/vendor/plugin/users/index ``` | 参数 | 说明 | 示例 | |------|------|------| | `$plugin` | 插件包名 | `'my/plugin'` | | `$entry` | 入口文件(点号分隔) | `'users.index'` | | `$prefix` | URL 前缀(默认 `api/plugins`) | `'api/plugins'` | ### render - 动态渲染 Vue 页面 获取 Vue 页面内容及其依赖文件。 ```php $result = Plugin::render('my/plugin', 'users/index.vue'); // 返回: ['entry' => '/users/index.vue', 'files' => [...]] ``` ### publishView - 发布视图到前端目录 将插件视图发布到 `web/src/views/` 目录。 ```php Plugin::publishView($pluginViewPath, 'my-plugin'); // 发布到: web/src/views/my-plugin/ ``` ### deleteView - 删除已发布的视图 ```php Plugin::deleteView('my-plugin'); ``` ## 数据库相关 ### migrate - 执行数据库迁移 执行指定路径的迁移文件。 ```php Plugin::migrate(Plugin::getPluginPath('test/test') . DIRECTORY_SEPARATOR . 'migrations'); ``` OR ```php Plugin::migrate(Plugin::getPluginPath($context['name']) . DIRECTORY_SEPARATOR . 'migrations'); ``` ### seed - 执行数据填充 ```php Plugin::seed(\Database\Seeders\MySeeder::class); ``` ### migrateModule - 执行模块迁移 ```php Plugin::migrateModule('MyModule'); ``` ### seedModule - 执行模块数据填充 ```php Plugin::seedModule('MyModule'); // 或指定 Seeder Plugin::seedModule('MyModule', MySeeder::class); ``` ## 模块相关 ### publishModule - 发布模块 将模块文件发布到 `modules/` 目录。 ```php Plugin::publishModule($sourcePath, 'my-module'); // 发布到: modules/MyModule/ ``` ## 菜单控制 ### deleteAdminModuleMenu - 删除模块菜单 删除指定模块的所有菜单。 ```php Plugin::deleteAdminModuleMenu('Test\Test'); ``` ### disableAdminModuleMenu - 禁用菜单 ```php Plugin::disableAdminModuleMenu('Test\Test', 'UserController@index'); // 或批量禁用 Plugin::disableAdminModuleMenu('Test\Test', ['UserController@index', 'UserController@store']); ``` ### enableAdminModuleMenu - 启用菜单 ```php Plugin::enableAdminModuleMenu('Test\Test', 'UserController@index'); ``` ## 资源相关 ### publish - 发布资源 将目录从源位置复制到目标位置。 ```php Plugin::publish($from, $to); ``` ### getPluginPath - 获取插件路径 ```php $path = Plugin::getPluginPath('my/plugin'); // 返回: /path/to/project/vendor/.../my/plugin ``` ### all - 获取所有已安装插件 ```php $plugins = Plugin::all(); // 返回: ['my/plugin' => ['path' => '...'], ...] ``` ### allRoutes - 获取所有插件路由文件 ```php $routes = Plugin::allRoutes(); // 返回: ['/path/to/plugin/routes/api.php', ...] ``` ## 常用组合示例 ### 安装时完整初始化 ```php public function afterInstall(array $context): void { // 1. 执行数据库迁移 Plugin::migrate($context['path'] . '/migrations'); // 2. 填充初始数据 Plugin::seed(\MyPlugin\Database\Seeders\InitSeeder::class); // 3. 创建菜单 Plugin::createMenus([ Plugin::createMenu('我的插件', '/my-plugin', $context['namespace'], children: [ Plugin::createMenu('首页', 'index', $context['namespace'], controller: 'IndexController', controllerMethod: 'index', type: 2, component: Plugin::view('my/plugin', 'index') ) ]) ]); } ``` ### 卸载时清理 ```php public function afterUninstall(array $context): void { // 删除菜单 Plugin::deleteAdminModuleMenu($context['namespace']); // 删除已发布的视图 Plugin::deleteView('my-plugin'); } ``` ## 方法速查表 | 方法 | 用途 | |------|------| | `createMenus()` | 批量创建菜单 | | `createMenu()` | 构建菜单数据 | | `view()` | 生成视图 URL | | `render()` | 渲染 Vue 页面 | | `migrate()` | 执行迁移 | | `seed()` | 执行填充 | | `publish()` | 发布资源 | | `publishView()` | 发布视图 | | `publishModule()` | 发布模块 | | `registerModule()` | 注册模块 | | `unregisterModule()` | 注销模块 | | `deleteAdminModuleMenu()` | 删除菜单 | | `getPluginPath()` | 获取插件路径 | | `all()` | 获取所有插件 | | `allRoutes()` | 获取所有路由 | --- --- url: /docs/5.0/plugin/faq.md --- # 常见问题 > 本文总结了插件开发和使用过程中常见的问题及解决方案。 # 插件开发 ## 安装相关 ### Q: 修改了插件代码后没有生效? **原因**:插件的路由、配置等文件需要重新安装才能加载。 **解决方案**: ```shell # 先卸载 composer remove your/plugin --ignore-platform-reqs # 再安装 composer require your/plugin:* --ignore-platform-reqs ``` ### Q: 安装时提示版本不满足 minimum-stability? **原因**:本地开发的包默认被视为 `dev` 版本,而项目可能要求 `stable`。 **解决方案**:在 `composer.json` 的 `repositories` 中指定版本: ```json { "repositories": [ { "type": "path", "url": "./packages/*/*", "options": { "versions": { "your/plugin": "1.0.0" } } } ] } ``` ### Q: 安装后路由 404? **可能原因**: 1. 路由文件未放在 `routes/` 目录 2. 插件未正确安装 3. 路由文件命名不是 `api.php` **解决方案**: 1. 确保路由文件位于 `your-plugin/routes/api.php` 2. 重新安装插件 3. 检查路由前缀是否正确 ## 钩子相关 ### Q: afterInstall 钩子没有执行? **可能原因**: 1. 钩子文件名不正确 2. 类名不正确 3. 方法名拼写错误 **正确配置**: * 文件名:`hook.php`(小写) * 类名:`Hook`(首字母大写) * 方法名:`afterInstall`(驼峰命名) ```php // hook.php delete(); } ``` ### Q: 菜单图标不显示? **原因**:图标名称不正确或使用了不存在的图标。 **解决方案**: 1. 访问 [Heroicons](https://heroicons.com/) 确认图标名称 2. 只填写图标名称,不需要前缀 3. 使用中划线命名,如 `cog-6-tooth` ## 视图相关 ### Q: Vue 页面访问返回 404? **可能原因**: 1. 视图文件路径不正确 2. 插件未安装 3. URL 格式错误 **正确的 URL 格式**: ``` http://127.0.0.1:8000/api/plugins/{vendor}/{plugin}/{path} ``` 例如:`api/plugins/test/test/users/index` 对应文件:`your-plugin/resource/views/users/index.vue` ### Q: Plugin::view() 生成的路径不对? **用法说明**: ```php // 正确用法 Plugin::view('test/test', 'users.index'); // 输出: api/plugins/test/test/users/index // 点号会自动转换为斜杠 Plugin::view('test/test', 'users.edit'); // 输出: api/plugins/test/test/users/edit ``` ## 命名空间相关 ### Q: 移动模型后报类找不到? **原因**:移动文件后没有修改命名空间。 **解决方案**:确保命名空间与目录结构匹配: ```php // 文件位置: packages/test/test/src/Models/User.php namespace Test\Test\Models; // 正确 // 错误示例 namespace App\Models; // 错误! ``` ### Q: PSR-4 自动加载不生效? **检查步骤**: 1. 确认 `composer.json` 中的 `autoload` 配置正确 2. 运行 `composer dump-autoload` 3. 重新安装插件 ```json { "autoload": { "psr-4": { "Test\\Test\\": "src/" } } } ``` ## 数据库相关 ### Q: 迁移文件找不到? **原因**:`--path` 参数使用了错误的路径格式。 **正确用法**: ```shell # Windows php artisan migrate --path=packages\test\test\migrations # Linux/Mac php artisan migrate --path=packages/test/test/migrations ``` ### Q: 如何在钩子中执行迁移? ```php public function afterInstall(array $context): void { Plugin::migrate($context['path'] . '/migrations'); } ``` ## 开发建议 ### 开发流程推荐 1. **修改代码** → 不需要重新安装 2. **修改路由/配置** → 需要重新安装 3. **修改 composer.json** → 需要重新安装 4. **修改钩子** → 需要重新安装并重新触发 ### 调试技巧 1. **查看日志**:`storage/logs/laravel.log` 2. **使用 dd()** :在控制器中调试 3. **Tinker 测试**:`php artisan tinker` ### 版本管理 * 开发阶段使用 `*` 版本约束 * 发布时指定具体版本号 * 遵循语义化版本规范 # 插件使用 ## 安装插件 ### Q: 如何安装插件? 从 CatchAdmin 插件市场下载的插件,解压后放到 `packages/` 目录,然后执行: ```shell composer require vendor/plugin-name:* --ignore-platform-reqs ``` ### Q: 安装插件后功能不生效? **解决方案**: 1. 清除缓存:`php artisan cache:clear` 2. 重新登录后台 3. 检查菜单权限是否已分配给当前角色 ### Q: 如何更新插件? ```shell # 先卸载旧版本 composer remove vendor/plugin-name --ignore-platform-reqs # 替换新版本文件到 packages/ 目录 # 重新安装 composer require vendor/plugin-name:* --ignore-platform-reqs ``` ## 卸载插件 ### Q: 如何卸载插件? ```shell composer remove vendor/plugin-name --ignore-platform-reqs ``` ### Q: 卸载后数据还在? **说明**:插件卸载默认只删除代码,不会删除数据库数据。 **如需清理数据**: 1. 手动删除相关数据表 2. 或在插件的 `afterUninstall` 钩子中添加数据清理逻辑 ## 还有问题? 如果以上内容没有解决你的问题,可以: * 查看 [快速入门](./quickstart.md) 确认基础配置 * 查看 [插件开发实战](./practice.md) 了解完整流程 --- --- url: /docs/5.0/plugin/mechanism.md --- # 插件核心机制 > 本章深入介绍 CatchAdmin 插件系统的核心组件和工作机制。 ## 系统架构概览 CatchAdmin 插件系统由以下核心组件构成: ``` ┌─────────────────────────────────────────────────────────────────┐ │ Composer │ │ (包管理器核心) │ ├──────────────────────────┬──────────────────────────────────────┤ │ PluginInstallerPlugin │ PluginHook │ │ (安装路径管理) │ (生命周期钩子) │ ├──────────────────────────┴──────────────────────────────────────┤ │ InstalledPluginManager │ │ (插件记录管理) │ ├─────────────────────────────────────────────────────────────────┤ │ Plugin │ │ (插件信息读取) │ ├─────────────────────────────────────────────────────────────────┤ │ PluginServiceProvider │ │ (路由加载 & 命令注册) │ └─────────────────────────────────────────────────────────────────┘ ``` ### 组件职责 | 组件 | 位置 | 职责 | |------|------|------| | `PluginInstallerPlugin` | `packages/plugin-installer/` | 注册自定义安装器 | | `PluginInstaller` | `packages/plugin-installer/` | 确定插件安装路径 | | `PluginHook` | `packages/plugin-hook/` | 监听 Composer 事件,执行钩子 | | `InstalledPluginManager` | `packages/plugin/` | 管理 plugins.json 文件 | | `Plugin` | `packages/plugin/` | 提供插件信息查询接口 | | `PluginServiceProvider` | `packages/plugin/` | 加载路由,注册命令 | ## PluginInstaller ### 作用 `PluginInstaller` 是一个 Composer 自定义安装器,负责将 `catchadmin-plugin` 类型的包安装到指定目录。 ### 核心逻辑 **PluginInstallerPlugin.php** - 注册安装器: ```php class PluginInstallerPlugin implements PluginInterface { public function activate(Composer $composer, IOInterface $io): void { $installer = new PluginInstaller($io, $composer); $composer->getInstallationManager()->addInstaller($installer); } } ``` **PluginInstaller.php** - 确定安装路径: ```php class PluginInstaller extends LibraryInstaller { public function supports(string $packageType): bool { return isset($this->typePathMap[$packageType]); } public function getInstallPath(PackageInterface $package): string { $basePath = $this->typePathMap[$package->getType()]; $name = $package->getPrettyName(); // vendor/package return $basePath . '/' . $name; } } ``` ## PluginHook - 生命周期钩子 ### 作用 `PluginHook` 监听 Composer 事件,在适当时机执行插件定义的钩子方法,并更新插件记录。 ### 订阅的 Composer 事件 ```php public static function getSubscribedEvents(): array { return [ PackageEvents::PRE_PACKAGE_INSTALL => 'onPrePackageInstall', PackageEvents::POST_PACKAGE_INSTALL => 'onPostPackageInstall', PackageEvents::PRE_PACKAGE_UNINSTALL => 'onPrePackageUninstall', PackageEvents::POST_PACKAGE_UNINSTALL => 'onPostPackageUninstall', PackageEvents::PRE_PACKAGE_UPDATE => 'onPrePackageUpdate', PackageEvents::POST_PACKAGE_UPDATE => 'onPostPackageUpdate', ScriptEvents::POST_AUTOLOAD_DUMP => 'onPostAutoloadDump', ]; } ``` ### 事件与钩子对应关系 | Composer 事件 | 触发时机 | 执行的钩子 | |---------------|----------|------------| | `PRE_PACKAGE_INSTALL` | 安装包之前 | `beforeInstall` | | `POST_PACKAGE_INSTALL` | 安装包之后 | (记录待处理) | | `POST_AUTOLOAD_DUMP` | autoload 生成后 | `afterInstall` | | `PRE_PACKAGE_UNINSTALL` | 卸载包之前 | `beforeUninstall` | | `POST_PACKAGE_UNINSTALL` | 卸载包之后 | (记录待处理) | | `POST_AUTOLOAD_DUMP` | autoload 生成后 | `afterUninstall` | | `PRE_PACKAGE_UPDATE` | 更新包之前 | `beforeUpdate` | | `POST_PACKAGE_UPDATE` | 更新包之后 | (记录待处理) | | `POST_AUTOLOAD_DUMP` | autoload 生成后 | `afterUpdate` | ### 钩子方法签名 钩子方法是**实例方法**(非静态方法): ```php // hook.php class Hook { // 安装钩子 public function beforeInstall(array $context): void; public function afterInstall(array $context): void; // 更新钩子 public function beforeUpdate(array $context): void; public function afterUpdate(array $context): void; // 卸载钩子 public function beforeUninstall(array $context): void; public function afterUninstall(array $context): void; } ``` ### $context 参数内容 ```php [ 'name' => 'vendor/package', // 包名 'version' => '1.0.0', // 版本号 'path' => 'packages/vendor/package', // 安装路径 'namespace' => 'Vendor\Package', // 根命名空间 ] ``` ### 钩子类加载机制 插件钩子采用**约定方式**加载: * **文件名**:`hook.php`(小写) * **类名**:`Hook`(首字母大写) * **位置**:插件根目录 ```php // packages/vendor/package/hook.php $method($context); } } } ``` :::tip 📌 约定说明 * 钩子类**不需要命名空间**,因为它不通过 PSR-4 加载 * 如需使用插件的其他类,在 `after*` 钩子中调用(此时 autoload 已生成) ::: ## InstalledPluginManager - 插件记录管理 ### 作用 `InstalledPluginManager` 负责管理 `storage/packages/plugins.json` 文件,提供已安装插件信息的增删改查接口。 ### 核心方法 ```php class InstalledPluginManager { protected string $storagePath; public function __construct(?string $storagePath = null) { if ($storagePath) { $this->storagePath = $storagePath; } elseif (function_exists('config')) { $this->storagePath = config('plugin.installed_file'); } else { // Composer 环境下使用默认路径 $this->storagePath = getcwd() . '/storage/packages/plugins.json'; } } // 获取所有已安装插件 public function getAll(): array; // 获取单个插件信息 public function get(string $name): ?array; // 添加插件记录 public function add(array $data): bool; // 更新插件记录 public function update(string $name, array $data): bool; // 删除插件记录 public function remove(string $name): bool; } ``` ### 环境兼容性 `InstalledPluginManager` 同时支持 Laravel 环境和 Composer 环境: ```php // Laravel 环境:使用 config() 函数 if (function_exists('config')) { $this->storagePath = config('plugin.installed_file'); } // Composer 环境:使用 getcwd() else { $this->storagePath = getcwd() . '/storage/packages/plugins.json'; } ``` ## PluginServiceProvider - 路由与命令加载 ### 作用 `PluginServiceProvider` 是 Laravel 服务提供者,负责: * 注册插件配置 * 加载插件路由 * 注册 Artisan 命令 ### 路由加载逻辑 ```php public function boot(): void { // 如果路由已缓存,跳过动态加载 if ($this->app->routesAreCached()) { return; } // 加载所有插件路由 foreach (Plugin::allRoutes() as $routeFile) { if (file_exists($routeFile)) { require $routeFile; } } } ``` ### 路由发现机制 `Plugin::allRoutes()` 方法从已安装插件中收集所有路由文件: ```php public static function allRoutes(): array { $routes = []; foreach (self::all() as $plugin) { $routesDir = base_path($plugin['path'] . '/routes'); if (is_dir($routesDir)) { $files = glob($routesDir . '/*.php'); $routes = array_merge($routes, $files); } } return $routes; } ``` ### 注册的 Artisan 命令 ```php protected $commands = [ PluginOptimizeCommand::class, // plugin:optimize PluginClearCommand::class, // plugin:clear PluginPackCommand::class, // catch:plugin-pack ]; ``` ## 安装/卸载完整流程图 ### 安装流程 ``` composer require vendor/plugin │ ▼ ┌───────────────────────────────────┐ │ 1. Composer 解析依赖 │ └───────────────────────────────────┘ │ ▼ ┌───────────────────────────────────┐ │ 2. PluginInstaller.supports() │ │ 检查是否为 catchadmin-plugin │ └───────────────────────────────────┘ │ ▼ ┌───────────────────────────────────┐ │ 3. PluginInstaller.getInstallPath()│ │ 确定安装路径 │ └───────────────────────────────────┘ │ ▼ ┌───────────────────────────────────┐ │ 4. PRE_PACKAGE_INSTALL 事件 │ │ → PluginHook.onPrePackageInstall│ │ → 执行 beforeInstall 钩子 │ └───────────────────────────────────┘ │ ▼ ┌───────────────────────────────────┐ │ 5. Composer 下载/链接包 │ └───────────────────────────────────┘ │ ▼ ┌───────────────────────────────────┐ │ 6. POST_PACKAGE_INSTALL 事件 │ │ → 记录待处理的安装信息 │ └───────────────────────────────────┘ │ ▼ ┌───────────────────────────────────┐ │ 7. Composer 生成 autoload │ └───────────────────────────────────┘ │ ▼ ┌───────────────────────────────────┐ │ 8. POST_AUTOLOAD_DUMP 事件 │ │ → InstalledPluginManager.add() │ │ → 写入 plugins.json │ │ → 执行 afterInstall 钩子 │ └───────────────────────────────────┘ │ ▼ 安装完成 ``` ### 卸载流程 ``` composer remove vendor/plugin │ ▼ ┌───────────────────────────────────┐ │ 1. Composer 解析依赖变更 │ └───────────────────────────────────┘ │ ▼ ┌───────────────────────────────────┐ │ 2. PRE_PACKAGE_UNINSTALL 事件 │ │ → 执行 beforeUninstall 钩子 │ │ → 记录待处理的卸载信息 │ └───────────────────────────────────┘ │ ▼ ┌───────────────────────────────────┐ │ 3. Composer 删除包 │ └───────────────────────────────────┘ │ ▼ ┌───────────────────────────────────┐ │ 4. POST_PACKAGE_UNINSTALL 事件 │ └───────────────────────────────────┘ │ ▼ ┌───────────────────────────────────┐ │ 5. Composer 重新生成 autoload │ └───────────────────────────────────┘ │ ▼ ┌───────────────────────────────────┐ │ 6. POST_AUTOLOAD_DUMP 事件 │ │ → 执行 afterUninstall 钩子 │ │ → InstalledPluginManager.remove()│ │ → 从 plugins.json 删除记录 │ └───────────────────────────────────┘ │ ▼ 卸载完成 ``` --- --- url: /docs/5.0/front/intro.md --- # CatchAdmin 前端开发 > Vue 3 + TypeScript + Element Plus 的现代化前端架构 CatchAdmin 前端采用现代化的技术栈构建,基于 Vue 3 生态系统。在开始前端开发前,建议先熟悉以下核心技术: ## 核心技术栈 ### 框架基础 * **Vue 3** [官方文档](https://cn.vuejs.org/) - 项目的核心框架,提供响应式数据绑定和组件化开发 * **TypeScript** [官方文档](https://www.tslang.cn/docs/home.html) - 提供类型安全和更好的开发体验 ### UI 和样式 * **Element Plus** [官网地址](https://element-plus.org/) - 企业级 UI 组件库,提供丰富的后台管理组件 * **Tailwind CSS** [官网地址](https://tailwindcss.com/) - 原子化 CSS 框架,快速构建自定义样式 * **Hero Icons** [官网地址](https://heroicons.com/) - 精美的 SVG 图标库 ### 状态管理和工具 * **Pinia** [官网地址](https://pinia.vuejs.org/) - Vue 3 推荐的状态管理方案,替代 Vuex 这些技术构成了 CatchAdmin 前端的技术基础,建议在开发前充分了解。 ## Vite 构建配置 CatchAdmin 使用 Vite 作为构建工具,提供快速的开发体验和优化的生产构建。以下是详细的配置说明: ```js title="vite.config.js" // rootPath 项目根目录 const rootPath = resolve(__dirname) export default defineConfig(({ command, mode }) => { const env = loadEnv(mode, process.cwd(), '') return { plugins: [ vue(), vueJsx(), createHtmlPlugin({ minify: true, // 调整入口文件,入口文件放到了 public 下 template: 'public/admin.html' }), // 路径别名配置,简化导入路径 alias({ entries: [ { find: '/admin', replacement: resolve(rootPath, 'resources/admin') }, { find: '@/module', replacement: resolve(rootPath, 'modules') } ] }), // 自动导入 Vue API,无需手动 import AutoImport({ imports: ['vue', 'vue-router', 'pinia', '@vueuse/core'] // resolvers: [ ElementPlusResolver({importStyle: 'sass'}) ] }), // 自动导入组件,无需手动注册 Components({ dirs: ['resources/admin/components/', 'resources/admin/layout/'], extensions: ['vue'], deep: true, dts: true, include: [/\.vue$/, /\.vue\?vue/], exclude: [/[\\/]node_modules[\\/]/, /[\\/]\.git[\\/]/, /[\\/]\.nuxt[\\/]/] // resolvers: [ ElementPlusResolver({ importStyle: 'sass'}) ] }), // 图标自动导入和编译 Icons({ compiler: 'vue3', autoInstall: true }) ], publicDir: false, // 全局常量定义 define: { BASE_URL: env.BASE_URL // API 基础地址 }, preprocessorOptions: { scss: { // additionalData: `@use "@/assets/styles/element.scss" as *;`, } }, // 开发服务器配置 server: { host: '127.0.0.1', port: 8000, open: true, // 自动打开浏览器 cors: true, // 允许跨域请求 strictPort: false, // 端口占用时尝试其他端口 hmr: true, // 热模块替换 fs: { allow: ['./'] // 文件系统访问权限 } }, // 生产构建配置 build: { chunkSizeWarningLimit: 2000, // 包体积警告阈值 minify: 'terser', // 使用 terser 压缩 terserOptions: { compress: { drop_console: false, // 保留 console pure_funcs: ['console.log', 'console.info'], // 移除指定 console 方法 drop_debugger: true // 移除 debugger } }, outDir: 'public/admin', // 构建输出目录 assetsDir: 'assets', // 静态资源目录 rollupOptions: { input: './public/admin.html', output: { chunkFileNames: 'assets/js/[name]-[hash].js', entryFileNames: 'assets/js/[name]-[hash].js', assetFileNames: 'assets/[ext]/[name]-[hash].[ext]' } } } } }) ``` ## 环境变量配置 ### 开发环境配置 CatchAdmin 的前端项目默认安装在根目录的 `web` 目录,前端相关的环境变量配置在 `.env`: ```bash title=".env" # 这个配置在 CatchAdmin 安装时已自动生成 VITE_BASE_URL=${APP_URL}/api/ ``` :::info Vite 环境变量规则 * 所有前端环境变量必须以 `VITE_` 前缀开头 * 在 `vite.config.js` 中可以直接通过 `env.BASE_URL` 访问 * 在 Vue 组件中通过 `import.meta.env.VITE_BASE_URL` 访问 ::: ### 生产环境配置 生产构建时需要创建 `.env.production` 文件: ```bash title=".env.production" # 生产环境 API 接口地址 VITE_BASE_URL=https://your-api-domain.com/api/ ``` **注意事项**: * 生产环境的 API 地址需要替换为实际的服务器地址 * 确保 API 地址末尾包含 `/api/` 路径 * HTTPS 环境下建议使用 HTTPS 协议的 API 地址 --- --- url: /docs/5.0/front/entry.md --- # 入口 前端项目放置在根目录 `web` 目录下,关于前端各个目录的作用就不做多介绍了,可以到[项目介绍](/docs/5.0/start/project_intro.md#目录结构)中查看。`main.ts` 即项目的入口 ```javascript import '@/styles/index.scss' import CatchAdmin from '@/support/catchAdmin' // 首先引入的是 catchadmin 对象 const admin = new CatchAdmin() // 启动项目 admin.bootstrap() ``` 进入到 `CatchAdmin` 对象中,可以看到项目引入了哪些全局组件 ```javascript title="web/src/support/catchAdmin.ts" import { createApp } from 'vue' import type { App as app } from 'vue' import App from '@/App.vue' import router, { bootstrapRouter } from '@/router' import ElementPlus from 'element-plus' import zh from 'element-plus/es/locale/lang/zh-cn' import { bootstrapStore } from '@/stores' import Cache from './cache' import { bootstrapI18n } from '@/i18n' import guard from '@/router/guard' /** * catchadmin */ export default class CatchAdmin { protected app: app protected element: string /** * construct * * @param ele */ constructor(ele: string = '#app') { this.app = createApp(App) this.element = ele } /** * admin boot */ bootstrap(): void { this.useElementPlus().usePinia().useI18n().useRouter().mount() } /** * 挂载节点 * * @returns */ protected mount(): void { this.app.mount(this.element) } /** * 加载路由 * * @returns */ protected useRouter(): CatchAdmin { // 拦截路由 guard(router) bootstrapRouter(this.app) return this } /** * ui * * @returns */ protected useElementPlus(): CatchAdmin { this.app.use(ElementPlus, { locale: Cache.get('language') === 'zh' && zh, }) return this } /** * use pinia */ protected usePinia(): CatchAdmin { bootstrapStore(this.app) return this } /** * use i18n */ protected useI18n(): CatchAdmin { bootstrapI18n(this.app) return this } } ``` 其实总结就是一句话,向 `Vue` 注入组件,最后挂载到 `#app` **dom** 上 ```javascript this.useElementPlus().usePinia().useI18n().useRouter().mount() ``` --- --- url: /docs/5.0/front/layout.md --- # 布局 不管是否进行二次开发,在开始之前都需要了解一下后台的页面布局。这对于认识前端系统非常重要。 布局文件放在 `resource/admin/layout` 下,这个差不多是标准了。看到 **layout** 文件夹,默认就是布局所在 ``` ├─components │ ├─header (头部组件) │ │ ├─index.vue | | ├─lang.vue (多语言组件) | | ├─logo.vue (logo 组件) | | ├─menuSearch.vue (菜单搜索组件) | | ├─notification.vue (通知组件) | | ├─profile.vue (个人组件) | | ├─theme.vue (主题组件/暗黑模式) | ├─ Menu(头部组件) │ │ ├─index.vue | | ├─item.vue (菜单 item 组件) | | ├─mask.vue (mask 组件) | | ├─menus.vue (菜单组件) | | │ └─content.vue 主题内容 │ └─sider.vue 侧边栏 ├─index.vue ``` ![CatchAdmin v5 布局](https://image.catchadmin.com/202512210950806.png) 采用的是传统的双栏布局,即左侧是 **Sider** 右侧是内容。可以从 `layout/index.vue` 看出布局 ```html title="resource/admin/layout/index.vue" ``` 内容区域分为`Header` 和 `router-view`,可以在 `layout/components/content.vue` 中 ```html title="resource/admin/layout/components/content.vue" ``` 所以当在 `vue router` 使用 `Layout` 组件是,组件的内容便会展示在 `layout` 内容组件的 `router-view` 中。譬如说 ```javascript title="resource/layout/index.ts" import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router' import type { App } from 'vue' export const constantRoutes: RouteRecordRaw[] = [ { path: '/dashboard', component: () => import('/admin/layout/index.vue'), children: [ { path: '', name: 'Dashboard', meta: { title: 'Dashboard', icon: 'home', hidden: false }, component: () => import('/admin/views/dashboard/index.vue') } ] } ] ``` `dashboard` 组件,也就是首页。使用的是 vue 路由嵌套的规则,Dashboard 组件被插入到内容组件的 `` 区域,这跟插槽有点类似了 ``` /layout/index /layout/index +------------------+ +-----------------+ | Layout | | Layout | | +--------------+ | | +-------------+ | | | Dashboard | | +------------> | | Develop | | | | | | | | | | | +--------------+ | | +-------------+ | +------------------+ +-----------------+ ``` :::info 如果不了解 vue router, 需要先了解[vue-router](https://router.vuejs.org/zh/guide/)看下文档 ::: --- --- url: /docs/5.0/front/side-menu.md --- # 侧边栏&路由 路由和侧边栏是组织起一个后台应用的关键骨架。 项目侧边栏和路由是绑定在一起的,`resource/admin/router/index.ts` 是整个路由的入口文件,如果是按正常顺序文档看下来,应该知道本项目的路由分为两种情况 * 动态生成的路由,也就是权限管理打开后,菜单管理的数据 * 每个模块的**views**目录下的 `router.js` 配置静态路由 所以一般情况下不用管`resource/admin/router/index.ts`路由这个入口文件。 ## 类型 对于权限和菜单,系统定义了两种类型,查看 `resource/admin/types` ### 权限类型 ```js title="resource/admin/types/Permissions.ts" export interface Permission { id: number // id parent_id: number // 父级 ID permission_name: string // 权限名称 type: number // 类型 icon: string // icon 图标 component: string // 组件 module: string // 模块 permission_mark: string // 权限标识 route: string // 路由,对应的是 vue route 的 path redirect: string keepAlive: boolean hidden: boolean // 是否隐藏 is_inner: boolean // 是否是内页 } ``` ### 菜单类型 菜单类型,最终都是由权限类型转换而来,所以一旦是动态生成的路由,那么元数据都是由菜单数据提供 ```js title="resource/admin/types/Menu.ts" import { Component } from 'vue' import { RouteRecordRaw } from 'vue-router' // meta 元数据 // 在记录上附加自定义数据。 // 这个数据将会附着在 vue route 上 export interface Meta { title: string icon: string // icon roles?: string[] // 哪些角色可以访问页面,未实现,保留 cache?: boolean // 页面缓存,未实现,保留 hidden: boolean // 是否隐藏,当设置成 true 时,菜单则不会在侧边栏显示。例如内页编辑页面啊,Login,页面 404 页面啊 keepalive?: boolean // 是否 keepalive 目前未实现,保留数据结构 is_inner?: boolean // 是否是内页 } // @ts-ignore // Menu 类型和 Vue Route 类型一样了 export interface Menu extends Omit { path: string // path 访问路径 name: string // name 菜单名称 meta?: Meta // meta,路由附着的额外数据 redirect?: string component?: Component // 页面组件 children?: Menu[] // 子菜单 } ``` 在了解完这两个相关类型之后,再来看动态菜单和权限如何实现的,静态菜单就不做介绍了。首先找到`resource/admin/route/guard/index.ts` 文件,从这里开始,这里是路由导航守卫。下面直接通过代码来注解如何实现 ```js title="resource/admin/route/guard/index.ts" const guard = (router: Router) => { // white list const whiteList: string[] = [WhiteListPage.LOGIN_PATH, WhiteListPage.NOT_FOUND_PATH] router.beforeEach(async (to, from, next) => { // set page title setPageTitle(to.meta.title as unknown as string) // page start progress.start() // 获取用户的 token const authToken = getAuthToken() // 如果 token 存在 if (authToken) { // 如果进入 /login 页面,重定向到首页 if (to.path === WhiteListPage.LOGIN_PATH) { next({ path: '/' }) } else { const userStore = useUserStore() // 获取用户ID if (userStore.getId) { next() } else { try { // 阻塞获取用户信息 // ⚠️ 用户信息已经包含了该用户所有可用权限,在 `permissions` 里 await userStore.getUserInfo() // 如果后端没有返回 permissions,前台则只使用静态路由 if (userStore.getPermissions !== undefined) { // 挂载路由(实际是从后端获取用户的权限) const permissionStore = usePermissionsStore() // 动态路由挂载,这里是主要实现动态路由菜单的地方 const asyncRoutes = permissionStore.getAsyncMenusFrom(toRaw(userStore.getPermissions)) // 在这里使用 addRoute 动态挂在路由 asyncRoutes.forEach((route: Menu) => { router.addRoute(route as unknown as RouteRecordRaw) }) } next({ ...to, replace: true }) } catch (e) { removeAuthToken() next({ path: `${WhiteListPage.LOGIN_PATH}?redirect=/${to.path}` }) } } } progress.done() } else { // 如果不在白名单 if (whiteList.indexOf(to.path) !== -1) { next() } else { next({ path: WhiteListPage.LOGIN_PATH }) } progress.done() } }) router.afterEach(() => { progress.done() }) } export default guard ``` ## 侧边栏 上面经过路由导航守卫之后,动态权限就已经转化为动态菜单了。主要通过这个方法来实现转换 ```js const asyncRoutes = permissionStore.getAsyncMenusFrom(toRaw(userStore.getPermissions)) ``` 这里就不细说里面的实现了,是通过递归实现无限极菜单。但是这里一个非常重要的点,就是权限是通过`pinia` 进行保存的,因为 `pinia` 是响应式的。找到 `resource/admin/store/user/permissions.ts`,看下 `permissionStore` 的定义 ```js title="resource/admin/store/user/permissions.ts" interface Permissions { menus: Menu[] // 菜单 asyncMenus: Menu[] // 动态菜单 permissions: Permission[] // 权限 menuPathMap: Map // menu 和 path 的 MAP 数据 } export const usePermissionsStore = defineStore('PermissionsStore', { // state 里面定义的几个数据都是响应式的 state: (): Permissions => { return { menus: [], asyncMenus: [], permissions: [], menuPathMap: new Map(), } }, } ``` 既然菜单都是响应式的,那就好办了呀!菜单的数据就直接从 `store` 获取就可以了。 侧边栏的实现是在 `layout/components/Menu`,侧边栏的菜单也是基于`ElementPlus` 的 `el-menu` 实现的。因为是动态菜单,所以这里的用到了`vue` 的[渲染函数](https://cn.vuejs.org/guide/extras/render-function.html#creating-vnodes)。源码在 `layout/components/Menu/index.vue` 中 --- --- url: /docs/5.0/front/permissions.md --- # 权限认证 上面其实也讲到了权限相关的,用户在通过认证之后,后端在用户信息中其实已经加入了该用户所有权限。可以通过 `web/src/store/user/index.ts` 的 `UserStore`获取 ```typescript const userHasPermissions = userStore.getPermissions ``` ## 权限指令 权限指令是使用 `vue`的 `directive` 实现一个前端操作控制的指令,例如新增,更新等等操作。如果你需要页面级别的权限操作,那么这个指令可以很好的帮助你实现该功能 例如控制权限模块的角色更新功能,你可以使用 `v-action` 进行控制,如果登录人员没有改操作权限,那么此操作按钮将不再页面展示。 ```javascript ``` 权限指令要求的格式和后端相似,格式如下 ```javascript module.controller.action or module@controller@action ``` ### 实现方案 众所周知,后端是模块的,为了防止模块之间的路由会发生冲突,所以权限标识是由**模块** + **controller@action** 组合 :::info 后端路由即 controller@action,权限标识也是这样定义 ::: 所以权限检测可以这么写, 伪代码如下 ```typescript function hasPermission(string mark) { // mark 是这样的形式 module + '@' + 'controller@action' // 当然也可以定义其他形式的 const userHasPermissions = userStore.getPermissions userHasPermissions.each(item => { if (permissions === (item.module + '@' + item.permission_mark)) { return true } }) return false } ``` 这样就是检测权限了,那么再将其引入到自定义指令中,这里代码仅提供思路,正确性未知 ```typescript app.directive('permission', (el, binding) => { const hasPermission = hasPermission(binding.value) if (!hasPermission) { el.style.display = none } }) ``` 在项目中这么使用 ```html ``` 具体实现可到前端项目的`directives`目录下的 `action` 查看 ## CatchTable 应用 [catchtable 按钮权限](./catch-table.md#表格按钮权限) --- --- url: /docs/5.0/front/style.md --- # 样式 样式存在 `resource/admin/style` 目录下,结构如下 ``` ├─theme | ├─dark.scss // 暗黑主题 | ├─index.scss | ├─light.css // 默认主题 ├─element.scss // Element 样式 ├─index.scss // scss 入口 ├─tailwind.css // tailwindcss ├─var.scss // 自定义变量 ``` 样式上好像并没有什么可以说的了, style 目录的样式都是全局样式。 还有一点就是目前后台的样式是响应式的,基于 `tailwindcss` 做的,tailwindcss 还是很方便的。 :::info 其实用到全局样式的地方不是很多,一般还是在 vue 文件中使用 scope 来改样式 ::: --- --- url: /docs/5.0/front/request.md --- # 请求 前端请求默认使用的是 `axios`,但是为了方便,后台提供了 `Http` 对象快速发起请求 ```typescript title="resource/admin/support/http.ts" import Http from '/admin/support/http' // GET 请求 http.get(path: string, params: object = {}) // POST 请求 http.post(path: string, data: object = {}) // PUT 请求 http.put(path: string, data: object = {}) // DELETE 请求 http.delete(path: string) ``` ## 设置超时 ```typescript Http.timeout(5).get() ``` ## 设置 BASEURL ```typescript Http.setBaseUrl('https://api.com').get() ``` ## 设置 header ```typescript Http.setHeader(key:string, value:string).get() ``` ## 表单请求 表单请求则使用了 `vue3` 的新特性 `hooks`,也称为[组合式函数](https://cn.vuejs.org/guide/reusability/composables.html)。查看 `resource/admin/composables/curd`,总共提供六个操作。 ## GetList `getList` 请求列表数据 ```typescript const { data, query, search, reset, loading } = useGetList(api) // 接口返回的数据必须 computed 才具备响应 const tableData = computed(() => data.value?.data) ``` * data 接口返回的数据 * query:{} 查询数据 * search() 搜索方法 * reset() 重制方法 * loading:boolean 列表请求 loading ## Create **create** 其实包含两个操作,创建和更新,当 **props.primary** 是 **null** 的时候,就是创建数据不为空时,则是更新数据 ```typescript const { formData, form, loading, submitForm, close } = useCreate(props.api, props.primary) // 更新的 ID if (props.primary) { useShow(props.api, props.primary, formData) } // 关闭弹窗 const emit = defineEmits(['close']) close(() => emit('close')) ``` * formData 提交的 Form 数据 * form 表单 ref * loading 提交数据表单 loading * submitForm(form) 点击提交表单的方法, 参数就是 `form` * close 关闭弹窗 ## Destroy ```typescript const { destroy, deleted } = useDestroy() onMounted(() => { // 观察数据是否删除,删除之后刷新列表 deleted(reset) }) ``` * destory(path: string, id: string | number) 删除数据的方法,一般都是用于列表删除数据 * deleted(callback: Function) 观测数据是否删除,参数删除后的回调操作 ## Enabled `enabled` 作用就是请求状态切换 ```typescript const { enabled, success, loading, afterEnabled } = useEnabled() ``` * enabled(path: string, id: string | number, data: object = {}) 请求切换 * success(callback: Function) 参数成功后的回调函数 * loading 请求时 loading * afterEnabled 请求完成之后的操作, 只有设置成方法才会被调用 ```typescript afterEnabled.value = () => {} ``` ## Open 打开 `Dialog` 弹窗,一般用于通过`Dialog` **创建/更新**数据的时候 ```typescript const { open, close, title, visible, id } = useOpen() ``` * open(primary: any = null) 显示`Dialog` * close(callback: Function) 关闭 `Dialog` callback 关闭后的回调方法 * title: string Dialog 标题 * visible: boolean Dialog 状态 * id 数据的 ID ## Show show 方法就是拉取更新时的数据,填充表单 ```typescript if (props.primary) { useShow(props.api, props.primary, formData) } ``` --- --- url: /docs/5.0/front/function.md --- # 常用函数集合 前端项目提供了非常多的常用函数,在文件 `src/support/helper.ts` 中。这些函数可以帮助我们更高效地开发前端应用。 ## 环境变量相关 ### env 获取环境变量的值。 ```typescript env(key: string): any ``` **参数:** * `key`: 环境变量名称 **返回值:** * 对应环境变量的值 **示例:** ```typescript // 获取 API 基础 URL const baseUrl = env('VITE_BASE_URL') // 获取应用名称 const appName = env('VITE_APP_NAME') ``` ### isProd 判断当前环境是否是生产环境。 ```typescript isProd(): boolean ``` **返回值:** * `true`: 当前是生产环境 * `false`: 当前不是生产环境 **示例:** ```typescript if (isProd()) { // 生产环境下的逻辑 } else { // 开发环境下的逻辑 } ``` ## 认证相关 ### rememberAuthToken 保存认证令牌到缓存中。 ```typescript rememberAuthToken(token: string): void ``` **参数:** * `token`: 认证令牌字符串 **示例:** ```typescript // 登录成功后保存令牌 rememberAuthToken('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...') ``` ### removeAuthToken 从缓存中移除认证令牌。 ```typescript removeAuthToken(): void ``` **示例:** ```typescript // 退出登录时移除令牌 removeAuthToken() ``` ### getAuthToken 获取当前的认证令牌。 ```typescript getAuthToken(): string | null ``` **返回值:** * 认证令牌字符串,如果不存在则返回 `null` **示例:** ```typescript const token = getAuthToken() if (token) { // 用户已登录 } else { // 用户未登录 } ``` ### getBearerToken 获取带有 Bearer 前缀的认证令牌,用于 HTTP 请求头。 ```typescript getBearerToken(): string | null ``` **返回值:** * 带有 Bearer 前缀的认证令牌字符串,如果不存在则返回 `null` **示例:** ```typescript const headers = { Authorization: getBearerToken() } // 发送请求 fetch('/api/user', { headers }) ``` ## 界面相关 ### isMiniScreen 判断当前是否是小屏幕设备(宽度小于 500px)。 ```typescript isMiniScreen(): boolean ``` **返回值:** * `true`: 当前是小屏幕 * `false`: 当前不是小屏幕 **示例:** ```typescript if (isMiniScreen()) { // 小屏幕适配逻辑 } else { // 大屏幕适配逻辑 } ``` ### t 国际化翻译函数,基于 i18n。 ```typescript t(translate: string): string ``` **参数:** * `translate`: 翻译键名 **返回值:** * 翻译后的文本 **示例:** ```typescript // 假设 i18n 配置中有 { "welcome": "欢迎使用" } const message = t('welcome') // 结果: "欢迎使用" ``` ### setPageTitle 设置页面标题。 ```typescript setPageTitle(title: string): void ``` **参数:** * `title`: 页面标题 **示例:** ```typescript // 设置页面标题为 "用户中心" setPageTitle('用户中心') // 如果有站点标题配置,结果会是 "用户中心-站点名称" ``` ## 类型判断 ### isUndefined 判断值是否是 undefined。 ```typescript isUndefined(value: any): boolean ``` **参数:** * `value`: 要判断的值 **返回值:** * `true`: 值是 undefined * `false`: 值不是 undefined **示例:** ```typescript if (isUndefined(user.name)) { // 处理 name 未定义的情况 } ``` ### isFunction 判断值是否是函数。 ```typescript isFunction(value: any): boolean ``` **参数:** * `value`: 要判断的值 **返回值:** * `true`: 值是函数 * `false`: 值不是函数 **示例:** ```typescript if (isFunction(callback)) { callback() } ``` ### isBoolean 判断值是否是布尔类型。 ```typescript isBoolean(value: any): boolean ``` **参数:** * `value`: 要判断的值 **返回值:** * `true`: 值是布尔类型 * `false`: 值不是布尔类型 **示例:** ```typescript if (isBoolean(config.enabled)) { // 处理 enabled 是布尔值的情况 } ``` ### isNumber 判断值是否是数字类型。 ```typescript isNumber(value: any): boolean ``` **参数:** * `value`: 要判断的值 **返回值:** * `true`: 值是数字类型 * `false`: 值不是数字类型 **示例:** ```typescript if (isNumber(age)) { // 处理 age 是数字的情况 } ``` ## 字符串处理 ### ucfirst 将字符串的首字母转为大写。 ```typescript ucfirst(str: string): string ``` **参数:** * `str`: 要处理的字符串 **返回值:** * 首字母大写后的字符串 **示例:** ```typescript const name = ucfirst('john') // 结果: "John" ``` ### lcfirst 将字符串的首字母转为小写。 ```typescript lcfirst(str: string): string ``` **参数:** * `str`: 要处理的字符串 **返回值:** * 首字母小写后的字符串 **示例:** ```typescript const name = lcfirst('John') // 结果: "john" ``` ### randomString 生成指定长度的随机字符串。 ```typescript randomString(e: number = 10): string ``` **参数:** * `e`: 生成的字符串长度,默认为 10 **返回值:** * 生成的随机字符串 **示例:** ```typescript // 生成默认长度(10)的随机字符串 const str1 = randomString() // 生成长度为 5 的随机字符串 const str2 = randomString(5) ``` ### strToFunction 将字符串转换为函数。 ```typescript strToFunction(str: string, params?: any): Function ``` **参数:** * `str`: 要转换的字符串 * `params`: 可选的参数 **返回值:** * 转换后的函数 **示例:** ```typescript // 将字符串转换为函数 const fn = strToFunction('function() { return "Hello World"; }') const result = fn() // 结果: "Hello World" // 带参数的情况 const fn2 = strToFunction('function(name) { return "Hello " + name; }', { name: 'John' }) const result2 = fn2('John') // 结果: "Hello John" ``` ## 文件处理 ### generateFilename 生成唯一的文件名。 ```typescript generateFilename(filename: string): string ``` **参数:** * `filename`: 原始文件名 **返回值:** * 生成的唯一文件名 **示例:** ```typescript const uniqueName = generateFilename('image.jpg') // 结果可能是: "1634567890abcDEF.jpg" ``` ### getFileExt 获取文件的扩展名。 ```typescript getFileExt(filename: string): string ``` **参数:** * `filename`: 文件名 **返回值:** * 文件的扩展名(包含点号) **示例:** ```typescript const ext = getFileExt('document.pdf') // 结果: ".pdf" ``` ### getFilename 从路径中获取文件名。 ```typescript getFilename(filename: string): string ``` **参数:** * `filename`: 文件路径 **返回值:** * 文件名 **示例:** ```typescript const name = getFilename('/path/to/document.pdf') // 结果: "document.pdf" ``` ## 数组处理 ### unique 数组去重。 ```typescript unique(arr: Array): Array ``` **参数:** * `arr`: 要去重的数组 **返回值:** * 去重后的数组 **示例:** ```typescript const arr = [1, 2, 2, 3, 3, 4] const uniqueArr = unique(arr) // 结果: [1, 2, 3, 4] ``` ## 日期处理 ### date 将时间戳转化成指定格式的日期字符串。 ```typescript date(format: string, timestamp: number): string ``` **参数:** * `format`: 日期格式,如 'YYYY-MM-DD HH:mm:ss' * `timestamp`: 时间戳(秒) **返回值:** * 格式化后的日期字符串 **示例:** ```typescript const formattedDate = date('YYYY-MM-DD HH:mm:ss', 1634567890) // 结果可能是: "2021-10-18 15:31:30" ``` ## 其他工具函数 ### \_window 获取全局配置。 ```typescript _window(key: string): any ``` **参数:** * `key`: 配置键名 **返回值:** * 配置值,如果不存在则返回 `null` **示例:** ```typescript const baseUrl = _window('BASE_URL') ``` ### getBaseUrl 获取项目的基础 URL。 ```typescript getBaseUrl(): string ``` **返回值:** * 项目的基础 URL **示例:** ```typescript const baseUrl = getBaseUrl() // 在非生产环境下返回 '/api' // 在生产环境下返回配置的 BASE_URL 或环境变量中的 VITE_BASE_URL ``` ### warpHost 为路径添加主机名,确保路径是完整的 URL。 ```typescript warpHost(path: string | null): string | null ``` **参数:** * `path`: 路径 **返回值:** * 添加主机名后的完整 URL **示例:** ```typescript const fullUrl = warpHost('/images/logo.png') // 如果前后端不在同一域名下,结果可能是: "https://api.example.com/images/logo.png" // 如果前后端在同一域名下,结果是: "/images/logo.png" ``` --- --- url: /docs/5.0/front/other.md --- # 其他功能 ## 页面缓存 页面缓存使用 Vue `` 组件。项目默认非开启状态,想要开启可以找到这个文件 ```javascript //src\layout\components\content.vue // 找到下面的代码 ``` 将注释打开,然后注释掉下面的代码`` 还需要找到下面的代码 ```javascript // 大概在 32 行 // const isKeepalive = computed(() => router.currentRoute.value.meta.keepalive) ``` 打开注释该注释即可!!! :::warning 注意 keepalive 组件副作用很多,因为他是将渲染后的页面保存在内存中。页面不会一次渲染,所以对于使用 onMounted 的页面会失效,页面不会重新加载数据 ::: --- --- url: /docs/5.0/front/catch-table.md --- # CatchTable 表格组件 - 高效动态数据表格解决方案 `CatchTable` 是一个专为 CatchAdmin Vue 应用设计的高性能表格组件,致力于简化后台管理系统中表格开发的复杂度。通过动态配置和模块化设计,CatchTable 能显著提升开发效率,提供完整的数据表格管理功能。 ## CatchTable 基础用法与快速上手 创建一个功能完整的数据表格只需简单配置即可实现。以下以用户管理页面为实例,详细演示 CatchTable 组件的基础使用方法 ![CatchAdmin 表格基础用法-laravel admin](https://image.catchadmin.com/202406130849406.png) 代码如下 ```javascript ``` ## CatchTable 按钮权限控制管理 CatchTable 提供完整的按钮权限管理功能。通过 `permission` 属性实现细粒度的权限控制,属性值格式为 `module.controller`(模块名.控制器名),请注意使用小写格式。以下是用户模块权限配置示例 ```javascript ``` ### CatchTable 内置操作方法 (Built-in Actions) CatchTable 预定义了完整的 CRUD 操作方法,每个操作都对应后端控制器的特定方法: * **export** - 数据导出功能,调用控制器的 `export` 方法 * **import** - 数据导入功能,调用控制器的 `import` 方法 * **store** - 数据新增功能,调用控制器的 `store` 方法 * **update** - 数据编辑功能,调用控制器的 `update` 方法 * **destroy** - 数据删除功能,调用控制器的 `destroy` 方法 * **restore** - 数据恢复功能,调用控制器的 `restore` 方法 ## CatchTable 高级搜索功能配置 ![CatchAdmin 表格搜索功能-laravel admin](https://image.catchadmin.com/202406130849989.png) CatchTable 提供强大的搜索功能,通过配置 `search-form` 属性即可实现多条件组合查询。支持多种表单控件类型,满足各种业务场景的搜索需求 ```javascript ``` ok,这样一个完整的表格页面就创建完成了。 ### search 组件支持以下表单组件 * `input` * `select` * `input-number` * `date` * `datetime` * `range` * `tree` * `remote-api-select` * `remote-select` #### Tree 组件特殊配置说明 `tree` 组件是基于下拉选择器的树形结构控件,专门用于处理具有层级关系的数据选择。由于 tree 组件通常需要从后端 API 动态获取数据,因此必须配置响应式数据源。以下是 tree 组件的标准配置方法: ```ts // 首先在 setup 中设置 search 相关组件 // 在 catch table 种设置 search 即可 ``` #### 远程下拉 使用远程接口下拉组件,可以获取后台任何带有分页接口数据。如果没有分页,请使用 `select` 组件 ```ts ``` #### 范围搜索 这里使用时间范围选择,接口会使用 `start_at` 和 `end_at` 两个搜索参数 ```ts ``` ## 获取当前列表的搜索参数数据 ```ts import { useQueryStore } from '@/components/catchTable/useQueryStore' const queryStore = useQueryStore() // 这样你就可以获取当前列表的搜索参数数据了 console.log(queryStore.getTableQuery) ``` ## CatchTable 数据新增功能实现 CatchTable 提供完整的 CRUD(增删改查)操作支持。数据新增功能通过 Vue 插槽(slot)机制实现,允许开发者自定义新增表单的界面和逻辑。以下演示如何在 CatchTable 中集成数据新增功能: ```javascript ``` 这里需要注意两点的是,一般情况下 Create 组件都是由代码自动生成功能生成的 * `Create` 组件是自带 `primary` props 的,用于更新 * `Create` 组件是自带 `api` props 的,api 主要用于接口提交 ### 弹窗关闭保持搜索条件 目前 CatchTable 内置了弹窗关闭保持搜索条件的功能,有时候翻页,例如翻页到第 10 页,修改数据,保存之后。会重置分页数据。如果需要保持搜索条件,可以 在 Create 组件中找到 `close` 方法。 ```javascript const closeDialog = inject('closeDialog') as Function onMounted(() => { close(() => closeDialog(false)) // 设置为 false,就不会重置分页数据了 }) ``` ## CatchTable 回收站功能配置 CatchTable 内置数据回收站功能,支持软删除和数据恢复机制。启用回收站功能只需简单的配置即可: ```javascript ``` ### 数据恢复 恢复功能需要添加一条路由才可以正常运行,例如用户管理(`UserController`)添加一条 `restore` 路由 ```php // 回收站恢复 Route::put('users/restore/{id}', [UserController::class, 'restore']); ``` :::warning 回收站数据的删除是强制删除,删除后数据将不可恢复 ::: ## 隐藏分页 一般列表都是需要分页的,但是某种场景下,需要隐藏分页的话,可以使用下面的代码 ```javascript ``` ## 树形表格 要使用树形表格,在 `catch-table` 中也是非常简单的,只需要 ```javascript ``` > {info} > 注意在 `catchtable` 中,树形表格都是自动隐藏分页的 ## 空数据显示的文本 如果表格没有数据,需要友好的提示的话,那么可以使用下面的代码,默认使用`暂无数据` ```javascript ``` ## 隐藏操作 表格默认一个新增操作,如果不需要的话,可以使用 ```javascript ``` ## 隐藏表头 ```javascript ``` ## 隐藏工具栏 在表格右上角,有三个默认工具栏操作,分别是 `刷新`,`表格栏目`, `搜索`, 如果不需要的话,可以使用 ```javascript ``` ## 隐藏多选删除 ```javascript ``` ## 默认参数 有这么一个场景,例如后台的字典管理,每个字典都需要管理字典值。而每个字典值列表则需要字典的 ID。这个时候 每个请求列表的 api 都是需要默认参数 `字典ID`。这个时候就需要添加默认参数 ```javascript ``` ## 搜索设置默认参数 如果需要给搜索框设置某一个默认值,可以使用 `default` 属性,这样每次进入列表页面,都可以自带一个默认搜索参数了 ```javascript ``` ## 默认选中 有时候表格需要默认选中一些数据,我们可以使用 ```javascript ``` :::tip 目前使用表格数据的主键数据作为选中依据 ::: ## Table 曝露方法 有一些需求可能需要直接操作表格的方法。目前表格对外有几个可以直接调用的方法,调用方法之前需要先设置 `table ref`,在获取整个`catchtable`对象 ref 之后,才可以使用 ```vue // js 代码 // ⚠️如果你对 vue 不熟悉的话,注意 ref="catchadmin" 这里 ref 的名称需要和 const [catchtable] 相同 ``` ### 搜索 在某些操作之后,需要搜索刷新列表 ```vue ``` ### 重置 在某些操作之后,需要重置列表,也可以叫做刷新吧 ```vue ``` ### 打开弹出层 ```vue ``` ### 关闭弹出层 ```vue ``` ### 删除 某些场景需要访问删除接口时候,就可以使用它 ```vue ``` ### 设置默认搜索参数 这个方法在某些特定场景下会有用到,比如一个表格列表的访问他的子列表,子列表需要父列表的某个条件才能访问到。这个时候就需要给子列表设置一个默认参数。`字典管理`列表就是一个很好的例子 ```vue ``` ### 获取表格多选 ID 目前 `catchadmin` 已经内置了多选删除。如果需要做其他多选操作的时候,可以使用它获取多选数据 ```vue ``` ## 表格插槽 为了让表格更加灵活点,`catchtable` 内置了几个插槽,来让用户自定义操作 ### 表格操作插槽 `catchtable` 默认只有新增操作,如果你需要添加其他的操作,那么你可以使用以下代码,新增表格的操作 ```vue ``` ![CatchAdmin 表格操作插槽-laravel admin](https://image.catchadmin.com/202406130851032.png) ### 搜索和表格之间插槽 `catchtable` 提供了搜索和表格之间的插槽,可以用于自定义搜索和表格之间的内容 ```vue ``` ### 批量操作插槽 目前表格内置了`批量删除`操作。当表格需要额外的批量操作时,可以使用该插槽。 ```vue ``` 光是这样的是不够的,还要获取批量选择 ID,请查看[获取表格多选 ID](#获取表格多选id),获取到多选 ID 之后进行操作 ![CatchAdmin 批量操作插槽-laravel admin](https://image.catchadmin.com/202406130852219.png) ### 栏目操作插槽 表格栏目支持`更新`和`删除`操作,如果还需要额外的操作,那么可以使用 ```vue // 通过 scope 你可以获取行数据 ``` ![CatchAdmin 栏目操作插槽-laravel admin](https://image.catchadmin.com/202406130852588.png) ### 弹窗插槽 弹窗插槽是每个表格都需要的,目前只服务于表单数据。 ```vue ``` ## 表格栏目 对于表格栏目,可以通过表格类型窥探一二。看下表格栏目是如何定义的 ```js export type columnType = 'expand' | 'selection' | 'index' | 'operate' export type fixed = 'fiexed' | 'right' | 'left' export interface Column { type?: columnType // 类型 expand select index label?: string prop?: string 'min-width'?: string | number width?: number | string slot?: 'string' header: 'string' // 表头插槽名称 align?: string fixed?: fixed sortable?: boolean | string 'sort-method'?: Function 'sort-by'?: Function resizable?: boolean 'header-align'?: string 'class-name'?: string selectable?: Function // function(row, index) show: boolean index?: number | Function // 如果设置了 type=index,可以通过传递 index 属性来自定义索引 children?: Array // 多级表头 filter?:Function, ellipsis?:boolean|number, // 当文字太多时,可以使用省略文字 switch: false, // swith 字段状态切换 // 操作 update?: boolean, // 编辑操作 destroy?: boolean // 删除操作 } ``` ### 栏目类型 `type` 字段 * `expand` 展开类型,树形结构的表格,规定哪个栏目展开 * `selection` 多选类型,一般用于表格多选操作。一般都是用于主键字段 * `index` 可以自定义索引 * `operate` 最后一行操作栏目 ### 栏目固定 `fiexed` 字段 * fixed 默认固定 * right 固定在右侧 * left 固定在左侧 ### 插槽 如果栏目是需要自定义,那么肯定是需要用插槽这个功能。只需要设置 `slot` 字段,例如插槽名称设置为 ```javascript { label: '你好', slot: 'hello' } ``` 那么此时只需要在`catchtable`组件如下设置 ```vue ``` ### 格式化字段 有时候并不需要插槽,例如当后台的接口中的性别字段(gender)返回 1, 2。其中 1 代表男 2 代表女,这个时候需要实现格式化方法即可 ```js { label: '性别', prop: 'gender', filter: (value) => { return value === 1 ? '男' : '女' } } ``` ### 自定义索引 当栏目的 type 设置成 `index` 时,则需要自定义索引,一般通过 `index` 来设置 ```js { type: 'index', prop: 'gender', index: () => {} } ``` ### 多级表头 当然,catchtable 也支持多集表头,只要一个简单的配置即可 ```js { prop: 'job_name', label: '岗位名称', children: [ { prop: 'coding', label: '岗位编码' }, { label: '状态', prop: 'status', switch: true, align: 'center' } ] } ``` ![CatchAdmin 多级表头-laravel admin](https://image.catchadmin.com/202406130854407.png) ### 字段太长,省略号 ```js { prop: 'description', label: '岗位描述', ellipsis: true // 添加该字段 }, ``` ### 字段状态切换 某些场景下,业务中只需要在表格中做某些字段的状态切换,这个时候就可以使用下面的代码 ```javascript { prop: 'status', // 设置字段,这里仅做演示 label: '状态', switch: true // 添加该字段 }, ``` `catchadmin`在后端通常使用 `enable` 方法做字段切换的路由, 你可以根据实际改动。代码如下 ```php public function enable($id, Request $request) { return $this->model->toggleBy($id, $request->get('field')); } ``` ![CatchAdmin 字段状态切换-laravel admin](https://image.catchadmin.com/202406130855026.png) ### 图片预览 如果表格中需要进行图片预览,那么可以使用下面的配置,只需要使用 `image` 属性 ```js { label: '内容', prop: 'content', image: true, }, ``` 如果你是想要预览,如果是单图的话,你需要使用 `filter` 转换成多图数组 ```js { label: '内容', prop: 'content', image: true, preview: true, filter: (value: any) => { return [value] } }, ``` ### 链接 如果表格中需要某个字段需要链接,那么可以使用下面的配置, 也是非常简单,只需要配置 `link` 属性 ```js { label: '链接', prop: 'url', link: true }, ``` ### 标签展示 如果表格中需要某个字段需要标签,那么可以使用下面的配置, 也是非常简单,只需要配置 `tags` 属性,单个标签 ```js { label: '类型', prop: 'type', tags: true }, ``` 多个标签一般都是配合枚举值,`catchadmin` 枚举一般使用 number,并且从数字`1`开始,数组可以很好配合使用 ```js { label: '类型', prop: 'type', tags: ['danger', 'info', 'success'], filter: (value: number) => { return value === 1 ? '轮播图' : value === 2 ? '友情链接' : '广告' } }, ``` ### 排序 某些场景下,业务中只需要在表格中做某个字段排序。通常来说,elementPlus 只是在前端列表单独一页排序,但是使用下面的代码,可以直接进行后端排序,不需要写任何一行代码,都是自动完成的 ```js { prop: 'sort', label: '排序', sortable: true } ``` ![CatchAdmin 表格排序-laravel admin](https://image.catchadmin.com/202406130856803.png) ### Mask 数据 某些时候,希望数据默认是以 `******` 这样的形式展示,那么你需要这么设置 ```js { prop: 'secret', label: '密钥', mask: true } ``` ![CatchAdmin 表格 Mask 数据-laravel admin](https://image.catchadmin.com/202410261739969.png) --- --- url: /docs/5.0/front/catch-form.md --- # 🔮 动态表单 经过一段时间调研和开发,最终还是推出了全新动态表单的功能,不仅支持 JSON 配置,还支持的动态解析和动态调用,相较于前一个版本,提高了非常多 :::tip 示例都是基于整个后台框架的,不要单独拎出去使用 ::: :::tip 如果你需要服务端组件,可以支持购买[动态表单](/docs/forms/intro) ::: ## 基本使用 先来看一个简单的表单示例,表单包含一个`input` 框架 ```vue ``` 使用 `CatchForm` 组件,这里非常简单,包含一个 props 和一个提交方法 * `schema` 是 form 的数据结构,就是存放 form 组件的对象 * `onSubmit` 是 form 提交方法 再来看下 schema 的结构 ```js type schema = { labelWidth: number // label 宽度 labelAlign: string // label 位置 size: string // 表单大小 footer: Object // 表单底部 class?: string // 表单 class 支持 tailwindcss disabled?: boolean // 是否禁用 labelBold?: boolean // label 文字是否粗体 items: formItemsType // 表单字段 } ``` 所以回到刚才的 `form` 数据,看看结构,里面只包含 `items`,也就是表单的字段集合。再来看看表单字段的结构 ```typescript { name: 'name', // 字段 name props: { // 组件对应的 props,可以参考 ElementPlus 对应组件的 props clearable: true }, label: '姓名', // label 值 component: 'input', // 组件 class: 'mt-4', // 组件 class,支持 tailwindcss required: true // 是否必选 } ``` 再来看看字段的定义, 包含全部 ```js interface formItemType { label?: string // label 值 name: string // 字段 name component: string // 字段组件 required?: boolean // 是否必填 props?: object // // 组件对应的 props,可以参考 ElementPlus 对应组件的 props initialValue?: any // 默认值 children?: formItemType[] // 支持子组件,例如 grid 组件 hidden?: boolean | string // 是否隐藏 hideLabel?: boolean // 是否隐藏 label rules?: any[] // 表单验证规则 class?: string // 组件 class,支持 tailwindcss style?: any // 行内样式 change?: changeItemType[] // change 方法 } ``` ## 表单组件 :::warning 所有组件的 `name` 都是必须的 动态组件内的 props 属性,都是和 ElementPlus 组件内的 `props`, 由于篇幅限制这里就不再展示,请到官方文档查看 ::: ### 辅助组件 #### Alert 组件 [Alert 组件 props](https://element-plus.org/zh-CN/component/alert.html#alert-api) ```typescript { name: 'alert', props: { title: "Hello Alert" }, component: 'alert', // 组件 } ``` #### button 组件 [button 组件 props](https://element-plus.org/zh-CN/component/button.html#button-api) ```typescript { name: 'button', props: { name: '提交', clickEvent: 'submitForm' // 点击提交事件 }, component: 'button', // 组件 } ``` #### 分割线组件 [分割线组件 props](https://element-plus.org/zh-CN/component/divider.html#api) ```typescript { name: 'divider', props: { title: '分割线组件' }, component: 'divider', // 组件 } ``` ### Layout 组件 #### Grid 组件 Grid 两栏 ```typescript { component: 'grid', children: [ { label: '名称', component: 'input', props: { placeholder: '请输入名称' }, name: 'name' }, { label: '名称1', component: 'input', props: { placeholder: '请输入名称1' }, name: 'name1' } ], props: { columns: 2, // 栏目数量 'column-gap': 20, // 栏目间距 'row-gap': 20 // 行间距 }, name: 'grid' } ``` #### Card 组件 `Card` 和 `Grid` 可以通过 `children`属性 组合使用 ```js { component: 'card', children: [ { label: '名称', component: 'input', props: { placeholder: '请输入名称' }, name: 'name' } ], props: { header: '卡片' }, name: 'card' } ``` #### Inline 行内组件 ```js { component: 'inline', children: [ { label: '名称', component: 'input', props: { placeholder: '请输入名称' }, name: 'name' }, { label: '名称1', component: 'input', props: { placeholder: '请输入名称' }, name: 'name1' } ], props: { align: 'left', gap: 20 }, name: 'inline' } ``` ### 表单字段组件 #### Switch 组件 [switch 组件 props](https://element-plus.org/zh-CN/component/switch.html#api) ```js { label: '开关', component: 'switch', props: { 'inline-prompt': false }, name: 'status' } ``` #### Input 组件 [Input 组件 props](https://element-plus.org/zh-CN/component/input.html#api) ```js { label: '名称', component: 'input', props: { placeholder: '请输入名称' }, name: 'name' } ``` #### Password 组件 [Input 组件 props](https://element-plus.org/zh-CN/component/input.html#api) ```js { label: '密码', component: 'password', props: { placeholder: '请输入密码' }, name: 'password' } ``` #### Select 组件 [Select 组件 props](https://element-plus.org/zh-CN/component/select.html#select-api) ```js { label: '下拉选择框', component: 'select', props: { options: [ { label: '选项1', value: 'value1' }, { label: '选项2', value: 'value2' }, { label: '选项3', value: 'value3' } ], placeholder: '请选择...', labelKey: 'label', valueKey: 'value' }, name: 'select' } ``` #### Cascader 组件 [Cascader 组件 props](https://element-plus.org/zh-CN/component/cascader.html#cascader-api) ```js { label: '级联选择器', component: 'cascader', props: { placeholder: '请选择...', labelKey: 'label', valueKey: 'value', options: [ { label: '选项1', value: 'value1', children: [ { label: '选项1-1', value: 'value1-1' }, { label: '选项1-2', value: 'value1-2' }, { label: '选项1-3', value: 'value1-2' } ] }, { label: '选项2', value: 'value2', children: [ { label: '选项2-1', value: 'value2-1' }, { label: '选项2-2', value: 'value2-2' }, { label: '选项2-3', value: 'value2-2' } ] }, { label: '选项3', value: 'value3' } ] }, name: 'cascader' } ``` #### Checkbox 组件 [Checkbox 组件 props](https://element-plus.org/zh-CN/component/checkbox.html#checkbox-api) ```js { label: '多选框组', component: 'checkbox', props: { placeholder: '请选择...', options: [ { label: '选项1', value: 'value1' }, { label: '选项2', value: 'value2' }, { label: '选项3', value: 'value3' } ], labelKey: 'label', valueKey: 'value' }, name: 'checkbox' } ``` #### ColorPicker 组件 [ColorPicker 组件 props](https://element-plus.org/zh-CN/component/color-picker.html#api) ```js { label: '颜色选择器', component: 'color_picker', name: 'colorPicker' } ``` #### 日期组件 [日期组件 props](https://element-plus.org/zh-CN/component/date-picker.html#api) ```js { label: '日期选择器', component: 'date_picker', props: { type: 'datetime', placeholder: '请选择日期', clearable: false }, name: 'DatePicker' } ``` #### 图标选择器 #### 数字组件 [数字组件 props](https://element-plus.org/zh-CN/component/input-number.html#api) ```js { label: '数字组件', initialValue: 1, component: 'input_number', name: 'input_number' } ``` #### Radio 组件 [Radio 组件 props](https://element-plus.org/zh-CN/component/radio.html#radio-api) ```js { label: '单选框组', component: 'radio', props: { options: [ { label: '选项1', value: 'value1' }, { label: '选项2', value: 'value2' }, { label: '选项3', value: 'value3' } ], labelKey: 'label', valueKey: 'value', optionType: 'circle', direction: 'horizontal', }, name: 'radio' } ``` #### Rate 评分组件 [Rate 评分组件 props](https://element-plus.org/zh-CN/component/rate.html#api) ```js { label: '评分', component: 'rate', name: 'rate' } ``` #### 滑块组件 [滑块组件 props](https://element-plus.org/zh-CN/component/slider.html#api) ```js { label: '滑块', component: 'slider', name: 'slider' } ``` #### Transfer 组件 [Transfer 组件 props](https://element-plus.org/zh-CN/component/transfer.html#api) ```js { label: '穿梭框', component: 'transfer', props: { options: [ { label: '选项1', value: 'value1' }, { label: '选项2', value: 'value2' }, { label: '选项3', value: 'value3' } ], labelKey: 'label', valueKey: 'value' }, name: 'transfer' } ``` #### 上传组件 ##### 单图上传 ```js import { getAuthToken, env } from '/admin/support/helper' const form = { items: [ { label: '单图上传', props: { action: env('VITE_BASE_URL') + 'upload/image', name: 'image', token: 'Bearer ' + getAuthToken() }, component: 'upload_image', name: 'image' } ] } ``` ##### 多图上传 ```js import { getAuthToken, env } from '/admin/support/helper' const form = { items: [ { label: '多图上传', props: { action: env('VITE_BASE_URL') + 'upload/image', name: 'image', token: 'Bearer ' + getAuthToken() }, component: 'upload_images', name: 'image' } ] } ``` ##### 单文件上传 ```js import { getAuthToken, env } from '/admin/support/helper' const form = { items: [ { label: '单文件上传', props: { action: env('VITE_BASE_URL') + 'upload/file', name: 'image', token: 'Bearer ' + getAuthToken() }, component: 'upload_file', name: 'file' } ] } ``` ##### 多文件上传 ```js import { getAuthToken, env } from '/admin/support/helper' const form = { items: [ { label: '多文件上传', props: { action: env('VITE_BASE_URL') + 'upload/file', name: 'image', token: 'Bearer ' + getAuthToken() }, component: 'upload_files', name: 'file' } ] } ``` #### Tree 组件 [Tree 组件 props](https://element-plus.org/zh-CN/component/tree.html#%E5%B1%9E%E6%80%A7) ```js { label: '树形结构', props: { 'show-checkbox': true, options: [ { label: '选项1', value: 'value1', children: [ { label: '选项1-1', value: 'value1-1' }, { label: '选项1-2', value: 'value1-2' }, { label: '选项1-3', value: 'value1-2' } ] }, { label: '选项2', value: 'value2', children: [ { label: '选项2-1', value: 'value2-1' }, { label: '选项2-2', value: 'value2-2' }, { label: '选项2-3', value: 'value2-2' } ] }, { label: '选项3', value: 'value3' } ], }, component: 'tree', name: 'tree' } ``` #### 自增表单 ```js { label: '动态配置', props: { children: [ { name: 'name', label: '名称', component: 'input', props: { clearable: true, placeholder: '请输入名称' } }, { name: 'name1', label: '名称1', component: 'input', props: { clearable: true, placeholder: '请输入名称1' } } ] }, component: 'form_list', name: 'hello' } ``` --- --- url: /docs/5.0/video.md --- # 视频教程 `CatchAdmin` 是一款基于 `Laravel` 开发的 PHP 开源后台管理框架系统,为用户提供了丰富的后台管理功能。在这个视频教程系列中,我将带您深入了解 `CatchAdmin` 的各个方面,包括但不限于: * 安装和配置 CatchAdmin * 使用 CatchAdmin 的各种功能,如用户管理、角色管理、权限管理、菜单管理等 * 开发自定义模块和扩展 我的视频教程将以实际项目为例,并结合实用的案例和示例,帮助您快速上手和使用 `CatchAdmin`。此外,我还将与您分享最佳实践和技巧,帮助您在使用 `CatchAdmin` 中更加高效和便捷。 我的视频教程将持续更新,以反映 `CatchAdmin` 的最新版本和最佳实践。如果您想获得最新的 `CatchAdmin` 视频教程,请订阅我的频道并打开通知。 ## laravel 版本 * [项目安装](https://www.bilibili.com/video/BV1eY411v71J) * [catchadmin 模块创建](https://www.bilibili.com/video/BV1jP41127aW/) * [catchadmin 快速开发](https://www.bilibili.com/video/BV1Qh4y1J7eB/) ## thinkphp 版本 * [项目安装](https://www.bilibili.com/video/BV1bD4y1R72m/) * [编写模块](https://www.bilibili.com/video/BV1Pk4y1y7no) * [catch-table 介绍](https://www.bilibili.com/video/BV1Py4y1x7q5/) --- --- url: /docs/5.0/faq.md --- # CatchAdmin 常见问题 > 使用 CatchAdmin 过程中的常见问题和解决方案 ## 响应格式不正确 如果你使用了类似 `postman` `apifox` 等等 api 管理工具,请求接口出现只输出一个字符串,而不是标准的后台响应结构的话。大概率是你缺少了头信息。你需要添加以下头信息 ```php Request-From: Dashboard ``` ## 依赖问题 由于 `Laravel12` 刚发布,CatchAdmin 的依赖可能无法正常安装。这通常是由于镜像更新慢导致的,建议取消使用镜像,直接从官方源下载。如果网络条件不佳,可以使用'魔法'工具(懂得吧)来提升下载速度。 ### 镜像 这是目前维护中的可用的 composer 镜像,使用下面的命令安装 ```shell composer config -g repos.packagist composer https://packagist.pages.dev ``` ## 路由未找到 遇到 CatchAdmin 路由访问问题时,首先检查路由是否存在: ```bash php artisan route:list ``` 如果接口路由不在路由表中,通常是因为相关模块未启用。请检查 `storage/app/modules.json` 文件中的模块状态,以权限模块为例: ```json { "title": "权限管理", "name": "permissions", "path": "permissions", "keywords": "权限, 角色, 部门", "description": "权限管理模块", "provider": "\\Modules\\Permissions\\Providers\\PermissionsServiceProvider", "version": "1.0.0", "enable": true // 该字段是否开启 } ``` ## 模块路由命名重复 在 CatchAdmin 开发中,当多个模块存在同名控制器时可能出现路由冲突。例如 CMS 模块和 SHOP 模块都有名为 `CategoryController` 的控制器。正常情况下,通过路由分组就能解决: ```php // cms 分类路由 Route::prefix('cms')->group(function () { Route::apiResource('category', CategoryController::class); }); // shop 分类路由 Route::prefix('shop')->group(function () { Route::apiResource('category', CategoryController::class); }); ``` 但是这里会出现一个问题,当使用 ```sh php artisan route:cache ``` 的时候,会提示一个错误 ```shell Unable to prepare route [api/shop/category] for serialization. Another route has already been assigned name [category.index]. ``` 这个问题就是两个路由的 `name` 重复了, 无法进行缓存了。这里就需要设置成这样,只改 shop 的路由即可 ```php // shop 分类路由 Route::prefix('shop')->group(function () { Route::apiResource('category', CategoryController::class)->names('shop_category') }); ``` ## 打包出现报错 在构建 CatchAdmin 前端项目时,如果出现过多的 TypeScript 类型错误,但你对类型检查不太敏感,这些错误通常不会影响应用正常运行。 快速解决方法是修改 `package.json` 文件中的 build 命令,跳过类型检查: ```json { "scripts": { "dev": "vite", "build": "vue-tsc --noEmit && vite build", // [!code --] "build": "vite build", // [!code ++] "preview": "vite preview" } } ``` ## Specified key was too long; max key length is 1000 bytes ```shell SOLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 1000 bytes (... ``` 如果安装的时候遇到这种错误,可以在使用下面的应急方案 :::code-group ```php [app/Providers/AppServiceProvider.php] namespace App\Providers; use Illuminate\Support\ServiceProvider; // 添加这一行 use Illuminate\Support\Facades\Schema; class AppServiceProvider extends ServiceProvider { /** * Register any application services. */ public function register(): void { // } /** * Bootstrap any application services. */ public function boot(): void { // 添加这一行 Schema::defaultStringLength(191); } } ``` ::: --- --- url: /docs/forms/components/option.md --- # Option 组件 --- --- url: /docs/5.0/start/thinkphp.md --- # ThinkPHP 版本安装 ## 环境要求 * PHP >= 8.0+ * Nginx * Mysql >= 5.7 ## 安装 ### 准备 在安装这个软件之前,您需要准备一些必要的工具,包括: * [git 代码管理](https://git-scm.com/downloads) * [composer PHP 包管理器](https://getcomposer.org/download/) * [nodejs >= 18.8.0](https://nodejs.org/zh-cn/) * [yarn 前端包管理器](https://yarn.bootcss.com/) * [vite](https://cn.vitejs.dev/) ### 下载项目 接下来,您需要下载 CatchAdmin 项目。您可以前往该项目的托管仓库 [CatchAdmin](https://gitee.com/catchamin/catchadmin-tp) 上的页面进行下载,也可以使用 `git` clone 命令将代码克隆到本地,这样就能及时获取代码更新。 ```sh git clone https://gitee.com/catchamin/catchadmin-tp.git ``` 请注意,该项目不提供 Web 安装方式,因此您需要使用命令行方式进行安装。在安装之前,请确保已经安装了 `composer` 包管理器。如果您使用的是 `Mac OS` 或者 `Linux`,可以在终端输入以下命令安装 `composer` ```shell // mac os brew install composer // linux sudo apt-get install composer ``` 如果您使用的是 `Windows` 系统,可以从 [composer](https://docs.phpcomposer.com/) 的官方网站下载 exe 安装文件进行安装。一旦您已经安装了 `composer`,接下来您可以进入 `CatchAdmin` 项目所在的目录,并运行以下命令进行安装: ```shell composer install ``` 这个命令会自动下载并安装`CatchAdmin`项目所需要的 PHP 包。 除了 PHP 包之外,该项目还需要一些前端包。您可以使用以下命令安装这些包: ```shell // 安装完 nodejs 之后,再安装 yarn npm install --global yarn ``` :::tip 一定要安装好 yarn 和 Git 工具 ::: ### 命令安装 :::tip 安装的时候输入 ::: ```shell // 安装后台, 按照提示输入对应信息即可 php think catch:install ``` 命令会自动安装前端项目,并且自动下载前端依赖。所以在这个命令执行完之后,可以直接使用下面的命令启动前端项目。在根目录下 ```sh cd web && yarn dev ``` :::warning 注意不能直接访问 PHP 项目,导致 Exception,前后端分离,需要通过 API 接口形式访问,所以你需要安装 VUE 项目后台,看到数据的展示 ::: :::tip 如果你是第一次使用 Vue,建议先去看看 [Vue](https://cn.vuejs.org/) 文档,了解一下 vue 后台使用了是 `element Plus` [文档地址](https://element-plus.org) ::: ## 代码生成 :::warning Laravel 和 tp 的代码生成功能是不一样的,默认项目使用 Laravel 的,如果需要开启 tp 的,则需要在前端项目的 `.env` 配置文件加上下面的配置 ::: ```javascript VITE_GENERATE = true ``` 因为是前后端分离,所以整个项目是分为两个项目存在的。 框架默认将前端项目安装在根目录的 `web` 目录,如果你要移动前端目录到其他目录,注意一定要设置下面的配置 * web\_path 前端项目录 * views\_path 前端项目 views 目录 找到 `config/catch.php` 配置文件,切换成实际的前端项目目录即可 ```php return [ // 前端项目目录 'web_path' => root_path('web'), // 前端视图目录 'views_path' => root_path('web').DIRECTORY_SEPARATOR.'src'.DIRECTORY_SEPARATOR.'views'.DIRECTORY_SEPARATOR, ]; ``` ### 打包前端项目 打包前请先配置正是环境 API 地址。在项目的根目录下的`.env.production`文件配置 ``` # base api VITE_BASE_URL = '正式环境的 API 地址' ``` 然后进行打包 ``` yarn run build ``` :::tip 前端项目配置最好开启 `Gzip`,可以加速前端项目访问速度。 ::: --- --- url: /docs/forms/components/transfer.md --- # Transfer [ElementPlus transfer 组件](https://element-plus.org/zh-CN/component/transfer.html) ### 设置数据 设置转移组件的数据。 ```php Transfer::date( [ ['key' => 1, 'label' => '选项 1'], ['key' => 2, 'label' => '选项 2'], ]) ``` **返回:** `static` *** ### 设置搜索框占位符 设置搜索框的占位符。 ```php Transfer::date([ ['key' => 1, 'label' => '选项 1'], ['key' => 2, 'label' => '选项 2'], ]) ``` **返回:** `static` *** ### 推送 设置目标顺序为将项目推送到列表末尾。 **返回:** `static` *** ### 设置标题 为左右列表设置自定义标题。 **返回:** `static` *** ### 推送到头部 设置目标顺序为将项目推送到列表头部。 **返回:** `static` *** ### 设置左侧已勾选项 设置初始状态下左侧列表的已勾选项的 key 数组。 **返回:** `static` *** ### 设置右侧已勾选项 设置初始状态下右侧列表的已勾选项的 key 数组。 **返回:** `static` *** ### 关闭验证 关闭验证功能。 **返回:** `static` *** ### 设置按钮文案 自定义按钮的文案。 **返回:** `static` *** ### 设置格式 设置格式化字符串。 **返回:** `static` *** --- --- url: /docs/forms/validates/required.md --- --- --- url: /docs/5.0/start/webman.md --- # Webman 版本安装 ## 环境要求 * PHP >= 8.0+ * Nginx * Mysql >= 5.7 ## 安装 ### 准备 在安装这个软件之前,您需要准备一些必要的工具,包括: * [git 代码管理](https://git-scm.com/downloads) * [composer PHP 包管理器](https://getcomposer.org/download/) * [nodejs >= 20.0](https://nodejs.org/zh-cn/) * [yarn 前端包管理器](https://yarn.bootcss.com/) * [vite](https://cn.vitejs.dev/) ### 下载项目 接下来,您需要下载 CatchAdmin 项目。您可以前往该项目的托管仓库 [CatchAdmin](https://gitee.com/catchamin/catchadmin-webman) 上的页面进行下载,也可以使用 `git` clone 命令将代码克隆到本地,这样就能及时获取代码更新。 ```sh git clone https://gitee.com/catchamin/catchadmin-webman.git ``` 请注意,该项目不提供 Web 安装方式,因此您需要使用命令行方式进行安装。在安装之前,请确保已经安装了 `composer` 包管理器。如果您使用的是 `Mac OS` 或者 `Linux`,可以在终端输入以下命令安装 `composer` ```shell // mac os brew install composer // linux sudo apt-get install composer ``` 如果您使用的是 `Windows` 系统,可以从 [composer](https://docs.phpcomposer.com/) 的官方网站下载 exe 安装文件进行安装。一旦您已经安装了 `composer`,接下来您可以进入 `CatchAdmin` 项目所在的目录,并运行以下命令进行安装: ```shell composer install ``` 这个命令会自动下载并安装`CatchAdmin`项目所需要的 PHP 包。 除了 PHP 包之外,该项目还需要一些前端包。您可以使用以下命令安装这些包: ```shell // 安装完 nodejs 之后,再安装 yarn npm install --global yarn ``` :::tip 一定要安装好 yarn 和 Git 工具 ::: ### 命令安装 ```shell // 安装后台, 按照提示输入对应信息即可 php webman catch:install ``` 命令会自动安装前端项目,并且自动下载前端依赖。所以在这个命令执行完之后,可以直接使用下面的命令启动前端项目。在根目录下 ```sh cd web && yarn dev ``` :::warning 注意不能直接访问 PHP 项目,导致 Exception,前后端分离,需要通过 API 接口形式访问,所以你需要安装 VUE 项目后台,看到数据的展示 ::: :::tip 如果你是第一次使用 Vue,建议先去看看 [Vue](https://cn.vuejs.org/) 文档,了解一下 vue 后台使用了是 `element Plus` [文档地址](https://element-plus.org) ::: ## 代码生成 :::warning Laravel 和 webman 的代码生成功能是不一样的,默认项目使用 Laravel 的,如果需要开启 webman 的,则需要在前端项目的 `.env` 配置文件加上下面的配置 ::: ```javascript VITE_GENERATE = true ``` 因为是前后端分离,所以整个项目是分为两个项目存在的。 框架默认将前端项目安装在根目录的 `web` 目录,如果你要移动前端目录到其他目录,注意一定要设置下面的配置 * web\_path 前端项目录 * views\_path 前端项目 views 目录 找到 `config/catch.php` 配置文件,切换成实际的前端项目目录即可 ```php return [ // 前端项目目录 'web_path' => root_path('web'), // 前端视图目录 'views_path' => root_path('web').DIRECTORY_SEPARATOR.'src'.DIRECTORY_SEPARATOR.'views'.DIRECTORY_SEPARATOR, ]; ``` ### 打包前端项目 打包前请先配置正是环境 API 地址。在项目的根目录下的`.env.production`文件配置 ``` # base api VITE_BASE_URL = '正式环境的 API 地址' ``` 然后进行打包 ``` yarn run build ``` :::tip 前端项目配置最好开启 `Gzip`,可以加速前端项目访问速度。 ::: --- --- url: /docs/5.0/server/dictionary.md --- # 字典功能 字典功能在后台一直是一个存在感很低的功能,尤其是前后端分离系统中。因为字典的数据在服务端,想要跟前端数据联动的话,需要对原始跟字段数据做一些标记。它最大的用处可能在生成代码的,为一些 `Radio` 组件或者 `Select` `Switch` 组件提供一些基础数据。如下 ![Catchadmin 字典功能-Laravel Admin](https://image.catchadmin.com/202408231339856.png) :::info [CatchAdmin 字典功能视频教程](https://www.bilibili.com/video/BV1RTWReFEHs/) ::: ## 扩展 当字典功能单独作为一个增删改查的功能,只能给前端生成页面提供一些基础数据的时候,其在后台的作用真的是非常小。但是在业务中又有很多地方用到这个。的确给定义一些选项提供了很大的方便,很大程度上保证了数据可以集中管理,不会那么分散。 但是在业务中,会有相当一部分逻辑判断会使用到字典的值。一旦需要使用到,很可能就是出现下面的代码 ```php // 这里以 status 举例,有 1 和 2 两个状态 if ($model->status === 2) {} ``` 这种代码在项目里如果大量出现的话,必定会是非常不可读的代码。会导致后期维护产生很多问题。所以以字典为枚举数据管理点,为字典自动生成枚举,提供给项目里面使用,最后会产生这样的代码 ```php // 状态断言 if (Status::Enable->assert($model->status)) {} ``` 这样的代码相较于之前有什么好处呢? * 可读写提高非常之多 * 一旦 `model->status === 2` 大量出现在代码里,如果这个状态改变了,那么改动的地方非常至多,使用枚举,只需要改动枚举值即可 ## 枚举生成 我们在字典功能提供了非常方便枚举生成功能 * 自动生成 * 对已有的枚举,会对字典内的值和当前枚举进行对比,如果不同,会覆盖生成 ![Catchadmin 字典枚举生成-Laravel Admin](https://image.catchadmin.com/202408231835985.png) * 列表操作的可以将列表所有字典数据生成枚举 * 数据操作枚举可以生成对应字典的枚举类 --- --- url: /docs/forms/components/button.md --- # 按钮组件 --- --- url: /docs/forms.md --- # 表单 ## 示例 ### 权限表单 ```php return Form::make(function (Form $form){ $form->row(function (Form $form){ $form->col( function (Form $form){ $form->radio('type', '菜单类型')->required()->asButton()->options(MenuType::class) ->defaultValue(1) // 目录 ->whenEqual(MenuType::Top->value(), function (Control $control){ $control->show([ 'permission_name', 'icon', 'module', 'component', 'route', 'hidden', 'redirect', 'sort', 'keepalive']); }) ->whenNotEqual(MenuType::Top->value(), function (Control $control){ $control->hide(['parent_id', 'redirect']); }) ->whenEqual(MenuType::Top->value(), function (Control $control){ $control->required(['permission_name', 'module', 'route']); }) // 菜单操作 ->whenEqual(MenuType::Menu->value(), function (Control $control){ $control->show([ 'permission_name', 'icon', 'module', 'component', 'route', 'hidden', 'redirect', 'sort', 'keepalive', 'select_permission_mark', 'active_menu']); }) ->whenEqual(MenuType::Menu->value(), function (Control $control){ $control->required([ 'permission_name', 'module', 'route', 'select_permission_mark', 'component', 'parent_id']); }) // 按钮操作 ->whenEqual(MenuType::Action->value(), function (Control $control){ $control->show(['permission_name', 'text_permission_mark']); }) ->whenEqual(MenuType::Action->value(), function (Control $control){ $control->required(['permission_name', 'text_permission_mark', 'parent_id']); }) ->emitChange(); $form->text('permission_name', '菜单名称')->maxlength(30)->showWordLimit(); $form->select('module', '所属模块')->options((new Modules())->get())->emitChange(); $form->text('route', '路由Path')->maxlength(30)->showWordLimit(); $form->text('redirect', 'Redirect')->maxlength(50)->showWordLimit(); $form->number('sort', '排序')->min(0)->max(999999)->defaultValue(1); })->span12(); $form->col(function (Form $form){ $form->cascader('parent_id', '上级菜单')->optionsTo('options')->options( \Modules\Permissions\Models\Permissions::query() ->whereIn('type', [ MenuType::Menu->value, MenuType::Top->value ])->get(['id as value', 'permission_name as label', 'parent_id'])->toTree(id: 'value') )->checkStrictly(); $form->selectOptions('permission_mark', '权限标识') ->setName('select_permission_mark') ->api('controllers'); $form->text('permission_mark', '权限标识')->setName('text_permission_mark'); $form->iconSelect('icon', '选择icon')->class('w-full'); $form->selectOptions('component', '所属组件')->api('components'); $form->radio('hidden', 'Hidden')->options(Status::class)->defaultValue(Status::Enable->value()); $form->radio('keepalive', 'Keepalive')->options(Status::class)->defaultValue(Status::Enable->value()); })->span12(); }); $form->text('active_menu', '激活菜单') ->info('如果是访问内页的菜单路由,例如创建文章 create/post, 虽然它隶属于文章列表,但实际上并不会嵌套在文章列表路由里 而是单独的一个路由,并且是不显示在左侧菜单的。所以在访问它的时候,需要左侧菜单高亮,则需要设置该参数'); }); ```