Compare commits
74 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
ae53d4e404 | ||
![]() |
504054b68e | ||
![]() |
ceb5a396d8 | ||
![]() |
be91cfbc4f | ||
![]() |
898ffbc822 | ||
![]() |
f321a71677 | ||
![]() |
246d2caf44 | ||
![]() |
d020c99db3 | ||
![]() |
44b74d53d9 | ||
![]() |
4e170dbd17 | ||
![]() |
f7c8d65ea9 | ||
![]() |
5b6e34f3fe | ||
![]() |
b79b226a74 | ||
![]() |
6ba18dfad2 | ||
![]() |
6630058508 | ||
![]() |
0bbb39696b | ||
![]() |
7fd87caa36 | ||
![]() |
2125966684 | ||
![]() |
4180cb2565 | ||
![]() |
dffad1e2c4 | ||
![]() |
3d70495836 | ||
![]() |
6372ccd877 | ||
![]() |
2ad466e617 | ||
![]() |
5ce104e820 | ||
![]() |
f56cb943ff | ||
![]() |
2b96f3b650 | ||
![]() |
d4020b93a3 | ||
![]() |
2f25a0892e | ||
![]() |
114387d030 | ||
![]() |
e3ab44e6d3 | ||
![]() |
0d918c9446 | ||
![]() |
002ad814e5 | ||
![]() |
b4a1e9bc4e | ||
![]() |
822ff3874a | ||
![]() |
78ca9bebc4 | ||
![]() |
7b7f13536f | ||
![]() |
766a01e766 | ||
![]() |
3196292c85 | ||
![]() |
f45b9315a9 | ||
![]() |
c3b36013d7 | ||
![]() |
17491ca7da | ||
![]() |
d1423eb6e8 | ||
![]() |
c190672603 | ||
![]() |
ddf521b62b | ||
![]() |
50c8470d73 | ||
![]() |
e9179ee084 | ||
![]() |
adb7ff5a03 | ||
![]() |
706410480b | ||
![]() |
61ecd0629f | ||
![]() |
84c85c3d12 | ||
![]() |
d8496f9e62 | ||
![]() |
1495a4c731 | ||
![]() |
0efe79ddb3 | ||
![]() |
068234b57c | ||
![]() |
dc1ce92194 | ||
![]() |
937e1745d2 | ||
![]() |
9f6f02ad24 | ||
![]() |
340e8c356b | ||
![]() |
65d3111e65 | ||
![]() |
22a8574824 | ||
![]() |
584477f711 | ||
![]() |
2ae7efce04 | ||
![]() |
b12edc9439 | ||
![]() |
c02297ab91 | ||
![]() |
b2b6dbd5ed | ||
![]() |
3f154e5fb5 | ||
![]() |
cff7b38058 | ||
![]() |
849493eea2 | ||
![]() |
8cace712ae | ||
![]() |
b44c8838c4 | ||
![]() |
901c7f6cd7 | ||
![]() |
870e81ab9d | ||
![]() |
d4ec2d104f | ||
![]() |
614448d07a |
10
README.md
10
README.md
@@ -141,15 +141,19 @@ composer create-project jaguarjack/catchadmin:dev-master
|
||||
|
||||
### Donate
|
||||
如果你觉得项目对你有帮助,可以请作者喝杯咖啡☕️!鼓励下
|
||||
<!--<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
|
||||
- [论坛讨论](http://bbs.catchadmin.com)
|
||||
- 可以提 `ISSUE`,请按照 `issue` 模板提问
|
||||
- 加入 Q 群 `302266230` 暗号 `catchadmin`。
|
||||
- 加入 Q 群 `302266230` 前请先 star 项目支持一下, 备注填写用户名 + 平台。例如: JaguarJack Github
|
||||
|
||||
### Thanks
|
||||
> 排名部分先后
|
||||
- 感谢 [JetBrains](https://www.jetbrains.com) 提供生产力巨高的 `PHPStorm`和`WebStorm`
|
||||
> 排名不分先后
|
||||
|
||||
- [top-think/think](https://github.com/top-think/think)
|
||||
- [element-admin](https://panjiachen.gitee.io/vue-element-admin-site/zh/)
|
||||
|
BIN
catch/.DS_Store
vendored
BIN
catch/.DS_Store
vendored
Binary file not shown.
@@ -31,7 +31,7 @@ class DomainMenusSeed extends Seeder
|
||||
return array (
|
||||
0 =>
|
||||
array (
|
||||
'id' => 72,
|
||||
'id' => 82,
|
||||
'permission_name' => '域名管理',
|
||||
'parent_id' => 0,
|
||||
'level' => '',
|
||||
@@ -47,15 +47,16 @@ class DomainMenusSeed extends Seeder
|
||||
'hidden' => 1,
|
||||
'sort' => 1,
|
||||
'created_at' => 1601105834,
|
||||
'updated_at' => 1601105834,
|
||||
'updated_at' => 1612754299,
|
||||
'deleted_at' => 0,
|
||||
),
|
||||
1 =>
|
||||
'children' =>
|
||||
array (
|
||||
'id' => 73,
|
||||
0 =>
|
||||
array (
|
||||
'id' => 83,
|
||||
'permission_name' => '域名设置',
|
||||
'parent_id' => 72,
|
||||
'level' => '72',
|
||||
'parent_id' => 82,
|
||||
'level' => '82',
|
||||
'route' => '/domain/index',
|
||||
'icon' => 'el-icon-setting',
|
||||
'module' => 'domain',
|
||||
@@ -68,15 +69,15 @@ class DomainMenusSeed extends Seeder
|
||||
'hidden' => 1,
|
||||
'sort' => 8,
|
||||
'created_at' => 1601105879,
|
||||
'updated_at' => 1601112604,
|
||||
'updated_at' => 1612754299,
|
||||
'deleted_at' => 0,
|
||||
),
|
||||
2 =>
|
||||
1 =>
|
||||
array (
|
||||
'id' => 84,
|
||||
'permission_name' => '域名记录',
|
||||
'parent_id' => 72,
|
||||
'level' => '72',
|
||||
'parent_id' => 82,
|
||||
'level' => '82',
|
||||
'route' => '/domain/record/:domain',
|
||||
'icon' => 'el-icon-document',
|
||||
'module' => 'domain',
|
||||
@@ -89,9 +90,11 @@ class DomainMenusSeed extends Seeder
|
||||
'hidden' => 2,
|
||||
'sort' => 1,
|
||||
'created_at' => 1601112569,
|
||||
'updated_at' => 1601112606,
|
||||
'updated_at' => 1612754299,
|
||||
'deleted_at' => 0,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -8,6 +8,7 @@
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: JaguarJack [ njphper@gmail.com ]
|
||||
// +----------------------------------------------------------------------
|
||||
/* @var think\Route $router */
|
||||
|
||||
// you should use `$router`
|
||||
use catchAdmin\domain\controller\DomainRecord;
|
||||
|
@@ -1,4 +1,7 @@
|
||||
<?php
|
||||
|
||||
/* @var think\Route $router */
|
||||
|
||||
$router->group(function () use ($router){
|
||||
# 登入
|
||||
$router->post('login', '\catchAdmin\login\controller\Index@login');
|
||||
|
@@ -36,7 +36,7 @@ class CatchCrontabCommand extends Command
|
||||
->addOption('pid', '-p', Option::VALUE_REQUIRED, 'you can send signal to the process of pid')
|
||||
->addOption('static', '-s', Option::VALUE_REQUIRED, 'default static process number', 1)
|
||||
->addOption('dynamic', '-dy', Option::VALUE_REQUIRED, 'default dynamic process number', 10)
|
||||
->addOption('interval', '-i', Option::VALUE_REQUIRED, 'interval/seconds', 60)
|
||||
->addOption('interval', '-i', Option::VALUE_REQUIRED, 'interval/seconds', 5)
|
||||
->setDescription('start catch crontab schedule');
|
||||
}
|
||||
|
||||
|
128
catch/monitor/command/ScheduleCommand.php
Normal file
128
catch/monitor/command/ScheduleCommand.php
Normal file
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | CatchAdmin [Just Like ~ ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2017~{$year} http://catchadmin.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: JaguarJack [ njphper@gmail.com ]
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace catchAdmin\monitor\command;
|
||||
|
||||
use catchAdmin\monitor\command\process\Process;
|
||||
use catchAdmin\monitor\model\Crontab;
|
||||
use catchAdmin\monitor\model\CrontabLog;
|
||||
use Cron\CronExpression;
|
||||
use think\console\Command;
|
||||
use think\console\Input;
|
||||
use think\console\Output;
|
||||
use think\facade\Log;
|
||||
|
||||
class ScheduleCommand extends Command
|
||||
{
|
||||
protected $pid;
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
// 指令配置
|
||||
$this->setName('catch:schedule')
|
||||
->setDescription('catch schedule');
|
||||
}
|
||||
|
||||
protected function execute(Input $input, Output $output)
|
||||
{
|
||||
try {
|
||||
foreach ($this->getExecuteAbleCommands() as $command) {
|
||||
|
||||
$process = new Process(function (Process $process) use ($command) {
|
||||
$this->executeCommand($command);
|
||||
$process->exit();
|
||||
});
|
||||
|
||||
$process->start();
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
Log::error('CatchSchedule Error:' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行 command
|
||||
*
|
||||
* @time 2021年01月18日
|
||||
* @param $command
|
||||
* @return void
|
||||
*/
|
||||
protected function executeCommand($command)
|
||||
{
|
||||
$start = time();
|
||||
|
||||
$errorMessage = '';
|
||||
|
||||
try {
|
||||
$this->getConsole()->call($command->task);
|
||||
} catch (\Exception $e) {
|
||||
$errorMessage = $e->getMessage();
|
||||
}
|
||||
|
||||
$end = time();
|
||||
|
||||
// 插入 crontab 执行日志
|
||||
CrontabLog::insert([
|
||||
'crontab_id' => $command->id,
|
||||
'used_time' => $end - $start,
|
||||
'status' => $errorMessage ? CrontabLog::FAILED : CrontabLog::SUCCESS,
|
||||
'error_message' => $errorMessage,
|
||||
'created_at' => time(),
|
||||
'updated_at' => time(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取可执行任务
|
||||
*
|
||||
* @time 2021年01月17日
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
* @return array
|
||||
*/
|
||||
protected function getExecuteAbleCommands()
|
||||
{
|
||||
$executeAbleCommands = [];
|
||||
|
||||
|
||||
Crontab::where('status', Crontab::ENABLE)
|
||||
->select()
|
||||
->each(function ($command) use (&$executeAbleCommands){
|
||||
if ($command->tactics == Crontab::EXECUTE_IMMEDIATELY) {
|
||||
$executeAbleCommands[] = $command;
|
||||
$command->tactics = Crontab::EXECUTE_NORMAL;
|
||||
return $command->save();
|
||||
}
|
||||
|
||||
$can = date('Y-m-d H:i',
|
||||
(new CronExpression(trim($command->cron)))
|
||||
->getNextRunDate(date('Y-m-d H:i:s'), 0, true)
|
||||
->getTimestamp()) == date('Y-m-d H:i', time());
|
||||
|
||||
if ($can) {
|
||||
// 如果任务只执行一次 之后禁用该任务
|
||||
if ($command->tactics === Crontab::EXECUTE_ONCE) {
|
||||
$command->tactics = Crontab::DISABLE;
|
||||
$command->save();
|
||||
}
|
||||
|
||||
$executeAbleCommands[] = $command;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
return $executeAbleCommands;
|
||||
}
|
||||
}
|
@@ -121,7 +121,7 @@ trait Store
|
||||
{
|
||||
$pidFile = config('catch.crontab.master_pid_file');
|
||||
|
||||
if (!file_exists($pidFile)) {
|
||||
if (!FileSystem::exists($pidFile)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ trait Store
|
||||
*/
|
||||
public function renderStatus()
|
||||
{
|
||||
return file_get_contents(self::statusPath());
|
||||
return FileSystem::sharedGet(self::statusPath());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -47,7 +47,7 @@ class Crontab extends CatchController
|
||||
*/
|
||||
public function save(Request $request)
|
||||
{
|
||||
CronExpression::factory($request->post('cron'));
|
||||
new CronExpression($request->post('cron'));
|
||||
|
||||
return CatchResponse::success($this->model->storeBy($request->post()));
|
||||
}
|
||||
@@ -73,7 +73,7 @@ class Crontab extends CatchController
|
||||
*/
|
||||
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()));
|
||||
}
|
||||
|
@@ -34,7 +34,7 @@ class Crontab extends Migrator
|
||||
->addColumn('group', 'boolean', ['null' => false,'default' => 1,'signed' => false,'comment' => '1 默认 2 系统',])
|
||||
->addColumn('task', 'string', ['limit' => 255,'null' => false,'default' => '','signed' => false,'comment' => '任务名称',])
|
||||
->addColumn('cron', 'string', ['limit' => 50,'null' => false,'default' => '','signed' => false,'comment' => 'cron 表达式',])
|
||||
->addColumn('tactics', 'boolean', ['null' => false,'default' => 1,'signed' => false,'comment' => '1 立即执行 2 执行一次 3 放弃执行',])
|
||||
->addColumn('tactics', 'boolean', ['null' => false,'default' => 1,'signed' => false,'comment' => '1 立即执行 2 执行一次 3 正常执行',])
|
||||
->addColumn('status', 'boolean', ['null' => false,'default' => 1,'signed' => false,'comment' => '1 正常 2 禁用',])
|
||||
->addColumn('remark', 'string', ['limit' => 1000,'null' => false,'default' => '','signed' => false,'comment' => '备注',])
|
||||
->addColumn('creator_id', 'integer', ['limit' => MysqlAdapter::INT_REGULAR,'null' => false,'default' => 0,'signed' => true,'comment' => '创建人ID',])
|
||||
|
@@ -38,6 +38,5 @@ class Crontab extends Model
|
||||
|
||||
const EXECUTE_IMMEDIATELY = 1; // 立即执行
|
||||
const EXECUTE_ONCE = 2; // 执行一次
|
||||
const EXECUTE_FORBIDDEN = 3; // 停止执行
|
||||
|
||||
const EXECUTE_NORMAL = 3; // 正常执行
|
||||
}
|
@@ -47,7 +47,7 @@ class CrontabLog extends CatchModel
|
||||
return $this->catchLeftJoin(Crontab::class, 'id', 'crontab_id', ['name', 'group', 'task'])
|
||||
->catchSearch()
|
||||
->catchOrder()
|
||||
->field(['used_time', 'error_message', 'crontab_log.status', 'crontab_log.id', 'crontab_log.created_at'])
|
||||
->field(['used_time', 'error_message', $this->aliasField('status'), $this->aliasField('id'), $this->aliasField('created_at')])
|
||||
->paginate();
|
||||
}
|
||||
}
|
@@ -19,6 +19,6 @@ trait CrontabSearch
|
||||
|
||||
public function searchStatusAttr($query, $value, $data)
|
||||
{
|
||||
return $query->whereLike('status', $value);
|
||||
return $query->where('status', $value);
|
||||
}
|
||||
}
|
||||
|
@@ -9,6 +9,8 @@
|
||||
// | Author: JaguarJack [ njphper@gmail.com ]
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
/* @var think\Route $router */
|
||||
|
||||
// you should use `$router`
|
||||
$router->group('monitor', function () use ($router){
|
||||
// crontab路由
|
||||
@@ -16,7 +18,7 @@ $router->group('monitor', function () use ($router){
|
||||
$router->put('crontab/enable/<id>', '\catchAdmin\monitor\controller\Crontab@disOrEnable');
|
||||
|
||||
// crontab 日志
|
||||
$router->get('crontab/log', '\catchAdmin\monitor\controller\CrontabLog@index');
|
||||
$router->delete('crontab/log/<id>', '\catchAdmin\monitor\controller\CrontabLog@delete');
|
||||
$router->get('crontab/log/list', '\catchAdmin\monitor\controller\CrontabLog@index');
|
||||
$router->delete('crontab/log/list/<id>', '\catchAdmin\monitor\controller\CrontabLog@delete');
|
||||
|
||||
})->middleware('auth');
|
@@ -100,6 +100,7 @@ class Permission extends CatchController
|
||||
$permission = $this->permissions->findBy($id);
|
||||
|
||||
$params = $request->param();
|
||||
|
||||
// 按钮类型
|
||||
if ($params['type'] == Permissions::BTN_TYPE && $permission->parent_id) {
|
||||
$parentPermission = $this->permissions->findBy($permission->parent_id);
|
||||
@@ -175,33 +176,7 @@ class Permission extends CatchController
|
||||
*/
|
||||
public function show($id)
|
||||
{
|
||||
$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([]);
|
||||
}
|
||||
return CatchResponse::success($this->permissions->show($id));
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,13 +1,11 @@
|
||||
<?php
|
||||
namespace catchAdmin\permissions\controller;
|
||||
|
||||
use catchAdmin\permissions\model\Permissions;
|
||||
use catchAdmin\permissions\model\Roles;
|
||||
use catcher\base\CatchRequest as Request;
|
||||
use catcher\base\CatchController;
|
||||
use catcher\CatchResponse;
|
||||
use catcher\exceptions\FailedException;
|
||||
use catcher\Tree;
|
||||
use think\response\Json;
|
||||
use catchAdmin\permissions\model\Roles as RoleModel;
|
||||
|
||||
@@ -23,7 +21,7 @@ class Role extends CatchController
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月09日
|
||||
* @return string
|
||||
* @return string|Json
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
@@ -46,11 +44,14 @@ class Role extends CatchController
|
||||
}
|
||||
|
||||
$this->role->storeBy($params);
|
||||
$permissions = $params['permissions'];
|
||||
if (!empty($permissions)) {
|
||||
$this->role->attachPermissions(array_unique($permissions));
|
||||
// 分配权限
|
||||
if (count($params['permissions'])) {
|
||||
$this->role->attachPermissions(array_unique($params['permissions']));
|
||||
}
|
||||
// 分配部门
|
||||
if (isset($params['departments']) && count($params['departments'])) {
|
||||
$this->role->attachDepartments($params['departments']);
|
||||
}
|
||||
|
||||
// 添加角色
|
||||
return CatchResponse::success();
|
||||
}
|
||||
@@ -59,6 +60,7 @@ class Role extends CatchController
|
||||
{
|
||||
$role = $this->role->findBy($id);
|
||||
$role->permissions = $role->getPermissions();
|
||||
$role->departments = $role->getDepartments();
|
||||
return CatchResponse::success($role);
|
||||
}
|
||||
|
||||
@@ -101,6 +103,28 @@ class Role extends CatchController
|
||||
$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();
|
||||
}
|
||||
|
||||
@@ -122,6 +146,8 @@ class Role extends CatchController
|
||||
$role = $this->role->findBy($id);
|
||||
// 删除权限
|
||||
$role->detachPermissions();
|
||||
// 删除部门关联
|
||||
$role->detachDepartments();
|
||||
// 删除用户关联
|
||||
$role->users()->detach();
|
||||
// 删除
|
||||
@@ -129,37 +155,4 @@ class Role extends CatchController
|
||||
|
||||
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,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
@@ -110,7 +110,7 @@ class User extends CatchController
|
||||
*/
|
||||
public function update($id, UpdateRequest $request)
|
||||
{
|
||||
$this->user->updateBy($id, $request->param());
|
||||
$this->user->updateBy($id, $request->filterEmptyField()->param());
|
||||
|
||||
$user = $this->user->findBy($id);
|
||||
|
||||
@@ -171,51 +171,6 @@ class User extends CatchController
|
||||
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)
|
||||
{
|
||||
return CatchResponse::success($this->user->updateBy($request->user()->id, $request->param()));
|
||||
return CatchResponse::success($this->user->updateBy($request->user()->id, $request->filterEmptyField()->param()));
|
||||
}
|
||||
}
|
||||
|
@@ -87,12 +87,18 @@ class Permissions extends CatchModel
|
||||
*/
|
||||
public static function onAfterInsert(Model $model)
|
||||
{
|
||||
$restful = intval($model->getData('restful'));
|
||||
|
||||
$model = self::where('id', $model->id)->find();
|
||||
|
||||
if ($model && $model->parent_id) {
|
||||
$parent = self::where('id', $model->parent_id)->find();
|
||||
|
||||
$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
|
||||
]);
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
$permission = $this->findBy($id);
|
||||
|
@@ -35,8 +35,18 @@ class Roles extends CatchModel
|
||||
public function getList()
|
||||
{
|
||||
return $this->catchSearch()
|
||||
->with(['permissions', 'departments'])
|
||||
->order('id', 'desc')
|
||||
->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();
|
||||
}
|
||||
|
||||
|
@@ -5,6 +5,7 @@ use catchAdmin\permissions\model\search\UserSearch;
|
||||
use catcher\base\CatchModel;
|
||||
use catcher\exceptions\FailedException;
|
||||
use catcher\Utils;
|
||||
use think\Paginator;
|
||||
|
||||
class Users extends CatchModel
|
||||
{
|
||||
@@ -47,16 +48,25 @@ class Users extends CatchModel
|
||||
* 用户列表
|
||||
*
|
||||
* @time 2019年12月08日
|
||||
* @return array|\think\Paginator
|
||||
*@throws \think\db\exception\DbException
|
||||
* @return \think\Paginator
|
||||
*/
|
||||
public function getList(): \think\Paginator
|
||||
public function getList()
|
||||
{
|
||||
return $this->withoutField(['updated_at'], true)
|
||||
$users = $this->withoutField(['updated_at', 'password', 'remember_token'], true)
|
||||
->catchSearch()
|
||||
->catchLeftJoin(Department::class, 'id', 'department_id', ['department_name'])
|
||||
->with(['jobs', 'roles'])
|
||||
->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']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -1,14 +1,13 @@
|
||||
<?php
|
||||
|
||||
/* @var think\Route $router */
|
||||
|
||||
$router->group(function () use ($router){
|
||||
// 角色
|
||||
$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->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');
|
||||
// 所有职位
|
||||
@@ -19,9 +18,7 @@ $router->group(function () use ($router){
|
||||
$router->resource('users', '\catchAdmin\permissions\controller\User');
|
||||
// 切换状态
|
||||
$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->get('users/get/roles', '\catchAdmin\permissions\controller\User@getRoles');
|
||||
$router->get('user/info', '\catchAdmin\permissions\controller\User@info');
|
||||
$router->get('user/export', '\catchAdmin\permissions\controller\User@export');
|
||||
})->middleware('auth');
|
50
catch/permissions/tables/Department.php
Normal file
50
catch/permissions/tables/Department.php
Normal 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');
|
||||
}
|
||||
}
|
44
catch/permissions/tables/Job.php
Normal file
44
catch/permissions/tables/Job.php
Normal 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');
|
||||
}
|
||||
}
|
50
catch/permissions/tables/Permission.php
Normal file
50
catch/permissions/tables/Permission.php
Normal 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');
|
||||
}
|
||||
}
|
43
catch/permissions/tables/Role.php
Normal file
43
catch/permissions/tables/Role.php
Normal 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');
|
||||
}
|
||||
}
|
54
catch/permissions/tables/User.php
Normal file
54
catch/permissions/tables/User.php
Normal 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');
|
||||
}
|
||||
}
|
32
catch/permissions/tables/forms/Department.php
Normal file
32
catch/permissions/tables/forms/Department.php
Normal 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),
|
||||
];
|
||||
}
|
||||
}
|
12
catch/permissions/tables/forms/Factory.php
Normal file
12
catch/permissions/tables/forms/Factory.php
Normal 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__;
|
||||
}
|
||||
}
|
23
catch/permissions/tables/forms/Job.php
Normal file
23
catch/permissions/tables/forms/Job.php
Normal 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),
|
||||
];
|
||||
}
|
||||
}
|
155
catch/permissions/tables/forms/Permission.php
Normal file
155
catch/permissions/tables/forms/Permission.php
Normal 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();
|
||||
}
|
||||
}
|
66
catch/permissions/tables/forms/Role.php
Normal file
66
catch/permissions/tables/forms/Role.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<?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('全部数据权限', 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%']),
|
||||
])
|
||||
];
|
||||
}
|
||||
|
||||
}
|
42
catch/permissions/tables/forms/User.php
Normal file
42
catch/permissions/tables/forms/User.php
Normal 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(),
|
||||
];
|
||||
}
|
||||
|
||||
}
|
@@ -9,6 +9,8 @@
|
||||
// | Author: JaguarJack [ njphper@gmail.com ]
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
/* @var think\Route $router */
|
||||
|
||||
// you should use `$router`
|
||||
$router->group('sms', function () use ($router){
|
||||
// config路由
|
||||
|
@@ -4,8 +4,6 @@ namespace catchAdmin\system\controller;
|
||||
use catcher\base\CatchController;
|
||||
use catcher\CatchResponse;
|
||||
use catchAdmin\system\model\Attachments as AttachmentsModel;
|
||||
use catcher\Utils;
|
||||
use catcher\facade\FileSystem;
|
||||
|
||||
class Attachments extends CatchController
|
||||
{
|
||||
@@ -35,22 +33,6 @@ class Attachments extends CatchController
|
||||
*/
|
||||
public function delete($id, AttachmentsModel $model)
|
||||
{
|
||||
$attachments = $model->whereIn('id', Utils::stringToArrayBy($id))->select();
|
||||
|
||||
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();
|
||||
return CatchResponse::success($model->deletes($id));
|
||||
}
|
||||
}
|
||||
|
@@ -17,12 +17,12 @@ class Module extends CatchController
|
||||
*
|
||||
* @return Json
|
||||
*/
|
||||
public function index()
|
||||
public function index(): Json
|
||||
{
|
||||
$modules = [];
|
||||
|
||||
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'));
|
||||
@@ -51,7 +51,7 @@ class Module extends CatchController
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
*/
|
||||
public function disOrEnable(string $module)
|
||||
public function disOrEnable(string $module): Json
|
||||
{
|
||||
$moduleInfo = CatchAdmin::getModuleInfo(CatchAdmin::directory() . $module);
|
||||
|
||||
@@ -71,7 +71,7 @@ class Module extends CatchController
|
||||
* @time 2020年09月21日
|
||||
* @return Json
|
||||
*/
|
||||
public function cache()
|
||||
public function cache(): Json
|
||||
{
|
||||
return CatchResponse::success(CatchAdmin::cacheServices());
|
||||
}
|
||||
@@ -82,7 +82,7 @@ class Module extends CatchController
|
||||
* @time 2020年09月21日
|
||||
* @return Json
|
||||
*/
|
||||
public function clear()
|
||||
public function clear(): Json
|
||||
{
|
||||
return !file_exists(CatchAdmin::getCacheServicesFile()) ?
|
||||
CatchResponse::fail('模块没有缓存') :
|
||||
|
@@ -746,28 +746,7 @@ class SystemMenusSeed extends Seeder
|
||||
'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,
|
||||
),
|
||||
)
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@@ -3,8 +3,10 @@ namespace catchAdmin\system\model;
|
||||
|
||||
use catchAdmin\system\model\search\AttachmentsSearch;
|
||||
use catcher\base\CatchModel;
|
||||
use catcher\Utils;
|
||||
use think\file\UploadedFile;
|
||||
use think\Model;
|
||||
use think\facade\Filesystem;
|
||||
|
||||
class Attachments extends CatchModel
|
||||
{
|
||||
@@ -54,4 +56,37 @@ class Attachments extends CatchModel
|
||||
'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;
|
||||
}
|
||||
}
|
||||
|
@@ -66,7 +66,6 @@ class Config extends CatchModel
|
||||
$config = [];
|
||||
foreach ($data as $key => $item) {
|
||||
foreach ($item as $k => $value) {
|
||||
if ($value) {
|
||||
$config[$key . '.' .$k] = [
|
||||
'pid' => $parentConfig['id'],
|
||||
'key' => $key . '.' . $k,
|
||||
@@ -76,7 +75,6 @@ class Config extends CatchModel
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->where('pid', $parentConfig->id)
|
||||
->select()
|
||||
|
@@ -11,7 +11,6 @@ class OperateLog extends \think\Model
|
||||
use BaseOptionsTrait;
|
||||
use OperateLogSearch;
|
||||
|
||||
|
||||
protected $name = 'operate_log';
|
||||
|
||||
protected $field = [
|
||||
@@ -42,4 +41,9 @@ class OperateLog extends \think\Model
|
||||
->order($this->aliasField('id'), 'desc')
|
||||
->paginate();
|
||||
}
|
||||
|
||||
protected function getCreatedAtAttr($value)
|
||||
{
|
||||
return date('Y-m-d H:i:s', $value);
|
||||
}
|
||||
}
|
||||
|
@@ -24,6 +24,6 @@ trait DeveloperSearch
|
||||
|
||||
public function searchStatusAttr($query, $value, $data)
|
||||
{
|
||||
return $query->where('driver', $value);
|
||||
return $query->where('status', $value);
|
||||
}
|
||||
}
|
@@ -1,4 +1,7 @@
|
||||
<?php
|
||||
|
||||
/* @var think\Route $router */
|
||||
|
||||
$router->group(function () use ($router) {
|
||||
// 登录日志
|
||||
$router->get('log/login', '\catchAdmin\system\controller\LoginLog@list');
|
||||
@@ -15,8 +18,10 @@ $router->group(function () use ($router) {
|
||||
$router->post('table/backup', '\catchAdmin\system\controller\DataDictionary@backup');
|
||||
|
||||
// 上传
|
||||
$router->post('upload/image', '\catchAdmin\system\controller\Upload@image');
|
||||
$router->post('upload/file', '\catchAdmin\system\controller\Upload@file');
|
||||
$router->group('upload', function () use ($router){
|
||||
$router->post('image', '\catchAdmin\system\controller\Upload@image');
|
||||
$router->post('file', '\catchAdmin\system\controller\Upload@file');
|
||||
})->middleware(\catcher\middlewares\JsonResponseMiddleware::class);
|
||||
|
||||
// 附件
|
||||
$router->resource('attachments', '\catchAdmin\system\controller\Attachments');
|
||||
@@ -43,7 +48,13 @@ $router->group(function () use ($router) {
|
||||
$router->put('modules/<module>', '\catchAdmin\system\controller\Module@disOrEnable');
|
||||
$router->put('cache/modules', '\catchAdmin\system\controller\Module@cache');
|
||||
$router->delete('clear/modules', '\catchAdmin\system\controller\Module@clear');
|
||||
|
||||
})->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'));
|
||||
});
|
||||
|
||||
|
||||
|
46
catch/system/tables/Database.php
Normal file
46
catch/system/tables/Database.php
Normal 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();
|
||||
}
|
||||
}
|
40
catch/system/tables/LoginLog.php
Normal file
40
catch/system/tables/LoginLog.php
Normal 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();
|
||||
|
||||
}
|
||||
}
|
46
catch/system/tables/OperateLog.php
Normal file
46
catch/system/tables/OperateLog.php
Normal 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();
|
||||
|
||||
}
|
||||
}
|
45
catch/system/tables/SensitiveWord.php
Normal file
45
catch/system/tables/SensitiveWord.php
Normal 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();
|
||||
}
|
||||
}
|
12
catch/system/tables/forms/Factory.php
Normal file
12
catch/system/tables/forms/Factory.php
Normal 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__;
|
||||
}
|
||||
}
|
15
catch/system/tables/forms/SensitiveWord.php
Normal file
15
catch/system/tables/forms/SensitiveWord.php
Normal 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('请输入敏感词'),
|
||||
];
|
||||
}
|
||||
}
|
@@ -9,6 +9,8 @@
|
||||
* @license https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt
|
||||
*/
|
||||
|
||||
/* @var think\Route $router */
|
||||
|
||||
$router->group('wechat', function () use ($router){
|
||||
// 公众号粉丝
|
||||
$router->group('official/users', function () use ($router){
|
||||
|
@@ -18,19 +18,21 @@
|
||||
],
|
||||
"require": {
|
||||
"php": ">=7.1.0",
|
||||
"topthink/framework": "6.0.5",
|
||||
"topthink/think-orm": "2.0.33",
|
||||
"topthink/framework": "6.0.6",
|
||||
"topthink/think-orm": "2.0.36",
|
||||
"topthink/think-migration": "^3.0",
|
||||
"thans/tp-jwt-auth": "1.1",
|
||||
"jaguarjack/think-filesystem-cloud": "dev-master",
|
||||
"thans/tp-jwt-auth": "^1.1",
|
||||
"overtrue/wechat": "^4.2",
|
||||
"phpoffice/phpspreadsheet": "^1.12",
|
||||
"dragonmantank/cron-expression": "^3.0",
|
||||
"dragonmantank/cron-expression": "3.1",
|
||||
"symfony/finder": "^4.4",
|
||||
"ext-json": "*",
|
||||
"overtrue/easy-sms": "^1.1",
|
||||
"jaguarjack/migration-generator": "dev-master",
|
||||
"lcobucci/jwt": "3.3"
|
||||
"lcobucci/jwt": "3.3",
|
||||
"jaguarjack/think-filesystem-cloud": "1.0",
|
||||
"topthink/think-view": "^1.0",
|
||||
"xaboy/form-builder": "~2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"topthink/think-trace": "^1.0",
|
||||
|
@@ -49,7 +49,7 @@ return [
|
||||
// 是否严格检查字段是否存在
|
||||
'fields_strict' => true,
|
||||
// 是否需要断线重连
|
||||
'break_reconnect' => false,
|
||||
'break_reconnect' => true,
|
||||
// 监听SQL
|
||||
'trigger_sql' => true,
|
||||
// 开启字段缓存
|
||||
|
@@ -3,13 +3,13 @@ declare(strict_types=1);
|
||||
|
||||
namespace catcher;
|
||||
|
||||
use think\helper\Arr;
|
||||
use catcher\facade\FileSystem;
|
||||
|
||||
class CatchAdmin
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 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日
|
||||
* @return array
|
||||
*/
|
||||
public static function getEnabledService()
|
||||
public static function getEnabledService(): array
|
||||
{
|
||||
$services = [];
|
||||
|
||||
@@ -211,96 +225,70 @@ class CatchAdmin
|
||||
}
|
||||
|
||||
/**
|
||||
* 开启模块
|
||||
* 获取模块 Json
|
||||
*
|
||||
* @time 2020年06月23日
|
||||
* @time 2021年02月08日
|
||||
* @param $module
|
||||
* @return bool
|
||||
* @return string
|
||||
*/
|
||||
public static function enableModule($module)
|
||||
public static function getModuleJson($module): string
|
||||
{
|
||||
$moduleJson = self::moduleDirectory($module) . 'module.json';
|
||||
|
||||
if (!file_exists($moduleJson)) {
|
||||
return true;
|
||||
if (is_dir($module)) {
|
||||
return $module . DIRECTORY_SEPARATOR . 'module.json';
|
||||
}
|
||||
|
||||
$info = \json_decode(file_get_contents($moduleJson), true);
|
||||
|
||||
$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;
|
||||
return self::moduleDirectory($module) . 'module.json';
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取模块信息
|
||||
*
|
||||
* @time 2019年11月30日
|
||||
* @time 2021年02月08日
|
||||
* @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')) {
|
||||
return \json_decode(file_get_contents($module. DIRECTORY_SEPARATOR . 'module.json'), true);
|
||||
}
|
||||
$moduleJson = self::getModuleJson($module);
|
||||
|
||||
if (!file_exists($moduleJson)) {
|
||||
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日
|
||||
* @return mixed
|
||||
*/
|
||||
public static function getRoutes()
|
||||
public static function getRoutes(): array
|
||||
{
|
||||
if (file_exists(self::getCacheRoutesFile())) {
|
||||
return [self::getCacheRoutesFile()];
|
||||
@@ -330,19 +318,6 @@ class CatchAdmin
|
||||
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) . ';');
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @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日
|
||||
@@ -420,22 +374,13 @@ class CatchAdmin
|
||||
{
|
||||
return include self::getCacheServicesFile();
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @time 2019年11月30日
|
||||
* @return mixed
|
||||
*/
|
||||
protected static function getCacheViewsFile()
|
||||
{
|
||||
return self::cacheDirectory() . 'views.php';
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年11月30日
|
||||
* @return mixed
|
||||
*/
|
||||
public static function getCacheServicesFile()
|
||||
public static function getCacheServicesFile(): string
|
||||
{
|
||||
return self::cacheDirectory() . 'services.php';
|
||||
}
|
||||
|
@@ -50,7 +50,7 @@ class CatchAdminService extends Service
|
||||
|
||||
$this->app->bind('catch\console', $catchConsole);
|
||||
|
||||
$this->commands($catchConsole->commands());
|
||||
$this->commands($catchConsole->defaultCommands());
|
||||
}
|
||||
}
|
||||
/**
|
||||
@@ -103,7 +103,10 @@ class CatchAdminService extends Service
|
||||
{
|
||||
$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([
|
||||
'connections' => $connections
|
||||
|
@@ -8,22 +8,33 @@ use catcher\exceptions\FailedException;
|
||||
use catcher\exceptions\LoginFailedException;
|
||||
use thans\jwt\facade\JWTAuth;
|
||||
use think\facade\Session;
|
||||
use think\helper\Str;
|
||||
|
||||
class CatchAuth
|
||||
{
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
protected $auth;
|
||||
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
protected $guard;
|
||||
|
||||
// 默认获取
|
||||
protected $username = 'email';
|
||||
|
||||
// 校验字段
|
||||
protected $password = 'password';
|
||||
|
||||
// 保存用户信息
|
||||
protected $user = [];
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $checkPassword = true;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->auth = config('catch.auth');
|
||||
@@ -53,8 +64,8 @@ class CatchAuth
|
||||
*/
|
||||
public function attempt($condition)
|
||||
{
|
||||
try {
|
||||
$user = $this->authenticate($condition);
|
||||
|
||||
if (!$user) {
|
||||
throw new LoginFailedException();
|
||||
}
|
||||
@@ -62,15 +73,11 @@ class CatchAuth
|
||||
throw new LoginFailedException('该用户已被禁用|' . $user->username, Code::USER_FORBIDDEN);
|
||||
}
|
||||
|
||||
if (!password_verify($condition['password'], $user->password)) {
|
||||
if ($this->checkPassword && !password_verify($condition['password'], $user->password)) {
|
||||
throw new LoginFailedException('登录失败|' . $user->username);
|
||||
}
|
||||
|
||||
return $this->{$this->getDriver()}($user);
|
||||
|
||||
} catch (\Exception $exception) {
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -236,8 +243,10 @@ class CatchAuth
|
||||
{
|
||||
$where = [];
|
||||
|
||||
$fields = array_keys(app($this->getProvider()['model'])->getFields());
|
||||
|
||||
foreach ($condition as $field => $value) {
|
||||
if ($field != $this->password) {
|
||||
if (in_array($field, $fields) && $field != $this->password) {
|
||||
$where[$field] = $value;
|
||||
}
|
||||
}
|
||||
@@ -270,4 +279,17 @@ class CatchAuth
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 忽略密码认证
|
||||
*
|
||||
* @time 2021年01月27日
|
||||
* @return $this
|
||||
*/
|
||||
public function ignorePasswordVerify(): CatchAuth
|
||||
{
|
||||
$this->checkPassword = false;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
@@ -14,9 +14,7 @@ namespace catcher;
|
||||
|
||||
use catcher\library\Composer;
|
||||
use catcher\facade\FileSystem;
|
||||
use Symfony\Component\Finder\SplFileInfo;
|
||||
use think\App;
|
||||
use think\console\Command;
|
||||
|
||||
class CatchConsole
|
||||
{
|
||||
@@ -37,7 +35,7 @@ class CatchConsole
|
||||
* @time 2020年07月02日
|
||||
* @return array
|
||||
*/
|
||||
public function commands()
|
||||
public function commands(): array
|
||||
{
|
||||
$commandFiles = FileSystem::allFiles($this->path);
|
||||
|
||||
@@ -62,20 +60,23 @@ class CatchConsole
|
||||
* @time 2020年07月19日
|
||||
* @return string
|
||||
*/
|
||||
protected function parseNamespace()
|
||||
protected function parseNamespace(): string
|
||||
{
|
||||
// 没有设置 namespace 默认使用 extend 目录
|
||||
if (!$this->namespace) {
|
||||
return root_path(). 'extend';
|
||||
$psr4 = (new Composer)->psr4Autoload();
|
||||
|
||||
if (strpos($this->namespace, '\\') === false) {
|
||||
$rootNamespace = $this->namespace . '\\';
|
||||
} else {
|
||||
$rootNamespace = substr($this->namespace, 0, strpos($this->namespace, '\\') + 1);
|
||||
}
|
||||
|
||||
$psr4 = (new Composer())->psr4Autoload();
|
||||
$path = root_path(). $psr4[$rootNamespace] . DIRECTORY_SEPARATOR;
|
||||
|
||||
$rootNamespace = substr($this->namespace, 0, strpos($this->namespace, '\\') + 1);
|
||||
if (strpos($this->namespace, '\\') !== false) {
|
||||
$path .= str_replace('\\', DIRECTORY_SEPARATOR, substr($this->namespace, strpos($this->namespace, '\\') + 1));
|
||||
}
|
||||
|
||||
return root_path(). $psr4[$rootNamespace] . DIRECTORY_SEPARATOR .
|
||||
|
||||
str_replace('\\', DIRECTORY_SEPARATOR, substr($this->namespace, strpos($this->namespace, '\\') + 1));
|
||||
return rtrim($path, '/');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -85,7 +86,7 @@ class CatchConsole
|
||||
* @param $path
|
||||
* @return $this
|
||||
*/
|
||||
public function path($path)
|
||||
public function path($path): CatchConsole
|
||||
{
|
||||
$this->path = $path;
|
||||
|
||||
@@ -99,11 +100,40 @@ class CatchConsole
|
||||
* @param $namespace
|
||||
* @return $this
|
||||
*/
|
||||
public function setNamespace($namespace)
|
||||
public function setNamespace($namespace): CatchConsole
|
||||
{
|
||||
$this->namespace = $namespace;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 默认 commands
|
||||
*
|
||||
* @time 2021年01月24日
|
||||
* @return array
|
||||
*/
|
||||
public function defaultCommands(): array
|
||||
{
|
||||
$defaultCommands = FileSystem::allFiles(__DIR__ . DIRECTORY_SEPARATOR . 'command');
|
||||
|
||||
$commands = [];
|
||||
|
||||
/* \Symfony\Component\Finder\SplFileInfo $command */
|
||||
foreach ($defaultCommands as $command) {
|
||||
if ($command->getExtension() === 'php') {
|
||||
|
||||
$filename = str_replace('.php', '', str_replace(__DIR__, '', $command->getPathname()));
|
||||
|
||||
$class = 'catcher' . str_replace(DIRECTORY_SEPARATOR, '\\', $filename);
|
||||
|
||||
if (class_exists($class)) {
|
||||
$commands[] = $class;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $commands;
|
||||
}
|
||||
|
||||
}
|
@@ -3,7 +3,6 @@ declare(strict_types=1);
|
||||
|
||||
namespace catcher;
|
||||
|
||||
use app\ExceptionHandle;
|
||||
use catcher\exceptions\CatchException;
|
||||
use catcher\exceptions\FailedException;
|
||||
use think\db\exception\DataNotFoundException;
|
||||
|
@@ -6,6 +6,7 @@ namespace catcher;
|
||||
use catcher\library\excel\Excel;
|
||||
use catcher\library\excel\ExcelContract;
|
||||
use think\facade\Cache;
|
||||
use think\helper\Str;
|
||||
use think\model\Collection;
|
||||
|
||||
class CatchModelCollection extends Collection
|
||||
@@ -19,9 +20,9 @@ class CatchModelCollection extends Collection
|
||||
* @param string $children
|
||||
* @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
|
||||
* @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
|
||||
{
|
||||
@@ -80,7 +81,7 @@ class CatchModelCollection extends Collection
|
||||
* @return bool
|
||||
* @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);
|
||||
}
|
||||
@@ -94,18 +95,31 @@ class CatchModelCollection extends Collection
|
||||
* @param string $column
|
||||
* @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){
|
||||
$item = intval($item);
|
||||
});
|
||||
|
||||
$childDepartmentIds = $this->whereIn($parentFields, $ids)->column($column);
|
||||
$childIds = $this->whereIn($parentFields, $ids)->column($column);
|
||||
|
||||
if (!empty($childDepartmentIds)) {
|
||||
$childDepartmentIds = array_merge($childDepartmentIds, $this->getAllChildrenIds($childDepartmentIds));
|
||||
if (!empty($childIds)) {
|
||||
$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);
|
||||
}
|
||||
}
|
@@ -138,6 +138,60 @@ class CatchQuery extends Query
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 快速搜索
|
||||
*
|
||||
* @param array $params
|
||||
* @return Query
|
||||
*/
|
||||
public function quickSearch($params = []): Query
|
||||
{
|
||||
$requestParams = \request()->param();
|
||||
|
||||
if (empty($params) && empty($requestParams)) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
foreach ($requestParams as $field => $value) {
|
||||
if (isset($params[$field])) {
|
||||
// ['>', value] || value
|
||||
if (is_array($params[$field])) {
|
||||
$this->where($field, $params[$field][0], $params[$field][1]);
|
||||
} else {
|
||||
$this->where($field, $value);
|
||||
}
|
||||
} else {
|
||||
// 区间范围 start_数据库字段 & end_数据库字段
|
||||
$startPos = strpos($field, 'start_');
|
||||
if ($startPos === 0) {
|
||||
$this->where(str_replace('start_','', $field), '>=', strtotime($value));
|
||||
}
|
||||
$endPos = strpos($field, 'end_');
|
||||
if ($endPos === 0) {
|
||||
$this->where(str_replace('end_', '', $field), '>=', strtotime($value));
|
||||
}
|
||||
// 模糊搜索
|
||||
if (Str::contains($field, 'like')) {
|
||||
[$operate, $field] = explode('_', $field);
|
||||
if ($operate === 'like') {
|
||||
$this->whereLike($field, $value);
|
||||
} else if ($operate === '%like') {
|
||||
$this->whereLeftLike($field, $value);
|
||||
} else {
|
||||
$this->whereRightLike($field, $value);
|
||||
}
|
||||
}
|
||||
|
||||
// = 值搜索
|
||||
if ($value || is_numeric($value)) {
|
||||
$this->where($field, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2020年01月13日
|
||||
@@ -178,6 +232,28 @@ class CatchQuery extends Query
|
||||
return parent::whereLike($field, $condition, $logic);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $field
|
||||
* @param $condition
|
||||
* @param string $logic
|
||||
* @return Query
|
||||
*/
|
||||
public function whereLeftLike(string $field, $condition, string $logic = 'AND'): Query
|
||||
{
|
||||
return $this->where($field, $condition, $logic, 'left');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $field
|
||||
* @param $condition
|
||||
* @param string $logic
|
||||
* @return Query
|
||||
*/
|
||||
public function whereRightLike(string $field, $condition, string $logic = 'AND'): Query
|
||||
{
|
||||
return $this->where($field, $condition, $logic, 'right');
|
||||
}
|
||||
|
||||
/**
|
||||
* 额外的字段
|
||||
*
|
||||
@@ -223,6 +299,10 @@ class CatchQuery extends Query
|
||||
$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);
|
||||
|
||||
return $this;
|
||||
|
45
extend/catcher/CatchTable.php
Normal file
45
extend/catcher/CatchTable.php
Normal 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);
|
||||
}
|
||||
}
|
@@ -47,11 +47,6 @@ class CatchUpload
|
||||
*/
|
||||
protected $path = '';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->initDriver();
|
||||
}
|
||||
|
||||
/**
|
||||
* upload files
|
||||
*
|
||||
@@ -63,6 +58,7 @@ class CatchUpload
|
||||
*/
|
||||
public function upload(UploadedFile $file): string
|
||||
{
|
||||
try {
|
||||
$this->initUploadConfig();
|
||||
|
||||
$path = Filesystem::disk($this->getDriver())->putFile($this->getPath(), $file);
|
||||
@@ -82,6 +78,10 @@ class CatchUpload
|
||||
}
|
||||
|
||||
throw new FailedException('Upload Failed, Try Again!');
|
||||
|
||||
} catch (\Exception $exception) {
|
||||
throw new FailedException($exception->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -254,70 +254,9 @@ class CatchUpload
|
||||
* @time 2020年06月01日
|
||||
* @return void
|
||||
*/
|
||||
protected function initUploadConfig()
|
||||
public function initUploadConfig()
|
||||
{
|
||||
$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;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 重新分配配置
|
||||
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;
|
||||
Utils::setFilesystemConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -336,11 +275,27 @@ class CatchUpload
|
||||
case CatchUpload::LOCAL:
|
||||
return $driver['domain'];
|
||||
case CatchUpload::OSS:
|
||||
return $driver['end_point'];
|
||||
return self::getOssDomain();
|
||||
case CatchUpload::QCLOUD:
|
||||
return $driver['cdn'];
|
||||
default:
|
||||
throw new FailedException(sprintf('Driver [%s] Not Supported.', $driver));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 OSS Domain
|
||||
*
|
||||
* @time 2021年01月20日
|
||||
* @return mixed|string
|
||||
*/
|
||||
protected static function getOssDomain(): string
|
||||
{
|
||||
$oss = \config('filesystem.disks.oss');
|
||||
if ($oss['is_cname'] === false) {
|
||||
return 'https://' . $oss['bucket'] . '.' . $oss['end_point'];
|
||||
}
|
||||
|
||||
return $oss['end_point'];
|
||||
}
|
||||
}
|
@@ -136,6 +136,10 @@ class Utils
|
||||
|
||||
$docComment = (new \ReflectionClass($controller))->getMethod($action)->getDocComment();
|
||||
|
||||
if (! $docComment) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return strpos($docComment, config('catch.permissions.method_auth_mark')) !== false;
|
||||
}
|
||||
|
||||
@@ -152,7 +156,7 @@ class Utils
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除前缀
|
||||
* 删除表前缀
|
||||
*
|
||||
* @time 2020年12月01日
|
||||
* @param string $table
|
||||
@@ -163,6 +167,19 @@ class Utils
|
||||
return str_replace(self::tablePrefix(), '', $table);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加表前缀
|
||||
*
|
||||
* @time 2020年12月26日
|
||||
* @param string $table
|
||||
* @return string
|
||||
*/
|
||||
public static function tableWithPrefix(string $table)
|
||||
{
|
||||
return Str::contains($table, self::tablePrefix()) ?
|
||||
$table : self::tablePrefix() . $table;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是超级管理员
|
||||
*
|
||||
@@ -197,4 +214,83 @@ class Utils
|
||||
{
|
||||
return root_path($path ? 'public/'. $path : 'public');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 过滤空字符字段
|
||||
*
|
||||
* @time 2021年01月16日
|
||||
* @param $data
|
||||
* @return mixed
|
||||
*/
|
||||
public static function filterEmptyValue($data)
|
||||
{
|
||||
foreach ($data as $k => $v) {
|
||||
if (!$v) {
|
||||
unset($data[$k]);
|
||||
}
|
||||
}
|
||||
|
||||
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');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -5,6 +5,7 @@ namespace catcher\base;
|
||||
|
||||
use catcher\CatchQuery;
|
||||
use catcher\traits\db\BaseOptionsTrait;
|
||||
use catcher\traits\db\RewriteTrait;
|
||||
use catcher\traits\db\TransTrait;
|
||||
use think\model\concern\SoftDelete;
|
||||
use catcher\traits\db\ScopeTrait;
|
||||
@@ -17,7 +18,7 @@ use catcher\traits\db\ScopeTrait;
|
||||
*/
|
||||
abstract class CatchModel extends \think\Model
|
||||
{
|
||||
use SoftDelete, TransTrait, BaseOptionsTrait, ScopeTrait;
|
||||
use SoftDelete, TransTrait, BaseOptionsTrait, ScopeTrait, RewriteTrait;
|
||||
|
||||
protected $createTime = 'created_at';
|
||||
|
||||
@@ -29,8 +30,8 @@ abstract class CatchModel extends \think\Model
|
||||
|
||||
protected $autoWriteTimestamp = true;
|
||||
|
||||
// 分页 Limit
|
||||
public const LIMIT = 10;
|
||||
|
||||
// 开启
|
||||
public const ENABLE = 1;
|
||||
// 禁用
|
||||
@@ -45,6 +46,6 @@ abstract class CatchModel extends \think\Model
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@@ -6,7 +6,7 @@ namespace catcher\base;
|
||||
use app\Request;
|
||||
use catcher\exceptions\FailedException;
|
||||
use catcher\exceptions\ValidateFailedException;
|
||||
use think\App;
|
||||
use catcher\Utils;
|
||||
|
||||
class CatchRequest extends Request
|
||||
{
|
||||
@@ -89,4 +89,22 @@ class CatchRequest extends Request
|
||||
return parent::post($name, $default, $filter); // TODO: Change the autogenerated stub
|
||||
}
|
||||
|
||||
/**
|
||||
* 过滤空字段
|
||||
*
|
||||
* @time 2021年01月16日
|
||||
* @return $this
|
||||
*/
|
||||
public function filterEmptyField(): CatchRequest
|
||||
{
|
||||
if ($this->isGet()) {
|
||||
$this->get = Utils::filterEmptyValue($this->get);
|
||||
} elseif ($this->isPost()) {
|
||||
$this->post = Utils::filterEmptyValue($this->post);
|
||||
} else {
|
||||
$this->put = Utils::filterEmptyValue($this->put);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
@@ -3,16 +3,11 @@ declare (strict_types = 1);
|
||||
|
||||
namespace catcher\command\Tools;
|
||||
|
||||
use catcher\CatchAdmin;
|
||||
use catcher\facade\FileSystem;
|
||||
use catcher\library\BackUpDatabase;
|
||||
use catcher\library\Zip;
|
||||
use think\console\Command;
|
||||
use think\console\Input;
|
||||
use think\console\input\Argument;
|
||||
use think\console\input\Option;
|
||||
use think\console\Output;
|
||||
use think\facade\Db;
|
||||
|
||||
class BackupCommand extends Command
|
||||
{
|
||||
|
34
extend/catcher/command/Tools/InitRootCommand.php
Normal file
34
extend/catcher/command/Tools/InitRootCommand.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace catcher\command\Tools;
|
||||
|
||||
use catchAdmin\permissions\model\Users;
|
||||
use catcher\library\BackUpDatabase;
|
||||
use think\console\Command;
|
||||
use think\console\Input;
|
||||
use think\console\input\Argument;
|
||||
use think\console\Output;
|
||||
|
||||
class InitRootCommand extends Command
|
||||
{
|
||||
protected $table;
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
// 指令配置
|
||||
$this->setName('catch:initAdmin')
|
||||
->setDescription('backup data you need');
|
||||
}
|
||||
|
||||
protected function execute(Input $input, Output $output)
|
||||
{
|
||||
if ($user = Users::where('id', config('catch.permissions.super_admin_id'))->find()) {
|
||||
|
||||
$user->password = 'catchadmin';
|
||||
|
||||
$user->save();
|
||||
}
|
||||
}
|
||||
}
|
167
extend/catcher/command/Tools/RegionCommand.php
Normal file
167
extend/catcher/command/Tools/RegionCommand.php
Normal 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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -116,7 +116,7 @@ class InstallProjectCommand extends Command
|
||||
|
||||
// 设置 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;
|
||||
}
|
||||
|
||||
|
@@ -10,6 +10,8 @@
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
// you should use `$router`
|
||||
/* @var think\Route $router */
|
||||
|
||||
$router->group(function () use ($router){
|
||||
})->middleware('auth');
|
||||
|
||||
|
@@ -8,7 +8,9 @@ use catcher\generate\factory\Migration;
|
||||
use catcher\generate\factory\Model;
|
||||
use catcher\generate\factory\Route;
|
||||
use catcher\generate\factory\SQL;
|
||||
use catcher\generate\support\Table;
|
||||
use catcher\library\Composer;
|
||||
use catcher\Utils;
|
||||
use think\facade\Db;
|
||||
|
||||
class Generator
|
||||
@@ -22,8 +24,11 @@ class Generator
|
||||
* @time 2020年04月29日
|
||||
* @param $params
|
||||
* @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)) {
|
||||
@@ -49,7 +54,7 @@ class Generator
|
||||
}
|
||||
|
||||
if ($params['create_table']) {
|
||||
$table = (new SQL)->done($model);
|
||||
(new SQL)->done($model);
|
||||
array_push($message, 'table created successfully');
|
||||
}
|
||||
|
||||
@@ -65,17 +70,17 @@ class Generator
|
||||
|
||||
// 只有创建了 Controller 最后成功才写入 route
|
||||
if ($params['create_controller']) {
|
||||
(new Route())->controller($controller['controller'])
|
||||
(new Route)->controller($controller['controller'])
|
||||
->restful($controller['restful'])
|
||||
// ->methods((new Controller())->parseOtherMethods($controller['other_function']))
|
||||
->done();
|
||||
}
|
||||
|
||||
} catch (\Exception $exception) {
|
||||
$this->rollback($files, $migration, $table);
|
||||
throw new FailedException($exception->getFile() . $exception->getLine() . $exception->getMessage());
|
||||
} catch (\Throwable $exception) {
|
||||
if (!$exception instanceof TableExistException) {
|
||||
$this->rollback($files, $migration);
|
||||
}
|
||||
|
||||
throw new FailedException($exception->getMessage());
|
||||
}
|
||||
|
||||
return $message;
|
||||
}
|
||||
@@ -97,9 +102,9 @@ class Generator
|
||||
|
||||
switch ($type) {
|
||||
case 'controller':
|
||||
return (new Controller())->getContent($controller);
|
||||
return (new Controller)->getContent($controller);
|
||||
case 'model':
|
||||
return (new Model())->getContent($model);
|
||||
return (new Model)->getContent($model);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -113,7 +118,7 @@ class Generator
|
||||
* @param $params
|
||||
* @return array[]
|
||||
*/
|
||||
protected function parseParams($params)
|
||||
protected function parseParams($params): array
|
||||
{
|
||||
$module = $params['controller']['module'] ?? false;
|
||||
|
||||
@@ -126,14 +131,14 @@ class Generator
|
||||
'model' => $params['controller']['model'] ?? '',
|
||||
'controller' => $params['controller']['controller'] ?? '',
|
||||
'restful' => $params['controller']['restful'],
|
||||
// 'other_function' => $params['controller']['other_function'],
|
||||
];
|
||||
|
||||
$table = $params['controller']['table'] ?? '';
|
||||
if ($table) {
|
||||
$table = \config('database.connections.mysql.prefix') . $table;
|
||||
|
||||
if ($table) {
|
||||
$table = Utils::tableWithPrefix($table);
|
||||
}
|
||||
|
||||
$model = [
|
||||
'table' => $table,
|
||||
'model' => $params['controller']['model'] ?? '',
|
||||
@@ -151,17 +156,14 @@ class Generator
|
||||
*
|
||||
* @param $files
|
||||
* @param $migration
|
||||
* @param $table
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @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)) {
|
||||
Db::query(sprintf('drop table %s', $table));
|
||||
if (Table::exist()) {
|
||||
Table::drop();
|
||||
}
|
||||
|
||||
foreach ($files as $file) {
|
||||
|
9
extend/catcher/generate/TableExistException.php
Normal file
9
extend/catcher/generate/TableExistException.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
namespace catcher\generate;
|
||||
|
||||
use catcher\exceptions\CatchException;
|
||||
|
||||
class TableExistException extends CatchException
|
||||
{
|
||||
|
||||
}
|
@@ -36,7 +36,7 @@ class Controller extends Factory
|
||||
* @param $params
|
||||
* @return bool|string|string[]
|
||||
*/
|
||||
public function done($params)
|
||||
public function done(array $params)
|
||||
{
|
||||
// 写入成功之后
|
||||
$controllerPath = $this->getGeneratePath($params['controller']);
|
||||
|
@@ -6,7 +6,7 @@ use think\facade\Db;
|
||||
|
||||
abstract class Factory
|
||||
{
|
||||
abstract public function done($param);
|
||||
abstract public function done(array $params);
|
||||
|
||||
/**
|
||||
* parse psr4 path
|
||||
@@ -28,7 +28,7 @@ abstract class Factory
|
||||
* @param $filePath
|
||||
* @return string
|
||||
*/
|
||||
protected function getGeneratePath($filePath)
|
||||
protected function getGeneratePath($filePath): string
|
||||
{
|
||||
$path = explode('\\', $filePath);
|
||||
|
||||
@@ -52,7 +52,7 @@ abstract class Factory
|
||||
* @param $filePath
|
||||
* @return string
|
||||
*/
|
||||
public function getModulePath($filePath)
|
||||
public function getModulePath($filePath): string
|
||||
{
|
||||
$path = explode('\\', $filePath);
|
||||
|
||||
@@ -72,7 +72,7 @@ abstract class Factory
|
||||
* @param $filename
|
||||
* @return array
|
||||
*/
|
||||
public function parseFilename($filename)
|
||||
public function parseFilename($filename): array
|
||||
{
|
||||
$namespace = explode('\\', $filename);
|
||||
|
||||
@@ -89,7 +89,7 @@ abstract class Factory
|
||||
* @param $table
|
||||
* @return bool
|
||||
*/
|
||||
public function hasTableExists($table)
|
||||
public function hasTableExists($table): bool
|
||||
{
|
||||
$tables = Db::connect()->getTables();
|
||||
|
||||
|
@@ -11,7 +11,15 @@ use think\helper\Str;
|
||||
|
||||
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;
|
||||
|
||||
|
@@ -24,7 +24,7 @@ class Model extends Factory
|
||||
* @param $params
|
||||
* @return string
|
||||
*/
|
||||
public function done($params)
|
||||
public function done(array $params): string
|
||||
{
|
||||
$content = $this->getContent($params);
|
||||
|
||||
@@ -50,7 +50,7 @@ class Model extends Factory
|
||||
{
|
||||
$extra = $params['extra'];
|
||||
|
||||
$table = $params['table'];
|
||||
$table = Utils::tableWithPrefix($params['table']);
|
||||
|
||||
[$modelName, $namespace] = $this->parseFilename($params['model']);
|
||||
|
||||
@@ -92,7 +92,6 @@ class Model extends Factory
|
||||
(new Arr)->build(Db::getFields($table))
|
||||
)->docComment('// 数据库字段映射'));
|
||||
});
|
||||
|
||||
})->getContent();
|
||||
}
|
||||
}
|
@@ -1 +0,0 @@
|
||||
<?php
|
@@ -16,7 +16,7 @@ class Route extends Factory
|
||||
|
||||
protected $methods = [];
|
||||
|
||||
public function done($params = [])
|
||||
public function done(array $params = [])
|
||||
{
|
||||
$route = [];
|
||||
|
||||
|
@@ -1,213 +1,156 @@
|
||||
<?php
|
||||
namespace catcher\generate\factory;
|
||||
|
||||
|
||||
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
|
||||
{
|
||||
protected $index = '';
|
||||
|
||||
|
||||
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)
|
||||
public function done(array $params)
|
||||
{
|
||||
if (!$params['table'] ?? false) {
|
||||
throw new FailedException('table name has lost~');
|
||||
}
|
||||
|
||||
if ($this->hasTableExists($params['table'])) {
|
||||
throw new FailedException(sprintf('table [%s] has existed', $params['table']));
|
||||
}
|
||||
$this->createTable($params);
|
||||
|
||||
$extra = $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);
|
||||
$this->createTableColumns($params['sql'], $params['extra']);
|
||||
|
||||
// 创建表 SQL
|
||||
return $this->createTable($params['table'], $createSql, $extra['engine'], 'utf8mb4', $extra['comment']);
|
||||
$this->createTableIndex($this->getIndexColumns($params['sql']));
|
||||
|
||||
return $params['table'];
|
||||
}
|
||||
|
||||
/**
|
||||
* parse sql
|
||||
* 创建表
|
||||
*
|
||||
* @time 2020年04月27日
|
||||
* @param $sql
|
||||
* @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
|
||||
* @time 2021年03月13日
|
||||
* @param array $params
|
||||
* @return void
|
||||
*/
|
||||
protected function parseIndex($index, $field)
|
||||
protected function createTable(array $params)
|
||||
{
|
||||
if ($index == 'unique') {
|
||||
$this->index .= "unique index unique_$field($field)," . PHP_EOL;
|
||||
} elseif ($index == 'index') {
|
||||
$this->index .= "index($field),". PHP_EOL;
|
||||
} elseif ($index == 'fulltext') {
|
||||
$this->index .= "fulltext key fulltext_$field($field)," . PHP_EOL;
|
||||
} elseif ($index == 'spatial') {
|
||||
$this->index .= "spatial index spatial_$field($field),". PHP_EOL;
|
||||
$table = new Table($params['table']);
|
||||
|
||||
if ($table::exist()) {
|
||||
throw new TableExistException(sprintf('Table [%s] has been existed', $params['table']));
|
||||
}
|
||||
|
||||
if(!$table::create(
|
||||
$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日
|
||||
* @return bool
|
||||
*/
|
||||
protected function doNotNeedDefaultValueType(string $type)
|
||||
protected function doNotNeedDefaultValueType(string $type): bool
|
||||
{
|
||||
return in_array($type, [
|
||||
'blob', 'text', 'geometry', 'json',
|
||||
'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');
|
||||
}
|
||||
}
|
272
extend/catcher/generate/support/Table.php
Normal file
272
extend/catcher/generate/support/Table.php
Normal 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;
|
||||
}
|
||||
}
|
376
extend/catcher/generate/support/TableColumn.php
Normal file
376
extend/catcher/generate/support/TableColumn.php
Normal 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);
|
||||
}
|
||||
}
|
@@ -23,7 +23,7 @@ class FileSystem
|
||||
* @param string $path
|
||||
* @return bool
|
||||
*/
|
||||
public function exists($path)
|
||||
public function exists(string $path): bool
|
||||
{
|
||||
return file_exists($path);
|
||||
}
|
||||
@@ -35,7 +35,7 @@ class FileSystem
|
||||
* @param bool $lock
|
||||
* @return string
|
||||
**/
|
||||
public function get($path, $lock = false)
|
||||
public function get(string $path, $lock = false): string
|
||||
{
|
||||
if ($this->isFile($path)) {
|
||||
return $lock ? $this->sharedGet($path) : file_get_contents($path);
|
||||
@@ -50,7 +50,7 @@ class FileSystem
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
public function sharedGet($path)
|
||||
public function sharedGet(string $path): string
|
||||
{
|
||||
$contents = '';
|
||||
|
||||
@@ -81,7 +81,7 @@ class FileSystem
|
||||
*
|
||||
* @throws FiledNotFoundException
|
||||
*/
|
||||
public function getRequire($path)
|
||||
public function getRequire(string $path)
|
||||
{
|
||||
if ($this->isFile($path)) {
|
||||
return require $path;
|
||||
@@ -96,7 +96,7 @@ class FileSystem
|
||||
* @param string $file
|
||||
* @return mixed
|
||||
*/
|
||||
public function requireOnce($file)
|
||||
public function requireOnce(string $file)
|
||||
{
|
||||
require_once $file;
|
||||
}
|
||||
@@ -107,7 +107,7 @@ class FileSystem
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
public function hash($path)
|
||||
public function hash(string $path): string
|
||||
{
|
||||
return md5_file($path);
|
||||
}
|
||||
@@ -120,7 +120,7 @@ class FileSystem
|
||||
* @param bool $lock
|
||||
* @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);
|
||||
}
|
||||
@@ -132,7 +132,7 @@ class FileSystem
|
||||
* @param string $content
|
||||
* @return void
|
||||
*/
|
||||
public function replace($path, $content)
|
||||
public function replace(string $path, string $content)
|
||||
{
|
||||
|
||||
clearstatcache(true, $path);
|
||||
@@ -155,7 +155,7 @@ class FileSystem
|
||||
* @param string $data
|
||||
* @return int
|
||||
*/
|
||||
public function prepend($path, $data)
|
||||
public function prepend(string $path, string $data)
|
||||
{
|
||||
if ($this->exists($path)) {
|
||||
return $this->put($path, $data.$this->get($path));
|
||||
@@ -171,7 +171,7 @@ class FileSystem
|
||||
* @param string $data
|
||||
* @return int
|
||||
*/
|
||||
public function append($path, $data)
|
||||
public function append(string $path, string $data): int
|
||||
{
|
||||
return file_put_contents($path, $data, FILE_APPEND);
|
||||
}
|
||||
@@ -183,7 +183,7 @@ class FileSystem
|
||||
* @param int|null $mode
|
||||
* @return mixed
|
||||
*/
|
||||
public function chmod($path, $mode = null)
|
||||
public function chmod(string $path, $mode = null)
|
||||
{
|
||||
if ($mode) {
|
||||
return chmod($path, $mode);
|
||||
@@ -198,7 +198,7 @@ class FileSystem
|
||||
* @param string|array $paths
|
||||
* @return bool
|
||||
*/
|
||||
public function delete($paths)
|
||||
public function delete($paths): bool
|
||||
{
|
||||
$paths = is_array($paths) ? $paths : func_get_args();
|
||||
|
||||
@@ -224,7 +224,7 @@ class FileSystem
|
||||
* @param string $target
|
||||
* @return bool
|
||||
*/
|
||||
public function move($path, $target)
|
||||
public function move(string $path, string $target): bool
|
||||
{
|
||||
return rename($path, $target);
|
||||
}
|
||||
@@ -236,7 +236,7 @@ class FileSystem
|
||||
* @param string $target
|
||||
* @return bool
|
||||
*/
|
||||
public function copy($path, $target)
|
||||
public function copy(string $path, string $target): bool
|
||||
{
|
||||
return copy($path, $target);
|
||||
}
|
||||
@@ -248,7 +248,7 @@ class FileSystem
|
||||
* @param string $link
|
||||
* @return void|mixed
|
||||
*/
|
||||
public function link($target, $link)
|
||||
public function link(string $target, string $link)
|
||||
{
|
||||
$isWin = strtolower(substr(PHP_OS, 0, 3)) === 'win';
|
||||
if (! $isWin) {
|
||||
@@ -266,7 +266,7 @@ class FileSystem
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
public function name($path)
|
||||
public function name(string $path): string
|
||||
{
|
||||
return pathinfo($path, PATHINFO_FILENAME);
|
||||
}
|
||||
@@ -277,7 +277,7 @@ class FileSystem
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
public function basename($path)
|
||||
public function basename(string $path): string
|
||||
{
|
||||
return pathinfo($path, PATHINFO_BASENAME);
|
||||
}
|
||||
@@ -288,7 +288,7 @@ class FileSystem
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
public function dirname($path)
|
||||
public function dirname(string $path): string
|
||||
{
|
||||
return pathinfo($path, PATHINFO_DIRNAME);
|
||||
}
|
||||
@@ -299,7 +299,7 @@ class FileSystem
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
public function extension($path)
|
||||
public function extension(string $path): string
|
||||
{
|
||||
return pathinfo($path, PATHINFO_EXTENSION);
|
||||
}
|
||||
@@ -310,7 +310,7 @@ class FileSystem
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
public function type($path)
|
||||
public function type(string $path): string
|
||||
{
|
||||
return filetype($path);
|
||||
}
|
||||
@@ -321,7 +321,7 @@ class FileSystem
|
||||
* @param string $path
|
||||
* @return string|false
|
||||
*/
|
||||
public function mimeType($path)
|
||||
public function mimeType(string $path)
|
||||
{
|
||||
return finfo_file(finfo_open(FILEINFO_MIME_TYPE), $path);
|
||||
}
|
||||
@@ -332,7 +332,7 @@ class FileSystem
|
||||
* @param string $path
|
||||
* @return int
|
||||
*/
|
||||
public function size($path)
|
||||
public function size(string $path): int
|
||||
{
|
||||
return filesize($path);
|
||||
}
|
||||
@@ -343,7 +343,7 @@ class FileSystem
|
||||
* @param string $path
|
||||
* @return int
|
||||
*/
|
||||
public function lastModified($path)
|
||||
public function lastModified(string $path): int
|
||||
{
|
||||
return filemtime($path);
|
||||
}
|
||||
@@ -354,7 +354,7 @@ class FileSystem
|
||||
* @param string $directory
|
||||
* @return bool
|
||||
*/
|
||||
public function isDirectory($directory)
|
||||
public function isDirectory(string $directory): bool
|
||||
{
|
||||
return is_dir($directory);
|
||||
}
|
||||
@@ -365,7 +365,7 @@ class FileSystem
|
||||
* @param string $path
|
||||
* @return bool
|
||||
*/
|
||||
public function isReadable($path)
|
||||
public function isReadable(string $path): bool
|
||||
{
|
||||
return is_readable($path);
|
||||
}
|
||||
@@ -376,7 +376,7 @@ class FileSystem
|
||||
* @param string $path
|
||||
* @return bool
|
||||
*/
|
||||
public function isWritable($path)
|
||||
public function isWritable(string $path): bool
|
||||
{
|
||||
return is_writable($path);
|
||||
}
|
||||
@@ -387,7 +387,7 @@ class FileSystem
|
||||
* @param string $file
|
||||
* @return bool
|
||||
*/
|
||||
public function isFile($file)
|
||||
public function isFile(string $file): bool
|
||||
{
|
||||
return is_file($file);
|
||||
}
|
||||
@@ -399,7 +399,7 @@ class FileSystem
|
||||
* @param int $flags
|
||||
* @return array
|
||||
*/
|
||||
public function glob($pattern, $flags = 0)
|
||||
public function glob(string $pattern, $flags = 0): array
|
||||
{
|
||||
return glob($pattern, $flags);
|
||||
}
|
||||
@@ -411,7 +411,7 @@ class FileSystem
|
||||
* @param bool $hidden
|
||||
* @return \Symfony\Component\Finder\SplFileInfo[]
|
||||
*/
|
||||
public function files($directory, $hidden = false)
|
||||
public function files(string $directory, $hidden = false): array
|
||||
{
|
||||
return iterator_to_array(
|
||||
Finder::create()->files()->ignoreDotFiles(! $hidden)->in($directory)->depth(0)->sortByName(),
|
||||
@@ -426,7 +426,7 @@ class FileSystem
|
||||
* @param bool $hidden
|
||||
* @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(),
|
||||
false
|
||||
@@ -439,7 +439,7 @@ class FileSystem
|
||||
* @param string $directory
|
||||
* @return array
|
||||
*/
|
||||
public function directories($directory)
|
||||
public function directories(string $directory): array
|
||||
{
|
||||
$directories = [];
|
||||
|
||||
@@ -459,7 +459,7 @@ class FileSystem
|
||||
* @param bool $force
|
||||
* @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) {
|
||||
return @mkdir($path, $mode, $recursive);
|
||||
@@ -476,7 +476,7 @@ class FileSystem
|
||||
* @param bool $overwrite
|
||||
* @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)) {
|
||||
return false;
|
||||
@@ -493,7 +493,7 @@ class FileSystem
|
||||
* @param int|null $options
|
||||
* @return bool
|
||||
*/
|
||||
public function copyDirectory($directory, $destination, $options = null)
|
||||
public function copyDirectory(string $directory, string $destination, $options = null): bool
|
||||
{
|
||||
if (! $this->isDirectory($directory)) {
|
||||
return false;
|
||||
@@ -537,7 +537,7 @@ class FileSystem
|
||||
* @param bool $preserve
|
||||
* @return bool
|
||||
*/
|
||||
public function deleteDirectory($directory, $preserve = false)
|
||||
public function deleteDirectory(string $directory, $preserve = false): bool
|
||||
{
|
||||
if (! $this->isDirectory($directory)) {
|
||||
return false;
|
||||
@@ -567,7 +567,7 @@ class FileSystem
|
||||
* @param string $directory
|
||||
* @return bool
|
||||
*/
|
||||
public function deleteDirectories($directory)
|
||||
public function deleteDirectories(string $directory): bool
|
||||
{
|
||||
$allDirectories = $this->directories($directory);
|
||||
|
||||
@@ -588,7 +588,7 @@ class FileSystem
|
||||
* @param string $directory
|
||||
* @return bool
|
||||
*/
|
||||
public function cleanDirectory($directory)
|
||||
public function cleanDirectory(string $directory): bool
|
||||
{
|
||||
return $this->deleteDirectory($directory, true);
|
||||
}
|
||||
|
@@ -125,7 +125,8 @@ class InstallLocalModule
|
||||
*/
|
||||
public function enableModule()
|
||||
{
|
||||
CatchAdmin::enableModule($this->module);
|
||||
CatchAdmin::updateModuleInfo($this->module, ['enable' => true]);
|
||||
|
||||
app(Permissions::class)->restore(['module' => trim($this->module)]);
|
||||
}
|
||||
|
||||
@@ -137,7 +138,7 @@ class InstallLocalModule
|
||||
*/
|
||||
public function disableModule()
|
||||
{
|
||||
CatchAdmin::disableModule($this->module);
|
||||
CatchAdmin::updateModuleInfo($this->module, ['enable' => false]);
|
||||
|
||||
Permissions::destroy(function ($query) {
|
||||
$query->where('module', trim($this->module));
|
||||
|
@@ -100,9 +100,9 @@ declare(strict_types=1);
|
||||
{
|
||||
$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)) . '%';
|
||||
|
||||
|
332
extend/catcher/library/form/Form.php
Normal file
332
extend/catcher/library/form/Form.php
Normal 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);
|
||||
}
|
||||
|
||||
}
|
34
extend/catcher/library/form/FormFactory.php
Normal file
34
extend/catcher/library/form/FormFactory.php
Normal 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();
|
||||
}
|
||||
}
|
49
extend/catcher/library/form/FormOptions.php
Normal file
49
extend/catcher/library/form/FormOptions.php
Normal 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;
|
||||
}
|
||||
}
|
140
extend/catcher/library/form/FormValidates.php
Normal file
140
extend/catcher/library/form/FormValidates.php
Normal 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('必须为纯汉字');
|
||||
}
|
||||
}
|
50
extend/catcher/library/form/components/AreaTrait.php
Normal file
50
extend/catcher/library/form/components/AreaTrait.php
Normal 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();
|
||||
}
|
||||
}
|
156
extend/catcher/library/form/components/Editor.php
Normal file
156
extend/catcher/library/form/components/Editor.php
Normal 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;
|
||||
}
|
||||
}
|
110
extend/catcher/library/table/Actions.php
Normal file
110
extend/catcher/library/table/Actions.php
Normal 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');
|
||||
}
|
||||
|
||||
}
|
67
extend/catcher/library/table/ComponentsTrait.php
Normal file
67
extend/catcher/library/table/ComponentsTrait.php
Normal 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($updateFields = null): HeaderItem
|
||||
{
|
||||
return $this->component('switch_', $updateFields ? : $this->attributes['prop']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
20
extend/catcher/library/table/Events.php
Normal file
20
extend/catcher/library/table/Events.php
Normal 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;
|
||||
}
|
||||
}
|
96
extend/catcher/library/table/HeaderItem.php
Normal file
96
extend/catcher/library/table/HeaderItem.php
Normal file
@@ -0,0 +1,96 @@
|
||||
<?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');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 动态访问
|
||||
*
|
||||
* @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};
|
||||
}
|
||||
}
|
127
extend/catcher/library/table/Search.php
Normal file
127
extend/catcher/library/table/Search.php
Normal 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);
|
||||
}
|
||||
}
|
481
extend/catcher/library/table/Table.php
Normal file
481
extend/catcher/library/table/Table.php
Normal file
@@ -0,0 +1,481 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
36
extend/catcher/library/table/components/Button.php
Normal file
36
extend/catcher/library/table/components/Button.php
Normal 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;
|
||||
}
|
||||
}
|
43
extend/catcher/library/table/components/Component.php
Normal file
43
extend/catcher/library/table/components/Component.php
Normal 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;
|
||||
}
|
||||
}
|
@@ -3,9 +3,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace catcher\traits\db;
|
||||
|
||||
use catcher\CatchModelCollection;
|
||||
use catcher\Utils;
|
||||
use think\Collection;
|
||||
|
||||
trait BaseOptionsTrait
|
||||
{
|
||||
@@ -42,7 +40,7 @@ trait BaseOptionsTrait
|
||||
*/
|
||||
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()};
|
||||
}
|
||||
|
||||
@@ -72,7 +70,7 @@ trait BaseOptionsTrait
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -164,13 +162,25 @@ trait BaseOptionsTrait
|
||||
*
|
||||
* @time 2020年01月13日
|
||||
* @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);
|
||||
}
|
||||
|
||||
if (is_array($field)) {
|
||||
foreach ($field as &$value) {
|
||||
$value = sprintf('%s.%s', $this->getTable(), $value);
|
||||
}
|
||||
|
||||
return $field;
|
||||
}
|
||||
|
||||
return $field;
|
||||
}
|
||||
|
||||
/**
|
||||
* 禁用/启用
|
||||
*
|
||||
@@ -191,23 +201,24 @@ trait BaseOptionsTrait
|
||||
}
|
||||
|
||||
/**
|
||||
* rewrite collection
|
||||
* 过滤数据
|
||||
*
|
||||
* @time 2020年10月20日
|
||||
* @param array|iterable $collection
|
||||
* @param string|null $resultSetType
|
||||
* @return CatchModelCollection|mixed
|
||||
* @time 2021年02月28日
|
||||
* @param $data
|
||||
* @return mixed
|
||||
*/
|
||||
public function toCollection(iterable $collection = [], string $resultSetType = null): Collection
|
||||
protected function filterData($data)
|
||||
{
|
||||
$resultSetType = $resultSetType ?: $this->resultSetType;
|
||||
|
||||
if ($resultSetType && false !== strpos($resultSetType, '\\')) {
|
||||
$collection = new $resultSetType($collection);
|
||||
} else {
|
||||
$collection = new CatchModelCollection($collection);
|
||||
foreach ($data as $field => $value) {
|
||||
if (is_null($value)) {
|
||||
unset($data[$field]);
|
||||
}
|
||||
|
||||
return $collection;
|
||||
if ($field == $this->getPk()) {
|
||||
unset($data[$field]);
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
80
extend/catcher/traits/db/RewriteTrait.php
Normal file
80
extend/catcher/traits/db/RewriteTrait.php
Normal file
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
namespace catcher\traits\db;
|
||||
|
||||
use catcher\CatchModelCollection;
|
||||
use think\Collection;
|
||||
|
||||
/**
|
||||
* 重写 think\Model 的方法
|
||||
*
|
||||
* Trait RewriteTrait
|
||||
* @package catcher\traits\db
|
||||
*/
|
||||
trait RewriteTrait
|
||||
{
|
||||
/**
|
||||
* 初始化
|
||||
*
|
||||
* CatchModel constructor.
|
||||
* @param array $data
|
||||
*/
|
||||
public function __construct(array $data = [])
|
||||
{
|
||||
parent::__construct($data);
|
||||
|
||||
$this->hidden = array_merge($this->hidden, $this->defaultHiddenFields());
|
||||
}
|
||||
|
||||
/**
|
||||
* hidden model fields
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function defaultHiddenFields(): array
|
||||
{
|
||||
return [$this->deleteTime];
|
||||
}
|
||||
|
||||
/**
|
||||
* 重写 hidden 方法,支持合并 hidden 属性
|
||||
*
|
||||
* @param array $hidden
|
||||
* @return $this
|
||||
*/
|
||||
public function hidden(array $hidden = [])
|
||||
{
|
||||
/**
|
||||
* 合并属性
|
||||
*/
|
||||
if (!count($this->hidden)) {
|
||||
$this->hidden = array_merge($this->hidden, $hidden);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
$this->hidden = $hidden;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
@@ -19,6 +19,10 @@ class SensitiveWord implements ValidateInterface
|
||||
{
|
||||
$trie = app(Trie::class);
|
||||
|
||||
if (!$trie->getTries()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$word = $trie->getSensitiveWords($trie->getTries(), $value, false);
|
||||
|
||||
return !$word;
|
||||
|
Reference in New Issue
Block a user