150 Commits
v1 ... v2.5

Author SHA1 Message Date
JaguarJack
068234b57c update:auth增加忽略密码验证,适配第三方登陆 2021-01-27 14:01:17 +08:00
JaguarJack
dc1ce92194 update 2021-01-24 20:27:27 +08:00
JaguarJack
937e1745d2 update:更新默认加载commands 2021-01-24 20:24:43 +08:00
JaguarJack
9f6f02ad24 update:更新上传路由 2021-01-20 20:30:04 +08:00
JaguarJack
340e8c356b fixed:捕获异常以Json方式返回 2021-01-20 20:12:08 +08:00
JaguarJack
65d3111e65 fixed:修复oss上传 2021-01-20 20:09:06 +08:00
JaguarJack
22a8574824 fixed:空值配置无法更新 2021-01-20 19:53:19 +08:00
JaguarJack
584477f711 update:更新包 2021-01-20 19:20:09 +08:00
JaguarJack
2ae7efce04 add:新增初始化管理密码命令 2021-01-20 19:19:28 +08:00
JaguarJack
b12edc9439 update:更新调度 2021-01-18 09:29:02 +08:00
JaguarJack
c02297ab91 更新:支持app commands 自动载入 2021-01-17 20:51:05 +08:00
JaguarJack
b2b6dbd5ed Merge branch 'master' of https://github.com/yanwenwu/catch-admin 2021-01-17 11:22:13 +08:00
JaguarJack
3f154e5fb5 更新:定时任务重新修改 2021-01-17 11:21:52 +08:00
JaguarJack
cff7b38058 update:开启短线重连 2021-01-17 11:17:37 +08:00
JaguarJack
849493eea2 add:新增请求过滤空值方法 2021-01-17 09:39:18 +08:00
JaguarJack
8cace712ae update readme 2020-12-27 13:20:44 +08:00
JaguarJack
b44c8838c4 add:新增隐藏字段功能 2020-12-27 12:33:30 +08:00
JaguarJack
901c7f6cd7 update:更新定时任务搜索 2020-12-26 22:27:06 +08:00
JaguarJack
870e81ab9d add:新增快速搜索 2020-12-26 22:26:36 +08:00
JaguarJack
d4ec2d104f fixed:修改命令行无法生成model field 2020-12-26 20:56:10 +08:00
JaguarJack
614448d07a update:更新监控路由 2020-12-26 20:54:34 +08:00
JaguarJack
dcbe82f398 fixed:修复创建模块 2020-12-13 10:16:46 +08:00
JaguarJack
afe70d39b9 fixed:修复CatchJoin无法连接同一个模型两次 2020-12-13 10:16:28 +08:00
JaguarJack
9118e07d7b fixed 2020-12-04 21:09:50 +08:00
JaguarJack
c0f05fcf8f fixed:模型生成数据库字段注释标记错误 2020-12-01 17:58:53 +08:00
JaguarJack
35445f37e1 fixed:模型name属性多加了表前缀 2020-12-01 17:55:36 +08:00
JaguarJack
94c430f491 update 2020-11-29 09:29:14 +08:00
JaguarJack
97efb82971 update:强制依赖jwt包 2020-11-29 09:18:07 +08:00
JaguarJack
5f49a22a5e add:新增用户token字段 2020-11-23 19:57:49 +08:00
JaguarJack
85f4fc0df8 update:个人信息校验邮箱唯一性 2020-11-21 20:07:36 +08:00
JaguarJack
04a7818608 fixed bug 2020-11-21 12:33:55 +08:00
JaguarJack
21c1df4f69 update:class增加when方法 2020-11-19 19:11:18 +08:00
JaguarJack
0dfe4fb5c6 fixed 2020-11-19 17:44:11 +08:00
JaguarJack
9ca1fd42ae update 2020-11-19 17:31:57 +08:00
JaguarJack
5713d12ce1 updae:基于AST重构代码生成 2020-11-19 17:31:31 +08:00
JaguarJack
e01790aa23 update:composer新增查找package方法 2020-11-19 17:31:04 +08:00
JaguarJack
ecf0970ca4 fixed:修复搜索参数值为0时导致搜索错误 2020-11-19 17:30:30 +08:00
JaguarJack
78e782dd01 fixed:云上传配置无法生效 2020-11-19 09:42:54 +08:00
JaguarJack
e4a5ae0c37 add:新增创建模块 2020-11-14 18:24:33 +08:00
JaguarJack
c8e9e6361c add:新增字段自增/减少方法 2020-11-04 14:09:23 +08:00
JaguarJack
7c4fa5c516 update:优化用户的部门搜索,减少SQL 2020-11-04 10:06:23 +08:00
JaguarJack
97b7f73ff2 add:新增模型获取所有子节点方法 2020-11-04 10:05:50 +08:00
JaguarJack
0b5c883012 update:支持无限级部门搜索 2020-11-04 08:20:15 +08:00
JaguarJack
a9671b6227 update:更新路由 2020-11-03 08:12:10 +08:00
JaguarJack
9ab22b1a1c update:移除角色与部门关联 2020-10-29 08:13:20 +08:00
JaguarJack
a931b7597c update:升级tp核心 2020-10-29 08:01:27 +08:00
JaguarJack
4506219fb2 update:优化auth认证 2020-10-26 19:09:28 +08:00
JaguarJack
91a1d253c5 update:更新request验证 2020-10-26 11:20:42 +08:00
JaguarJack
3d58942844 fixed:SQL解析错误 2020-10-23 15:45:47 +08:00
JaguarJack
e0b2aafd2c update:readme 2020-10-21 18:21:21 +08:00
JaguarJack
7278be4e49 add:新增模型数据缓存 2020-10-21 17:23:22 +08:00
JaguarJack
a62020650c add:新增模型导出 2020-10-21 13:54:55 +08:00
JaguarJack
9baadccfbb add:新增Collection toTree方法 2020-10-21 08:12:07 +08:00
JaguarJack
538006c3c6 update:rewrite request post,自动填入 creator_id 数据 2020-10-15 10:00:35 +08:00
JaguarJack
e2399b6aa6 add:新增域名管理权限 2020-10-14 20:58:34 +08:00
JaguarJack
c5aee52667 update:更新附件删除 2020-10-14 20:17:18 +08:00
JaguarJack
8991315888 add:新增忽略ssl方法 2020-10-14 20:07:36 +08:00
JaguarJack
9754a23360 update:初始化数据更新 2020-10-12 19:24:51 +08:00
JaguarJack
753f6b9dcf fixed:模块列表排除超级管理员 2020-10-12 14:15:41 +08:00
JaguarJack
bcb96cd3c4 update:更新模块列表 2020-10-12 14:00:40 +08:00
JaguarJack
3908c26e2c add:新增GET方法单独的认证标识 2020-10-12 12:22:05 +08:00
JaguarJack
f17570deef uodate:数据获取用户角色,无需用户传参 2020-10-12 10:18:51 +08:00
JaguarJack
390fc8ccd5 update:更新路由 2020-09-29 14:43:07 +08:00
JaguarJack
4d9f57a8c7 update:修改操作日志搜索 2020-09-29 14:34:11 +08:00
JaguarJack
b8e08eac96 update:升级框架至6.0.4 2020-09-29 14:33:45 +08:00
JaguarJack
bece4dac86 delete:冗余模块 2020-09-28 11:14:02 +08:00
JaguarJack
4b8d5aa507 add:域名管理 2020-09-28 09:55:30 +08:00
JaguarJack
5ec24ae9c9 update:模块配置加载 2020-09-26 15:11:50 +08:00
JaguarJack
25c5faf440 add:域名管理first commit 2020-09-26 15:10:41 +08:00
JaguarJack
097b0e1ee5 fixed:登录日志删除失败 2020-09-25 10:47:20 +08:00
JaguarJack
09b20c255b Merge branch 'master' of https://github.com/yanwenwu/catch-admin 2020-09-25 07:31:04 +08:00
JaguarJack
a3db671328 update:更新服务监控配置至模块内 2020-09-25 07:30:49 +08:00
JaguarJack
33177f26cb update:新增登录日志搜索 2020-09-24 12:19:41 +08:00
JaguarJack
45712076d2 fixed:模块Json文件无法写入 2020-09-23 08:05:31 +08:00
JaguarJack
5979088144 add:新增服务缓存,提高性能 2020-09-22 11:14:51 +08:00
JaguarJack
42e6cd36aa update:优化登录 2020-09-22 11:13:53 +08:00
JaguarJack
08b3e472a9 upate:支持增量权限菜单倒入 2020-09-21 16:14:27 +08:00
JaguarJack
42b99dd64c 更新README 2020-09-21 09:17:25 +08:00
JaguarJack
e412fd3b60 add:新增表单构建器 2020-09-21 09:16:12 +08:00
JaguarJack
4f0c37d281 add:新增用户信息编辑 2020-09-21 08:06:24 +08:00
JaguarJack
bae186d82a fixed:用户请求 2020-09-20 12:05:19 +08:00
JaguarJack
5223997031 update:优化定时任务日志记录 2020-09-20 09:50:48 +08:00
JaguarJack
5fa20a4f28 update:更新初始化密码 2020-09-19 21:17:41 +08:00
JaguarJack
0cd799dce3 update:默认模块排序 2020-09-19 16:10:08 +08:00
JaguarJack
72a878ed30 update:sms初始化关闭 2020-09-19 16:07:54 +08:00
JaguarJack
5f65e3d25f fixed:定时任务不执行 2020-09-19 16:07:32 +08:00
JaguarJack
66ec4f174d fixed:修复验证消息没有按设置提示 2020-09-18 18:53:46 +08:00
JaguarJack
64ab5439a6 升级composer.json 2020-09-17 21:22:23 +08:00
JaguarJack
0558764093 update:readme 2020-09-17 21:22:11 +08:00
JaguarJack
4216a48907 update:更新代码生成 2020-09-17 21:15:24 +08:00
JaguarJack
8b65690450 update:更新删除方法 2020-09-17 21:14:34 +08:00
JaguarJack
4f461bb673 add:新增短信平台管理 2020-09-17 21:14:00 +08:00
JaguarJack
e30de13d35 update:修改指令 2020-09-17 15:17:22 +08:00
JaguarJack
c72943da58 update:更新定时任务配置和初始化数据 2020-09-16 10:14:27 +08:00
JaguarJack
a98fbdc7a1 add:新增定时任务基类 2020-09-16 10:08:05 +08:00
JaguarJack
42ffcb75c7 update:更新whereLike查询 2020-09-16 10:07:34 +08:00
JaguarJack
c74c3c23d4 add:新增监控模块 2020-09-16 10:06:20 +08:00
JaguarJack
5211d29c5e update readme 2020-09-14 10:07:03 +08:00
JaguarJack
82dc1ebd05 update:更新初始化数据 2020-09-13 11:16:16 +08:00
JaguarJack
e35532850d update:更新微信菜单 2020-09-13 11:13:09 +08:00
JaguarJack
0da4627217 update:微信回复 2020-09-13 10:05:22 +08:00
JaguarJack
5fd218d26a update:更新模块管理 2020-09-12 18:35:31 +08:00
JaguarJack
ee624300b6 新增模块管理 2020-09-12 17:22:43 +08:00
JaguarJack
dc4855f5c1 fixed:数据字典分页查询 2020-09-12 11:11:59 +08:00
JaguarJack
9e13a9c937 upadte:优化路由写入 2020-09-11 18:19:06 +08:00
JaguarJack
90990f8782 update:微信模块初始化未安装状态 2020-09-11 07:43:44 +08:00
JaguarJack
40276babfb update:更新安装&新增本地模块安装 2020-09-11 07:42:38 +08:00
JaguarJack
818ffb2ce6 fixed:修复异常code 2020-09-09 11:35:01 +08:00
JaguarJack
763a05fa80 update:优化登录 2020-09-09 10:40:44 +08:00
JaguarJack
8c153cce60 update:转换路径 2020-09-08 19:54:05 +08:00
JaguarJack
93b6f1e2f1 fixed:数据字典分页 2020-09-08 19:36:24 +08:00
JaguarJack
61b9a07d99 update:新增角色标识唯一性 2020-09-08 16:25:36 +08:00
JaguarJack
d75c455bdc update:更新用户部门搜索 2020-09-08 14:36:32 +08:00
JaguarJack
04e2b1ffe5 update:更新项目安装,增加项目domain配置 2020-09-08 14:34:03 +08:00
JaguarJack
14b5b3ce3a update:更新角色初始化数据 2020-09-08 14:31:30 +08:00
JaguarJack
a4e84ffa75 update:更新配置 2020-09-08 14:13:00 +08:00
JaguarJack
bd7f62b9ed add:新增导出用户 2020-09-08 14:12:42 +08:00
JaguarJack
3a2689db18 update:更新部分组件 2020-09-08 14:10:27 +08:00
JaguarJack
3fb55deaaf add:优雅的返回 Json 数据 2020-09-08 10:06:53 +08:00
JaguarJack
b07defb0e9 update 2020-09-07 20:14:03 +08:00
JaguarJack
377b72ae19 update 2020-09-07 19:57:58 +08:00
JaguarJack
dd023caf36 update:readme 2020-09-07 17:37:49 +08:00
JaguarJack
163d1c4bee update:更新部门及以下数据权限 2020-09-07 16:16:25 +08:00
JaguarJack
2c2b7f8723 fixed table 2020-09-07 14:05:36 +08:00
JaguarJack
d533aeaa9e update 2020-09-07 08:29:12 +08:00
JaguarJack
a6cebc3750 update:更新上传获取配置 2020-09-07 07:44:56 +08:00
JaguarJack
214ca68b44 update:wechat 管理 2020-09-06 16:42:29 +08:00
JaguarJack
e712f824f5 update:支持无限级的菜单隐藏 2020-09-06 11:18:12 +08:00
JaguarJack
f301f149fb update:更新获取方法 2020-09-06 10:58:13 +08:00
JaguarJack
96751d6974 update:导出数据 2020-09-05 17:18:31 +08:00
JaguarJack
da9aa45036 update:更新初始化数据 2020-09-05 17:13:50 +08:00
yanwenwu
9ec1285cb9 update:修复导出 2020-09-05 17:12:04 +08:00
JaguarJack
3947ba7386 update数据 2020-09-05 16:34:43 +08:00
JaguarJack
d0a9a41c68 更新到处数据 2020-09-05 16:33:34 +08:00
JaguarJack
7fbee46c73 update 初始化数据 2020-09-05 16:24:00 +08:00
JaguarJack
c8a7d0291c update 2020-09-05 16:01:18 +08:00
JaguarJack
d0044ee019 update 2020-09-04 20:29:38 +08:00
JaguarJack
3466c8ec1f code 更新 2020-09-04 19:28:47 +08:00
JaguarJack
b3be31750a upate 2020-09-04 19:28:30 +08:00
JaguarJack
ca7a3df823 update 2020-09-04 19:01:57 +08:00
JaguarJack
9a5e7010b1 update 2020-09-04 16:21:18 +08:00
JaguarJack
2e67214032 迁移数据 2020-09-04 10:45:18 +08:00
JaguarJack
c5fb6f9409 迁移 2020-09-04 10:09:26 +08:00
JaguarJack
8f73948223 开发者搜索 2020-09-03 19:07:19 +08:00
JaguarJack
2941eeac1e update 2020-09-03 18:55:25 +08:00
JaguarJack
e0007d4150 update:更新搜索 2020-09-02 20:46:30 +08:00
JaguarJack
0e3656c7cc update:更新表结构和模型字段 2020-09-02 11:20:10 +08:00
JaguarJack
44ed0b9788 update:调整部门管理 2020-09-01 07:58:36 +08:00
JaguarJack
1d660ba648 update:更新表结构 2020-08-30 11:31:25 +08:00
JaguarJack
202f7f1dea update:更新表结构 2020-08-30 11:23:10 +08:00
213 changed files with 9391 additions and 1980 deletions

View File

@@ -4,7 +4,10 @@
<p align="center"><code>CatchAdmin</code>是一款基于<a href="http://www.thinkphp.cn/" target="_blank">thinkphp framework</a> <p align="center"><code>CatchAdmin</code>是一款基于<a href="http://www.thinkphp.cn/" target="_blank">thinkphp framework</a>
<a href="https://pro.loacg.com/docs/getting-started">ant degisn pro vue</a>二次开发而成后台管理系统,采用了目前趋势的前后端分离开发模式,后端仅需要提供简洁的 API 数据结构,前端负责呈现数据。目前前端采用数据驱动,大大提高了开发效率。这不仅仅是一个项目,更是后端更新技术栈的一次实践</p> <a href="https://github.com/PanJiaChen/vue-element-admin/">element admin</a>二次开发而成后台管理系统。因为 thinkphp 的简单高效,文档齐全。在看了很多 thinkphp 生态中的后台管理系统,发现没有一款合适的前后端分离系统。遂开发了 CatchAdmin。
完全利用了 thinkphp6 的新版本特性 ServiceProvider将管理系统模块之间的耦合降到了最低限度。每个模块之间都有独立的 controller路由模型数据表`。在开发上尽可能将模块之间的影响降到最低,降低了开发上的难度。基于 CatchAdmin 可以开发 cmsCRMOA 等
等系统。也封装了很多实用的工具,提升开发体验。
</p>
<p align="center"> <p align="center">
<a href="http://doc.catchadmin.com/">文档</a> | <a href="http://doc.catchadmin.com/">文档</a> |
@@ -28,18 +31,62 @@
<img src="https://svg.hamm.cn/badge.svg?key=License&value=Apache-2.0"/> <img src="https://svg.hamm.cn/badge.svg?key=License&value=Apache-2.0"/>
</p > </p >
## AntDV 版本
- 请使用 `v1`分支
## 功能
- [x] `用户管理` 后台用户管理
- [x] `部门管理` 配置公司的部门结构,支持树形结构
- [x] `岗位管理` 配置后台用户的职务
- [x] `菜单管理` 配置系统菜单,按钮等等
- [x] `角色管理` 配置用户担当的角色,分配权限
- [x] `数据字典` 管理后台表结构
- [x] `操作日志` 后台用户操作记录
- [x] `登录日志` 后台系统用户的登录记录
- [x] `代码生成` 生成 API 端的 CURD 操作
- [x] `敏感词` 支持敏感词配置
- [x] `附件管理` 可管理上传的文件
- [x] `定时任务` 可管理定时任务,而不依赖于 Crontab
- [x] `短信平台` 短信云管理,支持 阿里大于腾讯云UcloudSubmail
- [x] `云上传` 支持云上传七牛OSS腾讯
- [ ] `微信管理`
## 项目地址 ## 项目地址
- [github 地址](https://github.com/yanwenwu/catch-admin) - [github 地址](https://github.com/yanwenwu/catch-admin)
- [gitee 地址](https://gitee.com/jaguarjack/catchAdmin) - [gitee 地址](https://gitee.com/jaguarjack/catchAdmin)
- [前端 Vue 项目地址](https://github.com/yanwenwu/catch-admin-vue) - [前端 Vue 项目地址](https://github.com/yanwenwu/catch-admin-vue)
- [文档地址](https://github.com/catch-admin/document)[个人精力实在有限,希望可以小伙伴们可以一起维护文档] - [文档地址](https://github.com/catch-admin/document)[个人精力实在有限,希望可以小伙伴们可以一起维护文档]
## 预览 ## 预览
<p align="center"> <table>
<img src="https://cdn.learnku.com/uploads/images/202005/17/18206/0ECPy72zUZ.png!large"> <tr>
</p> <td><img src="https://s1.ax1x.com/2020/09/07/wucNXq.md.png"></td>
<p align="center"> <td><img src="https://s1.ax1x.com/2020/09/07/wucm6I.md.png"></td>
<img src="https://cdn.learnku.com/uploads/images/202005/17/18206/ngzSU0A9SI.png!large"> </tr>
</p> <tr>
<td><img src="https://s1.ax1x.com/2020/09/07/wucZpd.md.png"></td>
<td><img src="https://s1.ax1x.com/2020/09/07/wuce1A.md.png"></td>
</tr>
<tr>
<td><img src="https://s1.ax1x.com/2020/09/07/wucnXt.md.png"></td>
<td><img src="https://s1.ax1x.com/2020/09/07/wucKnP.md.png"></td>
</tr>
<tr>
<td><img src="https://s1.ax1x.com/2020/09/07/wuc3tg.md.png"></td>
<td><img src="https://s1.ax1x.com/2020/09/07/wucM0f.md.png"></td>
</tr>
<tr>
<td><img src="https://s1.ax1x.com/2020/09/07/wucQ78.md.png"></td>
<td><img src="https://s1.ax1x.com/2020/09/07/wuc1AS.md.png"></td>
</tr>
<tr>
<td><img src="https://s1.ax1x.com/2020/09/07/wuc8hQ.md.png"></td>
<td><img src="https://s1.ax1x.com/2020/09/07/wucY1s.md.png"></td>
</tr>
<tr>
<td><img src="https://s1.ax1x.com/2020/09/07/wucJpj.md.png"></td>
<td><img src="https://s1.ax1x.com/2020/09/07/wuctcn.md.png"></td>
</tr>
</table>
## 环境要求 ## 环境要求
- php7.1+ (需以下扩展) - php7.1+ (需以下扩展)
@@ -63,8 +110,7 @@ curl -sS https://install.phpcomposer.com/installer | php
composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/ composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/
composer install composer install --ignore-platform-reqs
``` ```
- composer 安装 - composer 安装
```shell ```shell
@@ -80,8 +126,8 @@ composer create-project jaguarjack/catchadmin:dev-master
## 体验地址 ## 体验地址
[体验地址](http://vue.catchadmin.com) [体验地址](http://vue.catchadmin.com)
- 账号: admin@gmail.com - 账号: catch@admin.com
- 密码: admin - 密码: catchadmin
[catchadmin 文档地址](http://doc.catchadmin.com) [catchadmin 文档地址](http://doc.catchadmin.com)
@@ -100,19 +146,15 @@ composer create-project jaguarjack/catchadmin:dev-master
### Talking ### Talking
- [论坛讨论](http://bbs.catchadmin.com) - [论坛讨论](http://bbs.catchadmin.com)
- 可以提 `ISSUE`,请按照 `issue` 模板提问 - 可以提 `ISSUE`,请按照 `issue` 模板提问
- 加入 Q 群 `302266230` 讨论以及反馈一些问题。 - 加入 Q 群 `302266230` 前请先 star 项目支持一下, 备注填写用户名 + 平台。例如: JaguarJack Github
- 加群需要付费,所以请使用能支持群费的客户端。(不喜勿喷,过滤一部分不看文档和 TP 框架文档并且衣来伸手饭来张口的用户)
- 不建议你付费入群,认真阅读文档可以解决所有问题
- 更愿意以 `ISSUE` 的方式提问
- 付费入群,群里的各位也是没有义务回答各种各样的基础问题。请 GOOGLE。
### Thanks ### Thanks
- 感谢 [JetBrains](https://www.jetbrains.com) 提供生产力巨高的 `PHPStorm`和`WebStorm`
> 排名部分先后 > 排名部分先后
- [top-think/think](https://github.com/top-think/think) - [top-think/think](https://github.com/top-think/think)
- [ant-design-pro-vue](https://github.com/sendya/ant-design-pro-vue) - [element-admin](https://panjiachen.gitee.io/vue-element-admin-site/zh/)
- [thans/tp-jwt-auth](https://packagist.org/packages/thans/tp-jwt-auth) - [thans/tp-jwt-auth](https://packagist.org/packages/thans/tp-jwt-auth)
- [workerman/workerman](https://github.com/walkor/Workerman)
- [jaguarjack/think-filesystem-cloud](https://github.com/yanwenwu/think-filesystem-cloud) - [jaguarjack/think-filesystem-cloud](https://github.com/yanwenwu/think-filesystem-cloud)
- [overtrue/wechat](https://github.com/overtrue/wechat) - [overtrue/wechat](https://github.com/overtrue/wechat)
- [jaguarjack/migration-generator](https://github.com/yanwenwu/migration-generator) - [jaguarjack/migration-generator](https://github.com/yanwenwu/migration-generator)

View File

@@ -33,7 +33,7 @@ class Request extends \think\Request
$user = $this->auth->guard($guard ? : config('catch.auth.default.guard'))->user(); $user = $this->auth->guard($guard ? : config('catch.auth.default.guard'))->user();
if ($user->status == Users::DISABLE) { if ($user->status == Users::DISABLE) {
throw new LoginFailedException('该用户已被禁用'); throw new LoginFailedException('该用户已被禁用', Code::USER_FORBIDDEN);
} }
} catch (\Exception $e) { } catch (\Exception $e) {
if ($e instanceof TokenExpiredException) { if ($e instanceof TokenExpiredException) {
@@ -45,7 +45,7 @@ class Request extends \think\Request
if ($e instanceof TokenInvalidException) { if ($e instanceof TokenInvalidException) {
throw new FailedException('token 不合法', Code::LOST_LOGIN); throw new FailedException('token 不合法', Code::LOST_LOGIN);
} }
throw new FailedException('认证失败: '. $e->getMessage(), Code::LOST_LOGIN); throw new FailedException('认证失败: '. $e->getMessage(), $e->getCode());
} }
return $user; return $user;

BIN
catch/.DS_Store vendored Normal file

Binary file not shown.

View File

@@ -0,0 +1,53 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~{$year} http://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
namespace catchAdmin\domain;
use catchAdmin\domain\support\contract\DomainActionInterface;
use catchAdmin\domain\support\contract\DomainRecordInterface;
use catchAdmin\domain\support\driver\aliyun\Domain;
use catchAdmin\domain\support\driver\aliyun\DomainRecord;
use catcher\ModuleService;
class DomainService extends ModuleService
{
public function register()
{
parent::register(); // TODO: Change the autogenerated stub
$this->registerInstance();
}
public function loadConfig()
{
return require __DIR__ . DIRECTORY_SEPARATOR . 'config.php';
}
/**
* @return string
*/
public function loadRouteFrom()
{
// TODO: Implement loadRouteFrom() method.
return __DIR__ . DIRECTORY_SEPARATOR . 'route.php';
}
/**
*
*/
protected function registerInstance()
{
$default = config('catch.domains.default');
$this->app->instance(DomainActionInterface::class, $this->app->make(__NAMESPACE__ . '\\support\\driver\\' . $default . '\Domain'));
$this->app->instance(DomainRecordInterface::class, $this->app->make(__NAMESPACE__ . '\\support\\driver\\' . $default . '\DomainRecord'));
}
}

46
catch/domain/README.md Normal file
View File

@@ -0,0 +1,46 @@
## 域名管理
- 阿里云(主支持)
- 腾讯云(需要做适配)
#### 配置
首先在 .env 文件设置
```
[ALIYUN]
ACCESS_KEY=
ACCESS_SECRET=
[QCLOUD]
ACCESS_KEY=
ACCESS_SECRET=
```
也可以在 config.php 文件配置
```
'domains' => [
// 默认阿里云
'default' => 'aliyun',
/**
* 阿里云配置
*
*/
'aliyun' => [
'api_domain' => 'http://alidns.aliyuncs.com',
'access_key' => Env::get('aliyun.access_key', ''),
'access_secret' => Env::get('aliyun.access_secret', ''),
],
/**
* 腾讯云配置
*
*/
'qcloud' => [
'api_domain' => 'cns.api.qcloud.com',
'access_key' => Env::get('qcloud.access_key', ''),
'access_secret' => Env::get('qcloud.access_secret', ''),
]
]
```

43
catch/domain/config.php Normal file
View File

@@ -0,0 +1,43 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2020 http://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
use think\facade\Env;
return [
'domains' => [
// 默认阿里云
'default' => 'aliyun',
/**
* 阿里云配置
*
*/
'aliyun' => [
'api_domain' => 'http://alidns.aliyuncs.com',
'access_key' => Env::get('aliyun.access_key', ''),
'access_secret' => Env::get('aliyun.access_secret', ''),
],
/**
* 腾讯云配置
*
*/
'qcloud' => [
'api_domain' => 'cns.api.qcloud.com',
'access_key' => Env::get('qcloud.access_key', ''),
'access_secret' => Env::get('qcloud.access_secret', ''),
]
]
];

View File

@@ -0,0 +1,50 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2020 http://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
namespace catchAdmin\domain\controller;
use catchAdmin\domain\support\contract\DomainActionInterface;
use catcher\base\CatchRequest as Request;
use catcher\CatchResponse;
use catcher\base\CatchController;
class Domain extends CatchController
{
protected $domain;
public function __construct(DomainActionInterface $domain)
{
$this->domain = $domain;
}
/**
* 列表
*
* @time 2020/09/11 18:14
* @param Request $request
* @return \think\Response
*/
public function index(Request $request): \think\Response
{
return CatchResponse::paginate($this->domain->getList($request->param()));
}
/**
* 读取
*
* @time 2020/09/11 18:14
* @param $name
* @return \think\Response
*/
public function read($name)
{
return CatchResponse::success($this->domain->read(str_replace('-', '.', $name)));
}
}

View File

@@ -0,0 +1,99 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2020 http://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
namespace catchAdmin\domain\controller;
use catchAdmin\domain\support\contract\DomainRecordInterface;
use catcher\base\CatchRequest as Request;
use catcher\CatchResponse;
use catcher\base\CatchController;
class DomainRecord extends CatchController
{
protected $domainRecord;
public function __construct(DomainRecordInterface $record)
{
$this->domainRecord = $record;
}
/**
* 列表
*
* @time 2020/09/11 18:14
* @param Request $request
* @return \think\Response
*/
public function index(Request $request): \think\Response
{
return CatchResponse::paginate($this->domainRecord->getList($request->param()));
}
/**
* 保存
*
* @time 2020/09/11 18:14
* @param Request Request
* @return \think\Response
*/
public function save(Request $request): \think\Response
{
return CatchResponse::success($this->domainRecord->store($request->post()));
}
/**
* 读取
*
* @time 2020/09/11 18:14
* @param $name
* @return \think\Response
*/
public function read($name): \think\Response
{
return CatchResponse::success($this->domainRecord->read($name));
}
/**
* 更新
*
* @time 2020/09/11 18:14
* @param Request $request
* @param $id
* @return \think\Response
*/
public function update($id, Request $request): \think\Response
{
return CatchResponse::success($this->domainRecord->update($id, $request->post()));
}
/**
* 删除
*
* @time 2020/09/11 18:14
* @param $id
* @return \think\Response
*/
public function delete($id): \think\Response
{
return CatchResponse::success($this->domainRecord->delete($id));
}
/**
* 设置状态
*
* @param $id
* @param $status
* @return \think\response\Json
*/
public function enable($id, $status)
{
return CatchResponse::success($this->domainRecord->enable($id, $status));
}
}

View File

@@ -0,0 +1,97 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~{$year} http://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
use think\migration\Seeder;
class DomainMenusSeed extends Seeder
{
/**
* Run Method.
*
* Write your database seeder using this method.
*
* More information on writing seeders is available here:
* http://docs.phinx.org/en/latest/seeding.html
*/
public function run()
{
\catcher\Utils::importTreeData($this->getPermissions(), 'permissions', 'parent_id');
}
protected function getPermissions()
{
return array (
0 =>
array (
'id' => 72,
'permission_name' => '域名管理',
'parent_id' => 0,
'level' => '',
'route' => '/domain',
'icon' => 'el-icon-stopwatch',
'module' => 'domain',
'creator_id' => 1,
'permission_mark' => 'domain',
'component' => 'layout',
'redirect' => '/domain/index',
'keepalive' => 1,
'type' => 1,
'hidden' => 1,
'sort' => 1,
'created_at' => 1601105834,
'updated_at' => 1601105834,
'deleted_at' => 0,
),
1 =>
array (
'id' => 73,
'permission_name' => '域名设置',
'parent_id' => 72,
'level' => '72',
'route' => '/domain/index',
'icon' => 'el-icon-setting',
'module' => 'domain',
'creator_id' => 1,
'permission_mark' => 'domain',
'component' => 'domain',
'redirect' => '',
'keepalive' => 1,
'type' => 1,
'hidden' => 1,
'sort' => 8,
'created_at' => 1601105879,
'updated_at' => 1601112604,
'deleted_at' => 0,
),
2 =>
array (
'id' => 84,
'permission_name' => '域名记录',
'parent_id' => 72,
'level' => '72',
'route' => '/domain/record/:domain',
'icon' => 'el-icon-document',
'module' => 'domain',
'creator_id' => 1,
'permission_mark' => 'domainRecord',
'component' => 'domainRecord',
'redirect' => '',
'keepalive' => 1,
'type' => 1,
'hidden' => 2,
'sort' => 1,
'created_at' => 1601112569,
'updated_at' => 1601112606,
'deleted_at' => 0,
),
);
}
}

15
catch/domain/module.json Normal file
View File

@@ -0,0 +1,15 @@
{
"name": "域名管理",
"alias": "domain",
"description": "域名,阿里云,腾讯云",
"version": "1.0.0",
"keywords": [],
"order": 0,
"services": [
"\\catchAdmin\\domain\\DomainService"
],
"aliases": {},
"files": [],
"requires": [],
"enable": false
}

23
catch/domain/route.php Normal file
View File

@@ -0,0 +1,23 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~{$year} http://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
// you should use `$router`
use catchAdmin\domain\controller\DomainRecord;
$router->group(function () use ($router){
// 域名管理
$router->get('domain', '\catchAdmin\domain\controller\Domain@index');
$router->get('domain/<name>', '\catchAdmin\domain\controller\Domain@read');
// 域名解析管理
$router->resource('record/domain', DomainRecord::class);
$router->put('record/domain/<id>/<status>', '\catchAdmin\domain\controller\DomainRecord@enable');
})->middleware('auth');

View File

@@ -0,0 +1,70 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2020 http://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
namespace catchAdmin\domain\support;
use catchAdmin\domain\support\signature\Aliyun;
use catchAdmin\domain\support\signature\Qcloud;
/**
* 公共参数
*
* Class CommonParams
* @package catchAdmin\domain\support
*/
class CommonParams
{
/**
* 阿里云公共参数
*
* @param array $params
* @param string $method
* @return array
*/
public static function aliyun(array $params, $method = 'GET')
{
date_default_timezone_set('UTC');
$params = array_merge($params, [
'Format' => 'json',
'Version' => '2015-01-09',
'AccessKeyId' => config('catch.domains.aliyun.access_key'),
'SignatureMethod' => 'HMAC-SHA1',
'Timestamp' => date('Y-m-d\TH:i:s\Z'),
'SignatureVersion' => '1.0',
'SignatureNonce' => uniqid()
]);
$params['Signature'] = (new Aliyun($params))->signature($method);
return $params;
}
/**
* 腾讯云公共参数
*
* @param array $params
* @param string $method
* @return array
*/
public static function qcloud(array $params, $method = 'GET')
{
$params = array_merge($params, [
'SecretId' => config('catch.domains.qcloud.access_key'),
'SignatureMethod' => 'HmacSHA1',
'Timestamp' => time(),
'Nonce' => uniqid()
]);
$params['Signature'] = (new Qcloud($params))->signature($method);
return $params;
}
}

View File

@@ -0,0 +1,112 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2020 http://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
namespace catchAdmin\domain\support;
use think\Paginator;
class Transformer
{
/**
* 分页展示
*
* @param array $data
* @return mixed
*/
public static function aliyunDomainPaginate(array $data)
{
$list = [];
foreach ($data['Domains']['Domain'] as $item) {
$list[] = [
'name' => $item['DomainName'],
'created_at' => date('Y-m-d', $item['CreateTimestamp']/1000),
'dns_server' => $item['DnsServers']['DnsServer'],
'from' => $item['VersionName'],
'free' => $item['VersionCode'] === 'mianfei',
'record_count' => $item['RecordCount'],
'tags' => $item['Tags']['Tag'],
'id' => $item['DomainId']
];
}
return Paginator::make($list, $data['PageSize'], $data['PageNumber'], $data['TotalCount']);
}
/**
* 腾讯云域名列表
*
* @param array $data
* @param $page
* @param $limit
* @return Paginator|\think\paginator\driver\Bootstrap
*/
public static function qcloudDomainPaginate(array $data, $page, $limit)
{
$info = $data['data']['info'];
$domains = $data['data']['domains'];
$list = [];
foreach ($domains as $item) {
$list[] = [
'name' => $item['name'],
'created_at' => $item['created_on'],
'dns_server' => [],
'from' => 'qcloud',
'free' => $item['grade'] === 'DP_Free',
'record_count' => $item['records'],
'tags' => [],
'id' => $item['id']
];
}
return Paginator::make($list, $limit, $page + 1,$info['domain_total']);
}
/**
* 阿里云域名解析
*
* @param array $data
* @return mixed
*/
public static function aliyunDomainRecordPaginate(array $data)
{
$list = [];
foreach ($data['DomainRecords']['Record'] as &$item) {
$list[] = array_change_key_case($item);
}
return Paginator::make($list, $data['PageSize'], $data['PageNumber'], $data['TotalCount']);
}
/**
* DNS 记录
*
* @param array $data
* @param $page
* @param $limit
* @return Paginator|\think\paginator\driver\Bootstrap
*/
public static function qcloudDomainRecordPaginate(array $data, $page, $limit)
{
$list = [];
foreach ($data['data']['records'] as &$item) {
$item['status'] = $item['status'] === 'enabled' ? 'ENABLE' : 'DISABLE';
$item['rr'] = $item['name'];
$item['recordid'] = $item['id'];
$list[] = array_change_key_case($item);
}
return Paginator::make($list, $limit, $page + 1, $data['data']['info']['record_total']);
}
}

View File

@@ -0,0 +1,22 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2020 http://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
namespace catchAdmin\domain\support\contract;
interface DomainActionInterface
{
public function getList(array $params);
public function store(array $params);
public function delete(array $params);
public function read($name);
}

View File

@@ -0,0 +1,27 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2020 http://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
namespace catchAdmin\domain\support\contract;
interface DomainRecordInterface
{
public function getList(array $params);
public function store(array $params);
public function delete($recordId);
public function read(array $params);
public function update($recordId, array $params);
public function enable($recordId, $status);
}

View File

@@ -0,0 +1,32 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2020 http://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
namespace catchAdmin\domain\support\driver;
use catcher\facade\Http;
use catchAdmin\domain\support\CommonParams;
trait ApiTrait
{
public function get(array $params)
{
$name = config('catch.domains.default');
$apiDomain = config('catch.domains.' . $name . '.api_domain');
if (strpos($apiDomain, 'https') === false &&
strpos($apiDomain, 'http') === false) {
$apiDomain = 'https://' . $apiDomain . '/v2/index.php';
}
return Http::ignoreSsl()->query(CommonParams::{$name}($params))
->get($apiDomain)->json();
}
}

View File

@@ -0,0 +1,55 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2020 http://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
namespace catchAdmin\domain\support\driver\aliyun;
use catchAdmin\domain\support\contract\DomainActionInterface;
use catchAdmin\domain\support\driver\ApiTrait;
use catchAdmin\domain\support\Transformer;
class Domain implements DomainActionInterface
{
use ApiTrait;
public function getList(array $params)
{
// TODO: Implement getList() method.
return Transformer::aliyunDomainPaginate($this->get([
'Action' => 'DescribeDomains',
'StarMark' => true,
'SearchModel' => 'LIKE',
'PageNumber' => $params['page'] ?? 1,
'PageSize' => $params['limit'] ?? 20,
]));
}
public function store(array $params)
{
// TODO: Implement add() method.
}
public function delete(array $params)
{
// TODO: Implement delete() method.
return $this->get([
'Action' => 'DeleteDomain',
'DomainName' => $params['name'],
]);
}
public function read($name)
{
// TODO: Implement info() method.
return $this->get([
'Action' => 'DescribeDomainInfo',
'DomainName' => $name
]);
}
}

View File

@@ -0,0 +1,147 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2020 http://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
namespace catchAdmin\domain\support\driver\aliyun;
use catchAdmin\domain\support\contract\DomainRecordInterface;
use catchAdmin\domain\support\driver\ApiTrait;
use catchAdmin\domain\support\Transformer;
class DomainRecord implements DomainRecordInterface
{
use ApiTrait;
/**
* 列表
*
* @param array $params
* @return mixed
*/
public function getList(array $params)
{
$data = [
'Action' => 'DescribeDomainRecords',
'DomainName' => $params['name'],
'PageNumber' => $params['page'] ?? 1,
'PageSize' => $params['limit'] ?? 20,
];
if ($params['rr']) {
$data['RRKeyWord'] = $params['rr'];
}
if ($params['type']) {
$data['TypeKeyWord'] = $params['type'];
}
if ($params['value']) {
$data['ValueKeyWord'] = $params['value'];
}
if ($params['line']) {
$data['Line'] = $params['line'];
}
if ($params['status']) {
$data['Status'] = $params['status'];
}
// TODO: Implement getList() method.
return Transformer::aliyunDomainRecordPaginate($this->get($data));
}
/**
* 新增解析
*
* @param array $params
* @return array
*
*/
public function store(array $params)
{
// TODO: Implement add() method.
return $this->get([
'Action' => 'AddDomainRecord',
'DomainName' => $params['name'],
'RR' => $params['rr'],
'Type' => $params['type'],
'Value' => $params['value'],
'Line' => $params['line'],
'TTL' => $params['ttl'],
]);
}
/**
* 删除解析
*
* @param $recordId
* @return array
*/
public function delete($recordId)
{
// TODO: Implement delete() method.
return $this->get([
'Action' => 'DeleteDomainRecord',
'RecordId' => $recordId
]);
}
/**
* 获取解析记录
*
* @param array $params
* @return array
*/
public function read(array $params)
{
// TODO: Implement info() method.
return $this->get([
'Action' => 'DescribeDomainRecord',
'RecordId' => $params['record_id'],
]);
}
/**
* 更新解析
*
* @param array $params
* @param $recordId
* @return array
*/
public function update($recordId, array $params)
{
// TODO: Implement update() method.
return $this->get([
'Action' => 'UpdateDomainRecord',
'RecordId' => $recordId,
'RR' => $params['rr'],
'Type' => $params['type'],
'Value' => $params['value'],
'Line' => $params['line'],
'TTL' => $params['ttl'],
]);
}
/**
* 设置状态
*
* @param $recordId
* @param $status
* @return array
*/
public function enable($recordId, $status)
{
return $this->get([
'Action' => 'SetDomainRecordStatus',
'RecordId' => $recordId,
'Status' => ucfirst(strtolower($status))
]);
}
}

View File

@@ -0,0 +1,56 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2020 http://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
namespace catchAdmin\domain\support\driver\qcloud;
use catchAdmin\domain\support\contract\DomainActionInterface;
use catchAdmin\domain\support\driver\ApiTrait;
use catchAdmin\domain\support\Transformer;
class Domain implements DomainActionInterface
{
use ApiTrait;
public function getList(array $params)
{
$offset = ($params['page'] ?? 1) - 1;
$length = $params['limit'] ?? 10;
// TODO: Implement getList() method.
return Transformer::qcloudDomainPaginate($this->get([
'Action' => 'DomainList',
'offset' => $offset,
'length' => $length
]), $offset, $length);
}
public function store(array $params)
{
// TODO: Implement add() method.
}
public function delete(array $params)
{
// TODO: Implement delete() method.
return $this->get([
'Action' => 'DeleteDomain',
'DomainName' => $params['name'],
]);
}
public function read($name)
{
// TODO: Implement info() method.
return $this->get([
'Action' => 'DescribeDomainInfo',
'DomainName' => $name
]);
}
}

View File

@@ -0,0 +1,125 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2020 http://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
namespace catchAdmin\domain\support\driver\qcloud;
use catchAdmin\domain\support\contract\DomainRecordInterface;
use catchAdmin\domain\support\driver\ApiTrait;
use catchAdmin\domain\support\Transformer;
class DomainRecord implements DomainRecordInterface
{
use ApiTrait;
/**
* 列表
*
* @param array $params
* @return mixed
*/
public function getList(array $params)
{
$data = [
'Action' => 'RecordList',
'domain' => $params['name'],
'offset' => ($params['page'] ?? 1) - 1,
'length' => $params['limit'] ?? 10,
];
if ($params['rr']) {
$data['subDomain'] = $params['rr'];
}
if ($params['type']) {
$data['recordType'] = $params['type'];
}
// TODO: Implement getList() method.
return Transformer::qcloudDomainRecordPaginate($this->get($data), $data['offset'], $data['length']);
}
/**
* 新增解析
*
* @param array $params
* @return array
*
*/
public function store(array $params)
{
// TODO: Implement add() method.
return $this->get([
'Action' => 'RecordCreate',
'domain' => $params['name'],
'subDomain' => $params['rr'],
'recordType' => $params['type'],
'value' => $params['value'],
'recordLine' => $params['line'],
'ttl' => $params['ttl'],
]);
}
/**
* 删除解析
*
* @param $recordId
* @return array
*/
public function delete($recordId)
{
// TODO: Implement delete() method.
return $this->get([
'Action' => 'RecordDelete',
'recordId' => $recordId
]);
}
/**
* 更新解析
*
* @param array $params
* @param $recordId
* @return array
*/
public function update($recordId, array $params)
{
// TODO: Implement update() method.
return $this->get([
'Action' => 'RecordModify',
'recordId' => $recordId,
'subDomain' => $params['rr'],
'recordType' => $params['type'],
'value' => $params['value'],
'recordLine' => $params['line'],
'ttl' => $params['ttl'],
]);
}
/**
* 设置状态
*
* @param $recordId
* @param $status
* @return array
*/
public function enable($recordId, $status)
{
return $this->get([
'Action' => 'RecordStatus',
'recordId' => $recordId,
'Status' => strtolower($status)
]);
}
public function read(array $params)
{
// TODO: Implement read() method.
}
}

View File

@@ -0,0 +1,64 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2020 http://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
namespace catchAdmin\domain\support\signature;
class Aliyun
{
/**
* @var array
*/
protected $params;
/**
* Aliyun constructor.
* @param $params
*/
public function __construct(array $params)
{
$this->params = $params;
}
/**
* encode
*
* @time 2020年09月25日
* @param $str
* @return string|string[]|null
*/
protected function percentEncode(string $str)
{
return preg_replace(['/\+/', '/\*/', '/%7E/'], ['%20', '%2A', '~'], urlencode($str));
}
/**
* 签名
*
* @time 2020年09月25日
* @param $method
* @return string
*/
public function signature(string $method)
{
ksort($this->params);
$queryString = '';
foreach ($this->params as $key => $param) {
$queryString .= '&' . $this->percentEncode($key) . '=' . $this->percentEncode($param);
}
$signString = $method . '&' .
$this->percentEncode('/') . '&' .
$this->percentEncode(substr($queryString, 1));
return base64_encode(hash_hmac('sha1', $signString, config('catch.domains.aliyun.access_secret'). '&', true));
}
}

View File

@@ -0,0 +1,63 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~{$year} http://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
namespace catchAdmin\domain\support\signature;
class Qcloud
{
/**
* @var array
*/
protected $params;
/**
* Qcloud constructor.
* @param $params
*/
public function __construct(array $params)
{
$this->params = $params;
}
/**
* key 替换
*
* @param $key
* @return mixed|string|string[]
*/
protected function replaceKey($key)
{
return strpos($key, '_') === false ?
$key : str_replace('_', '.', $key);
}
/**
* 签名
*
* @time 2020年09月25日
* @param $method
* @return string
*/
public function signature(string $method)
{
ksort($this->params);
$queryString = '';
foreach ($this->params as $key => $param) {
$queryString .= '&' . $this->replaceKey($key) . '=' . $param;
}
$signString = $method . config('catch.domains.qcloud.api_domain') . '/v2/index.php?'
. substr($queryString, 1);
return base64_encode(hash_hmac('sha1', $signString, config('catch.domains.qcloud.access_secret'), true));
}
}

View File

@@ -11,15 +11,13 @@ class LoginLogEvent
{ {
$agent = request()->header('user-agent'); $agent = request()->header('user-agent');
$username = Users::where('email', $params['email'])->value('username');
app(LoginLog::class)->storeBy([ app(LoginLog::class)->storeBy([
'login_name' => $username ? : $params['email'], 'login_name' => $params['login_name'],
'login_ip' => request()->ip(), 'login_ip' => request()->ip(),
'browser' => $this->getBrowser($agent), 'browser' => $this->getBrowser($agent),
'os' => $this->getOs($agent), 'os' => $this->getOs($agent),
'login_at' => time(), 'login_at' => time(),
'status' => $params['success'] ? 1 : 2, 'status' => $params['success'],
]); ]);
} }

View File

@@ -6,52 +6,105 @@ use catchAdmin\permissions\model\Users;
use catcher\base\CatchController; use catcher\base\CatchController;
use catcher\CatchAuth; use catcher\CatchAuth;
use catcher\CatchResponse; use catcher\CatchResponse;
use catcher\Code;
use catcher\exceptions\LoginFailedException; use catcher\exceptions\LoginFailedException;
use thans\jwt\facade\JWTAuth; use thans\jwt\facade\JWTAuth;
class Index extends CatchController class Index extends CatchController
{ {
/** /**
* 登陆 * 登陆
* *
* @time 2019年11月28日 * @time 2019年11月28日
* @param LoginRequest $request * @param LoginRequest $request
* @param CatchAuth $auth * @param CatchAuth $auth
* @return bool|string * @return bool|string
*/ */
public function login(LoginRequest $request, CatchAuth $auth) public function login(LoginRequest $request, CatchAuth $auth)
{ {
$params = $request->param(); $condition = $request->param();
$token = $auth->attempt($params); try {
$token = $auth->attempt($condition);
$user = $auth->user(); $user = $auth->user();
if ($user->status == Users::DISABLE) { $this->afterLoginSuccess($user, $token);
throw new LoginFailedException('该用户已被禁用'); // 登录事件
$this->loginEvent($user->username);
return CatchResponse::success([
'token' => $token,
], '登录成功');
} catch (\Exception $exception) {
$this->detailWithLoginFailed($exception, $condition);
$code = $exception->getCode();
return CatchResponse::fail($code == Code::USER_FORBIDDEN ?
'该账户已被禁用,请联系管理员' : '登录失败,请检查邮箱和密码', Code::LOGIN_FAILED);
} }
// 记录用户登录
$user->last_login_ip = request()->ip();
$user->last_login_time = time();
$user->save();
// 登录事件
$params['success'] = $token;
event('loginLog', $params);
return $token ? CatchResponse::success([
'token' => $token,
], '登录成功') : CatchResponse::success('', '登录失败');
} }
/** /**
* 登出 * 处理登录失败
* *
* @time 2019年11月28 * @time 2020年10月26
* @return \think\response\Json * @param $exception
*/ * @param $condition
* @return void
*/
protected function detailWithLoginFailed($exception, $condition)
{
$message = $exception->getMessage();
if (strpos($message, '|') !== false) {
$username = explode('|', $message)[1];
} else {
$username = $condition['email'];
}
$this->loginEvent($username, false);
}
/**
* 用户登录成功后
*
* @time 2020年09月09日
* @param $user
* @param $token
* @return void
*/
protected function afterLoginSuccess($user, $token)
{
$user->last_login_ip = request()->ip();
$user->last_login_time = time();
if ($user->hasField('remember_token')) {
$user->remember_token = $token;
}
$user->save();
}
/**
* 登录事件
*
* @time 2020年09月09日
* @param $name
* @param bool $success
* @return void
*/
protected function loginEvent($name, $success = true)
{
$params['login_name'] = $name;
$params['success'] = $success ? 1 : 2;
event('loginLog', $params);
}
/**
* 登出
*
* @time 2019年11月28日
* @return \think\response\Json
*/
public function logout(): \think\response\Json public function logout(): \think\response\Json
{ {
return CatchResponse::success(); return CatchResponse::success();

View File

@@ -4,7 +4,7 @@
"description": "login 模块", "description": "login 模块",
"version": "1.0.0", "version": "1.0.0",
"keywords": [], "keywords": [],
"order": 1, "order": 100,
"services": [ "services": [
"\\catchAdmin\\login\\LoginService" "\\catchAdmin\\login\\LoginService"
], ],

View File

@@ -0,0 +1,34 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~{$year} http://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
namespace catchAdmin\monitor;
use catcher\ModuleService;
class MonitorService extends ModuleService
{
protected function loadConfig()
{
return require __DIR__ . DIRECTORY_SEPARATOR . 'config.php';
}
public function loadRouteFrom()
{
// TODO: Implement loadRouteFrom() method.
return __DIR__ . DIRECTORY_SEPARATOR . 'route.php';
}
public function loadCommands()
{
return [__NAMESPACE__, __DIR__ . DIRECTORY_SEPARATOR . 'command'];
}
}

View File

@@ -0,0 +1,175 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~{$year} http://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
declare (strict_types = 1);
namespace catchAdmin\monitor\command;
use catchAdmin\monitor\command\process\Master;
use catchAdmin\monitor\command\process\Process;
use catcher\facade\FileSystem;
use think\console\Command;
use think\console\Input;
use think\console\input\Argument;
use think\console\input\Option;
use think\console\Output;
use think\console\Table;
class CatchCrontabCommand extends Command
{
protected $pid;
protected function configure()
{
// 指令配置
$this->setName('catch:crontab')
->addArgument('action', Argument::OPTIONAL, '[start|reload|stop|restart]', 'start')
->addOption('daemon', '-d', Option::VALUE_NONE, 'daemon mode')
->addOption('pid', '-p', Option::VALUE_REQUIRED, 'you can send signal to the process of pid')
->addOption('static', '-s', Option::VALUE_REQUIRED, 'default static process number', 1)
->addOption('dynamic', '-dy', Option::VALUE_REQUIRED, 'default dynamic process number', 10)
->addOption('interval', '-i', Option::VALUE_REQUIRED, 'interval/seconds', 5)
->setDescription('start catch crontab schedule');
}
protected function execute(Input $input, Output $output)
{
if (!$input->hasOption('pid')) {
$this->pid = Master::getMasterPid();
} else {
$this->pid = $input->getOption('pid');
}
if (!extension_loaded('pcntl') || !extension_loaded('posix')) {
$output->error('you should install extension [pcntl && posix]');
} else {
$this->{$input->getArgument('action')}();
}
}
/**
* 进程启动
*
* @time 2020年09月14日
* @return void
*/
protected function start()
{
$worker = new Master();
$worker->staticNumber($this->input->getOption('static'))
->dynamic($this->input->getOption('dynamic'))
->interval($this->input->getOption('interval'))
->asDaemon($this->input->hasOption('daemon'))
->run();
}
/**
* 停止任务
*
* @time 2020年07月07日
* @return void
*/
protected function stop()
{
$retryTimes = 0;
if (Process::isAlive($this->pid)) {
$this->output->info('🔨 catch crontab is running.');
Process::kill($this->pid, SIGTERM);
// 睡眠 1 秒
$this->output->info('⌛️ killing catch crontab service, please waiting...');
sleep(1);
if (!Process::isAlive($this->pid)) {
$this->output->info('🎉 catch crontab stopped!');
} else {
while (true) {
Process::kill($this->pid, SIGKILL);
if (Process::isAlive($this->pid)) {
$retryTimes++;
$this->output->info('🔥 retry $retryTimes times');
usleep(500 * 1000);
if ($retryTimes >= 3) {
$this->output->info('💔 catch crontab is running, stop failed, please use [kill -9 {$this->pid}] to Stop it');
break;
}
} else {
$this->output->info('🎉 catch crontab stopped!');
break;
}
}
}
Master::exitMasterDo();
} else {
$this->output->error('🤔️ catch crontab is not running, Please Check it!');
}
$this->output->info('🎉 stop catch crontab successfully');
}
/**
* 重启任务
*
* @time 2020年07月07日
* @return void
*/
protected function reload()
{
Process::kill($this->pid, SIGUSR1);
}
/**
* 重启
*
* @time 2020年07月07日
* @return void
*/
protected function restart()
{
$this->stop();
$this->output->info('catch crontab restarting...');
usleep(500 * 1000);
$this->start();
}
/**
* status
*
* @time 2020年07月22日
* @return void
*/
protected function status()
{
if ($this->pid) {
if (Process::isAlive($this->pid)) {
Process::kill($this->pid, SIGUSR2);
usleep(100000);
$worker = new Master;
$table = new Table;
$table->setHeader(['PID', '名称', '内存', '处理任务', '开始时间', '运行时间', '状态'], Table::ALIGN_CENTER);
$table->setRows($worker->getWorkerStatus(), Table::ALIGN_CENTER);
$this->output->info($table->render());
} else {
$this->output->error('🤔️ catch crontab is not running, Please Check it!');
}
} else {
$this->output->error('🤔️ catch crontab is not running, Please Check it!');
}
}
}

View File

@@ -0,0 +1,127 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~{$year} http://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace catchAdmin\monitor\command;
use catchAdmin\monitor\command\process\Process;
use catchAdmin\monitor\model\Crontab;
use catchAdmin\monitor\model\CrontabLog;
use Cron\CronExpression;
use think\console\Command;
use think\console\Input;
use think\console\Output;
use think\facade\Log;
class ScheduleCommand extends Command
{
protected $pid;
protected function configure()
{
// 指令配置
$this->setName('catch:schedule')
->setDescription('catch schedule');
}
protected function execute(Input $input, Output $output)
{
try {
foreach ($this->getExecuteAbleCommands() as $command) {
$process = new Process(function (Process $process) use ($command) {
$this->executeCommand($command);
$process->exit();
});
$process->start();
}
} catch (\Exception $e) {
Log::error('CatchSchedule Error:' . $e->getMessage());
}
}
/**
* 执行 command
*
* @time 2021年01月18日
* @param $command
* @return void
*/
protected function executeCommand($command)
{
$start = time();
$errorMessage = '';
try {
$this->getConsole()->call($command->task);
} catch (\Exception $e) {
$errorMessage = $e->getMessage();
}
$end = time();
// 插入 crontab 执行日志
CrontabLog::insert([
'crontab_id' => $command->id,
'used_time' => $end - $start,
'status' => $errorMessage ? CrontabLog::FAILED : CrontabLog::SUCCESS,
'error_message' => $errorMessage,
'created_at' => time(),
'updated_at' => time(),
]);
}
/**
* 获取可执行任务
*
* @time 2021年01月17日
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @return array
*/
protected function getExecuteAbleCommands()
{
$executeAbleCommands = [];
Crontab::where('status', Crontab::ENABLE)
->where('tactics', '<>', Crontab::EXECUTE_FORBIDDEN)
->select()
->each(function ($command) use (&$executeAbleCommands){
if ($command->tactics == Crontab::EXECUTE_IMMEDIATELY) {
$executeAbleCommands[] = $command;
return true;
}
$can = date('Y-m-d H:i', CronExpression::factory(trim($command->cron))
->getNextRunDate(date('Y-m-d H:i:s'), 0, true)
->getTimestamp()) == date('Y-m-d H:i', time());
if ($can) {
// 如果任务只执行一次 之后禁用该任务
if ($command->tactics === Crontab::EXECUTE_ONCE) {
Crontab::where('id', $command->id)->update([
'status' => Crontab::DISABLE,
]);
}
$executeAbleCommands[] = $command;
}
return true;
});
return $executeAbleCommands;
}
}

View File

@@ -0,0 +1,145 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~{$year} http://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
namespace catchAdmin\monitor\command\process;
use catcher\base\CatchCronTask;
trait Attributes
{
/**
* 是否以守护进程方式运行
*
* @var bool
*/
protected $daemon = false;
/**
* 静态进程数量
*
* @var int
*/
protected $static;
/**
* 动态进程数量
*
* @var int
*/
protected $dynamic;
/**
* 定时器触发时间
*
* @var int
*/
protected $interval;
/**
* set name
*
* @var
*/
protected $name = 'catch-crontab';
/**
* @var string
*/
protected $crontabQueueName = 'catch-crontab-task';
/**
* 安全退出
*
* @var bool
*/
protected $exitSafely = false;
/**
* 设置守护进程
*
* @time 2020年07月21日
* @param bool $daemon
* @return $this
*/
public function asDaemon($daemon = false)
{
$this->daemon = $daemon;
return $this;
}
public function staticNumber($n)
{
$this->static = $n;
return $this;
}
/**
* 可扩容
*
* @time 2020年07月21日
* @param $n
* @return $this
*/
public function dynamic($n)
{
$this->dynamic = $n;
return $this;
}
/**
* 定时
*
* @time 2020年07月21日
* @param $n
* @return $this
*/
public function interval($n)
{
$this->interval = $n;
return $this;
}
/**
* 设置 name
*
* @time 2020年07月23日
* @param $name
* @return $this
*/
public function name($name)
{
$this->name = $name;
return $this;
}
/**
* 设置报告错误
*
* @time 2020年07月24日
* @return void
*/
public function displayErrors()
{
ini_set('display_errors', 1);
error_reporting(E_ALL & ~E_WARNING);
ini_set('display_startup_errors', 1);
ini_set('ignore_repeated_errors', 1);
}
}

View File

@@ -0,0 +1,361 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~{$year} http://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
namespace catchAdmin\monitor\command\process;
use Exception;
use catcher\facade\Filesystem;
use think\cache\driver\Redis;
use think\facade\Cache;
/**
*
* - 以后台形式工作 daemon
* - 分静态进程和动态扩容进程
* - 信号处理机制
* - 重启工作进程
* - 重启服务
* - 定时器 扩容工作进程
* - 关闭进程
* - 统计信息
* - 是否拉起进程,工作进程销毁后是否继续主进程保留
* - Fatal Error 处理
* - Exception 处理
* - 发生内存泄漏如何处理
* - 错误输出到哪里
* - 提供基础面板查看
* - Log 文件的记录
*
* @time 2020年07月29日
*/
class Master
{
use RegisterSignal, Attributes, Store, ParseTask;
/**
* 保存子进程 PID
*
* @var array
*/
protected $workerIds = [];
/**
* 开始时间
*
* @var
*/
public $start_at;
/**
* @var
*/
public $worker_start_at;
/**
* 保存当前工作进程的数量
*
* @var
*/
protected $allWorkersCount;
/**
* 保存当前重定向输出文件
*
* @var string
*/
protected static $stdout;
/**
* 任务对象
*
* @var
*/
protected $taskService;
/**
* 处理的任务数量
*
* @var int
*/
protected $dealNum = 0;
/**
* busy waiting
*
* @var
*/
protected $status = 'waiting';
/**
* @var
*/
protected $redis;
/**
* 启动
*
* @time 2020年07月21日
* @return void
*/
public function run()
{
try {
if ($this->daemon) {
Process::daemon();
}
if ($this->interval) {
Process::alarm($this->interval);
}
$this->init();
// 初始化进程池
$this->initWorkers();
// 设置进程名称
Process::setWorkerName($this->name . ' master');
// 注册信号
$this->registerSignal();
// 写入进程状态
$this->setWorkerStatus($this->name . ' master');
// 信号发送
while (true) {
Process::dispatch();
$pid = pcntl_waitpid(-1, $status, WNOHANG);
Process::dispatch();
if ($pid > 0) {
if (isset($this->workerIds[$pid])) {
unset($this->workerIds[$pid]);
$this->deleteWorkerStatusFile($pid);
$this->worker_start_at = time();
// 如果进程挂掉,正常退出码都是 0当然这里可以自己定义看 exit($status) 设置什么
// 真实的 exit code pcntl_wexitstatus 函数获取
// exit code > 0 都是由于异常导致的
$exitCode = pcntl_wexitstatus($status);
if (!in_array($exitCode, [255, 250])) {
$this->forkStatic();
}
}
// 如果静态工作进程全部退出,会发生 CPU 空转,所以这里需要 sleep 1
if (!count($this->workerIds)) {
// sleep(1);
self::exitMasterDo();
exit(0);
}
}
usleep(500 * 1000);
}
} catch (\Throwable $exception) {
// todo
echo sprintf('[%s]: ', date('Y-m-d H:i:s')) . $exception->getMessage();
}
}
/**
* 初始化
* @throws Exception
*/
protected function init()
{
$this->displayErrors();
$this->start_at = $this->worker_start_at = time();
// 记录 masterID
FileSystem::put(self::masterPidStorePath(), posix_getpid());
// 保存信息
$this->saveTaskInfo();
// 初始化进程数量
$this->allWorkersCount = $this->static;
// 显示UI
$this->display();
// 重定向
$this->dup();
}
/**
* 初始化进程池
*
* @time 2020年07月21日
* @return void
*/
protected function initWorkers()
{
$this->redis = $this->getRedisHandle();
for ($i = 0; $i < $this->static; $i++) {
$this->forkStatic();
}
}
/**
* fork 进程
*
* @time 2020年07月21日
* @return void
*/
protected function forkDynamic()
{
$process = new Process(function (Process $process) {
$redis = $this->getRedisHandle();
while($crontab = $redis->rpop($this->crontabQueueName)) {
$task = $this->getTaskObject(\json_decode($crontab, true));
$task->run();
}
$process->exit();
});
$process->start();
$this->workerIds[$process->pid] = true;
}
/**
* 静态进程
*
* @time 2020年07月21日
* @return void
*/
protected function forkStatic()
{
$process = new Process(function (Process $process) {
$process->initMemory();
$name = $this->name . ' worker';
$this->setWorkerStatus($name, $this->dealNum, $this->status);
Process::setWorkerName($name);
Process::signal(SIGUSR2, function ($signal) use ($name) {
$this->setWorkerStatus($name, $this->dealNum, $this->status);
});
// 该信号保证进程完成任务后安全退出
Process::signal(SIGTERM, function ($signal) {
$this->exitSafely = true;
});
while (true) {
/************** 任务 *********************/
$this->status = 'busying';
$this->setWorkerStatus($name, $this->dealNum, 'busying');
// 处理定时任务
while ($crontab = $this->redis->rpop($this->crontabQueueName)) {
$task = $this->getTaskObject(\json_decode($crontab, true));
$task->run();
if ($task->shouldExit()) {
$process->exit(250);
}
$this->dealNum += 1;
}
$this->status = 'waiting';
$this->setWorkerStatus($name, $this->dealNum, 'waiting');
/****************处理*********************/
// 暂停一秒 让出CPU调度
sleep(1);
// 信号调度
Process::dispatch();
// 是否需要安全退出 || 查看内存是否溢出
if ($this->exitSafely || $process->isMemoryOverflow()) {
$process->exit();
//exit(0);
}
}
});
$process->start();
$this->workerIds[$process->pid] = true;
}
/**
* 重定向文件流
*
* @time 2020年07月22日
* @return void
* @throws Exception
*/
protected function dup()
{
if (!$this->daemon) {
return;
}
global $stdout, $stderr;
// 关闭标准输入输出
fclose(STDOUT);
fclose(STDIN);
fclose(STDERR);
// 重定向输出&错误
$stdoutPath = self::$stdout ?: self::stdoutPath();
!file_exists($stdoutPath) && touch($stdoutPath);
// 等待 100 毫秒
usleep(100 * 1000);
$stdout = fopen($stdoutPath, 'a');
$stderr = fopen($stdoutPath, 'a');
return;
}
/**
* 输出
*
* @time 2020年07月21日
* @return string
*/
public function output()
{
$isShowCtrlC = $this->daemon ? '' : 'Ctrl+c to stop' . "\r\n";
$info = <<<EOT
---------------------------------------------------------------- 🚀
| _ _ _ _ |
| | | | | | | | | |
| ___ __ _| |_ ___| |__ ___ _ __ ___ _ __ | |_ __ _| |__ |
| / __/ _` | __/ __| '_ \ / __| '__/ _ \| '_ \| __/ _` | '_ \ |
| | (_| (_| | || (__| | | | | (__| | | (_) | | | | || (_| | |_) ||
| \___\__,_|\__\___|_| |_| \___|_| \___/|_| |_|\__\__,_|_.__/ |
| | |
|----------------------------------------------------------------|
$isShowCtrlC
EOT;
return file_put_contents(self::statusPath(), $info);
}
/**
* 显示
*
* @time 2020年07月22日
* @return false|int
*/
protected function display()
{
$this->output();
return fwrite(STDOUT, $this->renderStatus());
}
/**
* 获取 redis 句柄
*
* @time 2020年09月15日
* @return object|null
*/
protected function getRedisHandle()
{
return Cache::store('redis')->handler();
}
}

View File

@@ -0,0 +1,47 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2020 http://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
namespace catchAdmin\monitor\command\process;
use catcher\facade\FileSystem;
use think\exception\ClassNotFoundException;
use think\helper\Str;
trait ParseTask
{
/**
* 获取任务
*
* @time 2020年09月15日
* @param $crontab
* @return mixed
*/
protected function getTaskObject($crontab)
{
$class = $this->getTaskNamespace() . ucfirst(Str::camel($crontab['task']));
if (class_exists($class)) {
return app()->make($class)->setCrontab($crontab);
}
throw new ClassNotFoundException('Task '. $crontab['task'] . ' not found');
}
/**
* 获取任务命名空间
*
* @time 2020年09月15日
* @return mixed
*/
protected function getTaskNamespace()
{
return config('catch.crontab.task_namespace');
}
}

View File

@@ -0,0 +1,213 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~{$year} http://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
namespace catchAdmin\monitor\command\process;
use catcher\exceptions\FailedException;
class Process
{
/**
* 保存工作进程 PID
*
* @var
*/
public $pid;
/**
* 用户自定义方法
*
* @var callable
*/
protected $callable;
/**
* 申请最大内存 给出缓冲期
*
* @var string
*/
protected $initMemory = '256M';
/**
* 超过最大内存报警
*
* @var float|int
*/
protected $allowMaxMemory = 128 * 1024 * 1024;
public function __construct(callable $callable)
{
$this->callable = $callable;
}
/**
* 守护进程
*
* @time 2020年07月21日
* @return void
* @throws FailedException
*/
public static function daemon()
{
$pid = pcntl_fork();
if ($pid < 0) {
throw new FailedException('fork process failed');
}
// 退出父进程
if ($pid > 0) {
exit(0);
}
// 设置新的会话组
if (posix_setsid() < 0) {
exit(0);
}
chdir('/');
// 重置掩码 权限问题
umask(0);
}
/**
* 启动进程
*
* @time 2020年07月21日
* @return void
*/
public function start()
{
$pid = pcntl_fork();
if ($this->pid < 0) {
exit('fork failed');
}
if ($pid > 0) {
$this->pid = $pid;
} else {
call_user_func_array($this->callable, [$this]);
}
}
/**
* 信号
*
* @time 2020年07月21日
* @param $signal
* @param $callable
* @param $restartSysCalls
* @return void
*/
public static function signal($signal, $callable, $restartSysCalls = false)
{
pcntl_signal($signal, $callable, $restartSysCalls);
}
/**
* default 1 second
*
* @param $interval
* @return mixed
*/
public static function alarm($interval = 1)
{
return pcntl_alarm($interval);
}
/**
* linux 进程下设置进程名称
*
* @time 2020年07月21日
* @param $title
* @return void
*/
public static function setWorkerName($title)
{
if (strtolower(PHP_OS) === 'linux') {
cli_set_process_title($title);
}
}
/**
* 安全退出
*
* @time 2020年07月21日
* @param int $status
* @return void
*/
public function exit($status = 0)
{
exit($status);
}
/**
* kill
*
* @time 2020年07月22日
* @param $pid
* @param $signal
* @return bool
*/
public static function kill($pid, $signal)
{
return posix_kill($pid, $signal);
}
/**
*
* @time 2020年07月22日
* @return void
*/
public static function dispatch()
{
pcntl_signal_dispatch();
}
/**
* 是否存活
*
* @time 2020年07月22日
* @param $pid
* @return bool
*/
public static function isAlive($pid)
{
return posix_kill($pid, 0);
}
/**
* 初始化进程内存
*
* @time 2020年07月22日
* @param int $memory
* @return void
*/
public function initMemory($memory = 0)
{
if (ini_get('memory_limit') != $this->initMemory) {
// 这里申请一块稍微大的内存
ini_set('memory_limit', $memory ?: $this->initMemory);
}
}
/**
* 是否超过最大内存
*
* @time 2020年07月22日
* @return mixed
*/
public function isMemoryOverflow()
{
// 一旦超过了允许的内存 直接退出进程
return memory_get_usage() > $this->allowMaxMemory;
}
}

View File

@@ -0,0 +1,158 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~{$year} http://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
namespace catchAdmin\monitor\command\process;
use catchAdmin\monitor\model\Crontab;
use catcher\facade\FileSystem;
use Cron\CronExpression;
use EasyWeChat\Kernel\Messages\News;
use think\cache\driver\Redis;
trait RegisterSignal
{
public function registerSignal()
{
// 退出信号
$this->exit();
// 等待子进程退出
$this->waitWorkersExit();
// 动态扩容
$this->workerChecked();
// 重启进程
$this->reload();
// 统计信息
$this->showStatus();
}
/**
* 进程退出
*
* @time 2020年07月21日
* @return void
*/
protected function exit()
{
Process::signal(SIGTERM, function ($signal) {
foreach ($this->workerIds as $pid => $v) {
if (isset($this->workerIds[$pid])) {
unset($this->workerIds[$pid]);
}
Process::kill($pid, SIGTERM);
}
Process::kill(self::getMasterPid(), SIGKILL);
});
Process::signal(SIGINT, function ($signal) {
foreach ($this->workerIds as $pid => $v) {
if (isset($this->workerIds[$pid])) {
unset($this->workerIds[$pid]);
}
Process::kill($pid, SIGKILL);
}
Process::kill(self::getMasterPid(), SIGKILL);
});
}
/**
* 子进程退出
*
* @time 2020年07月21日
* @return void
*/
protected function waitWorkersExit()
{
Process::signal(SIGCHLD, function ($signal) {
});
}
/**
* 进程检测
*
* @time 2020年07月21日
* @return void
*/
protected function workerChecked()
{
Process::signal(SIGALRM, function ($signal) {
$process = new Process(function (Process $process) {
$crontabs = Crontab::where('status', Crontab::ENABLE)
->where('tactics', '<>', Crontab::EXECUTE_FORBIDDEN)
->select()->toArray();
// 任务
foreach ($crontabs as $crontab) {
$can = date('Y-m-d H:i', CronExpression::factory(trim($crontab['cron']))
->getNextRunDate(date('Y-m-d H:i:s'), 0 , true)
->getTimestamp()) == date('Y-m-d H:i', time());
if ($can) {
// 如果任务只执行一次 之后禁用该任务
if ($crontab['tactics'] === Crontab::EXECUTE_ONCE) {
Crontab::where('id', $crontab['id'])->update([
'status' => Crontab::DISABLE,
]);
}
$redis = $this->getRedisHandle();
$redis->lpush($this->crontabQueueName, json_encode([
'id' => $crontab['id'],
'task' => $crontab['task'],
]));
}
}
$process->exit();
});
$process->start();
Process::alarm($this->interval);
});
}
/**
* 重启
*
* @time 2020年07月21日
* @return void
*/
protected function reload()
{
Process::signal(SIGUSR1, function ($signal) {
$this->worker_start_at = 0;
foreach ($this->workerIds as $pid => $v) {
Process::kill($pid, SIGTERM);
}
}, false);
}
/**
* 预留信号
*
* @time 2020年07月21日
* @return void
*/
protected function showStatus()
{
Process::signal(SIGUSR2, function ($signal) {
$this->setWorkerStatus($this->name . ' master');
foreach ($this->workerIds as $pid => $v) {
Process::kill($pid, SIGUSR2);
}
});
}
}

View File

@@ -0,0 +1,243 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~{$year} http://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
namespace catchAdmin\monitor\command\process;
use catcher\facade\FileSystem;
trait Store
{
/**
* worker 根目录
*
* @time 2020年07月23日
* @return string
*/
public static function storeTaskPath()
{
$path = config('catch.crontab.store_path');
if (!Filesystem::exists($path)) {
FileSystem::makeDirectory($path, 0777, true);
}
return $path;
}
/**
* 保存信息备用
*
* @time 2020年07月29日
* @return void
*/
protected function saveTaskInfo()
{
FileSystem::put(self::storeTaskPath() . 'information.json', \json_encode([
'name' => $this->name,
'static' => $this->static,
'dynamic' => $this->dynamic,
'interval' => $this->interval,
], JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE));
}
/**
* worker master pid
*
* @time 2020年07月23日
* @return string
*/
public static function masterPidStorePath()
{
return self::storeTaskPath() . 'master.pid';
}
/**
* worker master status
*
* @time 2020年07月23日
* @return string
*/
public static function statusPath()
{
return self::storeTaskPath() . 'master.status';
}
/**
* worker status
*
* @time 2020年07月23日
* @param string $name
* @return string
*/
public static function workerStatusPath($name)
{
$path = self::storeTaskPath() . 'status/';
if (!FileSystem::exists($path)) {
FileSystem::makeDirectory($path, 0777, true);
}
return $path . $name . '.status';
}
/**
*
* @time 2020年07月23日
* @return string
*/
public static function getWorkerStatusPath()
{
return self::storeTaskPath() . 'status/';
}
/**
* worker log
*
* @time 2020年07月23日
* @return string
*/
public static function stdoutPath()
{
return self::storeTaskPath() . 'errors.log';
}
/**
* 获取 master pid
*
* @time 2020年07月21日
* @return false|string
*/
public static function getMasterPid()
{
$pidFile = config('catch.crontab.master_pid_file');
if (!FileSystem::exists($pidFile)) {
return 0;
}
return FileSystem::sharedGet($pidFile);
}
/**
* status
*
* @time 2020年07月21日
* @return false|string
*/
public function renderStatus()
{
return FileSystem::sharedGet(self::statusPath());
}
/**
* 运行时间
*
* @time 2020年07月23日
* @param $runtime
* @return string
*/
protected function getRunningTime($runtime)
{
$day = 3600 * 24;
if ($runtime > $day) {
$days = floor($runtime / $day);
return $days . '天:' . gmstrftime('%H:%M:%S', $runtime % $day);
} else {
return gmstrftime('%H:%M:%S', $runtime);
}
}
/**
* 获取工作进程
*
* @time 2020年07月23日
* @return mixed
*/
public function getWorkerStatus()
{
usleep(500 * 1000);
$files = FileSystem::glob(self::storeTaskPath() . 'status/*.status');
$workerStatus = [];
foreach ($files as $file) {
$workerStatus[] = explode("\t", FileSystem::sharedGet($file));
}
return $workerStatus;
}
/**
* 设置进程状态
*
* @time 2020年07月23日
* @param $name
* @param int $dealNum
* @param string $status
* @return void
*/
protected function setWorkerStatus($name, $dealNum = 0, $status = 'running')
{
$startAt = strpos($name, 'worker') ? $this->worker_start_at : $this->start_at;
if ($this->daemon) {
FileSystem::put($this->workerStatusPath($this->workerStatusFileName($name)), implode("\t", [
posix_getpid(),
$name,
floor(memory_get_usage() / 1024 / 1024) . 'M',
$dealNum,
date('Y-m-d H:i:s', $startAt),
$this->getRunningTime(time() - $startAt),
$status
]));
}
}
/**
* 进程名称
*
* @time 2020年09月15日
* @param $name
* @return string
*/
protected function workerStatusFileName($name)
{
return $name . '_' . posix_getpid();
}
/**
* 删除进程状态文件
*
* @time 2020年09月15日
* @param $pid
* @return void
*/
protected function deleteWorkerStatusFile($pid)
{
@unlink(self::workerStatusPath($this->name . ' worker_' . $pid));
}
/**
* 退出
*
* @time 2020年09月15日
* @return void
*/
public static function exitMasterDo()
{
@unlink(self::masterPidStorePath());
@unlink(self::statusPath());
Filesystem::deleteDirectory(self::getWorkerStatusPath());
}
}

59
catch/monitor/config.php Normal file
View File

@@ -0,0 +1,59 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2020 http://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
return [
/**
*
* 定时任务配置
*
*/
'crontab' => [
/**
* 存储目录
*/
'store_path' => runtime_path('catch/crontab'),
/**
* 主进程 pid 存储
*/
'master_pid_file' => runtime_path('catch/crontab') . 'master.pid',
/**
* 日志配置
*/
'log' => [
// 日志记录方式
'type' => 'File',
// 日志保存目录
'path' => runtime_path('catch/schedule'),
// 单文件日志写入
'single' => false,
// 独立日志级别
'apart_level' => [],
// 最大日志文件数量
'max_files' => 0,
// 使用JSON格式记录
'json' => false,
// 日志处理
'processor' => null,
// 关闭通道日志写入
'close' => false,
// 日志输出格式化
'format' => '[%s][%s] %s',
// 是否实时写入
'realtime_write' => false,
],
/**
* crontab 任务命名空间
*/
'task_namespace' => '\\app\\task\\',
],
];

View File

@@ -0,0 +1,105 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2020 http://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
namespace catchAdmin\monitor\controller;
use catcher\base\CatchRequest as Request;
use catcher\CatchResponse;
use catcher\base\CatchController;
use catchAdmin\monitor\model\Crontab as CrontabModel;
use Cron\CronExpression;
class Crontab extends CatchController
{
protected $model;
public function __construct(CrontabModel $model)
{
$this->model = $model;
}
/**
* 列表
*
* @time 2020/09/14 20:35
*
* @return \think\Response
*/
public function index()
{
return CatchResponse::paginate($this->model->getList());
}
/**
* 保存
*
* @time 2020/09/14 20:35
* @param Request Request
* @return \think\Response
*/
public function save(Request $request)
{
CronExpression::factory($request->post('cron'));
return CatchResponse::success($this->model->storeBy($request->post()));
}
/**
* 读取
*
* @time 2020/09/14 20:35
* @param $id
* @return \think\Response
*/
public function read($id)
{
return CatchResponse::success($this->model->findBy($id));
}
/**
* 更新
*
* @time 2020/09/14 20:35
* @param Request $request
* @return \think\Response
*/
public function update(Request $request, $id)
{
CronExpression::factory($request->post('cron'));
return CatchResponse::success($this->model->updateBy($id, $request->post()));
}
/**
* 删除
*
* @time 2020/09/14 20:35
* @param $id
* @return \think\Response
*/
public function delete($id)
{
return CatchResponse::success($this->model->deleteBy($id));
}
/**
* 禁用启用
*
* @time 2020年09月15日
* @param $id
* @return \think\response\Json
*/
public function disOrEnable($id)
{
return CatchResponse::success($this->model->disOrEnable($id));
}
}

View File

@@ -0,0 +1,50 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2020 http://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
namespace catchAdmin\monitor\controller;
use catchAdmin\monitor\model\CrontabLog as LogModel;
use catcher\base\CatchController;
use catcher\CatchResponse;
use think\Request;
class CrontabLog extends CatchController
{
protected $model;
public function __construct(LogModel $model)
{
$this->model = $model;
}
/**
* 日志列表
*
* @time 2020年09月15日
* @throws \think\db\exception\DbException
* @return \think\response\Json
*/
public function index()
{
return CatchResponse::paginate($this->model->getList());
}
/**
* 删除日志
*
* @time 2020年09月15日
* @param $id
* @return \think\response\Json
*/
public function delete($id)
{
return CatchResponse::success($this->model->deleteBy($id));
}
}

View File

@@ -0,0 +1,46 @@
<?php
use think\migration\Migrator;
use think\migration\db\Column;
use Phinx\Db\Adapter\MysqlAdapter;
class Crontab extends Migrator
{
/**
* Change Method.
*
* Write your reversible migrations using this method.
*
* More information on writing migrations is available here:
* http://docs.phinx.org/en/latest/migrations.html#the-abstractmigration-class
*
* The following commands can be used in this method and Phinx will
* automatically reverse them when rolling back:
*
* createTable
* renameTable
* addColumn
* renameColumn
* addIndex
* addForeignKey
*
* Remember to call "create()" or "update()" and NOT "save()" when working
* with the Table class.
*/
public function change()
{
$table = $this->table('crontab', ['engine' => 'InnoDB', 'collation' => 'utf8mb4_general_ci', 'comment' => '定时任务' ,'id' => 'id','signed' => true ,'primary_key' => ['id']]);
$table->addColumn('name', 'string', ['limit' => 255,'null' => false,'default' => '','signed' => false,'comment' => '任务名称',])
->addColumn('group', 'boolean', ['null' => false,'default' => 1,'signed' => false,'comment' => '1 默认 2 系统',])
->addColumn('task', 'string', ['limit' => 255,'null' => false,'default' => '','signed' => false,'comment' => '任务名称',])
->addColumn('cron', 'string', ['limit' => 50,'null' => false,'default' => '','signed' => false,'comment' => 'cron 表达式',])
->addColumn('tactics', 'boolean', ['null' => false,'default' => 1,'signed' => false,'comment' => '1 立即执行 2 执行一次 3 放弃执行',])
->addColumn('status', 'boolean', ['null' => false,'default' => 1,'signed' => false,'comment' => '1 正常 2 禁用',])
->addColumn('remark', 'string', ['limit' => 1000,'null' => false,'default' => '','signed' => false,'comment' => '备注',])
->addColumn('creator_id', 'integer', ['limit' => MysqlAdapter::INT_REGULAR,'null' => false,'default' => 0,'signed' => true,'comment' => '创建人ID',])
->addColumn('created_at', 'integer', ['limit' => MysqlAdapter::INT_REGULAR,'null' => false,'default' => 0,'signed' => true,'comment' => '创建时间',])
->addColumn('updated_at', 'integer', ['limit' => MysqlAdapter::INT_REGULAR,'null' => false,'default' => 0,'signed' => true,'comment' => '更新时间',])
->addColumn('deleted_at', 'integer', ['limit' => MysqlAdapter::INT_REGULAR,'null' => false,'default' => 0,'signed' => true,'comment' => '软删除',])
->create();
}
}

View File

@@ -0,0 +1,51 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~{$year} http://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
use think\migration\Migrator;
use think\migration\db\Column;
use Phinx\Db\Adapter\MysqlAdapter;
class CrontabLog extends Migrator
{
/**
* Change Method.
*
* Write your reversible migrations using this method.
*
* More information on writing migrations is available here:
* http://docs.phinx.org/en/latest/migrations.html#the-abstractmigration-class
*
* The following commands can be used in this method and Phinx will
* automatically reverse them when rolling back:
*
* createTable
* renameTable
* addColumn
* renameColumn
* addIndex
* addForeignKey
*
* Remember to call "create()" or "update()" and NOT "save()" when working
* with the Table class.
*/
public function change()
{
$table = $this->table('crontab_log', ['engine' => 'Myisam', 'collation' => 'utf8mb4_general_ci', 'comment' => '定时任务日志' ,'id' => 'id','signed' => true ,'primary_key' => ['id']]);
$table->addColumn('crontab_id', 'integer', ['limit' => MysqlAdapter::INT_REGULAR,'null' => false,'default' => 0,'signed' => true,'comment' => 'crontab 任务ID',])
->addColumn('used_time', 'integer', ['limit' => MysqlAdapter::INT_REGULAR,'null' => false,'default' => 0,'signed' => true,'comment' => '任务消耗时间',])
->addColumn('status', 'boolean', ['null' => false,'default' => 1,'signed' => false,'comment' => '1 成功 2 失败',])
->addColumn('error_message', 'string', ['limit' => 1000,'null' => false,'default' => '','signed' => false,'comment' => '错误信息',])
->addColumn('created_at', 'integer', ['limit' => MysqlAdapter::INT_REGULAR,'null' => false,'default' => 0,'signed' => true,'comment' => '创建时间',])
->addColumn('updated_at', 'integer', ['limit' => MysqlAdapter::INT_REGULAR,'null' => false,'default' => 0,'signed' => true,'comment' => '更新时间',])
->addColumn('deleted_at', 'integer', ['limit' => MysqlAdapter::INT_REGULAR,'null' => false,'default' => 0,'signed' => true,'comment' => '软删除',])
->create();
}
}

View File

@@ -0,0 +1,253 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~{$year} http://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
use think\migration\Seeder;
class MonitorMenusSeed extends Seeder
{
/**
* Run Method.
*
* Write your database seeder using this method.
*
* More information on writing seeders is available here:
* http://docs.phinx.org/en/latest/seeding.html
*/
public function run()
{
\catcher\Utils::importTreeData($this->getPermissions(), 'permissions', 'parent_id');
}
protected function getPermissions()
{
return array (
0 =>
array (
'id' => 103,
'permission_name' => '系统监控',
'parent_id' => 0,
'level' => '',
'route' => '/monitor',
'icon' => 'el-icon-view',
'module' => 'monitor',
'creator_id' => 1,
'permission_mark' => 'monitor',
'component' => 'layout',
'redirect' => '/monitor/crontab',
'keepalive' => 1,
'type' => 1,
'hidden' => 1,
'sort' => 1,
'created_at' => 1600126383,
'updated_at' => 1600136975,
'deleted_at' => 0,
'children' =>
array (
0 =>
array (
'id' => 104,
'permission_name' => '定时任务',
'parent_id' => 103,
'level' => '103',
'route' => '/monitor/crontab',
'icon' => 'el-icon-time',
'module' => 'monitor',
'creator_id' => 1,
'permission_mark' => 'crontab',
'component' => 'crontab',
'redirect' => '',
'keepalive' => 1,
'type' => 1,
'hidden' => 1,
'sort' => 1,
'created_at' => 1600126931,
'updated_at' => 1600136975,
'deleted_at' => 0,
'children' =>
array (
0 =>
array (
'id' => 105,
'permission_name' => '列表',
'parent_id' => 104,
'level' => '103-104',
'route' => '',
'icon' => '',
'module' => 'monitor',
'creator_id' => 1,
'permission_mark' => 'crontab@index',
'component' => '',
'redirect' => '',
'keepalive' => 1,
'type' => 2,
'hidden' => 1,
'sort' => 1,
'created_at' => 1600127069,
'updated_at' => 1600136975,
'deleted_at' => 0,
),
1 =>
array (
'id' => 106,
'permission_name' => '保存',
'parent_id' => 104,
'level' => '103-104',
'route' => '',
'icon' => '',
'module' => 'monitor',
'creator_id' => 1,
'permission_mark' => 'crontab@save',
'component' => '',
'redirect' => '',
'keepalive' => 1,
'type' => 2,
'hidden' => 1,
'sort' => 1,
'created_at' => 1600127078,
'updated_at' => 1600136975,
'deleted_at' => 0,
),
2 =>
array (
'id' => 107,
'permission_name' => '更新',
'parent_id' => 104,
'level' => '103-104',
'route' => '',
'icon' => '',
'module' => 'monitor',
'creator_id' => 1,
'permission_mark' => 'crontab@update',
'component' => '',
'redirect' => '',
'keepalive' => 1,
'type' => 2,
'hidden' => 1,
'sort' => 1,
'created_at' => 1600127085,
'updated_at' => 1600136975,
'deleted_at' => 0,
),
3 =>
array (
'id' => 108,
'permission_name' => '删除',
'parent_id' => 104,
'level' => '103-104',
'route' => '',
'icon' => '',
'module' => 'monitor',
'creator_id' => 1,
'permission_mark' => 'crontab@delete',
'component' => '',
'redirect' => '',
'keepalive' => 1,
'type' => 2,
'hidden' => 1,
'sort' => 1,
'created_at' => 1600127091,
'updated_at' => 1600136975,
'deleted_at' => 0,
),
4 =>
array (
'id' => 109,
'permission_name' => '禁用/启用',
'parent_id' => 104,
'level' => '103-104',
'route' => '',
'icon' => '',
'module' => 'monitor',
'creator_id' => 1,
'permission_mark' => 'crontab@disOrEnable',
'component' => '',
'redirect' => '',
'keepalive' => 1,
'type' => 2,
'hidden' => 1,
'sort' => 1,
'created_at' => 1600129279,
'updated_at' => 1600136975,
'deleted_at' => 0,
),
),
),
1 =>
array (
'id' => 110,
'permission_name' => '任务日志',
'parent_id' => 103,
'level' => '103-104',
'route' => '/monitor/crontab/log/:crontab_id?',
'icon' => 'el-icon-guide',
'module' => 'monitor',
'creator_id' => 1,
'permission_mark' => 'CrontabLog',
'component' => 'crontabLog',
'redirect' => '',
'keepalive' => 1,
'type' => 1,
'hidden' => 2,
'sort' => 1,
'created_at' => 1600167562,
'updated_at' => 1600188651,
'deleted_at' => 0,
'children' =>
array (
0 =>
array (
'id' => 111,
'permission_name' => '列表',
'parent_id' => 110,
'level' => '103-104-110',
'route' => '',
'icon' => '',
'module' => 'monitor',
'creator_id' => 1,
'permission_mark' => 'CrontabLog@index',
'component' => '',
'redirect' => '',
'keepalive' => 1,
'type' => 2,
'hidden' => 1,
'sort' => 1,
'created_at' => 1600167574,
'updated_at' => 1600168082,
'deleted_at' => 0,
),
1 =>
array (
'id' => 112,
'permission_name' => '删除',
'parent_id' => 110,
'level' => '103-104-110',
'route' => '',
'icon' => '',
'module' => 'monitor',
'creator_id' => 1,
'permission_mark' => 'CrontabLog@delete',
'component' => '',
'redirect' => '',
'keepalive' => 1,
'type' => 2,
'hidden' => 1,
'sort' => 1,
'created_at' => 1600167581,
'updated_at' => 1600168082,
'deleted_at' => 0,
),
),
),
),
),
);
}
}

View File

@@ -0,0 +1,43 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2020 http://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
namespace catchAdmin\monitor\model;
use catchAdmin\monitor\model\search\CrontabSearch;
use catcher\base\CatchModel as Model;
class Crontab extends Model
{
use CrontabSearch;
protected $name = 'crontab';
protected $field = [
'id', //
'name', // 任务名称
'group', // 1 默认 2 系统
'task', // 任务名称
'cron', // cron 表达式
'tactics', // 1 立即执行 2 执行一次 3 放弃执行
'status', // 1 正常 2 禁用
'remark', // 备注
'creator_id', // 创建人ID
'created_at', // 创建时间
'updated_at', // 更新时间
'deleted_at', // 软删除
];
const EXECUTE_IMMEDIATELY = 1; // 立即执行
const EXECUTE_ONCE = 2; // 执行一次
const EXECUTE_FORBIDDEN = 3; // 停止执行
}

View File

@@ -0,0 +1,53 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2020 http://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
namespace catchAdmin\monitor\model;
use catchAdmin\monitor\model\search\CrontabLogSearch;
use catcher\base\CatchModel;
class CrontabLog extends CatchModel
{
use CrontabLogSearch;
protected $name = 'crontab_log';
protected $field = [
'id', //
'crontab_id', // crontab 任务ID
'used_time', // 任务消耗时间
'status', // 1 成功 2 失败
'error_message', // 错误信息
'created_at', // 创建时间
'updated_at', // 更新时间
'deleted_at', // 软删除
];
const SUCCESS = 1;
const FAILED = 2;
/**
* 获取日志列表
*
* @time 2020年09月15日
* @throws \think\db\exception\DbException
* @return mixed|\think\Paginator
*/
public function getList()
{
return $this->catchLeftJoin(Crontab::class, 'id', 'crontab_id', ['name', 'group', 'task'])
->catchSearch()
->catchOrder()
->field(['used_time', 'error_message', 'crontab_log.status', 'crontab_log.id', 'crontab_log.created_at'])
->paginate();
}
}

View File

@@ -0,0 +1,39 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2020 http://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
namespace catchAdmin\monitor\model\search;
trait CrontabLogSearch
{
public function searchCrontabIdAttr($query, $value, $data)
{
return $query->where('crontab_id', $value);
}
public function searchNameAttr($query, $value, $data)
{
return $query->whereLike('crontab.name', $value);
}
public function searchStatusAttr($query, $value, $data)
{
return $query->where('crontab_log.status', $value);
}
public function searchStartAtAttr($query, $value, $data)
{
return $query->where($this->aliasField('created_at'), '>=', strtotime($value));
}
public function searchEndAtAttr($query, $value, $data)
{
return $query->where($this->aliasField('created_at'), '<=', strtotime($value));
}
}

View File

@@ -0,0 +1,24 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2020 http://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
namespace catchAdmin\monitor\model\search;
trait CrontabSearch
{
public function searchNameAttr($query, $value, $data)
{
return $query->whereLike('name', $value);
}
public function searchStatusAttr($query, $value, $data)
{
return $query->where('status', $value);
}
}

15
catch/monitor/module.json Normal file
View File

@@ -0,0 +1,15 @@
{
"name": "系统监控",
"alias": "monitor",
"description": "系统监控模块",
"version": "1.0.0",
"keywords": [],
"order": 0,
"services": [
"\\catchAdmin\\monitor\\MonitorService"
],
"aliases": [],
"files": [],
"requires": [],
"enable": true
}

22
catch/monitor/route.php Normal file
View File

@@ -0,0 +1,22 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~{$year} http://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
// you should use `$router`
$router->group('monitor', function () use ($router){
// crontab路由
$router->resource('crontab', '\catchAdmin\monitor\controller\Crontab');
$router->put('crontab/enable/<id>', '\catchAdmin\monitor\controller\Crontab@disOrEnable');
// crontab 日志
$router->get('crontab/log/list', '\catchAdmin\monitor\controller\CrontabLog@index');
$router->delete('crontab/log/list/<id>', '\catchAdmin\monitor\controller\CrontabLog@delete');
})->middleware('auth');

View File

@@ -5,6 +5,7 @@ use catcher\base\CatchController;
use catchAdmin\permissions\model\Department as DepartmentModel; use catchAdmin\permissions\model\Department as DepartmentModel;
use catcher\base\CatchRequest; use catcher\base\CatchRequest;
use catcher\CatchResponse; use catcher\CatchResponse;
use catcher\exceptions\FailedException;
use catcher\Tree; use catcher\Tree;
class Department extends CatchController class Department extends CatchController
@@ -26,7 +27,7 @@ class Department extends CatchController
*/ */
public function index(): \think\response\Json public function index(): \think\response\Json
{ {
return CatchResponse::success(Tree::done($this->department->getList())); return CatchResponse::success($this->department->getList());
} }
/** /**
@@ -63,6 +64,10 @@ class Department extends CatchController
*/ */
public function delete($id): \think\response\Json public function delete($id): \think\response\Json
{ {
if ($this->department->where('parent_id', $id)->find()) {
throw new FailedException('存在子部门,无法删除');
}
return CatchResponse::success($this->department->deleteBy($id)); return CatchResponse::success($this->department->deleteBy($id));
} }
} }

View File

@@ -9,6 +9,7 @@ use catcher\exceptions\FailedException;
use catcher\library\ParseClass; use catcher\library\ParseClass;
use catcher\Tree; use catcher\Tree;
use catchAdmin\permissions\model\Permissions; use catchAdmin\permissions\model\Permissions;
use think\helper\Str;
use think\response\Json; use think\response\Json;
class Permission extends CatchController class Permission extends CatchController
@@ -46,9 +47,9 @@ class Permission extends CatchController
// 子节点的 key // 子节点的 key
$children = $request->param('actionList') ?? 'children'; $children = $request->param('actionList') ?? 'children';
// 返回树结构 // 返回树结构
return CatchResponse::success(Tree::done($menuList->each(function (&$item) use ($buttonList, $children){ return CatchResponse::success($menuList->each(function (&$item) use ($buttonList, $children){
$item[$children] = $buttonList[$item['id']] ?? []; $item[$children] = $buttonList[$item['id']] ?? [];
})->toArray())); })->toTree());
} }
/** /**
@@ -66,9 +67,22 @@ class Permission extends CatchController
// 如果是子分类 自动写入父类模块 // 如果是子分类 自动写入父类模块
$parentId = $params['parent_id'] ?? 0; $parentId = $params['parent_id'] ?? 0;
if ($parentId) { // 按钮类型寻找上级
$parent = $this->permissions->findBy($parentId); if ($params['type'] == Permissions::BTN_TYPE && $parentId) {
$params['module'] = $parent->module; $permissionMark = $params['permission_mark'];
// 查找父级
$parentPermission = $this->permissions->findBy($parentId);
// 如果父级是顶级 parent_id = 0
if ($parentPermission->parent_id) {
if (Str::contains($parentPermission->permission_mark, '@')) {
list($controller, $action) = explode('@', $parentPermission->permission_mark);
$permissionMark = $controller . '@' . $permissionMark;
} else {
$permissionMark = $parentPermission->permission_mark .'@'. $permissionMark;
}
}
$params['permission_mark'] = $permissionMark;
$params['module'] = $parentPermission->module;
} }
return CatchResponse::success($this->permissions->storeBy($params)); return CatchResponse::success($this->permissions->storeBy($params));
@@ -85,6 +99,33 @@ class Permission extends CatchController
{ {
$permission = $this->permissions->findBy($id); $permission = $this->permissions->findBy($id);
$params = $request->param();
// 按钮类型
if ($params['type'] == Permissions::BTN_TYPE && $permission->parent_id) {
$parentPermission = $this->permissions->findBy($permission->parent_id);
$permissionMark = $params['permission_mark'];
if ($parentPermission->parent_id) {
if (Str::contains($parentPermission->permission_mark, '@')) {
list($controller, $action) = explode('@', $parentPermission->permission_mark);
$permissionMark = $controller . '@' . $permissionMark;
} else {
$permissionMark = $parentPermission->permission_mark .'@'. $permissionMark;
}
}
$params['permission_mark'] = $permissionMark;
$this->permissions->where('id',$id)->update(array_merge($params, [
'parent_id' => $permission->parent_id,
'level' => $permission->level,
'updated_at' => time()
]));
return CatchResponse::success();
}
$params = array_merge($request->param(), [ $params = array_merge($request->param(), [
'parent_id' => $permission->parent_id, 'parent_id' => $permission->parent_id,
'level' => $permission->level 'level' => $permission->level
@@ -134,17 +175,9 @@ class Permission extends CatchController
*/ */
public function show($id) public function show($id)
{ {
$permission = $this->permissions->findBy($id); $this->permissions->show($id);
$permission->status = $permission->status == Permissions::ENABLE ? Permissions::DISABLE : Permissions::ENABLE; return CatchResponse::success();
if ($permission->save()) {
$this->permissions->where('parent_id', $id)->update([
'status' => $permission->status,
]);
}
return CatchResponse::success($permission->save());
} }
/** /**
@@ -160,14 +193,15 @@ class Permission extends CatchController
public function getMethods($id, ParseClass $parseClass) public function getMethods($id, ParseClass $parseClass)
{ {
$permission = Permissions::where('id', $id)->find(); $permission = Permissions::where('id', $id)->find();
$module = $permission->module; $module = $permission->module;
$controller = explode('@', $permission->permission_mark)[0]; $controller = explode('@', $permission->permission_mark)[0];
$methods = $parseClass->setModule('catch')->setRule($module, $controller)->onlySelfMethods(); try {
$methods = $parseClass->setModule('catch')->setRule($module, $controller)->onlySelfMethods();
return CatchResponse::success($methods); return CatchResponse::success($methods);
}catch (\Exception $e) {
return CatchResponse::success([]);
}
} }
} }

View File

@@ -2,18 +2,20 @@
namespace catchAdmin\permissions\controller; namespace catchAdmin\permissions\controller;
use catchAdmin\permissions\model\Permissions; use catchAdmin\permissions\model\Permissions;
use catchAdmin\permissions\model\Roles;
use catcher\base\CatchRequest as Request; use catcher\base\CatchRequest as Request;
use catcher\base\CatchController; use catcher\base\CatchController;
use catcher\CatchResponse; use catcher\CatchResponse;
use catcher\exceptions\FailedException; use catcher\exceptions\FailedException;
use catcher\Tree; use catcher\Tree;
use think\response\Json; use think\response\Json;
use catchAdmin\permissions\model\Roles as RoleModel;
class Role extends CatchController class Role extends CatchController
{ {
protected $role; protected $role;
public function __construct(\catchAdmin\permissions\model\Roles $role) public function __construct(RoleModel $role)
{ {
$this->role = $role; $this->role = $role;
} }
@@ -21,12 +23,11 @@ class Role extends CatchController
/** /**
* *
* @time 2019年12月09日 * @time 2019年12月09日
* @param Request $request
* @return string * @return string
*/ */
public function index() public function index()
{ {
return CatchResponse::success(Tree::done($this->role->getList())); return CatchResponse::success($this->role->getList());
} }
/** /**
@@ -38,15 +39,18 @@ class Role extends CatchController
*/ */
public function save(Request $request) public function save(Request $request)
{ {
$this->role->storeBy($request->param()); $params = $request->param();
$permissions = $request->param('permissions'); if (Roles::where('identify', $params['identify'])->find()) {
throw new FailedException('角色标识 [' . $params['identify'] . ']已存在');
}
$this->role->storeBy($params);
$permissions = $params['permissions'];
if (!empty($permissions)) { if (!empty($permissions)) {
$this->role->attachPermissions(array_unique($permissions)); $this->role->attachPermissions(array_unique($permissions));
} }
if (!empty($request->param('departments'))) {
$this->role->attachDepartments($request->param('departments'));
}
// 添加角色 // 添加角色
return CatchResponse::success(); return CatchResponse::success();
} }
@@ -55,7 +59,6 @@ class Role extends CatchController
{ {
$role = $this->role->findBy($id); $role = $this->role->findBy($id);
$role->permissions = $role->getPermissions(); $role->permissions = $role->getPermissions();
$role->departments = $role->getDepartments();
return CatchResponse::success($role); return CatchResponse::success($role);
} }
@@ -69,6 +72,10 @@ class Role extends CatchController
*/ */
public function update($id, Request $request): Json public function update($id, Request $request): Json
{ {
if (Roles::where('identify', $request->param('identify'))->where('id', '<>', $id)->find()) {
throw new FailedException('角色标识 [' . $request->param('identify') . ']已存在');
}
$this->role->updateBy($id, $request->param()); $this->role->updateBy($id, $request->param());
$role = $this->role->findBy($id); $role = $this->role->findBy($id);
@@ -94,28 +101,6 @@ class Role extends CatchController
$role->attachPermissions(array_unique($attachIds)); $role->attachPermissions(array_unique($attachIds));
} }
// 更新department
$hasDepartmentIds = $role->getDepartments()->column('id');
$departmentIds = $request->param('departments',[]);
// 已存在部门 IDS
$existedDepartmentIds = [];
foreach ($hasDepartmentIds as $hasDepartmentId) {
if (in_array($hasDepartmentId, $departmentIds)) {
$existedDepartmentIds[] = $hasDepartmentId;
}
}
$attachDepartmentIds = array_diff($departmentIds, $existedDepartmentIds);
$detachDepartmentIds = array_diff($hasDepartmentIds, $existedDepartmentIds);
if (!empty($detachDepartmentIds)) {
$role->detachDepartments($detachDepartmentIds);
}
if (!empty($attachDepartmentIds)) {
$role->attachDepartments(array_unique($attachDepartmentIds));
}
return CatchResponse::success(); return CatchResponse::success();
} }
@@ -137,8 +122,6 @@ class Role extends CatchController
$role = $this->role->findBy($id); $role = $this->role->findBy($id);
// 删除权限 // 删除权限
$role->detachPermissions(); $role->detachPermissions();
// 删除部门关联
$role->detachDepartments();
// 删除用户关联 // 删除用户关联
$role->users()->detach(); $role->users()->detach();
// 删除 // 删除

View File

@@ -1,16 +1,19 @@
<?php <?php
namespace catchAdmin\permissions\controller; namespace catchAdmin\permissions\controller;
use catchAdmin\permissions\excel\UserExport;
use catcher\base\CatchRequest as Request; use catcher\base\CatchRequest as Request;
use catchAdmin\permissions\model\Permissions; use catchAdmin\permissions\model\Permissions;
use catchAdmin\permissions\model\Roles; use catchAdmin\permissions\model\Roles;
use catchAdmin\permissions\model\Users; use catchAdmin\permissions\model\Users;
use catchAdmin\permissions\request\CreateRequest; use catchAdmin\permissions\request\CreateRequest;
use catchAdmin\permissions\request\UpdateRequest; use catchAdmin\permissions\request\UpdateRequest;
use catchAdmin\permissions\request\ProfileRequest;
use catcher\base\CatchController; use catcher\base\CatchController;
use catcher\CatchAuth; use catcher\CatchAuth;
use catcher\CatchCacheKeys; use catcher\CatchCacheKeys;
use catcher\CatchResponse; use catcher\CatchResponse;
use catcher\library\excel\Excel;
use catcher\Tree; use catcher\Tree;
use catcher\Utils; use catcher\Utils;
use think\facade\Cache; use think\facade\Cache;
@@ -49,7 +52,7 @@ class User extends CatchController
{ {
$user = $auth->user(); $user = $auth->user();
$roles = $user->getRoles(); $roles = $user->getRoles()->column('identify');
$permissionIds = $user->getPermissionsBy($user->id); $permissionIds = $user->getPermissionsBy($user->id);
// 缓存用户权限 // 缓存用户权限
@@ -65,15 +68,6 @@ class User extends CatchController
return CatchResponse::success($user); return CatchResponse::success($user);
} }
/**
*
* @time 2019年12月06日
* @throws \Exception
* @return string
*/
public function create()
{}
/** /**
* *
* @param CreateRequest $request * @param CreateRequest $request
@@ -86,7 +80,9 @@ class User extends CatchController
$this->user->attachRoles($request->param('roles')); $this->user->attachRoles($request->param('roles'));
$this->user->attachJobs($request->param('jobs')); if ($request->param('jobs')) {
$this->user->attachJobs($request->param('jobs'));
}
return CatchResponse::success('', '添加成功'); return CatchResponse::success('', '添加成功');
} }
@@ -105,12 +101,6 @@ class User extends CatchController
return CatchResponse::success($user); return CatchResponse::success($user);
} }
/**
* @param $id
* @return string
* @throws \Exception
*/
public function edit($id){}
/** /**
* *
* @time 2019年12月04日 * @time 2019年12月04日
@@ -120,7 +110,7 @@ class User extends CatchController
*/ */
public function update($id, UpdateRequest $request) public function update($id, UpdateRequest $request)
{ {
$this->user->updateBy($id, $request->param()); $this->user->updateBy($id, $request->filterEmptyField()->param());
$user = $this->user->findBy($id); $user = $this->user->findBy($id);
@@ -225,4 +215,30 @@ class User extends CatchController
'hasRoles' => $roleIds, 'hasRoles' => $roleIds,
]); ]);
} }
/**
* 导出
*
* @time 2020年09月08日
* @param Excel $excel
* @param UserExport $userExport
* @throws \PhpOffice\PhpSpreadsheet\Exception
* @return \think\response\Json
*/
public function export(Excel $excel, UserExport $userExport)
{
return CatchResponse::success($excel->save($userExport, Utils::publicPath('export/users')));
}
/**
* 更新个人信息
*
* @time 2020年09月20日
* @param ProfileRequest $request
* @return \think\response\Json
*/
public function profile(ProfileRequest $request)
{
return CatchResponse::success($this->user->updateBy($request->user()->id, $request->param()));
}
} }

View File

@@ -0,0 +1,42 @@
<?php
use think\migration\Migrator;
use think\migration\db\Column;
class UpdateRoles extends Migrator
{
/**
* Change Method.
*
* Write your reversible migrations using this method.
*
* More information on writing migrations is available here:
* http://docs.phinx.org/en/latest/migrations.html#the-abstractmigration-class
*
* The following commands can be used in this method and Phinx will
* automatically reverse them when rolling back:
*
* createTable
* renameTable
* addColumn
* renameColumn
* addIndex
* addForeignKey
*
* Remember to call "create()" or "update()" and NOT "save()" when working
* with the Table class.
*/
public function change()
{
if ($this->hasTable('roles')) {
$table = $this->table('roles');
$table->addColumn('identify', 'string', [
'limit' => 20,
'default' => 1,
'comment' => '角色的标识,用英文表示,用于后台路由权限',
'after' => 'role_name'])
->update();
}
}
}

View File

@@ -0,0 +1,40 @@
<?php
use think\migration\Migrator;
use think\migration\db\Column;
class UpdatePermissions extends Migrator
{
/**
* Change Method.
*
* Write your reversible migrations using this method.
*
* More information on writing migrations is available here:
* http://docs.phinx.org/en/latest/migrations.html#the-abstractmigration-class
*
* The following commands can be used in this method and Phinx will
* automatically reverse them when rolling back:
*
* createTable
* renameTable
* addColumn
* renameColumn
* addIndex
* addForeignKey
*
* Remember to call "create()" or "update()" and NOT "save()" when working
* with the Table class.
*/
public function change()
{
if ($this->hasTable('permissions')) {
$table = $this->table('permissions');
$table->removeColumn('method')
->removeColumn('hide_children_in_menu')
->renameColumn('status', 'hidden')
->update();
}
}
}

View File

@@ -0,0 +1,51 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~{$year} http://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
use think\migration\Migrator;
use think\migration\db\Column;
class AddUserAvatar extends Migrator
{
/**
* Change Method.
*
* Write your reversible migrations using this method.
*
* More information on writing migrations is available here:
* http://docs.phinx.org/en/latest/migrations.html#the-abstractmigration-class
*
* The following commands can be used in this method and Phinx will
* automatically reverse them when rolling back:
*
* createTable
* renameTable
* addColumn
* renameColumn
* addIndex
* addForeignKey
*
* Remember to call "create()" or "update()" and NOT "save()" when working
* with the Table class.
*/
public function change()
{
if ($this->hasTable('users')) {
$table = $this->table('users');
$table->addColumn('avatar', 'string', [
'limit' => 255,
'default' => '',
'comment' => '用户头像',
'after' => 'email'])
->update();
}
}
}

View File

@@ -0,0 +1,51 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~{$year} http://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
use think\migration\Migrator;
use think\migration\db\Column;
class AddUserRememberToken extends Migrator
{
/**
* Change Method.
*
* Write your reversible migrations using this method.
*
* More information on writing migrations is available here:
* http://docs.phinx.org/en/latest/migrations.html#the-abstractmigration-class
*
* The following commands can be used in this method and Phinx will
* automatically reverse them when rolling back:
*
* createTable
* renameTable
* addColumn
* renameColumn
* addIndex
* addForeignKey
*
* Remember to call "create()" or "update()" and NOT "save()" when working
* with the Table class.
*/
public function change()
{
if ($this->hasTable('users')) {
$table = $this->table('users');
$table->addColumn('remember_token', 'string', [
'limit' => 512,
'default' => '',
'comment' => '用户token',
'after' => 'avatar'])
->update();
}
}
}

View File

@@ -2,7 +2,7 @@
use think\migration\Seeder; use think\migration\Seeder;
class PermissionSeed extends Seeder class PermissionsMenusSeed extends Seeder
{ {
/** /**
* Run Method. * Run Method.
@@ -27,20 +27,18 @@ class PermissionSeed extends Seeder
'parent_id' => 0, 'parent_id' => 0,
'level' => '', 'level' => '',
'route' => '/permissions', 'route' => '/permissions',
'icon' => 'appstore', 'icon' => 'el-icon-cpu',
'module' => 'permissions', 'module' => 'permissions',
'creator_id' => 1, 'creator_id' => 1,
'method' => 'get', 'permission_mark' => 'permission',
'permission_mark' => 'permission@index', 'component' => 'layout',
'component' => 'pageView', 'redirect' => '/permissions/users',
'redirect' => '', 'hidden' => 1,
'hide_children_in_menu' => 2,
'keepalive' => 1, 'keepalive' => 1,
'type' => 1, 'type' => 1,
'status' => 1,
'sort' => 100, 'sort' => 100,
'created_at' => 1587461455, 'created_at' => 1587461455,
'updated_at' => 1593044101, 'updated_at' => 1599362429,
'deleted_at' => 0, 'deleted_at' => 0,
'children' => 'children' =>
array ( array (
@@ -51,20 +49,18 @@ class PermissionSeed extends Seeder
'parent_id' => 1, 'parent_id' => 1,
'level' => '1', 'level' => '1',
'route' => '/permissions/users', 'route' => '/permissions/users',
'icon' => 'user', 'icon' => 'el-icon-user',
'module' => 'permissions', 'module' => 'permissions',
'creator_id' => 1, 'creator_id' => 1,
'method' => 'get', 'permission_mark' => 'user',
'permission_mark' => 'user@index',
'component' => 'users', 'component' => 'users',
'redirect' => '', 'redirect' => '',
'hide_children_in_menu' => 2, 'hidden' => 1,
'keepalive' => 1, 'keepalive' => 1,
'type' => 1, 'type' => 1,
'status' => 1,
'sort' => 10, 'sort' => 10,
'created_at' => 1587461597, 'created_at' => 1587461597,
'updated_at' => 1592371975, 'updated_at' => 1599362429,
'deleted_at' => 0, 'deleted_at' => 0,
'children' => 'children' =>
array ( array (
@@ -78,17 +74,15 @@ class PermissionSeed extends Seeder
'icon' => '', 'icon' => '',
'module' => 'permissions', 'module' => 'permissions',
'creator_id' => 1, 'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'user@index', 'permission_mark' => 'user@index',
'component' => '', 'component' => '',
'redirect' => '', 'redirect' => '',
'hide_children_in_menu' => 1, 'hidden' => 1,
'keepalive' => 1, 'keepalive' => 1,
'type' => 2, 'type' => 2,
'status' => 1,
'sort' => 1, 'sort' => 1,
'created_at' => 1587461647, 'created_at' => 1587461647,
'updated_at' => 1591316160, 'updated_at' => 1599030266,
'deleted_at' => 0, 'deleted_at' => 0,
), ),
1 => 1 =>
@@ -101,17 +95,15 @@ class PermissionSeed extends Seeder
'icon' => '', 'icon' => '',
'module' => 'permissions', 'module' => 'permissions',
'creator_id' => 1, 'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'user@create', 'permission_mark' => 'user@create',
'component' => '', 'component' => '',
'redirect' => '', 'redirect' => '',
'hide_children_in_menu' => 1, 'hidden' => 1,
'keepalive' => 1, 'keepalive' => 1,
'type' => 2, 'type' => 2,
'status' => 1,
'sort' => 1, 'sort' => 1,
'created_at' => 1587461696, 'created_at' => 1587461696,
'updated_at' => 1587547118, 'updated_at' => 1599030266,
'deleted_at' => 0, 'deleted_at' => 0,
), ),
2 => 2 =>
@@ -124,17 +116,15 @@ class PermissionSeed extends Seeder
'icon' => '', 'icon' => '',
'module' => 'permissions', 'module' => 'permissions',
'creator_id' => 1, 'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'user@save', 'permission_mark' => 'user@save',
'component' => '', 'component' => '',
'redirect' => '', 'redirect' => '',
'hide_children_in_menu' => 1, 'hidden' => 1,
'keepalive' => 1, 'keepalive' => 1,
'type' => 2, 'type' => 2,
'status' => 1,
'sort' => 1, 'sort' => 1,
'created_at' => 1587461721, 'created_at' => 1587461721,
'updated_at' => 1591345475, 'updated_at' => 1599030266,
'deleted_at' => 0, 'deleted_at' => 0,
), ),
3 => 3 =>
@@ -147,17 +137,15 @@ class PermissionSeed extends Seeder
'icon' => '', 'icon' => '',
'module' => 'permissions', 'module' => 'permissions',
'creator_id' => 1, 'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'user@edit', 'permission_mark' => 'user@edit',
'component' => '', 'component' => '',
'redirect' => '', 'redirect' => '',
'hide_children_in_menu' => 1, 'hidden' => 1,
'keepalive' => 1, 'keepalive' => 1,
'type' => 2, 'type' => 2,
'status' => 1,
'sort' => 1, 'sort' => 1,
'created_at' => 1587461742, 'created_at' => 1587461742,
'updated_at' => 1591345504, 'updated_at' => 1599030266,
'deleted_at' => 0, 'deleted_at' => 0,
), ),
4 => 4 =>
@@ -170,17 +158,15 @@ class PermissionSeed extends Seeder
'icon' => '', 'icon' => '',
'module' => 'permissions', 'module' => 'permissions',
'creator_id' => 1, 'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'user@update', 'permission_mark' => 'user@update',
'component' => '', 'component' => '',
'redirect' => '', 'redirect' => '',
'hide_children_in_menu' => 1, 'hidden' => 1,
'keepalive' => 1, 'keepalive' => 1,
'type' => 2, 'type' => 2,
'status' => 1,
'sort' => 1, 'sort' => 1,
'created_at' => 1587461762, 'created_at' => 1587461762,
'updated_at' => 1587547118, 'updated_at' => 1599030266,
'deleted_at' => 0, 'deleted_at' => 0,
), ),
5 => 5 =>
@@ -193,17 +179,15 @@ class PermissionSeed extends Seeder
'icon' => '', 'icon' => '',
'module' => 'permissions', 'module' => 'permissions',
'creator_id' => 1, 'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'user@delete', 'permission_mark' => 'user@delete',
'component' => '', 'component' => '',
'redirect' => '', 'redirect' => '',
'hide_children_in_menu' => 1, 'hidden' => 1,
'keepalive' => 1, 'keepalive' => 1,
'type' => 2, 'type' => 2,
'status' => 1,
'sort' => 1, 'sort' => 1,
'created_at' => 1587461841, 'created_at' => 1587461841,
'updated_at' => 1587547118, 'updated_at' => 1599030266,
'deleted_at' => 0, 'deleted_at' => 0,
), ),
6 => 6 =>
@@ -216,17 +200,15 @@ class PermissionSeed extends Seeder
'icon' => '', 'icon' => '',
'module' => 'permissions', 'module' => 'permissions',
'creator_id' => 1, 'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'user@switchStatus', 'permission_mark' => 'user@switchStatus',
'component' => '', 'component' => '',
'redirect' => '', 'redirect' => '',
'hide_children_in_menu' => 1, 'hidden' => 1,
'keepalive' => 1, 'keepalive' => 1,
'type' => 2, 'type' => 2,
'status' => 1,
'sort' => 1, 'sort' => 1,
'created_at' => 1587461876, 'created_at' => 1587461876,
'updated_at' => 1587547118, 'updated_at' => 1599030266,
'deleted_at' => 0, 'deleted_at' => 0,
), ),
7 => 7 =>
@@ -239,17 +221,15 @@ class PermissionSeed extends Seeder
'icon' => '', 'icon' => '',
'module' => 'permissions', 'module' => 'permissions',
'creator_id' => 1, 'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'user@recover', 'permission_mark' => 'user@recover',
'component' => '', 'component' => '',
'redirect' => '', 'redirect' => '',
'hide_children_in_menu' => 1, 'hidden' => 1,
'keepalive' => 1, 'keepalive' => 1,
'type' => 2, 'type' => 2,
'status' => 1,
'sort' => 1, 'sort' => 1,
'created_at' => 1587461901, 'created_at' => 1587461901,
'updated_at' => 1587547118, 'updated_at' => 1599030266,
'deleted_at' => 0, 'deleted_at' => 0,
), ),
), ),
@@ -261,20 +241,18 @@ class PermissionSeed extends Seeder
'parent_id' => 1, 'parent_id' => 1,
'level' => '1', 'level' => '1',
'route' => '/permissions/roles', 'route' => '/permissions/roles',
'icon' => 'usergroup-add', 'icon' => 'el-icon-s-custom',
'module' => 'permissions', 'module' => 'permissions',
'creator_id' => 1, 'creator_id' => 1,
'method' => 'get', 'permission_mark' => 'role',
'permission_mark' => 'role@index',
'component' => 'roles', 'component' => 'roles',
'redirect' => '', 'redirect' => '',
'hide_children_in_menu' => 2, 'hidden' => 1,
'keepalive' => 1, 'keepalive' => 1,
'type' => 1, 'type' => 1,
'status' => 1,
'sort' => 9, 'sort' => 9,
'created_at' => 1587461939, 'created_at' => 1587461939,
'updated_at' => 1592371974, 'updated_at' => 1599362438,
'deleted_at' => 0, 'deleted_at' => 0,
'children' => 'children' =>
array ( array (
@@ -288,17 +266,15 @@ class PermissionSeed extends Seeder
'icon' => '', 'icon' => '',
'module' => 'permissions', 'module' => 'permissions',
'creator_id' => 1, 'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'role@index', 'permission_mark' => 'role@index',
'component' => '', 'component' => '',
'redirect' => '', 'redirect' => '',
'hide_children_in_menu' => 1, 'hidden' => 1,
'keepalive' => 1, 'keepalive' => 1,
'type' => 2, 'type' => 2,
'status' => 1,
'sort' => 1, 'sort' => 1,
'created_at' => 1587461984, 'created_at' => 1587461984,
'updated_at' => 1591341461, 'updated_at' => 1599362438,
'deleted_at' => 0, 'deleted_at' => 0,
), ),
1 => 1 =>
@@ -311,17 +287,15 @@ class PermissionSeed extends Seeder
'icon' => '', 'icon' => '',
'module' => 'permissions', 'module' => 'permissions',
'creator_id' => 1, 'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'role@create', 'permission_mark' => 'role@create',
'component' => '', 'component' => '',
'redirect' => '', 'redirect' => '',
'hide_children_in_menu' => 1, 'hidden' => 1,
'keepalive' => 1, 'keepalive' => 1,
'type' => 2, 'type' => 2,
'status' => 1,
'sort' => 1, 'sort' => 1,
'created_at' => 1587462007, 'created_at' => 1587462007,
'updated_at' => 1587547118, 'updated_at' => 1599362438,
'deleted_at' => 0, 'deleted_at' => 0,
), ),
2 => 2 =>
@@ -334,17 +308,15 @@ class PermissionSeed extends Seeder
'icon' => '', 'icon' => '',
'module' => 'permissions', 'module' => 'permissions',
'creator_id' => 1, 'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'role@save', 'permission_mark' => 'role@save',
'component' => '', 'component' => '',
'redirect' => '', 'redirect' => '',
'hide_children_in_menu' => 1, 'hidden' => 1,
'keepalive' => 1, 'keepalive' => 1,
'type' => 2, 'type' => 2,
'status' => 1,
'sort' => 1, 'sort' => 1,
'created_at' => 1587462021, 'created_at' => 1587462021,
'updated_at' => 1587547118, 'updated_at' => 1599362438,
'deleted_at' => 0, 'deleted_at' => 0,
), ),
3 => 3 =>
@@ -357,17 +329,15 @@ class PermissionSeed extends Seeder
'icon' => '', 'icon' => '',
'module' => 'permissions', 'module' => 'permissions',
'creator_id' => 1, 'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'role@edit', 'permission_mark' => 'role@edit',
'component' => '', 'component' => '',
'redirect' => '', 'redirect' => '',
'hide_children_in_menu' => 1, 'hidden' => 1,
'keepalive' => 1, 'keepalive' => 1,
'type' => 2, 'type' => 2,
'status' => 1,
'sort' => 1, 'sort' => 1,
'created_at' => 1587462040, 'created_at' => 1587462040,
'updated_at' => 1587547118, 'updated_at' => 1599362438,
'deleted_at' => 0, 'deleted_at' => 0,
), ),
4 => 4 =>
@@ -380,17 +350,15 @@ class PermissionSeed extends Seeder
'icon' => '', 'icon' => '',
'module' => 'permissions', 'module' => 'permissions',
'creator_id' => 1, 'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'role@update', 'permission_mark' => 'role@update',
'component' => '', 'component' => '',
'redirect' => '', 'redirect' => '',
'hide_children_in_menu' => 1, 'hidden' => 1,
'keepalive' => 1, 'keepalive' => 1,
'type' => 2, 'type' => 2,
'status' => 1,
'sort' => 1, 'sort' => 1,
'created_at' => 1587462058, 'created_at' => 1587462058,
'updated_at' => 1587547118, 'updated_at' => 1599362438,
'deleted_at' => 0, 'deleted_at' => 0,
), ),
5 => 5 =>
@@ -403,17 +371,15 @@ class PermissionSeed extends Seeder
'icon' => '', 'icon' => '',
'module' => 'permissions', 'module' => 'permissions',
'creator_id' => 1, 'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'role@delete', 'permission_mark' => 'role@delete',
'component' => '', 'component' => '',
'redirect' => '', 'redirect' => '',
'hide_children_in_menu' => 1, 'hidden' => 1,
'keepalive' => 1, 'keepalive' => 1,
'type' => 2, 'type' => 2,
'status' => 1,
'sort' => 1, 'sort' => 1,
'created_at' => 1587462070, 'created_at' => 1587462070,
'updated_at' => 1587547118, 'updated_at' => 1599362438,
'deleted_at' => 0, 'deleted_at' => 0,
), ),
6 => 6 =>
@@ -426,17 +392,15 @@ class PermissionSeed extends Seeder
'icon' => '', 'icon' => '',
'module' => 'permissions', 'module' => 'permissions',
'creator_id' => 1, 'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'role@getPermissions', 'permission_mark' => 'role@getPermissions',
'component' => '', 'component' => '',
'redirect' => '', 'redirect' => '',
'hide_children_in_menu' => 1, 'hidden' => 1,
'keepalive' => 1, 'keepalive' => 1,
'type' => 2, 'type' => 2,
'status' => 1,
'sort' => 1, 'sort' => 1,
'created_at' => 1587462094, 'created_at' => 1587462094,
'updated_at' => 1587547118, 'updated_at' => 1599362438,
'deleted_at' => 0, 'deleted_at' => 0,
), ),
), ),
@@ -448,20 +412,18 @@ class PermissionSeed extends Seeder
'parent_id' => 1, 'parent_id' => 1,
'level' => '1', 'level' => '1',
'route' => '/permissions/rules', 'route' => '/permissions/rules',
'icon' => 'build', 'icon' => 'el-icon-collection-tag',
'module' => 'permissions', 'module' => 'permissions',
'creator_id' => 1, 'creator_id' => 1,
'method' => 'get', 'permission_mark' => 'permission',
'permission_mark' => 'permission@index',
'component' => 'rules', 'component' => 'rules',
'redirect' => '', 'redirect' => '',
'hide_children_in_menu' => 2, 'hidden' => 1,
'keepalive' => 1, 'keepalive' => 1,
'type' => 1, 'type' => 1,
'status' => 1,
'sort' => 8, 'sort' => 8,
'created_at' => 1587462147, 'created_at' => 1587462147,
'updated_at' => 1592371979, 'updated_at' => 1599362475,
'deleted_at' => 0, 'deleted_at' => 0,
'children' => 'children' =>
array ( array (
@@ -475,17 +437,15 @@ class PermissionSeed extends Seeder
'icon' => '', 'icon' => '',
'module' => 'permissions', 'module' => 'permissions',
'creator_id' => 1, 'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'permission@index', 'permission_mark' => 'permission@index',
'component' => '', 'component' => '',
'redirect' => '', 'redirect' => '',
'hide_children_in_menu' => 1, 'hidden' => 1,
'keepalive' => 1, 'keepalive' => 1,
'type' => 2, 'type' => 2,
'status' => 1,
'sort' => 1, 'sort' => 1,
'created_at' => 1587462205, 'created_at' => 1587462205,
'updated_at' => 1587547118, 'updated_at' => 1599362475,
'deleted_at' => 0, 'deleted_at' => 0,
), ),
1 => 1 =>
@@ -498,17 +458,15 @@ class PermissionSeed extends Seeder
'icon' => '', 'icon' => '',
'module' => 'permissions', 'module' => 'permissions',
'creator_id' => 1, 'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'permission@create', 'permission_mark' => 'permission@create',
'component' => '', 'component' => '',
'redirect' => '', 'redirect' => '',
'hide_children_in_menu' => 1, 'hidden' => 1,
'keepalive' => 1, 'keepalive' => 1,
'type' => 2, 'type' => 2,
'status' => 1,
'sort' => 1, 'sort' => 1,
'created_at' => 1587462232, 'created_at' => 1587462232,
'updated_at' => 1587547118, 'updated_at' => 1599362475,
'deleted_at' => 0, 'deleted_at' => 0,
), ),
2 => 2 =>
@@ -521,40 +479,36 @@ class PermissionSeed extends Seeder
'icon' => '', 'icon' => '',
'module' => 'permissions', 'module' => 'permissions',
'creator_id' => 1, 'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'permission@save', 'permission_mark' => 'permission@save',
'component' => '', 'component' => '',
'redirect' => '', 'redirect' => '',
'hide_children_in_menu' => 1, 'hidden' => 1,
'keepalive' => 1, 'keepalive' => 1,
'type' => 2, 'type' => 2,
'status' => 1,
'sort' => 1, 'sort' => 1,
'created_at' => 1587462250, 'created_at' => 1587462250,
'updated_at' => 1587547118, 'updated_at' => 1599362475,
'deleted_at' => 0, 'deleted_at' => 0,
), ),
3 => 3 =>
array ( array (
'id' => 23, 'id' => 23,
'permission_name' => '查看', 'permission_name' => '禁用/启用',
'parent_id' => 19, 'parent_id' => 19,
'level' => '1-19', 'level' => '1-19',
'route' => '', 'route' => '',
'icon' => '', 'icon' => '',
'module' => 'permissions', 'module' => 'permissions',
'creator_id' => 1, 'creator_id' => 1,
'method' => 'get', 'permission_mark' => 'permission@show',
'permission_mark' => 'permission@edit',
'component' => '', 'component' => '',
'redirect' => '', 'redirect' => '',
'hide_children_in_menu' => 1, 'hidden' => 1,
'keepalive' => 1, 'keepalive' => 1,
'type' => 2, 'type' => 2,
'status' => 1,
'sort' => 1, 'sort' => 1,
'created_at' => 1587462273, 'created_at' => 1587462273,
'updated_at' => 1587547118, 'updated_at' => 1599362475,
'deleted_at' => 0, 'deleted_at' => 0,
), ),
4 => 4 =>
@@ -567,17 +521,15 @@ class PermissionSeed extends Seeder
'icon' => '', 'icon' => '',
'module' => 'permissions', 'module' => 'permissions',
'creator_id' => 1, 'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'permission@update', 'permission_mark' => 'permission@update',
'component' => '', 'component' => '',
'redirect' => '', 'redirect' => '',
'hide_children_in_menu' => 1, 'hidden' => 1,
'keepalive' => 1, 'keepalive' => 1,
'type' => 2, 'type' => 2,
'status' => 1,
'sort' => 1, 'sort' => 1,
'created_at' => 1587462284, 'created_at' => 1587462284,
'updated_at' => 1587547118, 'updated_at' => 1599362475,
'deleted_at' => 0, 'deleted_at' => 0,
), ),
5 => 5 =>
@@ -590,17 +542,36 @@ class PermissionSeed extends Seeder
'icon' => '', 'icon' => '',
'module' => 'permissions', 'module' => 'permissions',
'creator_id' => 1, 'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'permission@delete', 'permission_mark' => 'permission@delete',
'component' => '', 'component' => '',
'redirect' => '', 'redirect' => '',
'hide_children_in_menu' => 1, 'hidden' => 1,
'keepalive' => 1, 'keepalive' => 1,
'type' => 2, 'type' => 2,
'status' => 1,
'sort' => 1, 'sort' => 1,
'created_at' => 1587462296, 'created_at' => 1587462296,
'updated_at' => 1587547118, 'updated_at' => 1599362475,
'deleted_at' => 0,
),
6 =>
array (
'id' => 106,
'permission_name' => '权限方法',
'parent_id' => 19,
'level' => '1-19',
'route' => '',
'icon' => '',
'module' => 'permissions',
'creator_id' => 1,
'permission_mark' => 'permission@getMethods',
'component' => '',
'redirect' => '',
'hidden' => 1,
'keepalive' => 1,
'type' => 2,
'sort' => 1,
'created_at' => 1599221913,
'updated_at' => 1599362475,
'deleted_at' => 0, 'deleted_at' => 0,
), ),
), ),
@@ -612,20 +583,18 @@ class PermissionSeed extends Seeder
'parent_id' => 1, 'parent_id' => 1,
'level' => '1', 'level' => '1',
'route' => '/permissions/departments', 'route' => '/permissions/departments',
'icon' => 'desktop', 'icon' => 'el-icon-monitor',
'module' => 'permissions', 'module' => 'permissions',
'creator_id' => 1, 'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'departments', 'permission_mark' => 'departments',
'component' => 'departments', 'component' => 'departments',
'redirect' => '', 'redirect' => '',
'hide_children_in_menu' => 2, 'hidden' => 1,
'keepalive' => 1, 'keepalive' => 1,
'type' => 1, 'type' => 1,
'status' => 1,
'sort' => 7, 'sort' => 7,
'created_at' => 1587462488, 'created_at' => 1587462488,
'updated_at' => 1587547118, 'updated_at' => 1599362429,
'deleted_at' => 0, 'deleted_at' => 0,
'children' => 'children' =>
array ( array (
@@ -639,17 +608,15 @@ class PermissionSeed extends Seeder
'icon' => '', 'icon' => '',
'module' => 'permissions', 'module' => 'permissions',
'creator_id' => 1, 'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'department@index', 'permission_mark' => 'department@index',
'component' => '', 'component' => '',
'redirect' => '', 'redirect' => '',
'hide_children_in_menu' => 1, 'hidden' => 1,
'keepalive' => 1, 'keepalive' => 1,
'type' => 2, 'type' => 2,
'status' => 1,
'sort' => 1, 'sort' => 1,
'created_at' => 1587462529, 'created_at' => 1587462529,
'updated_at' => 1587547118, 'updated_at' => 1599030565,
'deleted_at' => 0, 'deleted_at' => 0,
), ),
1 => 1 =>
@@ -662,17 +629,15 @@ class PermissionSeed extends Seeder
'icon' => '', 'icon' => '',
'module' => 'permissions', 'module' => 'permissions',
'creator_id' => 1, 'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'department@save', 'permission_mark' => 'department@save',
'component' => '', 'component' => '',
'redirect' => '', 'redirect' => '',
'hide_children_in_menu' => 1, 'hidden' => 1,
'keepalive' => 1, 'keepalive' => 1,
'type' => 2, 'type' => 2,
'status' => 1,
'sort' => 1, 'sort' => 1,
'created_at' => 1587462548, 'created_at' => 1587462548,
'updated_at' => 1587547118, 'updated_at' => 1599030565,
'deleted_at' => 0, 'deleted_at' => 0,
), ),
2 => 2 =>
@@ -685,17 +650,15 @@ class PermissionSeed extends Seeder
'icon' => '', 'icon' => '',
'module' => 'permissions', 'module' => 'permissions',
'creator_id' => 1, 'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'department@update', 'permission_mark' => 'department@update',
'component' => '', 'component' => '',
'redirect' => '', 'redirect' => '',
'hide_children_in_menu' => 1, 'hidden' => 1,
'keepalive' => 1, 'keepalive' => 1,
'type' => 2, 'type' => 2,
'status' => 1,
'sort' => 1, 'sort' => 1,
'created_at' => 1587462579, 'created_at' => 1587462579,
'updated_at' => 1587547118, 'updated_at' => 1599030565,
'deleted_at' => 0, 'deleted_at' => 0,
), ),
3 => 3 =>
@@ -708,17 +671,15 @@ class PermissionSeed extends Seeder
'icon' => '', 'icon' => '',
'module' => 'permissions', 'module' => 'permissions',
'creator_id' => 1, 'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'department@delete', 'permission_mark' => 'department@delete',
'component' => '', 'component' => '',
'redirect' => '', 'redirect' => '',
'hide_children_in_menu' => 1, 'hidden' => 1,
'keepalive' => 1, 'keepalive' => 1,
'type' => 2, 'type' => 2,
'status' => 1,
'sort' => 1, 'sort' => 1,
'created_at' => 1587462592, 'created_at' => 1587462592,
'updated_at' => 1587547118, 'updated_at' => 1599030565,
'deleted_at' => 0, 'deleted_at' => 0,
), ),
), ),
@@ -730,20 +691,18 @@ class PermissionSeed extends Seeder
'parent_id' => 1, 'parent_id' => 1,
'level' => '1', 'level' => '1',
'route' => '/permissions/jobs', 'route' => '/permissions/jobs',
'icon' => 'skin', 'icon' => 'el-icon-setting',
'module' => 'permissions', 'module' => 'permissions',
'creator_id' => 1, 'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'job', 'permission_mark' => 'job',
'component' => 'jobs', 'component' => 'jobs',
'redirect' => '', 'redirect' => '',
'hide_children_in_menu' => 2, 'hidden' => 1,
'keepalive' => 1, 'keepalive' => 1,
'type' => 1, 'type' => 1,
'status' => 1,
'sort' => 1, 'sort' => 1,
'created_at' => 1587462707, 'created_at' => 1587462707,
'updated_at' => 1587547118, 'updated_at' => 1599362429,
'deleted_at' => 0, 'deleted_at' => 0,
'children' => 'children' =>
array ( array (
@@ -757,17 +716,15 @@ class PermissionSeed extends Seeder
'icon' => '', 'icon' => '',
'module' => 'permissions', 'module' => 'permissions',
'creator_id' => 1, 'creator_id' => 1,
'method' => 'get', 'permission_mark' => 'job@indexs',
'permission_mark' => 'job@index',
'component' => '', 'component' => '',
'redirect' => '', 'redirect' => '',
'hide_children_in_menu' => 1, 'hidden' => 2,
'keepalive' => 1, 'keepalive' => 1,
'type' => 2, 'type' => 2,
'status' => 1,
'sort' => 1, 'sort' => 1,
'created_at' => 1587462757, 'created_at' => 1587462757,
'updated_at' => 1587547118, 'updated_at' => 1598959522,
'deleted_at' => 0, 'deleted_at' => 0,
), ),
1 => 1 =>
@@ -780,17 +737,15 @@ class PermissionSeed extends Seeder
'icon' => '', 'icon' => '',
'module' => 'permissions', 'module' => 'permissions',
'creator_id' => 1, 'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'job@save', 'permission_mark' => 'job@save',
'component' => '', 'component' => '',
'redirect' => '', 'redirect' => '',
'hide_children_in_menu' => 1, 'hidden' => 2,
'keepalive' => 1, 'keepalive' => 1,
'type' => 2, 'type' => 2,
'status' => 1,
'sort' => 1, 'sort' => 1,
'created_at' => 1587462774, 'created_at' => 1587462774,
'updated_at' => 1587547118, 'updated_at' => 1598959522,
'deleted_at' => 0, 'deleted_at' => 0,
), ),
2 => 2 =>
@@ -803,17 +758,15 @@ class PermissionSeed extends Seeder
'icon' => '', 'icon' => '',
'module' => 'permissions', 'module' => 'permissions',
'creator_id' => 1, 'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'job@update', 'permission_mark' => 'job@update',
'component' => '', 'component' => '',
'redirect' => '', 'redirect' => '',
'hide_children_in_menu' => 1, 'hidden' => 2,
'keepalive' => 1, 'keepalive' => 1,
'type' => 2, 'type' => 2,
'status' => 1,
'sort' => 1, 'sort' => 1,
'created_at' => 1587462785, 'created_at' => 1587462785,
'updated_at' => 1587547118, 'updated_at' => 1598959522,
'deleted_at' => 0, 'deleted_at' => 0,
), ),
3 => 3 =>
@@ -826,17 +779,15 @@ class PermissionSeed extends Seeder
'icon' => '', 'icon' => '',
'module' => 'permissions', 'module' => 'permissions',
'creator_id' => 1, 'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'job@delete', 'permission_mark' => 'job@delete',
'component' => '', 'component' => '',
'redirect' => '', 'redirect' => '',
'hide_children_in_menu' => 1, 'hidden' => 2,
'keepalive' => 1, 'keepalive' => 1,
'type' => 2, 'type' => 2,
'status' => 1,
'sort' => 1, 'sort' => 1,
'created_at' => 1587462794, 'created_at' => 1587462794,
'updated_at' => 1587547118, 'updated_at' => 1598959522,
'deleted_at' => 0, 'deleted_at' => 0,
), ),
4 => 4 =>
@@ -849,17 +800,15 @@ class PermissionSeed extends Seeder
'icon' => '', 'icon' => '',
'module' => 'permissions', 'module' => 'permissions',
'creator_id' => 1, 'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'job@getAll', 'permission_mark' => 'job@getAll',
'component' => '', 'component' => '',
'redirect' => '', 'redirect' => '',
'hide_children_in_menu' => 1, 'hidden' => 2,
'keepalive' => 1, 'keepalive' => 1,
'type' => 2, 'type' => 2,
'status' => 1,
'sort' => 1, 'sort' => 1,
'created_at' => 1587462818, 'created_at' => 1587462818,
'updated_at' => 1587547118, 'updated_at' => 1598959522,
'deleted_at' => 0, 'deleted_at' => 0,
), ),
), ),

View File

@@ -24,7 +24,9 @@ class RolesSeed extends Seeder
{ {
\catchAdmin\permissions\model\Roles::create([ \catchAdmin\permissions\model\Roles::create([
'role_name' => '超级管理员', 'role_name' => '超级管理员',
'identify' => 'admin',
'description' => 'super user', 'description' => 'super user',
'data_range' => 1,
'creator_id' => 1, 'creator_id' => 1,
]); ]);

View File

@@ -16,8 +16,8 @@ class UsersSeed extends Seeder
{ {
return \catchAdmin\permissions\model\Users::create([ return \catchAdmin\permissions\model\Users::create([
'username' => 'admin', 'username' => 'admin',
'password' => 'admin', 'password' => 'catchadmin',
'email' => 'admin@gmail.com', 'email' => 'catch@admin.com',
'creator_id' => 1, 'creator_id' => 1,
]); ]);
} }

View File

@@ -0,0 +1,78 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2020 http://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
namespace catchAdmin\permissions\excel;
use catchAdmin\permissions\model\Users;
use catcher\library\excel\ExcelContract;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
class UserExport implements ExcelContract
{
/**
* 设置头部
*
* @time 2020年09月08日
* @return string[]
*/
public function headers(): array
{
// TODO: Implement headers() method.
return [
'id', '用户名', '邮箱', '状态', '创建日期'
];
}
/**
* 处理数据
*
* @time 2020年09月08日
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @return \think\Collection
*/
public function sheets()
{
// TODO: Implement sheets() method.
$users = Users::field(['id', 'username', 'email', 'status', 'created_at'])->select();
foreach ($users as &$user) {
$user->status = $user->status == Users::ENABLE ? '启用' : '停用';
}
return $users;
}
/**
* 设置开始行
*
* @time 2020年09月08日
* @return int
*/
public function setRow()
{
return 2;
}
/**
* 设置标题
*
* @time 2020年09月08日
* @return array
*/
public function setTitle()
{
return [
'A1:G1', '导出用户', Alignment::HORIZONTAL_CENTER
];
}
}

View File

@@ -32,6 +32,7 @@ class PermissionsMiddleware
// 模块忽略 // 模块忽略
[$module, $controller, $action] = Utils::parseRule($rule); [$module, $controller, $action] = Utils::parseRule($rule);
// toad // toad
if (in_array($module, $this->ignoreModule())) { if (in_array($module, $this->ignoreModule())) {
return $next($request); return $next($request);
@@ -42,11 +43,11 @@ class PermissionsMiddleware
throw new PermissionForbiddenException('Login is invalid', Code::LOST_LOGIN); throw new PermissionForbiddenException('Login is invalid', Code::LOST_LOGIN);
} }
// 超级管理员 // 超级管理员
if ($request->user()->id === config('catch.permissions.super_admin_id')) { if (Utils::isSuperAdmin()) {
return $next($request); return $next($request);
} }
// Get 请求 // Get 请求
if ($request->isGet() && config('catch.permissions.is_allow_get')) { if ($this->allowGet($request)) {
return $next($request); return $next($request);
} }
// 判断权限 // 判断权限
@@ -106,4 +107,21 @@ class PermissionsMiddleware
'permission' => $permission, 'permission' => $permission,
]); ]);
} }
/**
* get allow
*
* @time 2020年10月12日
* @param $request
* @return bool
* @throws \ReflectionException
*/
protected function allowGet($request)
{
if (Utils::isMethodNeedAuth($request->rule()->getName())) {
return false;
}
return $request->isGet() && config('catch.permissions.is_allow_get');
}
} }

View File

@@ -13,7 +13,7 @@ trait DataRangScopeTrait
* @author JaguarJack <njphper@gmail.com> * @author JaguarJack <njphper@gmail.com>
* @date 2020/6/6 * @date 2020/6/6
*/ */
protected function dataRange($roles) public function dataRange($roles = [])
{ {
if (Utils::isSuperAdmin()) { if (Utils::isSuperAdmin()) {
return $this; return $this;
@@ -44,6 +44,10 @@ trait DataRangScopeTrait
$user = request()->user(); $user = request()->user();
if (empty($roles)) {
$roles = $user->getRoles();
}
foreach ($roles as $role) { foreach ($roles as $role) {
switch ($role->data_range) { switch ($role->data_range) {
case Roles::ALL_DATA: case Roles::ALL_DATA:
@@ -57,6 +61,11 @@ trait DataRangScopeTrait
$userIds[] = $user->id; $userIds[] = $user->id;
break; break;
case Roles::DEPARTMENT_DOWN_DATA: case Roles::DEPARTMENT_DOWN_DATA:
// 查一下下级部门
$departmentIds = Department::where('parent_id', $user->department_id)->column('id');
$departmentIds[] = $user->department_id;
$userIds = array_merge([$user->id], $this->getUserIdsByDepartmentId($departmentIds));
break;
case Roles::DEPARTMENT_DATA: case Roles::DEPARTMENT_DATA:
$userIds = array_merge($userIds, $this->getUserIdsByDepartmentId([$user->department_id])); $userIds = array_merge($userIds, $this->getUserIdsByDepartmentId([$user->department_id]));
break; break;

View File

@@ -3,6 +3,7 @@ namespace catchAdmin\permissions\model;
use catchAdmin\permissions\model\search\DepartmentSearch; use catchAdmin\permissions\model\search\DepartmentSearch;
use catcher\base\CatchModel; use catcher\base\CatchModel;
use think\db\exception\DbException;
class Department extends CatchModel class Department extends CatchModel
{ {
@@ -29,16 +30,32 @@ class Department extends CatchModel
* 列表数据 * 列表数据
* *
* @time 2020年01月09日 * @time 2020年01月09日
* @param $params
* @return array * @return array
* @throws \think\db\exception\DbException * @throws DbException
*/ */
public function getList(): array public function getList(): array
{ {
return $this->withoutField(['department_name']) return $this->catchSearch()
->addFields(['department_name as title'])
->catchSearch()
->catchOrder() ->catchOrder()
->select()->toArray(); ->select()->toTree();
}
/**
* 获取子部门IDS
*
* @time 2020年11月04日
* @param $id
* @throws DbException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @return mixed
*/
public static function getChildrenDepartmentIds($id)
{
$departmentIds = Department::field(['id', 'parent_id'])->select()->getAllChildrenIds([$id]);
$departmentIds[] = $id;
return $departmentIds;
} }
} }

View File

@@ -19,12 +19,10 @@ class Permissions extends CatchModel
'component', // 组件 'component', // 组件
'redirect', 'redirect',
'keepalive', 'keepalive',
'hide_children_in_menu',
'creator_id', 'creator_id',
'status', 'hidden',
'module', // 模块 'module', // 模块
'route', // 路由 'route', // 路由
'method', // 请求方法
'permission_mark', // 权限标识 'permission_mark', // 权限标识
'type', // 1 菜单 2 按钮 'type', // 1 菜单 2 按钮
'sort', // 排序字段 'sort', // 排序字段
@@ -71,7 +69,7 @@ class Permissions extends CatchModel
return parent::whereIn('id', $permissionIds) return parent::whereIn('id', $permissionIds)
->field(['permission_name as title', 'id', 'parent_id', ->field(['permission_name as title', 'id', 'parent_id',
'route', 'icon', 'component', 'redirect', 'module', 'route', 'icon', 'component', 'redirect', 'module',
'keepalive as keepAlive', 'hide_children_in_menu', 'type', 'permission_mark', 'status' 'keepalive as keepAlive', 'type', 'permission_mark', 'hidden'
]) ])
->catchOrder() ->catchOrder()
->select(); ->select();
@@ -101,4 +99,44 @@ class Permissions extends CatchModel
return true; return true;
} }
public function show($id)
{
$permission = $this->findBy($id);
// 不能使用改属性判断,模型有该属性,使用数组方式
// $permission->hidden
$hidden = $permission['hidden'] == Permissions::ENABLE ? Permissions::DISABLE : Permissions::ENABLE;
$nextLevelIds = $this->getNextLevel([$id]);
$nextLevelIds[] = $id;
return $this->whereIn('id', $nextLevelIds)->update([
'hidden' => $hidden,
'updated_at' => time(),
]);
}
/**
* 获取 level ids
*
* @time 2020年09月06日
* @param array $id
* @param array $ids
* @return array
*/
protected function getNextLevel(array $id, &$ids = [])
{
$_ids = $this->whereIn('parent_id', $id)
->where('type', self::MENU_TYPE)
->column('id');
if (count($_ids)) {
$ids = array_merge($_ids, $this->getNextLevel($_ids, $ids));
}
return $ids;
}
} }

View File

@@ -21,6 +21,7 @@ class Roles extends CatchModel
protected $field = [ protected $field = [
'id', // 'id', //
'role_name', // 角色名 'role_name', // 角色名
'identify', // 身份标识
'parent_id', // 父级ID 'parent_id', // 父级ID
'creator_id', // 创建者 'creator_id', // 创建者
'data_range', // 数据范围 'data_range', // 数据范围
@@ -36,7 +37,7 @@ class Roles extends CatchModel
return $this->catchSearch() return $this->catchSearch()
->order('id', 'desc') ->order('id', 'desc')
->select() ->select()
->toArray(); ->toTree();
} }
/** /**

View File

@@ -19,6 +19,8 @@ class Users extends CatchModel
'username', // 用户名 'username', // 用户名
'password', // 用户密码 'password', // 用户密码
'email', // 邮箱 登录 'email', // 邮箱 登录
'avatar', // 头像
'remember_token',
'creator_id', // 创建者ID 'creator_id', // 创建者ID
'department_id', // 部门ID 'department_id', // 部门ID
'status', // 用户状态 1 正常 2 禁用 'status', // 用户状态 1 正常 2 禁用
@@ -27,7 +29,6 @@ class Users extends CatchModel
'created_at', // 创建时间 'created_at', // 创建时间
'updated_at', // 更新时间 'updated_at', // 更新时间
'deleted_at', // 删除状态0未删除 >0 已删除 'deleted_at', // 删除状态0未删除 >0 已删除
]; ];
/** /**

View File

@@ -1,6 +1,8 @@
<?php <?php
namespace catchAdmin\permissions\model\search; namespace catchAdmin\permissions\model\search;
use catchAdmin\permissions\model\Department;
trait UserSearch trait UserSearch
{ {
public function searchUsernameAttr($query, $value, $data) public function searchUsernameAttr($query, $value, $data)
@@ -18,8 +20,20 @@ trait UserSearch
return $query->where($this->aliasField('status'), $value); return $query->where($this->aliasField('status'), $value);
} }
/**
* 查询部门下的用户
*
* @time 2020年11月04日
* @param $query
* @param $value
* @param $data
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @return mixed
*/
public function searchDepartmentIdAttr($query, $value, $data) public function searchDepartmentIdAttr($query, $value, $data)
{ {
return $query->where($this->aliasField('department_id'), $value); return $query->whereIn($this->aliasField('department_id'), Department::getChildrenDepartmentIds($value));
} }
} }

View File

@@ -4,7 +4,7 @@
"description": "权限管理模块", "description": "权限管理模块",
"version": "1.0.0", "version": "1.0.0",
"keywords": [], "keywords": [],
"order": 2, "order": 100,
"services": [ "services": [
"\\catchAdmin\\permissions\\PermissionService" "\\catchAdmin\\permissions\\PermissionService"
], ],

View File

@@ -17,7 +17,7 @@ class CreateRequest extends CatchRequest
]; ];
} }
protected function message(): array protected function message()
{ {
// TODO: Implement message() method. // TODO: Implement message() method.
} }

View File

@@ -0,0 +1,17 @@
<?php
namespace catchAdmin\permissions\request;
use catchAdmin\permissions\model\Users;
use catcher\base\CatchRequest;
class ProfileRequest extends CatchRequest
{
protected function rules(): array
{
// TODO: Implement rules() method.
return [
'username|用户名' => 'require|max:20',
'email|邮箱' => 'require|email|unique:'.Users::class . ',email,' . $this->user()->id,
];
}
}

View File

@@ -15,9 +15,4 @@ class UpdateRequest extends CatchRequest
'email|邮箱' => 'require|email|unique:'.Users::class, 'email|邮箱' => 'require|email|unique:'.Users::class,
]; ];
} }
protected function message(): array
{
// TODO: Implement message() method.
}
} }

View File

@@ -11,16 +11,17 @@ $router->group(function () use ($router){
// 部门 // 部门
$router->resource('departments', '\catchAdmin\permissions\controller\Department'); $router->resource('departments', '\catchAdmin\permissions\controller\Department');
// 所有职位
$router->get('jobs/all', '\catchAdmin\permissions\controller\Job@getAll');
// 岗位 // 岗位
$router->resource('jobs', '\catchAdmin\permissions\controller\Job'); $router->resource('jobs', '\catchAdmin\permissions\controller\Job');
$router->get('jobs/all', '\catchAdmin\permissions\controller\Job@getAll');
// 用户 // 用户
$router->resource('users', '\catchAdmin\permissions\controller\User'); $router->resource('users', '\catchAdmin\permissions\controller\User');
// 切换状态 // 切换状态
$router->put('users/switch/status/<id>', '\catchAdmin\permissions\controller\User@switchStatus'); $router->put('users/switch/status/<id>', '\catchAdmin\permissions\controller\User@switchStatus');
$router->put('users/recover/<id>', '\catchAdmin\permissions\controller\User@recover'); $router->put('users/recover/<id>', '\catchAdmin\permissions\controller\User@recover');
$router->put('user/profile', '\catchAdmin\permissions\controller\User@profile');
$router->get('users/get/roles', '\catchAdmin\permissions\controller\User@getRoles'); $router->get('users/get/roles', '\catchAdmin\permissions\controller\User@getRoles');
$router->get('user/info', '\catchAdmin\permissions\controller\User@info'); $router->get('user/info', '\catchAdmin\permissions\controller\User@info');
$router->get('user/export', '\catchAdmin\permissions\controller\User@export');
})->middleware('auth'); })->middleware('auth');

226
catch/sms/Sms.php Normal file
View File

@@ -0,0 +1,226 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2020 http://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
namespace catchAdmin\sms;
use catchAdmin\sms\model\SmsConfig;
use catcher\exceptions\FailedException;
use Overtrue\EasySms\EasySms;
use think\helper\Str;
class Sms
{
/**
* timeout http 请求时间
*
* @var int
*/
protected $timeout = 5;
/**
* 错误日志
*
* @var string
*/
protected $errorLog;
/**
* 网关
*
* @var array
*/
protected $gateways = [];
/**
* 配置
*
* @var array
*/
protected $config = [];
/**
* 发送数据
*
* @var array
*/
protected $sendData = [];
/**
* Sms constructor.
* @param $config
*/
public function __construct(array $config)
{
$config['timeout'] = $this->timeout;
$config['gateways']['errorlog'] = runtime_path('log') . 'sms.log';
$this->config = $config;
}
/**
* 发送
*
* @time 2020年09月17日
* @param string $phone
* @param array $data
* @return mixed
* @throws \Overtrue\EasySms\Exceptions\NoGatewayAvailableException
* @throws \Overtrue\EasySms\Exceptions\InvalidArgumentException
*/
public function send(string $phone, array $data)
{
try {
$this->sendData['data'] = $data;
return $this->easySms()
->send($phone, $this->sendData);
} catch (\Exception $exception) {
throw new FailedException($exception->getMessage());
}
}
/**
* easy sms
*
* @time 2020年09月17日
* @return EasySms
*/
public function easySms()
{
return new EasySms($this->config);
}
/**
* 内容
*
* @time 2020年09月17日
* @param $content
* @param string $key
* @return $this
*/
public function content($content, $key = 'content')
{
$this->sendData[$key] = $content;
return $this;
}
/**
* 模版
*
* @time 2020年09月17日
* @param $template
* @param string $key
* @return $this
*/
public function template($template, $key = 'template')
{
$this->sendData[$key] = $template;
return $this;
}
/**
* 超时间时间 s
*
* @time 2020年09月17日
* @param int $timeout
* @return $this
*/
public function timeout(int $timeout)
{
$this->config['timeout'] = $timeout;
return $this;
}
/**
* 记录记录地址
*
* @time 2020年09月17日
* @param string $log
* @return $this
*/
public function errorLog(string $log)
{
$this->config['gateways']['errorlog'] = $log;
return $this;
}
/**
* gateways config
*
* @time 2020年09月17日
* @param $gateways
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @return array
*/
protected static function getGatewaysConfig($gateways)
{
$gatewaysConfig = [];
$smsConfig = new SmsConfig();
foreach ($gateways as $gate) {
$c = $smsConfig->findByName($gate);
if ($c) {
$c->hasConfig()
->select()
->each(function ($item) use (&$gatewaysConfig, $gate){
$gatewaysConfig[$gate][$item['key']] = $item['value'];
});
}
}
return $gatewaysConfig;
}
/**
* sms
*
* @time 2020年09月17日
* @param $method
* @param $arg
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @return Sms
*/
public static function __callStatic($method, $arg)
{
$gateways = Str::snake($method);
if (Str::contains($gateways, '_')) {
$gateways = explode('_', $gateways);
} else {
$gateways = [$gateways];
}
$config = [
'default' => [
'gateways' => $gateways,
],
'gateways' => static::getGatewaysConfig($gateways)
];
return new self($config);
}
}

23
catch/sms/SmsService.php Normal file
View File

@@ -0,0 +1,23 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~{$year} http://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
namespace catchAdmin\sms;
use catcher\ModuleService;
class SmsService extends ModuleService
{
public function loadRouteFrom()
{
// TODO: Implement loadRouteFrom() method.
return __DIR__ . DIRECTORY_SEPARATOR . 'route.php';
}
}

View File

@@ -0,0 +1,89 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2020 http://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
namespace catchAdmin\sms\controller;
use catcher\base\CatchRequest as Request;
use catcher\CatchResponse;
use catcher\base\CatchController;
use catchAdmin\sms\model\SmsConfig as SmsConfigModel;
class Config extends CatchController
{
protected $model;
public function __construct(SmsConfigModel $model)
{
$this->model = $model;
}
/**
* 列表
*
* @time 2020/09/16 17:28
*
* @return \think\Response
*/
public function index()
{
return CatchResponse::paginate($this->model->getList());
}
/**
* 保存
*
* @time 2020/09/16 17:28
* @param Request Request
* @return \think\Response
*/
public function save(Request $request)
{
return CatchResponse::success($this->model->storeBy($request->param()));
}
/**
* 读取
*
* @time 2020/09/16 17:28
* @param $id
* @return \think\Response
*/
public function read($id)
{
return CatchResponse::success($this->model->findBy($id));
}
/**
* 更新
*
* @time 2020/09/16 17:28
* @param Request $request
* @return \think\Response
*/
public function update(Request $request, $id)
{
return CatchResponse::success($this->model->updateBy($id, $request->post()));
}
/**
* 删除
*
* @time 2020/09/16 17:28
* @param $id
* @return \think\Response
*/
public function delete($id)
{
return CatchResponse::success($this->model->deleteBy($id));
}
}

View File

@@ -0,0 +1,86 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2020 http://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
namespace catchAdmin\sms\controller;
use catcher\base\CatchRequest as Request;
use catcher\CatchResponse;
use catcher\base\CatchController;
use catchAdmin\sms\model\SmsTemplate as SmsTemplateModel;
class Template extends CatchController
{
protected $model;
public function __construct(SmsTemplateModel $model)
{
$this->model = $model;
}
/**
* 列表
*
* @time 2020/09/16 17:28
*
* @return \think\Response
*/
public function index()
{
return CatchResponse::success($this->model->getList());
}
/**
* 保存
*
* @time 2020/09/16 17:28
* @param Request Request
* @return \think\Response
*/
public function save(Request $request)
{
return CatchResponse::success($this->model->storeBy($request->param()));
}
/**
* 读取
*
* @time 2020/09/16 17:28
* @param $id
* @return \think\Response
*/
public function read($id)
{
return CatchResponse::success($this->model->findBy($id));
}
/**
* 更新
*
* @time 2020/09/16 17:28
* @param Request $request
* @return \think\Response
*/
public function update(Request $request, $id)
{
return CatchResponse::success($this->model->updateBy($id, $request->post()));
}
/**
* 删除
*
* @time 2020/09/16 17:28
* @param $id
* @return \think\Response
*/
public function delete($id)
{
return CatchResponse::success($this->model->deleteBy($id));
}
}

View File

@@ -0,0 +1,43 @@
<?php
use think\migration\Migrator;
use think\migration\db\Column;
use Phinx\Db\Adapter\MysqlAdapter;
class SmsConfig extends Migrator
{
/**
* Change Method.
*
* Write your reversible migrations using this method.
*
* More information on writing migrations is available here:
* http://docs.phinx.org/en/latest/migrations.html#the-abstractmigration-class
*
* The following commands can be used in this method and Phinx will
* automatically reverse them when rolling back:
*
* createTable
* renameTable
* addColumn
* renameColumn
* addIndex
* addForeignKey
*
* Remember to call "create()" or "update()" and NOT "save()" when working
* with the Table class.
*/
public function change()
{
$table = $this->table('sms_config', ['engine' => 'InnoDB', 'collation' => 'utf8mb4_general_ci', 'comment' => 'sms 配置' ,'id' => 'id','signed' => true ,'primary_key' => ['id']]);
$table->addColumn('name', 'string', ['limit' => 50,'null' => true,'signed' => false,'comment' => '运营商名称',])
->addColumn('pid', 'integer', ['limit' => MysqlAdapter::INT_SMALL,'null' => false,'default' => 0,'signed' => false,'comment' => '父级ID',])
->addColumn('key', 'string', ['limit' => 100,'null' => false,'default' => '','signed' => false,'comment' => 'key',])
->addColumn('value', 'string', ['limit' => 255,'null' => false,'default' => '','signed' => false,'comment' => 'value',])
->addColumn('creator_id', 'integer', ['limit' => MysqlAdapter::INT_REGULAR,'null' => false,'default' => 0,'signed' => true,'comment' => '创建人ID',])
->addColumn('created_at', 'integer', ['limit' => MysqlAdapter::INT_REGULAR,'null' => false,'default' => 0,'signed' => true,'comment' => '创建时间',])
->addColumn('updated_at', 'integer', ['limit' => MysqlAdapter::INT_REGULAR,'null' => false,'default' => 0,'signed' => true,'comment' => '更新时间',])
->addColumn('deleted_at', 'integer', ['limit' => MysqlAdapter::INT_REGULAR,'null' => false,'default' => 0,'signed' => true,'comment' => '软删除',])
->create();
}
}

View File

@@ -0,0 +1,43 @@
<?php
use think\migration\Migrator;
use think\migration\db\Column;
use Phinx\Db\Adapter\MysqlAdapter;
class SmsTemplate extends Migrator
{
/**
* Change Method.
*
* Write your reversible migrations using this method.
*
* More information on writing migrations is available here:
* http://docs.phinx.org/en/latest/migrations.html#the-abstractmigration-class
*
* The following commands can be used in this method and Phinx will
* automatically reverse them when rolling back:
*
* createTable
* renameTable
* addColumn
* renameColumn
* addIndex
* addForeignKey
*
* Remember to call "create()" or "update()" and NOT "save()" when working
* with the Table class.
*/
public function change()
{
$table = $this->table('sms_template', ['engine' => 'InnoDB', 'collation' => 'utf8mb4_general_ci', 'comment' => '短信模版' ,'id' => 'id','signed' => true ,'primary_key' => ['id']]);
$table->addColumn('operator', 'string', ['limit' => 50,'null' => false,'default' => '','signed' => false,'comment' => '运营商',])
->addColumn('name', 'string', ['limit' => 50,'null' => false,'default' => '','signed' => false,'comment' => '模版名称',])
->addColumn('identify', 'string', ['limit' => 50,'null' => false,'default' => '','signed' => false,'comment' => '模版标识',])
->addColumn('code', 'string', ['limit' => 100,'null' => false,'default' => '','signed' => false,'comment' => '模版CODE',])
->addColumn('creator_id', 'integer', ['limit' => MysqlAdapter::INT_REGULAR,'null' => false,'default' => 0,'signed' => true,'comment' => '创建人ID',])
->addColumn('created_at', 'integer', ['limit' => MysqlAdapter::INT_REGULAR,'null' => false,'default' => 0,'signed' => true,'comment' => '创建时间',])
->addColumn('updated_at', 'integer', ['limit' => MysqlAdapter::INT_REGULAR,'null' => false,'default' => 0,'signed' => true,'comment' => '更新时间',])
->addColumn('deleted_at', 'integer', ['limit' => MysqlAdapter::INT_REGULAR,'null' => false,'default' => 0,'signed' => true,'comment' => '软删除',])
->create();
}
}

View File

@@ -0,0 +1,79 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~{$year} http://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
use think\migration\Seeder;
class SmsMenusSeed extends Seeder
{
/**
* Run Method.
*
* Write your database seeder using this method.
*
* More information on writing seeders is available here:
* http://docs.phinx.org/en/latest/seeding.html
*/
public function run()
{
\catcher\Utils::importTreeData($this->getPermissions(), 'permissions', 'parent_id');
}
protected function getPermissions()
{
return array (
0 =>
array (
'id' => 113,
'permission_name' => '短信管理',
'parent_id' => 0,
'level' => '',
'route' => '/sms',
'icon' => 'el-icon-s-promotion',
'module' => 'sms',
'creator_id' => 1,
'permission_mark' => 'sms',
'component' => 'layout',
'redirect' => '',
'keepalive' => 1,
'type' => 1,
'hidden' => 1,
'sort' => 1,
'created_at' => 1600229598,
'updated_at' => 1600229598,
'deleted_at' => 0,
'children' =>
array (
0 =>
array (
'id' => 114,
'permission_name' => '短信配置',
'parent_id' => 113,
'level' => '113',
'route' => '/sms/config',
'icon' => 'el-icon-copy-document',
'module' => 'sms',
'creator_id' => 1,
'permission_mark' => 'sms',
'component' => 'sms',
'redirect' => '',
'keepalive' => 1,
'type' => 1,
'hidden' => 1,
'sort' => 1,
'created_at' => 1600229654,
'updated_at' => 1600229778,
'deleted_at' => 0,
),
),
),
);
}
}

View File

@@ -0,0 +1,141 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2020 http://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
namespace catchAdmin\sms\model;
use catcher\base\CatchModel as Model;
class SmsConfig extends Model
{
protected $name = 'sms_config';
protected $field = [
'id', //
'name', // 运营商名称
'pid', // 父级ID
'key', // key
'value', // value
'creator_id', // 创建人ID
'created_at', // 创建时间
'updated_at', // 更新时间
'deleted_at', // 软删除
];
public function hasConfig()
{
return $this->hasMany(SmsConfig::class, 'pid', 'id');
}
/**
* 保存
*
* @time 2020年09月16日
* @param array $data
* @return bool|int
*/
public function storeBy(array $data)
{
$config = $this->findByName($data['name']);
if ($config) {
unset($data['name']);
$hasConfig = $config->hasConfig()->select();
if (empty($hasConfig)) {
return $this->insertConfig($config->id, $data);
}
$this->deleteBy(array_column($hasConfig->toArray(), 'id'), true);
$this->insertConfig($config->id, $data);
return true;
}
if (parent::storeBy([
'name' => $data['name']
])) {
unset($data['name']);
$this->insertConfig($this->id, $data);
return true;
}
}
/**
* 新增配置
*
* @time 2020年09月16日
* @param $pid
* @param $data
* @return int
*/
protected function insertConfig($pid, $data)
{
$config = [];
$creatorId = $data['creator_id'];
unset($data['creator_id']);
foreach ($data as $k => $v) {
$config[] = [
'key' => $k,
'value' => $v,
'pid' => $pid,
'creator_id' => $creatorId,
'created_at' => time(),
'updated_at' => time(),
];
}
return $this->insertAll($config);
}
/**
* 根据 name 查找
*
* @time 2020年09月16日
* @param $name
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @return array|\think\Model|null
*/
public function findByName($name)
{
return $this->where('name', $name)->find();
}
/**
* 查找配置
*
* @time 2020年09月16日
* @param $id
* @param array|string[] $field
* @param false $trash
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @return array|mixed
*/
public function findBy($id, array $field = ['*'], $trash = false)
{
$config = [];
if (!$this->findByName($id)) {
return [];
}
$this->findByName($id)
->hasConfig()
->select()
->each(function ($item) use (&$config){
$config[$item['key']] = $item['value'];
});
return $config;
}
}

View File

@@ -0,0 +1,37 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2020 http://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
namespace catchAdmin\sms\model;
use catchAdmin\sms\model\search\SmsTemplateSearch;
use catcher\base\CatchModel as Model;
class SmsTemplate extends Model
{
use SmsTemplateSearch;
protected $name = 'sms_template';
protected $field = [
'id', //
'operator', // 运营商
'name', // 模版名称
'identify', // 模版标识
'code', // 模版CODE
'creator_id', // 创建人ID
'created_at', // 创建时间
'updated_at', // 更新时间
'deleted_at', // 软删除
];
protected $paginate = false;
}

View File

@@ -0,0 +1,19 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2020 http://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
namespace catchAdmin\sms\model\search;
trait SmsTemplateSearch
{
public function searchOperatorAttr($query, $value, $data)
{
return $query->where('operator', $value);
}
}

15
catch/sms/module.json Normal file
View File

@@ -0,0 +1,15 @@
{
"name": "短信模块",
"alias": "sms",
"description": "短信sms阿里大于",
"version": "1.0.0",
"keywords": [],
"order": 0,
"services": [
"\\catchAdmin\\sms\\SmsService"
],
"aliases": {},
"files": [],
"requires": [],
"enable": false
}

18
catch/sms/route.php Normal file
View File

@@ -0,0 +1,18 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~{$year} http://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
// you should use `$router`
$router->group('sms', function () use ($router){
// config路由
$router->resource('config', '\catchAdmin\sms\controller\Config');
// template 路由
$router->resource('template', '\catchAdmin\sms\controller\Template');
})->middleware('auth');

View File

@@ -11,6 +11,8 @@
namespace catchAdmin\system; namespace catchAdmin\system;
use catchAdmin\system\events\AttachmentEvent; use catchAdmin\system\events\AttachmentEvent;
use catcher\command\MigrateRunCommand;
use catcher\command\SeedRunCommand;
use catcher\ModuleService; use catcher\ModuleService;
class SystemService extends ModuleService class SystemService extends ModuleService
@@ -28,4 +30,12 @@ class SystemService extends ModuleService
'attachment' => [ AttachmentEvent::class ], 'attachment' => [ AttachmentEvent::class ],
]; ];
} }
protected function registerCommands()
{
$this->commands([
MigrateRunCommand::class,
SeedRunCommand::class,
]);
}
} }

View File

@@ -5,7 +5,7 @@ use catcher\base\CatchController;
use catcher\CatchResponse; use catcher\CatchResponse;
use catchAdmin\system\model\Attachments as AttachmentsModel; use catchAdmin\system\model\Attachments as AttachmentsModel;
use catcher\Utils; use catcher\Utils;
use think\facade\Filesystem; use catcher\facade\FileSystem;
class Attachments extends CatchController class Attachments extends CatchController
{ {
@@ -39,7 +39,15 @@ class Attachments extends CatchController
if ($model->deleteBy($id)) { if ($model->deleteBy($id)) {
foreach ($attachments as $attachment) { foreach ($attachments as $attachment) {
Filesystem::delete($attachment->path); if ($attachment->driver == 'local') {
$localPath = config('filesystem.disks.local.root') . DIRECTORY_SEPARATOR;
$path = $localPath . str_replace('\\','\/', $attachment->path);
if (FileSystem::exists($path)) {
Filesystem::delete($path);
}
} else {
Filesystem::delete($attachment->path);
}
} }
} }

View File

@@ -7,7 +7,6 @@ use catcher\CatchResponse;
use catcher\exceptions\FailedException; use catcher\exceptions\FailedException;
use catcher\library\BackUpDatabase; use catcher\library\BackUpDatabase;
use think\Collection; use think\Collection;
use think\facade\Console;
use think\facade\Db; use think\facade\Db;
use think\Paginator; use think\Paginator;
@@ -24,7 +23,7 @@ class DataDictionary extends CatchController
$tables = Db::query('show table status'); $tables = Db::query('show table status');
// 重组数据 // 重组数据
foreach ($tables as $key => &$table) { foreach ($tables as &$table) {
$table = array_change_key_case($table); $table = array_change_key_case($table);
$table['index_length'] = $table['index_length'] > 1024 ? intval($table['index_length']/1024) .'MB' : $table['index_length'].'KB'; $table['index_length'] = $table['index_length'] > 1024 ? intval($table['index_length']/1024) .'MB' : $table['index_length'].'KB';
$table['data_length'] = $table['data_length'] > 1024 ? intval($table['data_length']/1024) .'MB' : $table['data_length'].'KB'; $table['data_length'] = $table['data_length'] > 1024 ? intval($table['data_length']/1024) .'MB' : $table['data_length'].'KB';
@@ -41,8 +40,10 @@ class DataDictionary extends CatchController
if ($engine = $request->get('engine', null)) { if ($engine = $request->get('engine', null)) {
$tables = $tables->where('engine', $engine)->values(); $tables = $tables->where('engine', $engine)->values();
} }
$page = $request->get('page', 1) ? : 1;
$limit = $request->get('limit', 10);
return CatchResponse::paginate(Paginator::make($tables->toArray(), $request->get('limit') ?? 10, $request->get('page') ?? 1, $tables->count(), false, [])); return CatchResponse::paginate(Paginator::make(array_slice($tables->toArray(), ($page - 1) * $limit, $limit), $limit, $page, $tables->count(), false, []));
} }
/** /**

View File

@@ -3,6 +3,7 @@ namespace catchAdmin\system\controller;
use catcher\base\CatchController; use catcher\base\CatchController;
use catcher\CatchResponse; use catcher\CatchResponse;
use catcher\generate\CreateModule;
use catcher\generate\Generator; use catcher\generate\Generator;
use think\Request; use think\Request;
@@ -25,4 +26,10 @@ class Generate extends CatchController
{ {
return CatchResponse::success($generator->preview($request->param())); return CatchResponse::success($generator->preview($request->param()));
} }
public function createModule(Request $request, CreateModule $module)
{
return CatchResponse::success($module->generate($request->post()));
}
} }

View File

@@ -4,7 +4,6 @@ namespace catchAdmin\system\controller;
use catcher\base\CatchController; use catcher\base\CatchController;
use catcher\CatchResponse; use catcher\CatchResponse;
use think\facade\Db;
use catchAdmin\system\model\LoginLog as Log; use catchAdmin\system\model\LoginLog as Log;
class LoginLog extends CatchController class LoginLog extends CatchController
@@ -26,11 +25,12 @@ class LoginLog extends CatchController
* *
* @time 2020年04月28日 * @time 2020年04月28日
* @param Log $log * @param Log $log
* @param $id
* @throws \Exception * @throws \Exception
* @return \think\response\Json * @return \think\response\Json
*/ */
public function empty(Log $log) public function empty($id, Log $log)
{ {
return CatchResponse::success($log->where('id', '>', 0)->delete(), '清空成功'); return CatchResponse::success($log->deleteBy($id), '删除成功');
} }
} }

View File

@@ -0,0 +1,91 @@
<?php
namespace catchAdmin\system\controller;
use catchAdmin\permissions\model\Permissions;
use catcher\base\CatchController;
use catcher\CatchResponse;
use catcher\CatchAdmin;
use catcher\library\InstallCatchModule;
use catcher\library\InstallLocalModule;
use catcher\Utils;
use think\response\Json;
class Module extends CatchController
{
/**
* 模块列表
*
* @return Json
*/
public function index()
{
$modules = [];
foreach(CatchAdmin::getModulesDirectory() as $d) {
$modules[] = json_decode(file_get_contents($d . 'module.json'), true);
}
$hasModules = array_unique(Permissions::whereIn('id', request()->user()->getPermissionsBy())->column('module'));
$orders = array_column($modules, 'order');
array_multisort($orders, SORT_DESC, $modules);
if (!Utils::isSuperAdmin()) {
foreach ($modules as $k => $module) {
if (!in_array($module['alias'], $hasModules)) {
unset($modules[$k]);
}
}
}
return CatchResponse::success(array_values($modules));
}
/**
* 禁用/启用模块
*
* @param string $module
* @return Json
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\db\exception\DataNotFoundException
*/
public function disOrEnable(string $module)
{
$moduleInfo = CatchAdmin::getModuleInfo(CatchAdmin::directory() . $module);
$install = new InstallLocalModule($module);
if (!$moduleInfo['enable']) {
$install->findModuleInPermissions() ? $install->enableModule() : $install->done();
} else {
$install->disableModule();
}
return CatchResponse::success();
}
/**
* 缓存
*
* @time 2020年09月21日
* @return Json
*/
public function cache()
{
return CatchResponse::success(CatchAdmin::cacheServices());
}
/**
* 清理缓存
*
* @time 2020年09月21日
* @return Json
*/
public function clear()
{
return !file_exists(CatchAdmin::getCacheServicesFile()) ?
CatchResponse::fail('模块没有缓存') :
CatchResponse::success(unlink(CatchAdmin::getCacheServicesFile()));
}
}

View File

@@ -15,6 +15,7 @@ use catcher\base\CatchController;
use catcher\base\CatchRequest; use catcher\base\CatchRequest;
use catcher\CatchResponse; use catcher\CatchResponse;
use catcher\CatchUpload; use catcher\CatchUpload;
use catcher\exceptions\FailedException;
class Upload extends CatchController class Upload extends CatchController
{ {
@@ -37,6 +38,10 @@ class Upload extends CatchController
{ {
$images = $request->file(); $images = $request->file();
if (!$images) {
throw new FailedException('请选择图片上传');
}
return CatchResponse::success($upload->checkImages($images)->multiUpload($images['image'])); return CatchResponse::success($upload->checkImages($images)->multiUpload($images['image']));
} }

View File

@@ -35,7 +35,7 @@ class Developers extends Migrator
->addColumn('mobile', 'string', ['limit' => 30,'null' => false,'default' => '','signed' => false,'comment' => '手机号',]) ->addColumn('mobile', 'string', ['limit' => 30,'null' => false,'default' => '','signed' => false,'comment' => '手机号',])
->addColumn('id_card', 'string', ['limit' => 50,'null' => false,'default' => '','signed' => false,'comment' => '身份证',]) ->addColumn('id_card', 'string', ['limit' => 50,'null' => false,'default' => '','signed' => false,'comment' => '身份证',])
->addColumn('alipay_account', 'string', ['limit' => 100,'null' => false,'default' => '','signed' => false,'comment' => '支付宝账户',]) ->addColumn('alipay_account', 'string', ['limit' => 100,'null' => false,'default' => '','signed' => false,'comment' => '支付宝账户',])
->addColumn('status', 'boolean', ['null' => false,'default' => 1,'signed' => false,'comment' => '1 待认证 1 已认证',]) ->addColumn('status', 'boolean', ['null' => false,'default' => 1,'signed' => false,'comment' => '1 待认证 2 已认证',])
->addColumn('created_at', 'integer', ['limit' => MysqlAdapter::INT_REGULAR,'null' => false,'default' => 0,'signed' => true,'comment' => '创建时间',]) ->addColumn('created_at', 'integer', ['limit' => MysqlAdapter::INT_REGULAR,'null' => false,'default' => 0,'signed' => true,'comment' => '创建时间',])
->addColumn('updated_at', 'integer', ['limit' => MysqlAdapter::INT_REGULAR,'null' => false,'default' => 0,'signed' => true,'comment' => '更新时间',]) ->addColumn('updated_at', 'integer', ['limit' => MysqlAdapter::INT_REGULAR,'null' => false,'default' => 0,'signed' => true,'comment' => '更新时间',])
->addColumn('deleted_at', 'integer', ['limit' => MysqlAdapter::INT_REGULAR,'null' => false,'default' => 0,'signed' => true,'comment' => '软删除',]) ->addColumn('deleted_at', 'integer', ['limit' => MysqlAdapter::INT_REGULAR,'null' => false,'default' => 0,'signed' => true,'comment' => '软删除',])

View File

@@ -18,8 +18,8 @@ class ConfigSeed extends Seeder
[ [
'name' => '基础配置', 'name' => '基础配置',
'pid' => 0, 'pid' => 0,
'component' => 'basis', 'component' => 'basic',
'key' => 'basis', 'key' => 'basic',
], ],
[ [
'name' => '上传配置', 'name' => '上传配置',

View File

@@ -0,0 +1,775 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~{$year} http://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
use think\migration\Seeder;
class SystemMenusSeed extends Seeder
{
/**
* Run Method.
*
* Write your database seeder using this method.
*
* More information on writing seeders is available here:
* http://docs.phinx.org/en/latest/seeding.html
*/
public function run()
{
\catcher\Utils::importTreeData($this->getPermissions(), 'permissions', 'parent_id');
}
protected function getPermissions()
{
return array (
0 =>
array (
'id' => 38,
'permission_name' => '系统管理',
'parent_id' => 0,
'level' => '',
'route' => '/system',
'icon' => 'el-icon-s-tools',
'module' => 'system',
'creator_id' => 1,
'permission_mark' => 'system',
'component' => 'layout',
'redirect' => 'attactments',
'keepalive' => 2,
'type' => 1,
'hidden' => 1,
'sort' => 1,
'created_at' => 1587462349,
'updated_at' => 1599288737,
'deleted_at' => 0,
'children' =>
array (
0 =>
array (
'id' => 39,
'permission_name' => '数据字典',
'parent_id' => 38,
'level' => '38',
'route' => '/system/database',
'icon' => 'el-icon-copy-document',
'module' => 'system',
'creator_id' => 1,
'permission_mark' => 'dataDictionary',
'component' => 'database',
'redirect' => '',
'keepalive' => 1,
'type' => 1,
'hidden' => 1,
'sort' => 8,
'created_at' => 1587463087,
'updated_at' => 1599362678,
'deleted_at' => 0,
'children' =>
array (
0 =>
array (
'id' => 40,
'permission_name' => '查看',
'parent_id' => 39,
'level' => '38-39',
'route' => '',
'icon' => '',
'module' => 'system',
'creator_id' => 1,
'permission_mark' => 'dataDictionary@view',
'component' => '',
'redirect' => '',
'keepalive' => 1,
'type' => 2,
'hidden' => 1,
'sort' => 1,
'created_at' => 1587463113,
'updated_at' => 1599362691,
'deleted_at' => 0,
),
1 =>
array (
'id' => 41,
'permission_name' => '列表',
'parent_id' => 39,
'level' => '38-39',
'route' => '',
'icon' => '',
'module' => 'system',
'creator_id' => 1,
'permission_mark' => 'dataDictionary@tables',
'component' => '',
'redirect' => '',
'keepalive' => 1,
'type' => 2,
'hidden' => 1,
'sort' => 10,
'created_at' => 1587463173,
'updated_at' => 1599362678,
'deleted_at' => 0,
),
2 =>
array (
'id' => 42,
'permission_name' => '优化',
'parent_id' => 39,
'level' => '38-39',
'route' => '',
'icon' => '',
'module' => 'system',
'creator_id' => 1,
'permission_mark' => 'dataDictionary@optimize',
'component' => '',
'redirect' => '',
'keepalive' => 1,
'type' => 2,
'hidden' => 1,
'sort' => 1,
'created_at' => 1587463201,
'updated_at' => 1599362678,
'deleted_at' => 0,
),
3 =>
array (
'id' => 43,
'permission_name' => '备份',
'parent_id' => 39,
'level' => '38-39',
'route' => '',
'icon' => '',
'module' => 'system',
'creator_id' => 1,
'permission_mark' => 'optimize@backup',
'component' => '',
'redirect' => '',
'keepalive' => 1,
'type' => 2,
'hidden' => 1,
'sort' => 1,
'created_at' => 1587463217,
'updated_at' => 1599362678,
'deleted_at' => 0,
),
),
),
1 =>
array (
'id' => 44,
'permission_name' => '附件管理',
'parent_id' => 38,
'level' => '38',
'route' => '/system/attactments',
'icon' => 'el-icon-folder-opened',
'module' => 'system',
'creator_id' => 1,
'permission_mark' => 'attactments',
'component' => 'attachment',
'redirect' => '',
'keepalive' => 1,
'type' => 1,
'hidden' => 1,
'sort' => 10,
'created_at' => 1587463302,
'updated_at' => 1599288737,
'deleted_at' => 0,
'children' =>
array (
0 =>
array (
'id' => 45,
'permission_name' => '列表',
'parent_id' => 44,
'level' => '38-44',
'route' => '',
'icon' => '',
'module' => 'system',
'creator_id' => 1,
'permission_mark' => 'attachments@index',
'component' => '',
'redirect' => '',
'keepalive' => 1,
'type' => 2,
'hidden' => 1,
'sort' => 1,
'created_at' => 1587463335,
'updated_at' => 1599217559,
'deleted_at' => 0,
),
1 =>
array (
'id' => 46,
'permission_name' => '删除',
'parent_id' => 44,
'level' => '38-44',
'route' => '',
'icon' => '',
'module' => 'system',
'creator_id' => 1,
'permission_mark' => 'attachments@delete',
'component' => '',
'redirect' => '',
'keepalive' => 1,
'type' => 2,
'hidden' => 1,
'sort' => 1,
'created_at' => 1587463355,
'updated_at' => 1599217559,
'deleted_at' => 0,
),
2 =>
array (
'id' => 47,
'permission_name' => '上传图片',
'parent_id' => 44,
'level' => '38-44',
'route' => '',
'icon' => '',
'module' => 'system',
'creator_id' => 1,
'permission_mark' => 'upload@image',
'component' => '',
'redirect' => '',
'keepalive' => 1,
'type' => 2,
'hidden' => 1,
'sort' => 1,
'created_at' => 1587466919,
'updated_at' => 1599217559,
'deleted_at' => 0,
),
3 =>
array (
'id' => 48,
'permission_name' => '上传文件',
'parent_id' => 44,
'level' => '38-44',
'route' => '',
'icon' => '',
'module' => 'system',
'creator_id' => 1,
'permission_mark' => 'upload@file',
'component' => '',
'redirect' => '',
'keepalive' => 1,
'type' => 2,
'hidden' => 1,
'sort' => 1,
'created_at' => 1587466939,
'updated_at' => 1599217559,
'deleted_at' => 0,
),
),
),
2 =>
array (
'id' => 49,
'permission_name' => '配置管理',
'parent_id' => 38,
'level' => '38',
'route' => '/system/config',
'icon' => 'el-icon-setting',
'module' => 'system',
'creator_id' => 1,
'permission_mark' => 'config',
'component' => 'config',
'redirect' => '',
'keepalive' => 1,
'type' => 1,
'hidden' => 1,
'sort' => 9,
'created_at' => 1587466991,
'updated_at' => 1599288737,
'deleted_at' => 0,
'children' =>
array (
0 =>
array (
'id' => 50,
'permission_name' => '父级配置',
'parent_id' => 49,
'level' => '38-49',
'route' => '',
'icon' => '',
'module' => 'system',
'creator_id' => 1,
'permission_mark' => 'config@parent',
'component' => '',
'redirect' => '',
'keepalive' => 1,
'type' => 2,
'hidden' => 1,
'sort' => 1,
'created_at' => 1587467036,
'updated_at' => 1591345651,
'deleted_at' => 0,
),
1 =>
array (
'id' => 51,
'permission_name' => '存储',
'parent_id' => 49,
'level' => '38-49',
'route' => '',
'icon' => '',
'module' => 'system',
'creator_id' => 1,
'permission_mark' => 'config@save',
'component' => '',
'redirect' => '',
'keepalive' => 1,
'type' => 2,
'hidden' => 1,
'sort' => 1,
'created_at' => 1587467052,
'updated_at' => 1587547118,
'deleted_at' => 0,
),
2 =>
array (
'id' => 52,
'permission_name' => '获取',
'parent_id' => 49,
'level' => '38-49',
'route' => '',
'icon' => '',
'module' => 'system',
'creator_id' => 1,
'permission_mark' => 'config@read',
'component' => '',
'redirect' => '',
'keepalive' => 1,
'type' => 2,
'hidden' => 1,
'sort' => 1,
'created_at' => 1587467062,
'updated_at' => 1587547118,
'deleted_at' => 0,
),
),
),
3 =>
array (
'id' => 53,
'permission_name' => '登陆日志',
'parent_id' => 38,
'level' => '38',
'route' => '/system/log/login',
'icon' => 'el-icon-coin',
'module' => 'system',
'creator_id' => 1,
'permission_mark' => 'loginLog',
'component' => 'loginLog',
'redirect' => '',
'keepalive' => 1,
'type' => 1,
'hidden' => 1,
'sort' => 5,
'created_at' => 1587467150,
'updated_at' => 1599288737,
'deleted_at' => 0,
'children' =>
array (
0 =>
array (
'id' => 54,
'permission_name' => '列表',
'parent_id' => 53,
'level' => '38-53',
'route' => '',
'icon' => '',
'module' => 'system',
'creator_id' => 1,
'permission_mark' => 'loginlog@list',
'component' => '',
'redirect' => '',
'keepalive' => 1,
'type' => 2,
'hidden' => 1,
'sort' => 1,
'created_at' => 1587467206,
'updated_at' => 1587547118,
'deleted_at' => 0,
),
1 =>
array (
'id' => 55,
'permission_name' => '清空',
'parent_id' => 53,
'level' => '38-53',
'route' => '',
'icon' => '',
'module' => 'system',
'creator_id' => 1,
'permission_mark' => 'loginlog@empty',
'component' => '',
'redirect' => '',
'keepalive' => 1,
'type' => 2,
'hidden' => 1,
'sort' => 1,
'created_at' => 1587467221,
'updated_at' => 1587547118,
'deleted_at' => 0,
),
),
),
4 =>
array (
'id' => 56,
'permission_name' => '操作日志',
'parent_id' => 38,
'level' => '38',
'route' => '/system/log/operate',
'icon' => 'el-icon-house',
'module' => 'system',
'creator_id' => 1,
'permission_mark' => 'operateLog',
'component' => 'operateLog',
'redirect' => '',
'keepalive' => 1,
'type' => 1,
'hidden' => 1,
'sort' => 1,
'created_at' => 1587467180,
'updated_at' => 1599288737,
'deleted_at' => 0,
'children' =>
array (
0 =>
array (
'id' => 57,
'permission_name' => '列表',
'parent_id' => 56,
'level' => '38-56',
'route' => '',
'icon' => '',
'module' => 'system',
'creator_id' => 1,
'permission_mark' => 'operatelog@list',
'component' => '',
'redirect' => '',
'keepalive' => 1,
'type' => 2,
'hidden' => 1,
'sort' => 1,
'created_at' => 1587467246,
'updated_at' => 1587547118,
'deleted_at' => 0,
),
1 =>
array (
'id' => 58,
'permission_name' => '清空',
'parent_id' => 56,
'level' => '38-56',
'route' => '',
'icon' => '',
'module' => 'system',
'creator_id' => 1,
'permission_mark' => 'operatelog@empty',
'component' => '',
'redirect' => '',
'keepalive' => 1,
'type' => 2,
'hidden' => 1,
'sort' => 1,
'created_at' => 1587467266,
'updated_at' => 1587547118,
'deleted_at' => 0,
),
),
),
5 =>
array (
'id' => 59,
'permission_name' => '代码生成',
'parent_id' => 38,
'level' => '38',
'route' => '/system/generate',
'icon' => 'el-icon-scissors',
'module' => 'system',
'creator_id' => 1,
'permission_mark' => 'generate',
'component' => 'generate',
'redirect' => '',
'keepalive' => 1,
'type' => 1,
'hidden' => 1,
'sort' => 1,
'created_at' => 1587717452,
'updated_at' => 1599288737,
'deleted_at' => 0,
'children' =>
array (
0 =>
array (
'id' => 60,
'permission_name' => '生成',
'parent_id' => 59,
'level' => '38-59',
'route' => '',
'icon' => '',
'module' => 'system',
'creator_id' => 1,
'permission_mark' => 'generate@save',
'component' => '',
'redirect' => '',
'keepalive' => 1,
'type' => 2,
'hidden' => 1,
'sort' => 1,
'created_at' => 1588110923,
'updated_at' => 1599217574,
'deleted_at' => 0,
),
1 =>
array (
'id' => 61,
'permission_name' => '预览',
'parent_id' => 59,
'level' => '38-59',
'route' => '',
'icon' => '',
'module' => 'system',
'creator_id' => 1,
'permission_mark' => 'generate@preview',
'component' => '',
'redirect' => '',
'keepalive' => 1,
'type' => 2,
'hidden' => 1,
'sort' => 1,
'created_at' => 1588110962,
'updated_at' => 1599217574,
'deleted_at' => 0,
),
),
),
6 =>
array (
'id' => 62,
'permission_name' => '敏感词库',
'parent_id' => 38,
'level' => '38',
'route' => '/sensitive/word',
'icon' => 'el-icon-folder-delete',
'module' => 'system',
'creator_id' => 1,
'permission_mark' => 'sensitiveWord',
'component' => 'sensitiveWord',
'redirect' => '',
'keepalive' => 1,
'type' => 1,
'hidden' => 1,
'sort' => 1,
'created_at' => 1592375865,
'updated_at' => 1599288737,
'deleted_at' => 0,
'children' =>
array (
0 =>
array (
'id' => 63,
'permission_name' => '列表',
'parent_id' => 62,
'level' => '38-62',
'route' => '',
'icon' => '',
'module' => 'system',
'creator_id' => 1,
'permission_mark' => 'sensitiveWord@index',
'component' => '',
'redirect' => '',
'keepalive' => 1,
'type' => 2,
'hidden' => 1,
'sort' => 1,
'created_at' => 1592382167,
'updated_at' => 1593589434,
'deleted_at' => 0,
),
1 =>
array (
'id' => 64,
'permission_name' => '新增',
'parent_id' => 62,
'level' => '38-62',
'route' => '',
'icon' => '',
'module' => 'system',
'creator_id' => 1,
'permission_mark' => 'sensitiveWord@save',
'component' => '',
'redirect' => '',
'keepalive' => 1,
'type' => 2,
'hidden' => 1,
'sort' => 1,
'created_at' => 1592382179,
'updated_at' => 1593589434,
'deleted_at' => 0,
),
2 =>
array (
'id' => 65,
'permission_name' => '更新',
'parent_id' => 62,
'level' => '38-62',
'route' => '',
'icon' => '',
'module' => 'system',
'creator_id' => 1,
'permission_mark' => 'sensitiveWord@update',
'component' => '',
'redirect' => '',
'keepalive' => 1,
'type' => 2,
'hidden' => 1,
'sort' => 1,
'created_at' => 1592382192,
'updated_at' => 1593589434,
'deleted_at' => 0,
),
3 =>
array (
'id' => 66,
'permission_name' => '删除',
'parent_id' => 62,
'level' => '38-62',
'route' => '',
'icon' => '',
'module' => 'system',
'creator_id' => 1,
'permission_mark' => 'sensitiveWord@delete',
'component' => '',
'redirect' => '',
'keepalive' => 1,
'type' => 2,
'hidden' => 1,
'sort' => 1,
'created_at' => 1592382202,
'updated_at' => 1593589434,
'deleted_at' => 0,
),
),
),
7 =>
array (
'id' => 67,
'permission_name' => '开发者',
'parent_id' => 38,
'level' => '38',
'route' => '/system/develop',
'icon' => 'el-icon-rank',
'module' => 'system',
'creator_id' => 1,
'permission_mark' => 'develop',
'component' => 'develop',
'redirect' => '',
'keepalive' => 1,
'type' => 1,
'hidden' => 1,
'sort' => 1,
'created_at' => 1594626307,
'updated_at' => 1599288737,
'deleted_at' => 0,
),
8 =>
array (
'id' => 68,
'permission_name' => '模块管理',
'parent_id' => 38,
'level' => '38',
'route' => '/system/module',
'icon' => 'el-icon-postcard',
'module' => 'system',
'creator_id' => 1,
'permission_mark' => 'module',
'component' => 'module',
'redirect' => '',
'keepalive' => 1,
'type' => 1,
'hidden' => 1,
'sort' => 1,
'created_at' => 1599904306,
'updated_at' => 1599904306,
'deleted_at' => 0,
'children' =>
array (
0 =>
array (
'id' => 69,
'permission_name' => '列表',
'parent_id' => 68,
'level' => '38-68',
'route' => '',
'icon' => '',
'module' => 'system',
'creator_id' => 1,
'permission_mark' => 'module@index',
'component' => '',
'redirect' => '',
'keepalive' => 1,
'type' => 2,
'hidden' => 1,
'sort' => 1,
'created_at' => 1599904319,
'updated_at' => 1599904319,
'deleted_at' => 0,
),
1 =>
array (
'id' => 70,
'permission_name' => '禁用/启用',
'parent_id' => 68,
'level' => '38-68',
'route' => '',
'icon' => '',
'module' => 'system',
'creator_id' => 1,
'permission_mark' => 'module@disOrEnable',
'component' => '',
'redirect' => '',
'keepalive' => 1,
'type' => 2,
'hidden' => 1,
'sort' => 1,
'created_at' => 1599904331,
'updated_at' => 1599904331,
'deleted_at' => 0,
),
),
),
9 =>
array (
'id' => 116,
'permission_name' => '表单构建',
'parent_id' => 38,
'level' => '38',
'route' => '/system/form',
'icon' => 'el-icon-knife-fork',
'module' => 'system',
'creator_id' => 1,
'permission_mark' => 'form',
'component' => 'form',
'redirect' => '',
'keepalive' => 1,
'type' => 1,
'hidden' => 1,
'sort' => 1,
'created_at' => 1600648935,
'updated_at' => 1600648935,
'deleted_at' => 0,
),
),
),
);
}
}

View File

@@ -1,621 +0,0 @@
<?php
use think\migration\Seeder;
class SystemPermissionSeed extends Seeder
{
/**
* Run Method.
*
* Write your database seeder using this method.
*
* More information on writing seeders is available here:
* http://docs.phinx.org/en/latest/seeding.html
*/
public function run()
{
\catcher\Utils::importTreeData($this->getPermissions(), 'permissions', 'parent_id');
}
protected function getPermissions()
{
return array(
0 =>
array(
'id' => 37,
'permission_name' => '系统管理',
'parent_id' => 0,
'level' => '',
'route' => '/system',
'icon' => 'bar-chart',
'module' => 'system',
'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'system',
'component' => 'pageView',
'redirect' => '',
'hide_children_in_menu' => 2,
'keepalive' => 2,
'type' => 1,
'status' => 1,
'sort' => 1,
'created_at' => 1587462349,
'updated_at' => 1593044431,
'deleted_at' => 0,
'children' =>
array(
0 =>
array(
'id' => 38,
'permission_name' => '数据字典',
'parent_id' => 37,
'level' => '37',
'route' => '/system/database',
'icon' => 'hdd',
'module' => 'system',
'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'dataDictionary@index',
'component' => 'database',
'redirect' => '',
'hide_children_in_menu' => 2,
'keepalive' => 1,
'type' => 1,
'status' => 1,
'sort' => 8,
'created_at' => 1587463087,
'updated_at' => 1593044431,
'deleted_at' => 0,
'children' =>
array(
0 =>
array(
'id' => 39,
'permission_name' => '查看',
'parent_id' => 38,
'level' => '37-38',
'route' => '',
'icon' => '',
'module' => 'system',
'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'dataDictionary@view',
'component' => '',
'redirect' => '',
'hide_children_in_menu' => 1,
'keepalive' => 1,
'type' => 2,
'status' => 1,
'sort' => 1,
'created_at' => 1587463113,
'updated_at' => 1591343449,
'deleted_at' => 0,
),
1 =>
array(
'id' => 40,
'permission_name' => '列表',
'parent_id' => 38,
'level' => '37-38',
'route' => '',
'icon' => '',
'module' => 'system',
'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'dataDictionary@tables',
'component' => '',
'redirect' => '',
'hide_children_in_menu' => 1,
'keepalive' => 1,
'type' => 2,
'status' => 1,
'sort' => 10,
'created_at' => 1587463173,
'updated_at' => 1587547118,
'deleted_at' => 0,
),
2 =>
array(
'id' => 41,
'permission_name' => '优化',
'parent_id' => 38,
'level' => '37-38',
'route' => '',
'icon' => '',
'module' => 'system',
'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'dataDictionary@optimize',
'component' => '',
'redirect' => '',
'hide_children_in_menu' => 1,
'keepalive' => 1,
'type' => 2,
'status' => 1,
'sort' => 1,
'created_at' => 1587463201,
'updated_at' => 1587547118,
'deleted_at' => 0,
),
3 =>
array(
'id' => 42,
'permission_name' => '备份',
'parent_id' => 38,
'level' => '37-38',
'route' => '',
'icon' => '',
'module' => 'system',
'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'optimize@backup',
'component' => '',
'redirect' => '',
'hide_children_in_menu' => 1,
'keepalive' => 1,
'type' => 2,
'status' => 1,
'sort' => 1,
'created_at' => 1587463217,
'updated_at' => 1587547118,
'deleted_at' => 0,
),
),
),
1 =>
array(
'id' => 43,
'permission_name' => '附件管理',
'parent_id' => 37,
'level' => '37',
'route' => '/attactments',
'icon' => 'folder-open',
'module' => 'system',
'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'attactments',
'component' => 'attachment',
'redirect' => '',
'hide_children_in_menu' => 2,
'keepalive' => 1,
'type' => 1,
'status' => 1,
'sort' => 10,
'created_at' => 1587463302,
'updated_at' => 1593044431,
'deleted_at' => 0,
'children' =>
array(
0 =>
array(
'id' => 44,
'permission_name' => '列表',
'parent_id' => 43,
'level' => '37-43',
'route' => '',
'icon' => '',
'module' => 'system',
'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'attachments@index',
'component' => '',
'redirect' => '',
'hide_children_in_menu' => 1,
'keepalive' => 1,
'type' => 2,
'status' => 1,
'sort' => 1,
'created_at' => 1587463335,
'updated_at' => 1587547118,
'deleted_at' => 0,
),
1 =>
array(
'id' => 45,
'permission_name' => '删除',
'parent_id' => 43,
'level' => '37-43',
'route' => '',
'icon' => '',
'module' => 'system',
'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'attachments@delete',
'component' => '',
'redirect' => '',
'hide_children_in_menu' => 1,
'keepalive' => 1,
'type' => 2,
'status' => 1,
'sort' => 1,
'created_at' => 1587463355,
'updated_at' => 1587547118,
'deleted_at' => 0,
),
2 =>
array(
'id' => 46,
'permission_name' => '上传图片',
'parent_id' => 43,
'level' => '37-43',
'route' => '',
'icon' => '',
'module' => 'system',
'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'upload@image',
'component' => '',
'redirect' => '',
'hide_children_in_menu' => 1,
'keepalive' => 1,
'type' => 2,
'status' => 1,
'sort' => 1,
'created_at' => 1587466919,
'updated_at' => 1587547118,
'deleted_at' => 0,
),
3 =>
array(
'id' => 47,
'permission_name' => '上传文件',
'parent_id' => 43,
'level' => '37-43',
'route' => '',
'icon' => '',
'module' => 'system',
'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'upload@file',
'component' => '',
'redirect' => '',
'hide_children_in_menu' => 1,
'keepalive' => 1,
'type' => 2,
'status' => 1,
'sort' => 1,
'created_at' => 1587466939,
'updated_at' => 1587547118,
'deleted_at' => 0,
),
),
),
2 =>
array(
'id' => 48,
'permission_name' => '配置管理',
'parent_id' => 37,
'level' => '37',
'route' => '/system/config',
'icon' => 'setting',
'module' => 'system',
'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'config',
'component' => 'config',
'redirect' => '',
'hide_children_in_menu' => 2,
'keepalive' => 1,
'type' => 1,
'status' => 1,
'sort' => 9,
'created_at' => 1587466991,
'updated_at' => 1593044431,
'deleted_at' => 0,
'children' =>
array(
0 =>
array(
'id' => 49,
'permission_name' => '父级配置',
'parent_id' => 48,
'level' => '37-48',
'route' => '',
'icon' => '',
'module' => 'system',
'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'config@parent',
'component' => '',
'redirect' => '',
'hide_children_in_menu' => 1,
'keepalive' => 1,
'type' => 2,
'status' => 1,
'sort' => 1,
'created_at' => 1587467036,
'updated_at' => 1591345651,
'deleted_at' => 0,
),
1 =>
array(
'id' => 50,
'permission_name' => '存储',
'parent_id' => 48,
'level' => '37-48',
'route' => '',
'icon' => '',
'module' => 'system',
'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'config@save',
'component' => '',
'redirect' => '',
'hide_children_in_menu' => 1,
'keepalive' => 1,
'type' => 2,
'status' => 1,
'sort' => 1,
'created_at' => 1587467052,
'updated_at' => 1587547118,
'deleted_at' => 0,
),
2 =>
array(
'id' => 51,
'permission_name' => '获取',
'parent_id' => 48,
'level' => '37-48',
'route' => '',
'icon' => '',
'module' => 'system',
'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'config@read',
'component' => '',
'redirect' => '',
'hide_children_in_menu' => 1,
'keepalive' => 1,
'type' => 2,
'status' => 1,
'sort' => 1,
'created_at' => 1587467062,
'updated_at' => 1587547118,
'deleted_at' => 0,
),
),
),
3 =>
array(
'id' => 52,
'permission_name' => '登陆日志',
'parent_id' => 37,
'level' => '37',
'route' => '/system/log/login',
'icon' => 'export',
'module' => 'system',
'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'loginLog',
'component' => 'loginLog',
'redirect' => '',
'hide_children_in_menu' => 2,
'keepalive' => 1,
'type' => 1,
'status' => 1,
'sort' => 5,
'created_at' => 1587467150,
'updated_at' => 1593044431,
'deleted_at' => 0,
'children' =>
array(
0 =>
array(
'id' => 53,
'permission_name' => '列表',
'parent_id' => 52,
'level' => '37-52',
'route' => '',
'icon' => '',
'module' => 'system',
'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'loginlog@list',
'component' => '',
'redirect' => '',
'hide_children_in_menu' => 1,
'keepalive' => 1,
'type' => 2,
'status' => 1,
'sort' => 1,
'created_at' => 1587467206,
'updated_at' => 1587547118,
'deleted_at' => 0,
),
1 =>
array(
'id' => 54,
'permission_name' => '清空',
'parent_id' => 52,
'level' => '37-52',
'route' => '',
'icon' => '',
'module' => 'system',
'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'loginlog@empty',
'component' => '',
'redirect' => '',
'hide_children_in_menu' => 1,
'keepalive' => 1,
'type' => 2,
'status' => 1,
'sort' => 1,
'created_at' => 1587467221,
'updated_at' => 1587547118,
'deleted_at' => 0,
),
),
),
4 =>
array(
'id' => 55,
'permission_name' => '操作日志',
'parent_id' => 37,
'level' => '37',
'route' => '/system/log/operate',
'icon' => 'profile',
'module' => 'system',
'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'operateLog',
'component' => 'operateLog',
'redirect' => '',
'hide_children_in_menu' => 2,
'keepalive' => 1,
'type' => 1,
'status' => 1,
'sort' => 1,
'created_at' => 1587467180,
'updated_at' => 1593044431,
'deleted_at' => 0,
'children' =>
array(
0 =>
array(
'id' => 56,
'permission_name' => '列表',
'parent_id' => 55,
'level' => '37-55',
'route' => '',
'icon' => '',
'module' => 'system',
'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'operatelog@list',
'component' => '',
'redirect' => '',
'hide_children_in_menu' => 1,
'keepalive' => 1,
'type' => 2,
'status' => 1,
'sort' => 1,
'created_at' => 1587467246,
'updated_at' => 1587547118,
'deleted_at' => 0,
),
1 =>
array(
'id' => 57,
'permission_name' => '清空',
'parent_id' => 55,
'level' => '37-55',
'route' => '',
'icon' => '',
'module' => 'system',
'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'operatelog@empty',
'component' => '',
'redirect' => '',
'hide_children_in_menu' => 1,
'keepalive' => 1,
'type' => 2,
'status' => 1,
'sort' => 1,
'created_at' => 1587467266,
'updated_at' => 1587547118,
'deleted_at' => 0,
),
),
),
5 =>
array(
'id' => 58,
'permission_name' => '代码生成',
'parent_id' => 37,
'level' => '37',
'route' => '/generate',
'icon' => 'scissor',
'module' => 'system',
'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'generate',
'component' => 'generate',
'redirect' => '',
'hide_children_in_menu' => 2,
'keepalive' => 1,
'type' => 1,
'status' => 1,
'sort' => 1,
'created_at' => 1587717452,
'updated_at' => 1593044431,
'deleted_at' => 0,
'children' =>
array(
0 =>
array(
'id' => 59,
'permission_name' => '生成',
'parent_id' => 58,
'level' => '37-58',
'route' => '',
'icon' => '',
'module' => 'system',
'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'generate@save',
'component' => '',
'redirect' => '',
'hide_children_in_menu' => 1,
'keepalive' => 1,
'type' => 2,
'status' => 1,
'sort' => 1,
'created_at' => 1588110923,
'updated_at' => 1588110923,
'deleted_at' => 0,
),
1 =>
array(
'id' => 60,
'permission_name' => '预览',
'parent_id' => 58,
'level' => '37-58',
'route' => '',
'icon' => '',
'module' => 'system',
'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'generate@preview',
'component' => '',
'redirect' => '',
'hide_children_in_menu' => 1,
'keepalive' => 1,
'type' => 2,
'status' => 1,
'sort' => 1,
'created_at' => 1588110962,
'updated_at' => 1588110962,
'deleted_at' => 0,
),
),
),
6 =>
array(
'id' => 68,
'permission_name' => '敏感词库',
'parent_id' => 37,
'level' => '37',
'route' => '/sensitive/word',
'icon' => 'sliders',
'module' => 'system',
'creator_id' => 1,
'method' => 'get',
'permission_mark' => 'sensitiveWord',
'component' => 'sensitiveWord',
'redirect' => '',
'hide_children_in_menu' => 2,
'keepalive' => 1,
'type' => 1,
'status' => 1,
'sort' => 1,
'created_at' => 1592375865,
'updated_at' => 1593044431,
'deleted_at' => 0,
),
),
),
);
}
}

View File

@@ -1,12 +1,15 @@
<?php <?php
namespace catchAdmin\system\model; namespace catchAdmin\system\model;
use catchAdmin\system\model\search\AttachmentsSearch;
use catcher\base\CatchModel; use catcher\base\CatchModel;
use think\file\UploadedFile; use think\file\UploadedFile;
use think\Model; use think\Model;
class Attachments extends CatchModel class Attachments extends CatchModel
{ {
use AttachmentsSearch;
protected $name = 'attachments'; protected $name = 'attachments';
protected $field = [ protected $field = [
@@ -27,24 +30,10 @@ class Attachments extends CatchModel
{ {
return $this->order('id', 'desc') return $this->order('id', 'desc')
->catchSearch() ->catchSearch()
->catchOrder()
->paginate(); ->paginate();
} }
public function searchFileExtAttr($query, $value, $data)
{
return $query->where('file_ext', $value);
}
public function searchMimeTypesAttr($query, $value, $data)
{
return $query->where('mime_type', $value);
}
public function searchDriver($query, $value, $data)
{
return $query->where('driver', $value);
}
/** /**
* *
* *

View File

@@ -2,6 +2,7 @@
namespace catchAdmin\system\model; namespace catchAdmin\system\model;
use catcher\base\CatchModel; use catcher\base\CatchModel;
use catcher\exceptions\FailedException;
use thans\jwt\exception\UserNotDefinedException; use thans\jwt\exception\UserNotDefinedException;
use think\Model; use think\Model;
@@ -55,92 +56,43 @@ class Config extends CatchModel
return true; return true;
} }
// 子配置 $parent = $data['parent'] ?? false;
if ($data['pid'] ?? false) { if (!$parent) {
$config = \json_decode($data['config'], true); throw new FailedException('父配置丢失');
$pid = $data['pid']; }
unset($data['pid']); unset($data['parent']);
/**[
'key' => [
'k' => 'v'
],
'k' => 'v' $parentConfig = $this->where('key', $parent)->find();
]*/ $config = [];
foreach ($config as $key => $value) { foreach ($data as $key => $item) {
if (empty($value)) { foreach ($item as $k => $value) {
continue; $config[$key . '.' .$k] = [
} 'pid' => $parentConfig['id'],
// 如果二级配置存在 'key' => $key . '.' . $k,
$secondLevel = $this->isExistConfig($key, $pid); 'value' => $value,
if ($secondLevel) { 'created_at' => time(),
// value 是字符串 'updated_at' => time(),
if (!is_array($value)) { ];
if ($value != $secondLevel->value) {
$secondLevel->value = $value;
$secondLevel->save();
}
} else {
// 数组
$thirdLevel = [];
$this->subConfig($secondLevel->id, ['id', 'key', 'value'])
->each(function ($item, $key) use (&$thirdLevel){
$thirdLevel[$item['key']] = $item;
});
if (!empty($value)) {
$new = [];
foreach ($value as $k => $v) {
if (isset($thirdLevel[$k])) {
if ($v != $thirdLevel[$k]->value) {
$thirdLevel[$k]->value = $v;
$thirdLevel[$k]->save();
}
} else {
$new[] = [
'pid' => $secondLevel->id,
'key' => $k,
'value' => $v,
];
}
}
if (!empty($new)) {
parent::insertAllBy($new);
}
}
}
} else {
if (!is_array($value)) {
parent::createBy([
'pid' => $pid,
'key' => $key,
'value' => $value,
]);
} else {
$id = parent::createBy([
'pid' => $pid,
'key' => $key,
]);
if (!empty($value)) {
$newConfig = [];
foreach ($value as $k => $v) {
$newConfig[] = [
'key' => $k,
'value' => $v,
'pid' => $id,
];
}
parent::insertAllBy($newConfig);
}
}
}
} }
return true;
} }
return parent::storeBy($data); $this->where('pid', $parentConfig->id)
->select()
->each(function ($item) use (&$config){
if (isset($config[$item['key']])) {
if ($config[$item['key']]['value'] != $item->value) {
$item['value'] = $config[$item['key']]['value'];
$item->save();
}
unset($config[$item['key']]);
}
});
if (count($config)) {
return $this->insertAll($config);
}
return true;
} }
/** /**
@@ -183,28 +135,26 @@ class Config extends CatchModel
* 获取配置 * 获取配置
* *
* @time 2020年04月20日 * @time 2020年04月20日
* @param int $pid * @param string $component
* @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException * @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException * @throws \think\db\exception\ModelNotFoundException
* @return array|mixed * @return array|mixed
*/ */
public function getConfig($pid = 0) public function getConfig(string $component)
{ {
$data = []; $data = [];
$configs = $this->where('pid', $this->where('component', $component)->value('id'))
$configs = $this->where('pid', $pid)
->field('id,`key` as k,value,pid') ->field('id,`key` as k,value,pid')
->select(); ->select();
foreach ($configs as $config) { foreach ($configs as $config) {
if ($config->value !== '') { if (strpos($config['k'], '.') !== false) {
$data[$config->k] = $config->value; list($object, $key) = explode('.', $config['k']);
} else { $data[$object][$key] = $config['value'];
$data[$config->k] = $this->getConfig($config->id);
} }
} }
return empty($data) ? '' : $data; return $data;
} }
} }

View File

@@ -11,10 +11,13 @@
namespace catchAdmin\system\model; namespace catchAdmin\system\model;
use catchAdmin\system\model\search\DeveloperSearch;
use catcher\base\CatchModel as Model; use catcher\base\CatchModel as Model;
class Developers extends Model class Developers extends Model
{ {
use DeveloperSearch;
protected $name = 'developers'; protected $name = 'developers';
protected $field = [ protected $field = [

View File

@@ -8,31 +8,22 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ] // | Author: JaguarJack [ njphper@gmail.com ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
namespace catcher\library; namespace catchAdmin\system\model\search;
use catcher\library\crontab\Schedule; trait AttachmentsSearch
class ScheduleKernel
{ {
protected $schedule; public function searchFileExtAttr($query, $value, $data)
public function __construct()
{ {
$this->schedule = new Schedule(); return $query->where('file_ext', $value);
} }
protected function run() public function searchMimeTypesAttr($query, $value, $data)
{ {
$this->schedule->command('catch:cache')->everyThirtySeconds(); return $query->where('mime_type', $value);
$this->schedule->command('test')->everyTenSeconds();
} }
public function searchDriverAttr($query, $value, $data)
public function tasks()
{ {
$this->run(); return $query->where('driver', $value);
return $this->schedule->getCronTask();
} }
} }

View File

@@ -0,0 +1,29 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2020 http://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
namespace catchAdmin\system\model\search;
trait DeveloperSearch
{
public function searchUsernameAttr($query, $value, $data)
{
return $query->whereLike('username', $value);
}
public function searchMobileAttr($query, $value, $data)
{
return $query->whereLike('mobile', $value);
}
public function searchStatusAttr($query, $value, $data)
{
return $query->where('driver', $value);
}
}

View File

@@ -4,18 +4,13 @@ namespace catchAdmin\system\model\search;
trait LoginLogSearch trait LoginLogSearch
{ {
public function searchLoginNameAttr($query, $value, $data) public function searchStartAtAttr($query, $value, $data)
{ {
return $query->whereLike('login_name', $value); return $query->whereTime('login_at', '>=', strtotime($value));
} }
public function searchLoginIpAttr($query, $value, $data) public function searchEndAtAttr($query, $value, $data)
{ {
return $query->whereLike('login_ip', $value); return $query->whereTime('login_at', '<=', strtotime($value));
}
public function searchLoginAtAttr($query, $value, $data)
{
return $query->whereTime('login_at', 'between', $value);
} }
} }

View File

@@ -2,6 +2,8 @@
namespace catchAdmin\system\model\search; namespace catchAdmin\system\model\search;
use catchAdmin\permissions\model\Users;
trait OperateLogSearch trait OperateLogSearch
{ {
public function searchModuleAttr($query, $value, $data) public function searchModuleAttr($query, $value, $data)
@@ -16,7 +18,7 @@ trait OperateLogSearch
public function searchCreatorAttr($query, $value, $data) public function searchCreatorAttr($query, $value, $data)
{ {
return $query->where('username', $value); return $query->whereLike(app(Users::class)->getTable() . '.username', $value);
} }
public function searchCreateAtAttr($query, $value, $data) public function searchCreateAtAttr($query, $value, $data)

Some files were not shown because too many files have changed in this diff Show More