60 Commits
v2.5 ... v2.6.1

Author SHA1 Message Date
JaguarJack
fb579a5771 update:新增选择数据权限默认选项#gitee#issueI3NNH1 2021-04-24 20:35:33 +08:00
JaguarJack
4e1e040936 add:新增导入导出公共接口 2021-04-24 20:32:36 +08:00
JaguarJack
38e10896d4 update:新增模型导入方法 2021-04-24 20:32:05 +08:00
JaguarJack
ba1595f75f update:新增本地上传方法 2021-04-24 20:31:45 +08:00
JaguarJack
566514f729 delete:transtrait 2021-04-24 20:31:19 +08:00
JaguarJack
48c41f7948 add:新增excel的导入导出组件 2021-04-24 20:30:28 +08:00
JaguarJack
f67a4f33d5 add:新增导入组件 2021-04-24 20:29:33 +08:00
JaguarJack
ae53d4e404 add:新增菜单创建restful快捷方式 2021-04-20 18:56:05 +08:00
JaguarJack
504054b68e add:新增获取省市区数据命令 2021-04-20 08:46:14 +08:00
JaguarJack
ceb5a396d8 update:优化基础组件 2021-04-20 08:45:08 +08:00
JaguarJack
be91cfbc4f fixed#gitee#I3J1IL 2021-04-18 07:45:02 +08:00
JaguarJack
898ffbc822 update:更新Editor组件 2021-04-11 21:01:41 +08:00
JaguarJack
f321a71677 update:更新table&form组件 2021-04-10 21:57:51 +08:00
JaguarJack
246d2caf44 update:修改搜索label文字错误 2021-04-10 08:13:34 +08:00
JaguarJack
d020c99db3 fixed:权限菜单错误&用户修改密码 2021-04-09 08:07:22 +08:00
JaguarJack
44b74d53d9 update:更新一些页面操作 2021-04-05 22:11:36 +08:00
JaguarJack
4e170dbd17 add:新增强制更新组件方法 2021-04-05 22:03:25 +08:00
JaguarJack
f7c8d65ea9 update:更新搜索组件 2021-04-05 12:26:31 +08:00
JaguarJack
5b6e34f3fe update:更新权限列表搜索 2021-04-05 12:26:12 +08:00
JaguarJack
b79b226a74 update:重新渲染system页面 2021-04-03 12:50:21 +08:00
JaguarJack
6ba18dfad2 update:更新action操作 2021-04-03 12:49:55 +08:00
JaguarJack
6630058508 delete:删除冗余 2021-04-03 10:35:53 +08:00
JaguarJack
0bbb39696b update:更新表单action 2021-04-03 10:35:21 +08:00
JaguarJack
7fd87caa36 fixed 2021-04-02 12:05:44 +08:00
JaguarJack
2125966684 fixed:class not found 2021-04-01 20:17:25 +08:00
JaguarJack
4180cb2565 update:更新路由注释,编辑器可追踪 2021-04-01 18:39:11 +08:00
JaguarJack
dffad1e2c4 update:更新菜单列表 2021-03-31 20:44:40 +08:00
JaguarJack
3d70495836 update:更新数据 2021-03-31 20:23:18 +08:00
JaguarJack
6372ccd877 新增路由 2021-03-31 20:21:39 +08:00
JaguarJack
2ad466e617 update:table组件 2021-03-31 20:21:16 +08:00
JaguarJack
5ce104e820 update:form组件 2021-03-31 20:21:02 +08:00
JaguarJack
f56cb943ff add:新增catchTable 2021-03-31 20:20:47 +08:00
JaguarJack
2b96f3b650 update:更新权限系统 2021-03-31 20:20:21 +08:00
JaguarJack
d4020b93a3 add:新增table组件 2021-03-29 19:52:01 +08:00
JaguarJack
2f25a0892e update:更新form功能 2021-03-29 19:51:41 +08:00
JaguarJack
114387d030 update readme 2021-03-28 13:00:20 +08:00
JaguarJack
e3ab44e6d3 fixed:代码生成表失败 2021-03-25 17:51:24 +08:00
Talent.Miao
0d918c9446 修复代码生成Bug 2021-03-25 16:29:46 +08:00
JaguarJack
002ad814e5 fixed:冲突 2021-03-14 07:47:46 +08:00
JaguarJack
b4a1e9bc4e add:新增表单生成 2021-03-14 07:42:01 +08:00
JaguarJack
822ff3874a update:优化代码生成 2021-03-14 07:41:15 +08:00
JaguarJack
78ca9bebc4 rm 2021-03-07 10:52:08 +08:00
JaguarJack
7b7f13536f Merge branch 'master' of https://github.com/yanwenwu/catch-admin 2021-03-06 20:06:28 +08:00
JaguarJack
766a01e766 update:更新快捷搜索 2021-03-06 20:05:20 +08:00
JaguarJack
3196292c85 Merge pull request #28 from tlerbao/patch-1
修复带有表前缀时找不到字段的问题
2021-03-02 08:07:43 +08:00
JaguarJack
f45b9315a9 update:更新aliasField方法,支持数组 2021-03-01 21:02:01 +08:00
JaguarJack
c3b36013d7 fixed:修复附件无法删除 2021-03-01 21:01:37 +08:00
JaguarJack
17491ca7da add: 新增implode方法 2021-03-01 21:00:09 +08:00
Talent.Miao
d1423eb6e8 修复带有表前缀时找不到字段的问题 2021-03-01 09:43:21 +08:00
JaguarJack
c190672603 update:优化代码 2021-02-27 18:31:59 +08:00
JaguarJack
ddf521b62b add:新增 implode 方法 2021-02-27 18:30:40 +08:00
JaguarJack
50c8470d73 update:优化auth 2021-02-22 08:52:39 +08:00
JaguarJack
e9179ee084 update 2021-02-10 08:33:17 +08:00
JaguarJack
adb7ff5a03 fixed:gitee Issue#I37RKN 2021-02-08 17:28:25 +08:00
JaguarJack
706410480b update:优化部分代码 2021-02-08 11:26:54 +08:00
JaguarJack
61ecd0629f update:优化模块信息获取 2021-02-08 11:12:36 +08:00
JaguarJack
84c85c3d12 fixed:修复定时任务立即执行导致任务执行混乱 2021-02-08 10:25:03 +08:00
JaguarJack
d8496f9e62 update:更新自定义权限 2021-02-07 17:21:34 +08:00
JaguarJack
1495a4c731 update:更新crontab 2021-02-07 09:42:01 +08:00
JaguarJack
0efe79ddb3 update:修复多数据库切换之后CatchQuery方法失效 2021-02-05 13:52:23 +08:00
97 changed files with 4779 additions and 849 deletions

View File

@@ -143,6 +143,9 @@ composer create-project jaguarjack/catchadmin:dev-master
如果你觉得项目对你有帮助,可以请作者喝杯咖啡☕️!鼓励下 如果你觉得项目对你有帮助,可以请作者喝杯咖啡☕️!鼓励下
<img src="https://cdn.learnku.com/uploads/images/202008/11/18206/e6qAAM8Bod.jpg!large"> <img src="https://cdn.learnku.com/uploads/images/202008/11/18206/e6qAAM8Bod.jpg!large">
### Who used
- [uctoo 应用开发管理后台](https://gitee.com/uctoo/uctoo)
### Talking ### Talking
- [论坛讨论](http://bbs.catchadmin.com) - [论坛讨论](http://bbs.catchadmin.com)
- 可以提 `ISSUE`,请按照 `issue` 模板提问 - 可以提 `ISSUE`,请按照 `issue` 模板提问
@@ -150,7 +153,7 @@ composer create-project jaguarjack/catchadmin:dev-master
### Thanks ### Thanks
- 感谢 [JetBrains](https://www.jetbrains.com) 提供生产力巨高的 `PHPStorm`和`WebStorm` - 感谢 [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)
- [element-admin](https://panjiachen.gitee.io/vue-element-admin-site/zh/) - [element-admin](https://panjiachen.gitee.io/vue-element-admin-site/zh/)

BIN
catch/.DS_Store vendored

Binary file not shown.

View File

@@ -0,0 +1,47 @@
<?php
namespace catchAdmin\cms\table;
use catcher\CatchTable;
use catcher\library\table\Actions;
use catcher\library\table\HeaderItem;
use catcher\library\table\Search;
class Category extends CatchTable
{
public function table()
{
// TODO: Implement table() method.
return $this->getTable('category')
->header([
HeaderItem::label('分类名称')->prop('name'),
HeaderItem::label('自定义链接')->prop('url'),
HeaderItem::label('栏目类型')->prop('type')->component('type'),
HeaderItem::label('投稿')->prop('is_can_contribute')->withSwitchComponent(),
HeaderItem::label('评论')->prop('is_can_comment')->withSwitchComponent(),
HeaderItem::label('状态')->prop('status')->withSwitchComponent(),
HeaderItem::label('权重')->prop('weight')->withEditNumberComponent(),
HeaderItem::label('创建时间')->prop('created_at'),
HeaderItem::label('操作')->actions([
Actions::update(),
Actions::delete()
])
])
->withActions([
Actions::create()
])
->withSearch([
Search::label('分类名称')->name('请输入分类名称'),
Search::label('状态')->name('请选择状态'),
])
->toTreeTable()
->render();
}
public function form()
{
// TODO: Implement form() method.
}
}

View File

@@ -31,7 +31,7 @@ class DomainMenusSeed extends Seeder
return array ( return array (
0 => 0 =>
array ( array (
'id' => 72, 'id' => 82,
'permission_name' => '域名管理', 'permission_name' => '域名管理',
'parent_id' => 0, 'parent_id' => 0,
'level' => '', 'level' => '',
@@ -47,15 +47,16 @@ class DomainMenusSeed extends Seeder
'hidden' => 1, 'hidden' => 1,
'sort' => 1, 'sort' => 1,
'created_at' => 1601105834, 'created_at' => 1601105834,
'updated_at' => 1601105834, 'updated_at' => 1612754299,
'deleted_at' => 0, 'deleted_at' => 0,
), 'children' =>
1 =>
array ( array (
'id' => 73, 0 =>
array (
'id' => 83,
'permission_name' => '域名设置', 'permission_name' => '域名设置',
'parent_id' => 72, 'parent_id' => 82,
'level' => '72', 'level' => '82',
'route' => '/domain/index', 'route' => '/domain/index',
'icon' => 'el-icon-setting', 'icon' => 'el-icon-setting',
'module' => 'domain', 'module' => 'domain',
@@ -68,15 +69,15 @@ class DomainMenusSeed extends Seeder
'hidden' => 1, 'hidden' => 1,
'sort' => 8, 'sort' => 8,
'created_at' => 1601105879, 'created_at' => 1601105879,
'updated_at' => 1601112604, 'updated_at' => 1612754299,
'deleted_at' => 0, 'deleted_at' => 0,
), ),
2 => 1 =>
array ( array (
'id' => 84, 'id' => 84,
'permission_name' => '域名记录', 'permission_name' => '域名记录',
'parent_id' => 72, 'parent_id' => 82,
'level' => '72', 'level' => '82',
'route' => '/domain/record/:domain', 'route' => '/domain/record/:domain',
'icon' => 'el-icon-document', 'icon' => 'el-icon-document',
'module' => 'domain', 'module' => 'domain',
@@ -89,9 +90,11 @@ class DomainMenusSeed extends Seeder
'hidden' => 2, 'hidden' => 2,
'sort' => 1, 'sort' => 1,
'created_at' => 1601112569, 'created_at' => 1601112569,
'updated_at' => 1601112606, 'updated_at' => 1612754299,
'deleted_at' => 0, 'deleted_at' => 0,
), ),
),
),
); );
} }
} }

View File

@@ -8,6 +8,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ] // | Author: JaguarJack [ njphper@gmail.com ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
/* @var think\Route $router */
// you should use `$router` // you should use `$router`
use catchAdmin\domain\controller\DomainRecord; use catchAdmin\domain\controller\DomainRecord;

View File

@@ -1,4 +1,7 @@
<?php <?php
/* @var think\Route $router */
$router->group(function () use ($router){ $router->group(function () use ($router){
# 登入 # 登入
$router->post('login', '\catchAdmin\login\controller\Index@login'); $router->post('login', '\catchAdmin\login\controller\Index@login');

View File

@@ -96,25 +96,26 @@ class ScheduleCommand extends Command
{ {
$executeAbleCommands = []; $executeAbleCommands = [];
Crontab::where('status', Crontab::ENABLE) Crontab::where('status', Crontab::ENABLE)
->where('tactics', '<>', Crontab::EXECUTE_FORBIDDEN)
->select() ->select()
->each(function ($command) use (&$executeAbleCommands){ ->each(function ($command) use (&$executeAbleCommands){
if ($command->tactics == Crontab::EXECUTE_IMMEDIATELY) { if ($command->tactics == Crontab::EXECUTE_IMMEDIATELY) {
$executeAbleCommands[] = $command; $executeAbleCommands[] = $command;
return true; $command->tactics = Crontab::EXECUTE_NORMAL;
return $command->save();
} }
$can = date('Y-m-d H:i', CronExpression::factory(trim($command->cron)) $can = date('Y-m-d H:i',
(new CronExpression(trim($command->cron)))
->getNextRunDate(date('Y-m-d H:i:s'), 0, true) ->getNextRunDate(date('Y-m-d H:i:s'), 0, true)
->getTimestamp()) == date('Y-m-d H:i', time()); ->getTimestamp()) == date('Y-m-d H:i', time());
if ($can) { if ($can) {
// 如果任务只执行一次 之后禁用该任务 // 如果任务只执行一次 之后禁用该任务
if ($command->tactics === Crontab::EXECUTE_ONCE) { if ($command->tactics === Crontab::EXECUTE_ONCE) {
Crontab::where('id', $command->id)->update([ $command->tactics = Crontab::DISABLE;
'status' => Crontab::DISABLE, $command->save();
]);
} }
$executeAbleCommands[] = $command; $executeAbleCommands[] = $command;

View File

@@ -47,7 +47,7 @@ class Crontab extends CatchController
*/ */
public function save(Request $request) public function save(Request $request)
{ {
CronExpression::factory($request->post('cron')); new CronExpression($request->post('cron'));
return CatchResponse::success($this->model->storeBy($request->post())); return CatchResponse::success($this->model->storeBy($request->post()));
} }
@@ -73,7 +73,7 @@ class Crontab extends CatchController
*/ */
public function update(Request $request, $id) public function update(Request $request, $id)
{ {
CronExpression::factory($request->post('cron')); new CronExpression($request->post('cron'));
return CatchResponse::success($this->model->updateBy($id, $request->post())); return CatchResponse::success($this->model->updateBy($id, $request->post()));
} }

View File

@@ -34,7 +34,7 @@ class Crontab extends Migrator
->addColumn('group', 'boolean', ['null' => false,'default' => 1,'signed' => false,'comment' => '1 默认 2 系统',]) ->addColumn('group', 'boolean', ['null' => false,'default' => 1,'signed' => false,'comment' => '1 默认 2 系统',])
->addColumn('task', 'string', ['limit' => 255,'null' => false,'default' => '','signed' => false,'comment' => '任务名称',]) ->addColumn('task', 'string', ['limit' => 255,'null' => false,'default' => '','signed' => false,'comment' => '任务名称',])
->addColumn('cron', 'string', ['limit' => 50,'null' => false,'default' => '','signed' => false,'comment' => 'cron 表达式',]) ->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('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('status', 'boolean', ['null' => false,'default' => 1,'signed' => false,'comment' => '1 正常 2 禁用',])
->addColumn('remark', 'string', ['limit' => 1000,'null' => false,'default' => '','signed' => false,'comment' => '备注',]) ->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('creator_id', 'integer', ['limit' => MysqlAdapter::INT_REGULAR,'null' => false,'default' => 0,'signed' => true,'comment' => '创建人ID',])

View File

@@ -38,6 +38,5 @@ class Crontab extends Model
const EXECUTE_IMMEDIATELY = 1; // 立即执行 const EXECUTE_IMMEDIATELY = 1; // 立即执行
const EXECUTE_ONCE = 2; // 执行一次 const EXECUTE_ONCE = 2; // 执行一次
const EXECUTE_FORBIDDEN = 3; // 停止执行 const EXECUTE_NORMAL = 3; // 正常执行
} }

View File

@@ -47,7 +47,7 @@ class CrontabLog extends CatchModel
return $this->catchLeftJoin(Crontab::class, 'id', 'crontab_id', ['name', 'group', 'task']) return $this->catchLeftJoin(Crontab::class, 'id', 'crontab_id', ['name', 'group', 'task'])
->catchSearch() ->catchSearch()
->catchOrder() ->catchOrder()
->field(['used_time', 'error_message', 'crontab_log.status', 'crontab_log.id', 'crontab_log.created_at']) ->field(['used_time', 'error_message', $this->aliasField('status'), $this->aliasField('id'), $this->aliasField('created_at')])
->paginate(); ->paginate();
} }
} }

View File

@@ -9,6 +9,8 @@
// | Author: JaguarJack [ njphper@gmail.com ] // | Author: JaguarJack [ njphper@gmail.com ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
/* @var think\Route $router */
// you should use `$router` // you should use `$router`
$router->group('monitor', function () use ($router){ $router->group('monitor', function () use ($router){
// crontab路由 // crontab路由

View File

@@ -100,6 +100,7 @@ class Permission extends CatchController
$permission = $this->permissions->findBy($id); $permission = $this->permissions->findBy($id);
$params = $request->param(); $params = $request->param();
// 按钮类型 // 按钮类型
if ($params['type'] == Permissions::BTN_TYPE && $permission->parent_id) { if ($params['type'] == Permissions::BTN_TYPE && $permission->parent_id) {
$parentPermission = $this->permissions->findBy($permission->parent_id); $parentPermission = $this->permissions->findBy($permission->parent_id);
@@ -175,33 +176,7 @@ class Permission extends CatchController
*/ */
public function show($id) public function show($id)
{ {
$this->permissions->show($id); return CatchResponse::success($this->permissions->show($id));
return CatchResponse::success();
}
/**
*
* @time 2020年06月05日
* @param $id
* @param ParseClass $parseClass
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @return Json
*/
public function getMethods($id, ParseClass $parseClass)
{
$permission = Permissions::where('id', $id)->find();
$module = $permission->module;
$controller = explode('@', $permission->permission_mark)[0];
try {
$methods = $parseClass->setModule('catch')->setRule($module, $controller)->onlySelfMethods();
return CatchResponse::success($methods);
}catch (\Exception $e) {
return CatchResponse::success([]);
}
} }
} }

View File

@@ -1,13 +1,11 @@
<?php <?php
namespace catchAdmin\permissions\controller; namespace catchAdmin\permissions\controller;
use catchAdmin\permissions\model\Permissions;
use catchAdmin\permissions\model\Roles; 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 think\response\Json; use think\response\Json;
use catchAdmin\permissions\model\Roles as RoleModel; use catchAdmin\permissions\model\Roles as RoleModel;
@@ -23,7 +21,7 @@ class Role extends CatchController
/** /**
* *
* @time 2019年12月09日 * @time 2019年12月09日
* @return string * @return string|Json
*/ */
public function index() public function index()
{ {
@@ -46,11 +44,14 @@ class Role extends CatchController
} }
$this->role->storeBy($params); $this->role->storeBy($params);
$permissions = $params['permissions']; // 分配权限
if (!empty($permissions)) { if (count($params['permissions'])) {
$this->role->attachPermissions(array_unique($permissions)); $this->role->attachPermissions(array_unique($params['permissions']));
}
// 分配部门
if (isset($params['departments']) && count($params['departments'])) {
$this->role->attachDepartments($params['departments']);
} }
// 添加角色 // 添加角色
return CatchResponse::success(); return CatchResponse::success();
} }
@@ -59,6 +60,7 @@ 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);
} }
@@ -101,6 +103,28 @@ 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();
} }
@@ -122,6 +146,8 @@ 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();
// 删除 // 删除
@@ -129,37 +155,4 @@ class Role extends CatchController
return CatchResponse::success(); return CatchResponse::success();
} }
/**
*
* @time 2019年12月11日
* @param Request $request
* @param \catchAdmin\permissions\model\Permissions $permission
* @return Json
*/
public function getPermissions(Request $request, \catchAdmin\permissions\model\Permissions $permission): Json
{
$parentRoleHasPermissionIds = [];
if ($request->param('parent_id')) {
$permissions = $this->role->findBy($request->param('parent_id'))->getPermissions();
foreach ($permissions as $_permission) {
$parentRoleHasPermissionIds[] = $_permission->pivot->permission_id;
}
}
$permissions = Tree::done(Permissions::whereIn('id', $parentRoleHasPermissionIds)->select()->toArray());
$permissionIds = [];
if ($request->param('role_id')) {
$roleHasPermissions = $this->role->findBy($request->param('role_id'))->getPermissions();
foreach ($roleHasPermissions as $_permission) {
$permissionIds[] = $_permission->pivot->permission_id;
}
}
return CatchResponse::success([
'permissions' => $permissions,
'hasPermissions' => $permissionIds,
]);
}
} }

View File

@@ -171,51 +171,6 @@ class User extends CatchController
return CatchResponse::success([], '操作成功'); return CatchResponse::success([], '操作成功');
} }
/**
*
* @time 2019年12月07日
* @param $id
* @return \think\response\Json
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\db\exception\DataNotFoundException
*/
public function recover($id): \think\response\Json
{
$trashedUser = $this->user->findBy($id, ['*'], true);
if ($this->user->where('email', $trashedUser->email)->find()) {
return CatchResponse::fail(sprintf('该恢复用户的邮箱 [%s] 已被占用', $trashedUser->email));
}
return CatchResponse::success($this->user->recover($id));
}
/**
*
* @time 2019年12月11日
* @param Request $request
* @param Roles $roles
* @return \think\response\Json
*/
public function getRoles(Request $request, Roles $roles): \think\response\Json
{
$roles = Tree::done($roles->getList());
$roleIds = [];
if ($request->param('uid')) {
$userHasRoles = $this->user->findBy($request->param('uid'))->getRoles();
foreach ($userHasRoles as $role) {
$roleIds[] = $role->pivot->role_id;
}
}
return CatchResponse::success([
'roles' => $roles,
'hasRoles' => $roleIds,
]);
}
/** /**
* 导出 * 导出
* *
@@ -239,6 +194,6 @@ class User extends CatchController
*/ */
public function profile(ProfileRequest $request) public function profile(ProfileRequest $request)
{ {
return CatchResponse::success($this->user->updateBy($request->user()->id, $request->param())); return CatchResponse::success($this->user->updateBy($request->user()->id, $request->filterEmptyField()->param()));
} }
} }

View File

@@ -87,12 +87,18 @@ class Permissions extends CatchModel
*/ */
public static function onAfterInsert(Model $model) public static function onAfterInsert(Model $model)
{ {
$restful = intval($model->getData('restful'));
$model = self::where('id', $model->id)->find(); $model = self::where('id', $model->id)->find();
if ($model && $model->parent_id) { if ($model && $model->parent_id) {
$parent = self::where('id', $model->parent_id)->find(); $parent = self::where('id', $model->parent_id)->find();
$level = $parent->level ? $parent->level . '-' . $parent->id : $parent->id; $level = $parent->level ? $parent->level . '-' . $parent->id : $parent->id;
return $model->where('id', $model->id)->update([
$restful && self::createRestful($model, $level);
return $model->updateBy('id', [
'level' => $level 'level' => $level
]); ]);
} }
@@ -101,6 +107,40 @@ class Permissions extends CatchModel
} }
/**
* 创建 restful 菜单
*
* @time 2021年04月20日
* @param Model $model
* @param $level
* @return void
*/
protected static function createRestful(Model $model, $level)
{
$restful = [
'index' => '列表',
'save' => '保存',
'update' => '更新',
'delete' => '删除',
];
foreach ($restful as $k => $r) {
self::insert([
'parent_id' => $model->id,
'permission_name' => $r,
'level' => $level . '-' . $model->id,
'module' => $model->getData('module'),
'creator_id' => $model->getData('creator_id'),
'permission_mark' => $model->getData('permission_mark') . '@' . $k,
'type' => self::BTN_TYPE,
'created_at' => time(),
'updated_at' => time(),
'sort' => 1,
]);
}
}
public function show($id) public function show($id)
{ {
$permission = $this->findBy($id); $permission = $this->findBy($id);

View File

@@ -35,8 +35,18 @@ class Roles extends CatchModel
public function getList() public function getList()
{ {
return $this->catchSearch() return $this->catchSearch()
->with(['permissions', 'departments'])
->order('id', 'desc') ->order('id', 'desc')
->select() ->select()
->each(function (&$item){
$permissions = $item->permissions->column('id');
unset($item['permissions']);
$item['_permissions'] = $permissions;
$departments = $item->departments->column('id');
unset($item['departments']);
$item['departments'] = $departments;
})
->toTree(); ->toTree();
} }

View File

@@ -5,6 +5,7 @@ use catchAdmin\permissions\model\search\UserSearch;
use catcher\base\CatchModel; use catcher\base\CatchModel;
use catcher\exceptions\FailedException; use catcher\exceptions\FailedException;
use catcher\Utils; use catcher\Utils;
use think\Paginator;
class Users extends CatchModel class Users extends CatchModel
{ {
@@ -47,16 +48,25 @@ class Users extends CatchModel
* 用户列表 * 用户列表
* *
* @time 2019年12月08日 * @time 2019年12月08日
* @throws \think\db\exception\DbException * @return array|\think\Paginator
* @return \think\Paginator *@throws \think\db\exception\DbException
*/ */
public function getList(): \think\Paginator public function getList()
{ {
return $this->withoutField(['updated_at'], true) $users = $this->withoutField(['updated_at', 'password', 'remember_token'], true)
->catchSearch() ->catchSearch()
->catchLeftJoin(Department::class, 'id', 'department_id', ['department_name']) ->catchLeftJoin(Department::class, 'id', 'department_id', ['department_name'])
->with(['jobs', 'roles'])
->order($this->aliasField('id'), 'desc') ->order($this->aliasField('id'), 'desc')
->paginate(); ->paginate()->toArray();
foreach ($users['data'] as &$user) {
$user['roles'] = array_column($user['roles'], 'id');
$user['jobs'] = array_column($user['jobs'], 'id');
}
return Paginator::make($users['data'], $users['per_page'], $users['current_page'], $users['total']);
} }
/** /**

View File

@@ -1,14 +1,13 @@
<?php <?php
/* @var think\Route $router */
$router->group(function () use ($router){ $router->group(function () use ($router){
// 角色 // 角色
$router->resource('roles', '\catchAdmin\permissions\controller\Role'); $router->resource('roles', '\catchAdmin\permissions\controller\Role');
// 角色列表
$router->get('/role/get/permissions', '\catchAdmin\permissions\controller\Role@getPermissions');
// 权限 // 权限
$router->resource('permissions', '\catchAdmin\permissions\controller\Permission'); $router->resource('permissions', '\catchAdmin\permissions\controller\Permission');
$router->put('permissions/show/<id>', '\catchAdmin\permissions\controller\Permission@show'); $router->put('permissions/show/<id>', '\catchAdmin\permissions\controller\Permission@show');
$router->get('controller/methods/<id>', '\catchAdmin\permissions\controller\Permission@getMethods');
// 部门 // 部门
$router->resource('departments', '\catchAdmin\permissions\controller\Department'); $router->resource('departments', '\catchAdmin\permissions\controller\Department');
// 所有职位 // 所有职位
@@ -19,9 +18,7 @@ $router->group(function () use ($router){
$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('user/profile', '\catchAdmin\permissions\controller\User@profile'); $router->put('user/profile', '\catchAdmin\permissions\controller\User@profile');
$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'); $router->get('user/export', '\catchAdmin\permissions\controller\User@export');
})->middleware('auth'); })->middleware('auth');

View File

@@ -0,0 +1,50 @@
<?php
namespace catchAdmin\permissions\tables;
use catchAdmin\permissions\tables\forms\Factory;
use catcher\CatchTable;
use catcher\library\table\Actions;
use catcher\library\table\HeaderItem;
use catcher\library\table\Search;
use catcher\library\table\Table;
class Department extends CatchTable
{
/**
* table
*
* @time 2021年03月29日
* @return array
*/
protected function table(): array
{
// TODO: Implement table() method.
return $this->getTable('department')->header([
HeaderItem::label('部门名称')->prop('department_name'),
HeaderItem::label('排序')->prop('sort')->withEditNumberComponent(),
HeaderItem::label('状态')->prop('status')->withSwitchComponent(),
HeaderItem::label('创建时间')->prop('created_at'),
HeaderItem::label('操作')->width(260)->actions([
Actions::update(),
Actions::delete(),
])
])->withApiRoute('departments')->withActions([
Actions::create()
])->withSearch([
Search::label('部门名称')->text('department_name', '请输入部门名称'),
Search::label('状态')->status()
])->withDialogWidth('35%')
->toTreeTable()->render();
}
/**
* form 方式
*
* @time 2021年03月29日
* @return array
*/
protected function form(): array
{
return Factory::create('department');
}
}

View File

@@ -0,0 +1,44 @@
<?php
namespace catchAdmin\permissions\tables;
use catcher\CatchTable;
use catchAdmin\permissions\tables\forms\Factory;
use catcher\library\table\Actions;
use catcher\library\table\HeaderItem;
use catcher\library\table\Search;
class Job extends CatchTable
{
public function table()
{
return $this->getTable('job')
->header([
HeaderItem::label('')->type('selection'),
HeaderItem::label('岗位名称')->prop('job_name'),
HeaderItem::label('编码')->prop('coding'),
HeaderItem::label('状态')->prop('status')->withSwitchComponent(),
HeaderItem::label('创建时间')->prop('created_at'),
HeaderItem::label('操作')->width(250)->actions([
Actions::update(),
Actions::delete()
])
])
->withActions([
Actions::create()
])
->withSearch([
Search::label('岗位名称')->text('job_name', '岗位名称')
])
->withApiRoute('jobs')
->selectionChange()
->render();
}
public function form()
{
// TODO: Implement form() method.
return Factory::create('job');
}
}

View File

@@ -0,0 +1,50 @@
<?php
namespace catchAdmin\permissions\tables;
use catcher\CatchTable;
use catchAdmin\permissions\tables\forms\Factory;
use catcher\library\table\Actions;
use catcher\library\table\HeaderItem;
use catcher\library\table\Search;
class Permission extends CatchTable
{
public function table()
{
return $this->getTable('permission')
->header([
HeaderItem::label('菜单名称')->prop('permission_name'),
HeaderItem::label('路由Path')->prop('route'),
HeaderItem::label('权限标识')->prop('actionList')->width(250)->component('actions', 'actionList'),
HeaderItem::label('状态')->prop('hidden')->component('status'),
HeaderItem::label('创建时间')->prop('created_at'),
HeaderItem::label('操作')->width(250)->actions([
Actions::update(),
Actions::delete()
])
])
->withActions([
Actions::create()
])
->withSearch([
Search::label('菜单名称')->text('permission_name', '菜单名称')->clearable(true),
Search::hidden('actionList', 'actionList')
])
->withFilterParams([
'permission_name' => '',
'actionList' => 'actionList'
])
->withDefaultQueryParams(['actionList'])
->withApiRoute('permissions')
->toTreeTable()
->render();
}
public function form()
{
// TODO: Implement form() method.
return Factory::create('permission');
}
}

View File

@@ -0,0 +1,43 @@
<?php
namespace catchAdmin\permissions\tables;
use catcher\CatchTable;
use catchAdmin\permissions\tables\forms\Factory;
use catcher\library\table\Actions;
use catcher\library\table\HeaderItem;
use catcher\library\table\Search;
class Role extends CatchTable
{
public function table()
{
// TODO: Implement table() method.
return $this->getTable('role')
->header([
HeaderItem::label('角色名称')->prop('role_name')->width(300),
HeaderItem::label('角色标识')->prop('identify')->width(300),
HeaderItem::label('角色描述')->prop('description'),
HeaderItem::label('创建时间')->prop('created_at'),
HeaderItem::label('操作')->width(250)->actions([
Actions::update(), Actions::delete()
])
])
->withSearch([
Search::label('角色名称')->text('role_name', '角色名称'),
])
->withApiRoute('roles')
->withActions([
Actions::create()
])->withDialogWidth('40%')
->toTreeTable()
->forceUpdate()
->render();
}
protected function form()
{
// TODO: Implement form() method.
return Factory::create('role');
}
}

View File

@@ -0,0 +1,54 @@
<?php
namespace catchAdmin\permissions\tables;
use catcher\CatchTable;
use catchAdmin\permissions\tables\forms\Factory;
use catcher\library\table\Actions;
use catcher\library\table\HeaderItem;
use catcher\library\table\Search;
class User extends CatchTable
{
public function table()
{
// TODO: Implement table() method.
return $this->getTable('user')
->header([
HeaderItem::label('')->selection(),
HeaderItem::label('用户名')->prop('username'),
HeaderItem::label('邮箱')->prop('email'),
HeaderItem::label('状态')->prop('status')->component('status', 'status'),
HeaderItem::label('创建时间')->prop('created_at'),
HeaderItem::label('操作')->width(200)->actions([
Actions::update(), Actions::delete()
])
])
->withSearch([
Search::label('用户名')->text('username', '用户名'),
Search::label('邮箱')->text('email', '邮箱'),
Search::label('状态')->status(),
Search::hidden('department_id', '')
])
->withApiRoute('users')
->withActions([
Actions::create(),
Actions::export()
])
->withExportRoute('user/export')
->withFilterParams([
'username' => '',
'email' => '',
'status' => '',
'department_id' => ''
])
->selectionChange()
->render();
}
protected function form()
{
// TODO: Implement form() method.
return Factory::create('user');
}
}

View File

@@ -0,0 +1,32 @@
<?php
namespace catchAdmin\permissions\tables\forms;
use catchAdmin\permissions\model\Department as DepartmentModel;
use catcher\library\form\Form;
class Department extends Form
{
public function fields(): array
{
return [
// TODO: Implement fields() method
Form::cascader('parent_id', '上级部门', [0])->options(
DepartmentModel::field(['id', 'parent_id', 'department_name'])->select()->toTree()
)->clearable(true)->filterable(true)->props([
'props' => [
'value' => 'id',
'label' => 'department_name',
'checkStrictly' => true
],
])->style(['width' => '100%']),
Form::input('department_name', '部门名称')->required()->placeholder('请输入部门名称'),
Form::input('principal', '部门负责人'),
Form::input('mobile', '负责人联系方式'),
Form::email('email', '邮箱'),
Form::radio('status', '状态')->value(1)->options(
Form::options()->add('启用', 1)->add('禁用', 2)->render()
),
Form::number('sort', '排序')->value(1)->min(1)->max(10000),
];
}
}

View File

@@ -0,0 +1,12 @@
<?php
namespace catchAdmin\permissions\tables\forms;
use catcher\library\form\FormFactory;
class Factory extends FormFactory
{
public static function from(): string
{
return __NAMESPACE__;
}
}

View File

@@ -0,0 +1,23 @@
<?php
namespace catchAdmin\permissions\tables\forms;
use catcher\library\form\Form;
class Job extends Form
{
public function fields(): array
{
// TODO: Implement fields() method.
return [
self::input('job_name', '岗位名称')->required(),
self::input('coding', '岗位编码'),
self::radio('status', '状态')->value(1)->options(
self::options()->add('启用', 1)->add('禁用', 2)->render()
),
self::number('sort', '排序')->value(1)->min(1)->max(10000),
];
}
}

View File

@@ -0,0 +1,155 @@
<?php
namespace catchAdmin\permissions\tables\forms;
use catchAdmin\permissions\model\Permissions;
use catcher\CatchAdmin;
use catcher\library\form\Form;
class Permission extends Form
{
public function fields(): array
{
$this->getModules();
// TODO: Implement fields() method.
return [
self::cascader('parent_id', '父级菜单', [])->options(
Permissions::where('type', Permissions::MENU_TYPE)->field(['id', 'permission_name', 'parent_id'])
->select()->toTree()
)->col(12)->props(self::props('permission_name', 'id', [
'checkStrictly' => true
]))->filterable(true)->clearable(true)->style(['width' => '100%']),
self::radio('type', '菜单类型')
->button()
->value(1)
->options(
self::options()->add('菜单', 1)->add('按钮', 2)->render()
)->appendControl(
1,
[
self::input('permission_name', '菜单名称')->required()->col(12),
self::input('permission_mark', '权限标识')->required()->col(12),
self::select('module', '模块')
->required()
->style(['width' => '100%'])
->allowCreate(true)
->filterable(true)
->clearable(true)
->col(12)
->options($this->getModules()),
self::input('icon', '菜单图标')
->col(12)
->style(['width' => '100%'])
->clearable(true),
self::input('route', '菜单Path')->col(12),
self::cascader('component', '组件')
->col(12)
->options([])
->style(['width' => '100%'])
->showAllLevels(false),
self::input('redirect', 'Redirect')->col(12),
self::number('sort', '排序')->value(1)->col(12),
self::radio('keepalive', 'Keepalive')
->value(1)
->col(12)
->options(
self::options()->add('启用', 1)
->add('禁用', 2)
->render()
),
self::radio('hidden', 'Hidden')->value(1)->options(
self::options()->add('显示', 1)->add('隐藏', 2)->render()
)->col(12),
self::radio('restful', 'Restful 路由')->value(0)->options(
self::options()->add('生成', 1)->add('不生成', 0)->render()
)->col(12)
]
)
->appendControl( 2,
[
self::select('permission_name', '菜单名称')
->allowCreate(true)
->filterable(true)
->options(
self::options()->add('列表', '列表')
->add('创建', '创建')
->add('更新', '更新')->add('读取', '读取')
->add('删除', '删除')->add('禁用/启用', '禁用/启用')
->add('导出', '导出')->add('导入', '导入')->render()
)
->required()->style(['width' => '100%'])->col(12),
self::select('permission_mark', '权限标识')
->allowCreate(true)
->filterable(true)
->options(
self::options()->add('index', 'index')
->add('save', 'save')
->add('update', 'update')->add('read', 'read')
->add('delete', 'delete')->add('disable', 'disable')
->add('export', 'export')->add('import', 'import')->render()
)
->required()->col(12),
self::number('sort', '排序')->value(1)->col(12),
]
)->col(12)
];
}
/**
* 获取模块
*
* @time 2021年03月31日
* @return array
*/
protected function getModules(): array
{
$modules = [];
foreach(CatchAdmin::getModulesDirectory() as $d) {
$module = CatchAdmin::getModuleInfo($d);
if (in_array($module['alias'], ['login'])) {
continue;
}
if ($module['enable']) {
$modules[] = [
'value' => $module['alias'],
'label' => $module['name']
];
}
}
return $modules;
}
/**
* icons
*
* @time 2021年03月31日
* @return array
*/
protected function getIcons(): array
{
$icons = ['platform-eleme', 'eleme', 'delete-solid', 'delete', 's-tools', 'setting', 'user-solid', 'user', 'phone', 'phone-outline', 'more', 'more-outline', 'star-on', 'star-off', 's-goods', 'goods', 'warning', 'warning-outline', 'question', 'info', 'remove', 'circle-plus', 'success', 'error', 'zoom-in', 'zoom-out', 'remove-outline', 'circle-plus-outline', 'circle-check', 'circle-close', 's-help', 'help', 'minus', 'plus', 'check', 'close', 'picture', 'picture-outline', 'picture-outline-round', 'upload', 'upload2', 'download', 'camera-solid', 'camera', 'video-camera-solid', 'video-camera', 'message-solid', 'bell', 's-cooperation', 's-order', 's-platform', 's-fold', 's-unfold', 's-operation', 's-promotion', 's-home', 's-release', 's-ticket', 's-management', 's-open', 's-shop', 's-marketing', 's-flag', 's-comment', 's-finance', 's-claim', 's-custom', 's-opportunity', 's-data', 's-check', 's-grid', 'menu', 'share', 'd-caret', 'caret-left', 'caret-right', 'caret-bottom', 'caret-top', 'bottom-left', 'bottom-right', 'back', 'right', 'bottom', 'top', 'top-left', 'top-right', 'arrow-left', 'arrow-right', 'arrow-down', 'arrow-up', 'd-arrow-left', 'd-arrow-right', 'video-pause', 'video-play', 'refresh', 'refresh-right', 'refresh-left', 'finished', 'sort', 'sort-up', 'sort-down', 'rank', 'loading', 'view', 'c-scale-to-original', 'date', 'edit', 'edit-outline', 'folder', 'folder-opened', 'folder-add', 'folder-remove', 'folder-delete', 'folder-checked', 'tickets', 'document-remove', 'document-delete', 'document-copy', 'document-checked', 'document', 'document-add', 'printer', 'paperclip', 'takeaway-box', 'search', 'monitor', 'attract', 'mobile', 'scissors', 'umbrella', 'headset', 'brush', 'mouse', 'coordinate', 'magic-stick', 'reading', 'data-line', 'data-board', 'pie-chart', 'data-analysis', 'collection-tag', 'film', 'suitcase', 'suitcase-1', 'receiving', 'collection', 'files', 'notebook-1', 'notebook-2', 'toilet-paper', 'office-building', 'school', 'table-lamp', 'house', 'no-smoking', 'smoking', 'shopping-cart-full', 'shopping-cart-1', 'shopping-cart-2', 'shopping-bag-1', 'shopping-bag-2', 'sold-out', 'sell', 'present', 'box', 'bank-card', 'money', 'coin', 'wallet', 'discount', 'price-tag', 'news', 'guide', 'male', 'female', 'thumb', 'cpu', 'link', 'connection', 'open', 'turn-off', 'set-up', 'chat-round', 'chat-line-round', 'chat-square', 'chat-dot-round', 'chat-dot-square', 'chat-line-square', 'message', 'postcard', 'position', 'turn-off-microphone', 'microphone', 'close-notification', 'bangzhu', 'time', 'odometer', 'crop', 'aim', 'switch-button', 'full-screen', 'copy-document', 'mic', 'stopwatch', 'medal-1', 'medal', 'trophy', 'trophy-1', 'first-aid-kit', 'discover', 'place', 'location', 'location-outline', 'location-information', 'add-location', 'delete-location', 'map-location', 'alarm-clock', 'timer', 'watch-1', 'watch', 'lock', 'unlock', 'key', 'service', 'mobile-phone', 'bicycle', 'truck', 'ship', 'basketball', 'football', 'soccer', 'baseball', 'wind-power', 'light-rain', 'lightning', 'heavy-rain', 'sunrise', 'sunrise-1', 'sunset', 'sunny', 'cloudy', 'partly-cloudy', 'cloudy-and-sunny', 'moon', 'moon-night', 'dish', 'dish-1', 'food', 'chicken', 'fork-spoon', 'knife-fork', 'burger', 'tableware', 'sugar', 'dessert', 'ice-cream', 'hot-water', 'water-cup', 'coffee-cup', 'cold-drink', 'goblet', 'goblet-full', 'goblet-square', 'goblet-square-full', 'refrigerator', 'grape', 'watermelon', 'cherry', 'apple', 'pear', 'orange', 'coffee', 'ice-tea', 'ice-drink', 'milk-tea', 'potato-strips', 'lollipop', 'ice-cream-square', 'ice-cream-round'];
$options = self::options();
foreach ($icons as $icon) {
$icon = 'el-icon-' . $icon;
$options->add(htmlspecialchars(sprintf('<i class=\"%s\"></i> %s', $icon, $icon)), $icon);
}
return $options->render();
}
}

View File

@@ -0,0 +1,67 @@
<?php
namespace catchAdmin\permissions\tables\forms;
use catchAdmin\permissions\model\Department as DepartmentModel;
use catchAdmin\permissions\model\Permissions;
use catchAdmin\permissions\model\Roles;
use catcher\library\form\Form;
class Role extends Form
{
public function fields(): array
{
// TODO: Implement fields() method.
return [
Form::cascader('parent_id', '上级角色', [])->options(
Roles::field(['id', 'parent_id', 'role_name'])->select()->toTree()
)->clearable(true)->filterable(true)->props([
'props' => [
'value' => 'id',
'label' => 'role_name',
'checkStrictly' => true
],
])->style(['width' => '100%']),
self::input('role_name', '角色名称')->required()
->clearable(true)->placeholder('请填写角色名称'),
self::input('identify', '角色标识')
->clearable(true)->required()
->placeholder('请填写角色标识'),
self::textarea('description', '角色描述')
->clearable(true)->placeholder('请填写角色描述'),
self::tree('_permissions', '角色权限', [])
->props(self::props('permission_name', 'id', [],
Permissions::field(['id', 'parent_id', 'permission_name'])->select()->toTree()
))
->required(),
self::select('data_range', '数据权限')
->placeholder('请选择数据权限')
->options(
self::options()->add('请选择数据权限', 0)
->add('全部数据权限', Roles::ALL_DATA)
->add('自定义数据权限', Roles::SELF_CHOOSE)
->add('仅本人数据权限', Roles::SELF_DATA)
->add('本部门数据权限', Roles::DEPARTMENT_DATA)
->add('部门以及以下数据权限', Roles::DEPARTMENT_DOWN_DATA)
->render()
)->style(['width' => '100%'])
->appendControl(Roles::SELF_CHOOSE, [
self::cascader('departments', '自定义权限')
->options(
DepartmentModel::field(['id', 'parent_id', 'department_name'])->select()->toTree()
)
->props(self::props('department_name', 'id', [
'multiple' => true,
'emitPath' => false
]))
->showAllLevels(false)
->style(['width' => '100%']),
])
];
}
}

View File

@@ -0,0 +1,42 @@
<?php
namespace catchAdmin\permissions\tables\forms;
use catchAdmin\permissions\model\Department as DepartmentModel;
use catchAdmin\permissions\model\Job;
use catchAdmin\permissions\model\Roles;
use catcher\library\form\Form;
class User extends Form
{
public function fields(): array
{
// TODO: Implement fields() method.
return [
self::input('username', '昵称')->col(self::col(12))->clearable(true)->required(),
self::cascader('department_id', '部门', [])
->col(self::col(12))
->options(
DepartmentModel::field(['id', 'parent_id', 'department_name'])->select()->toTree()
)
->props(self::props('department_name', 'id', [
'checkStrictly' => true
]))->clearable(true),
self::email('email', '邮箱')->col(self::col(12))->required()->clearable(true),
self::selectMultiple('jobs', '岗位', [])
->col(self::col(12))->options(
Job::where('status', Job::ENABLE)->field(['id as value', 'job_name as label'])->select()->toArray()
)->clearable(true)->filterable(true),
self::input('password', '密码')->col(self::col(12))
->placeholder('请输入密码')->clearable(true),
self::tree('roles', '角色', [])
->props(self::props('role_name', 'id', [], Roles::field(['id', 'parent_id', 'role_name'])->select()->toTree()))
->required(),
];
}
}

View File

@@ -9,6 +9,8 @@
// | Author: JaguarJack [ njphper@gmail.com ] // | Author: JaguarJack [ njphper@gmail.com ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
/* @var think\Route $router */
// you should use `$router` // you should use `$router`
$router->group('sms', function () use ($router){ $router->group('sms', function () use ($router){
// config路由 // config路由

View File

@@ -4,8 +4,6 @@ namespace catchAdmin\system\controller;
use catcher\base\CatchController; 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\facade\FileSystem;
class Attachments extends CatchController class Attachments extends CatchController
{ {
@@ -35,22 +33,6 @@ class Attachments extends CatchController
*/ */
public function delete($id, AttachmentsModel $model) public function delete($id, AttachmentsModel $model)
{ {
$attachments = $model->whereIn('id', Utils::stringToArrayBy($id))->select(); return CatchResponse::success($model->deletes($id));
if ($model->deleteBy($id)) {
foreach ($attachments as $attachment) {
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);
}
}
}
return CatchResponse::success();
} }
} }

View File

@@ -0,0 +1,105 @@
<?php
namespace catchAdmin\system\controller;
use catcher\base\CatchController;
use catcher\CatchResponse;
use think\Request;
class Excel extends CatchController
{
/**
* 导出
*
* @time 2021年04月22日
* @param Request $request
* @return \think\response\Json
*/
public function export(Request $request): \think\response\Json
{
$fields = $this->resetFields(\json_decode($request->post('fields'), true));
$excel = app()->make($request->post('model'))
->field(array_column($fields, 'field'))
->select()
->each(function (&$item, $key) use ($fields) {
foreach ($fields as $field) {
if (isset($field['options']) && count($field['options'])) {
$options = $this->valueToLabel($field['options']);
$item[$field['field']] = $options[$item[$field['field']]] ?? '';
}
}
})->export(array_column($fields, 'name'));
return CatchResponse::success($excel);
}
/**
* 导入
*
* @time 2021年04月23日
* @param Request $request
* @return \think\response\Json
*/
public function import(Request $request): \think\response\Json
{
return CatchResponse::success(app()->make($request->post('model'))
->import(
\json_decode($request->post('fields'), 'field'),
$request->file('file')
));
}
/**
* value => label
*
* @time 2021年04月22日
* @param array $options
* @return array
*/
protected function valueToLabel(array $options): array
{
$p = [];
foreach ($options as $option) {
$p[$option['value']] = $option['label'];
}
return $p;
}
/**
*label => value
*
* @time 2021年04月22日
* @param array $options
* @return array
*/
protected function labelToValue(array $options): array
{
$p = [];
foreach ($options as $option) {
$p[$option['label']] = $option['value'];
}
return $p;
}
/**
* 重组 fields
*
* @time 2021年04月22日
* @param array $fields
* @return array
*/
protected function resetFields(array $fields): array
{
$f = [];
foreach ($fields as $field) {
$f[$field['field']] = $field;
}
return $f;
}
}

View File

@@ -17,12 +17,12 @@ class Module extends CatchController
* *
* @return Json * @return Json
*/ */
public function index() public function index(): Json
{ {
$modules = []; $modules = [];
foreach(CatchAdmin::getModulesDirectory() as $d) { foreach(CatchAdmin::getModulesDirectory() as $d) {
$modules[] = json_decode(file_get_contents($d . 'module.json'), true); $modules[] = CatchAdmin::getModuleInfo($d);
} }
$hasModules = array_unique(Permissions::whereIn('id', request()->user()->getPermissionsBy())->column('module')); $hasModules = array_unique(Permissions::whereIn('id', request()->user()->getPermissionsBy())->column('module'));
@@ -51,7 +51,7 @@ class Module extends CatchController
* @throws \think\db\exception\ModelNotFoundException * @throws \think\db\exception\ModelNotFoundException
* @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DataNotFoundException
*/ */
public function disOrEnable(string $module) public function disOrEnable(string $module): Json
{ {
$moduleInfo = CatchAdmin::getModuleInfo(CatchAdmin::directory() . $module); $moduleInfo = CatchAdmin::getModuleInfo(CatchAdmin::directory() . $module);
@@ -71,7 +71,7 @@ class Module extends CatchController
* @time 2020年09月21日 * @time 2020年09月21日
* @return Json * @return Json
*/ */
public function cache() public function cache(): Json
{ {
return CatchResponse::success(CatchAdmin::cacheServices()); return CatchResponse::success(CatchAdmin::cacheServices());
} }
@@ -82,7 +82,7 @@ class Module extends CatchController
* @time 2020年09月21日 * @time 2020年09月21日
* @return Json * @return Json
*/ */
public function clear() public function clear(): Json
{ {
return !file_exists(CatchAdmin::getCacheServicesFile()) ? return !file_exists(CatchAdmin::getCacheServicesFile()) ?
CatchResponse::fail('模块没有缓存') : CatchResponse::fail('模块没有缓存') :

View File

@@ -746,28 +746,7 @@ class SystemMenusSeed extends Seeder
'deleted_at' => 0, '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

@@ -3,8 +3,10 @@ namespace catchAdmin\system\model;
use catchAdmin\system\model\search\AttachmentsSearch; use catchAdmin\system\model\search\AttachmentsSearch;
use catcher\base\CatchModel; use catcher\base\CatchModel;
use catcher\Utils;
use think\file\UploadedFile; use think\file\UploadedFile;
use think\Model; use think\Model;
use think\facade\Filesystem;
class Attachments extends CatchModel class Attachments extends CatchModel
{ {
@@ -54,4 +56,37 @@ class Attachments extends CatchModel
'path' => $data['path'] 'path' => $data['path']
]); ]);
} }
/**
* 批量删除
*
* @time 2021年03月01日
* @param $id
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @return bool
*/
public function deletes($id): bool
{
Utils::setFilesystemConfig();
$this->whereIn('id', Utils::stringToArrayBy($id))
->select()
->each(function ($attachment){
if ($attachment->delete()) {
if ($attachment->driver == 'local') {
$localPath = config('filesystem.disks.local.root') . DIRECTORY_SEPARATOR;
$path = $localPath . str_replace('\\','\/', $attachment->path);
if (file_exists($path)) {
Filesystem::delete($path);
}
} else {
Filesystem::delete($attachment->path);
}
}
});
return true;
}
} }

View File

@@ -11,7 +11,6 @@ class OperateLog extends \think\Model
use BaseOptionsTrait; use BaseOptionsTrait;
use OperateLogSearch; use OperateLogSearch;
protected $name = 'operate_log'; protected $name = 'operate_log';
protected $field = [ protected $field = [
@@ -42,4 +41,9 @@ class OperateLog extends \think\Model
->order($this->aliasField('id'), 'desc') ->order($this->aliasField('id'), 'desc')
->paginate(); ->paginate();
} }
protected function getCreatedAtAttr($value)
{
return date('Y-m-d H:i:s', $value);
}
} }

View File

@@ -24,6 +24,6 @@ trait DeveloperSearch
public function searchStatusAttr($query, $value, $data) public function searchStatusAttr($query, $value, $data)
{ {
return $query->where('driver', $value); return $query->where('status', $value);
} }
} }

View File

@@ -1,4 +1,7 @@
<?php <?php
/* @var think\Route $router */
$router->group(function () use ($router) { $router->group(function () use ($router) {
// 登录日志 // 登录日志
$router->get('log/login', '\catchAdmin\system\controller\LoginLog@list'); $router->get('log/login', '\catchAdmin\system\controller\LoginLog@list');
@@ -46,6 +49,17 @@ $router->group(function () use ($router) {
$router->put('cache/modules', '\catchAdmin\system\controller\Module@cache'); $router->put('cache/modules', '\catchAdmin\system\controller\Module@cache');
$router->delete('clear/modules', '\catchAdmin\system\controller\Module@clear'); $router->delete('clear/modules', '\catchAdmin\system\controller\Module@clear');
// excel 导入&导出通用
$router->post('excel/export', '\catchAdmin\system\controller\Excel@export');
$router->post('excel/import', '\catchAdmin\system\controller\Excel@import');
})->middleware('auth'); })->middleware('auth');
// 获取 table
$router->get('table/<module>/<tableClass>', function ($module, $tableClass){
$table = sprintf('\\catchAdmin\\%s\\tables\\%s', $module, ucfirst($tableClass));
return (new $table)->render(request()->param('only'));
});

View File

@@ -0,0 +1,46 @@
<?php
namespace catchAdmin\system\tables;
use catcher\CatchTable;
use catcher\library\table\Actions;
use catcher\library\table\HeaderItem;
use catcher\library\table\Search;
class Database extends CatchTable
{
protected function form()
{
// TODO: Implement form() method.
return [];
}
protected function table()
{
// TODO: Implement table() method.
return $this->getTable('database')
->header([
HeaderItem::label('表名')->prop('name'),
HeaderItem::label('引擎')->prop('engine'),
HeaderItem::label('字符集')->prop('collation'),
HeaderItem::label('数据行数')->prop('rows'),
HeaderItem::label('数据大小')->prop('data_length'),
HeaderItem::label('索引大小')->prop('index_length'),
HeaderItem::label('注释')->prop('comment'),
HeaderItem::label('创建时间')->prop('create_time'),
HeaderItem::label('操作')->actions([
Actions::view()
]),
])
->withApiRoute('tables')
->withSearch([
Search::text('tablename', '请输入表名'),
Search::select('engine', '请选择引擎', [
['label' => 'MyISAM', 'value' => 'MyISAM'],
['label' => 'InnoDB', 'value' => 'InnoDB']
])
])
->render();
}
}

View File

@@ -0,0 +1,40 @@
<?php
namespace catchAdmin\system\tables;
use catchAdmin\system\tables\forms\Factory;
use catcher\CatchTable;
use catcher\library\table\HeaderItem;
use catcher\library\table\Search;
class LoginLog extends CatchTable
{
protected function form()
{
// TODO: Implement form() method.
return [];
}
protected function table()
{
// TODO: Implement table() method.
return $this->getTable('loginLog')
->header([
HeaderItem::label()->selection(),
HeaderItem::label('登陆用户')->prop('login_name'),
HeaderItem::label('登陆IP')->prop('login_ip'),
HeaderItem::label('客户端')->prop('browser'),
HeaderItem::label('系统')->prop('os'),
HeaderItem::label('登陆状态')->prop('status')->component('status'),
HeaderItem::label('登陆时间')->prop('login_at')->component('loginAt'),
])
->withApiRoute('log/login')
->withSearch([
Search::startAt(),
Search::label('结束时间')->endAt()
])
->selectionChange()
->render();
}
}

View File

@@ -0,0 +1,46 @@
<?php
namespace catchAdmin\system\tables;
use catcher\CatchTable;
use catcher\library\table\HeaderItem;
use catcher\library\table\Search;
class OperateLog extends CatchTable
{
protected function form()
{
// TODO: Implement form() method.
return [];
}
protected function table()
{
// TODO: Implement table() method.
return $this->getTable('operateLog')
->header([
HeaderItem::label()->selection(),
HeaderItem::label('编号')->prop('id'),
HeaderItem::label('操作人')->prop('creator'),
HeaderItem::label('操作模块')->prop('module'),
HeaderItem::label('操作菜单')->prop('operate'),
HeaderItem::label('菜单标识')->prop('route'),
HeaderItem::label('请求方式')->prop('method'),
HeaderItem::label('参数')->prop('params')->component('params'),
])
->withApiRoute('log/operate')
->withSearch([
Search::text('creator', '请输入操作人'),
Search::text('module', '请输入模块'),
Search::select('method', '请选择请求方法', [
['label' => 'GET', 'value' => 'GET'],
['label' => 'POST', 'value' => 'POST'],
['label' => 'PUT', 'value' => 'PUT'],
['label' => 'DELETE', 'value' => 'DELETE'],
])
])
->selectionChange()
->render();
}
}

View File

@@ -0,0 +1,45 @@
<?php
namespace catchAdmin\system\tables;
use catchAdmin\system\tables\forms\Factory;
use catcher\CatchTable;
use catcher\library\table\Actions;
use catcher\library\table\HeaderItem;
use catcher\library\table\Search;
class SensitiveWord extends CatchTable
{
protected function form()
{
// TODO: Implement form() method.
return Factory::create('SensitiveWord');
}
protected function table()
{
// TODO: Implement table() method.
return $this->getTable('SensitiveWord')
->header([
HeaderItem::label()->selection(),
HeaderItem::label('编号')->prop('id'),
HeaderItem::label('敏感词')->prop('word'),
HeaderItem::label('创建人')->prop('creator'),
HeaderItem::label('创建时间')->prop('created_at'),
HeaderItem::label('更新时间')->prop('updated_at'),
HeaderItem::label('操作')->actions([
Actions::update(),
Actions::delete()
])
])
->withActions([
Actions::create()
])
->withDialogWidth('35%')
->withApiRoute('sensitive/word')
->withSearch([
Search::text('word', '输入敏感词')
])
->selectionChange()
->render();
}
}

View File

@@ -0,0 +1,12 @@
<?php
namespace catchAdmin\system\tables\forms;
use catcher\library\form\FormFactory;
class Factory extends FormFactory
{
public static function from(): string
{
return __NAMESPACE__;
}
}

View File

@@ -0,0 +1,15 @@
<?php
namespace catchAdmin\system\tables\forms;
use catchAdmin\permissions\model\Department as DepartmentModel;
use catcher\library\form\Form;
class SensitiveWord extends Form
{
public function fields(): array
{
return [
Form::input('word', '敏感词')->required()->placeholder('请输入敏感词'),
];
}
}

View File

@@ -9,6 +9,8 @@
* @license https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt * @license https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt
*/ */
/* @var think\Route $router */
$router->group('wechat', function () use ($router){ $router->group('wechat', function () use ($router){
// 公众号粉丝 // 公众号粉丝
$router->group('official/users', function () use ($router){ $router->group('official/users', function () use ($router){

View File

@@ -19,18 +19,20 @@
"require": { "require": {
"php": ">=7.1.0", "php": ">=7.1.0",
"topthink/framework": "6.0.6", "topthink/framework": "6.0.6",
"topthink/think-orm": "2.0.33", "topthink/think-orm": "2.0.36",
"topthink/think-migration": "^3.0", "topthink/think-migration": "^3.0",
"thans/tp-jwt-auth": "1.1", "thans/tp-jwt-auth": "^1.1",
"overtrue/wechat": "^4.2", "overtrue/wechat": "^4.2",
"phpoffice/phpspreadsheet": "^1.12", "phpoffice/phpspreadsheet": "^1.12",
"dragonmantank/cron-expression": "^3.0", "dragonmantank/cron-expression": "3.1",
"symfony/finder": "^4.4", "symfony/finder": "^4.4",
"ext-json": "*", "ext-json": "*",
"overtrue/easy-sms": "^1.1", "overtrue/easy-sms": "^1.1",
"jaguarjack/migration-generator": "dev-master", "jaguarjack/migration-generator": "dev-master",
"lcobucci/jwt": "3.3", "lcobucci/jwt": "3.3",
"jaguarjack/think-filesystem-cloud": "1.0" "jaguarjack/think-filesystem-cloud": "1.0",
"topthink/think-view": "^1.0",
"xaboy/form-builder": "~2.0"
}, },
"require-dev": { "require-dev": {
"topthink/think-trace": "^1.0", "topthink/think-trace": "^1.0",

View File

@@ -3,13 +3,13 @@ declare(strict_types=1);
namespace catcher; namespace catcher;
use think\helper\Arr; use catcher\facade\FileSystem;
class CatchAdmin class CatchAdmin
{ {
public static $root = 'catch'; public static $root = 'catch';
public const VERSION = '2.1.0'; public const VERSION = '2.5.0';
/** /**
@@ -22,6 +22,20 @@ class CatchAdmin
return app()->getRootPath() . self::$root . DIRECTORY_SEPARATOR; return app()->getRootPath() . self::$root . DIRECTORY_SEPARATOR;
} }
/**
* 设置 root
*
* @time 2021年03月28日
* @param $root
* @return CatchAdmin
*/
public static function setRoot($root): CatchAdmin
{
self::$root = $root;
return new self();
}
/** /**
* 创建目录 * 创建目录
* *
@@ -192,7 +206,7 @@ class CatchAdmin
* @time 2020年06月23日 * @time 2020年06月23日
* @return array * @return array
*/ */
public static function getEnabledService() public static function getEnabledService(): array
{ {
$services = []; $services = [];
@@ -211,96 +225,70 @@ class CatchAdmin
} }
/** /**
* 开启模块 * 获取模块 Json
* *
* @time 2020年06月23 * @time 2021年02月08
* @param $module * @param $module
* @return bool * @return string
*/ */
public static function enableModule($module) public static function getModuleJson($module): string
{ {
$moduleJson = self::moduleDirectory($module) . 'module.json'; if (is_dir($module)) {
return $module . DIRECTORY_SEPARATOR . 'module.json';
if (!file_exists($moduleJson)) {
return true;
} }
$info = \json_decode(file_get_contents($moduleJson), true); return self::moduleDirectory($module) . 'module.json';
$info['enable'] = true;
if (!is_writeable($moduleJson)) {
chmod($moduleJson, 666);
}
file_put_contents($moduleJson, \json_encode($info, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
return true;
}
/**
* 关闭模块
*
* @time 2020年06月23日
* @param $module
* @return bool
*/
public static function disableModule($module)
{
$moduleJson = self::moduleDirectory($module) . 'module.json';
if (!file_exists($moduleJson)) {
return true;
}
$info = \json_decode(file_get_contents($moduleJson), true);
$info['enable'] = false;
if (!is_writeable($moduleJson)) {
chmod($moduleJson, 666);
}
file_put_contents($moduleJson, \json_encode($info, JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE));
return true;
}
/**
*
* @time 2019年11月30日
* @return array
*/
protected static function getModuleViews(): array
{
$views = [];
foreach (self::getModulesDirectory() as $module) {
if (is_dir($module . 'view')) {
$moduleInfo = self::getModuleInfo($module);
$moduleName = $moduleInfo['alias'] ?? Arr::last(explode('/', $module));
$views[$moduleName] = $module . 'view' . DIRECTORY_SEPARATOR;
}
}
return $views;
} }
/** /**
* 获取模块信息 * 获取模块信息
* *
* @time 2019年11月30 * @time 2021年02月08
* @param $module * @param $module
* @return mixed * @return array
*/ */
public static function getModuleInfo($module) public static function getModuleInfo($module): array
{ {
if (file_exists($module . DIRECTORY_SEPARATOR . 'module.json')) { $moduleJson = self::getModuleJson($module);
return \json_decode(file_get_contents($module. DIRECTORY_SEPARATOR . 'module.json'), true);
} if (!file_exists($moduleJson)) {
return []; return [];
} }
return \json_decode(FileSystem::sharedGet($moduleJson), true);
}
/**
* 更新模块信息
*
* @time 2021年02月08日
* @param $module
* @param $info
* @return bool
*/
public static function updateModuleInfo($module, $info): bool
{
$moduleInfo = self::getModuleInfo($module);
if (!count($moduleInfo)) {
return false;
}
foreach ($moduleInfo as $k => $v) {
if (isset($info[$k])) {
$moduleInfo[$k] = $info[$k];
}
}
if (! is_writeable(self::getModuleJson($module))) {
chmod(self::getModuleJson($module), 666);
}
FileSystem::put(self::getModuleJson($module), \json_encode($moduleInfo, JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE));
return true;
}
/** /**
* 获取服务 * 获取服务
* *
@@ -321,7 +309,7 @@ class CatchAdmin
* @time 2019年11月30日 * @time 2019年11月30日
* @return mixed * @return mixed
*/ */
public static function getRoutes() public static function getRoutes(): array
{ {
if (file_exists(self::getCacheRoutesFile())) { if (file_exists(self::getCacheRoutesFile())) {
return [self::getCacheRoutesFile()]; return [self::getCacheRoutesFile()];
@@ -330,19 +318,6 @@ class CatchAdmin
return self::getModuleRoutes(); return self::getModuleRoutes();
} }
/**
*
* @time 2019年11月30日
* @return array|mixed
*/
public static function getViews()
{
if (file_exists(self::getCacheViewsFile())) {
return self::getCacheViews();
}
return self::getModuleViews();
}
/** /**
* *
@@ -390,27 +365,6 @@ class CatchAdmin
. var_export(self::getEnabledService(), true) . ';'); . var_export(self::getEnabledService(), true) . ';');
} }
/**
*
* @time 2019年11月30日
* @return false|int
*/
public static function cacheViews()
{
return file_put_contents(self::getCacheViewsFile(), "<?php\r\n return "
. var_export(self::getModuleViews(), true) . ';');
}
/**
*
* @time 2019年11月30日
* @return mixed
*/
protected static function getCacheViews()
{
return include self::getCacheViewsFile();
}
/** /**
* *
* @time 2019年11月30日 * @time 2019年11月30日
@@ -420,22 +374,13 @@ class CatchAdmin
{ {
return include self::getCacheServicesFile(); return include self::getCacheServicesFile();
} }
/**
*
* @time 2019年11月30日
* @return mixed
*/
protected static function getCacheViewsFile()
{
return self::cacheDirectory() . 'views.php';
}
/** /**
* *
* @time 2019年11月30日 * @time 2019年11月30日
* @return mixed * @return mixed
*/ */
public static function getCacheServicesFile() public static function getCacheServicesFile(): string
{ {
return self::cacheDirectory() . 'services.php'; return self::cacheDirectory() . 'services.php';
} }

View File

@@ -103,7 +103,10 @@ class CatchAdminService extends Service
{ {
$connections = $this->app->config->get('database.connections'); $connections = $this->app->config->get('database.connections');
$connections['mysql']['query'] = CatchQuery::class; // 支持多数据库配置注入 Query
foreach ($connections as &$connection) {
$connection['query'] = CatchQuery::class;
}
$this->app->config->set([ $this->app->config->set([
'connections' => $connections 'connections' => $connections

View File

@@ -8,7 +8,6 @@ use catcher\exceptions\FailedException;
use catcher\exceptions\LoginFailedException; use catcher\exceptions\LoginFailedException;
use thans\jwt\facade\JWTAuth; use thans\jwt\facade\JWTAuth;
use think\facade\Session; use think\facade\Session;
use think\helper\Str;
class CatchAuth class CatchAuth
{ {
@@ -65,8 +64,6 @@ class CatchAuth
*/ */
public function attempt($condition) public function attempt($condition)
{ {
try {
$user = $this->authenticate($condition); $user = $this->authenticate($condition);
if (!$user) { if (!$user) {
@@ -81,10 +78,6 @@ class CatchAuth
} }
return $this->{$this->getDriver()}($user); return $this->{$this->getDriver()}($user);
} catch (\Exception $exception) {
//
}
} }
@@ -250,8 +243,10 @@ class CatchAuth
{ {
$where = []; $where = [];
$fields = array_keys(app($this->getProvider()['model'])->getFields());
foreach ($condition as $field => $value) { foreach ($condition as $field => $value) {
if ($field != $this->password) { if (in_array($field, $fields) && $field != $this->password) {
$where[$field] = $value; $where[$field] = $value;
} }
} }

View File

@@ -3,7 +3,6 @@ declare(strict_types=1);
namespace catcher; namespace catcher;
use app\ExceptionHandle;
use catcher\exceptions\CatchException; use catcher\exceptions\CatchException;
use catcher\exceptions\FailedException; use catcher\exceptions\FailedException;
use think\db\exception\DataNotFoundException; use think\db\exception\DataNotFoundException;

View File

@@ -6,6 +6,7 @@ namespace catcher;
use catcher\library\excel\Excel; use catcher\library\excel\Excel;
use catcher\library\excel\ExcelContract; use catcher\library\excel\ExcelContract;
use think\facade\Cache; use think\facade\Cache;
use think\helper\Str;
use think\model\Collection; use think\model\Collection;
class CatchModelCollection extends Collection class CatchModelCollection extends Collection
@@ -19,9 +20,9 @@ class CatchModelCollection extends Collection
* @param string $children * @param string $children
* @return array * @return array
*/ */
public function toTree($pid = 0, $pidField = 'parent_id', $children = 'children') public function toTree($pid = 0, $pidField = 'parent_id', $children = 'children'): array
{ {
return Tree::done($this->items, $pid, $pidField, $children); return Tree::done($this->toArray(), $pid, $pidField, $children);
} }
@@ -35,7 +36,7 @@ class CatchModelCollection extends Collection
* @throws \PhpOffice\PhpSpreadsheet\Exception * @throws \PhpOffice\PhpSpreadsheet\Exception
* @return mixed|string[] * @return mixed|string[]
*/ */
public function export($header, $path = '', $disk = 'local') public function export($header, $path = '', $disk = 'local'): array
{ {
$excel = new Class($header, $this->items) implements ExcelContract $excel = new Class($header, $this->items) implements ExcelContract
{ {
@@ -80,7 +81,7 @@ class CatchModelCollection extends Collection
* @return bool * @return bool
* @throws \Psr\SimpleCache\InvalidArgumentException * @throws \Psr\SimpleCache\InvalidArgumentException
*/ */
public function cache($key, int $ttl = 0, string $store = 'redis') public function cache($key, int $ttl = 0, string $store = 'redis'): bool
{ {
return Cache::store($store)->set($key, $this->items, $ttl); return Cache::store($store)->set($key, $this->items, $ttl);
} }
@@ -94,18 +95,31 @@ class CatchModelCollection extends Collection
* @param string $column * @param string $column
* @return array * @return array
*/ */
public function getAllChildrenIds(array $ids, $parentFields = 'parent_id', $column = 'id') public function getAllChildrenIds(array $ids, $parentFields = 'parent_id', $column = 'id'): array
{ {
array_walk($ids, function (&$item){ array_walk($ids, function (&$item){
$item = intval($item); $item = intval($item);
}); });
$childDepartmentIds = $this->whereIn($parentFields, $ids)->column($column); $childIds = $this->whereIn($parentFields, $ids)->column($column);
if (!empty($childDepartmentIds)) { if (!empty($childIds)) {
$childDepartmentIds = array_merge($childDepartmentIds, $this->getAllChildrenIds($childDepartmentIds)); $childIds = array_merge($childIds, $this->getAllChildrenIds($childIds));
} }
return $childDepartmentIds; return $childIds;
}
/**
* implode
*
* @time 2021年02月24日
* @param string $separator
* @param string $column
* @return string
*/
public function implode(string $column = '', string $separator = ','): string
{
return implode($separator, $column ? array_column($this->items, $column) : $this->items);
} }
} }

View File

@@ -181,10 +181,13 @@ class CatchQuery extends Query
$this->whereRightLike($field, $value); $this->whereRightLike($field, $value);
} }
} }
// = 值搜索 // = 值搜索
if ($value || is_numeric($value)) {
$this->where($field, $value); $this->where($field, $value);
} }
} }
}
return $this; return $this;
} }
@@ -296,6 +299,10 @@ class CatchQuery extends Query
$this->order($this->getTable() . '.sort', $order); $this->order($this->getTable() . '.sort', $order);
} }
if (in_array('weight', array_keys($this->getFields()))) {
$this->order($this->getTable() . '.weight', $order);
}
$this->order($this->getTable() . '.' . $this->getPk(), $order); $this->order($this->getTable() . '.' . $this->getPk(), $order);
return $this; return $this;

View File

@@ -0,0 +1,45 @@
<?php
namespace catcher;
use catcher\library\table\Table;
abstract class CatchTable
{
abstract protected function table();
abstract protected function form();
/**
* 渲染
*
* @time 2021年03月29日
* @param $only => form || table
* @return array|\think\response\Json
*/
public function render($only)
{
if ($only) {
return CatchResponse::success([
$only => $this->{$only}()
]);
}
return CatchResponse::success([
'table' => $this->table(),
'form' => $this->form()
]);
}
/**
* 获取表对象
*
* @time 2021年03月30日
* @param string $tableName
* @return Table
*/
protected function getTable(string $tableName): Table
{
return new Table($tableName);
}
}

View File

@@ -47,11 +47,6 @@ class CatchUpload
*/ */
protected $path = ''; protected $path = '';
public function __construct()
{
$this->initDriver();
}
/** /**
* upload files * upload files
* *
@@ -89,6 +84,21 @@ class CatchUpload
} }
} }
/**
* 上传到 Local
*
* @time 2021年04月21日
* @param $file
* @return string
*/
public function toLocal($file): string
{
$path = Filesystem::disk(self::LOCAL)->putFile($this->getPath(), $file);
return public_path() . $this->getLocalPath($path);
}
/** /**
* 本地路径 * 本地路径
* *
@@ -96,7 +106,7 @@ class CatchUpload
* @param $path * @param $path
* @return string * @return string
*/ */
protected function getLocalPath($path) protected function getLocalPath($path): string
{ {
if ($this->getDriver() === self::LOCAL) { if ($this->getDriver() === self::LOCAL) {
@@ -259,70 +269,9 @@ class CatchUpload
* @time 2020年06月01日 * @time 2020年06月01日
* @return void * @return void
*/ */
protected function initUploadConfig() public function initUploadConfig()
{ {
$configModel = app(Config::class); Utils::setFilesystemConfig();
$upload = $configModel->where('key', 'upload')->find();
if ($upload) {
$disk = app()->config->get('filesystem.disks');
$uploadConfigs = $configModel->getConfig($upload->component);
if (!empty($uploadConfigs)) {
// 读取上传可配置数据
foreach ($uploadConfigs as $key => &$config) {
// $disk[$key]['type'] = $key;
// 腾讯云配置处理
if (strtolower($key) == 'qcloud') {
$config['credentials'] = [
'appId' => $config['app_id'] ?? '',
'secretKey' => $config['secret_key'] ?? '',
'secretId' => $config['secret_id'] ?? '',
];
$readFromCdn = $config['read_from_cdn'] ?? 0;
$config['read_from_cdn'] = intval($readFromCdn) == 1;
}
// OSS 配置
if (strtolower($key) == 'oss') {
$isCname = $config['is_cname'] ?? 0;
$config['is_cname'] = intval($isCname) == 1;
}
}
// 合并数组
array_walk($disk, function (&$item, $key) use ($uploadConfigs) {
if (!in_array($key, ['public', 'local'])) {
if ($uploadConfigs[$key] ?? false) {
foreach ($uploadConfigs[$key] as $k => $value) {
$item[$k] = $value;
}
}
}
});
// 重新分配配置
app()->config->set([
'disks' => $disk,
], 'filesystem');
}
}
}
/**
* 初始化
*
* @time 2020年09月07日
* @return $this
*/
protected function initDriver()
{
if ($driver = Utils::config('site.upload')) {
$this->driver = $driver;
}
return $this;
} }
/** /**

View File

@@ -136,6 +136,10 @@ class Utils
$docComment = (new \ReflectionClass($controller))->getMethod($action)->getDocComment(); $docComment = (new \ReflectionClass($controller))->getMethod($action)->getDocComment();
if (! $docComment) {
return false;
}
return strpos($docComment, config('catch.permissions.method_auth_mark')) !== false; return strpos($docComment, config('catch.permissions.method_auth_mark')) !== false;
} }
@@ -229,4 +233,64 @@ class Utils
return $data; return $data;
} }
/**
* 设置 filesystem config
*
* @time 2021年03月01日
* @return void
*/
public static function setFilesystemConfig()
{
$configModel = app(Config::class);
$upload = $configModel->where('key', 'upload')->find();
if ($upload) {
$disk = app()->config->get('filesystem.disks');
$uploadConfigs = $configModel->getConfig($upload->component);
if (!empty($uploadConfigs)) {
// 读取上传可配置数据
foreach ($uploadConfigs as $key => &$config) {
// $disk[$key]['type'] = $key;
// 腾讯云配置处理
if (strtolower($key) == 'qcloud') {
$config['credentials'] = [
'appId' => $config['app_id'] ?? '',
'secretKey' => $config['secret_key'] ?? '',
'secretId' => $config['secret_id'] ?? '',
];
$readFromCdn = $config['read_from_cdn'] ?? 0;
$config['read_from_cdn'] = intval($readFromCdn) == 1;
}
// OSS 配置
if (strtolower($key) == 'oss') {
$isCname = $config['is_cname'] ?? 0;
$config['is_cname'] = intval($isCname) == 1;
}
}
// 合并数组
array_walk($disk, function (&$item, $key) use ($uploadConfigs) {
if (!in_array($key, ['public', 'local'])) {
if ($uploadConfigs[$key] ?? false) {
foreach ($uploadConfigs[$key] as $k => $value) {
$item[$k] = $value;
}
}
}
});
$default = Utils::config('site.upload');
// 重新分配配置
app()->config->set([
'default' => $default ? : 'local',
'disks' => $disk,
], 'filesystem');
}
}
}
} }

View File

@@ -18,7 +18,7 @@ use catcher\traits\db\ScopeTrait;
*/ */
abstract class CatchModel extends \think\Model abstract class CatchModel extends \think\Model
{ {
use SoftDelete, TransTrait, BaseOptionsTrait, ScopeTrait, RewriteTrait; use SoftDelete, BaseOptionsTrait, ScopeTrait, RewriteTrait;
protected $createTime = 'created_at'; protected $createTime = 'created_at';
@@ -46,6 +46,6 @@ abstract class CatchModel extends \think\Model
*/ */
public function hasField(string $field) public function hasField(string $field)
{ {
return property_exists($this, 'field') ? in_array($field, $this->field) : false; return property_exists($this, 'field') && in_array($field, $this->field);
} }
} }

View File

@@ -0,0 +1,167 @@
<?php
declare (strict_types = 1);
namespace catcher\command\Tools;
use catcher\facade\FileSystem;
use catcher\generate\support\Table;
use catcher\generate\support\TableColumn;
use catcher\library\Compress;
use catcher\library\ProgressBar;
use catcher\library\Zip;
use think\console\Command;
use think\console\Input;
use think\console\input\Argument;
use think\console\Output;
use think\facade\Db;
class RegionCommand extends Command
{
protected function configure()
{
// 指令配置
$this->setName('region')
->addOption('rollback', '-r', Argument::REQUIRED, '删除 Region')
->setDescription('create region data');
}
protected function execute(Input $input, Output $output)
{
if ($input->hasOption('rollback')) {
$this->deleteRegion();
} else {
$output->info('start create region');
$this->createRegion();
$output->info('create region successfully');
$this->importRegionData();
}
}
protected function createRegion()
{
$table = new Table('region');
if ($table::exist()) {
$this->output->error('table [region] has existed!');
exit;
}
if (! $table::create('id', 'InnoDB', '地区表')) {
$this->output->error('table [region] create failed!');
exit;
}
$column = new TableColumn();
$table::addColumn($column->int('parent_id', 10)->setDefault(0)->setComment('父级'));
$table::addColumn($column->tinyint('level', 1)->setDefault(1)->setComment('等级'));
$table::addColumn($column->varchar('name', 50)->setDefault('')->setComment('地区名称'));
$table::addColumn($column->varchar('initial', 100)->setDefault('')->setComment('首字母'));
$table::addColumn($column->varchar('pinyin', 100)->setDefault('')->setComment('拼音'));
$table::addColumn($column->varchar('city_code', 100)->setDefault('')->setComment('城市编码'));
$table::addColumn($column->varchar('ad_code', 100)->setDefault('')->setComment('区域编码'));
$table::addColumn($column->varchar('lng_lat', 500)->setDefault('')->setComment('中心经纬度'));
$table::addIndex(['level']);
}
protected function deleteRegion()
{
$table = new Table('region');
if (! $table::drop()) {
$this->output->error('table [region] drop failed!');
exit;
}
$this->output->info('table [region] has deleted!');
}
protected function importRegionData()
{
try {
$compress = new Compress();
$this->output->info('start downloading');
$regionZip = runtime_path() . DIRECTORY_SEPARATOR . 'region.zip';
$regionJson = runtime_path() .DIRECTORY_SEPARATOR . 'region.json';
$compress->savePath($regionZip)
->download('http://json.think-region.yupoxiong.com/region.json.zip');
if (!FileSystem::exists($regionZip)) {
$this->output->error('import failed! Json data download failed');
}
(new Zip)->make($regionZip, \ZipArchive::CREATE)
->extractTo(runtime_path())->close();
$region = \json_decode(file_get_contents($regionJson, true));
$this->output->info('start import region data');
Db::startTrans();
$data = [];
$total = count($region);
$bar = new ProgressBar($this->output, $total);
$bar->start();
foreach ($region as $k => $r) {
$data[] = [
'id' => $r->id,
'parent_id' => $r->parent_id,
'level' => $r->level,
'name' => $r->name,
'initial' => $r->initial,
'pinyin' => $r->pinyin,
'city_code' => $r->citycode,
'ad_code' => $r->adcode,
'lng_lat' => $r->lng_lat,
];
if (count($data) >= 500) {
if (!Db::name('region')->insertAll($data)) {
Db::rollback();
break;
}
$data = [];
$bar->advance(500);
}
if ($total == $k+1) {
if (!Db::name('region')->insertAll($data)) {
Db::rollback();
break;
}
$bar->advance(count($data));
}
}
$bar->finished();
Db::commit();
unlink($regionZip);
unlink($regionJson);
$this->output->info(PHP_EOL . 'import region data successfully');
} catch (\Exception $e) {
$this->output->error($e->getMessage());
exit();
}
}
}

View File

@@ -116,7 +116,7 @@ class InstallProjectCommand extends Command
// 设置 app domain // 设置 app domain
$appDomain = strtolower($this->output->ask($this->input, '👉 first, you should set app domain: ')); $appDomain = strtolower($this->output->ask($this->input, '👉 first, you should set app domain: '));
if (strpos('http://', $appDomain) === false || strpos('https://', $appDomain) === false) { if (strpos($appDomain, 'http://') === false || strpos( $appDomain, 'https://') === false) {
$appDomain = 'http://' . $appDomain; $appDomain = 'http://' . $appDomain;
} }

View File

@@ -10,6 +10,8 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// you should use `$router` // you should use `$router`
/* @var think\Route $router */
$router->group(function () use ($router){ $router->group(function () use ($router){
})->middleware('auth'); })->middleware('auth');

View File

@@ -8,7 +8,9 @@ use catcher\generate\factory\Migration;
use catcher\generate\factory\Model; use catcher\generate\factory\Model;
use catcher\generate\factory\Route; use catcher\generate\factory\Route;
use catcher\generate\factory\SQL; use catcher\generate\factory\SQL;
use catcher\generate\support\Table;
use catcher\library\Composer; use catcher\library\Composer;
use catcher\Utils;
use think\facade\Db; use think\facade\Db;
class Generator class Generator
@@ -22,8 +24,11 @@ class Generator
* @time 2020年04月29日 * @time 2020年04月29日
* @param $params * @param $params
* @return array * @return array
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\db\exception\DataNotFoundException
*/ */
public function done($params) public function done($params): array
{ {
// 判断是否安装了扩展包 // 判断是否安装了扩展包
if (!(new Composer)->hasPackage(self::NEED_PACKAGE)) { if (!(new Composer)->hasPackage(self::NEED_PACKAGE)) {
@@ -49,7 +54,7 @@ class Generator
} }
if ($params['create_table']) { if ($params['create_table']) {
$table = (new SQL)->done($model); (new SQL)->done($model);
array_push($message, 'table created successfully'); array_push($message, 'table created successfully');
} }
@@ -65,17 +70,17 @@ class Generator
// 只有创建了 Controller 最后成功才写入 route // 只有创建了 Controller 最后成功才写入 route
if ($params['create_controller']) { if ($params['create_controller']) {
(new Route())->controller($controller['controller']) (new Route)->controller($controller['controller'])
->restful($controller['restful']) ->restful($controller['restful'])
// ->methods((new Controller())->parseOtherMethods($controller['other_function']))
->done(); ->done();
} }
} catch (\Throwable $exception) {
} catch (\Exception $exception) { if (!$exception instanceof TableExistException) {
$this->rollback($files, $migration, $table); $this->rollback($files, $migration);
throw new FailedException($exception->getFile() . $exception->getLine() . $exception->getMessage());
} }
throw new FailedException($exception->getMessage());
}
return $message; return $message;
} }
@@ -97,9 +102,9 @@ class Generator
switch ($type) { switch ($type) {
case 'controller': case 'controller':
return (new Controller())->getContent($controller); return (new Controller)->getContent($controller);
case 'model': case 'model':
return (new Model())->getContent($model); return (new Model)->getContent($model);
default: default:
break; break;
} }
@@ -113,7 +118,7 @@ class Generator
* @param $params * @param $params
* @return array[] * @return array[]
*/ */
protected function parseParams($params) protected function parseParams($params): array
{ {
$module = $params['controller']['module'] ?? false; $module = $params['controller']['module'] ?? false;
@@ -126,14 +131,14 @@ class Generator
'model' => $params['controller']['model'] ?? '', 'model' => $params['controller']['model'] ?? '',
'controller' => $params['controller']['controller'] ?? '', 'controller' => $params['controller']['controller'] ?? '',
'restful' => $params['controller']['restful'], 'restful' => $params['controller']['restful'],
// 'other_function' => $params['controller']['other_function'],
]; ];
$table = $params['controller']['table'] ?? ''; $table = $params['controller']['table'] ?? '';
if ($table) {
$table = \config('database.connections.mysql.prefix') . $table;
if ($table) {
$table = Utils::tableWithPrefix($table);
} }
$model = [ $model = [
'table' => $table, 'table' => $table,
'model' => $params['controller']['model'] ?? '', 'model' => $params['controller']['model'] ?? '',
@@ -151,17 +156,14 @@ class Generator
* *
* @param $files * @param $files
* @param $migration * @param $migration
* @param $table
* @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
* @author JaguarJack <njphper@gmail.com>
* @date 2020/7/11
*/ */
protected function rollback($files, $migration, $table) protected function rollback($files, $migration)
{ {
if ((new SQL())->hasTableExists($table)) { if (Table::exist()) {
Db::query(sprintf('drop table %s', $table)); Table::drop();
} }
foreach ($files as $file) { foreach ($files as $file) {

View File

@@ -0,0 +1,9 @@
<?php
namespace catcher\generate;
use catcher\exceptions\CatchException;
class TableExistException extends CatchException
{
}

View File

@@ -36,7 +36,7 @@ class Controller extends Factory
* @param $params * @param $params
* @return bool|string|string[] * @return bool|string|string[]
*/ */
public function done($params) public function done(array $params)
{ {
// 写入成功之后 // 写入成功之后
$controllerPath = $this->getGeneratePath($params['controller']); $controllerPath = $this->getGeneratePath($params['controller']);

View File

@@ -6,7 +6,7 @@ use think\facade\Db;
abstract class Factory abstract class Factory
{ {
abstract public function done($param); abstract public function done(array $params);
/** /**
* parse psr4 path * parse psr4 path
@@ -28,7 +28,7 @@ abstract class Factory
* @param $filePath * @param $filePath
* @return string * @return string
*/ */
protected function getGeneratePath($filePath) protected function getGeneratePath($filePath): string
{ {
$path = explode('\\', $filePath); $path = explode('\\', $filePath);
@@ -52,7 +52,7 @@ abstract class Factory
* @param $filePath * @param $filePath
* @return string * @return string
*/ */
public function getModulePath($filePath) public function getModulePath($filePath): string
{ {
$path = explode('\\', $filePath); $path = explode('\\', $filePath);
@@ -72,7 +72,7 @@ abstract class Factory
* @param $filename * @param $filename
* @return array * @return array
*/ */
public function parseFilename($filename) public function parseFilename($filename): array
{ {
$namespace = explode('\\', $filename); $namespace = explode('\\', $filename);
@@ -89,7 +89,7 @@ abstract class Factory
* @param $table * @param $table
* @return bool * @return bool
*/ */
public function hasTableExists($table) public function hasTableExists($table): bool
{ {
$tables = Db::connect()->getTables(); $tables = Db::connect()->getTables();

View File

@@ -11,7 +11,15 @@ use think\helper\Str;
class Migration extends Factory class Migration extends Factory
{ {
public function done($params) /**
*
* @time 2021年03月13日
* @param array $params
* @throws \Doctrine\DBAL\DBALException
* @throws \JaguarJack\MigrateGenerator\Exceptions\EmptyInDatabaseException
* @return string
*/
public function done(array $params): string
{ {
[$module, $tableName] = $params; [$module, $tableName] = $params;

View File

@@ -24,7 +24,7 @@ class Model extends Factory
* @param $params * @param $params
* @return string * @return string
*/ */
public function done($params) public function done(array $params): string
{ {
$content = $this->getContent($params); $content = $this->getContent($params);

View File

@@ -1 +0,0 @@
<?php

View File

@@ -16,7 +16,7 @@ class Route extends Factory
protected $methods = []; protected $methods = [];
public function done($params = []) public function done(array $params = [])
{ {
$route = []; $route = [];

View File

@@ -1,213 +1,156 @@
<?php <?php
namespace catcher\generate\factory; namespace catcher\generate\factory;
use catcher\exceptions\FailedException; use catcher\exceptions\FailedException;
use think\facade\Db; use catcher\generate\support\Table;
use catcher\generate\support\TableColumn;
use catcher\generate\TableExistException;
use Phinx\Db\Adapter\AdapterInterface;
class SQL extends Factory class SQL extends Factory
{ {
protected $index = ''; public function done(array $params)
public function done($params)
{
Db::execute($this->createSQL($params));
// 判断表是否创建成功
if (!$this->hasTableExists($params['table'])) {
throw new FailedException(sprintf('create table [%s] failed', $params['table']));
}
return $params['table'];
}
/**
* create table sql
*
* @time 2020年04月28日
* @param $params
* @return string
*/
protected function createSQL($params)
{ {
if (!$params['table'] ?? false) { if (!$params['table'] ?? false) {
throw new FailedException('table name has lost~'); throw new FailedException('table name has lost~');
} }
if ($this->hasTableExists($params['table'])) { $this->createTable($params);
throw new FailedException(sprintf('table [%s] has existed', $params['table']));
}
$extra = $params['extra']; $this->createTableColumns($params['sql'], $params['extra']);
// 主键
$createSql = $this->primaryKey($extra['primary_key']);
// 字段
$ifHaveNotFields = true;
foreach ($params['sql'] as $sql) {
if (!$sql['field'] || !$sql['type']) {
continue;
}
$ifHaveNotFields = false;
$createSql .= $this->parseSQL($sql);
}
// 如果没有设置数据库字段
if ($ifHaveNotFields) {
throw new FailedException('Do you have set mysql fields?');
}
// 创建人
if ($extra['creator_id'] ?? false) {
$createSql .= $this->parseCreatorId();
}
// 创建时间
if ($extra['created_at'] ?? false) {
$createSql .= $this->parseCreatedAt();
}
// 软删除
if ($extra['soft_delete'] ?? false) {
$createSql .= $this->parseDeletedAt();
}
// 索引
if ($this->index) {
$createSql .= $this->index;
}
$createSql = rtrim($createSql, ',' . PHP_EOL);
// 创建表 SQL $this->createTableIndex($this->getIndexColumns($params['sql']));
return $this->createTable($params['table'], $createSql, $extra['engine'], 'utf8mb4', $extra['comment']);
return $params['table'];
} }
/** /**
* parse sql * 创建表
* *
* @time 2020年04月27 * @time 2021年03月13
* @param $sql * @param array $params
* @return string
*/
protected function parseSQL($sql)
{
// 解析索引
if ($sql['index']) {
$this->parseIndex($sql['index'], $sql['field']);
}
// 字段
$_sql[] = sprintf('`%s`', $sql['field']);
// 类型
$_sql[] = $sql['type'] . ($sql['length'] ? sprintf('(%s)', $sql['length']) : '');
if ($sql['unsigned']) {
$_sql[] = 'unsigned';
}
// 默认值
$default = trim(trim($sql['default'], '\''));
if (!$sql['nullable']) {
$_sql[] = 'not null';
if ($default == '' || $default === '') {
if (!$this->doNotNeedDefaultValueType($sql['type'])) {
$_sql[] = ' default \'\'';
}
} else {
if (strpos('int', $sql['type']) === false) {
$_sql[] = ' default ' . (int)$default ;
} else {
$_sql[] = ' default ' . $default;
}
}
}
// 字段注释
$_sql[] = $sql['comment'] ? sprintf('comment \'%s\'', $sql['comment']) : '';
return implode(' ', $_sql) . ','. PHP_EOL;
}
/**
* parse primary key
*
* @time 2020年04月27日
* @param $id
* @return string
*/
protected function primaryKey($id)
{
return sprintf('`%s`', $id) . ' int unsigned not null auto_increment primary key,'. PHP_EOL;
}
/**
* parse created_at & updated_at
*
* @time 2020年04月27日
* @return string
*/
protected function parseCreatedAt()
{
return sprintf('`created_at` int unsigned not null default 0 comment \'%s\',', '创建时间') . PHP_EOL .
sprintf('`updated_at` int unsigned not null default 0 comment \'%s\',', '更新时间') . PHP_EOL;
}
/**
* parse deleted_at
*
* @time 2020年04月27日
* @return string
*/
protected function parseDeletedAt()
{
return sprintf('`deleted_at` int unsigned not null default 0 comment \'%s\',', '软删除') . PHP_EOL;
}
/**
* parse creator id
*
* @time 2020年07月01日
* @return string
*/
protected function parseCreatorId()
{
return sprintf('`creator_id` int unsigned not null default 0 comment \'%s\',', '创建人ID') . PHP_EOL;
}
/**
* created table
*
* @time 2020年04月27日
* @param $table
* @param $sql
* @param string $engine
* @param string $charset
* @param string $comment
* @return string
*/
protected function createTable($table, $sql, $engine='InnoDB', $charset = 'utf8mb4', $comment = '')
{
return sprintf('create table `%s`(' . PHP_EOL.
'%s)'.PHP_EOL .
'engine=%s default charset=%s comment=\'%s\'', $table, $sql, $engine, $charset, $comment);
}
/**
* parse index
*
* @time 2020年04月27日
* @param $index
* @param $field
* @return void * @return void
*/ */
protected function parseIndex($index, $field) protected function createTable(array $params)
{ {
if ($index == 'unique') { $table = new Table($params['table']);
$this->index .= "unique index unique_$field($field)," . PHP_EOL;
} elseif ($index == 'index') { if ($table::exist()) {
$this->index .= "index($field),". PHP_EOL; throw new TableExistException(sprintf('Table [%s] has been existed', $params['table']));
} elseif ($index == 'fulltext') { }
$this->index .= "fulltext key fulltext_$field($field)," . PHP_EOL;
} elseif ($index == 'spatial') { if(!$table::create(
$this->index .= "spatial index spatial_$field($field),". PHP_EOL; $params['extra']['primary_key'],
$params['extra']['engine'],
$params['extra']['comment']
)) {
throw new FailedException(sprintf('created table [%s] failed', $params['table']));
} }
} }
/**
* 创建 columns
*
* @time 2021年03月13日
* @param $columns
* @param $extra
* @return void
*/
protected function createTableColumns($columns, $extra)
{
$tableColumns = [];
foreach ($columns as $column) {
if ($column['type'] === AdapterInterface::PHINX_TYPE_DECIMAL) {
$tableColumn = (new TableColumn)->{$column['type']}($column['field']);
} else if ($column['type'] === AdapterInterface::PHINX_TYPE_ENUM || $column['type'] === AdapterInterface::PHINX_TYPE_SET) {
$tableColumn = (new TableColumn)->{$column['type']}($column['field'], $column['default']);
}else {
$tableColumn = (new TableColumn)->{$column['type']}($column['field'], $column['length'] ?? 0);
}
if ($column['nullable']) {
$tableColumn->setNullable();
}
if ($column['unsigned']) {
$tableColumn->setUnsigned();
}
if ($column['comment']) {
$tableColumn->setComment($column['comment']);
}
if (!$this->doNotNeedDefaultValueType($column['type'])) {
$tableColumn->setDefault($column['default']);
}
$tableColumns[] = $tableColumn;
}
if ($extra['created_at']) {
$tableColumns[] = $this->createCreateAtColumn();
$tableColumns[] = $this->createUpdateAtColumn();
}
if ($extra['soft_delete']) {
$tableColumns[] = $this->createDeleteAtColumn();
}
if ($extra['creator_id']) {
$tableColumns[] = $this->createCreatorIdColumn();
}
foreach ($tableColumns as $column) {
if (!Table::addColumn($column)) {
throw new FailedException('创建失败');
}
}
}
/**
* 创建 index
*
* @time 2021年03月13日
* @param $indexes
* @return void
*/
protected function createTableIndex($indexes)
{
$method = [
'index' => 'addIndex',
'unique' => 'addUniqueIndex',
'fulltext' => 'addFulltextIndex',
];
foreach ($indexes as $type => $index) {
foreach ($index as $i) {
Table::{$method[$type]}($i);
}
}
}
/**
* 获取有索引的 column
*
* @time 2021年03月13日
* @param $columns
* @return array
*/
protected function getIndexColumns($columns): array
{
$index = [];
foreach ($columns as $column) {
if ($column['index']) {
$index[$column['index']][] = $column['field'];
}
}
return $index;
}
/** /**
* 不需要默认值 * 不需要默认值
@@ -216,12 +159,64 @@ class SQL extends Factory
* @time 2020年10月23日 * @time 2020年10月23日
* @return bool * @return bool
*/ */
protected function doNotNeedDefaultValueType(string $type) protected function doNotNeedDefaultValueType(string $type): bool
{ {
return in_array($type, [ return in_array($type, [
'blob', 'text', 'geometry', 'json', 'blob', 'text', 'geometry', 'json',
'tinytext', 'mediumtext', 'longtext', 'tinytext', 'mediumtext', 'longtext',
'tinyblob', 'mediumblob', 'longblob' 'tinyblob', 'mediumblob', 'longblob', 'enum', 'set',
'date', 'datetime', 'time', 'timestamp', 'year'
]); ]);
} }
/**
* 创建时间
*
* @time 2021年03月13日
* @return \think\migration\db\Column
*/
protected function createCreateAtColumn(): \think\migration\db\Column
{
return (new TableColumn)->int('created_at', 10)
->setUnsigned()
->setDefault(0)
->setComment('创建时间');
}
/**
* 更新时间
*
* @time 2021年03月13日
* @return \think\migration\db\Column
*/
protected function createUpdateAtColumn(): \think\migration\db\Column
{
return (new TableColumn)->int('updated_at', 10)
->setUnsigned()->setDefault(0)->setComment('更新时间');
}
/**
* 软删除
*
* @time 2021年03月13日
* @return \think\migration\db\Column
*/
protected function createDeleteAtColumn(): \think\migration\db\Column
{
return (new TableColumn)->int('deleted_at', 10)
->setUnsigned()->setDefault(0)->setComment('软删除字段');
}
/**
* 创建人
*
* @time 2021年03月13日
* @return \think\migration\db\Column
*/
protected function createCreatorIdColumn(): \think\migration\db\Column
{
return (new TableColumn)->int('creator_id', 10)
->setUnsigned()->setDefault(0)->setComment('创建人ID');
}
} }

View File

@@ -0,0 +1,272 @@
<?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 catcher\generate\support;
use catcher\exceptions\FailedException;
use catcher\Utils;
use Phinx\Db\Adapter\AdapterFactory;
use think\facade\Db;
use think\migration\db\Column;
class Table
{
protected static $adapter = null;
protected static $table = null;
protected static $tableName = null;
public function __construct(string $tableName)
{
self::$tableName = $tableName;
}
/**
* 获取 table 对象
*
* @time 2021年03月04日
* @return \think\migration\db\Table
*/
protected static function getTable(): \think\migration\db\Table
{
if (self::$table) {
return self::$table;
}
return (new \think\migration\db\Table(Utils::tableWithoutPrefix(self::$tableName)))->setAdapter(self::getAdapter());
}
/**
* create table
*
* @time 2021年03月04日
* @param string $primaryKey
* @param string $engine
* @param string $comment
* @return bool
*/
public static function create(string $primaryKey, string $engine, string $comment): bool
{
self::getTable()
->setId($primaryKey)
->setPrimaryKey($primaryKey)
->setEngine($engine)
->setComment($comment)
->setCollation('utf8mb4_general_ci')
->create();
return self::exist();
}
/**
* 表是否存在
*
* @time 2021年03月04日
* @return bool
*/
public static function exist(): bool
{
return self::getTable()->exists();
}
/**
* 删除表
*
* @time 2021年03月04日
* @return bool
*/
public static function drop(): bool
{
if (!self::exist()) {
throw new FailedException(sprintf('table [%s] not exist, drop failed', self::$tableName));
}
self::getTable()->drop();
return ! self::exist();
}
/**
* 新增 column
*
* @time 2021年03月04日
* @param mixed $column
* @return bool
*/
public static function addColumn($column): bool
{
if ($column instanceof \Closure) {
$column = $column();
}
if (!$column instanceof Column) {
throw new FailedException('Column Must Be "think\migration\db\Column');
}
// 新增字段
self::getTable()
->addColumn($column)
->update();
return self::hasColumn($column->getName());
}
/**
* 是否存在 column
*
* @time 2021年03月08日
* @param string $column
* @return bool
*/
public static function hasColumn(string $column): bool
{
return self::getTable()->hasColumn($column);
}
/**
* 获取表结构信息
*
* @time 2021年03月05日
* @return array
*/
public static function columns(): array
{
return array_values(Db::getFields(Utils::tableWithPrefix(self::$tableName)));
}
/**
* 删除 column
*
* @time 2021年03月04日
* @param string $column
* @return bool
*/
public static function dropColumn(string $column): bool
{
self::getTable()->removeColumn($column)->update();
if (self::getTable()->hasColumn($column)) {
throw new FailedException('remove column ['.$column.'] failed');
}
return true;
}
/**
* 唯一索引
*
* @time 2021年03月13日
* @param string| array $columns
* @return void
*/
public static function addUniqueIndex($columns)
{
self::getTable()->addIndex($columns, [
'unique' => true, 'name' => self::$tableName . '_' . (is_string($columns) ? $columns : implode('_', $columns))
])->update();
}
/**
* 添加普通索引
*
* @time 2021年03月13日
* @param string| array $columns
* @return void
*/
public static function addIndex($columns)
{
self::getTable()->addIndex($columns, [
'name' => self::$tableName . '_' . (is_string($columns) ? $columns : implode('_', $columns))
])->update();
}
/**
* 添加全文索引
*
* @time 2021年03月13日
* @param string| array $columns
* @return void
*/
public static function addFulltextIndex($columns)
{
self::getTable()->addIndex($columns, [
'type' => 'fulltext',
'name' => self::$tableName . '_' . (is_string($columns) ? $columns : implode('_', $columns))
])->update();
}
/**
* 获取适配器
*
* @time 2021年03月04日
* @return mixed
*/
public static function getAdapter()
{
if (self::$adapter) {
return self::$adapter;
}
$options = self::getDbConfig();
$adapter = AdapterFactory::instance()->getAdapter($options['adapter'], $options);
if ($adapter->hasOption('table_prefix') || $adapter->hasOption('table_suffix')) {
$adapter = AdapterFactory::instance()->getWrapper('prefix', $adapter);
}
self::$adapter = $adapter;
return $adapter;
}
/**
* 获取数据库配置
* @return array
*/
protected static function getDbConfig(): array
{
$default = app()->config->get('database.default');
$config = app()->config->get("database.connections.{$default}");
if (0 == $config['deploy']) {
$dbConfig = [
'adapter' => $config['type'],
'host' => $config['hostname'],
'name' => $config['database'],
'user' => $config['username'],
'pass' => $config['password'],
'port' => $config['hostport'],
'charset' => $config['charset'],
'table_prefix' => $config['prefix'],
];
} else {
$dbConfig = [
'adapter' => explode(',', $config['type'])[0],
'host' => explode(',', $config['hostname'])[0],
'name' => explode(',', $config['database'])[0],
'user' => explode(',', $config['username'])[0],
'pass' => explode(',', $config['password'])[0],
'port' => explode(',', $config['hostport'])[0],
'charset' => explode(',', $config['charset'])[0],
'table_prefix' => explode(',', $config['prefix'])[0],
];
}
$table = app()->config->get('database.migration_table', 'migrations');
$dbConfig['default_migration_table'] = $dbConfig['table_prefix'] . $table;
return $dbConfig;
}
}

View File

@@ -0,0 +1,376 @@
<?php
namespace catcher\generate\support;
use catcher\Utils;
use Phinx\Db\Adapter\AdapterInterface;
use Phinx\Db\Adapter\MysqlAdapter;
use think\migration\db\Column;
class TableColumn
{
/**
* tinyint
*
* @time 2021年03月13日
* @param string $name
* @param int $length
* @return Column
*/
public function tinyint(string $name, int $length): Column
{
return Column::tinyInteger($name);
}
/**
* boolean
*
* @time 2021年03月13日
* @param string $name
* @param int $length
* @return Column
*/
public function boolean(string $name, int $length): Column
{
return Column::boolean($name);
}
/**
* smallint
*
* @time 2021年03月13日
* @param string $name
* @param int $length
* @return Column
*/
public function smallint(string $name, int $length): Column
{
return Column::smallInteger($name);
}
/**
* int
*
* @time 2021年03月13日
* @param string $name
* @param int $length
* @return Column
*/
public function int(string $name, int $length): Column
{
return Column::integer($name);
}
/**
* mediumint
*
* @time 2021年03月13日
* @param string $name
* @param int $length
* @return Column
*/
public function mediumint(string $name, int $length): Column
{
return Column::mediumInteger($name);
}
/**
* bigint
*
* @time 2021年03月13日
* @param string $name
* @param int $length
* @return Column
*/
public function bigint(string $name, int $length): Column
{
return Column::bigInteger($name);
}
/**
* 浮点数
*
* @time 2021年03月08日
* @param string $name
* @param int $length
* @return Column
*/
public function float(string $name, int $length): Column
{
return Column::float($name);
}
/**
* 浮点数
*
* @time 2021年03月08日
* @param string $name
* @param int $precision
* @param int $scale
* @return Column
*/
public function decimal(string $name, $precision = 8, $scale = 2): Column
{
return Column::decimal($name, $precision, $scale);
}
/**
* string 类型
*
* @time 2021年03月08日
* @param string $name
* @param int $length
* @return Column
*/
public function varchar(string $name, int $length): Column
{
return Column::string($name, $length);
}
/**
* char
*
* @time 2021年03月13日
* @param string $name
* @param int $length
* @return Column
*/
public function char(string $name, int $length): Column
{
return Column::char($name, $length);
}
/**
* 普通文本
*
* @time 2021年03月08日
* @param string $name
* @param int $length
* @return Column
*/
public function text(string $name, int $length): Column
{
return Column::text($name);
}
/**
* 小文本
*
* @time 2021年03月13日
* @param string $name
* @param int $length
* @return Column
*/
public function tinytext(string $name, int $length): Column
{
return Column::make($name, AdapterInterface::PHINX_TYPE_TEXT, ['length' => MysqlAdapter::TEXT_TINY]);
}
/**
* 中长文本
*
* @time 2021年03月13日
* @param string $name
* @param int $length
* @return Column
*/
public function mediumtext(string $name, int $length): Column
{
return Column::mediumText($name);
}
/**
* 超大文本
*
* @time 2021年03月08日
* @param string $name
* @param int $length
* @return Column
*/
public function longtext(string $name, int $length): Column
{
return Column::longText($name);
}
/**
* binary
*
* @time 2021年03月13日
* @param string $name
* @param int $length
* @return Column
*/
public function binary(string $name, int $length): Column
{
return Column::binary($name);
}
/**
* varbinary
*
* @time 2021年03月13日
* @param string $name
* @param int $length
* @return Column
*/
public function varbinary(string $name, int $length): Column
{
return Column::make($name, AdapterInterface::PHINX_TYPE_VARBINARY);
}
/**
* tinyblob
*
* @time 2021年03月13日
* @param string $name
* @param int $length
* @return Column
*/
public function tinyblob(string $name, int $length): Column
{
return Column::make($name, AdapterInterface::PHINX_TYPE_BLOB, ['length' => MysqlAdapter::BLOB_TINY]);
}
/**
* blob
*
* @time 2021年03月13日
* @param string $name
* @param int $length
* @return Column
*/
public function blob(string $name, int $length): Column
{
return Column::make($name, AdapterInterface::PHINX_TYPE_BLOB, ['length' => MysqlAdapter::BLOB_REGULAR]);
}
/**
* mediumblob
*
* @time 2021年03月13日
* @param string $name
* @param int $length
* @return Column
*/
public function mediumblob(string $name, int $length): Column
{
return Column::make($name, AdapterInterface::PHINX_TYPE_BLOB, ['length' => MysqlAdapter::BLOB_MEDIUM]);
}
/**
* longblob
*
* @time 2021年03月13日
* @param string $name
* @param int $length
* @return Column
*/
public function longblob(string $name, int $length): Column
{
return Column::make($name, AdapterInterface::PHINX_TYPE_BLOB, ['length' => MysqlAdapter::BLOB_LONG]);
}
/**
* 时间类型
*
* @time 2021年03月08日
* @param string $name
* @param int $length
* @return Column
*/
public function date(string $name, int $length): Column
{
return Column::date($name);
}
/**
* 日期时间
*
* @time 2021年03月08日
* @param string $name
* @param int $length
* @return Column
*/
public function datetime(string $name, int $length): Column
{
return Column::dateTime($name)->setOptions(['default' => 'CURRENT_TIMESTAMP']);
}
/**
* 实践格式
*
* @time 2021年03月08日
* @param string $name
* @param int $length
* @return Column
*/
public function time(string $name, int $length): Column
{
return Column::time($name);
}
/**
* 时间戳
*
* @time 2021年03月08日
* @param string $name
* @param int $length
* @return Column
*/
public function timestamp(string $name, int $length): Column
{
return Column::timestamp($name)->setOptions(['default' => 'CURRENT_TIMESTAMP']);
}
/**
* enum 类型
*
* @time 2021年03月13日
* @param $name
* @param $values
* @return Column
*/
public function enum(string $name, $values): Column
{
return Column::enum($name, is_string($values) ? Utils::stringToArrayBy($values) : $values);
}
/**
* set 类型
*
* @time 2021年03月13日
* @param string $name
* @param $values
* @return Column
*/
public function set(string $name, $values): Column
{
$values = is_string($values) ? Utils::stringToArrayBy($values) : $values;
return Column::make($name, AdapterInterface::PHINX_TYPE_SET, compact('values'));
}
/**
* json 穿
*
* @time 2021年03月13日
* @param string $name
* @return Column
*/
public function json(string $name): Column
{
return Column::json($name);
}
/**
* uuid
*
* @time 2021年03月13日
* @param string $name
* @return Column
*/
public function uuid(string $name): Column
{
return Column::uuid($name);
}
}

View File

@@ -23,7 +23,7 @@ class FileSystem
* @param string $path * @param string $path
* @return bool * @return bool
*/ */
public function exists($path) public function exists(string $path): bool
{ {
return file_exists($path); return file_exists($path);
} }
@@ -35,7 +35,7 @@ class FileSystem
* @param bool $lock * @param bool $lock
* @return string * @return string
**/ **/
public function get($path, $lock = false) public function get(string $path, $lock = false): string
{ {
if ($this->isFile($path)) { if ($this->isFile($path)) {
return $lock ? $this->sharedGet($path) : file_get_contents($path); return $lock ? $this->sharedGet($path) : file_get_contents($path);
@@ -50,7 +50,7 @@ class FileSystem
* @param string $path * @param string $path
* @return string * @return string
*/ */
public function sharedGet($path) public function sharedGet(string $path): string
{ {
$contents = ''; $contents = '';
@@ -81,7 +81,7 @@ class FileSystem
* *
* @throws FiledNotFoundException * @throws FiledNotFoundException
*/ */
public function getRequire($path) public function getRequire(string $path)
{ {
if ($this->isFile($path)) { if ($this->isFile($path)) {
return require $path; return require $path;
@@ -96,7 +96,7 @@ class FileSystem
* @param string $file * @param string $file
* @return mixed * @return mixed
*/ */
public function requireOnce($file) public function requireOnce(string $file)
{ {
require_once $file; require_once $file;
} }
@@ -107,7 +107,7 @@ class FileSystem
* @param string $path * @param string $path
* @return string * @return string
*/ */
public function hash($path) public function hash(string $path): string
{ {
return md5_file($path); return md5_file($path);
} }
@@ -120,7 +120,7 @@ class FileSystem
* @param bool $lock * @param bool $lock
* @return int|bool * @return int|bool
*/ */
public function put($path, $contents, $lock = false) public function put(string $path, string $contents, $lock = false)
{ {
return file_put_contents($path, $contents, $lock ? LOCK_EX : 0); return file_put_contents($path, $contents, $lock ? LOCK_EX : 0);
} }
@@ -132,7 +132,7 @@ class FileSystem
* @param string $content * @param string $content
* @return void * @return void
*/ */
public function replace($path, $content) public function replace(string $path, string $content)
{ {
clearstatcache(true, $path); clearstatcache(true, $path);
@@ -155,7 +155,7 @@ class FileSystem
* @param string $data * @param string $data
* @return int * @return int
*/ */
public function prepend($path, $data) public function prepend(string $path, string $data)
{ {
if ($this->exists($path)) { if ($this->exists($path)) {
return $this->put($path, $data.$this->get($path)); return $this->put($path, $data.$this->get($path));
@@ -171,7 +171,7 @@ class FileSystem
* @param string $data * @param string $data
* @return int * @return int
*/ */
public function append($path, $data) public function append(string $path, string $data): int
{ {
return file_put_contents($path, $data, FILE_APPEND); return file_put_contents($path, $data, FILE_APPEND);
} }
@@ -183,7 +183,7 @@ class FileSystem
* @param int|null $mode * @param int|null $mode
* @return mixed * @return mixed
*/ */
public function chmod($path, $mode = null) public function chmod(string $path, $mode = null)
{ {
if ($mode) { if ($mode) {
return chmod($path, $mode); return chmod($path, $mode);
@@ -198,7 +198,7 @@ class FileSystem
* @param string|array $paths * @param string|array $paths
* @return bool * @return bool
*/ */
public function delete($paths) public function delete($paths): bool
{ {
$paths = is_array($paths) ? $paths : func_get_args(); $paths = is_array($paths) ? $paths : func_get_args();
@@ -224,7 +224,7 @@ class FileSystem
* @param string $target * @param string $target
* @return bool * @return bool
*/ */
public function move($path, $target) public function move(string $path, string $target): bool
{ {
return rename($path, $target); return rename($path, $target);
} }
@@ -236,7 +236,7 @@ class FileSystem
* @param string $target * @param string $target
* @return bool * @return bool
*/ */
public function copy($path, $target) public function copy(string $path, string $target): bool
{ {
return copy($path, $target); return copy($path, $target);
} }
@@ -248,7 +248,7 @@ class FileSystem
* @param string $link * @param string $link
* @return void|mixed * @return void|mixed
*/ */
public function link($target, $link) public function link(string $target, string $link)
{ {
$isWin = strtolower(substr(PHP_OS, 0, 3)) === 'win'; $isWin = strtolower(substr(PHP_OS, 0, 3)) === 'win';
if (! $isWin) { if (! $isWin) {
@@ -266,7 +266,7 @@ class FileSystem
* @param string $path * @param string $path
* @return string * @return string
*/ */
public function name($path) public function name(string $path): string
{ {
return pathinfo($path, PATHINFO_FILENAME); return pathinfo($path, PATHINFO_FILENAME);
} }
@@ -277,7 +277,7 @@ class FileSystem
* @param string $path * @param string $path
* @return string * @return string
*/ */
public function basename($path) public function basename(string $path): string
{ {
return pathinfo($path, PATHINFO_BASENAME); return pathinfo($path, PATHINFO_BASENAME);
} }
@@ -288,7 +288,7 @@ class FileSystem
* @param string $path * @param string $path
* @return string * @return string
*/ */
public function dirname($path) public function dirname(string $path): string
{ {
return pathinfo($path, PATHINFO_DIRNAME); return pathinfo($path, PATHINFO_DIRNAME);
} }
@@ -299,7 +299,7 @@ class FileSystem
* @param string $path * @param string $path
* @return string * @return string
*/ */
public function extension($path) public function extension(string $path): string
{ {
return pathinfo($path, PATHINFO_EXTENSION); return pathinfo($path, PATHINFO_EXTENSION);
} }
@@ -310,7 +310,7 @@ class FileSystem
* @param string $path * @param string $path
* @return string * @return string
*/ */
public function type($path) public function type(string $path): string
{ {
return filetype($path); return filetype($path);
} }
@@ -321,7 +321,7 @@ class FileSystem
* @param string $path * @param string $path
* @return string|false * @return string|false
*/ */
public function mimeType($path) public function mimeType(string $path)
{ {
return finfo_file(finfo_open(FILEINFO_MIME_TYPE), $path); return finfo_file(finfo_open(FILEINFO_MIME_TYPE), $path);
} }
@@ -332,7 +332,7 @@ class FileSystem
* @param string $path * @param string $path
* @return int * @return int
*/ */
public function size($path) public function size(string $path): int
{ {
return filesize($path); return filesize($path);
} }
@@ -343,7 +343,7 @@ class FileSystem
* @param string $path * @param string $path
* @return int * @return int
*/ */
public function lastModified($path) public function lastModified(string $path): int
{ {
return filemtime($path); return filemtime($path);
} }
@@ -354,7 +354,7 @@ class FileSystem
* @param string $directory * @param string $directory
* @return bool * @return bool
*/ */
public function isDirectory($directory) public function isDirectory(string $directory): bool
{ {
return is_dir($directory); return is_dir($directory);
} }
@@ -365,7 +365,7 @@ class FileSystem
* @param string $path * @param string $path
* @return bool * @return bool
*/ */
public function isReadable($path) public function isReadable(string $path): bool
{ {
return is_readable($path); return is_readable($path);
} }
@@ -376,7 +376,7 @@ class FileSystem
* @param string $path * @param string $path
* @return bool * @return bool
*/ */
public function isWritable($path) public function isWritable(string $path): bool
{ {
return is_writable($path); return is_writable($path);
} }
@@ -387,7 +387,7 @@ class FileSystem
* @param string $file * @param string $file
* @return bool * @return bool
*/ */
public function isFile($file) public function isFile(string $file): bool
{ {
return is_file($file); return is_file($file);
} }
@@ -399,7 +399,7 @@ class FileSystem
* @param int $flags * @param int $flags
* @return array * @return array
*/ */
public function glob($pattern, $flags = 0) public function glob(string $pattern, $flags = 0): array
{ {
return glob($pattern, $flags); return glob($pattern, $flags);
} }
@@ -411,7 +411,7 @@ class FileSystem
* @param bool $hidden * @param bool $hidden
* @return \Symfony\Component\Finder\SplFileInfo[] * @return \Symfony\Component\Finder\SplFileInfo[]
*/ */
public function files($directory, $hidden = false) public function files(string $directory, $hidden = false): array
{ {
return iterator_to_array( return iterator_to_array(
Finder::create()->files()->ignoreDotFiles(! $hidden)->in($directory)->depth(0)->sortByName(), Finder::create()->files()->ignoreDotFiles(! $hidden)->in($directory)->depth(0)->sortByName(),
@@ -426,7 +426,7 @@ class FileSystem
* @param bool $hidden * @param bool $hidden
* @return \Symfony\Component\Finder\SplFileInfo[] * @return \Symfony\Component\Finder\SplFileInfo[]
*/ */
public function allFiles($directory, $hidden = false) public function allFiles(string $directory, $hidden = false): array
{ {
return iterator_to_array(Finder::create()->files()->ignoreDotFiles(! $hidden)->in($directory)->sortByName(), return iterator_to_array(Finder::create()->files()->ignoreDotFiles(! $hidden)->in($directory)->sortByName(),
false false
@@ -439,7 +439,7 @@ class FileSystem
* @param string $directory * @param string $directory
* @return array * @return array
*/ */
public function directories($directory) public function directories(string $directory): array
{ {
$directories = []; $directories = [];
@@ -459,7 +459,7 @@ class FileSystem
* @param bool $force * @param bool $force
* @return bool * @return bool
*/ */
public function makeDirectory($path, $mode = 0755, $recursive = false, $force = false) public function makeDirectory(string $path, $mode = 0755, $recursive = false, $force = false): bool
{ {
if ($force) { if ($force) {
return @mkdir($path, $mode, $recursive); return @mkdir($path, $mode, $recursive);
@@ -476,7 +476,7 @@ class FileSystem
* @param bool $overwrite * @param bool $overwrite
* @return bool * @return bool
*/ */
public function moveDirectory($from, $to, $overwrite = false) public function moveDirectory(string $from, string $to, $overwrite = false): bool
{ {
if ($overwrite && $this->isDirectory($to) && ! $this->deleteDirectory($to)) { if ($overwrite && $this->isDirectory($to) && ! $this->deleteDirectory($to)) {
return false; return false;
@@ -493,7 +493,7 @@ class FileSystem
* @param int|null $options * @param int|null $options
* @return bool * @return bool
*/ */
public function copyDirectory($directory, $destination, $options = null) public function copyDirectory(string $directory, string $destination, $options = null): bool
{ {
if (! $this->isDirectory($directory)) { if (! $this->isDirectory($directory)) {
return false; return false;
@@ -537,7 +537,7 @@ class FileSystem
* @param bool $preserve * @param bool $preserve
* @return bool * @return bool
*/ */
public function deleteDirectory($directory, $preserve = false) public function deleteDirectory(string $directory, $preserve = false): bool
{ {
if (! $this->isDirectory($directory)) { if (! $this->isDirectory($directory)) {
return false; return false;
@@ -567,7 +567,7 @@ class FileSystem
* @param string $directory * @param string $directory
* @return bool * @return bool
*/ */
public function deleteDirectories($directory) public function deleteDirectories(string $directory): bool
{ {
$allDirectories = $this->directories($directory); $allDirectories = $this->directories($directory);
@@ -588,7 +588,7 @@ class FileSystem
* @param string $directory * @param string $directory
* @return bool * @return bool
*/ */
public function cleanDirectory($directory) public function cleanDirectory(string $directory): bool
{ {
return $this->deleteDirectory($directory, true); return $this->deleteDirectory($directory, true);
} }

View File

@@ -125,7 +125,8 @@ class InstallLocalModule
*/ */
public function enableModule() public function enableModule()
{ {
CatchAdmin::enableModule($this->module); CatchAdmin::updateModuleInfo($this->module, ['enable' => true]);
app(Permissions::class)->restore(['module' => trim($this->module)]); app(Permissions::class)->restore(['module' => trim($this->module)]);
} }
@@ -137,7 +138,7 @@ class InstallLocalModule
*/ */
public function disableModule() public function disableModule()
{ {
CatchAdmin::disableModule($this->module); CatchAdmin::updateModuleInfo($this->module, ['enable' => false]);
Permissions::destroy(function ($query) { Permissions::destroy(function ($query) {
$query->where('module', trim($this->module)); $query->where('module', trim($this->module));

View File

@@ -100,9 +100,9 @@ declare(strict_types=1);
{ {
$left = $this->total - $this->current; $left = $this->total - $this->current;
$empty = str_repeat(' ', $left * $this->average); $empty = str_repeat(' ', intval($left * $this->average));
$bar = str_repeat('>', $this->current * $this->average); $bar = str_repeat('>', intval($this->current * $this->average));
$percent = ((int)(sprintf('%.2f', $this->current/$this->total) * 100)) . '%'; $percent = ((int)(sprintf('%.2f', $this->current/$this->total) * 100)) . '%';

View File

@@ -0,0 +1,50 @@
<?php
declare(strict_types=1);
namespace catcher\library\excel\reader;
use catcher\exceptions\FailedException;
use PhpOffice\PhpSpreadsheet\Reader\Csv;
use PhpOffice\PhpSpreadsheet\Reader\Ods;
use PhpOffice\PhpSpreadsheet\Reader\Slk;
use PhpOffice\PhpSpreadsheet\Reader\Xlsx;
use PhpOffice\PhpSpreadsheet\Reader\Xml;
class Factory
{
/**
* make reader
*
* @time 2021年04月01日
* @param $filename
* @return mixed
*/
public static function make($filename)
{
$ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
if (isset(self::readers()[$ext])) {
return app()->make(self::readers()[$ext]);
}
throw new FailedException('Dont Support The File Extension');
}
/**
* readers
*
* @time 2021年04月01日
* @return string[]
*/
protected static function readers(): array
{
return [
'xlsx' => Xlsx::class,
'xml' => Xml::class,
'ods' => Ods::class,
'slk' => Slk::class,
'csv' => Csv::class,
];
}
}

View File

@@ -0,0 +1,64 @@
<?php
declare(strict_types=1);
namespace catcher\library\excel\reader;
trait Macro
{
/**
* 移除不需要的列
*
* @time 2021年04月21日
* @param ...$indexes
* @return mixed
*/
public function remove(...$indexes)
{
foreach ($indexes as $index) {
unset($this->sheets[$index]);
}
return $this;
}
/**
* 设置 memory
*
* @time 2021年04月21日
* @param int $memory
* @return mixed
*/
public function memory(int $memory)
{
ini_set('memory_limit', $memory . 'M');
return $this;
}
/**
* 处理
*
* @time 2021年04月23日
* @return array
*/
protected function dealWith(): array
{
$headers = $this->headers();
$data = [];
foreach ($this->sheets as &$sheet) {
$d = [];
foreach ($headers as $k => $header) {
$d[$header] = method_exists($this, 'deal' . ucfirst($header)) ?
$this->{'deal' . ucfirst($header)}($sheet) : $sheet[$k];
}
$data[] = $d;
}
return $data;
}
}

View File

@@ -0,0 +1,74 @@
<?php
declare(strict_types=1);
namespace catcher\library\excel\reader;
use catcher\CatchUpload;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
abstract class Reader
{
use Macro;
/**
* 当前的 sheet
*
* false 代表获取全部 sheets
*
* @var bool
*/
protected $active = true;
protected $sheets;
/**
* 导入
*
* @time 2021年04月21日
* @param $file
* @return Reader
*/
public function import($file): Reader
{
$file = (new CatchUpload)->setPath('excel')->toLocal($file);
$reader = Factory::make($file);
// 设置只读
$reader->setReadDataOnly(true);
/* @var $spreadsheet Spreadsheet */
$spreadsheet = $reader->load($file);
if ($this->active) {
$this->sheets = $spreadsheet->getActiveSheet()->toArray();
} else {
foreach ($spreadsheet->getAllSheets() as $sheet) {
$this->sheets[] = $sheet->toArray();
}
}
return $this;
}
/**
* 必须实现的方法
*
* @time 2021年04月21日
* @return mixed
*/
abstract public function headers();
/**
* 数据处理
*
* @time 2021年04月23日
* @param callable $callback
* @return mixed
*/
public function then(callable $callback)
{
return $callback($this->dealWith());
}
}

View File

@@ -0,0 +1,332 @@
<?php
// +----------------------------------------------------------------------
// | Catch-CMS Design On 2020
// +----------------------------------------------------------------------
// | 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 catcher\library\form;
use catcher\exceptions\FailedException;
use catcher\library\form\components\AreaTrait;
use catcher\library\form\components\Editor;
use FormBuilder\Exception\FormBuilderException;
use FormBuilder\Factory\Elm;
use FormBuilder\UI\Elm\Components\Upload;
use FormBuilder\UI\Elm\Traits\CascaderFactoryTrait;
use FormBuilder\UI\Elm\Traits\CheckBoxFactoryTrait;
use FormBuilder\UI\Elm\Traits\ColorPickerFactoryTrait;
use FormBuilder\UI\Elm\Traits\DatePickerFactoryTrait;
use FormBuilder\UI\Elm\Traits\FormStyleFactoryTrait;
use FormBuilder\UI\Elm\Traits\FrameFactoryTrait;
use FormBuilder\UI\Elm\Traits\GroupFactoryTrait;
use FormBuilder\UI\Elm\Traits\HiddenFactoryTrait;
use FormBuilder\UI\Elm\Traits\InputFactoryTrait;
use FormBuilder\UI\Elm\Traits\InputNumberFactoryTrait;
use FormBuilder\UI\Elm\Traits\RadioFactoryTrait;
use FormBuilder\UI\Elm\Traits\RateFactoryTrait;
use FormBuilder\UI\Elm\Traits\SelectFactoryTrait;
use FormBuilder\UI\Elm\Traits\SliderFactoryTrait;
use FormBuilder\UI\Elm\Traits\SwitchesFactoryTrait;
use FormBuilder\UI\Elm\Traits\TimePickerFactoryTrait;
use FormBuilder\UI\Elm\Traits\TreeFactoryTrait;
use FormBuilder\UI\Elm\Traits\UploadFactoryTrait;
use FormBuilder\UI\Elm\Traits\ValidateFactoryTrait;
abstract class Form
{
use CascaderFactoryTrait;
use CheckBoxFactoryTrait;
use ColorPickerFactoryTrait;
use DatePickerFactoryTrait;
use FrameFactoryTrait;
use HiddenFactoryTrait;
use InputNumberFactoryTrait;
use InputFactoryTrait;
use RadioFactoryTrait;
use RateFactoryTrait;
use SliderFactoryTrait;
use SelectFactoryTrait;
use FormStyleFactoryTrait;
use SwitchesFactoryTrait;
use TimePickerFactoryTrait;
use TreeFactoryTrait;
use UploadFactoryTrait;
use ValidateFactoryTrait;
use GroupFactoryTrait;
use FormValidates;
use AreaTrait;
protected $primaryKeyField = 'id';
protected $fieldsValue = [];
/**
* 必须实现的
*
* @time 2021年03月06日
* @return array
*/
abstract public function fields(): array;
/**
* 创建 Form
*
* @time 2021年03月06日
* @return array
*/
public function create(): array
{
$fields = $this->getFields();
// 获取表单字段填充的值
if (method_exists($this, 'getFieldsValue')) {
$this->fieldsValue = $this->getFieldsValue();
$fields = $this->setFieldsValue($fields);
}
return $this->rule($fields);
}
/**
* 设置 fields values
*
* @time 2021年03月12日
* @param $fields
* @return mixed
*/
protected function setFieldsValue($fields)
{
foreach ($fields as $field) {
$name = $field->getName();
if (isset($this->fieldsValue[$name])) {
$field->value($this->fieldsValue[$name]);
}
}
return $fields;
}
/**
* 获取 form fields
*
* @time 2021年03月12日
* @return array
*/
protected function getFields(): array
{
if ($this->primaryKeyField) {
return array_merge($this->fields(), [
self::hidden($this->primaryKeyField, 0)
]);
}
return $this->fields();
}
/**
* form rule
*
* @time 2021年03月06日
* @param array $rules
* @return array
*/
public function rule(array $rules): array
{
try{
return Elm::createForm('', $rules)->formRule();
} catch (FormBuilderException $e) {
throw new FailedException('Form Created Failed: ' .$e->getMessage());
}
}
/**
* 上传图片地址
*
* @time 2021年03月03日
* @return string
*/
public static function uploadImageUrl(): string
{
return env('app.domain') . '/upload/image';
}
/**
* 上传文件地址
*
* @time 2021年03月10日
* @return string
*/
public static function uploadFileUrl(): string
{
return env('app.domain') . '/upload/file';
}
/**
* auth token
*
* @time 2021年04月11日
* @return string[]
*/
public static function authorization(): array
{
return [
'authorization' => 'Bearer ' . request()->user()->remember_token,
];
}
/**
* 上传图片
*
* @time 2021年03月03日
* @param $title
* @param string $value
* @return mixed
*/
public static function image(string $title, string $value = ''): Upload
{
return self::uploadImage('image', $title, self::uploadImageUrl(), $value)
->uploadName('image')
->data(['none' => ''])
->headers(self::authorization());
}
/**
* 多图
*
* @time 2021年03月03日
* @param $title
* @param array $value
* @return mixed
*/
public static function images(string $title, array $value = []): Upload
{
return self::uploadImages('image', $title, self::uploadImageUrl(), $value)
->uploadName('image')
->data(['none' => ''])
->headers(self::authorization());
}
/**
* 上传文件
*
* @time 2021年03月10日
* @param string $title
* @param string $value
* @return Upload
*/
public static function file(string $title, string $value = ''): Upload
{
return self::uploadFile('file', $title, self::uploadFileUrl(), $value)
->uploadName('image')
->data(['none' => ''])
->headers(self::authorization());
}
/**
* 上传多文件
*
* @time 2021年03月10日
* @param string $title
* @param array $value
* @return Upload
*/
public static function files(string $title, array $value = []): Upload
{
return self::uploadFiles('file', $title, self::uploadFileUrl(), $value)
->uploadName('file')
->data(['none' => ''])
->headers(self::authorization());
}
/**
* options
*
* @time 2021年03月24日
* @return FormOptions
*/
public static function options(): FormOptions
{
return new FormOptions();
}
/**
* props
*
* @time 2021年03月30日
* @param $label
* @param string $value
* @param array $extra
* @param array $data
* @return array
*/
public static function props($label, $value = 'id', array $extra = [], array $data = []): array
{
$props = [
'props' => array_merge([
'label' => $label,
'value' => $value,
], $extra)
];
if (count($data)) {
$props['data'] = $data;
}
return $props;
}
/**
* 不需要 props
*
* @time 2021年03月30日
* @param $label
* @param string $value
* @param array $extra
* @return array
*/
public static function treeProps($label, $value = 'id', array $extra = []): array
{
return array_merge([
'label' => $label,
'value' => $value,
], $extra);
}
/**
* col
*
* @time 2021年03月30日
* @param int $col
* @return array
*/
public static function col(int $col): array
{
return ['span' => $col];
}
/**
* 编辑器
*
* @time 2021年04月08日
* @param $field
* @param $title
* @param string $value
* @return Editor
*/
public static function editor(string $field, string $title, string $value = ''): Editor
{
return new Editor($field, $title, $value);
}
}

View File

@@ -0,0 +1,34 @@
<?php
namespace catcher\library\form;
use catcher\exceptions\FailedException;
abstract class FormFactory
{
abstract public static function from();
/**
* 创建 Form
*
* @time 2021年03月02日
* @param $name
* @return mixed
*/
public static function create($name)
{
$form = static::from() . '\\'. ucfirst($name);
if (!class_exists($form)) {
throw new FailedException(sprintf('Form [%s] not found! Please create it first', ucfirst($name)));
}
$form = app($form);
if (!$form instanceof Form) {
throw new FailedException(sprintf('Form [%s] must implements interface [FormCreate]', ucfirst($name)));
}
return $form->create();
}
}

View File

@@ -0,0 +1,49 @@
<?php
// +----------------------------------------------------------------------
// | Catch-CMS Design On 2020
// +----------------------------------------------------------------------
// | 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 catcher\library\form;
class FormOptions
{
protected $options = [];
/**
* 增加 option
*
* @time 2021年03月24日
* @param $label
* @param $value
* @return $this
*/
public function add($label, $value): FormOptions
{
$this->options[] = [
'value' => $value,
'label' => $label,
];
return $this;
}
/**
* 获取
*
* @time 2021年03月24日
* @return array
*/
public function render()
{
return $this->options;
}
}

View File

@@ -0,0 +1,140 @@
<?php
namespace catcher\library\form;
use FormBuilder\UI\Elm\Validate;
trait FormValidates
{
/**
* 正则验证
*
* @time 2021年03月06日
* @param string $pattern
* @return Validate
*/
public static function validatePattern(string $pattern): Validate
{
return self::validateStr()->pattern($pattern);
}
/**
* 纯数字验证
*
* @time 2021年03月12日
* @return Validate
*/
public static function validateAlpha(): Validate
{
return self::validatePattern('^[A-Za-z]+$')->message('必须为纯字母');
}
/**
* 字母和数字
*
* @time 2021年03月12日
* @return Validate
*/
public static function validateAlphaNum(): Validate
{
return self::validatePattern('^[A-Za-z0-9]+$')->message('必须为字母和数字');
}
/**
*
*
* @time 2021年03月12日
* @return Validate
*/
public static function validateAlphaDash(): Validate
{
return self::validatePattern('^[A-Za-z0-9\-\_]+$')->message('必须为字母和数字下划线_及破折号-');
}
/**
* 手机号
*
* @time 2021年03月12日
* @return Validate
*/
public static function validateMobile(): Validate
{
return self::validatePattern('^1[3-9]\d{9}$')->message('请输入正确的手机号格式');
}
/**
* 身份证
*
* @time 2021年03月12日
* @return Validate
*/
public static function validateIdCard(): Validate
{
return self::validatePattern('(^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$)|(^[1-9]\d{5}\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}$)')->message('身份证输入格式不正确');
}
/**
* 邮政编码
*
* @time 2021年03月12日
* @return Validate
*/
public static function validateZip(): Validate
{
return self::validatePattern('\d{6}')->message('请输入有效的邮政编码');
}
/**
* IP 地址
*
* @time 2021年03月12日
* @return Validate
*/
public static function validateIp(): Validate
{
return self::validatePattern('((?:(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d))')->message('请输入正确的 IP 地址');
}
/**
* 座机
*
* @time 2021年03月12日
* @return Validate
*/
public static function validateLandLine(): Validate
{
return self::validatePattern('\d{3}-\d{8}|\d{4}-\d{7}')->message('请输入正确的座机格式');
}
/**
* 密码
*
* @time 2021年03月12日
* @return Validate
*/
public static function validatePassword(): Validate
{
return self::validatePattern('^[a-zA-Z]\w{5,18}$')->message('以字母开头长度在6~18之间只能包含字母、数字和下划线');
}
/**
* 强密码
*
* @time 2021年03月12日
* @return Validate
*/
public static function validateStrongPassword(): Validate
{
return self::validatePattern('^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,20}$')->message('必须包含大小写字母和数字的组合不能使用特殊字符长度在8-20之间');
}
/**
* 纯汉字
*
* @time 2021年03月12日
* @return Validate
*/
public static function validateChineseCharacter(): Validate
{
return self::validatePattern('^[\u4e00-\u9fa5]{0,}$')->message('必须为纯汉字');
}
}

View File

@@ -0,0 +1,50 @@
<?php
namespace catcher\library\form\components;
use catcher\traits\db\RewriteTrait;
use FormBuilder\Factory\Elm;
trait AreaTrait
{
public function area($field = 'area', $title = '地区', $props = [])
{
if (!count($props)) {
$props = self::props('name', 'id', [
'checkStrictly' => true
]);
}
return self::cascader($field, $title)
->options($this->getRegion(3))
->props($props)
->clearable(true)
->filterable(true);
}
public function createValidate()
{
// TODO: Implement createValidate() method.
return Elm::validateStr();
}
/**
* 支持四级
* $level 1,2,3,4
* @time 2021年04月19日
* @param int $level
* @return mixed
*/
protected function getRegion($level = 1)
{
$areaModel = new class extends \think\Model {
protected $name = 'region';
use RewriteTrait;
};
return $areaModel->where('level', '<=', $level)
->field(['id', 'name', 'parent_id'])
->select()->toTree();
}
}

View File

@@ -0,0 +1,156 @@
<?php
namespace catcher\library\form\components;
use catcher\library\form\Form;
use FormBuilder\Driver\FormComponent;
use FormBuilder\Factory\Elm;
class Editor extends FormComponent
{
protected $defaultProps = [
'type' => 'editor'
];
protected $defaultPlugins = ['advlist anchor autolink autosave lists code codesample colorpicker colorpicker contextmenu directionality emoticons fullscreen hr image imagetools insertdatetime link lists media nonbreaking noneditable pagebreak paste preview print save searchreplace spellchecker tabfocus table template textcolor textpattern visualblocks visualchars wordcount'];
protected $defaultToolbars = ['searchreplace bold italic underline strikethrough alignleft aligncenter alignright outdent indent blockquote undo redo removeformat subscript superscript code codesample', 'hr bullist numlist link image charmap preview anchor pagebreak insertdatetime media table emoticons forecolor backcolor fullscreen'];
/**
* 初始化
*
* @time 2021年04月11日
* @return Editor|void
*/
protected function init(): Editor
{
return $this->plugins()
->toolbars()
->language()
->initContent()
->uploadConf();
}
public function createValidate()
{
// TODO: Implement createValidate() method.
return Elm::validateStr();
}
/**
* set plugins
*
* @time 2021年04月11日
* @param array $plugins
* @return Editor
*/
public function plugins(array $plugins = []): Editor
{
$this->props([
'plugins' => count($plugins) ? $plugins : $this->defaultPlugins,
]);
return $this;
}
/**
* set toolbars
*
* @time 2021年04月11日
* @param array $toolbars
* @return Editor
*/
public function toolbars(array $toolbars = []): Editor
{
$this->props([
'toolbar' => count($toolbars) ? $toolbars : $this->defaultToolbars,
]);
return $this;
}
/**
* 设置语言
* 支持 'es_MX', 'en', 'zh_CN', 'ja'
* @time 2021年04月11日
* @param string $language
* @return $this
*/
public function language(string $language = 'zh_CN'): Editor
{
$this->props([
'language' => $language
]);
return $this;
}
/**
* 编辑器高度
*
* @time 2021年04月11日
* @param int $height
* @return $this
*/
public function height(int $height = 500): Editor
{
$this->props([
'height' => $height
]);
return $this;
}
/**
* 宽度设置
*
* @time 2021年04月11日
* @param string $width
* @return $this
*/
public function width($width = 'auto'): Editor
{
$this->props([
'width' => $width
]);
return $this;
}
/**
* 编辑器默认内容
*
* @time 2021年04月11日
* @param string $content
* @return $this
*/
public function initContent(string $content = ''): Editor
{
$this->props([
'initContent' => $content
]);
return $this;
}
/**
* 上传配置
*
* @time 2021年04月11日
* @param int $size
* @return $this
*/
public function uploadConf(int $size = 10): Editor
{
$this->props([
'uploadConf' => array_merge([
'url' => Form::uploadImageUrl(),
'size' => $size,
], Form::authorization())
]);
return $this;
}
}

View File

@@ -0,0 +1,110 @@
<?php
namespace catcher\library\table;
use catcher\library\table\components\Button;
class Actions
{
protected static $noText = false;
/**
* 创建按钮
*
* @time 2021年03月23日
* @param string $text
* @param string $event
* @return mixed
*/
public static function create(string $text = '新建', string $event = 'handleCreate')
{
return self::normal($text, 'primary',$event)->icon('el-icon-plus');
}
/**
* 更新按钮
*
* @time 2021年03月23日
* @param string $text
* @param string $event
* @return mixed
*/
public static function update(string $text = '更新', string $event = 'handleUpdate')
{
return self::normal($text, 'primary', $event)->icon('el-icon-edit');
}
/**
* 删除按钮
*
* @time 2021年03月23日
* @param string $text
* @param string $event
* @return mixed
*/
public static function delete(string $text = '删除', string $event = 'handleDel')
{
return self::normal($text, 'danger', $event)->icon('el-icon-delete');
}
/**
* 查询按钮
*
* @time 2021年03月23日
* @param string $text
* @param string $type
* @param string|null $event
* @return mixed
*/
public static function view(string $text = '查看', $type = 'success', string $event = 'handleView')
{
return self::normal($text, $type, $event)->icon('el-icon-view');
}
/**
* normal
*
* @time 2021年03月23日
* @param string $text
* @param string $type
* @param string|null $event
* @return Button
*/
public static function normal(string $text, $type = '', string $event = null): Button
{
$button = (new Button)
->size('mini')
->type($type)
->text(self::$noText ? '' : $text);
if ($event) {
return $button->click($event);
}
return $button;
}
/**
* 导出按钮
*
* @time 2021年04月02日
* @return mixed
*/
public static function export()
{
return self::normal('导出', 'success','handleExport')->icon('el-icon-download');
}
/**
* 导入按钮
*
* @time 2021年04月02日
* @return mixed
*/
public static function import()
{
return self::normal('导入', 'warning', 'handleImport')->icon('el-icon-upload2');
}
}

View File

@@ -0,0 +1,67 @@
<?php
namespace catcher\library\table;
trait ComponentsTrait
{
/**
* component
*
* @time 2021年03月24日
* @param string $name
* @param string $updateField
* @param array $options
* @return ComponentsTrait|HeaderItem
*/
public function component(string $name, string $updateField = '', $options = [])
{
$this->attributes['component'][] = [
'name' => $name,
'field' => $updateField ? : $this->attributes['prop'],
'options' => $options
];
return $this;
}
/**
* switch
*
* @time 2021年03月23日
* @param null $updateFields
* @return HeaderItem
*/
public function withSwitchComponent(array $options = [], $updateFields = null): HeaderItem
{
return $this->component('switch_', $updateFields ? : $this->attributes['prop'], $options);
}
/**
* edit
*
* @time 2021年03月23日
* @param null $updateFields
* @return HeaderItem
*/
public function withEditComponent($updateFields = null): HeaderItem
{
return $this->component('edit', $updateFields ? : $this->attributes['prop']);
}
/**
* Edit Number
*
* @time 2021年03月23日
* @param null $updateFields
* @return HeaderItem
*/
public function withEditNumberComponent($updateFields = null): HeaderItem
{
return $this->component('editNumber', $updateFields ? : $this->attributes['prop']);
}
public function withSelectComponent(array $options, $updateFields = null): HeaderItem
{
return $this->component('select_', $updateFields ? : $this->attributes['prop'], $options);
}
}

View File

@@ -0,0 +1,20 @@
<?php
namespace catcher\library\table;
trait Events
{
/**
* 表格选择事件
*
* @time 2021年03月29日
* @return mixed
*/
public function selectionChange()
{
$this->appendEvents([
'selection-change' => 'handleSelectMulti'
]);
return $this;
}
}

View File

@@ -0,0 +1,109 @@
<?php
namespace catcher\library\table;
/**
*
* @time 2021年04月21日
*/
class Excel
{
protected static $label;
protected $sheets = [];
/**
* name
*
* @time 2021年04月21日
* @param string $name
* @return $this
*/
public function prop(string $name): Excel
{
$this->sheets['prop'] = $name;
return $this;
}
/**
* label
*
* @time 2021年04月21日
* @param string $label
* @return $this
*/
protected function label(string $label): Excel
{
$this->sheets['label'] = $label;
return $this;
}
/**
* options
*
* @time 2021年04月21日
* @param array $options
* @return $this
*/
public function options(array $options): Excel
{
$this->sheets['options'] = $options;
return $this;
}
/**
* 导入
*
* @time 2021年04月22日
* @param bool $import
* @return $this
*/
public function import(bool $import = true): Excel
{
$this->sheets['import'] = $import;
return $this;
}
/**
* 导出
*
* @time 2021年04月22日
* @param bool $export
* @return $this
*/
public function export(bool $export = true): Excel
{
$this->sheets['export'] = $export;
return $this;
}
/**
* 渲染
*
* @time 2021年04月21日
* @return array
*/
public function render(): array
{
return $this->sheets;
}
/**
* 静态访问
*
* @time 2021年04月21日
* @param $method
* @param $params
* @return false|mixed
*/
public static function __callStatic($method, $params)
{
return call_user_func_array([new self(), $method], $params);
}
}

View File

@@ -0,0 +1,121 @@
<?php
namespace catcher\library\table;
class HeaderItem
{
use ComponentsTrait;
protected $attributes = [];
public function __construct(string $label)
{
$this->attributes['label'] = $label;
return $this;
}
public static function label(string $label = ''): HeaderItem
{
return new self($label);
}
public function prop(string $prop): HeaderItem
{
$this->attributes['prop'] = $prop;
return $this;
}
public function width(string $width): HeaderItem
{
$this->attributes['width'] = $width;
return $this;
}
public function actions(array $actions): HeaderItem
{
foreach ($actions as $action) {
$this->attributes['action'][] = $action->render();
}
return $this;
}
public function isBubble($bubble = false): HeaderItem
{
$this->attributes['isBubble'] = $bubble;
return $this;
}
/**
* 可排序
*
* @time 2021年03月31日
* @return $this
*/
public function sortable(): HeaderItem
{
$this->attributes['sortable'] = true;
return $this;
}
/**
* selection
*
* @time 2021年03月29日
* @return mixed
*/
public function selection()
{
return $this->width(50)->type('selection');
}
/**
* dont export
*
* @time 2021年04月22日
* @return $this
*/
public function dontExport(): HeaderItem
{
$this->attributes['export'] = false;
return $this;
}
/**
* dont import
*
* @time 2021年04月22日
* @return $this
*/
public function dontImport(): HeaderItem
{
$this->attributes['import'] = false;
return $this;
}
/**
* 动态访问
*
* @time 2021年03月24日
* @param $method
* @param $params
* @return $this
*/
public function __call($method, $params): HeaderItem
{
$this->attributes[$method] = $params[0];
return $this;
}
public function __get($key)
{
return $this->{$key};
}
}

View File

@@ -0,0 +1,127 @@
<?php
namespace catcher\library\table;
use catcher\base\CatchModel;
use FormBuilder\UI\Elm\Components\Input;
use FormBuilder\UI\Elm\Components\Select;
use FormBuilder\UI\Elm\Components\DatePicker;
use catcher\library\form\Form;
class Search
{
protected static $label = '';
public static function label(string $label): Search
{
self::$label = $label;
return new self();
}
/**
* 名称
*
* @time 2021年03月23日
* @param $placeholder
* @return \FormBuilder\UI\Elm\Components\Input
*/
public static function name(string $placeholder): Input
{
return Form::input('name', self::$label)->placeholder($placeholder);
}
/**
* 状态
*
* @time 2021年03月23日
* @param $placeholder
* @return \FormBuilder\UI\Elm\Components\Select
*/
public static function status(string $placeholder = '请选择状态'): Select
{
return self::select('status', $placeholder, [
[ 'value' => CatchModel::ENABLE, 'label'=> ' 正常'],
[ 'value' => CatchModel::DISABLE, 'label'=> ' 禁用']
]);
}
/**
* 开始时间
*
* @time 2021年03月23日
* @param string $placeholder
* @return \FormBuilder\UI\Elm\Components\DatePicker
*/
public static function startAt(string $placeholder = '请选择开始时间'): DatePicker
{
return self::label(self::$label ? : '开始时间')->datetime('start_at', $placeholder);
}
/**
* 结束时间
*
* @time 2021年03月23日
* @param string $placeholder
* @return \FormBuilder\UI\Elm\Components\DatePicker
*/
public static function endAt(string $placeholder = '请选择结束时间'): DatePicker
{
return self::label(self::$label ? : '结束时间')->datetime('end_at', $placeholder);
}
/**
* 文本
*
* @time 2021年03月23日
* @param $name
* @param $placeholder
* @return \FormBuilder\UI\Elm\Components\Input
*/
public static function text(string $name, string $placeholder): Input
{
return Form::input($name, self::$label)->placeholder($placeholder);
}
/**
* 选择
*
* @time 2021年03月23日
* @param $name
* @param $placeholder
* @param $options
* @return \FormBuilder\UI\Elm\Components\Select
*/
public static function select(string $name, string $placeholder, array $options): Select
{
return Form::select($name, self::$label)->placeholder($placeholder)->options($options);
}
/**
* 选择时间
*
* @time 2021年03月23日
* @param $name
* @param $placeholder
* @return \FormBuilder\UI\Elm\Components\DatePicker
*/
public static function datetime(string $name, string $placeholder): DatePicker
{
return Form::dateTime($name, self::$label)
->placeholder($placeholder)
->format('yyyy-MM-dd HH:mm:ss')
->valueFormat('yyyy-MM-dd HH:mm:ss');
}
/**
* 代理方法
*
* @time 2021年04月06日
* @param $method
* @param $params
* @return mixed
*/
public static function __callStatic($method, $params)
{
return Form::{$method}(...$params);
}
}

View File

@@ -0,0 +1,515 @@
<?php
namespace catcher\library\table;
class Table
{
use Events;
/**
* 头信息
*
* @var array
*/
protected $headers = [];
/**
* table 操作
*
* @var array
*/
protected $actions = [];
/**
* 搜索参数
*
* @var array
*/
protected $search = [];
/**
* 表格引用
*
* @var string
*/
protected $ref;
/**
* @var array
*/
protected $defaultQueryParams = [];
/**
* 表单事件
*
* @var array
*/
protected $events = [];
/**
* 是否隐藏分页
*
* @var bool
*/
protected $hiddenPaginate = false;
/**
* tree table
*
* @var array
*/
protected $tree = [];
/**
* @var string
*/
protected $apiRoute;
/**
* @var bool
*/
protected $loading = false;
/**
* @var array
*/
protected $dialog;
/**
* @var array
*/
protected $filterParams;
/**
* @var string
*/
protected $importRoute;
/**
* @var string
*/
protected $exportRoute;
/**
* @var bool
*/
protected $forceUpdate = false;
/**
* @var array
*/
protected $excel = [];
/**
* 导出 excel 所使用 model
*
* @var string
*/
protected $usedModel;
/**
* Table constructor.
* @param string $ref
*/
public function __construct(string $ref)
{
$this->ref = $ref;
}
/**
* 设置头信息
*
* @time 2021年03月21日
* @param array $header
* @return $this
*/
public function header(array $header): Table
{
foreach ($header as $h) {
$this->headers[] = $h->attributes;
}
return $this;
}
/**
* 设置 actions
*
* @time 2021年03月21日
* @param array $actions
* @return $this
*/
public function withActions(array $actions): Table
{
foreach ($actions as $action) {
$this->actions[] = $action->render();
}
return $this;
}
/**
* 设置搜索参数
*
* @time 2021年03月21日
* @param array $search
* @return $this
*/
public function withSearch(array $search): Table
{
$this->search = $search;
return $this;
}
/**
* 表单事件
*
* @time 2021年03月21日
* @param array $events
* @return $this
*/
public function withEvents(array $events): Table
{
$this->events = $events;
return $this;
}
/**
* excel 信息
*
* @time 2021年04月21日
* @param array $excel
* @param string $usedModel
* @return $this
*/
public function withUsedModelAndExcel(string $usedModel, array $excel): Table
{
foreach ($excel as $e) {
$this->excel[] = $e->render();
}
$this->usedModel = $usedModel;
return $this;
}
/**
* set
*
* @time 2021年03月29日
* @param array $params
* @return $this
*/
public function withDefaultQueryParams(array $params): Table
{
$this->defaultQueryParams = $params;
return $this;
}
/**
* filter params
*
* @time 2021年03月30日
* @param array $filterParams
* @return $this
*/
public function withFilterParams(array $filterParams): Table
{
$this->filterParams = $filterParams;
return $this;
}
/**
* 隐藏分页
*
* @time 2021年03月29日
* @return $this
*/
public function withHiddenPaginate(): Table
{
$this->hiddenPaginate = true;
return $this;
}
/**
* 设置 api route
*
* @time 2021年03月29日
* @param string $apiRoute
* @return $this
*/
public function withApiRoute(string $apiRoute): Table
{
$this->apiRoute = $apiRoute;
return $this;
}
/**
* loading
*
* @time 2021年03月29日
* @return $this
*/
public function withLoading(): Table
{
$this->loading = true;
return $this;
}
/**
* 设置弹出层的宽度
*
* @time 2021年03月29日
* @param string $width
* @return $this
*/
public function withDialogWidth(string $width): Table
{
$this->dialog['width'] = $width;
return $this;
}
/**
* 导出路由
*
* @time 2021年04月02日
* @param string $route
* @return $this
*/
public function withImportRoute(string $route): Table
{
$this->importRoute = $route;
return $this;
}
/**
* 导出路由
*
* @time 2021年04月02日
* @param string $route
* @return $this
*/
public function withExportRoute(string $route): Table
{
$this->exportRoute = $route;
return $this;
}
/**
* 变成 tree table
*
* @time 2021年03月29日
* @param string $rowKey
* @param array $props ['children' => '', 'hasChildren' => '']
* @return $this
*/
public function toTreeTable(string $rowKey = 'id', array $props = []): Table
{
$this->tree['row_key'] = $rowKey;
$this->tree['props'] = count($props) ? $props : [
'children' => 'children',
'hasChildren' => 'hasChildren'
];
return $this;
}
/**
* 强制更新组件
*
* @time 2021年04月05日
* @return $this
*/
public function forceUpdate(): Table
{
$this->forceUpdate = true;
return $this;
}
/**
* 渲染
*
* @time 2021年03月21日
* @return array
*/
public function render(): array
{
$render = [];
foreach (get_class_vars(self::class) as $property => $v) {
if (!empty($this->{$property})) {
$render[$property] = $this->{$property};
}
}
return $render;
}
/**
* 追加 headers
*
* @time 2021年03月28日
* @param $header
* @return $this
*/
public function appendHeaders($header): Table
{
if ($header instanceof HeaderItem) {
$this->headers[] = $header;
}
if (is_array($header)) {
$this->headers = array_merge($this->headers, $header);
}
return $this;
}
/**
* 追加
*
* @time 2021年03月29日
* @param string $param
* @return $this
*/
public function appendDefaultQueryParams(string $param): Table
{
$this->defaultQueryParams[] = $param;
return $this;
}
/**
* 追加 events
*
* @time 2021年03月28日
* @param array $events
* @return $this
*/
public function appendEvents(array $events): Table
{
$this->events = array_merge($this->events, $events);
return $this;
}
/**
* 追加 events
*
* @time 2021年03月28日
* @param array $actions
* @return $this
*/
public function appendActions(array $actions): Table
{
$this->actions = array_merge($this->actions, $actions);
return $this;
}
/**
* 追加 header
*
* @time 2021年03月28日
* @param array $header
* @return $this
*/
public function appendHeader(array $header): Table
{
$this->headers = array_merge($this->headers, $header);
return $this;
}
/**
* 新增 filter params
*
* @time 2021年03月30日
* @param array $params
* @return $this
*/
public function appendFilterParams(array $params): Table
{
$this->filterParams = array_merge($this->filterParams, $params);
return $this;
}
/**
* 获取头部
*
* @time 2021年03月29日
* @return array
*/
public function getHeader(): array
{
return $this->headers;
}
/**
* 获取事件
*
* @time 2021年03月29日
* @return array
*/
public function getEvents(): array
{
return $this->events;
}
/**
* 获取表格操作
*
* @time 2021年03月29日
* @return array
*/
public function getActions(): array
{
return $this->actions;
}
/**
* 获取 默认 query params
*
* @time 2021年03月29日
* @return array
*/
public function getDefaultQueryParams(): array
{
return $this->defaultQueryParams;
}
/**
* get filter params
*
* @time 2021年03月30日
* @return array
*/
public function getFilterParams(): array
{
return $this->filterParams;
}
}

View File

@@ -0,0 +1,36 @@
<?php
namespace catcher\library\table\components;
class Button extends Component
{
protected $el = 'button';
public function icon(string $icon): Button
{
$this->attributes['icon'] = $icon;
return $this;
}
public function text(string $text): Button
{
$this->attributes['label'] = $text;
return $this;
}
public function style(string $style): Button
{
$this->attributes['class'] = $style;
return $this;
}
public function click(string $click): Button
{
$this->attributes['click'] = $click;
return $this;
}
}

View File

@@ -0,0 +1,43 @@
<?php
namespace catcher\library\table\components;
class Component
{
/**
* @var array
*/
protected $attributes = [];
protected $el;
public function __construct()
{
$this->attributes['el'] = $this->el;
}
/**
* 魔术方法
*
* @time 2021年03月21日
* @param $method
* @param $params
* @return $this
*/
public function __call($method, $params): Component
{
$this->attributes[$method] = $params[0];
return $this;
}
/**
* 输出
*
* @time 2021年03月23日
* @return array
*/
public function render()
{
return $this->attributes;
}
}

View File

@@ -3,9 +3,8 @@ declare(strict_types=1);
namespace catcher\traits\db; namespace catcher\traits\db;
use catcher\CatchModelCollection; use catcher\library\excel\reader\Reader;
use catcher\Utils; use catcher\Utils;
use think\Collection;
trait BaseOptionsTrait trait BaseOptionsTrait
{ {
@@ -42,7 +41,7 @@ trait BaseOptionsTrait
*/ */
public function storeBy(array $data) public function storeBy(array $data)
{ {
if ($this->allowField($this->field)->save($data)) { if ($this->allowField($this->field)->save($this->filterData($data))) {
return $this->{$this->getPk()}; return $this->{$this->getPk()};
} }
@@ -72,7 +71,7 @@ trait BaseOptionsTrait
*/ */
public function updateBy($id, $data, $field = ''): bool public function updateBy($id, $data, $field = ''): bool
{ {
if (static::update($data, [$field ? : $this->getPk() => $id], $this->field)) { if (static::update($this->filterData($data), [$field ? : $this->getPk() => $id], $this->field)) {
return true; return true;
} }
@@ -164,13 +163,25 @@ trait BaseOptionsTrait
* *
* @time 2020年01月13日 * @time 2020年01月13日
* @param $field * @param $field
* @return string * @return array|string
*/ */
public function aliasField($field): string public function aliasField($field)
{ {
if (is_string($field)) {
return sprintf('%s.%s', $this->getTable(), $field); return sprintf('%s.%s', $this->getTable(), $field);
} }
if (is_array($field)) {
foreach ($field as &$value) {
$value = sprintf('%s.%s', $this->getTable(), $value);
}
return $field;
}
return $field;
}
/** /**
* 禁用/启用 * 禁用/启用
* *
@@ -191,23 +202,75 @@ trait BaseOptionsTrait
} }
/** /**
* rewrite collection * 过滤数据
* *
* @time 2020年10月20 * @time 2021年02月28
* @param array|iterable $collection * @param $data
* @param string|null $resultSetType * @return mixed
* @return CatchModelCollection|mixed
*/ */
public function toCollection(iterable $collection = [], string $resultSetType = null): Collection protected function filterData($data)
{ {
$resultSetType = $resultSetType ?: $this->resultSetType; foreach ($data as $field => $value) {
if (is_null($value)) {
if ($resultSetType && false !== strpos($resultSetType, '\\')) { unset($data[$field]);
$collection = new $resultSetType($collection);
} else {
$collection = new CatchModelCollection($collection);
} }
return $collection; if ($field == $this->getPk()) {
unset($data[$field]);
}
}
return $data;
}
public function import($fields, $file)
{
$excel = new class(array_column($fields, 'field')) extends Reader {
protected $fields;
public function __construct($fields)
{
$this->fields = $fields;
}
public function headers()
{
// TODO: Implement headers() method.
return $this->fields;
}
};
$options = [];
foreach ($fields as $field) {
$p = [];
if (isset($field['options']) && count($field['options'])) {
foreach ($field['options'] as $op) {
$p[$op['label']] = $op['value'];
}
$options[$field['field']] = $p;
}
}
$creatorId = request()->user()->id;
$excel->import($file)->remove(0)->then(function ($data) use ($options, $creatorId){
foreach ($data as &$d) {
foreach ($d as $field => &$v) {
if (isset($options[$field])) {
$v = $options[$field][$v];
}
}
$d['creator_id'] = $creatorId;
$this->createBy($d);
}
});
return true;
} }
} }

View File

@@ -1,6 +1,9 @@
<?php <?php
namespace catcher\traits\db; namespace catcher\traits\db;
use catcher\CatchModelCollection;
use think\Collection;
/** /**
* 重写 think\Model 的方法 * 重写 think\Model 的方法
* *
@@ -53,4 +56,25 @@ trait RewriteTrait
return $this; return $this;
} }
/**
* rewrite collection
*
* @time 2020年10月20日
* @param array|iterable $collection
* @param string|null $resultSetType
* @return CatchModelCollection|mixed
*/
public function toCollection(iterable $collection = [], string $resultSetType = null): Collection
{
$resultSetType = $resultSetType ?: $this->resultSetType;
if ($resultSetType && false !== strpos($resultSetType, '\\')) {
$collection = new $resultSetType($collection);
} else {
$collection = new CatchModelCollection($collection);
}
return $collection;
}
} }

View File

@@ -1,50 +0,0 @@
<?php
declare(strict_types=1);
namespace catcher\traits\db;
use think\facade\Db;
trait TransTrait
{
/**
*
* @time 2019年12月03日
* @return void
*/
public function startTrans()
{
Db::startTrans();
}
/**
*
* @time 2019年12月03日
* @return void
*/
public function commit()
{
Db::commit();
}
/**
*
* @time 2019年12月03日
* @return void
*/
public function rollback()
{
Db::rollback();
}
/**
*
* @time 2019年12月03日
* @param \Closure $function
* @return void
*/
public function transaction(\Closure $function)
{
Db::transaction($function());
}
}

View File

@@ -19,6 +19,10 @@ class SensitiveWord implements ValidateInterface
{ {
$trie = app(Trie::class); $trie = app(Trie::class);
if (!$trie->getTries()) {
return true;
}
$word = $trie->getSensitiveWords($trie->getTries(), $value, false); $word = $trie->getSensitiveWords($trie->getTries(), $value, false);
return !$word; return !$word;