冲突
This commit is contained in:
commit
cf1dedabd4
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,5 +1,6 @@
|
||||
/.idea
|
||||
/.vscode
|
||||
/vendor
|
||||
/database
|
||||
*.log
|
||||
.env
|
12
README.md
12
README.md
@ -14,14 +14,14 @@
|
||||
|
||||
### install
|
||||
- curl -sS http://install.phpcomposer.com/installer | php
|
||||
- composer config -g repo.packagist composer https://packagist.laravel-china.org
|
||||
- composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/
|
||||
- composer update
|
||||
- php think install:project
|
||||
- php think catch:install
|
||||
|
||||
### Use
|
||||
- 配置虚拟域名 OR 在根目录下执行 php think run
|
||||
- yourUrl/login
|
||||
- 默认用户名 admin 密码 admin
|
||||
- 默认用户名 admin@gmail.com 密码 admin
|
||||
|
||||
### Problem
|
||||
> SQLSTATE[42000]: Syntax error or access violation: 1067 Invalid default value for 'updated_at'
|
||||
@ -39,3 +39,9 @@ remove 'NO_ZERO_IN_DATE,NO_ZERO_DATE'
|
||||
- 
|
||||
|
||||
仅供学习
|
||||
|
||||
## 体验地址
|
||||
|
||||
[体验地址](http://catch.njphper.com/login)
|
||||
- 账号: test@catch.com
|
||||
- 密码: 123456
|
@ -2,6 +2,10 @@
|
||||
namespace app;
|
||||
|
||||
use catcher\CatchResponse;
|
||||
use catcher\exceptions\CatchException;
|
||||
use catcher\exceptions\FailedException;
|
||||
use catcher\exceptions\LoginFailedException;
|
||||
use catcher\exceptions\PermissionForbiddenException;
|
||||
use think\db\exception\DataNotFoundException;
|
||||
use think\db\exception\ModelNotFoundException;
|
||||
use think\exception\Handle;
|
||||
@ -45,17 +49,17 @@ class ExceptionHandle extends Handle
|
||||
* Render an exception into an HTTP response.
|
||||
*
|
||||
* @access public
|
||||
* @param \think\Request $request
|
||||
* @param \think\Request $request
|
||||
* @param Throwable $e
|
||||
* @return Response
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function render($request, Throwable $e): Response
|
||||
{
|
||||
// 添加自定义异常处理机制
|
||||
if ($request->isAjax()) {
|
||||
return CatchResponse::fail($e->getMessage(), $e->getCode());
|
||||
}
|
||||
// if ($e instanceof CatchException){
|
||||
return CatchResponse::fail($e->getMessage(), $e->getCode());
|
||||
// }
|
||||
// 其他错误交给系统处理
|
||||
return parent::render($request, $e);
|
||||
//return parent::render($request, $e);
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,12 @@ namespace app;
|
||||
|
||||
// 应用请求对象类
|
||||
|
||||
use catchAdmin\user\Auth;
|
||||
|
||||
class Request extends \think\Request
|
||||
{
|
||||
|
||||
public function user()
|
||||
{
|
||||
return Auth::user();
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
<?php
|
||||
// 事件定义文件
|
||||
|
||||
return [
|
||||
'bind' => [
|
||||
],
|
||||
'bind' => [],
|
||||
|
||||
'listen' => [
|
||||
'AppInit' => [],
|
||||
@ -10,9 +10,7 @@ return [
|
||||
'HttpEnd' => [],
|
||||
'LogLevel' => [],
|
||||
'LogWrite' => [],
|
||||
'RouteLoaded' => [
|
||||
catcher\event\LoadModuleRoutes::class,
|
||||
],
|
||||
'RouteLoaded' => [],
|
||||
],
|
||||
|
||||
'subscribe' => [
|
||||
|
@ -1,10 +1,21 @@
|
||||
<?php
|
||||
namespace catchAdmin;
|
||||
|
||||
use catchAdmin\login\LoginLogListener;
|
||||
use catchAdmin\permissions\OperateLogListener;
|
||||
use catchAdmin\permissions\PermissionsMiddleware;
|
||||
use catchAdmin\system\event\LoginLogEvent;
|
||||
use catchAdmin\system\event\OperateLogEvent;
|
||||
use catchAdmin\user\Auth;
|
||||
use catcher\command\BackupCommand;
|
||||
use catcher\command\CompressPackageCommand;
|
||||
use catcher\command\CreateModuleCommand;
|
||||
use catcher\command\InstallCommand;
|
||||
use catcher\command\MigrateRunCommand;
|
||||
use catcher\command\ModelGeneratorCommand;
|
||||
use catcher\command\ModuleCacheCommand;
|
||||
use catcher\command\SeedRunCommand;
|
||||
use catcher\event\LoadModuleRoutes;
|
||||
use catcher\validates\Sometimes;
|
||||
use think\facade\Validate;
|
||||
use think\Service;
|
||||
@ -17,17 +28,32 @@ class CatchAdminService extends Service
|
||||
* @return void
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
$this->registerCommands();
|
||||
$this->registerValidates();
|
||||
$this->registerMiddleWares();
|
||||
$this->registerEvents();
|
||||
$this->registerListeners();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月13日
|
||||
* @return void
|
||||
*/
|
||||
protected function registerCommands(): void
|
||||
{
|
||||
$this->commands([
|
||||
InstallCommand::class,
|
||||
ModuleCacheCommand::class,
|
||||
MigrateRunCommand::class,
|
||||
ModelGeneratorCommand::class,
|
||||
SeedRunCommand::class,
|
||||
BackupCommand::class,
|
||||
CompressPackageCommand::class,
|
||||
CreateModuleCommand::class,
|
||||
]);
|
||||
|
||||
$this->registerValidates();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月07日
|
||||
@ -44,6 +70,51 @@ class CatchAdminService extends Service
|
||||
$validate->extend($vali->type(), [$vali, 'verify'], $vali->message());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月12日
|
||||
* @return void
|
||||
*/
|
||||
protected function registerMiddleWares(): void
|
||||
{
|
||||
$this->app->middleware->import([
|
||||
'catch_check_permission' => PermissionsMiddleware::class,
|
||||
], 'route');
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月12日
|
||||
* @return void
|
||||
*/
|
||||
protected function registerEvents(): void
|
||||
{
|
||||
$this->app->event->bind([
|
||||
'loginLog' => LoginLogEvent::class,
|
||||
'operateLog' => OperateLogEvent::class,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册监听者
|
||||
*
|
||||
* @time 2019年12月12日
|
||||
* @return void
|
||||
*/
|
||||
protected function registerListeners(): void
|
||||
{
|
||||
$this->app->event->listenEvents([
|
||||
'loginLog' => [
|
||||
LoginLogListener::class,
|
||||
],
|
||||
'operateLog' => [
|
||||
OperateLogListener::class,
|
||||
],
|
||||
'RouteLoaded' => [
|
||||
LoadModuleRoutes::class
|
||||
]
|
||||
]);
|
||||
}
|
||||
}
|
23
catchAdmin/helper.php
Normal file
23
catchAdmin/helper.php
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
function editButton($name = '修改', $event = 'edit')
|
||||
{
|
||||
return sprintf(
|
||||
'<a class="layui-btn layui-btn-primary layui-btn-xs" lay-event="%s">%s</a>',
|
||||
$event, $name);
|
||||
}
|
||||
|
||||
function deleteButton($name = '删除', $event = 'del')
|
||||
{
|
||||
return sprintf(
|
||||
'<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="%s">%s</a>',
|
||||
$event, $name);
|
||||
}
|
||||
|
||||
function addButton($name = '新增', $event = 'add')
|
||||
{
|
||||
return sprintf(
|
||||
'<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="%s">%s</a>',
|
||||
$event, $name);
|
||||
}
|
||||
|
@ -1,13 +1,59 @@
|
||||
<?php
|
||||
namespace catchAdmin\index\controller;
|
||||
|
||||
use catchAdmin\permissions\model\Permissions;
|
||||
use catchAdmin\user\Auth;
|
||||
use catcher\base\CatchController;
|
||||
use catcher\Tree;
|
||||
use think\facade\Db;
|
||||
|
||||
use catcher\base\BaseController;
|
||||
|
||||
class Index extends BaseController
|
||||
class Index extends CatchController
|
||||
{
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月11日
|
||||
* @return string
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
*/
|
||||
public function index(): string
|
||||
{
|
||||
$permissionIds = Auth::user()->getPermissionsBy();
|
||||
|
||||
$menus = Permissions::whereIn('id', $permissionIds)
|
||||
->where('type', Permissions::MENU_TYPE)
|
||||
->field(['id', 'parent_id', 'permission_name', 'route'])
|
||||
->select()->toArray();
|
||||
|
||||
return $this->fetch([
|
||||
'menus' => Tree::done($menus),
|
||||
'username' => Auth::user()->username,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月11日
|
||||
* @throws \Exception
|
||||
* @return string
|
||||
*/
|
||||
public function theme(): string
|
||||
{
|
||||
return $this->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月12日
|
||||
* @throws \Exception
|
||||
* @return string
|
||||
*/
|
||||
public function dashboard(): string
|
||||
{
|
||||
$mysqlVersion = Db::query('select version() as version');
|
||||
return $this->fetch([
|
||||
'mysql_version' => $mysqlVersion['0']['version'],
|
||||
]);
|
||||
}
|
||||
}
|
@ -1,3 +1,5 @@
|
||||
<?php
|
||||
|
||||
$router->get('/', '\catchAdmin\index\controller\index/index');
|
||||
$router->get('/', '\catchAdmin\index\controller\Index@index');
|
||||
$router->get('theme', '\catchAdmin\index\controller\Index@theme');
|
||||
$router->get('dashboard', '\catchAdmin\index\controller\Index@dashboard');
|
||||
|
221
catchAdmin/index/view/dashboard.html
Normal file
221
catchAdmin/index/view/dashboard.html
Normal file
@ -0,0 +1,221 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<title>CatchAdmin 后台开发框架</title>
|
||||
<link rel="stylesheet" href="__CATCH_ADMIN_LIBS__/layui/css/layui.css"/>
|
||||
<link rel="stylesheet" href="__CATCH_ADMIN_MODULE__/admin.css?v=315"/>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
|
||||
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
|
||||
<![endif]-->
|
||||
<style>
|
||||
/** 卡片轮播图样式 */
|
||||
.admin-carousel .layui-carousel-ind {
|
||||
position: absolute;
|
||||
top: -41px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.admin-carousel .layui-carousel-ind ul {
|
||||
background: 0 0;
|
||||
}
|
||||
|
||||
.admin-carousel .layui-carousel-ind li {
|
||||
background-color: #e2e2e2;
|
||||
}
|
||||
|
||||
.admin-carousel .layui-carousel-ind li.layui-this {
|
||||
background-color: #999;
|
||||
}
|
||||
|
||||
/** 广告位轮播图 */
|
||||
.admin-news .layui-carousel-ind {
|
||||
height: 45px;
|
||||
}
|
||||
|
||||
.admin-news a {
|
||||
display: block;
|
||||
line-height: 60px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<!-- 加载动画 -->
|
||||
<div class="page-loading">
|
||||
<div class="ball-loader">
|
||||
<span></span><span></span><span></span><span></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 正文开始 -->
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-row layui-col-space15">
|
||||
<div class="layui-col-xs12 layui-col-sm6 layui-col-md3">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">
|
||||
访问量<span class="layui-badge layui-bg-blue pull-right">周</span>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<p class="lay-big-font">99,666</p>
|
||||
<p>总计访问量<span class="pull-right">88万 <i class="layui-icon layui-icon-flag"></i></span></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-xs12 layui-col-sm6 layui-col-md3">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">
|
||||
下载<span class="layui-badge layui-bg-black pull-right">月</span>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<p class="lay-big-font">33,555</p>
|
||||
<p>新下载<span class="pull-right">10% <i class="layui-icon"></i></span></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-xs12 layui-col-sm6 layui-col-md3">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">
|
||||
Start<span class="layui-badge layui-bg-green pull-right">周</span>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<p class="lay-big-font">99,666</p>
|
||||
<p>总Start数<span class="pull-right">88万 <i class="layui-icon layui-icon-rate"></i></span></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-xs12 layui-col-sm6 layui-col-md3">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">
|
||||
活跃用户<span class="layui-badge layui-bg-orange pull-right">月</span>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<p class="lay-big-font">66,666</p>
|
||||
<p>最近一个月<span class="pull-right">15% <i class="layui-icon layui-icon-user"></i></span></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-row layui-col-space15">
|
||||
<div class="layui-col-lg8 layui-col-md7">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">更新日志</div>
|
||||
<div class="layui-card-body">
|
||||
<ul class="layui-timeline">
|
||||
<li class="layui-timeline-item">
|
||||
<i class="layui-icon layui-timeline-axis"></i>
|
||||
<div class="layui-timeline-content layui-text">
|
||||
<h3 class="layui-timeline-title">
|
||||
V1.0
|
||||
<small>catchAdmin 后台框架发布</small> 
|
||||
<span class="layui-badge-rim">2019-12-15</span>
|
||||
</h3>
|
||||
<ul>
|
||||
<li>基于 Thinkphp6 & layui 开发</li>
|
||||
<li>完整的权限管理</li>
|
||||
<li>模块化开发方式</li>
|
||||
<li>...</li>
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
<li class="layui-timeline-item">
|
||||
<i class="layui-icon layui-timeline-axis"></i>
|
||||
<div class="layui-timeline-content layui-text">
|
||||
<div class="layui-timeline-title">
|
||||
CatchAdmin 开发中... <span class="layui-badge-rim">更早</span>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-lg4 layui-col-md5">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">后台框架</div>
|
||||
<div class="layui-card-body">
|
||||
<table class="layui-table layui-text">
|
||||
<colgroup>
|
||||
<col width="100">
|
||||
<col>
|
||||
</colgroup>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>PHP 版本</td>
|
||||
<td>{$Think.PHP_VERSION}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>MYSQL 版本</td>
|
||||
<td>{$mysql_version}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>WEB 服务器</td>
|
||||
<td>{$_SERVER['SERVER_SOFTWARE']}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>操作系统</td>
|
||||
<td>{$Think.PHP_OS}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>opcache (建议开启)</td>
|
||||
{if condition="function_exists('opcache_get_configuration')"}
|
||||
<td>{:opcache_get_configuration()['directives']['opcache.enable'] ? '开启' : '关闭' }</td>
|
||||
{else/}
|
||||
<td>未开启</td>
|
||||
{/if}
|
||||
</tr>
|
||||
<tr>
|
||||
<td>最大执行时间</td>
|
||||
<td>{:get_cfg_var("max_execution_time")} s</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>上传限制大小(M)</td>
|
||||
<td>{:get_cfg_var ("upload_max_filesize")}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>当前时间</td>
|
||||
<td>{:date("Y-m-d H:i:s")}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>核心框架</td>
|
||||
<td>Thinkphp v6</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- js部分 -->
|
||||
<script type="text/javascript" src="__CATCH_ADMIN_LIBS__/layui/layui.js"></script>
|
||||
<script type="text/javascript" src="__CATCH_ADMIN_JS__/common.js?v=315"></script>
|
||||
<script>
|
||||
layui.use(['layer', 'carousel'], function () {
|
||||
var $ = layui.jquery;
|
||||
var layer = layui.layer;
|
||||
var carousel = layui.carousel;
|
||||
var device = layui.device;
|
||||
|
||||
// 渲染轮播
|
||||
carousel.render({
|
||||
elem: '.layui-carousel',
|
||||
width: '100%',
|
||||
height: '60px',
|
||||
arrow: 'none',
|
||||
autoplay: true,
|
||||
trigger: device.ios || device.android ? 'click' : 'hover',
|
||||
anim: 'fade'
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
38
catchAdmin/index/view/error.html
Normal file
38
catchAdmin/index/view/error.html
Normal file
@ -0,0 +1,38 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<title>403</title>
|
||||
<link rel="stylesheet" href="__CATCH_ADMIN_LIBS__/layui/css/layui.css"/>
|
||||
<link rel="stylesheet" href="__CATCH_ADMIN_MODULE__/admin.css?v=315"/>
|
||||
<link rel="stylesheet" href="__CATCH_ADMIN_CSS__/error-page.css"/>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
|
||||
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
|
||||
<![endif]-->
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- 正文开始 -->
|
||||
<div class="error-page">
|
||||
<img class="error-page-img" src="__CATCH_ADMIN_IMAGES__/ic_403.png">
|
||||
<div class="error-page-info">
|
||||
<h1>403</h1>
|
||||
<div class="error-page-info-desc">{$msg}</div>
|
||||
<div>
|
||||
{if ($code == 10006)}
|
||||
<a href="{:url('login')}" class="layui-btn">返回登录</a>
|
||||
{else/}
|
||||
<button onclick="history(-1)" class="layui-btn">返回上一页</button>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- js部分 -->
|
||||
<script type="text/javascript" src="__CATCH_ADMIN_LIBS__/layui/layui.js"></script>
|
||||
<script type="text/javascript" src="__CATCH_ADMIN_JS__/common.js?v=315"></script>
|
||||
</body>
|
||||
</html>
|
@ -30,33 +30,33 @@
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="layui-nav layui-layout-right">
|
||||
<!-- <li class="layui-nav-item" lay-unselect>
|
||||
<a ew-event="message" title="消息">
|
||||
<i class="layui-icon layui-icon-notice"></i>
|
||||
<span class="layui-badge-dot"></span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="layui-nav-item" lay-unselect>
|
||||
<a ew-event="message" title="消息">
|
||||
<i class="layui-icon layui-icon-notice"></i>
|
||||
<span class="layui-badge-dot"></span><!--小红点-->
|
||||
</a>
|
||||
</li>
|
||||
<li class="layui-nav-item" lay-unselect>
|
||||
<a ew-event="note" title="便签"><i class="layui-icon layui-icon-note"></i></a>
|
||||
</li>
|
||||
<a ew-event="note" title="便签"><i class="layui-icon layui-icon-note"></i></a>
|
||||
</li>-->
|
||||
<li class="layui-nav-item layui-hide-xs" lay-unselect>
|
||||
<a ew-event="fullScreen" title="全屏"><i class="layui-icon layui-icon-screen-full"></i></a>
|
||||
</li>
|
||||
<li class="layui-nav-item" lay-unselect>
|
||||
<a>
|
||||
<img src="__CATCH_ADMIN_IMAGES__/head.png" class="layui-nav-img">
|
||||
<cite>管理员</cite>
|
||||
<cite>{$username}</cite>
|
||||
</a>
|
||||
<dl class="layui-nav-child">
|
||||
<dd lay-unselect>
|
||||
<a ew-href="page/template/user-info.html">个人中心</a>
|
||||
<!--<dd lay-unselect>
|
||||
<a ew-href="javascript:;">个人中心</a>
|
||||
</dd>
|
||||
<dd lay-unselect>
|
||||
<a ew-event="psw">修改密码</a>
|
||||
</dd>
|
||||
<hr>
|
||||
<hr>-->
|
||||
<dd lay-unselect>
|
||||
<a ew-event="logout" data-url="page/template/login.html">退出</a>
|
||||
<a id="logout">退出</a>
|
||||
</dd>
|
||||
</dl>
|
||||
</li>
|
||||
@ -71,147 +71,29 @@
|
||||
<div class="layui-side-scroll">
|
||||
<ul class="layui-nav layui-nav-tree arrow2" lay-filter="admin-side-nav" lay-accordion="true"
|
||||
style="margin-top: 15px;">
|
||||
<li class="layui-nav-item">
|
||||
<a><i class="layui-icon layui-icon-home"></i> <cite>Dashboard</cite></a>
|
||||
<dl class="layui-nav-child">
|
||||
<dd><a lay-href="page/console/console.html">控制台</a></dd>
|
||||
<dd><a lay-href="page/console/introduction.html">介绍页</a></dd>
|
||||
<dd><a lay-href="page/console/dashboard.html">分析页</a></dd>
|
||||
<dd><a lay-href="page/console/welcome.html">欢迎页</a></dd>
|
||||
</dl>
|
||||
</li>
|
||||
<li class="layui-nav-item">
|
||||
<a><i class="layui-icon layui-icon-set"></i> <cite>权限管理</cite></a>
|
||||
<dl class="layui-nav-child">
|
||||
<dd><a lay-href="{:url('user')}">用户管理</a></dd>
|
||||
<dd><a lay-href="page/system/role.html">角色管理</a></dd>
|
||||
<dd><a lay-href="page/system/authorities.html">菜单管理</a></dd>
|
||||
<dd><a lay-href="page/system/loginRecord.html">登录日志</a></dd>
|
||||
</dl>
|
||||
</li>
|
||||
<li class="layui-nav-item">
|
||||
<a><i class="layui-icon layui-icon-template"></i> <cite>模板页面</cite></a>
|
||||
<dl class="layui-nav-child">
|
||||
<dd>
|
||||
<a>表单页</a>
|
||||
{foreach $menus as $key => $menu }
|
||||
<li class="layui-nav-item">
|
||||
{if (!empty($menu['children']))}
|
||||
<a><i class="layui-icon layui-icon-home"></i> <cite>{$menu['permission_name']}</cite></a>
|
||||
<dl class="layui-nav-child">
|
||||
<dd><a lay-href="page/template/form/form-basic.html">基础表单</a></dd>
|
||||
<dd><a lay-href="page/template/form/form-advance.html">复杂表单</a></dd>
|
||||
<dd><a lay-href="page/template/form/form-step.html">分步表单</a></dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>
|
||||
<a>表格页</a>
|
||||
<dl class="layui-nav-child">
|
||||
<dd><a lay-href="page/template/table/table-basic.html">数据表格</a></dd>
|
||||
<dd><a lay-href="page/template/table/table-advance.html">复杂查询</a></dd>
|
||||
<dd><a lay-href="page/template/table/table-ltrt.html">左树右表</a></dd>
|
||||
<dd><a lay-href="page/template/table/table-img.html">表格缩略图</a></dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>
|
||||
<a>错误页</a>
|
||||
<dl class="layui-nav-child">
|
||||
<dd><a lay-href="page/template/error/error-500.html">500</a></dd>
|
||||
<dd><a lay-href="page/template/error/error-404.html">404</a></dd>
|
||||
<dd><a lay-href="page/template/error/error-403.html">403</a></dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd><a lay-href="page/template/user-info.html">个人中心</a></dd>
|
||||
<dd><a lay-href="page/template/empty.html">空白页面</a></dd>
|
||||
<dd><a href="page/template/login.html" target="_blank">登录页面</a></dd>
|
||||
</dl>
|
||||
</li>
|
||||
<li class="layui-nav-item">
|
||||
<a><i class="layui-icon layui-icon-component"></i> <cite>扩展组件</cite></a>
|
||||
<dl class="layui-nav-child">
|
||||
<dd>
|
||||
<a>常用组件</a>
|
||||
<dl class="layui-nav-child">
|
||||
<dd><a lay-href="page/plugin/basic/dialog.html">弹出层</a></dd>
|
||||
<dd><a lay-href="page/plugin/basic/dropdown.html">下拉菜单</a></dd>
|
||||
<dd><a lay-href="page/plugin/basic/cascader.html">级联选择器</a></dd>
|
||||
<dd><a lay-href="page/plugin/basic/notice.html">消息通知</a></dd>
|
||||
<dd><a lay-href="page/plugin/basic/tips.html">文字提示</a></dd>
|
||||
<dd><a lay-href="page/plugin/basic/tagsInput.html">标签输入</a></dd>
|
||||
<dd><a lay-href="page/plugin/basic/split.html">分割面板</a></dd>
|
||||
<dd><a lay-href="page/plugin/basic/circleProgress.html">圆形进度条</a></dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>
|
||||
<a>进阶组件</a>
|
||||
<dl class="layui-nav-child">
|
||||
<dd><a lay-href="page/plugin/advance/tableX.html">表格扩展</a></dd>
|
||||
<dd><a lay-href="page/plugin/advance/formX.html">表单扩展</a></dd>
|
||||
<dd><a lay-href="page/plugin/advance/dataGrid.html">数据列表</a></dd>
|
||||
<dd><a lay-href="page/plugin/advance/printer.html">打印插件</a></dd>
|
||||
<dd><a lay-href="page/plugin/advance/ckeditor.html">富文本编辑</a></dd>
|
||||
<dd><a lay-href="page/plugin/advance/player.html">视频播放器</a></dd>
|
||||
<dd><a lay-href="page/plugin/advance/introJs.html">引导插件</a></dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>
|
||||
<a>工具组件</a>
|
||||
<dl class="layui-nav-child">
|
||||
<dd><a lay-href="page/plugin/util/contextMenu.html">ContextMenu</a></dd>
|
||||
<dd><a lay-href="page/plugin/util/mousewheel.html">MouseWheel</a></dd>
|
||||
<dd><a lay-href="page/plugin/util/other.html">其他</a></dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd><a lay-href="page/plugin/more.html">更多扩展</a></dd>
|
||||
</dl>
|
||||
</li>
|
||||
<li class="layui-nav-item">
|
||||
<a><i class="layui-icon layui-icon-app"></i> <cite>经典实例</cite></a>
|
||||
<dl class="layui-nav-child">
|
||||
<dd><a lay-href="page/example/dialog.html">弹窗实例</a></dd>
|
||||
<dd><a lay-href="page/example/syxm.html">经典实例2</a></dd>
|
||||
<dd><a lay-href="page/example/form.html">表单实例</a></dd>
|
||||
<dd><a lay-href="page/example/file.html">文件管理</a></dd>
|
||||
<dd><a lay-href="page/example/table-crud.html">表格CRUD</a></dd>
|
||||
<dd><a href="page/example/side-more.html" target="_blank">多系统模式</a></dd>
|
||||
<dd><a href="page/example/side-ajax.html" target="_blank">Ajax侧边栏</a></dd>
|
||||
</dl>
|
||||
</li>
|
||||
<li class="layui-nav-item">
|
||||
<a><i class="layui-icon layui-icon-release"></i> <cite>LayUI组件</cite></a>
|
||||
<dl class="layui-nav-child">
|
||||
<dd><a lay-href="https://www.layui.com/demo/button.html">组件演示</a></dd>
|
||||
<dd><a lay-href="https://www.layui.com/doc/element/button.html#use">layui文档</a></dd>
|
||||
<dd><a lay-href="https://layer.layui.com/">layer弹窗组件</a></dd>
|
||||
<dd><a lay-href="https://www.layui.com/laydate/">laydate日期组件</a></dd>
|
||||
</dl>
|
||||
</li>
|
||||
<li class="layui-nav-item">
|
||||
<a><i class="layui-icon layui-icon-unlink"></i> <cite>多级菜单</cite></a>
|
||||
<dl class="layui-nav-child">
|
||||
<dd><a>二级菜单</a></dd>
|
||||
<dd>
|
||||
<a>二级菜单</a>
|
||||
<dl class="layui-nav-child">
|
||||
<dd><a>三级菜单</a></dd>
|
||||
<dd>
|
||||
<a>三级菜单</a>
|
||||
{foreach $menu['children'] as $m}
|
||||
{if (!empty($m['children']))}
|
||||
<a><i class="layui-icon layui-icon-home"></i> <cite>{$m['permission_name']}</cite></a>
|
||||
<dl class="layui-nav-child">
|
||||
<dd><a>四级菜单</a></dd>
|
||||
<dd>
|
||||
<a>四级菜单</a>
|
||||
<dl class="layui-nav-child">
|
||||
<dd><a>五级菜单</a></dd>
|
||||
<dd>
|
||||
<a lay-href="https://baidu.com">百度一下</a>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
{foreach $m['children'] as $_m}
|
||||
<dd><a lay-href="{:url($_m['route'])}">{$_m['permission_name']}</a></dd>
|
||||
{/foreach}
|
||||
</dl>
|
||||
</dd>
|
||||
{else/}
|
||||
<dd><a lay-href="{:url($m['route'])}">{$m['permission_name']}</a></dd>
|
||||
{/if}
|
||||
{/foreach}
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</li>
|
||||
<li class="layui-nav-item">
|
||||
<a lay-href="//baidu.com"><i class="layui-icon layui-icon-unlink"></i> <cite>一级菜单</cite></a>
|
||||
</li>
|
||||
{else/}
|
||||
<a lay-href="{:url($menu['route'])}"><i class="layui-icon layui-icon-unlink"></i> <cite>{$menu['permission_name']}</cite></a>
|
||||
{/if}
|
||||
</li>
|
||||
{/foreach}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@ -220,7 +102,7 @@
|
||||
<div class="layui-body"></div>
|
||||
<!-- 底部 -->
|
||||
<div class="layui-footer">
|
||||
copyright 2017 ~ © {:date('Y', time())} <a href="http://easyweb.vip" target="_blank">catchadmin.com</a> all rights reserved.
|
||||
copyright 2017 ~ © {:date('Y', time())} <a href="https://catchadmin.com" target="_blank">catchadmin.com</a> all rights reserved.
|
||||
<span class="pull-right">Version 2.0</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -236,17 +118,25 @@
|
||||
<script type="text/javascript" src="__CATCH_ADMIN_LIBS__/layui/layui.js"></script>
|
||||
<script type="text/javascript" src="__CATCH_ADMIN_JS__/common.js?v=315"></script>
|
||||
<script>
|
||||
layui.use(['index'], function () {
|
||||
layui.use(['index', 'admin'], function () {
|
||||
var $ = layui.jquery;
|
||||
var index = layui.index;
|
||||
var admin = layui.admin;
|
||||
|
||||
// 默认加载主页
|
||||
index.loadHome({
|
||||
menuPath: 'page/console/console.html',
|
||||
menuPath: '{:url("dashboard")}',
|
||||
menuName: '<i class="layui-icon layui-icon-home"></i>'
|
||||
});
|
||||
|
||||
$(document).on('click','#logout',function(){
|
||||
admin.req('{:url("logout")}', {}, function (response) {
|
||||
if (response.code === 10000) {
|
||||
window.location.href = "{:url('login')}";
|
||||
}
|
||||
}, 'post')
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
259
catchAdmin/index/view/theme.html
Normal file
259
catchAdmin/index/view/theme.html
Normal file
@ -0,0 +1,259 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" class="bg-white">
|
||||
<head>
|
||||
<title>设置</title>
|
||||
<meta charset="utf-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<link rel="stylesheet" href="__CATCH_ADMIN_LIBS__/layui/css/layui.css"/>
|
||||
<link rel="stylesheet" href="__CATCH_ADMIN_MODULE__/admin.css?v=315"/>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
|
||||
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
|
||||
<![endif]-->
|
||||
<style>
|
||||
body {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.layui-card-body {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.theme-div {
|
||||
padding-left: 15px;
|
||||
padding-top: 20px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.btnTheme {
|
||||
display: inline-block;
|
||||
margin: 0 6px 15px 0;
|
||||
padding: 4px;
|
||||
border: 1px solid #fff;
|
||||
}
|
||||
|
||||
.btnTheme img {
|
||||
width: 80px;
|
||||
height: 50px;
|
||||
border: 1px solid #f2f2f2;
|
||||
background: #F2F2F2;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.btnTheme:hover, .btnTheme.active {
|
||||
border-color: #5FB878;
|
||||
}
|
||||
|
||||
.more-menu-item {
|
||||
display: block;
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
font-size: 16px;
|
||||
border-bottom: 1px solid #e8e8e8;
|
||||
color: #333;
|
||||
padding: 0px 25px;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.more-menu-item:first-child {
|
||||
border-top: 1px solid #e8e8e8;
|
||||
}
|
||||
|
||||
.more-menu-item:hover {
|
||||
background: #F2F2F2;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.more-menu-item .layui-icon {
|
||||
padding-right: 10px;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.more-menu-item:after {
|
||||
content: "\e602";
|
||||
font-family: layui-icon !important;
|
||||
position: absolute;
|
||||
right: 16px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.more-menu-item.no-icon:after {
|
||||
content: "";
|
||||
}
|
||||
|
||||
/** 设置表单样式 */
|
||||
.set-item-label {
|
||||
display: inline-block;
|
||||
height: 38px;
|
||||
line-height: 38px;
|
||||
padding-left: 20px;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.set-item-ctrl {
|
||||
display: inline-block;
|
||||
height: 38px;
|
||||
line-height: 38px;
|
||||
}
|
||||
|
||||
.set-item-ctrl > * {
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- 加载动画 -->
|
||||
<div class="page-loading">
|
||||
<div class="ball-loader">
|
||||
<span></span><span></span><span></span><span></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-card-header">设置主题</div>
|
||||
<div class="layui-card-body">
|
||||
<!-- 主题列表 -->
|
||||
<div class="theme-div"></div>
|
||||
|
||||
<!-- 导航 -->
|
||||
<div class="more-menu">
|
||||
<a class="more-menu-item" href="https://gitee.com/jaguarjack/catchAdmin" target="_blank">
|
||||
<i class="layui-icon layui-icon-read" style="font-size: 19px;"></i> Git 地址
|
||||
</a>
|
||||
<a class="more-menu-item" href="https://catchadmin.com" target="_blank">
|
||||
<i class="layui-icon layui-icon-tabs" style="font-size: 16px;"></i> 官网
|
||||
</a>
|
||||
<!--<a class="more-menu-item" href="https://demo.easyweb.vip/theme" target="_blank">
|
||||
<i class="layui-icon layui-icon-theme"></i> 主题生成器
|
||||
</a>-->
|
||||
</div>
|
||||
|
||||
<!-- 控制开关 -->
|
||||
<div class="layui-form" style="margin: 25px 0;">
|
||||
<div class="layui-form-item">
|
||||
<label class="set-item-label">页 脚:</label>
|
||||
<div class="set-item-ctrl">
|
||||
<input id="setFooter" lay-filter="setFooter" type="checkbox" lay-skin="switch" lay-text="开启|关闭">
|
||||
</div>
|
||||
<label class="set-item-label"> Tab 记忆:</label>
|
||||
<div class="set-item-ctrl">
|
||||
<input id="setTab" lay-filter="setTab" type="checkbox" lay-skin="switch" lay-text="开启|关闭">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="set-item-label">多标签:</label>
|
||||
<div class="set-item-ctrl">
|
||||
<input id="setMoreTab" lay-filter="setMoreTab" type="checkbox" lay-skin="switch" lay-text="开启|关闭">
|
||||
</div>
|
||||
<label class="set-item-label">切换刷新:</label>
|
||||
<div class="set-item-ctrl">
|
||||
<input id="setRefresh" lay-filter="setRefresh" type="checkbox" lay-skin="switch" lay-text="开启|关闭">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="set-item-label">导航箭头:</label>
|
||||
<div class="set-item-ctrl">
|
||||
<input lay-filter="navArrow" type="radio" value="" title="默认" name="navArrow">
|
||||
<input lay-filter="navArrow" type="radio" value="arrow2" title="箭头" name="navArrow">
|
||||
<input lay-filter="navArrow" type="radio" value="arrow3" title="加号" name="navArrow">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script type="text/javascript" src="__CATCH_ADMIN_LIBS__/layui/layui.js"></script>
|
||||
<script type="text/javascript" src="__CATCH_ADMIN_JS__/common.js?v=315"></script>
|
||||
<script>
|
||||
layui.use(['layer', 'form', 'admin'], function () {
|
||||
var $ = layui.jquery;
|
||||
var layer = layui.layer;
|
||||
var form = layui.form;
|
||||
var admin = layui.admin;
|
||||
var leftNav = '.layui-layout-admin>.layui-side>.layui-side-scroll>.layui-nav';
|
||||
var mainTab = '.layui-body>.layui-tab[lay-filter="admin-pagetabs"]';
|
||||
|
||||
var themes = [
|
||||
{title: '黑白主题', theme: 'admin'},
|
||||
{title: '黑色主题', theme: 'black'},
|
||||
{title: '蓝色主题', theme: 'blue'},
|
||||
{title: '藏青主题', theme: 'cyan'},
|
||||
{title: '黄色主题', theme: 'yellow'},
|
||||
{title: '绿色主题', theme: 'green'},
|
||||
{title: '粉红主题', theme: 'pink'},
|
||||
{title: '紫白主题', theme: 'purple-white'},
|
||||
{title: '紫色主题', theme: 'purple'},
|
||||
{title: '白色主题', theme: 'white'},
|
||||
{title: '红白主题', theme: 'red-white'},
|
||||
{title: '红色主题', theme: 'red'}
|
||||
];
|
||||
for (var i = 0; i < themes.length; i++) {
|
||||
var str = '<div class="btnTheme" theme="theme-' + themes[i].theme + '" title="' + themes[i].title + '">';
|
||||
str += ' <img src="__CATCH_ADMIN_MODULE__/theme/img/theme-' + themes[i].theme + '.png">';
|
||||
str += ' </div>';
|
||||
$('.theme-div').append(str)
|
||||
}
|
||||
|
||||
// 切换主题
|
||||
var mTheme = layui.data(admin.tableName).theme;
|
||||
$('.btnTheme[theme=' + (mTheme ? mTheme : admin.defaultTheme) + ']').addClass('active');
|
||||
$('.btnTheme').click(function () {
|
||||
$('.btnTheme').removeClass('active');
|
||||
$(this).addClass('active');
|
||||
admin.changeTheme($(this).attr('theme'));
|
||||
});
|
||||
|
||||
// 关闭/开启页脚
|
||||
var openFooter = layui.data(admin.tableName).openFooter;
|
||||
$('#setFooter').prop('checked', openFooter == undefined ? true : openFooter);
|
||||
form.on('switch(setFooter)', function (data) {
|
||||
var checked = data.elem.checked;
|
||||
layui.data(admin.tableName, {key: 'openFooter', value: checked});
|
||||
checked ? top.layui.jquery('body.layui-layout-body').removeClass('close-footer') : top.layui.jquery('body.layui-layout-body').addClass('close-footer');
|
||||
});
|
||||
|
||||
// 关闭/开启Tab记忆功能
|
||||
$('#setTab').prop('checked', top.layui.index.cacheTab);
|
||||
form.on('switch(setTab)', function (data) {
|
||||
top.layui.index.setTabCache(data.elem.checked);
|
||||
});
|
||||
|
||||
// 切换Tab自动刷新
|
||||
var tabAutoRefresh = layui.data(admin.tableName).tabAutoRefresh;
|
||||
$('#setRefresh').prop('checked', tabAutoRefresh == undefined ? false : tabAutoRefresh);
|
||||
form.on('switch(setRefresh)', function (data) {
|
||||
var checked = data.elem.checked;
|
||||
layui.data(admin.tableName, {key: 'tabAutoRefresh', value: checked});
|
||||
checked ? top.layui.jquery(mainTab).attr('lay-autoRefresh', 'true') : top.layui.jquery(mainTab).removeAttr('lay-autoRefresh');
|
||||
});
|
||||
|
||||
// 关闭/开启多标签
|
||||
var openTab = layui.data(admin.tableName).openTab;
|
||||
$('#setMoreTab').prop('checked', openTab == undefined ? top.layui.index.pageTabs : openTab);
|
||||
form.on('switch(setMoreTab)', function (data) {
|
||||
var checked = data.elem.checked;
|
||||
layui.data(admin.tableName, {key: 'openTab', value: checked});
|
||||
admin.putTempData('indexTabs', undefined); // 清除缓存的Tab
|
||||
top.location.reload();
|
||||
});
|
||||
|
||||
// 导航小三角
|
||||
var navArrow = layui.data(admin.tableName).navArrow;
|
||||
if (navArrow == undefined) {
|
||||
var $sideNav = top.layui.jquery('.layui-side .layui-nav-tree');
|
||||
navArrow = $sideNav.hasClass('arrow2') ? 'arrow2' : $sideNav.hasClass('arrow3') ? 'arrow3' : '';
|
||||
}
|
||||
$('[name="navArrow"][value="' + (navArrow ? navArrow : '') + '"]').prop('checked', 'true');
|
||||
form.on('radio(navArrow)', function (data) {
|
||||
layui.data(admin.tableName, {key: 'navArrow', value: data.value});
|
||||
top.layui.jquery(leftNav).removeClass('arrow2 arrow3');
|
||||
data.value && top.layui.jquery(leftNav).addClass(data.value);
|
||||
});
|
||||
|
||||
form.render('checkbox');
|
||||
form.render('radio');
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -1,56 +0,0 @@
|
||||
<?php
|
||||
namespace catchAdmin\login;
|
||||
|
||||
use app\exceptions\LoginFailedException;
|
||||
use think\Db;
|
||||
use think\facade\Session;
|
||||
|
||||
class Auth
|
||||
{
|
||||
protected $loginUser = 'admin_user';
|
||||
|
||||
/**
|
||||
* Auth constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->loginUser = md5($this->loginUser);
|
||||
}
|
||||
|
||||
/**
|
||||
* 登陆
|
||||
*
|
||||
* @time 2019年11月28日
|
||||
* @param $params
|
||||
* @throws LoginFailedException
|
||||
* @return bool
|
||||
*/
|
||||
public function login($params)
|
||||
{
|
||||
$user = Db::table('admin_users')
|
||||
->where('name', $params['name'])
|
||||
// ->where('password', $params['password'])
|
||||
->first();
|
||||
|
||||
if (!password_verify($params('password'), $user->password)) {
|
||||
throw new LoginFailedException('登陆失败, 请检查用户名和密码');
|
||||
}
|
||||
|
||||
Session::set($this->loginUser, $user);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 退出登陆
|
||||
*
|
||||
* @time 2019年11月28日
|
||||
* @return bool
|
||||
*/
|
||||
public function logout()
|
||||
{
|
||||
Session::delete($this->loginUser);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
81
catchAdmin/login/LoginLogListener.php
Normal file
81
catchAdmin/login/LoginLogListener.php
Normal file
@ -0,0 +1,81 @@
|
||||
<?php
|
||||
namespace catchAdmin\login;
|
||||
|
||||
use catchAdmin\user\model\Users;
|
||||
use think\facade\Db;
|
||||
|
||||
class LoginLogListener
|
||||
{
|
||||
public function handle($params)
|
||||
{
|
||||
$agent = request()->header('user-agent');
|
||||
|
||||
$username = Users::where('email', $params['email'])->value('username');
|
||||
|
||||
Db::name('login_log')->insert([
|
||||
'login_name' => $username ? : $params['email'],
|
||||
'login_ip' => request()->ip(),
|
||||
'browser' => $this->getBrowser($agent),
|
||||
'os' => $this->getOs($agent),
|
||||
'login_at' => time(),
|
||||
'status' => $params['success'] ? 1 : 2,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月12日
|
||||
* @param $agent
|
||||
* @return string
|
||||
*/
|
||||
private function getOs($agent): string
|
||||
{
|
||||
if (false !== stripos($agent, 'win') && preg_match('/nt 6.1/i', $agent)) {
|
||||
return 'Windows 7';
|
||||
}
|
||||
if (false !== stripos($agent, 'win') && preg_match('/nt 6.2/i', $agent)) {
|
||||
return 'Windows 8';
|
||||
}
|
||||
if(false !== stripos($agent, 'win') && preg_match('/nt 10.0/i', $agent)) {
|
||||
return 'Windows 10';#添加win10判断
|
||||
}
|
||||
if (false !== stripos($agent, 'win') && preg_match('/nt 5.1/i', $agent)) {
|
||||
return 'Windows XP';
|
||||
}
|
||||
if (false !== stripos($agent, 'linux')) {
|
||||
return 'Linux';
|
||||
}
|
||||
if (false !== stripos($agent, 'mac')) {
|
||||
return 'mac';
|
||||
}
|
||||
|
||||
return '未知';
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月12日
|
||||
* @param $agent
|
||||
* @return string
|
||||
*/
|
||||
private function getBrowser($agent): string
|
||||
{
|
||||
if (false !== stripos($agent, "MSIE")) {
|
||||
return 'MSIE';
|
||||
}
|
||||
if (false !== stripos($agent, "Firefox")) {
|
||||
return 'Firefox';
|
||||
}
|
||||
if (false !== stripos($agent, "Chrome")) {
|
||||
return 'Chrome';
|
||||
}
|
||||
if (false !== stripos($agent, "Safari")) {
|
||||
return 'Safari';
|
||||
}
|
||||
if (false !== stripos($agent, "Opera")) {
|
||||
return 'Opera';
|
||||
}
|
||||
|
||||
return '未知';
|
||||
}
|
||||
}
|
@ -1,11 +1,14 @@
|
||||
<?php
|
||||
namespace catchAdmin\login\controller;
|
||||
|
||||
use catchAdmin\login\Auth;
|
||||
use app\exceptions\LoginFailedException;
|
||||
use catchAdmin\user\Auth;
|
||||
use catchAdmin\login\request\LoginRequest;
|
||||
use catcher\base\BaseController;
|
||||
use catcher\base\CatchController;
|
||||
use catcher\CatchResponse;
|
||||
use think\captcha\Captcha;
|
||||
|
||||
class Index extends BaseController
|
||||
class Index extends CatchController
|
||||
{
|
||||
/**
|
||||
* 登录
|
||||
@ -25,25 +28,48 @@ class Index extends BaseController
|
||||
* @time 2019年11月28日
|
||||
* @param LoginRequest $request
|
||||
* @return bool|string
|
||||
* @throws \app\exceptions\LoginFailedException
|
||||
* @throws \catcher\exceptions\LoginFailedException
|
||||
* @throws \cather\exceptions\LoginFailedException
|
||||
* @throws LoginFailedException
|
||||
*/
|
||||
public function login(LoginRequest $request)
|
||||
{
|
||||
(new Auth())->login($request->post());
|
||||
$params = $request->param();
|
||||
$isSucceed = Auth::login($params);
|
||||
// 登录事件
|
||||
$params['success'] = $isSucceed;
|
||||
event('loginLog', $params);
|
||||
|
||||
return $isSucceed ? CatchResponse::success('', '登录成功') :
|
||||
|
||||
CatchResponse::success('', '登录失败');
|
||||
}
|
||||
|
||||
/**
|
||||
* 登出
|
||||
*
|
||||
* @time 2019年11月28日
|
||||
* @return bool
|
||||
* @return \think\response\Json
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function logout(): bool
|
||||
public function logout(): \think\response\Json
|
||||
{
|
||||
if ((new Auth())->logout()) {
|
||||
return redirect(url('login'));
|
||||
if (Auth::logout()) {
|
||||
return CatchResponse::success();
|
||||
}
|
||||
|
||||
return false;
|
||||
return CatchResponse::fail('登出失败');
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月12日
|
||||
* @param Captcha $captcha
|
||||
* @param null $config
|
||||
* @return \think\Response
|
||||
*/
|
||||
public function captcha(Captcha $captcha, $config = null): \think\Response
|
||||
{
|
||||
return $captcha->create($config);
|
||||
}
|
||||
}
|
@ -1,15 +1,15 @@
|
||||
<?php
|
||||
namespace catchAdmin\login\request;
|
||||
|
||||
use catcher\base\BaseRequest;
|
||||
use catcher\base\CatchRequest;
|
||||
|
||||
class LoginRequest extends BaseRequest
|
||||
class LoginRequest extends CatchRequest
|
||||
{
|
||||
protected function rules(): array
|
||||
{
|
||||
// TODO: Implement rules() method.
|
||||
return [
|
||||
'name|用户名' => 'require|max:25',
|
||||
'email|用户名' => 'email',
|
||||
'password|密码' => 'require',
|
||||
'captcha|验证码' => 'require|captcha'
|
||||
];
|
||||
|
@ -1,8 +1,11 @@
|
||||
<?php
|
||||
|
||||
# 登陆页面
|
||||
$router->get('login', '\catchAdmin\login\controller\Index/index');
|
||||
$router->get('login', '\catchAdmin\login\controller\Index@index');
|
||||
# 登入
|
||||
$router->post('login', '\catchAdmin\login\controller\Index/login');
|
||||
$router->post('login', '\catchAdmin\login\controller\Index@login');
|
||||
# 登出
|
||||
$router->post('logout', '\catchAdmin\login\controller\Index/logout');
|
||||
$router->post('logout', '\catchAdmin\login\controller\Index@logout');
|
||||
# 验证码
|
||||
$router->get('catch/captcha/[:config]','\catchAdmin\login\controller\Index@captcha');
|
||||
|
||||
|
@ -1,18 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace catchAdmin\login\validate;
|
||||
|
||||
use catcher\base\BaseValidate;
|
||||
|
||||
class LoginValidate extends BaseValidate
|
||||
{
|
||||
protected function getRules(): array
|
||||
{
|
||||
// TODO: Implement getRules() method.
|
||||
return [
|
||||
'name|用户名' => 'require|max:25',
|
||||
'password|密码' => 'require',
|
||||
'captcha|验证码' => 'require|captcha'
|
||||
];
|
||||
}
|
||||
}
|
@ -27,7 +27,7 @@
|
||||
<body>
|
||||
<div class="login-wrapper">
|
||||
<div class="login-header">
|
||||
<img src="/static/assets/images/logo.png"> EasyWeb后台开发框架
|
||||
<img src="__CATCH_ADMIN_IMAGES__/logo.png"> CatchAdmin 后台管理系统
|
||||
</div>
|
||||
<div class="login-body">
|
||||
<div class="layui-card">
|
||||
@ -38,8 +38,8 @@
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label"><i class="layui-icon layui-icon-username"></i></label>
|
||||
<div class="layui-input-block">
|
||||
<input name="name" type="text" placeholder="账号" class="layui-input"
|
||||
lay-verType="tips" lay-verify="required" required/>
|
||||
<input name="email" type="text" placeholder="邮箱" class="layui-input"
|
||||
lay-verType="tips" lay-verify="required|email" required/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
@ -58,7 +58,7 @@
|
||||
autocomplete="off" lay-verType="tips" lay-verify="required" required/>
|
||||
</div>
|
||||
<div class="layui-col-xs5" style="padding-left: 6px;">
|
||||
<img src="{:captcha_src()}" alt="captcha" class="captcha" onclick="this.src = this.src + '?t=' + (new Date).getTime();"/>
|
||||
<img src="{:url('catch/captcha')}" alt="captcha" class="captcha" onclick="this.src = this.src + '?t=' + (new Date).getTime();"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -81,7 +81,7 @@
|
||||
</div>
|
||||
|
||||
<div class="login-footer">
|
||||
<p>© 2015 ~ {:date('Y', time())} @Lawyer 版权所有</p>
|
||||
<p>© 2015 ~ {:date('Y', time())} @catchAdmin 版权所有</p>
|
||||
<!--<p>
|
||||
<span><a href="https://easyweb.vip" target="_blank">获取授权</a></span>
|
||||
<span><a href="https://easyweb.vip/doc/" target="_blank">开发文档</a></span>
|
||||
@ -106,7 +106,20 @@
|
||||
type: 'post',
|
||||
data: obj.field,
|
||||
success: function(response) {
|
||||
layer.msg(response.msg)
|
||||
if (response.code === 10000) {
|
||||
layer.msg(response.msg, {
|
||||
icon: 1,
|
||||
time: 2000 //2秒关闭(如果不配置,默认是3秒)
|
||||
}, function () {
|
||||
//do something
|
||||
window.location.href = '/';
|
||||
})
|
||||
} else {
|
||||
layer.msg(response.msg, {
|
||||
icon: 2,
|
||||
time: 2000 //2秒关闭(如果不配置,默认是3秒)
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
return false;
|
||||
|
28
catchAdmin/permissions/OperateLogListener.php
Normal file
28
catchAdmin/permissions/OperateLogListener.php
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace catchAdmin\permissions;
|
||||
|
||||
use catchAdmin\permissions\model\Permissions;
|
||||
use catcher\CatchAdmin;
|
||||
use think\facade\Db;
|
||||
|
||||
class OperateLogListener
|
||||
{
|
||||
public function handle($params)
|
||||
{
|
||||
$request = $params['request'];
|
||||
$permission = $params['permission'];
|
||||
|
||||
$parentPermission = Permissions::where('id', $permission->parent_id)->value('permission_name');
|
||||
Db::name('operate_log')->insert([
|
||||
'creator_id' => $request->user()->id,
|
||||
'module' => $parentPermission ? : '',
|
||||
'method' => $request->method(),
|
||||
'operate' => $permission->permission_name,
|
||||
'route' => $permission->route,
|
||||
'params' => json_encode($request->param()),
|
||||
'created_at' => time(),
|
||||
'ip' => $request->ip(),
|
||||
]);
|
||||
}
|
||||
}
|
98
catchAdmin/permissions/PermissionsMiddleware.php
Normal file
98
catchAdmin/permissions/PermissionsMiddleware.php
Normal file
@ -0,0 +1,98 @@
|
||||
<?php
|
||||
namespace catchAdmin\permissions;
|
||||
|
||||
use app\Request;
|
||||
use catchAdmin\permissions\model\Permissions;
|
||||
use catcher\exceptions\PermissionForbiddenException;
|
||||
use think\helper\Str;
|
||||
|
||||
class PermissionsMiddleware
|
||||
{
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月12日
|
||||
* @param Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
* @throws PermissionForbiddenException
|
||||
*/
|
||||
public function handle(Request $request, \Closure $next)
|
||||
{
|
||||
$rule = $rule = $request->rule()->getName();
|
||||
|
||||
if (!$rule) {
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
[$module, $controller, $action] = $this->parseRule($rule);
|
||||
|
||||
if (in_array($module, $this->ignoreModule())) {
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
if (!$request->user()) {
|
||||
throw new PermissionForbiddenException('Login is invalid', 10006);
|
||||
}
|
||||
|
||||
// toad
|
||||
if (($permission = $this->getPermission($module, $controller, $action, $request))
|
||||
&& !in_array($permission->id, $request->user()->getPermissionsBy())) {
|
||||
throw new PermissionForbiddenException();
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
protected function parseRule($rule)
|
||||
{
|
||||
[$controller, $action] = explode(Str::contains($rule, '@') ? '@' : '/', $rule);
|
||||
|
||||
$controller = explode('\\', $controller);
|
||||
|
||||
$controllerName = strtolower(array_pop($controller));
|
||||
|
||||
array_pop($controller);
|
||||
|
||||
$module = array_pop($controller);
|
||||
|
||||
return [$module, $controllerName, $action];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月14日
|
||||
* @param $module
|
||||
* @param $controllerName
|
||||
* @param $action
|
||||
* @param $request
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
* @return array|bool|\think\Model|null
|
||||
*/
|
||||
protected function getPermission($module, $controllerName, $action, $request)
|
||||
{
|
||||
$permissionMark = sprintf('%s:%s', $controllerName, $action);
|
||||
$permission = Permissions::where('module', $module)->where('permission_mark', $permissionMark)->find();
|
||||
|
||||
if (!$permission) {
|
||||
return false;
|
||||
}
|
||||
|
||||
event('operateLog', [
|
||||
'request' => $request,
|
||||
'permission' => $permission,
|
||||
]);
|
||||
|
||||
return $permission;
|
||||
}
|
||||
|
||||
protected function ignoreModule()
|
||||
{
|
||||
return ['login'];
|
||||
}
|
||||
}
|
166
catchAdmin/permissions/controller/Permission.php
Normal file
166
catchAdmin/permissions/controller/Permission.php
Normal file
@ -0,0 +1,166 @@
|
||||
<?php
|
||||
namespace catchAdmin\permissions\controller;
|
||||
|
||||
|
||||
use app\Request;
|
||||
use catcher\base\CatchController;
|
||||
use catcher\CatchAdmin;
|
||||
use catcher\CatchForm;
|
||||
use catcher\CatchResponse;
|
||||
use catcher\exceptions\FailedException;
|
||||
use catcher\Tree;
|
||||
use catchAdmin\permissions\model\Permissions as Permissions;
|
||||
|
||||
class Permission extends CatchController
|
||||
{
|
||||
protected $permissions;
|
||||
|
||||
public function __construct(Permissions $permissions)
|
||||
{
|
||||
$this->permissions = $permissions;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月11日
|
||||
* @throws \Exception
|
||||
* @return string
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return $this->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月11日
|
||||
* @param Request $request
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function list(Request $request)
|
||||
{
|
||||
return CatchResponse::success(Tree::done($this->permissions->getList($request->param())));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月11日
|
||||
* @throws \Exception
|
||||
* @return string
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
$form = new CatchForm();
|
||||
$form->formId('permission');
|
||||
$form->text('permission_name', '菜单名称', true)->verify('required')->placeholder('请输入菜单名称');
|
||||
$form->hidden('parent_id')->default(\request()->param('id') ?? 0);
|
||||
$form->select('module', '模块', true)->verify('required')->options(CatchAdmin::getModulesInfo());
|
||||
$form->text('route', '路由')->placeholder('请输入路由');
|
||||
$form->radio('method', '请求方法', true)->default(Permissions::GET)->options([
|
||||
['value' => Permissions::GET, 'title' => 'get'],
|
||||
['value' => Permissions::POST, 'title' => 'post'],
|
||||
['value' => Permissions::PUT, 'title' => 'put'],
|
||||
['value' => Permissions::DELETE, 'title' => 'delete'],
|
||||
]);
|
||||
$form->text('permission_mark', '权限标识', true)->verify('required')->placeholder('请输入权限标识controller:action');
|
||||
$form->radio('type', '类型', true)->default(Permissions::BTN_TYPE)->options([
|
||||
['value' => Permissions::MENU_TYPE, 'title' => '菜单'],
|
||||
['value' => Permissions::BTN_TYPE, 'title' => '按钮'],
|
||||
]);
|
||||
$form->text('sort', '排序')->verify('numberX')->default(1)->placeholder('倒叙排序');
|
||||
$form->formBtn('submitPermission');
|
||||
|
||||
return $this->fetch(['form' => $form->render()]);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月11日
|
||||
* @param Request $request
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function save(Request $request)
|
||||
{
|
||||
return CatchResponse::success($this->permissions->storeBy($request->param()));
|
||||
}
|
||||
|
||||
public function read()
|
||||
{}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月11日
|
||||
* @param $id
|
||||
* @throws \Exception
|
||||
* @return string
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
$permission = $this->permissions->findBy($id);
|
||||
|
||||
$form = new CatchForm();
|
||||
$form->formId('permission');
|
||||
$form->text('permission_name', '菜单名称', true)
|
||||
->default($permission->permission_name)
|
||||
->verify('required')
|
||||
->placeholder('请输入菜单名称');
|
||||
$form->hidden('parent_id')->default($permission->parent_id);
|
||||
$form->select('module', '模块', true)->default($permission->module)->options(CatchAdmin::getModulesInfo());
|
||||
$form->text('route', '路由')->default($permission->route)->placeholder('请输入路由');
|
||||
$form->radio('method', '请求方法', true)->verify('required')->default($permission->method)->options([
|
||||
['value' => Permissions::GET, 'title' => 'get'],
|
||||
['value' => Permissions::POST, 'title' => 'post'],
|
||||
['value' => Permissions::PUT, 'title' => 'put'],
|
||||
['value' => Permissions::DELETE, 'title' => 'delete'],
|
||||
]);
|
||||
$form->text('permission_mark', '权限标识', true)
|
||||
->default($permission->permission_mark)
|
||||
->verify('required')->placeholder('请输入权限标识controller:action');
|
||||
$form->radio('type', '类型', true)->default($permission->type)->options([
|
||||
['value' => Permissions::MENU_TYPE, 'title' => '菜单'],
|
||||
['value' => Permissions::BTN_TYPE, 'title' => '按钮'],
|
||||
]);
|
||||
$form->text('sort', '排序')->verify('numberX')->default($permission->sort)->placeholder('倒叙排序');
|
||||
$form->formBtn('submitPermission');
|
||||
|
||||
return $this->fetch([
|
||||
'form' => $form->render(),
|
||||
'permission_id' => $permission->id,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月11日
|
||||
* @param $id
|
||||
* @param Request $request
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function update($id, Request $request)
|
||||
{
|
||||
return CatchResponse::success($this->permissions->updateBy($id, $request->param()));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月11日
|
||||
* @param $id
|
||||
* @throws FailedException
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function delete($id)
|
||||
{
|
||||
if ($this->permissions->where('parent_id', $id)->find()) {
|
||||
throw new FailedException('存在子菜单,无法删除');
|
||||
}
|
||||
|
||||
$this->permissions->findBy($id)->roles()->detach();
|
||||
|
||||
return CatchResponse::success($this->permissions->deleteBy($id));
|
||||
}
|
||||
}
|
||||
|
||||
|
197
catchAdmin/permissions/controller/Role.php
Normal file
197
catchAdmin/permissions/controller/Role.php
Normal file
@ -0,0 +1,197 @@
|
||||
<?php
|
||||
namespace catchAdmin\permissions\controller;
|
||||
|
||||
use app\Request;
|
||||
use catcher\base\CatchController;
|
||||
use catcher\CatchForm;
|
||||
use catcher\CatchResponse;
|
||||
use catcher\exceptions\FailedException;
|
||||
use catcher\Tree;
|
||||
use think\response\Json;
|
||||
|
||||
class Role extends CatchController
|
||||
{
|
||||
protected $role;
|
||||
|
||||
public function __construct(\catchAdmin\permissions\model\Roles $role)
|
||||
{
|
||||
$this->role = $role;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月09日
|
||||
* @throws \Exception
|
||||
* @return string
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return $this->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月11日
|
||||
* @throws \Exception
|
||||
* @return string
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
$form = new CatchForm();
|
||||
$form->formId('role');
|
||||
$form->text('role_name', '角色名称', true)->verify('required')->placeholder('请输入角色名称');
|
||||
$form->hidden('parent_id')->default(\request()->param('id') ?? 0);
|
||||
$form->textarea('description', '角色描述')->placeholder('请输入角色描述');
|
||||
$form->dom('<div id="permissions"></div>', '权限');
|
||||
$form->formBtn('submitRole');
|
||||
|
||||
return $this->fetch([
|
||||
'form' => $form->render(),
|
||||
'parent_id' => \request()->param('id') ?? 0,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月11日
|
||||
* @param Request $request
|
||||
* @return Json
|
||||
* @throws \think\db\exception\DbException
|
||||
*/
|
||||
public function save(Request $request)
|
||||
{
|
||||
$this->role->storeBy($request->param());
|
||||
|
||||
if (!empty($request->param('permissionids'))) {
|
||||
$this->role->attach($request->param('permissionids'));
|
||||
}
|
||||
// 添加角色
|
||||
return CatchResponse::success();
|
||||
}
|
||||
|
||||
public function read($id)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月11日
|
||||
* @param $id
|
||||
* @throws \Exception
|
||||
* @return string
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
$role = $this->role->findBy($id);
|
||||
|
||||
$form = new CatchForm();
|
||||
$form->formId('role');
|
||||
$form->hidden('parent_id')->default($role->parent_id);
|
||||
$form->text('role_name', '角色名称', true)->default($role->name)->verify('required')->placeholder('请输入角色名称');
|
||||
$form->textarea('description', '角色描述')->default($role->description)->placeholder('请输入角色描述');
|
||||
$form->dom('<div id="permissions"></div>', '权限');
|
||||
$form->formBtn('submitRole');
|
||||
|
||||
return $this->fetch([
|
||||
'form' => $form->render(),
|
||||
'role_id' => $role->id,
|
||||
'parent_id' => $role->parent_id
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月11日
|
||||
* @param $id
|
||||
* @param Request $request
|
||||
* @return Json
|
||||
* @throws \think\db\exception\DbException
|
||||
*/
|
||||
public function update($id, Request $request)
|
||||
{
|
||||
$this->role->updateBy($id, $request->param());
|
||||
|
||||
$role = $this->role->findBy($id);
|
||||
|
||||
$role->detach();
|
||||
|
||||
if (!empty($request->param('permissionids'))) {
|
||||
$role->attach($request->param('permissionids'));
|
||||
}
|
||||
|
||||
return CatchResponse::success();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月11日
|
||||
* @param $id
|
||||
* @throws FailedException
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
* @return Json
|
||||
*/
|
||||
public function delete($id)
|
||||
{
|
||||
if ($this->role->where('parent_id', $id)->find()) {
|
||||
throw new FailedException('存在子角色,无法删除');
|
||||
}
|
||||
$role = $this->role->findBy($id);
|
||||
// 删除权限
|
||||
$role->detach();
|
||||
// 删除用户关联
|
||||
$role->users()->detach();
|
||||
// 删除
|
||||
$this->role->deleteBy($id);
|
||||
|
||||
return CatchResponse::success();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月11日
|
||||
* @param Request $request
|
||||
* @return Json
|
||||
*/
|
||||
public function list(Request $request)
|
||||
{
|
||||
return CatchResponse::success(Tree::done($this->role->getList($request->param())));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @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 = null;
|
||||
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($permission->getList([
|
||||
'permission_ids' => $parentRoleHasPermissionIds
|
||||
]));
|
||||
|
||||
$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,
|
||||
]);
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
use think\migration\Migrator;
|
||||
use think\migration\db\Column;
|
||||
|
||||
class Roles extends Migrator
|
||||
{
|
||||
/**
|
||||
* Change Method.
|
||||
*
|
||||
* Write your reversible migrations using this method.
|
||||
*
|
||||
* More information on writing migrations is available here:
|
||||
* http://docs.phinx.org/en/latest/migrations.html#the-abstractmigration-class
|
||||
*
|
||||
* The following commands can be used in this method and Phinx will
|
||||
* automatically reverse them when rolling back:
|
||||
*
|
||||
* createTable
|
||||
* renameTable
|
||||
* addColumn
|
||||
* renameColumn
|
||||
* addIndex
|
||||
* addForeignKey
|
||||
*
|
||||
* Remember to call "create()" or "update()" and NOT "save()" when working
|
||||
* with the Table class.
|
||||
*/
|
||||
public function change()
|
||||
{
|
||||
$table = $this->table('roles',['engine'=>'Innodb', 'comment' => '角色表', 'signed' => false]);
|
||||
$table->addColumn('role_name', 'string',['limit' => 15,'default'=>'','comment'=>'角色名'])
|
||||
->addColumn('parent_id', 'integer',['default'=>0,'comment'=>'父级ID', 'signed' => false])
|
||||
->addColumn('description', 'string',['default'=> '','comment'=>'角色备注'])
|
||||
->addColumn('created_at', 'integer', array('default'=>0,'comment'=>'创建时间', 'signed' => false ))
|
||||
->addColumn('updated_at', 'integer', array('default'=>0,'comment'=>'更新时间', 'signed' => false))
|
||||
->addColumn('deleted_at', 'integer', array('default'=>0,'comment'=>'删除状态,0未删除 >0 已删除', 'signed' => false))
|
||||
->create();
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
use think\migration\Migrator;
|
||||
use think\migration\db\Column;
|
||||
|
||||
class Permissions extends Migrator
|
||||
{
|
||||
/**
|
||||
* Change Method.
|
||||
*
|
||||
* Write your reversible migrations using this method.
|
||||
*
|
||||
* More information on writing migrations is available here:
|
||||
* http://docs.phinx.org/en/latest/migrations.html#the-abstractmigration-class
|
||||
*
|
||||
* The following commands can be used in this method and Phinx will
|
||||
* automatically reverse them when rolling back:
|
||||
*
|
||||
* createTable
|
||||
* renameTable
|
||||
* addColumn
|
||||
* renameColumn
|
||||
* addIndex
|
||||
* addForeignKey
|
||||
*
|
||||
* Remember to call "create()" or "update()" and NOT "save()" when working
|
||||
* with the Table class.
|
||||
*/
|
||||
public function change()
|
||||
{
|
||||
$table = $this->table('permissions',['engine'=>'Innodb', 'comment' => '菜单表', 'signed' => false]);
|
||||
$table->addColumn('permission_name', 'string',['limit' => 15,'default'=>'','comment'=>'菜单名称'])
|
||||
->addColumn('parent_id', 'integer',['default'=>0,'comment'=>'父级ID', 'signed' => false])
|
||||
->addColumn('route', 'string', ['default' => '', 'comment' => '路由', 'limit' => 50])
|
||||
->addColumn('module', 'string', ['default' => '', 'comment' => '模块', 'limit' => 20])
|
||||
->addColumn('method', 'string', ['default' => 'get', 'comment' => '路由请求方法', 'limit' => 15])
|
||||
->addColumn('permission_mark', 'string', ['null' => false, 'comment' => '权限标识', 'limit' => 50])
|
||||
->addColumn('type', 'integer',['limit' => \Phinx\Db\Adapter\MysqlAdapter::INT_TINY,'default'=> 1,'comment'=>'1 菜单 2 按钮'])
|
||||
->addColumn('sort', 'integer',['default'=> 0,'comment'=>'排序字段'])
|
||||
->addColumn('created_at', 'integer', array('default'=>0,'comment'=>'创建时间', 'signed' => false ))
|
||||
->addColumn('updated_at', 'integer', array('default'=>0,'comment'=>'更新时间', 'signed' => false))
|
||||
->addColumn('deleted_at', 'integer', array('default'=>0,'comment'=>'删除状态,null 未删除 timestamp 已删除', 'signed' => false))
|
||||
->create();
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
use think\migration\Migrator;
|
||||
use think\migration\db\Column;
|
||||
|
||||
class UserHasRoles extends Migrator
|
||||
{
|
||||
/**
|
||||
* Change Method.
|
||||
*
|
||||
* Write your reversible migrations using this method.
|
||||
*
|
||||
* More information on writing migrations is available here:
|
||||
* http://docs.phinx.org/en/latest/migrations.html#the-abstractmigration-class
|
||||
*
|
||||
* The following commands can be used in this method and Phinx will
|
||||
* automatically reverse them when rolling back:
|
||||
*
|
||||
* createTable
|
||||
* renameTable
|
||||
* addColumn
|
||||
* renameColumn
|
||||
* addIndex
|
||||
* addForeignKey
|
||||
*
|
||||
* Remember to call "create()" or "update()" and NOT "save()" when working
|
||||
* with the Table class.
|
||||
*/
|
||||
public function change()
|
||||
{
|
||||
$table = $this->table('user_has_roles',['engine'=>'Innodb', 'comment' => '用户角色表', 'signed' => false]);
|
||||
$table->addColumn('uid', 'integer',['comment'=>'用户ID', 'signed' => false])
|
||||
->addColumn('role_id', 'integer', ['comment'=>'角色ID', 'signed' => false])
|
||||
->create();
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
use think\migration\Migrator;
|
||||
use think\migration\db\Column;
|
||||
|
||||
class RoleHasPermissions extends Migrator
|
||||
{
|
||||
/**
|
||||
* Change Method.
|
||||
*
|
||||
* Write your reversible migrations using this method.
|
||||
*
|
||||
* More information on writing migrations is available here:
|
||||
* http://docs.phinx.org/en/latest/migrations.html#the-abstractmigration-class
|
||||
*
|
||||
* The following commands can be used in this method and Phinx will
|
||||
* automatically reverse them when rolling back:
|
||||
*
|
||||
* createTable
|
||||
* renameTable
|
||||
* addColumn
|
||||
* renameColumn
|
||||
* addIndex
|
||||
* addForeignKey
|
||||
*
|
||||
* Remember to call "create()" or "update()" and NOT "save()" when working
|
||||
* with the Table class.
|
||||
*/
|
||||
public function change()
|
||||
{
|
||||
$table = $this->table('role_has_permissions',['engine'=>'Innodb', 'comment' => '角色权限表', 'signed' => false]);
|
||||
$table->addColumn('role_id', 'integer',['comment'=>'角色ID', 'signed' => false])
|
||||
->addColumn('permission_id', 'integer', ['comment'=>'权限ID', 'signed' => false])
|
||||
->create();
|
||||
}
|
||||
}
|
603
catchAdmin/permissions/database/seeds/PermissionSeed.php
Normal file
603
catchAdmin/permissions/database/seeds/PermissionSeed.php
Normal file
@ -0,0 +1,603 @@
|
||||
<?php
|
||||
|
||||
use think\migration\Seeder;
|
||||
|
||||
class PermissionSeed extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run Method.
|
||||
*
|
||||
* Write your database seeder using this method.
|
||||
*
|
||||
* More information on writing seeders is available here:
|
||||
* http://docs.phinx.org/en/latest/seeding.html
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$this->roles();
|
||||
$this->createPermissions();
|
||||
}
|
||||
|
||||
protected function roles()
|
||||
{
|
||||
\catchAdmin\permissions\model\Roles::create([
|
||||
'role_name' => '超级管理员',
|
||||
'description' => 'super user',
|
||||
]);
|
||||
|
||||
\think\facade\Db::name('user_has_roles')->insert([
|
||||
'role_id' => 1,
|
||||
'uid' => 1,
|
||||
]);
|
||||
|
||||
\think\facade\Db::name('role_has_permissions')->insertAll(array (
|
||||
0 =>
|
||||
array (
|
||||
'role_id' => 1,
|
||||
'permission_id' => 4,
|
||||
),
|
||||
1 =>
|
||||
array (
|
||||
'role_id' => 1,
|
||||
'permission_id' => 6,
|
||||
),
|
||||
2 =>
|
||||
array (
|
||||
'role_id' => 1,
|
||||
'permission_id' => 7,
|
||||
),
|
||||
3 =>
|
||||
array (
|
||||
'role_id' => 1,
|
||||
'permission_id' => 8,
|
||||
),
|
||||
4 =>
|
||||
array (
|
||||
'role_id' => 1,
|
||||
'permission_id' => 9,
|
||||
),
|
||||
5 =>
|
||||
array (
|
||||
'role_id' => 1,
|
||||
'permission_id' => 10,
|
||||
),
|
||||
6 =>
|
||||
array (
|
||||
'role_id' => 1,
|
||||
'permission_id' => 11,
|
||||
),
|
||||
7 =>
|
||||
array (
|
||||
'role_id' => 1,
|
||||
'permission_id' => 12,
|
||||
),
|
||||
8 =>
|
||||
array (
|
||||
'role_id' => 1,
|
||||
'permission_id' => 13,
|
||||
),
|
||||
9 =>
|
||||
array (
|
||||
'role_id' => 1,
|
||||
'permission_id' => 14,
|
||||
),
|
||||
10 =>
|
||||
array (
|
||||
'role_id' => 1,
|
||||
'permission_id' => 15,
|
||||
),
|
||||
11 =>
|
||||
array (
|
||||
'role_id' => 1,
|
||||
'permission_id' => 16,
|
||||
),
|
||||
12 =>
|
||||
array (
|
||||
'role_id' => 1,
|
||||
'permission_id' => 17,
|
||||
),
|
||||
13 =>
|
||||
array (
|
||||
'role_id' => 1,
|
||||
'permission_id' => 18,
|
||||
),
|
||||
14 =>
|
||||
array (
|
||||
'role_id' => 1,
|
||||
'permission_id' => 19,
|
||||
),
|
||||
15 =>
|
||||
array (
|
||||
'role_id' => 1,
|
||||
'permission_id' => 20,
|
||||
),
|
||||
16 =>
|
||||
array (
|
||||
'role_id' => 1,
|
||||
'permission_id' => 21,
|
||||
),
|
||||
17 =>
|
||||
array (
|
||||
'role_id' => 1,
|
||||
'permission_id' => 22,
|
||||
),
|
||||
18 =>
|
||||
array (
|
||||
'role_id' => 1,
|
||||
'permission_id' => 23,
|
||||
),
|
||||
19 =>
|
||||
array (
|
||||
'role_id' => 1,
|
||||
'permission_id' => 24,
|
||||
),
|
||||
20 =>
|
||||
array (
|
||||
'role_id' => 1,
|
||||
'permission_id' => 25,
|
||||
),
|
||||
21 =>
|
||||
array (
|
||||
'role_id' => 1,
|
||||
'permission_id' => 26,
|
||||
),
|
||||
22 =>
|
||||
array (
|
||||
'role_id' => 1,
|
||||
'permission_id' => 27,
|
||||
),
|
||||
23 =>
|
||||
array (
|
||||
'role_id' => 1,
|
||||
'permission_id' => 28,
|
||||
),
|
||||
24 =>
|
||||
array (
|
||||
'role_id' => 1,
|
||||
'permission_id' => 29,
|
||||
),
|
||||
25 =>
|
||||
array (
|
||||
'role_id' => 1,
|
||||
'permission_id' => 30,
|
||||
),
|
||||
26 =>
|
||||
array (
|
||||
'role_id' => 1,
|
||||
'permission_id' => 31,
|
||||
),
|
||||
27 =>
|
||||
array (
|
||||
'role_id' => 1,
|
||||
'permission_id' => 32,
|
||||
),
|
||||
28 =>
|
||||
array (
|
||||
'role_id' => 1,
|
||||
'permission_id' => 33,
|
||||
),
|
||||
29 =>
|
||||
array (
|
||||
'role_id' => 1,
|
||||
'permission_id' => 34,
|
||||
),
|
||||
30 =>
|
||||
array (
|
||||
'role_id' => 1,
|
||||
'permission_id' => 35,
|
||||
),
|
||||
31 =>
|
||||
array (
|
||||
'role_id' => 1,
|
||||
'permission_id' => 36,
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
protected function createPermissions()
|
||||
{
|
||||
foreach (array (
|
||||
0 =>
|
||||
array (
|
||||
'id' => 4,
|
||||
'permission_name' => 'Dashboard',
|
||||
'parent_id' => 0,
|
||||
'module' => 'index',
|
||||
'route' => 'dashboard',
|
||||
'method' => 'get',
|
||||
'permission_mark' => 'index:dashboard',
|
||||
'type' => 1,
|
||||
'sort' => 10000,
|
||||
),
|
||||
1 =>
|
||||
array (
|
||||
'id' => 5,
|
||||
'permission_name' => '主题',
|
||||
'parent_id' => 4,
|
||||
'module' => '',
|
||||
'route' => 'themes',
|
||||
'method' => 'get',
|
||||
'permission_mark' => 'index:theme',
|
||||
'type' => 2,
|
||||
'sort' => 0,
|
||||
),
|
||||
2 =>
|
||||
array (
|
||||
'id' => 6,
|
||||
'permission_name' => '用户管理',
|
||||
'parent_id' => 16,
|
||||
'module' => 'user',
|
||||
'route' => 'user',
|
||||
'method' => 'get',
|
||||
'permission_mark' => 'user:index',
|
||||
'type' => 1,
|
||||
'sort' => 9999,
|
||||
),
|
||||
3 =>
|
||||
array (
|
||||
'id' => 7,
|
||||
'permission_name' => '创建',
|
||||
'parent_id' => 6,
|
||||
'module' => 'user',
|
||||
'route' => 'user',
|
||||
'method' => 'get',
|
||||
'permission_mark' => 'user:create',
|
||||
'type' => 2,
|
||||
'sort' => 0,
|
||||
),
|
||||
4 =>
|
||||
array (
|
||||
'id' => 8,
|
||||
'permission_name' => '保存',
|
||||
'parent_id' => 6,
|
||||
'module' => 'user',
|
||||
'route' => 'user',
|
||||
'method' => 'post',
|
||||
'permission_mark' => 'user:save',
|
||||
'type' => 2,
|
||||
'sort' => 0,
|
||||
),
|
||||
5 =>
|
||||
array (
|
||||
'id' => 9,
|
||||
'permission_name' => '查看',
|
||||
'parent_id' => 6,
|
||||
'module' => 'user',
|
||||
'route' => 'user/<id>/edit',
|
||||
'method' => 'get',
|
||||
'permission_mark' => 'user:edit',
|
||||
'type' => 2,
|
||||
'sort' => 0,
|
||||
),
|
||||
6 =>
|
||||
array (
|
||||
'id' => 10,
|
||||
'permission_name' => '编辑',
|
||||
'parent_id' => 6,
|
||||
'module' => 'user',
|
||||
'route' => 'user/<id>',
|
||||
'method' => 'put',
|
||||
'permission_mark' => 'user:update',
|
||||
'type' => 2,
|
||||
'sort' => 0,
|
||||
),
|
||||
7 =>
|
||||
array (
|
||||
'id' => 11,
|
||||
'permission_name' => '删除',
|
||||
'parent_id' => 6,
|
||||
'module' => 'user',
|
||||
'route' => 'user/<id>',
|
||||
'method' => 'delete',
|
||||
'permission_mark' => 'user:delete',
|
||||
'type' => 2,
|
||||
'sort' => 0,
|
||||
),
|
||||
8 =>
|
||||
array (
|
||||
'id' => 12,
|
||||
'permission_name' => '列表',
|
||||
'parent_id' => 6,
|
||||
'module' => 'user',
|
||||
'route' => 'users',
|
||||
'method' => 'get',
|
||||
'permission_mark' => 'user:list',
|
||||
'type' => 2,
|
||||
'sort' => 0,
|
||||
),
|
||||
9 =>
|
||||
array (
|
||||
'id' => 13,
|
||||
'permission_name' => '禁用/启用',
|
||||
'parent_id' => 6,
|
||||
'module' => 'user',
|
||||
'route' => 'user/switch/status/<id>',
|
||||
'method' => 'put',
|
||||
'permission_mark' => 'user:switchStatus',
|
||||
'type' => 2,
|
||||
'sort' => 0,
|
||||
),
|
||||
10 =>
|
||||
array (
|
||||
'id' => 14,
|
||||
'permission_name' => '恢复',
|
||||
'parent_id' => 6,
|
||||
'module' => 'user',
|
||||
'route' => 'user/recover/<id>',
|
||||
'method' => 'put',
|
||||
'permission_mark' => 'user:recover',
|
||||
'type' => 2,
|
||||
'sort' => 0,
|
||||
),
|
||||
11 =>
|
||||
array (
|
||||
'id' => 15,
|
||||
'permission_name' => '角色管理',
|
||||
'parent_id' => 16,
|
||||
'module' => 'permissions',
|
||||
'route' => 'role',
|
||||
'method' => 'get',
|
||||
'permission_mark' => 'role:index',
|
||||
'type' => 1,
|
||||
'sort' => 1000,
|
||||
),
|
||||
12 =>
|
||||
array (
|
||||
'id' => 16,
|
||||
'permission_name' => '权限管理',
|
||||
'parent_id' => 0,
|
||||
'module' => 'permissions',
|
||||
'route' => '',
|
||||
'method' => 'get',
|
||||
'permission_mark' => '@:@',
|
||||
'type' => 1,
|
||||
'sort' => 1,
|
||||
),
|
||||
13 =>
|
||||
array (
|
||||
'id' => 17,
|
||||
'permission_name' => '菜单管理',
|
||||
'parent_id' => 16,
|
||||
'module' => 'permissions',
|
||||
'route' => 'permission',
|
||||
'method' => 'get',
|
||||
'permission_mark' => 'permission:index',
|
||||
'type' => 1,
|
||||
'sort' => 1,
|
||||
),
|
||||
14 =>
|
||||
array (
|
||||
'id' => 18,
|
||||
'permission_name' => '创建',
|
||||
'parent_id' => 15,
|
||||
'module' => 'permissions',
|
||||
'route' => 'role/create',
|
||||
'method' => 'get',
|
||||
'permission_mark' => 'role:create',
|
||||
'type' => 2,
|
||||
'sort' => 1,
|
||||
),
|
||||
15 =>
|
||||
array (
|
||||
'id' => 19,
|
||||
'permission_name' => '保存',
|
||||
'parent_id' => 15,
|
||||
'module' => 'permissions',
|
||||
'route' => 'role',
|
||||
'method' => 'post',
|
||||
'permission_mark' => 'role:save',
|
||||
'type' => 2,
|
||||
'sort' => 1,
|
||||
),
|
||||
16 =>
|
||||
array (
|
||||
'id' => 20,
|
||||
'permission_name' => '查看',
|
||||
'parent_id' => 15,
|
||||
'module' => 'permissions',
|
||||
'route' => 'role/<id>/edit',
|
||||
'method' => 'get',
|
||||
'permission_mark' => 'role:edit',
|
||||
'type' => 2,
|
||||
'sort' => 1,
|
||||
),
|
||||
17 =>
|
||||
array (
|
||||
'id' => 21,
|
||||
'permission_name' => '更新',
|
||||
'parent_id' => 15,
|
||||
'module' => 'permissions',
|
||||
'route' => 'role/<id>',
|
||||
'method' => 'put',
|
||||
'permission_mark' => 'role:update',
|
||||
'type' => 2,
|
||||
'sort' => 1,
|
||||
),
|
||||
18 =>
|
||||
array (
|
||||
'id' => 22,
|
||||
'permission_name' => '删除',
|
||||
'parent_id' => 15,
|
||||
'module' => 'permissions',
|
||||
'route' => 'role/<id>',
|
||||
'method' => 'delete',
|
||||
'permission_mark' => 'role:delete',
|
||||
'type' => 2,
|
||||
'sort' => 1,
|
||||
),
|
||||
19 =>
|
||||
array (
|
||||
'id' => 23,
|
||||
'permission_name' => '列表',
|
||||
'parent_id' => 15,
|
||||
'module' => 'permissions',
|
||||
'route' => 'roles',
|
||||
'method' => 'get',
|
||||
'permission_mark' => 'role:list',
|
||||
'type' => 2,
|
||||
'sort' => 1,
|
||||
),
|
||||
20 =>
|
||||
array (
|
||||
'id' => 24,
|
||||
'permission_name' => '获取权限',
|
||||
'parent_id' => 15,
|
||||
'module' => 'permissions',
|
||||
'route' => 'role/get/permissions',
|
||||
'method' => 'get',
|
||||
'permission_mark' => 'role:getPermissions',
|
||||
'type' => 2,
|
||||
'sort' => 1,
|
||||
),
|
||||
21 =>
|
||||
array (
|
||||
'id' => 25,
|
||||
'permission_name' => '删除',
|
||||
'parent_id' => 17,
|
||||
'module' => 'permissions',
|
||||
'route' => 'permission/<id>',
|
||||
'method' => 'delete',
|
||||
'permission_mark' => 'permissions:delete',
|
||||
'type' => 2,
|
||||
'sort' => 1,
|
||||
),
|
||||
22 =>
|
||||
array (
|
||||
'id' => 26,
|
||||
'permission_name' => '更新',
|
||||
'parent_id' => 17,
|
||||
'module' => 'permissions',
|
||||
'route' => 'permission/<id>',
|
||||
'method' => 'put',
|
||||
'permission_mark' => 'permission:update',
|
||||
'type' => 2,
|
||||
'sort' => 1,
|
||||
),
|
||||
23 =>
|
||||
array (
|
||||
'id' => 27,
|
||||
'permission_name' => '查看',
|
||||
'parent_id' => 17,
|
||||
'module' => 'permissions',
|
||||
'route' => 'permissions/<id>/edit',
|
||||
'method' => 'get',
|
||||
'permission_mark' => 'permission:edit',
|
||||
'type' => 2,
|
||||
'sort' => 1,
|
||||
),
|
||||
24 =>
|
||||
array (
|
||||
'id' => 28,
|
||||
'permission_name' => '创建',
|
||||
'parent_id' => 17,
|
||||
'module' => 'permissions',
|
||||
'route' => 'permission/create',
|
||||
'method' => 'get',
|
||||
'permission_mark' => 'permission:create',
|
||||
'type' => 2,
|
||||
'sort' => 1,
|
||||
),
|
||||
25 =>
|
||||
array (
|
||||
'id' => 29,
|
||||
'permission_name' => '保存',
|
||||
'parent_id' => 17,
|
||||
'module' => 'permissions',
|
||||
'route' => 'permission',
|
||||
'method' => 'post',
|
||||
'permission_mark' => 'permission',
|
||||
'type' => 2,
|
||||
'sort' => 1,
|
||||
|
||||
),
|
||||
26 =>
|
||||
array (
|
||||
'id' => 30,
|
||||
'permission_name' => '列表',
|
||||
'parent_id' => 17,
|
||||
'module' => 'permissions',
|
||||
'route' => 'permissions',
|
||||
'method' => 'get',
|
||||
'permission_mark' => 'permission:list',
|
||||
'type' => 2,
|
||||
'sort' => 1,
|
||||
),
|
||||
27 =>
|
||||
array (
|
||||
'id' => 31,
|
||||
'permission_name' => '系统管理',
|
||||
'parent_id' => 0,
|
||||
'module' => 'system',
|
||||
'route' => '',
|
||||
'method' => 'get',
|
||||
'permission_mark' => 's:s',
|
||||
'type' => 1,
|
||||
'sort' => 1,
|
||||
),
|
||||
28 =>
|
||||
array (
|
||||
'id' => 32,
|
||||
'permission_name' => '日志管理',
|
||||
'parent_id' => 31,
|
||||
'module' => 'system',
|
||||
'route' => '',
|
||||
'method' => 'get',
|
||||
'permission_mark' => 'log:log',
|
||||
'type' => 1,
|
||||
'sort' => 1,
|
||||
),
|
||||
29 =>
|
||||
array (
|
||||
'id' => 33,
|
||||
'permission_name' => '登录日志',
|
||||
'parent_id' => 32,
|
||||
'module' => 'system',
|
||||
'route' => 'loginLog/index',
|
||||
'method' => 'get',
|
||||
'permission_mark' => 'operateLog:index',
|
||||
'type' => 1,
|
||||
'sort' => 1,
|
||||
),
|
||||
30 =>
|
||||
array (
|
||||
'id' => 34,
|
||||
'permission_name' => '操作日志',
|
||||
'parent_id' => 32,
|
||||
'module' => 'index',
|
||||
'route' => 'operateLog/index',
|
||||
'method' => 'get',
|
||||
'permission_mark' => 'loginLog:index',
|
||||
'type' => 1,
|
||||
'sort' => 1,
|
||||
),
|
||||
31 =>
|
||||
array (
|
||||
'id' => 35,
|
||||
'permission_name' => '数据字典',
|
||||
'parent_id' => 31,
|
||||
'module' => 'system',
|
||||
'route' => 'data/dictionary',
|
||||
'method' => 'get',
|
||||
'permission_mark' => 'datadictory:index',
|
||||
'type' => 1,
|
||||
'sort' => 1,
|
||||
),
|
||||
32 =>
|
||||
array (
|
||||
'id' => 36,
|
||||
'permission_name' => '查看表',
|
||||
'parent_id' => 35,
|
||||
'module' => 'system',
|
||||
'route' => 'table/view/<table>',
|
||||
'method' => 'get',
|
||||
'permission_mark' => 'datadictionary:view',
|
||||
'type' => 2,
|
||||
'sort' => 1,
|
||||
),
|
||||
) as $permission) {
|
||||
\catchAdmin\permissions\model\Permissions::create($permission);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
57
catchAdmin/permissions/model/HasRolesTrait.php
Normal file
57
catchAdmin/permissions/model/HasRolesTrait.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?php
|
||||
namespace catchAdmin\permissions\model;
|
||||
|
||||
trait HasRolesTrait
|
||||
{
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月08日
|
||||
* @return mixed
|
||||
*/
|
||||
public function roles()
|
||||
{
|
||||
return $this->belongsToMany(Roles::class, 'user_has_roles', 'role_id', 'uid');
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月08日
|
||||
* @return mixed
|
||||
*/
|
||||
public function getRoles()
|
||||
{
|
||||
return $this->roles()->select();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月08日
|
||||
* @param array $roles
|
||||
* @return mixed
|
||||
*/
|
||||
public function attach(array $roles)
|
||||
{
|
||||
if (empty($roles)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
sort($roles);
|
||||
|
||||
return $this->roles()->attach($roles);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月08日
|
||||
* @param array $roles
|
||||
* @return mixed
|
||||
*/
|
||||
public function detach(array $roles = [])
|
||||
{
|
||||
if (empty($roles)) {
|
||||
return $this->roles()->detach();
|
||||
}
|
||||
|
||||
return $this->roles()->detach($roles);
|
||||
}
|
||||
}
|
56
catchAdmin/permissions/model/Permissions.php
Normal file
56
catchAdmin/permissions/model/Permissions.php
Normal file
@ -0,0 +1,56 @@
|
||||
<?php
|
||||
namespace catchAdmin\permissions\model;
|
||||
|
||||
use catcher\base\CatchModel;
|
||||
|
||||
class Permissions extends CatchModel
|
||||
{
|
||||
protected $name = 'permissions';
|
||||
|
||||
protected $field = [
|
||||
'id', //
|
||||
'permission_name', // 菜单名称
|
||||
'parent_id', // 父级ID
|
||||
'module', // 模块
|
||||
'route', // 路由
|
||||
'method', // 请求方法
|
||||
'permission_mark', // 权限标识
|
||||
'type', // 1 菜单 2 按钮
|
||||
'sort', // 排序字段
|
||||
'created_at', // 创建时间
|
||||
'updated_at', // 更新时间
|
||||
'deleted_at', // 删除状态,null 未删除 timestamp 已删除
|
||||
|
||||
];
|
||||
|
||||
public const MENU_TYPE = 1;
|
||||
public const BTN_TYPE = 2;
|
||||
|
||||
public const GET = 'get';
|
||||
public const POST = 'post';
|
||||
public const PUT = 'put';
|
||||
public const DELETE = 'delete';
|
||||
|
||||
public function getList($search = [])
|
||||
{
|
||||
return $this->when($search['name'] ?? false, function ($query) use ($search){
|
||||
$query->whereLike('name', $search['name']);
|
||||
})
|
||||
->when($search['id'] ?? false, function ($query) use ($search){
|
||||
$query->where('parent_id', $search['id'])
|
||||
->whereOr('id', $search['id']);
|
||||
})
|
||||
->when($search['permission_ids'] ?? false, function ($query) use ($search){
|
||||
$query->whereIn('id', $search['permission_ids']);
|
||||
})
|
||||
->order('sort', 'desc')
|
||||
->order('id', 'desc')
|
||||
->select()
|
||||
->toArray();
|
||||
}
|
||||
|
||||
public function roles(): \think\model\relation\BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Roles::class, 'role_has_permissions', 'role_id', 'permission_id');
|
||||
}
|
||||
}
|
98
catchAdmin/permissions/model/Roles.php
Normal file
98
catchAdmin/permissions/model/Roles.php
Normal file
@ -0,0 +1,98 @@
|
||||
<?php
|
||||
namespace catchAdmin\permissions\model;
|
||||
|
||||
use catchAdmin\user\model\Users;
|
||||
use catcher\base\CatchModel;
|
||||
|
||||
class Roles extends CatchModel
|
||||
{
|
||||
protected $name = 'roles';
|
||||
|
||||
protected $field = [
|
||||
'id', //
|
||||
'role_name', // 角色名
|
||||
'parent_id', // 父级ID
|
||||
'description', // 角色备注
|
||||
'created_at', // 创建时间
|
||||
'updated_at', // 更新时间
|
||||
'deleted_at', // 删除状态,0未删除 >0 已删除
|
||||
|
||||
];
|
||||
|
||||
public function getList($search = [])
|
||||
{
|
||||
return $this->when($search['name'] ?? false, function ($query) use ($search){
|
||||
$query->whereLike('name', $search['name']);
|
||||
})
|
||||
->when($search['id'] ?? false, function ($query) use ($search){
|
||||
$query->where('parent_id', $search['id'])
|
||||
->whereOr('id', $search['id']);
|
||||
})
|
||||
->order('id', 'desc')
|
||||
->select()
|
||||
->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月08日
|
||||
* @return \think\model\relation\BelongsToMany
|
||||
*/
|
||||
public function users(): \think\model\relation\BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Users::class, 'user_has_roles', 'uid', 'role_id');
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月09日
|
||||
* @return \think\model\relation\BelongsToMany
|
||||
*/
|
||||
public function permissions(): \think\model\relation\BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Permissions::class, 'role_has_permissions', 'permission_id', 'role_id');
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月08日
|
||||
* @return mixed
|
||||
*/
|
||||
public function getPermissions()
|
||||
{
|
||||
return $this->permissions()->select();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月08日
|
||||
* @param array $permissions
|
||||
* @return mixed
|
||||
* @throws \think\db\exception\DbException
|
||||
*/
|
||||
public function attach(array $permissions)
|
||||
{
|
||||
if (empty($permissions)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
sort($permissions);
|
||||
|
||||
return $this->permissions()->attach($permissions);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月08日
|
||||
* @param array $roles
|
||||
* @return mixed
|
||||
*/
|
||||
public function detach(array $roles = [])
|
||||
{
|
||||
if (empty($roles)) {
|
||||
return $this->permissions()->detach();
|
||||
}
|
||||
|
||||
return $this->permissions()->detach($roles);
|
||||
}
|
||||
}
|
@ -4,9 +4,7 @@
|
||||
"description": "",
|
||||
"keywords": [],
|
||||
"order": 2,
|
||||
"services": [
|
||||
"catchAdmin\\permissions\\PermissionService"
|
||||
],
|
||||
"services": [],
|
||||
"aliases": {},
|
||||
"files": [],
|
||||
"requires": []
|
||||
|
@ -1 +1,11 @@
|
||||
<?php
|
||||
// 角色
|
||||
$router->resource('role', '\catchAdmin\permissions\controller\Role');
|
||||
// 角色列表
|
||||
$router->get('roles', '\catchAdmin\permissions\controller\Role@list');
|
||||
$router->get('/role/get/permissions', '\catchAdmin\permissions\controller\Role@getPermissions');
|
||||
|
||||
// 权限
|
||||
$router->resource('permission', '\catchAdmin\permissions\controller\Permission');
|
||||
// 权限列表
|
||||
$router->get('permissions', '\catchAdmin\permissions\controller\Permission@list');
|
||||
|
22
catchAdmin/permissions/view/permission/create.html
Normal file
22
catchAdmin/permissions/view/permission/create.html
Normal file
@ -0,0 +1,22 @@
|
||||
{$form|raw}
|
||||
<script>
|
||||
layui.use(['layer', 'form', 'admin', 'formX'], function () {
|
||||
var $ = layui.jquery;
|
||||
var layer = layui.layer;
|
||||
var form = layui.form;
|
||||
var admin = layui.admin;
|
||||
var mUser = admin.getLayerData('#permission'); // 列表页面传递的数据,#modelUserForm这个只要写弹窗内任意一个元素的id即可
|
||||
form.render();
|
||||
// 回显数据
|
||||
form.val('role', mUser);
|
||||
// 表单提交事件
|
||||
form.on('submit(submitPermission)', function (data) {
|
||||
admin.req('{:url("permission")}', data.field, function (response) {
|
||||
layer.msg(response.msg, {icon: 1});
|
||||
admin.putLayerData('formOk', true, '#permission'); // 设置操作成功的标识,#modelUserForm这个只要写弹窗内任意一个元素的id即可
|
||||
admin.closeDialog('#permission'); // 关闭页面层弹窗
|
||||
}, 'post');
|
||||
return false;
|
||||
});
|
||||
});
|
||||
</script>
|
22
catchAdmin/permissions/view/permission/edit.html
Normal file
22
catchAdmin/permissions/view/permission/edit.html
Normal file
@ -0,0 +1,22 @@
|
||||
{$form|raw}
|
||||
<script>
|
||||
layui.use(['layer', 'form', 'admin', 'formX'], function () {
|
||||
var $ = layui.jquery;
|
||||
var layer = layui.layer;
|
||||
var form = layui.form;
|
||||
var admin = layui.admin;
|
||||
var mUser = admin.getLayerData('#permission'); // 列表页面传递的数据,#modelUserForm这个只要写弹窗内任意一个元素的id即可
|
||||
form.render();
|
||||
// 回显数据
|
||||
form.val('permission', mUser);
|
||||
// 表单提交事件
|
||||
form.on('submit(submitPermission)', function (data) {
|
||||
admin.req('permission/'+ "{$permission_id}", data.field, function (response) {
|
||||
layer.msg(response.msg, {icon: 1});
|
||||
admin.putLayerData('formOk', true, '#permission'); // 设置操作成功的标识,#modelUserForm这个只要写弹窗内任意一个元素的id即可
|
||||
admin.closeDialog('#permission'); // 关闭页面层弹窗
|
||||
}, 'put');
|
||||
return false;
|
||||
});
|
||||
});
|
||||
</script>
|
200
catchAdmin/permissions/view/permission/index.html
Normal file
200
catchAdmin/permissions/view/permission/index.html
Normal file
@ -0,0 +1,200 @@
|
||||
{extend name="$layout"}
|
||||
{block name="title"}角色管理{/block}
|
||||
{block name="search"}
|
||||
<div class="layui-form toolbar">
|
||||
<div class="layui-form-item">
|
||||
<!--<div class="layui-inline">
|
||||
<div class="layui-input-inline mr0">
|
||||
<input id="edtSearchAuth" class="layui-input" type="text" placeholder="输入角色名称"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<button id="btnSearchAuth" class="layui-btn icon-btn"><i class="layui-icon"></i>搜索
|
||||
</button>-->
|
||||
<button id="btnAddAuth" class="layui-btn icon-btn"><i class="layui-icon"></i>添加</button>
|
||||
<!--</div>-->
|
||||
</div>
|
||||
</div>
|
||||
{/block}
|
||||
{block name="table"}
|
||||
<table class="layui-table" id="tablePermission" lay-filter="tablePermission"></table>
|
||||
<!-- 表格操作列 -->
|
||||
<script type="text/html" id="tableBarAuth">
|
||||
{:editButton()}
|
||||
{:addButton('新增子菜单')}
|
||||
{:deleteButton()}
|
||||
</script>
|
||||
{/block}
|
||||
{block name="script"}
|
||||
<script>
|
||||
layui.use(['layer', 'form', 'table', 'admin', 'util', 'treeTable'], function () {
|
||||
var $ = layui.jquery;
|
||||
var layer = layui.layer;
|
||||
var form = layui.form;
|
||||
var table = layui.table;
|
||||
var util = layui.util;
|
||||
var admin = layui.admin;
|
||||
var treeTable = layui.treeTable;
|
||||
|
||||
var treeTb = treeTable.render({
|
||||
tree: {
|
||||
arrowType: 'arrow2',
|
||||
iconIndex: 1, // 折叠图标显示在第几列
|
||||
idName: 'id', // 自定义id字段的名称
|
||||
childName: 'children', // 自定义标识是否还有子节点的字段名称
|
||||
pidName: 'parent_id',
|
||||
isPidData: true,
|
||||
getIcon: function(d) { // 自定义图标
|
||||
// d是当前行的数据
|
||||
if (d.children.length) { // 判断是否有子集
|
||||
return '<i class="ew-tree-icon ew-tree-icon-folder"></i>';
|
||||
} else {
|
||||
return '<i class="ew-tree-icon ew-tree-icon-file"></i>';
|
||||
}
|
||||
}
|
||||
},
|
||||
elem: '#tablePermission',
|
||||
cellMinWidth: 100,
|
||||
cols: [
|
||||
{type: 'numbers', title: '#'},
|
||||
{field: 'permission_name', title: '菜单名称', minWidth: 200},
|
||||
{field: 'route', title: '菜单路由', templet: function (d) {
|
||||
return escapeChars(d.route);
|
||||
}
|
||||
},
|
||||
{field: 'method', title: '请求方法', width: 90},
|
||||
{field: 'permission_mark', title: '权限标识'},
|
||||
{field: 'type', title: '菜单类型', templet: function (d) {
|
||||
return d.type == 1 ? '<button class="layui-btn layui-btn-primary layui-btn-xs">菜单</button>' :
|
||||
'<button class="layui-btn layui-btn-primary layui-btn-xs">按钮</button>'
|
||||
}, width: 90, align: 'center'
|
||||
},
|
||||
{field: 'sort', title: '排序', width:60, align: 'center'},
|
||||
{
|
||||
field: 'created_at', sort: true, templet: function (d) {
|
||||
return util.toDateString(d.created_at);
|
||||
}, title: '创建时间', maxWidth: 100
|
||||
},
|
||||
{templet: '#tableBarAuth', title: '操作', align: 'center', minWidth: 150}
|
||||
],
|
||||
reqData: function(data, callback) {
|
||||
// 在这里写ajax请求,通过callback方法回调数据
|
||||
$.get('{:url("permissions")}', function (res) {
|
||||
callback(res.data); // 参数是数组类型
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 添加按钮点击事件
|
||||
$('#btnAddAuth').click(function () {
|
||||
showEditModel();
|
||||
});
|
||||
function escapeChars(str) {
|
||||
str = str.replace(/&/g, '&');
|
||||
str = str.replace(/</g, '<');
|
||||
str = str.replace(/>/g, '>');
|
||||
str = str.replace(/'/g, '´');
|
||||
str = str.replace(/"/g, '"');
|
||||
str = str.replace(/\|/g, '¦');
|
||||
return str;
|
||||
}
|
||||
// 工具条点击事件
|
||||
treeTable.on('tool(tablePermission)', function (obj) {
|
||||
var data = obj.data;
|
||||
var layEvent = obj.event;
|
||||
if (layEvent === 'edit') { // 修改
|
||||
showEditModel(data);
|
||||
} else if (layEvent === 'del') { // 删除
|
||||
doDel(obj);
|
||||
} else {
|
||||
showEditModel(data, true);
|
||||
}
|
||||
});
|
||||
treeTable.on('row(tablePermission)', function(obj){
|
||||
console.log(obj.value); //得到修改后的值
|
||||
console.log(obj.field); //当前编辑的字段名
|
||||
console.log(obj.data); //所在行的所有相关数据
|
||||
});
|
||||
// 删除
|
||||
function doDel(obj) {
|
||||
layer.confirm('确定要删除“' + obj.data.permission_name + '”吗?', {
|
||||
skin: 'layui-layer-admin',
|
||||
shade: .1
|
||||
}, function (index) {
|
||||
layer.close(index);
|
||||
admin.req('/permission/'+ obj.data.id, {}, function (response) {
|
||||
if (response.code === 10000) {
|
||||
layer.msg(response.msg, {icon: 1});
|
||||
obj.del()
|
||||
} else {
|
||||
layer.msg(response.msg, {icon: 2});
|
||||
}
|
||||
}, 'delete');
|
||||
});
|
||||
}
|
||||
|
||||
// 显示表单弹窗
|
||||
// 显示表单弹窗
|
||||
function showEditModel(permission, addPermission= false) {
|
||||
var layIndex = admin.open({
|
||||
title: addPermission ? '新增子菜单' : ((permission ? '修改' : '添加') + '菜单'),
|
||||
url: addPermission ? '/permission/create' + '?id='+permission.id : (permission ? '/permission/'+permission.id + '/edit': '/permission/create'),
|
||||
data: addPermission ? '' : permission, // 传递数据到表单页面
|
||||
end: function () {
|
||||
if (admin.getLayerData(layIndex, 'formOk')) { // 判断表单操作成功标识
|
||||
if (addPermission) {
|
||||
treeTb.reload();
|
||||
setTimeout(function () {
|
||||
treeTb.expand(permission.id)
|
||||
}, 200)
|
||||
} else {
|
||||
if (permission) {
|
||||
treeTb.reload();
|
||||
setTimeout(function () {
|
||||
treeTb.expand(permission.id)
|
||||
}, 200)
|
||||
} else {
|
||||
treeTb.reload(); // 成功刷新表格
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
success: function (layero, dIndex) {
|
||||
// 弹窗超出范围不出现滚动条
|
||||
$(layero).children('.layui-layer-content').css('overflow', 'visible');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 搜索按钮点击事件
|
||||
$('#btnSearchAuth').click(function () {
|
||||
$('#edtSearchAuth').removeClass('layui-form-danger');
|
||||
var keyword = $('#edtSearchAuth').val();
|
||||
var $tds = $('#tableAuth').next('.treeTable').find('.layui-table-body tbody tr td');
|
||||
$tds.css('background-color', 'transparent');
|
||||
if (!keyword) {
|
||||
layer.tips('请输入关键字', '#edtSearchAuth', {tips: [1, '#ff4c4c']});
|
||||
$('#edtSearchAuth').addClass('layui-form-danger');
|
||||
$('#edtSearchAuth').focus();
|
||||
return;
|
||||
}
|
||||
var searchCount = 0;
|
||||
$tds.each(function () {
|
||||
if ($(this).text().indexOf(keyword) >= 0) {
|
||||
$(this).css('background-color', '#FAE6A0');
|
||||
if (searchCount == 0) {
|
||||
$('body,html').stop(true);
|
||||
$('body,html').animate({scrollTop: $(this).offset().top - 150}, 500);
|
||||
}
|
||||
searchCount++;
|
||||
}
|
||||
});
|
||||
if (searchCount == 0) {
|
||||
layer.msg("没有匹配结果", {icon: 5, anim: 6});
|
||||
} else {
|
||||
treetable.expandAll('#tableAuth');
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{/block}
|
35
catchAdmin/permissions/view/role/create.html
Normal file
35
catchAdmin/permissions/view/role/create.html
Normal file
@ -0,0 +1,35 @@
|
||||
{$form|raw}
|
||||
<script>
|
||||
layui.use(['layer', 'form', 'admin', 'formX', 'authtree'], function () {
|
||||
var $ = layui.jquery;
|
||||
var layer = layui.layer;
|
||||
var form = layui.form;
|
||||
var admin = layui.admin;
|
||||
var authtree = layui.authtree;
|
||||
var mUser = admin.getLayerData('#role'); // 列表页面传递的数据,#modelUserForm这个只要写弹窗内任意一个元素的id即可
|
||||
// 回显数据
|
||||
form.val('role', mUser);
|
||||
// 表单提交事件
|
||||
form.on('submit(submitRole)', function (data) {
|
||||
admin.req('{:url("role")}', data.field, function (response) {
|
||||
layer.msg(response.msg, {icon: 1});
|
||||
admin.putLayerData('formOk', true, '#role'); // 设置操作成功的标识,#modelUserForm这个只要写弹窗内任意一个元素的id即可
|
||||
admin.closeDialog('#role'); // 关闭页面层弹窗
|
||||
}, 'post');
|
||||
return false;
|
||||
});
|
||||
admin.req('{:url("/role/get/permissions")}',{parent_id:"{$parent_id}"}, function (response) {
|
||||
authtree.render('#permissions', response.data.permissions,{
|
||||
inputname: 'permissionids[]',
|
||||
layfilter: 'lay-check-auth',
|
||||
autowidth: true,
|
||||
nameKey: 'permission_name',
|
||||
valueKey: 'id',
|
||||
childKey: 'children',
|
||||
collapseLeafNode: true,
|
||||
theme: 'auth-skin-default',
|
||||
});
|
||||
})
|
||||
|
||||
});
|
||||
</script>
|
36
catchAdmin/permissions/view/role/edit.html
Normal file
36
catchAdmin/permissions/view/role/edit.html
Normal file
@ -0,0 +1,36 @@
|
||||
{$form|raw}
|
||||
<script>
|
||||
layui.use(['layer', 'form', 'admin', 'formX', 'authtree'], function () {
|
||||
var $ = layui.jquery;
|
||||
var layer = layui.layer;
|
||||
var form = layui.form;
|
||||
var admin = layui.admin;
|
||||
var mUser = admin.getLayerData('#role'); // 列表页面传递的数据,#modelUserForm这个只要写弹窗内任意一个元素的id即可
|
||||
var authtree = layui.authtree;
|
||||
|
||||
// 回显数据
|
||||
form.val('role', mUser);
|
||||
admin.req('{:url("/role/get/permissions")}',{role_id:"{$role_id}", parent_id:"{$parent_id}"}, function (response) {
|
||||
authtree.render('#permissions', response.data.permissions,{
|
||||
inputname: 'permissionids[]',
|
||||
layfilter: 'lay-check-auth',
|
||||
autowidth: true,
|
||||
nameKey: 'permission_name',
|
||||
valueKey: 'id',
|
||||
childKey: 'children',
|
||||
collapseLeafNode: true,
|
||||
theme: 'auth-skin-default',
|
||||
checkedKey: response.data.hasPermissions
|
||||
});
|
||||
})
|
||||
// 表单提交事件
|
||||
form.on('submit(submitRole)', function (data) {
|
||||
admin.req('role/'+ "{$role_id}", data.field, function (response) {
|
||||
layer.msg(response.msg, {icon: 1});
|
||||
admin.putLayerData('formOk', true, '#role'); // 设置操作成功的标识,#modelUserForm这个只要写弹窗内任意一个元素的id即可
|
||||
admin.closeDialog('#role'); // 关闭页面层弹窗
|
||||
}, 'put');
|
||||
return false;
|
||||
});
|
||||
});
|
||||
</script>
|
178
catchAdmin/permissions/view/role/index.html
Normal file
178
catchAdmin/permissions/view/role/index.html
Normal file
@ -0,0 +1,178 @@
|
||||
{extend name="$layout"}
|
||||
{block name="title"}角色管理{/block}
|
||||
{block name="search"}
|
||||
<div class="layui-form toolbar">
|
||||
<div class="layui-form-item">
|
||||
<!--<div class="layui-inline">
|
||||
<div class="layui-input-inline mr0">
|
||||
<input id="edtSearchAuth" class="layui-input" type="text" placeholder="输入角色名称"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<button id="btnSearchAuth" class="layui-btn icon-btn"><i class="layui-icon"></i>搜索
|
||||
</button>-->
|
||||
<button id="btnAddAuth" class="layui-btn icon-btn"><i class="layui-icon"></i>添加</button>
|
||||
<!--</div>-->
|
||||
</div>
|
||||
</div>
|
||||
{/block}
|
||||
{block name="table"}
|
||||
<table class="layui-table" id="tableRole"></table>
|
||||
<!-- 表格操作列 -->
|
||||
<script type="text/html" id="tableBarAuth">
|
||||
{:editButton()}
|
||||
{:addButton('新增子角色')}
|
||||
{:deleteButton()}
|
||||
</script>
|
||||
{/block}
|
||||
{block name="script"}
|
||||
<script>
|
||||
layui.use(['layer', 'form', 'table', 'admin', 'util', 'treeTable'], function () {
|
||||
var $ = layui.jquery;
|
||||
var layer = layui.layer;
|
||||
var form = layui.form;
|
||||
var table = layui.table;
|
||||
var util = layui.util;
|
||||
var admin = layui.admin;
|
||||
var treeTable = layui.treeTable;
|
||||
|
||||
var treeTb = treeTable.render({
|
||||
tree: {
|
||||
arrowType: 'arrow2',
|
||||
iconIndex: 1, // 折叠图标显示在第几列
|
||||
idName: 'id', // 自定义id字段的名称
|
||||
childName: 'children', // 自定义标识是否还有子节点的字段名称
|
||||
pidName: 'parent_id',
|
||||
isPidData: true,
|
||||
getIcon: function(d) { // 自定义图标
|
||||
// d是当前行的数据
|
||||
if (d.children.length) { // 判断是否有子集
|
||||
return '<i class="ew-tree-icon ew-tree-icon-folder"></i>';
|
||||
} else {
|
||||
return '<i class="ew-tree-icon ew-tree-icon-file"></i>';
|
||||
}
|
||||
}
|
||||
},
|
||||
elem: '#tableRole',
|
||||
cellMinWidth: 100,
|
||||
cols: [
|
||||
{type: 'numbers', title: '#'},
|
||||
{field: 'role_name', title: '角色名称', minWidth: 100},
|
||||
{field: 'description', title: '角色描述'},
|
||||
{
|
||||
field: 'created_at', sort: true, templet: function (d) {
|
||||
return util.toDateString(d.created_at);
|
||||
}, title: '创建时间', maxWidth: 100
|
||||
},
|
||||
{templet: '#tableBarAuth', title: '操作', align: 'center', minWidth: 120}
|
||||
],
|
||||
reqData: function(data, callback) {
|
||||
// 在这里写ajax请求,通过callback方法回调数据
|
||||
$.get('{:url("roles")}', function (res) {
|
||||
callback(res.data); // 参数是数组类型
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 添加按钮点击事件
|
||||
$('#btnAddAuth').click(function () {
|
||||
showEditModel();
|
||||
});
|
||||
|
||||
// 工具条点击事件
|
||||
treeTable.on('tool(tableRole)', function (obj) {
|
||||
var data = obj.data;
|
||||
var layEvent = obj.event;
|
||||
if (layEvent === 'edit') { // 修改
|
||||
showEditModel(data);
|
||||
} else if (layEvent === 'del') { // 删除
|
||||
doDel(obj);
|
||||
} else {
|
||||
showEditModel(data, true);
|
||||
}
|
||||
});
|
||||
|
||||
// 删除
|
||||
function doDel(obj) {
|
||||
layer.confirm('确定要删除“' + obj.data.role_name + '”吗?', {
|
||||
skin: 'layui-layer-admin',
|
||||
shade: .1
|
||||
}, function (index) {
|
||||
layer.close(index);
|
||||
admin.req('/role/'+ obj.data.id, {}, function (response) {
|
||||
if (response.code === 10000) {
|
||||
layer.msg(response.msg, {icon: 1});
|
||||
obj.del()
|
||||
} else {
|
||||
layer.msg(response.msg, {icon: 2});
|
||||
}
|
||||
}, 'delete');
|
||||
});
|
||||
}
|
||||
|
||||
// 显示表单弹窗
|
||||
// 显示表单弹窗
|
||||
function showEditModel(mRole, addRole = false) {
|
||||
var layIndex = admin.open({
|
||||
title: addRole ? '新增子角色' : ((mRole ? '修改' : '添加') + '角色'),
|
||||
url: addRole ? '/role/create' + '?id='+mRole.id : (mRole ? '/role/'+mRole.id + '/edit': '/role/create'),
|
||||
data: addRole ? '' : mRole, // 传递数据到表单页面
|
||||
area: '700px',
|
||||
end: function () {
|
||||
if (admin.getLayerData(layIndex, 'formOk')) { // 判断表单操作成功标识
|
||||
if (addRole) {
|
||||
treeTb.reload();
|
||||
setTimeout(function () {
|
||||
treeTb.expand(mRole.id)
|
||||
}, 200)
|
||||
} else {
|
||||
if (mRole) {
|
||||
treeTb.reload();
|
||||
setTimeout(function () {
|
||||
treeTb.expand(mRole.id)
|
||||
}, 200)
|
||||
} else {
|
||||
treeTb.reload(); // 成功刷新表格
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
success: function (layero, dIndex) {
|
||||
// 弹窗超出范围不出现滚动条
|
||||
$(layero).children('.layui-layer-content').css('overflow', 'visible');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 搜索按钮点击事件
|
||||
$('#btnSearchAuth').click(function () {
|
||||
$('#edtSearchAuth').removeClass('layui-form-danger');
|
||||
var keyword = $('#edtSearchAuth').val();
|
||||
var $tds = $('#tableAuth').next('.treeTable').find('.layui-table-body tbody tr td');
|
||||
$tds.css('background-color', 'transparent');
|
||||
if (!keyword) {
|
||||
layer.tips('请输入关键字', '#edtSearchAuth', {tips: [1, '#ff4c4c']});
|
||||
$('#edtSearchAuth').addClass('layui-form-danger');
|
||||
$('#edtSearchAuth').focus();
|
||||
return;
|
||||
}
|
||||
var searchCount = 0;
|
||||
$tds.each(function () {
|
||||
if ($(this).text().indexOf(keyword) >= 0) {
|
||||
$(this).css('background-color', '#FAE6A0');
|
||||
if (searchCount == 0) {
|
||||
$('body,html').stop(true);
|
||||
$('body,html').animate({scrollTop: $(this).offset().top - 150}, 500);
|
||||
}
|
||||
searchCount++;
|
||||
}
|
||||
});
|
||||
if (searchCount == 0) {
|
||||
layer.msg("没有匹配结果", {icon: 5, anim: 6});
|
||||
} else {
|
||||
treetable.expandAll('#tableAuth');
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{/block}
|
84
catchAdmin/system/controller/DataDictionary.php
Normal file
84
catchAdmin/system/controller/DataDictionary.php
Normal file
@ -0,0 +1,84 @@
|
||||
<?php
|
||||
namespace catchAdmin\system\controller;
|
||||
|
||||
use app\Request;
|
||||
use catcher\base\CatchController;
|
||||
use catcher\CatchResponse;
|
||||
use catcher\exceptions\FailedException;
|
||||
use think\facade\Console;
|
||||
use think\facade\Db;
|
||||
use think\Paginator;
|
||||
|
||||
class DataDictionary extends CatchController
|
||||
{
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月13日
|
||||
* @throws \Exception
|
||||
* @return string
|
||||
*/
|
||||
public function index(): string
|
||||
{
|
||||
return $this->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月13日
|
||||
* @param Request $request
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function tables(Request $request): \think\response\Json
|
||||
{
|
||||
$tables = Db::query('show table status');
|
||||
|
||||
return CatchResponse::paginate(Paginator::make($tables, $request->get('limit') ?? 10, $request->get('page'), count($tables), false, []));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月13日
|
||||
* @param $table
|
||||
* @throws \Exception
|
||||
* @return string
|
||||
*/
|
||||
public function view($table): string
|
||||
{
|
||||
$this->table = Db::query('show full columns from ' . $table);
|
||||
|
||||
return $this->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月13日
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function optimize(): \think\response\Json
|
||||
{
|
||||
$tables = \request()->post('data');
|
||||
|
||||
foreach ($tables as $table) {
|
||||
Db::query(sprintf('optimize table %s', $table));
|
||||
}
|
||||
|
||||
return CatchResponse::success([], '优化成功');
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月13日
|
||||
* @throws FailedException
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function backup(): \think\response\Json
|
||||
{
|
||||
try {
|
||||
Console::call('backup:data', [trim(implode(',', \request()->post('data')), ',')]);
|
||||
}catch (\Exception $e) {
|
||||
throw new FailedException($e->getMessage());
|
||||
}
|
||||
|
||||
return CatchResponse::success([], '备份成功');
|
||||
}
|
||||
}
|
24
catchAdmin/system/controller/LoginLog.php
Normal file
24
catchAdmin/system/controller/LoginLog.php
Normal file
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
namespace catchAdmin\system\controller;
|
||||
|
||||
use catcher\base\CatchController;
|
||||
use catcher\CatchResponse;
|
||||
use think\facade\Db;
|
||||
|
||||
class LoginLog extends CatchController
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
return $this->fetch();
|
||||
}
|
||||
|
||||
public function list()
|
||||
{
|
||||
return CatchResponse::paginate(Db::name('login_log')->paginate(10));
|
||||
}
|
||||
|
||||
public function empty()
|
||||
{
|
||||
return CatchResponse::success(Db::name('login_log')->delete(true), '清空成功');
|
||||
}
|
||||
}
|
30
catchAdmin/system/controller/OperateLog.php
Normal file
30
catchAdmin/system/controller/OperateLog.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
namespace catchAdmin\system\controller;
|
||||
|
||||
use catcher\base\CatchController;
|
||||
use catcher\CatchResponse;
|
||||
use think\facade\Db;
|
||||
|
||||
class OperateLog extends CatchController
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
return $this->fetch();
|
||||
}
|
||||
|
||||
public function list()
|
||||
{
|
||||
return CatchResponse::paginate(
|
||||
Db::name('operate_log')
|
||||
->field(['operate_log.*', 'users.username as creator'])
|
||||
->join('users','users.id = operate_log.creator_id')
|
||||
->order('id', 'desc')
|
||||
->paginate(10)
|
||||
);
|
||||
}
|
||||
|
||||
public function empty()
|
||||
{
|
||||
return CatchResponse::success(Db::name('operate_log')->delete(true), '清空成功');
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
use think\migration\Migrator;
|
||||
use think\migration\db\Column;
|
||||
|
||||
class LoginLog extends Migrator
|
||||
{
|
||||
/**
|
||||
* Change Method.
|
||||
*
|
||||
* Write your reversible migrations using this method.
|
||||
*
|
||||
* More information on writing migrations is available here:
|
||||
* http://docs.phinx.org/en/latest/migrations.html#the-abstractmigration-class
|
||||
*
|
||||
* The following commands can be used in this method and Phinx will
|
||||
* automatically reverse them when rolling back:
|
||||
*
|
||||
* createTable
|
||||
* renameTable
|
||||
* addColumn
|
||||
* renameColumn
|
||||
* addIndex
|
||||
* addForeignKey
|
||||
*
|
||||
* Remember to call "create()" or "update()" and NOT "save()" when working
|
||||
* with the Table class.
|
||||
*/
|
||||
public function change()
|
||||
{
|
||||
$table = $this->table('login_log',['engine'=>'Myisam', 'comment' => '登录日志', 'signed' => false]);
|
||||
$table->addColumn('login_name', 'string',['limit' => 50,'default'=>'','comment'=>'用户名'])
|
||||
->addColumn('login_ip', 'string',['default'=>0, 'limit' => 20, 'comment'=>'登录地点ip', 'signed' => false])
|
||||
->addColumn('browser', 'string',['default'=> '','comment'=>'浏览器'])
|
||||
->addColumn('os', 'string',['default'=> '','comment'=>'操作系统'])
|
||||
->addColumn('login_at', 'integer', array('default'=>0,'comment'=>'登录时间', 'signed' => false ))
|
||||
->addColumn('status', 'integer',['limit' => \Phinx\Db\Adapter\MysqlAdapter::INT_TINY,'default'=> 1,'comment'=>'1 成功 2 失败'])
|
||||
->create();
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
use think\migration\Migrator;
|
||||
use think\migration\db\Column;
|
||||
|
||||
class OperateLog extends Migrator
|
||||
{
|
||||
/**
|
||||
* Change Method.
|
||||
*
|
||||
* Write your reversible migrations using this method.
|
||||
*
|
||||
* More information on writing migrations is available here:
|
||||
* http://docs.phinx.org/en/latest/migrations.html#the-abstractmigration-class
|
||||
*
|
||||
* The following commands can be used in this method and Phinx will
|
||||
* automatically reverse them when rolling back:
|
||||
*
|
||||
* createTable
|
||||
* renameTable
|
||||
* addColumn
|
||||
* renameColumn
|
||||
* addIndex
|
||||
* addForeignKey
|
||||
*
|
||||
* Remember to call "create()" or "update()" and NOT "save()" when working
|
||||
* with the Table class.
|
||||
*/
|
||||
public function change()
|
||||
{
|
||||
$table = $this->table('operate_log',['engine'=>'Myisam', 'comment' => '操作日志', 'signed' => false]);
|
||||
$table->addColumn('module', 'string',['limit' => 50,'default'=>'','comment'=>'模块名称'])
|
||||
->addColumn('operate', 'string',['default'=> '', 'limit' => 20, 'comment'=>'操作模块'])
|
||||
->addColumn('route', 'string',['default'=> '','limit' => 20, 'comment'=>'路由'])
|
||||
->addColumn('params', 'string',['default'=> '','limit' => 1000, 'comment'=>'参数'])
|
||||
->addColumn('ip', 'string',['default'=>'', 'limit' => 20,'comment'=>'ip', 'signed' => false])
|
||||
->addColumn('creator_id', 'integer',['default'=> 0,'comment'=>'创建人ID', 'signed' => false])
|
||||
->addColumn('method', 'string',['default'=> '','comment'=>'请求方法'])
|
||||
->addColumn('created_at', 'integer', array('default'=>0,'comment'=>'登录时间', 'signed' => false ))
|
||||
->create();
|
||||
}
|
||||
}
|
12
catchAdmin/system/event/LoginLogEvent.php
Normal file
12
catchAdmin/system/event/LoginLogEvent.php
Normal file
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
namespace catchAdmin\system\event;
|
||||
|
||||
class LoginLogEvent
|
||||
{
|
||||
protected $params;
|
||||
|
||||
public function __construct(array $params)
|
||||
{
|
||||
$this->params = $params;
|
||||
}
|
||||
}
|
12
catchAdmin/system/event/OperateLogEvent.php
Normal file
12
catchAdmin/system/event/OperateLogEvent.php
Normal file
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
namespace catchAdmin\system\event;
|
||||
|
||||
class OperateLogEvent
|
||||
{
|
||||
protected $params;
|
||||
|
||||
public function __construct(array $params)
|
||||
{
|
||||
$this->params = $params;
|
||||
}
|
||||
}
|
11
catchAdmin/system/module.json
Normal file
11
catchAdmin/system/module.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "系统管理",
|
||||
"alias": "system",
|
||||
"description": "",
|
||||
"keywords": [],
|
||||
"order": 2,
|
||||
"services": [],
|
||||
"aliases": {},
|
||||
"files": [],
|
||||
"requires": []
|
||||
}
|
18
catchAdmin/system/route.php
Normal file
18
catchAdmin/system/route.php
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
// 登录日志
|
||||
$router->get('log/login', '\catchAdmin\system\controller\LoginLog@list');
|
||||
$router->get('loginLog/index', '\catchAdmin\system\controller\LoginLog@index');
|
||||
$router->delete('loginLog/empty', '\catchAdmin\system\controller\LoginLog@empty');
|
||||
// 操作日志
|
||||
$router->get('log/operate', '\catchAdmin\system\controller\OperateLog@list');
|
||||
$router->get('operateLog/index', '\catchAdmin\system\controller\OperateLog@index');
|
||||
$router->delete('operateLog/empty', '\catchAdmin\system\controller\OperateLog@empty');
|
||||
|
||||
// 数据字典
|
||||
$router->get('data/dictionary', '\catchAdmin\system\controller\DataDictionary@index');
|
||||
$router->get('tables', '\catchAdmin\system\controller\DataDictionary@tables');
|
||||
$router->get('table/view/<table>', '\catchAdmin\system\controller\DataDictionary@view');
|
||||
$router->post('table/optimize', '\catchAdmin\system\controller\DataDictionary@optimize');
|
||||
$router->post('table/backup', '\catchAdmin\system\controller\DataDictionary@backup');
|
||||
|
||||
|
113
catchAdmin/system/view/dataDictionary/index.html
Normal file
113
catchAdmin/system/view/dataDictionary/index.html
Normal file
@ -0,0 +1,113 @@
|
||||
{extend name="$layout"}
|
||||
{block name="title"}登录日志{/block}
|
||||
{block name="search"}
|
||||
<div class="layui-form toolbar">
|
||||
<div class="layui-form-item">
|
||||
<!--<div class="layui-inline">
|
||||
<div class="layui-input-inline mr0">
|
||||
<input id="edtSearchAuth" class="layui-input" type="text" placeholder="输入角色名称"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<button id="btnSearchAuth" class="layui-btn icon-btn"><i class="layui-icon"></i>搜索
|
||||
</button>-->
|
||||
<button id="optimize" class="layui-btn icon-btn"><i class="layui-icon"></i>优化</button>
|
||||
<button id="backup" class="layui-btn layui-btn-normal icon-btn"><i class="layui-icon"></i>备份</button>
|
||||
<!--</div>-->
|
||||
</div>
|
||||
</div>
|
||||
{/block}
|
||||
{block name="table"}
|
||||
<table class="layui-table" id="database" lay-filter="database"></table>
|
||||
<!-- 表格操作列 -->cl
|
||||
<script type="text/html" id="operate">
|
||||
{:editButton('查看', 'view')}
|
||||
</script>
|
||||
{/block}
|
||||
{block name="script"}
|
||||
<script>
|
||||
layui.use(['layer', 'table', 'util', 'admin'], function () {
|
||||
var $ = layui.jquery;
|
||||
var table = layui.table;
|
||||
var admin = layui.admin;
|
||||
|
||||
table.render({
|
||||
elem: '#database',
|
||||
url: '{:url("tables")}',
|
||||
page: true,
|
||||
response: {
|
||||
statusCode: 10000,
|
||||
},
|
||||
// toolbar: true,
|
||||
cellMinWidth: 100,
|
||||
cols: [[
|
||||
{type: 'checkbox'},
|
||||
{field: 'Name', title: '表名'},
|
||||
{field: 'Engine', title: '表引擎'},
|
||||
{field: 'Collation', title: '数据集'},
|
||||
{field: 'Rows',title: '数据行数'},
|
||||
{field: 'Index_length', title: '索引大小', templet: function (d) {
|
||||
if (d.Index_length < (1024 * 1024)) {
|
||||
return Math.round(d.Index_length / 1024) + 'KB'
|
||||
} else {
|
||||
return Math.round(d.Index_length/(1024 * 1024)) + 'MB'
|
||||
}
|
||||
}
|
||||
},
|
||||
{field: 'Data_length', title: '数据大小', templet: function (d) {
|
||||
if (d.Data_length < (1024 * 1024)) {
|
||||
return Math.round(d.Data_length / 1024) + 'KB'
|
||||
} else {
|
||||
return Math.round(d.Data_length/(1024 * 1024)) + 'MB'
|
||||
}
|
||||
}
|
||||
},
|
||||
{field: 'Create_time', title: '创建时间'},
|
||||
{field: 'Comment', title: '表注释'},
|
||||
{align: 'center', toolbar: '#operate', title: '操作'}
|
||||
]],
|
||||
});
|
||||
|
||||
// 工具条点击事件
|
||||
table.on('tool(database)', function (obj) {
|
||||
if (obj.event === 'view') { // 查看
|
||||
admin.open({
|
||||
title: '查看表结构',
|
||||
url: '/table/view/'+obj.data.Name,
|
||||
area: '900px',
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$('#optimize').click(function () {
|
||||
var checkRows = table.checkStatus('database');
|
||||
if (checkRows.data.length == 0) {
|
||||
layer.msg('选择需要优化的表', {icon: 2});
|
||||
} else {
|
||||
var name = [];
|
||||
checkRows.data.map(function(item,index){
|
||||
name.push(item.Name)
|
||||
});
|
||||
admin.req("{:url('table/optimize')}", {data:name},function (response) {
|
||||
layer.msg(response.msg, {icon: 1})
|
||||
}, 'post')
|
||||
}
|
||||
})
|
||||
|
||||
$('#backup').click(function () {
|
||||
var checkRows = table.checkStatus('database');
|
||||
if (checkRows.data.length == 0) {
|
||||
layer.msg('选择需要备份的表', {icon: 2});
|
||||
} else {
|
||||
var name = [];
|
||||
checkRows.data.map(function(item,index){
|
||||
name.push(item.Name)
|
||||
});
|
||||
admin.req("{:url('table/backup')}", {data:name},function (response) {
|
||||
layer.msg(response.msg, {icon: response.code === 10000 ? 1 : 2})
|
||||
}, 'post')
|
||||
}
|
||||
})
|
||||
});
|
||||
</script>
|
||||
{/block}
|
39
catchAdmin/system/view/dataDictionary/view.html
Normal file
39
catchAdmin/system/view/dataDictionary/view.html
Normal file
@ -0,0 +1,39 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Title</title>
|
||||
</head>
|
||||
<body>
|
||||
<div style="padding: 10px">
|
||||
<table class="layui-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>字段</th>
|
||||
<th>类型</th>
|
||||
<th>字符集</th>
|
||||
<th>Null</th>
|
||||
<th>索引</th>
|
||||
<th>默认值</th>
|
||||
<th>权限</th>
|
||||
<th>注释</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{foreach $table as $field}
|
||||
<tr>
|
||||
<td>{$field['Field']}</td>
|
||||
<td>{$field['Type']}</td>
|
||||
<td>{$field['Collation']}</td>
|
||||
<td>{$field['Null']}</td>
|
||||
<td>{$field['Key']}</td>
|
||||
<td>{$field['Default']}</td>
|
||||
<td>{$field['Privileges']}</td>
|
||||
<td>{$field['Comment']}</td>
|
||||
</tr>
|
||||
{/foreach}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
68
catchAdmin/system/view/loginLog/index.html
Normal file
68
catchAdmin/system/view/loginLog/index.html
Normal file
@ -0,0 +1,68 @@
|
||||
{extend name="$layout"}
|
||||
{block name="title"}登录日志{/block}
|
||||
{block name="search"}
|
||||
<div class="layui-form toolbar">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<div class="layui-input-inline mr0">
|
||||
<input id="edtSearchAuth" class="layui-input" type="text" placeholder="输入角色名称"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<button id="btnSearchAuth" class="layui-btn icon-btn"><i class="layui-icon"></i>搜索
|
||||
</button>
|
||||
<button id="empty" class="layui-btn icon-btn"><i class="layui-icon"></i>清空</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/block}
|
||||
{block name="table"}
|
||||
<table class="layui-table" id="log"></table>
|
||||
{/block}
|
||||
{block name="script"}
|
||||
<script>
|
||||
layui.use(['layer', 'form', 'table', 'util', 'admin'], function () {
|
||||
var $ = layui.jquery;
|
||||
var table = layui.table;
|
||||
var util = layui.util;
|
||||
var admin = layui.admin;
|
||||
|
||||
var t = table.render({
|
||||
elem: '#log',
|
||||
url: '{:url("log/login")}',
|
||||
page: true,
|
||||
response: {
|
||||
statusCode: 10000,
|
||||
},
|
||||
// toolbar: true,
|
||||
cellMinWidth: 100,
|
||||
cols: [[
|
||||
{type: 'id', title: '序号', field: 'id'},
|
||||
{field: 'login_name', title: '登录名'},
|
||||
{field: 'login_ip', title: '登录IP'},
|
||||
{field: 'browser', title: '浏览器'},
|
||||
{field: 'os', title: '操作系统'},
|
||||
{field: 'status', title: '状态', templet: function (d) {
|
||||
return d.status === 1 ?
|
||||
'<button class="layui-btn layui-btn-xs">成功</button>' :
|
||||
'<button class="layui-btn layui-btn-xs layui-btn-danger">失败</button>'
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'login_at', templet: function (d) {
|
||||
return util.toDateString(d.login_at);
|
||||
}, title: '登录时间'
|
||||
},
|
||||
]],
|
||||
});
|
||||
$('#empty').click(function () {
|
||||
layer.confirm('确定清空日志吗?', function () {
|
||||
admin.req("{:url('loginLog/empty')}", {}, function (response) {
|
||||
layer.msg(response.msg, {icon:1});
|
||||
t.reload();
|
||||
}, 'delete')
|
||||
})
|
||||
})
|
||||
});
|
||||
</script>
|
||||
{/block}
|
63
catchAdmin/system/view/operateLog/index.html
Normal file
63
catchAdmin/system/view/operateLog/index.html
Normal file
@ -0,0 +1,63 @@
|
||||
{extend name="$layout"}
|
||||
{block name="title"}操作日志{/block}
|
||||
{block name="search"}
|
||||
<div class="layui-form toolbar">
|
||||
<div class="layui-form-item">
|
||||
<!--<div class="layui-inline">
|
||||
<div class="layui-input-inline mr0">
|
||||
<input id="edtSearchAuth" class="layui-input" type="text" placeholder="输入角色名称"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<button id="btnSearchAuth" class="layui-btn icon-btn"><i class="layui-icon"></i>搜索
|
||||
</button>-->
|
||||
<button id="empty" class="layui-btn icon-btn"><i class="layui-icon"></i>清空</button>
|
||||
<!--</div>-->
|
||||
</div>
|
||||
</div>
|
||||
{/block}
|
||||
{block name="table"}
|
||||
<table class="layui-table" id="log"></table>
|
||||
{/block}
|
||||
{block name="script"}
|
||||
<script>
|
||||
layui.use(['layer', 'form', 'table', 'util', 'admin'], function () {
|
||||
var $ = layui.jquery;
|
||||
var table = layui.table;
|
||||
var util = layui.util;
|
||||
var admin = layui.admin;
|
||||
|
||||
var t = table.render({
|
||||
elem: '#log',
|
||||
url: '{:url("log/operate")}',
|
||||
page: true,
|
||||
response: {
|
||||
statusCode: 10000,
|
||||
},
|
||||
// toolbar: true,
|
||||
cellMinWidth: 100,
|
||||
cols: [[
|
||||
{type: 'id', title: '序号', field: 'id'},
|
||||
{field: 'module', title: '模块'},
|
||||
{field: 'ip', title: 'IP'},
|
||||
{field: 'operate', title: 'operate'},
|
||||
{field: 'creator', title: '操作者'},
|
||||
{field: 'method', title: '请求方法'},
|
||||
{
|
||||
field: 'created_at', sort: true, templet: function (d) {
|
||||
return util.toDateString(d.created_at);
|
||||
}, title: '创建时间'
|
||||
},
|
||||
]],
|
||||
});
|
||||
$('#empty').click(function () {
|
||||
layer.confirm('确定清空日志吗?', function () {
|
||||
admin.req("{:url('operateLog/empty')}", {}, function (response) {
|
||||
layer.msg(response.msg, {icon:1});
|
||||
t.reload();
|
||||
}, 'delete')
|
||||
})
|
||||
})
|
||||
});
|
||||
</script>
|
||||
{/block}
|
99
catchAdmin/user/Auth.php
Normal file
99
catchAdmin/user/Auth.php
Normal file
@ -0,0 +1,99 @@
|
||||
<?php
|
||||
namespace catchAdmin\user;
|
||||
|
||||
use catchAdmin\permissions\model\Permissions;
|
||||
use catchAdmin\user\model\Users;
|
||||
use catcher\exceptions\LoginFailedException;
|
||||
use think\facade\Session;
|
||||
|
||||
class Auth
|
||||
{
|
||||
protected const USER_KEY = 'admin_user';
|
||||
|
||||
/**
|
||||
* 登陆
|
||||
*
|
||||
* @time 2019年11月28日
|
||||
* @param $params
|
||||
* @return bool
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
* @throws LoginFailedException
|
||||
*/
|
||||
public static function login($params)
|
||||
{
|
||||
$user = Users::where('email', $params['email'])->find();
|
||||
|
||||
if (!$user) {
|
||||
throw new LoginFailedException('登陆失败, 请检查用户名和密码');
|
||||
}
|
||||
|
||||
if (!password_verify($params['password'], $user->password)) {
|
||||
throw new LoginFailedException('登陆失败, 请检查用户名和密码');
|
||||
}
|
||||
|
||||
if ($user->status == Users::DISABLE) {
|
||||
throw new LoginFailedException('该用户已被禁用');
|
||||
}
|
||||
|
||||
// 记录用户登录
|
||||
$user->last_login_ip = request()->ip();
|
||||
$user->last_login_time = time();
|
||||
$user->save();
|
||||
|
||||
Session::set(self::getLoginUserKey(), $user);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 退出登陆
|
||||
*
|
||||
* @time 2019年11月28日
|
||||
* @return bool
|
||||
*/
|
||||
public static function logout(): bool
|
||||
{
|
||||
Session::delete(self::getLoginUserKey());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月15日
|
||||
* @return mixed
|
||||
*/
|
||||
public static function user()
|
||||
{
|
||||
return Session::get(self::getLoginUserKey(), null);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月15日
|
||||
* @return string
|
||||
*/
|
||||
protected static function getLoginUserKey(): string
|
||||
{
|
||||
return md5(self::USER_KEY);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月15日
|
||||
* @param $mark
|
||||
* @param $module
|
||||
* @return bool
|
||||
*/
|
||||
public static function hasPermissions($mark, $module): bool
|
||||
{
|
||||
$permissionIds = self::user()->get->getPermissionsBy();
|
||||
|
||||
$permissionId = Permissions::where('module', $module)
|
||||
->where('permission_mark', $mark)->value('id');
|
||||
|
||||
return in_array($permissionId, $permissionIds);
|
||||
}
|
||||
}
|
@ -2,15 +2,16 @@
|
||||
namespace catchAdmin\user\controller;
|
||||
|
||||
use app\Request;
|
||||
use catchAdmin\permissions\model\Roles;
|
||||
use catchAdmin\user\model\Users;
|
||||
use catchAdmin\user\request\CreateRequest;
|
||||
use catchAdmin\user\request\UpdateRequest;
|
||||
use catcher\base\BaseController;
|
||||
use catcher\base\CatchController;
|
||||
use catcher\CatchForm;
|
||||
use catcher\CatchResponse;
|
||||
use think\response\Json;
|
||||
use catcher\Tree;
|
||||
|
||||
class User extends BaseController
|
||||
class User extends CatchController
|
||||
{
|
||||
protected $user;
|
||||
|
||||
@ -46,10 +47,11 @@ class User extends BaseController
|
||||
$form = new CatchForm();
|
||||
|
||||
$form->formId('userForm');
|
||||
$form->text('username', '用户名')->verify('required')->placeholder('请输入用户名');
|
||||
$form->text('email', '邮箱')->verify('email')->placeholder('请输入邮箱');
|
||||
$form->password('password', '密码')->id('pwd')->verify('required|psw')->placeholder('请输入密码');
|
||||
$form->password('passwordConfirm', '确认密码')->verify('required|equalTo', ['pwd', '两次密码输入不一致'])->placeholder('请再次输入密码');
|
||||
$form->text('username', '用户名', true)->verify('required')->placeholder('请输入用户名');
|
||||
$form->text('email', '邮箱', true)->verify('email')->placeholder('请输入邮箱');
|
||||
$form->password('password', '密码', true)->id('pwd')->verify('required|psw')->placeholder('请输入密码');
|
||||
$form->password('passwordConfirm', '确认密码', true)->verify('required|equalTo', ['pwd', '两次密码输入不一致'])->placeholder('请再次输入密码');
|
||||
$form->dom('<div id="roles"></div>', '角色');
|
||||
$form->formBtn('submitUser');
|
||||
|
||||
return $this->fetch([
|
||||
@ -65,7 +67,13 @@ class User extends BaseController
|
||||
*/
|
||||
public function save(CreateRequest $request)
|
||||
{
|
||||
return CatchResponse::success($this->user->storeBy($request->post()));
|
||||
$this->user->storeBy($request->post());
|
||||
|
||||
if (!empty($request->param('roleids'))) {
|
||||
$this->user->attach($request->param('roleids'));
|
||||
}
|
||||
|
||||
return CatchResponse::success();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -90,10 +98,11 @@ class User extends BaseController
|
||||
$form = new CatchForm();
|
||||
|
||||
$form->formId('userForm');
|
||||
$form->text('username', '用户名')->verify('required')->default($user->username)->placeholder('请输入用户名');
|
||||
$form->text('email', '邮箱')->verify('email')->default($user->email)->placeholder('请输入邮箱');
|
||||
$form->text('username', '用户名', true)->verify('required')->default($user->username)->placeholder('请输入用户名');
|
||||
$form->text('email', '邮箱', true)->verify('email')->default($user->email)->placeholder('请输入邮箱');
|
||||
$form->password('password', '密码')->id('pwd')->placeholder('请输入密码');
|
||||
$form->password('passwordConfirm', '确认密码')->verify('equalTo', ['pwd', '两次密码输入不一致'])->placeholder('请再次输入密码');
|
||||
$form->dom('<div id="roles"></div>', '角色');
|
||||
$form->formBtn('submitUser');
|
||||
|
||||
return $this->fetch([
|
||||
@ -111,7 +120,17 @@ class User extends BaseController
|
||||
*/
|
||||
public function update($id, UpdateRequest $request)
|
||||
{
|
||||
return CatchResponse::success($this->user->updateBy($id, $request->post()));
|
||||
$this->user->updateBy($id, $request->post());
|
||||
|
||||
$user = $this->user->findBy($id);
|
||||
|
||||
$user->detach();
|
||||
|
||||
if (!empty($request->param('roleids'))) {
|
||||
$user->attach($request->param('roleids'));
|
||||
}
|
||||
|
||||
return CatchResponse::success();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -122,7 +141,12 @@ class User extends BaseController
|
||||
*/
|
||||
public function delete($id)
|
||||
{
|
||||
return CatchResponse::success($this->user->deleteBy($id));
|
||||
// 删除角色
|
||||
$this->user->findBy($id)->detach();
|
||||
|
||||
$this->user->deleteBy($id);
|
||||
|
||||
return CatchResponse::success();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -158,4 +182,29 @@ class User extends BaseController
|
||||
|
||||
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,
|
||||
]);
|
||||
}
|
||||
}
|
@ -33,11 +33,11 @@ class Users extends Migrator
|
||||
->addColumn('password', 'string',array('limit' => 255,'comment'=>'用户密码'))
|
||||
->addColumn('email', 'string',array('limit' => 100, 'comment'=>'邮箱 登录'))
|
||||
->addColumn('status', 'boolean',array('limit' => 1,'default'=> 1,'comment'=>'用户状态 1 正常 2 禁用'))
|
||||
->addColumn('last_login_ip', 'integer',array('limit' => 11,'default'=>0,'comment'=>'最后登录IP'))
|
||||
->addColumn('last_login_ip', 'string',array('limit' => 30,'default'=>0,'comment'=>'最后登录IP'))
|
||||
->addColumn('last_login_time', 'integer',array('default'=>0,'comment'=>'最后登录时间', 'signed' => false))
|
||||
->addColumn('created_at', 'integer', array('default'=>0,'comment'=>'创建时间', 'signed' => false ))
|
||||
->addColumn('updated_at', 'integer', array('default'=>0,'comment'=>'更新时间', 'signed' => false))
|
||||
->addColumn('deleted_at', 'integer', array('null'=>true,'comment'=>'删除状态,0未删除 >0 已删除', 'signed' => false))
|
||||
->addColumn('deleted_at', 'integer', array('default'=>0,'comment'=>'删除状态,0未删除 >0 已删除', 'signed' => false))
|
||||
->create();
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
use think\migration\Seeder;
|
||||
|
||||
class Abc extends Seeder
|
||||
class UsersSeed extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run Method.
|
||||
@ -14,6 +14,10 @@ class Abc extends Seeder
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
|
||||
return \catchAdmin\user\model\Users::create([
|
||||
'username' => 'admin',
|
||||
'password' => 'admin',
|
||||
'email' => 'admin@gmail.com',
|
||||
]);
|
||||
}
|
||||
}
|
@ -1,10 +1,13 @@
|
||||
<?php
|
||||
namespace catchAdmin\user\model;
|
||||
|
||||
use catcher\base\BaseModel;
|
||||
use catchAdmin\permissions\model\HasRolesTrait;
|
||||
use catcher\base\CatchModel;
|
||||
|
||||
class Users extends BaseModel
|
||||
class Users extends CatchModel
|
||||
{
|
||||
use HasRolesTrait;
|
||||
|
||||
protected $name = 'users';
|
||||
|
||||
protected $field = [
|
||||
@ -33,9 +36,19 @@ class Users extends BaseModel
|
||||
return password_hash($value, PASSWORD_DEFAULT);
|
||||
}
|
||||
|
||||
public function getList($search)
|
||||
/**
|
||||
* 用户列表
|
||||
*
|
||||
* @time 2019年12月08日
|
||||
* @param $search
|
||||
* @throws \think\db\exception\DbException
|
||||
* @return \think\Paginator
|
||||
*/
|
||||
public function getList($search): \think\Paginator
|
||||
{
|
||||
return (($search['trash'] ?? false) ? static::onlyTrashed() : $this)->when($search['username'] ?? false, function ($query) use ($search){
|
||||
return (($search['trash'] ?? false) ? static::onlyTrashed() : $this)
|
||||
->field(['id', 'username', 'email', 'status','last_login_time','last_login_ip', 'created_at', 'updated_at'])
|
||||
->when($search['username'] ?? false, function ($query) use ($search){
|
||||
return $query->whereLike('username', $search['username']);
|
||||
})
|
||||
->when($search['email'] ?? false, function ($query) use ($search){
|
||||
@ -45,4 +58,26 @@ class Users extends BaseModel
|
||||
return $query->where('status', $search['status']);
|
||||
})->paginate($search['limit'] ?? $this->limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取权限
|
||||
*
|
||||
* @time 2019年12月12日
|
||||
* @param $uid
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
* @return array
|
||||
*/
|
||||
public function getPermissionsBy($uid = 0): array
|
||||
{
|
||||
$roles = $uid ? $this->findBy($uid)->getRoles() : $this->getRoles();
|
||||
|
||||
$permissionIds = [];
|
||||
foreach ($roles as $role) {
|
||||
$permissionIds = array_merge($permissionIds, $role->getPermissions()->column('id'));
|
||||
}
|
||||
|
||||
return array_unique($permissionIds);
|
||||
}
|
||||
}
|
@ -2,9 +2,9 @@
|
||||
namespace catchAdmin\user\request;
|
||||
|
||||
use catchAdmin\user\model\Users;
|
||||
use catcher\base\BaseRequest;
|
||||
use catcher\base\CatchRequest;
|
||||
|
||||
class CreateRequest extends BaseRequest
|
||||
class CreateRequest extends CatchRequest
|
||||
{
|
||||
|
||||
protected function rules(): array
|
||||
|
@ -2,9 +2,9 @@
|
||||
namespace catchAdmin\user\request;
|
||||
|
||||
use catchAdmin\user\model\Users;
|
||||
use catcher\base\BaseRequest;
|
||||
use catcher\base\CatchRequest;
|
||||
|
||||
class UpdateRequest extends BaseRequest
|
||||
class UpdateRequest extends CatchRequest
|
||||
{
|
||||
protected function rules(): array
|
||||
{
|
||||
|
@ -2,7 +2,8 @@
|
||||
|
||||
$router->resource('user', '\catchAdmin\user\controller\User');
|
||||
// 用户列表
|
||||
$router->get('users', '\catchAdmin\user\controller\User/list');
|
||||
$router->get('users', '\catchAdmin\user\controller\User@list');
|
||||
// 切换状态
|
||||
$router->put('user/switch/status/<id>', '\catchAdmin\user\controller\User/switchStatus');
|
||||
$router->put('user/recover/<id>', '\catchAdmin\user\controller\User/recover');
|
||||
$router->put('user/switch/status/<id>', '\catchAdmin\user\controller\User@switchStatus');
|
||||
$router->put('user/recover/<id>', '\catchAdmin\user\controller\User@recover');
|
||||
$router->get('user/get/roles', '\catchAdmin\user\controller\User@getRoles');
|
||||
|
@ -1,17 +0,0 @@
|
||||
<?php
|
||||
namespace catchAdmin\user\validate;
|
||||
|
||||
use catcher\base\BaseValidate;
|
||||
|
||||
class CreateValidate extends BaseValidate
|
||||
{
|
||||
protected function getRules(): array
|
||||
{
|
||||
// TODO: Implement getRules() method.
|
||||
return [
|
||||
'username|用户名' => 'require|max:20',
|
||||
'password|密码' => 'require|max:20',
|
||||
'email|邮箱' => 'require|email'
|
||||
];
|
||||
}
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
<?php
|
||||
namespace catchAdmin\user\validate;
|
||||
|
||||
use catchAdmin\user\model\Users;
|
||||
use catcher\base\BaseValidate;
|
||||
|
||||
class UpdateValidate extends BaseValidate
|
||||
{
|
||||
protected function getRules(): array
|
||||
{
|
||||
// TODO: Implement getRules() method.
|
||||
return [
|
||||
'username|用户名' => 'require|max:20',
|
||||
'password|密码' => 'require|max:20',
|
||||
'email|邮箱' => 'require|email|unique:'.Users::class.',email,'.request()->route('user').',id',
|
||||
];
|
||||
}
|
||||
}
|
@ -1,28 +1,38 @@
|
||||
{$form|raw}
|
||||
<script>
|
||||
layui.use(['layer', 'form', 'admin', 'formX'], function () {
|
||||
layui.use(['layer', 'form', 'admin', 'formX','authtree'], function () {
|
||||
var $ = layui.jquery;
|
||||
var layer = layui.layer;
|
||||
var form = layui.form;
|
||||
var admin = layui.admin;
|
||||
var authtree = layui.authtree;
|
||||
var mUser = admin.getLayerData('#userForm'); // 列表页面传递的数据,#modelUserForm这个只要写弹窗内任意一个元素的id即可
|
||||
// 回显数据
|
||||
form.val('userForm', mUser);
|
||||
|
||||
// 表单提交事件
|
||||
form.on('submit(submitUser)', function (data) {
|
||||
layer.load(2);
|
||||
var url = mUser ? '{:url("user")}' : '{:url("user")}';
|
||||
$.post(url, data.field, function (response) {
|
||||
layer.closeAll('loading');
|
||||
if (response.code === 10000) {
|
||||
admin.req(url, data.field, function (response) {
|
||||
layer.msg(response.msg, {icon: 1});
|
||||
admin.putLayerData('formOk', true, '#userForm'); // 设置操作成功的标识,#modelUserForm这个只要写弹窗内任意一个元素的id即可
|
||||
admin.closeDialog('#userForm'); // 关闭页面层弹窗
|
||||
} else {
|
||||
layer.msg(response.msg, {icon: 2});
|
||||
}
|
||||
}, 'json');
|
||||
}, 'post');
|
||||
return false;
|
||||
});
|
||||
admin.req('{:url("/user/get/roles")}',{}, function (response) {
|
||||
authtree.render('#roles', response.data.roles,{
|
||||
inputname: 'roleids[]',
|
||||
layfilter: 'lay-check-auth',
|
||||
autowidth: true,
|
||||
nameKey: 'role_name',
|
||||
valueKey: 'id',
|
||||
childKey: 'children',
|
||||
collapseLeafNode: true,
|
||||
theme: 'auth-skin-default',
|
||||
autochecked: false,
|
||||
autoclose: false,
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
@ -1,25 +1,38 @@
|
||||
{$form|raw}
|
||||
<script>
|
||||
layui.use(['layer', 'form', 'admin', 'formX'], function () {
|
||||
layui.use(['layer', 'form', 'admin', 'formX', 'authtree'], function () {
|
||||
var $ = layui.jquery;
|
||||
var layer = layui.layer;
|
||||
var form = layui.form;
|
||||
var admin = layui.admin;
|
||||
var authtree = layui.authtree;
|
||||
var mUser = admin.getLayerData('#userForm'); // 列表页面传递的数据,#modelUserForm这个只要写弹窗内任意一个元素的id即可
|
||||
// 回显数据
|
||||
form.val('userForm', mUser);
|
||||
var uid = "{$uid}";
|
||||
admin.req('{:url("/user/get/roles")}',{uid:uid}, function (response) {
|
||||
authtree.render('#roles', response.data.roles, {
|
||||
inputname: 'roleids[]',
|
||||
primaryKey: 'id',
|
||||
parentKey: 'parent_id',
|
||||
layfilter: 'lay-check-auth',
|
||||
autowidth: true,
|
||||
nameKey: 'role_name',
|
||||
valueKey: 'id',
|
||||
childKey: 'children',
|
||||
collapseLeafNode: true,
|
||||
theme: 'auth-skin-default',
|
||||
checkedKey: response.data.hasRoles,
|
||||
autochecked: false,
|
||||
autoclose: false,
|
||||
});
|
||||
});
|
||||
// 表单提交事件
|
||||
form.on('submit(submitUser)', function (data) {
|
||||
admin.req('/user/' + uid, data.field, function (response) {
|
||||
layer.closeAll('loading');
|
||||
if (response.code == 10000) {
|
||||
layer.msg(response.msg, {icon: 1});
|
||||
admin.putLayerData('formOk', true, '#userForm'); // 设置操作成功的标识,#modelUserForm这个只要写弹窗内任意一个元素的id即可
|
||||
admin.closeDialog('#userForm'); // 关闭页面层弹窗
|
||||
} else {
|
||||
layer.msg(response.msg, {icon: 2});
|
||||
}
|
||||
}, 'put');
|
||||
return false;
|
||||
});
|
||||
|
@ -1,4 +1,4 @@
|
||||
{extend name="../../../view/layout"}
|
||||
{extend name="$layout"}
|
||||
{block name="title"}用户管理{/block}
|
||||
{block name="search"}
|
||||
<div class="layui-form toolbar">
|
||||
@ -47,7 +47,7 @@
|
||||
<table class="layui-table" id="tableUser" lay-filter="tableUser"></table>
|
||||
<!-- 表格操作列 -->
|
||||
<script type="text/html" id="tableBarUser">
|
||||
<a class="layui-btn layui-btn-primary layui-btn-xs" lay-event="edit">修改</a>
|
||||
{:editButton()}
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="{{d.deleted_at ? 'recover' : 'del'}}">{{d.deleted_at ? '恢复' : '删除'}}</a>
|
||||
</script>
|
||||
<!-- 表格状态列 -->
|
||||
@ -122,7 +122,6 @@
|
||||
});
|
||||
|
||||
function recover(uid, username) {
|
||||
console.log(username)
|
||||
layer.confirm('确定要恢复“' + username + '”吗?', {
|
||||
skin: 'layui-layer-admin',
|
||||
shade: .1
|
||||
@ -145,6 +144,7 @@
|
||||
title: (mUser ? '修改' : '添加') + '用户',
|
||||
url: mUser ? '/user/'+mUser.id + '/edit':'/user/create',
|
||||
data: mUser, // 传递数据到表单页面
|
||||
area: '500px',
|
||||
end: function () {
|
||||
if (admin.getLayerData(layIndex, 'formOk')) { // 判断表单操作成功标识
|
||||
insTb.reload(); // 成功刷新表格
|
||||
|
@ -28,7 +28,9 @@
|
||||
"topthink/think-trace":"^1.0"
|
||||
},
|
||||
"autoload": {
|
||||
"files": [],
|
||||
"files": [
|
||||
"catchAdmin/helper.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"app\\": "app",
|
||||
"catchAdmin\\": "catchAdmin",
|
||||
|
13
config/catch.php
Normal file
13
config/catch.php
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
return [
|
||||
/**
|
||||
* set domain if you need
|
||||
*
|
||||
*/
|
||||
'domain' => '',
|
||||
|
||||
/**
|
||||
* set error page
|
||||
*/
|
||||
'error' => root_path('catchAdmin/index/view/') . 'error.html',
|
||||
];
|
@ -7,11 +7,11 @@ return [
|
||||
// pathinfo分隔符
|
||||
'pathinfo_depr' => '/',
|
||||
// URL伪静态后缀
|
||||
'url_html_suffix' => 'html',
|
||||
'url_html_suffix' => '',
|
||||
// URL普通方式参数 用于自动生成
|
||||
'url_common_param' => true,
|
||||
// 是否开启路由延迟解析
|
||||
'url_lazy_route' => false,
|
||||
'url_lazy_route' => true,
|
||||
// 是否强制使用路由
|
||||
'url_route_must' => false,
|
||||
// 合并路由规则
|
||||
|
@ -13,7 +13,7 @@ return [
|
||||
// 存储连接标识 当type使用cache的时候有效
|
||||
'store' => null,
|
||||
// 过期时间
|
||||
'expire' => 1440,
|
||||
'expire' => 24 * 3600,
|
||||
// 前缀
|
||||
'prefix' => '',
|
||||
'prefix' => 'catch_admin',
|
||||
];
|
||||
|
@ -18,15 +18,14 @@ class CatchAdmin
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建目录
|
||||
*
|
||||
* @time 2019年12月04日
|
||||
* @param $module
|
||||
* @time 2019年12月16日
|
||||
* @param string $directory
|
||||
* @return string
|
||||
*/
|
||||
public static function moduleDirectory($module): string
|
||||
public static function makeDirectory(string $directory): string
|
||||
{
|
||||
$directory = self::directory() . $module . DIRECTORY_SEPARATOR;
|
||||
|
||||
if (!is_dir($directory) && !mkdir($directory, 0777, true) && !is_dir($directory)) {
|
||||
throw new \RuntimeException(sprintf('Directory "%s" was not created', $directory));
|
||||
}
|
||||
@ -34,6 +33,17 @@ class CatchAdmin
|
||||
return $directory;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月04日
|
||||
* @param $module
|
||||
* @return string
|
||||
*/
|
||||
public static function moduleDirectory($module): string
|
||||
{
|
||||
return self::makeDirectory(self::directory() . $module . DIRECTORY_SEPARATOR);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年11月30日
|
||||
@ -41,13 +51,18 @@ class CatchAdmin
|
||||
*/
|
||||
public static function cacheDirectory(): string
|
||||
{
|
||||
$directory = app()->getRuntimePath() . self::NAME . DIRECTORY_SEPARATOR;
|
||||
return self::makeDirectory(app()->getRuntimePath() . self::NAME . DIRECTORY_SEPARATOR);
|
||||
}
|
||||
|
||||
if (!is_dir($directory) && !mkdir($directory, 0777, true) && !is_dir($directory)) {
|
||||
throw new \RuntimeException(sprintf('Directory "%s" was not created', $directory));
|
||||
}
|
||||
|
||||
return $directory;
|
||||
/**
|
||||
* 备份地址
|
||||
*
|
||||
* @time 2019年12月13日
|
||||
* @return string
|
||||
*/
|
||||
public static function backupDirectory(): string
|
||||
{
|
||||
return self::makeDirectory(self::cacheDirectory() . 'backup' .DIRECTORY_SEPARATOR);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -81,13 +96,7 @@ class CatchAdmin
|
||||
*/
|
||||
public static function getModuleViewPath($module): string
|
||||
{
|
||||
$directory = self::directory() . $module . DIRECTORY_SEPARATOR . 'view' . DIRECTORY_SEPARATOR;
|
||||
|
||||
if (!is_dir($directory) && !mkdir($directory, 0777, true) && !is_dir($directory)) {
|
||||
throw new \RuntimeException(sprintf('Directory "%s" was not created', $directory));
|
||||
}
|
||||
|
||||
return $directory;
|
||||
return self::makeDirectory(self::directory() . $module . DIRECTORY_SEPARATOR . 'view' . DIRECTORY_SEPARATOR);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -98,13 +107,7 @@ class CatchAdmin
|
||||
*/
|
||||
public static function getModuleModelDirectory($module): string
|
||||
{
|
||||
$directory = self::directory() . $module . DIRECTORY_SEPARATOR . 'model' . DIRECTORY_SEPARATOR;
|
||||
|
||||
if (!is_dir($directory) && !mkdir($directory, 0777, true) && !is_dir($directory)) {
|
||||
throw new \RuntimeException(sprintf('Directory "%s" was not created', $directory));
|
||||
}
|
||||
|
||||
return $directory;
|
||||
return self::makeDirectory(self::directory() . $module . DIRECTORY_SEPARATOR . 'model' . DIRECTORY_SEPARATOR);
|
||||
}
|
||||
/**
|
||||
*
|
||||
@ -126,6 +129,32 @@ class CatchAdmin
|
||||
return $modules;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月12日
|
||||
* @return array
|
||||
*/
|
||||
public static function getModulesInfo($select = true): array
|
||||
{
|
||||
$modules = [];
|
||||
if ($select) {
|
||||
foreach (self::getModulesDirectory() as $module) {
|
||||
$moduleInfo = self::getModuleInfo($module);
|
||||
$modules[] = [
|
||||
'value' => $moduleInfo['alias'],
|
||||
'title' => $moduleInfo['name'],
|
||||
];
|
||||
}
|
||||
} else {
|
||||
foreach (self::getModulesDirectory() as $module) {
|
||||
$moduleInfo = self::getModuleInfo($module);
|
||||
$modules[$moduleInfo['alias']] = $moduleInfo['name'];
|
||||
}
|
||||
}
|
||||
|
||||
return $modules;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年11月30日
|
||||
@ -201,17 +230,15 @@ class CatchAdmin
|
||||
/**
|
||||
*
|
||||
* @time 2019年11月30日
|
||||
* @return string
|
||||
* @return mixed
|
||||
*/
|
||||
public static function getRoutes(): string
|
||||
public static function getRoutes()
|
||||
{
|
||||
if (file_exists(self::getCacheViewsFile())) {
|
||||
return self::getCacheRoutesFile();
|
||||
if (file_exists(self::getCacheRoutesFile())) {
|
||||
return [self::getCacheRoutesFile()];
|
||||
}
|
||||
|
||||
self::cacheRoutes();
|
||||
|
||||
return self::getCacheRoutesFile();
|
||||
return self::getModuleRoutes();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -228,6 +255,24 @@ class CatchAdmin
|
||||
return self::getModuleViews();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月15日
|
||||
* @return array
|
||||
*/
|
||||
public static function getModuleRoutes(): array
|
||||
{
|
||||
$routeFiles = [];
|
||||
foreach (self::getModulesDirectory() as $module) {
|
||||
$moduleInfo = self::getModuleInfo($module);
|
||||
if (!in_array($moduleInfo['alias'], ['login']) && file_exists($module . 'route.php')) {
|
||||
$routeFiles[] = $module . 'route.php';
|
||||
}
|
||||
}
|
||||
|
||||
return $routeFiles;
|
||||
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @time 2019年11月30日
|
||||
@ -235,14 +280,9 @@ class CatchAdmin
|
||||
*/
|
||||
public static function cacheRoutes()
|
||||
{
|
||||
$routeFiles = [];
|
||||
foreach (self::getModulesDirectory() as $module) {
|
||||
if (file_exists($module . 'route.php')) {
|
||||
$routeFiles[] = $module . 'route.php';
|
||||
}
|
||||
}
|
||||
$routes = '';
|
||||
foreach ($routeFiles as $route) {
|
||||
|
||||
foreach (self::getModuleRoutes() as $route) {
|
||||
$routes .= trim(str_replace('<?php', '', file_get_contents($route))) . PHP_EOL;
|
||||
}
|
||||
|
||||
|
@ -6,12 +6,14 @@ namespace catcher;
|
||||
* @package catcher
|
||||
*
|
||||
*
|
||||
* @method CatchForm text($column, $label = '')
|
||||
* @method CatchForm image($column, $label = '')
|
||||
* @method CatchForm radio($column, $label = '')
|
||||
* @method CatchForm select($column, $label = '')
|
||||
* @method CatchForm textarea($column, $label = '')
|
||||
* @method CatchForm password($column, $label = '')
|
||||
* @method CatchForm text($column, $label = '', $required = false)
|
||||
* @method CatchForm image($column, $label = '', $required = false)
|
||||
* @method CatchForm radio($column, $label = '', $required = false)
|
||||
* @method CatchForm select($column, $label = '', $required = false)
|
||||
* @method CatchForm textarea($column, $label = '', $required = false)
|
||||
* @method CatchForm password($column, $label = '', $required = false)
|
||||
* @method CatchForm hidden($column, $label = '', $required = false)
|
||||
* @method CatchForm dom($column, $label = '', $required = false)
|
||||
*
|
||||
*/
|
||||
class CatchForm
|
||||
@ -30,35 +32,65 @@ class CatchForm
|
||||
|
||||
protected $btn;
|
||||
|
||||
public function action($acton)
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月10日
|
||||
* @param $acton
|
||||
* @return CatchForm
|
||||
*/
|
||||
public function action($acton): CatchForm
|
||||
{
|
||||
$this->action = $acton;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function method($method)
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月10日
|
||||
* @param $method
|
||||
* @return CatchForm
|
||||
*/
|
||||
public function method($method): CatchForm
|
||||
{
|
||||
$this->method = $method;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function formId($formId)
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月10日
|
||||
* @param $formId
|
||||
* @return CatchForm
|
||||
*/
|
||||
public function formId($formId): CatchForm
|
||||
{
|
||||
$this->formId = $formId;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function enctype($enctype ="multipart/form-data")
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月10日
|
||||
* @param string $enctype
|
||||
* @return CatchForm
|
||||
*/
|
||||
public function enctype($enctype ="multipart/form-data"): CatchForm
|
||||
{
|
||||
$this->enctype = $enctype;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function id($id)
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月10日
|
||||
* @param $id
|
||||
* @return CatchForm
|
||||
*/
|
||||
public function id($id): CatchForm
|
||||
{
|
||||
$this->fields[$this->name] = array_merge($this->fields[$this->name], [
|
||||
'id' => sprintf('id="%s"', $id),
|
||||
@ -66,8 +98,15 @@ class CatchForm
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function class($class='', $labelClass = '', $inlineClass = '')
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月10日
|
||||
* @param string $class
|
||||
* @param string $labelClass
|
||||
* @param string $inlineClass
|
||||
* @return CatchForm
|
||||
*/
|
||||
public function class($class='', $labelClass = '', $inlineClass = ''): CatchForm
|
||||
{
|
||||
$this->fields[$this->name] = array_merge($this->fields[$this->name], [
|
||||
'class' => $class,
|
||||
@ -78,7 +117,13 @@ class CatchForm
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function options(array $options)
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月10日
|
||||
* @param array $options
|
||||
* @return CatchForm
|
||||
*/
|
||||
public function options(array $options): CatchForm
|
||||
{
|
||||
$this->fields[$this->name] = array_merge($this->fields[$this->name], [
|
||||
'options' => $options,
|
||||
@ -87,7 +132,13 @@ class CatchForm
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function default($value)
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月10日
|
||||
* @param $value
|
||||
* @return CatchForm
|
||||
*/
|
||||
public function default($value): CatchForm
|
||||
{
|
||||
$this->fields[$this->name] = array_merge($this->fields[$this->name], [
|
||||
'default' => $value,
|
||||
@ -96,8 +147,12 @@ class CatchForm
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function disabled()
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月10日
|
||||
* @return CatchForm
|
||||
*/
|
||||
public function disabled(): CatchForm
|
||||
{
|
||||
$this->fields[$this->name] = array_merge($this->fields[$this->name], [
|
||||
'disabled' => '',
|
||||
@ -106,7 +161,14 @@ class CatchForm
|
||||
|
||||
return $this;
|
||||
}
|
||||
public function placeholder($content)
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月10日
|
||||
* @param $content
|
||||
* @return CatchForm
|
||||
*/
|
||||
public function placeholder($content): CatchForm
|
||||
{
|
||||
$this->fields[$this->name] = array_merge($this->fields[$this->name], [
|
||||
'placeholder' => 'placeholder='.$content,
|
||||
@ -115,7 +177,12 @@ class CatchForm
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function readonly()
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月10日
|
||||
* @return CatchForm
|
||||
*/
|
||||
public function readonly(): CatchForm
|
||||
{
|
||||
$this->fields[$this->name] = array_merge($this->fields[$this->name], [
|
||||
'readonly' => 'readonly',
|
||||
@ -124,24 +191,35 @@ class CatchForm
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function render()
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月10日
|
||||
* @return string
|
||||
*/
|
||||
public function render(): string
|
||||
{
|
||||
$form = sprintf('<form id="%s" lay-filter="%s" class="layui-form model-form">', $this->formId, $this->formId);
|
||||
|
||||
foreach ($this->fields as $field) {
|
||||
$form .= sprintf($this->baseField(),
|
||||
$form .= in_array($field['type'], ['hidden']) ?
|
||||
$this->{$field['type'].'Field'}($field)
|
||||
: sprintf($this->baseField(),
|
||||
$field['labelClass'] ?? '',
|
||||
$field['label'],
|
||||
$field['inlineClass'] ?? '',
|
||||
$this->{$field['type'].'Field'}($field)) ;
|
||||
|
||||
$this->{$field['type'].'Field'}($field));
|
||||
}
|
||||
|
||||
return $form . $this->btn. '</form>';
|
||||
}
|
||||
|
||||
public function append($append)
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月10日
|
||||
* @param $append
|
||||
* @return CatchForm
|
||||
*/
|
||||
public function append($append): CatchForm
|
||||
{
|
||||
$this->fields[$this->name] = array_merge($this->fields[$this->name], [
|
||||
'append' => $append,
|
||||
@ -150,23 +228,36 @@ class CatchForm
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月10日
|
||||
* @param $method
|
||||
* @param $arguments
|
||||
* @return $this
|
||||
*/
|
||||
public function __call($method, $arguments)
|
||||
{
|
||||
// TODO: Implement __call() method.
|
||||
$this->name = $arguments[0] ?? '';
|
||||
$label = $arguments[1] ?? '';
|
||||
$required = $arguments[2] ?? false;
|
||||
|
||||
$this->fields[$this->name] = [
|
||||
'name' => $this->name,
|
||||
'type' => $method,
|
||||
'label' => $label,
|
||||
'label' => $required ? '<i style="color:red">*</i> '.$label : $label,
|
||||
'inline' => false,
|
||||
];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function inline()
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月10日
|
||||
* @return CatchForm
|
||||
*/
|
||||
protected function inline(): CatchForm
|
||||
{
|
||||
$this->fields[] = array_merge($this->fields, [
|
||||
'inline' => true,
|
||||
@ -175,7 +266,12 @@ class CatchForm
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function baseField()
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月10日
|
||||
* @return string
|
||||
*/
|
||||
private function baseField(): string
|
||||
{
|
||||
return
|
||||
'<div class="layui-form-item">
|
||||
@ -192,9 +288,9 @@ class CatchForm
|
||||
* @time 2019年12月06日
|
||||
* @param $filter
|
||||
* @param string $position
|
||||
* @return string
|
||||
* @return CatchForm
|
||||
*/
|
||||
public function formBtn($filter, $position = 'text-right')
|
||||
public function formBtn($filter, $position = 'text-right'): CatchForm
|
||||
{
|
||||
$this->btn = sprintf('<div class="layui-form-item %s">
|
||||
<button class="layui-btn layui-btn-primary" type="button" ew-event="closePageDialog">取消</button>
|
||||
@ -204,7 +300,14 @@ class CatchForm
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function verify($rule, $equalTo = [])
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月10日
|
||||
* @param $rule
|
||||
* @param array $equalTo
|
||||
* @return CatchForm
|
||||
*/
|
||||
public function verify($rule, $equalTo = []): CatchForm
|
||||
{
|
||||
if (empty($equalTo)) {
|
||||
$this->fields[$this->name] = array_merge($this->fields[$this->name], [
|
||||
@ -222,6 +325,12 @@ class CatchForm
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月10日
|
||||
* @param $field
|
||||
* @return string
|
||||
*/
|
||||
private function textField($field)
|
||||
{
|
||||
return
|
||||
@ -238,19 +347,31 @@ class CatchForm
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月10日
|
||||
* @param $field
|
||||
* @return string
|
||||
*/
|
||||
private function selectField($field)
|
||||
{
|
||||
$select = sprintf('<select name="%s">', $field['name']);
|
||||
$select = sprintf('<select name="%s" %s>', $field['name'], $field['verify'] ?? '');
|
||||
|
||||
$default = $field['default'] ?? '';
|
||||
|
||||
foreach ($field['options'] as $key => $option) {
|
||||
$select .= sprintf('<option value="%s"%s>%s</option>', $key, $default == $key ? ' selected' : '',$option);
|
||||
$select .= sprintf('<option value="%s"%s>%s</option>', $option['value'], $default == $key ? ' selected' : '',$option['title']);
|
||||
}
|
||||
|
||||
return $select . '</select>';
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月10日
|
||||
* @param $field
|
||||
* @return string
|
||||
*/
|
||||
private function passwordField($field)
|
||||
{
|
||||
return sprintf('<input name="%s" class="layui-input" %s type="password" %s %s>',
|
||||
@ -261,11 +382,50 @@ class CatchForm
|
||||
);
|
||||
}
|
||||
|
||||
private function radioField()
|
||||
{}
|
||||
private function radioField($field)
|
||||
{
|
||||
$radio = '';
|
||||
foreach ($field['options'] as $option) {
|
||||
$radio .= sprintf('<input name="%s" type="radio" value="%s" title="%s" %s/>',
|
||||
$field['name'], $option['value'], $option['title'], $option['value'] == $field['default'] ? 'checked' : ''
|
||||
);
|
||||
}
|
||||
|
||||
private function textareaField()
|
||||
{}
|
||||
return $radio;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月09日
|
||||
* @param $field
|
||||
* @return string
|
||||
*/
|
||||
private function textareaField($field): string
|
||||
{
|
||||
return sprintf('<textarea name="%s" %s class="layui-textarea">%s</textarea>',
|
||||
$field['name'],
|
||||
$field['placeholder'] ?? '',
|
||||
$field['default'] ?? ''
|
||||
);
|
||||
}
|
||||
|
||||
private function domField($field)
|
||||
{
|
||||
return $field['name'];
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月10日
|
||||
* @param $field
|
||||
* @return string
|
||||
*/
|
||||
private function hiddenField($field): string
|
||||
{
|
||||
return sprintf('<input name="%s" value="%s" type="hidden">',
|
||||
$field['name'], $field['default']
|
||||
);
|
||||
}
|
||||
|
||||
private function imageField()
|
||||
{}
|
||||
|
@ -1,7 +1,9 @@
|
||||
<?php
|
||||
namespace catcher;
|
||||
|
||||
use think\facade\View;
|
||||
use think\Paginator;
|
||||
use think\Response;
|
||||
|
||||
class CatchResponse
|
||||
{
|
||||
@ -47,13 +49,18 @@ class CatchResponse
|
||||
* @time 2019年12月02日
|
||||
* @param string $msg
|
||||
* @param int $code
|
||||
* @return \think\response\Json
|
||||
* @return mixed
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function fail($msg = '', $code = 10001): \think\response\Json
|
||||
public static function fail($msg = '', $code = 10001)
|
||||
{
|
||||
return json([
|
||||
'code' => $code,
|
||||
'msg' => $msg,
|
||||
]);
|
||||
if (request()->isAjax()) {
|
||||
return json([
|
||||
'code' => $code,
|
||||
'msg' => $msg,
|
||||
]);
|
||||
}
|
||||
|
||||
return Response::create(config('catch.error'), 'view', $code)->assign(['msg' => $msg, 'code' => $code]);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +0,0 @@
|
||||
<?php
|
||||
namespace catcher;
|
||||
|
||||
class Form
|
||||
{
|
||||
|
||||
}
|
22
extend/catcher/Tree.php
Normal file
22
extend/catcher/Tree.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
namespace catcher;
|
||||
|
||||
class Tree
|
||||
{
|
||||
public static function done(array $items, $pid = 0, $pidField = 'parent_id', $children = 'children')
|
||||
{
|
||||
$tree = [];
|
||||
|
||||
foreach ($items as $key => $item) {
|
||||
if ($item[$pidField] == $pid) {
|
||||
$child = self::done($items, $item['id'], $pidField);
|
||||
$item[$children] = count($child) ? $child : [];
|
||||
$tree[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
return $tree;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
<?php
|
||||
namespace catcher\base;
|
||||
|
||||
use catcher\CatchAdmin;
|
||||
use think\facade\View;
|
||||
|
||||
abstract class BaseController
|
||||
{
|
||||
/**
|
||||
*
|
||||
* @time 2019年11月28日
|
||||
* @param array $data
|
||||
* @param string $template
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function fetch(array $data = [], $template = ''): string
|
||||
{
|
||||
$stack = \debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 2);
|
||||
|
||||
$end = end($stack);
|
||||
|
||||
View::config([
|
||||
'view_path' => CatchAdmin::getViews()[$this->getModule($end['class'])]
|
||||
]);
|
||||
|
||||
return View::fetch($template ? : $this->getTemp($end['class'], $end['function']), $data);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月03日
|
||||
* @param $class
|
||||
* @param $func
|
||||
* @return string
|
||||
*/
|
||||
protected function getTemp($class, $func)
|
||||
{
|
||||
$viewPath = CatchAdmin::getModuleViewPath($this->getModule($class));
|
||||
|
||||
$class = explode('\\', $class);
|
||||
|
||||
$className = strtolower(end($class));
|
||||
|
||||
if (is_dir($viewPath . $className)) {
|
||||
return sprintf('%s/%s', $className, $func);
|
||||
}
|
||||
|
||||
return $func;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月03日
|
||||
* @param $class
|
||||
* @return mixed
|
||||
*/
|
||||
protected function getModule($class)
|
||||
{
|
||||
return explode('\\', $class)[1];
|
||||
}
|
||||
}
|
135
extend/catcher/base/CatchController.php
Normal file
135
extend/catcher/base/CatchController.php
Normal file
@ -0,0 +1,135 @@
|
||||
<?php
|
||||
namespace catcher\base;
|
||||
|
||||
use catcher\CatchAdmin;
|
||||
use think\facade\View;
|
||||
|
||||
abstract class CatchController
|
||||
{
|
||||
protected $data = [];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->loadConfig();
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @time 2019年11月28日
|
||||
* @param array $data
|
||||
* @param string $template
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function fetch(array $data = [], $template = ''): string
|
||||
{
|
||||
$stack = \debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 2);
|
||||
|
||||
$end = end($stack);
|
||||
|
||||
View::config($this->getViewPath($end['class']));
|
||||
|
||||
$this->setLayout();
|
||||
|
||||
$template = $template ? : $this->getTemp($end['class'], $end['function']);
|
||||
|
||||
return View::fetch($template, array_merge($this->data, $data));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @time 2019年12月17日
|
||||
* @param $module
|
||||
* @return array
|
||||
*/
|
||||
protected function getViewPath($module): array
|
||||
{
|
||||
return [
|
||||
'view_path' => CatchAdmin::getViews()[$this->getModule($module)],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月17日
|
||||
* @return void
|
||||
*/
|
||||
protected function setLayout(): void
|
||||
{
|
||||
$this->data['layout'] = root_path('view') . 'layout.html';
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月03日
|
||||
* @param $class
|
||||
* @param $func
|
||||
* @return string
|
||||
*/
|
||||
protected function getTemp($class, $func): string
|
||||
{
|
||||
$viewPath = CatchAdmin::getModuleViewPath($this->getModule($class));
|
||||
|
||||
$class = explode('\\', $class);
|
||||
|
||||
$className = lcfirst(end($class));
|
||||
|
||||
if (is_dir($viewPath . $className)) {
|
||||
return sprintf('%s/%s', $className, $func);
|
||||
}
|
||||
|
||||
return $func;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月03日
|
||||
* @param $class
|
||||
* @return mixed
|
||||
*/
|
||||
protected function getModule($class)
|
||||
{
|
||||
return explode('\\', $class)[1];
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @time 2019年12月15日
|
||||
* @return void
|
||||
*/
|
||||
protected function loadConfig()
|
||||
{
|
||||
$module = explode('\\', get_class($this))[1];
|
||||
|
||||
$moduleConfig = CatchAdmin::moduleDirectory($module) . 'config.php';
|
||||
|
||||
if (file_exists(CatchAdmin::moduleDirectory($module) . 'config.php')) {
|
||||
app()->config->load($moduleConfig);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月13日
|
||||
* @param $name
|
||||
* @param $value
|
||||
* @return void
|
||||
*/
|
||||
public function __set($name, $value)
|
||||
{
|
||||
// TODO: Implement __set() method.
|
||||
$this->data[$name] = $value;
|
||||
}
|
||||
|
||||
public function __get($name)
|
||||
{
|
||||
// TODO: Implement __get() method.
|
||||
}
|
||||
|
||||
public function __isset($name)
|
||||
{
|
||||
// TODO: Implement __isset() method.
|
||||
}
|
||||
}
|
@ -5,7 +5,7 @@ use catcher\traits\db\BaseOptionsTrait;
|
||||
use catcher\traits\db\TransTrait;
|
||||
use think\model\concern\SoftDelete;
|
||||
|
||||
abstract class BaseModel extends \think\Model
|
||||
abstract class CatchModel extends \think\Model
|
||||
{
|
||||
use SoftDelete;
|
||||
use TransTrait;
|
||||
@ -17,6 +17,8 @@ abstract class BaseModel extends \think\Model
|
||||
|
||||
protected $deleteTime = 'deleted_at';
|
||||
|
||||
protected $defaultSoftDelete = 0;
|
||||
|
||||
protected $autoWriteTimestamp = true;
|
||||
|
||||
protected $limit = 10;
|
@ -2,10 +2,11 @@
|
||||
namespace catcher\base;
|
||||
|
||||
use app\Request;
|
||||
use catcher\exceptions\FailedException;
|
||||
use catcher\exceptions\ValidateFailedException;
|
||||
use think\Validate;
|
||||
|
||||
abstract class BaseRequest extends Request
|
||||
class CatchRequest extends Request
|
||||
{
|
||||
/**
|
||||
* Request constructor.
|
||||
@ -27,16 +28,16 @@ abstract class BaseRequest extends Request
|
||||
*/
|
||||
protected function validate()
|
||||
{
|
||||
$validate = new Validate();
|
||||
try {
|
||||
$validate = new Validate();
|
||||
|
||||
if (!$validate->check(request()->param(), $this->rules())) {
|
||||
throw new ValidateFailedException($validate->getError());
|
||||
if (!$validate->check(request()->param(), $this->rules())) {
|
||||
throw new FailedException($validate->getError());
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
throw new ValidateFailedException($e->getMessage());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
abstract protected function rules(): array;
|
||||
|
||||
abstract protected function message(): array;
|
||||
}
|
@ -4,7 +4,7 @@ namespace catcher\base;
|
||||
use catcher\validates\Sometimes;
|
||||
use think\Validate;
|
||||
|
||||
abstract class BaseValidate extends Validate
|
||||
abstract class CatchValidate extends Validate
|
||||
{
|
||||
public function __construct()
|
||||
{
|
184
extend/catcher/command/BackupCommand.php
Normal file
184
extend/catcher/command/BackupCommand.php
Normal file
@ -0,0 +1,184 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace catcher\command;
|
||||
|
||||
use catcher\CatchAdmin;
|
||||
use think\Config;
|
||||
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
|
||||
{
|
||||
protected $table;
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
// 指令配置
|
||||
$this->setName('backup:data')
|
||||
->addArgument('tables', Argument::REQUIRED, 'backup tables')
|
||||
->addOption('zip', 'z',Option::VALUE_REQUIRED, 'is need zip')
|
||||
->setDescription('backup data you need');
|
||||
}
|
||||
|
||||
protected function execute(Input $input, Output $output)
|
||||
{
|
||||
$tables = $this->input->getArgument('tables');
|
||||
|
||||
$isZip = $this->input->getOption('zip') ?? true;
|
||||
|
||||
$this->generator(explode(',', $tables), CatchAdmin::backupDirectory());
|
||||
|
||||
if ($isZip) {
|
||||
$this->zip();
|
||||
}
|
||||
|
||||
$output->info('succeed!');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年09月30日
|
||||
* @param $tables
|
||||
* @param $format
|
||||
* @param $path
|
||||
* @return void
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
*/
|
||||
public function generator($tables, $path)
|
||||
{
|
||||
foreach ($tables as $table) {
|
||||
$this->table = $table;
|
||||
|
||||
$this->createDataFile();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建数据文件
|
||||
*
|
||||
* @time 2019年09月27日
|
||||
* @param $format
|
||||
* @return void
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
*/
|
||||
public function createDataFile(): void
|
||||
{
|
||||
$file = CatchAdmin::backupDirectory() . $this->table . '.sql';
|
||||
|
||||
$handle = fopen($file, 'wb+');
|
||||
|
||||
fwrite($handle, $begin = "BEGIN;\r\n", \strlen($begin));
|
||||
$this->createClass($this->table, $handle);
|
||||
fwrite($handle, $end = 'COMMIT;', \strlen($end));
|
||||
|
||||
fclose($handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建了临时模型
|
||||
*
|
||||
* @time 2019年09月27日
|
||||
* @param $table
|
||||
* @param $format
|
||||
* @param $handle
|
||||
* @return void
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
*/
|
||||
protected function createClass($table, $handle)
|
||||
{
|
||||
$this->setUnbuffered();
|
||||
|
||||
// 防止 IO 多次写入
|
||||
$buffer = [];
|
||||
|
||||
// 记录中记录
|
||||
$total = Db::table($table)->count();
|
||||
|
||||
$limit = 1000;
|
||||
|
||||
// 生成器减少内存
|
||||
while ($total > 0) {
|
||||
$items = Db::table($table)->limit($limit)->select();
|
||||
|
||||
$this->writeIn($handle, $items);
|
||||
|
||||
$total -= $limit;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* sql 文件格式
|
||||
*
|
||||
* @time 2019年09月27日
|
||||
* @param $handle
|
||||
* @param $data
|
||||
* @return void
|
||||
*/
|
||||
protected function writeIn($handle, $datas)
|
||||
{
|
||||
$values = '';
|
||||
$sql = '';
|
||||
foreach ($datas as $data) {
|
||||
foreach ($data as $value) {
|
||||
$values .= sprintf("'%s'", $value) . ',';
|
||||
}
|
||||
|
||||
$sql .= sprintf('INSERT INTO `%s` VALUE (%s);' . "\r\n", $this->table, rtrim($values, ','));
|
||||
$values = '';
|
||||
}
|
||||
|
||||
fwrite($handle, $sql, strlen($sql));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 设置未缓存模式
|
||||
*
|
||||
* @time 2019年09月29日
|
||||
* @return void
|
||||
*/
|
||||
protected function setUnbuffered()
|
||||
{
|
||||
$connections = \config('database.connections');
|
||||
|
||||
$connections['mysql']['params'] = [
|
||||
\PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => false
|
||||
];
|
||||
|
||||
\config([
|
||||
'connections' => $connections,
|
||||
],'database.connections');
|
||||
|
||||
}
|
||||
|
||||
protected function zip()
|
||||
{
|
||||
if (extension_loaded('zip')) {
|
||||
$files = glob(CatchAdmin::backupDirectory() . '*.sql');
|
||||
$zip = new \ZipArchive();
|
||||
$zip->open(root_path('database/') . 'backup.zip', \ZipArchive::CREATE);
|
||||
$zip->addEmptyDir('backup');
|
||||
foreach ($files as $file) {
|
||||
$zip->addFile($file, 'backup/'. basename($file));
|
||||
}
|
||||
$zip->close();
|
||||
|
||||
foreach ($files as $file) {
|
||||
unlink($file);
|
||||
}
|
||||
rmdir(CatchAdmin::backupDirectory());
|
||||
}
|
||||
}
|
||||
}
|
149
extend/catcher/command/CompressPackageCommand.php
Normal file
149
extend/catcher/command/CompressPackageCommand.php
Normal file
@ -0,0 +1,149 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace catcher\command;
|
||||
|
||||
use catcher\CatchAdmin;
|
||||
use think\console\Command;
|
||||
use think\console\Input;
|
||||
use think\console\input\Argument;
|
||||
use think\console\input\Option;
|
||||
use think\console\input\Option as InputOption;
|
||||
use think\console\Output;
|
||||
|
||||
class CompressPackageCommand extends Command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
// 指令配置
|
||||
$this->setName('package:zip')
|
||||
->addArgument('package', Argument::REQUIRED, 'package name')
|
||||
->addOption('compress', 'c', InputOption::VALUE_REQUIRED, 'zip or unzip')
|
||||
->setDescription('compress package to zip');
|
||||
}
|
||||
|
||||
protected function execute(Input $input, Output $output)
|
||||
{
|
||||
$package = $this->input->getArgument('package');
|
||||
$compress = $this->input->getOption('compress');
|
||||
|
||||
if (!extension_loaded('zip')) {
|
||||
$this->output->error('you should install extension [zip]');
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($compress == 'false') {
|
||||
$this->unzip();
|
||||
} else {
|
||||
$this->zip($package);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 压缩包
|
||||
*
|
||||
* @time 2019年12月16日
|
||||
* @param $package
|
||||
* @return void
|
||||
*/
|
||||
protected function zip($package): void
|
||||
{
|
||||
if (!is_dir(CatchAdmin::directory() . $package)) {
|
||||
$package = $this->output->ask($this->input, sprintf('Can not find [%s] in catchAdmin directory, you should input package again', $package));
|
||||
}
|
||||
|
||||
if (!is_dir(CatchAdmin::directory() . $package)) {
|
||||
$this->output->error('check package exists?');exit;
|
||||
}
|
||||
|
||||
$files = $this->getFilesFromDir(CatchAdmin::directory() . $package);
|
||||
$packageZip = new \ZipArchive();
|
||||
$packageZip->open(CatchAdmin::directory() . $package . '.zip', \ZipArchive::CREATE);
|
||||
$packageZip->addEmptyDir($package);
|
||||
foreach ($files as $file) {
|
||||
$baseName = basename($file);
|
||||
$localName = str_replace([CatchAdmin::directory(), $baseName], ['', ''], $file);
|
||||
$packageZip->addFile($file, $localName . $baseName);
|
||||
}
|
||||
$packageZip->close();
|
||||
$this->output->info(sprintf('%s.zip compress successfully!', $package));
|
||||
}
|
||||
|
||||
/**
|
||||
* overwrite package
|
||||
*
|
||||
* @time 2019年12月16日
|
||||
* @return bool
|
||||
*/
|
||||
protected function unzip()
|
||||
{
|
||||
$zip = new \ZipArchive();
|
||||
|
||||
//dd($zip->open(CatchAdmin::directory() . 'permissions.zip'));
|
||||
$res = $zip->open(CatchAdmin::directory() . 'permissions.zip');
|
||||
$extractToPath = CatchAdmin::directory() . 'goods';
|
||||
|
||||
if (is_dir($extractToPath)) {
|
||||
$this->rmDir($extractToPath);
|
||||
}
|
||||
|
||||
$extractToPath = CatchAdmin::makeDirectory($extractToPath);
|
||||
|
||||
if ($res === true) {
|
||||
$zip->extractTo($extractToPath);
|
||||
$zip->close();
|
||||
$this->output->info('unzip successfully');
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->output->error('unzip failed');
|
||||
}
|
||||
|
||||
|
||||
protected function rmDir($packageDir)
|
||||
{
|
||||
$fileSystemIterator = new \FilesystemIterator($packageDir);
|
||||
try {
|
||||
foreach ($fileSystemIterator as $fileSystem) {
|
||||
if ($fileSystem->isDir()) {
|
||||
if ((new \FilesystemIterator($fileSystem->getPathName()))->valid()) {
|
||||
$this->rmDir($fileSystem->getPathName());
|
||||
} else {
|
||||
rmdir($fileSystem->getPathName());
|
||||
}
|
||||
} else {
|
||||
unlink($fileSystem->getPathName());
|
||||
}
|
||||
}
|
||||
} catch (\Exception $exception) {
|
||||
$this->output->error($exception->getMessage());
|
||||
exit;
|
||||
}
|
||||
|
||||
rmdir($packageDir);
|
||||
}
|
||||
|
||||
/**
|
||||
* get files from dir
|
||||
*
|
||||
* @time 2019年12月16日
|
||||
* @param $packageDir
|
||||
* @return array
|
||||
*/
|
||||
protected function getFilesFromDir($packageDir): array
|
||||
{
|
||||
$files = [];
|
||||
|
||||
$fileSystemIterator = new \FilesystemIterator($packageDir);
|
||||
|
||||
foreach ($fileSystemIterator as $fileSystem) {
|
||||
if ($fileSystem->isDir()) {
|
||||
$files = array_merge($this->getFilesFromDir($fileSystem->getPathName()), $files);
|
||||
} else {
|
||||
$files[] = $fileSystem->getPathName();
|
||||
}
|
||||
}
|
||||
|
||||
return $files;
|
||||
}
|
||||
}
|
206
extend/catcher/command/CreateModuleCommand.php
Normal file
206
extend/catcher/command/CreateModuleCommand.php
Normal file
@ -0,0 +1,206 @@
|
||||
<?php
|
||||
namespace catcher\command;
|
||||
|
||||
use think\console\Command;
|
||||
use think\console\Input;
|
||||
use think\console\input\Argument;
|
||||
use think\console\input\Option;
|
||||
use think\console\Output;
|
||||
use catcher\CatchAdmin;
|
||||
use think\helper\Str;
|
||||
|
||||
class CreateModuleCommand extends Command
|
||||
{
|
||||
protected $module;
|
||||
|
||||
protected $moduleDir;
|
||||
|
||||
protected $stubDir;
|
||||
|
||||
protected $namespaces;
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('create:module')
|
||||
->addArgument('module', Argument::REQUIRED, 'module name')
|
||||
->addOption('controller', '-c',Option::VALUE_REQUIRED, 'controller name')
|
||||
->addOption('migration', '-m',Option::VALUE_REQUIRED, 'migration name')
|
||||
->addOption('seed', '-s',Option::VALUE_REQUIRED, 'seed name')
|
||||
->addOption('service', '-se',Option::VALUE_REQUIRED, 'service name')
|
||||
->setDescription('create module service');
|
||||
}
|
||||
|
||||
protected function execute(Input $input, Output $output)
|
||||
{
|
||||
$this->module = strtolower($input->getArgument('module'));
|
||||
|
||||
|
||||
$this->moduleDir = CatchAdmin::moduleDirectory($this->module);
|
||||
$this->stubDir = __DIR__ . DIRECTORY_SEPARATOR .'stubs'. DIRECTORY_SEPARATOR;
|
||||
|
||||
$this->namespaces = CatchAdmin::NAME . '\\' . $this->module . '\\';
|
||||
|
||||
$this->createController();
|
||||
$this->createService();
|
||||
$this->createMigration();
|
||||
$this->createSeeds();
|
||||
$this->createRoute();
|
||||
$this->moduleJson();
|
||||
|
||||
$output->warning('module created');
|
||||
}
|
||||
|
||||
|
||||
protected function createController()
|
||||
{
|
||||
$controllers = $this->input->getOption('controller');
|
||||
|
||||
$controllerPath = $this->moduleDir . 'controller' . DIRECTORY_SEPARATOR;
|
||||
|
||||
CatchAdmin::makeDirectory($controllerPath);
|
||||
|
||||
$controllers = $controllers ? explode(',', $controllers) : ['Index'];
|
||||
|
||||
foreach ($controllers as $controller) {
|
||||
file_put_contents($controllerPath . ucfirst($controller) . '.php', str_replace(
|
||||
['{CLASS}', '{NAMESPACE}', '{MODULE}'],
|
||||
[ucfirst($controller), $this->namespaces . 'controller', $this->module],
|
||||
file_get_contents($this->stubDir . 'controller.stub')
|
||||
));
|
||||
}
|
||||
|
||||
$this->output->info('🎉 create controller successfully');
|
||||
$this->createView($controllers);
|
||||
$this->createRequest($controllers);
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected function createView($controllers)
|
||||
{
|
||||
$viewPath = $this->moduleDir . 'view' . DIRECTORY_SEPARATOR;
|
||||
|
||||
CatchAdmin::makeDirectory($viewPath);
|
||||
|
||||
$default = ['index.', 'create.', 'edit.'];
|
||||
|
||||
$viewSuffix = config('view.view_suffix');
|
||||
|
||||
if (count($controllers) === 1) {
|
||||
foreach ($default as $v) {
|
||||
file_put_contents($viewPath . $v .$viewSuffix, '');
|
||||
}
|
||||
} else {
|
||||
foreach ($controllers as $controller) {
|
||||
CatchAdmin::makeDirectory($viewPath . ucwords($controller));
|
||||
foreach ($default as $v) {
|
||||
file_put_contents($viewPath . ucwords($controller) . DIRECTORY_SEPARATOR .$v . $viewSuffix, '');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->output->info('🎉 create view successfully');
|
||||
}
|
||||
|
||||
protected function createRequest($controllers)
|
||||
{
|
||||
$requestPath = $this->moduleDir . DIRECTORY_SEPARATOR . 'request' . DIRECTORY_SEPARATOR;
|
||||
|
||||
CatchAdmin::makeDirectory($requestPath);
|
||||
|
||||
$default = ['CreateRequest.php', 'UpdateRequest.php'];
|
||||
|
||||
if (count($controllers) === 1) {
|
||||
foreach ($default as $v) {
|
||||
file_put_contents($requestPath . $v, str_replace(
|
||||
['{NAMESPACE}', '{CLASS}'],
|
||||
[$this->namespaces . 'request', 'Create'],
|
||||
file_get_contents($this->stubDir. 'request.stub')));
|
||||
}
|
||||
} else {
|
||||
foreach ($controllers as $controller) {
|
||||
CatchAdmin::makeDirectory($requestPath . ucwords($controller));
|
||||
foreach ($default as $v) {
|
||||
file_put_contents($requestPath . ucwords($controller). DIRECTORY_SEPARATOR . $v, str_replace(
|
||||
['{NAMESPACE}', '{CLASS}'],
|
||||
[$this->namespaces . 'request' . ucwords($controller), 'Create'],
|
||||
file_get_contents($this->stubDir . 'request.stub')));
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->output->info('🎉 create view successfully');
|
||||
}
|
||||
|
||||
protected function createMigration()
|
||||
{
|
||||
$migrations = $this->input->getOption('migration');
|
||||
|
||||
$migrationPath = $this->moduleDir . 'database'.DIRECTORY_SEPARATOR.'migrations'.DIRECTORY_SEPARATOR;
|
||||
|
||||
CatchAdmin::makeDirectory($migrationPath);
|
||||
|
||||
if ($migrations) {
|
||||
$migrations = explode(',', $migrations);
|
||||
|
||||
foreach ($migrations as $migration) {
|
||||
$filename = date('Ymdhis', time()) . '_' .Str::snake($migration) . '.php';
|
||||
|
||||
file_put_contents($migrationPath . $filename, str_replace(
|
||||
['{CLASS}'], [ucfirst($migration)], file_get_contents($this->stubDir.'migration.stub')));
|
||||
}
|
||||
$this->output->info('🎉 create migrations successfully');
|
||||
}
|
||||
}
|
||||
|
||||
protected function createSeeds()
|
||||
{
|
||||
$seeds = $this->input->getOption('seed');
|
||||
|
||||
$seedPath = $this->moduleDir . 'database'.DIRECTORY_SEPARATOR.'seeds'.DIRECTORY_SEPARATOR;
|
||||
|
||||
CatchAdmin::makeDirectory($seedPath);
|
||||
|
||||
if ($seeds) {
|
||||
$seeds = explode(',', $seeds);
|
||||
|
||||
foreach ($seeds as $seed) {
|
||||
$filename = ucfirst(Str::camel($seed)) . 'Seed.php';
|
||||
|
||||
file_put_contents($seedPath . $filename, str_replace(
|
||||
['{CLASS}'], [ucfirst($seed)], file_get_contents($this->stubDir.'seeder.stub')));
|
||||
}
|
||||
|
||||
$this->output->info('🎉 create seeds successfully');
|
||||
}
|
||||
}
|
||||
|
||||
protected function moduleJson()
|
||||
{
|
||||
file_put_contents($this->moduleDir.DIRECTORY_SEPARATOR .'module.json', str_replace(
|
||||
['{MODULE}', '{SERVICE}'],
|
||||
[$this->module, $this->namespaces. ucfirst($this->module) . 'Service'],
|
||||
file_get_contents($this->stubDir . 'module.stub')));
|
||||
$this->output->info('🎉 create module.json successfully');
|
||||
}
|
||||
|
||||
protected function createRoute()
|
||||
{
|
||||
file_put_contents($this->moduleDir.DIRECTORY_SEPARATOR .'route.php',
|
||||
file_get_contents($this->stubDir . 'route.stub'));
|
||||
$this->output->info('🎉 create route.php successfully');
|
||||
}
|
||||
|
||||
protected function createService()
|
||||
{
|
||||
$service = $this->input->getOption('service');
|
||||
if ($service) {
|
||||
file_put_contents($this->moduleDir . DIRECTORY_SEPARATOR . ucfirst($this->module) . 'Service.php', str_replace(
|
||||
['{CLASS}', '{NAMESPACE}'],
|
||||
[ucfirst($this->module), $this->namespaces . '\\' . $this->module],
|
||||
file_get_contents($this->stubDir.'service.stub')));
|
||||
$this->output->info('🎉 create service successfully');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
<?php
|
||||
namespace catcher\command;
|
||||
|
||||
use catcher\CatchAdmin;
|
||||
use think\console\Command;
|
||||
use think\console\Input;
|
||||
use think\console\input\Argument;
|
||||
@ -12,11 +13,11 @@ use think\facade\Db;
|
||||
class InstallCommand extends Command
|
||||
{
|
||||
|
||||
protected $dataInstall = true;
|
||||
protected $databaseLink = [];
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('install:project')
|
||||
$this->setName('catch:install')
|
||||
// ->addArgument('module', Argument::REQUIRED, 'module name')
|
||||
->setDescription('install project');
|
||||
}
|
||||
@ -128,6 +129,8 @@ class InstallCommand extends Command
|
||||
}
|
||||
}
|
||||
|
||||
$this->databaseLink = [$host, $database, $username, $password, $port, $charset, $prefix];
|
||||
|
||||
$this->generateEnvFile($host, $database, $username, $password, $port, $charset, $prefix);
|
||||
}
|
||||
}
|
||||
@ -140,31 +143,31 @@ class InstallCommand extends Command
|
||||
*/
|
||||
protected function secondStep(): void
|
||||
{
|
||||
$modulePaths = glob(root_path('module') . '*');
|
||||
if (file_exists(root_path() . '.env')) {
|
||||
$connections = \config('database.connections');
|
||||
|
||||
$this->checkRootDatabase();
|
||||
[
|
||||
$connections['mysql']['hostname'],
|
||||
$connections['mysql']['database'],
|
||||
$connections['mysql']['username'],
|
||||
$connections['mysql']['password'],
|
||||
$connections['mysql']['hostport'],
|
||||
$connections['mysql']['charset'],
|
||||
$connections['mysql']['prefix'],
|
||||
] = $this->databaseLink;
|
||||
|
||||
foreach ($modulePaths as $path) {
|
||||
if (is_dir($path)) {
|
||||
$moduleDatabasePath = $path . DIRECTORY_SEPARATOR . 'database' . DIRECTORY_SEPARATOR;
|
||||
if (is_dir($moduleDatabasePath)) {
|
||||
if (is_dir($moduleDatabasePath . 'migrations' . DIRECTORY_SEPARATOR)) {
|
||||
$migrationFiles = glob($moduleDatabasePath . 'migrations' . DIRECTORY_SEPARATOR . '*.php');
|
||||
foreach ($migrationFiles as $file) {
|
||||
copy($file,
|
||||
root_path('database') . 'migrations'. DIRECTORY_SEPARATOR .
|
||||
pathinfo($file, PATHINFO_BASENAME));
|
||||
}
|
||||
}
|
||||
\config([
|
||||
'connections' => $connections,
|
||||
], 'database');
|
||||
|
||||
if (is_dir($moduleDatabasePath . 'seeds' . DIRECTORY_SEPARATOR)) {
|
||||
$seedFiles = glob($moduleDatabasePath . 'seeds' . DIRECTORY_SEPARATOR . '*.php');
|
||||
foreach ($seedFiles as $file) {
|
||||
copy($file,
|
||||
root_path('database') . 'seeds' . DIRECTORY_SEPARATOR .
|
||||
pathinfo($file, PATHINFO_BASENAME));
|
||||
}
|
||||
}
|
||||
foreach (CatchAdmin::getModulesDirectory() as $directory) {
|
||||
$moduleInfo = CatchAdmin::getModuleInfo($directory);
|
||||
if (is_dir(CatchAdmin::moduleMigrationsDirectory($moduleInfo['alias']))) {
|
||||
$output = Console::call('catch-migrate:run', [$moduleInfo['alias']]);
|
||||
$this->output->info(sprintf('module [%s] migrations %s', $moduleInfo['alias'], $output->fetch()));
|
||||
|
||||
$seedOut = Console::call('catch-seed:run', [$moduleInfo['alias']]);
|
||||
$this->output->info(sprintf('module [%s] seeds %s', $moduleInfo['alias'], $seedOut->fetch()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -190,9 +193,7 @@ class InstallCommand extends Command
|
||||
protected function finished(): void
|
||||
{
|
||||
// todo something
|
||||
if ($this->dataInstall) {
|
||||
rmdir($this->app->getRootPath() . 'database');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -210,6 +211,7 @@ class InstallCommand extends Command
|
||||
*/
|
||||
protected function generateEnvFile($host, $database, $username, $password, $port, $charset, $prefix): void
|
||||
{
|
||||
try {
|
||||
$env = \parse_ini_file(root_path() . '.example.env', true);
|
||||
|
||||
$env['DATABASE']['HOSTNAME'] = $host;
|
||||
@ -236,29 +238,22 @@ class InstallCommand extends Command
|
||||
}
|
||||
}
|
||||
|
||||
file_put_contents(root_path() . '.env', $dotEnv);
|
||||
|
||||
if ($this->getEnvFile()) {
|
||||
$this->output->info('env file has been generated');
|
||||
}
|
||||
|
||||
if ((new \mysqli($host, $username, $password, null, $port))->query(sprintf('CREATE DATABASE IF NOT EXISTS %s DEFAULT CHARSET %s COLLATE %s_general_ci;',
|
||||
$database, $charset, $charset))) {
|
||||
$this->output->info(sprintf('🎉 create database %s successfully', $database));
|
||||
|
||||
exec(sprintf('%s %s migrate:run', getenv('_'), root_path() . DIRECTORY_SEPARATOR . 'think'));
|
||||
|
||||
$this->output->info('🎉 database table install successfully');
|
||||
|
||||
exec(sprintf('%s %s seed:run', getenv('_'),root_path() . DIRECTORY_SEPARATOR . 'think'));
|
||||
|
||||
$this->output->info('🎉 Fill database table successfully ');
|
||||
} else {
|
||||
$this->dataInstall = false;
|
||||
$this->output->warning(sprintf('create database %s failed, you should create it by yourself', $database));
|
||||
$this->output->warning('you should use `php think migrate:run` to create tables');
|
||||
$this->output->warning('you should use `php think seed:run` to fill tables data');
|
||||
$this->output->warning(sprintf('create database %s failed,you need create database first by yourself', $database));
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$this->output->error($e->getMessage());
|
||||
exit(0);
|
||||
}
|
||||
|
||||
file_put_contents(root_path() . '.env', $dotEnv);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -322,7 +317,8 @@ class InstallCommand extends Command
|
||||
| \___/\__,_/\__/\___/_/ /_/ /_/ |_\__,_/_/ /_/ /_/_/_/ /_/ |
|
||||
| |
|
||||
\ __ __ __ __ _ __ _ __ enjoy it ! _ __ __ __ __ __ __ ___ _ @ 2017 ~ %s
|
||||
|
||||
账号: admin@gmail.com
|
||||
密码: admin
|
||||
', $year));
|
||||
|
||||
}
|
||||
|
@ -46,6 +46,8 @@ EOT
|
||||
}
|
||||
$end = microtime(true);
|
||||
|
||||
// 重置 migrations 在循环冲无法重复使用
|
||||
$this->migrations = null;
|
||||
$output->writeln('');
|
||||
$output->writeln('<comment>All Done. Took ' . sprintf('%.4fs', $end - $start) . '</comment>');
|
||||
}
|
||||
|
@ -80,9 +80,9 @@ class ModelGeneratorCommand extends Command
|
||||
<?php
|
||||
namespace catchAdmin\{Module}\model;
|
||||
|
||||
use cather\Model;
|
||||
use cather\base\BaseModel;
|
||||
|
||||
class {Class} extends Model
|
||||
class {Class} extends BaseModel
|
||||
{
|
||||
protected \$name = '{Name}';
|
||||
|
||||
|
63
extend/catcher/command/SeedRunCommand.php
Normal file
63
extend/catcher/command/SeedRunCommand.php
Normal file
@ -0,0 +1,63 @@
|
||||
<?php
|
||||
namespace catcher\command;
|
||||
|
||||
use catcher\CatchAdmin;
|
||||
use think\console\Command;
|
||||
use think\console\Input;
|
||||
use think\console\input\Argument;
|
||||
use think\console\input\Argument as InputArgument;
|
||||
use think\console\input\Option;
|
||||
use think\console\input\Option as InputOption;
|
||||
use think\console\Output;
|
||||
use think\migration\command\seed\Run;
|
||||
|
||||
class SeedRunCommand extends Run
|
||||
{
|
||||
protected $module;
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
// 指令配置
|
||||
$this->setName('catch-seed:run')
|
||||
->setDescription('the catch-seed:run command to Run database seeders')
|
||||
->addArgument('module', Argument::REQUIRED, 'seed the module database')
|
||||
->addOption('--seed', '-s', InputOption::VALUE_REQUIRED, 'What is the name of the seeder?')
|
||||
->setHelp(<<<EOT
|
||||
The <info>catch-seed:run</info> command runs all available or individual seeders
|
||||
<info>php think catch-seed:run module</info>
|
||||
<info>php think catch-seed:run -s UserSeeder</info>
|
||||
<info>php think catch-seed:run -v</info>
|
||||
|
||||
EOT
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
protected function execute(Input $input, Output $output)
|
||||
{
|
||||
$this->module = strtolower($input->getArgument('module'));
|
||||
$seed = $input->getOption('seed');
|
||||
|
||||
// run the seed(ers)
|
||||
$start = microtime(true);
|
||||
$this->seed($seed);
|
||||
$end = microtime(true);
|
||||
$this->seeds = null;
|
||||
$output->writeln('<comment>All Done. Took ' . sprintf('%.4fs', $end - $start) . '</comment>');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* 获取 seeder path
|
||||
* @return string
|
||||
* @param $module
|
||||
* @date: 2019/12/10 14:01
|
||||
*/
|
||||
protected function getPath()
|
||||
{
|
||||
return CatchAdmin::moduleSeedsDirectory($this->module);
|
||||
}
|
||||
|
||||
|
||||
}
|
21
extend/catcher/command/stubs/command.stub
Normal file
21
extend/catcher/command/stubs/command.stub
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
namespace {NAMESPACE};
|
||||
|
||||
use think\console\Command;
|
||||
use think\console\Input;
|
||||
use think\console\input\Argument;
|
||||
use think\console\input\Option;
|
||||
use think\console\Output;
|
||||
|
||||
class {CLASS}Command extends Command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('')
|
||||
->setDescription('');
|
||||
}
|
||||
|
||||
protected function execute(Input $input, Output $output)
|
||||
{
|
||||
}
|
||||
}
|
35
extend/catcher/command/stubs/controller.stub
Normal file
35
extend/catcher/command/stubs/controller.stub
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
namespace {NAMESPACE};
|
||||
|
||||
use catcher\base\CatchController;
|
||||
|
||||
class {CLASS} extends CatchController
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
return $this->fetch();
|
||||
}
|
||||
|
||||
public function create()
|
||||
{
|
||||
return $this->fetch();
|
||||
}
|
||||
|
||||
public function save()
|
||||
{}
|
||||
|
||||
public function read()
|
||||
{}
|
||||
|
||||
public function edit()
|
||||
{
|
||||
return $this->fetch();
|
||||
}
|
||||
|
||||
public function update()
|
||||
{}
|
||||
|
||||
public function delete()
|
||||
{}
|
||||
|
||||
}
|
11
extend/catcher/command/stubs/event.stub
Normal file
11
extend/catcher/command/stubs/event.stub
Normal file
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace {NAMESPACE};
|
||||
|
||||
class {CLASS}
|
||||
{
|
||||
public function handle()
|
||||
{
|
||||
}
|
||||
}
|
@ -3,7 +3,7 @@
|
||||
use think\migration\Migrator;
|
||||
use think\migration\db\Column;
|
||||
|
||||
class AnyClassNameYouWant extends Migrator
|
||||
class {CLASS} extends Migrator
|
||||
{
|
||||
/**
|
||||
* Change Method.
|
13
extend/catcher/command/stubs/module.stub
Normal file
13
extend/catcher/command/stubs/module.stub
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "",
|
||||
"alias": "{MODULE}",
|
||||
"description": "",
|
||||
"keywords": [],
|
||||
"order": 0,
|
||||
"services": [
|
||||
"{SERVICE}"
|
||||
],
|
||||
"aliases": {},
|
||||
"files": [],
|
||||
"requires": []
|
||||
}
|
14
extend/catcher/command/stubs/request.stub
Normal file
14
extend/catcher/command/stubs/request.stub
Normal file
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
namespace {NAMESPACE};
|
||||
|
||||
use catcher\base\CatchRequest;
|
||||
|
||||
class {CLASS}Request extends CatchRequest
|
||||
{
|
||||
public function rule()
|
||||
{
|
||||
return [
|
||||
// rule
|
||||
];
|
||||
}
|
||||
}
|
5
extend/catcher/command/stubs/route.stub
Normal file
5
extend/catcher/command/stubs/route.stub
Normal file
@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
// you should user `$router`
|
||||
// $router->get('index', 'controller@method');
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
use think\migration\Seeder;
|
||||
|
||||
class Abc extends Seeder
|
||||
class {CLASS} extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run Method.
|
15
extend/catcher/command/stubs/service.stub
Normal file
15
extend/catcher/command/stubs/service.stub
Normal file
@ -0,0 +1,15 @@
|
||||
<?php
|
||||
namespace {NAMESPACE};
|
||||
|
||||
use think\Service;
|
||||
|
||||
class {CLASS}Service extends Service
|
||||
{
|
||||
/**
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
}
|
||||
}
|
@ -18,8 +18,34 @@ class LoadModuleRoutes
|
||||
{
|
||||
$router = app(Route::class);
|
||||
|
||||
$router->group(function () use ($router) {
|
||||
include CatchAdmin::getRoutes();
|
||||
});
|
||||
$domain = config('catch.domain');
|
||||
|
||||
$routes = $this->getRoutes();
|
||||
|
||||
if ($domain) {
|
||||
$router->domain($domain, function () use ($router, $routes) {
|
||||
foreach ($routes as $route) {
|
||||
include $route;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
$router->group(function () use ($router, $routes) {
|
||||
foreach ($routes as $route) {
|
||||
include $route;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月15日
|
||||
* @return array
|
||||
*/
|
||||
protected function getRoutes(): array
|
||||
{
|
||||
$routes = CatchAdmin::getRoutes();
|
||||
array_push($routes, CatchAdmin::directory() . 'login' . DIRECTORY_SEPARATOR . 'route.php');
|
||||
return $routes;
|
||||
}
|
||||
}
|
||||
|
5
extend/catcher/exceptions/CatchException.php
Normal file
5
extend/catcher/exceptions/CatchException.php
Normal file
@ -0,0 +1,5 @@
|
||||
<?php
|
||||
namespace catcher\exceptions;
|
||||
|
||||
abstract class CatchException extends \Exception
|
||||
{}
|
7
extend/catcher/exceptions/FailedException.php
Normal file
7
extend/catcher/exceptions/FailedException.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
namespace catcher\exceptions;
|
||||
|
||||
class FailedException extends CatchException
|
||||
{
|
||||
protected $code = 10010;
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
<?php
|
||||
namespace cather\exceptions;
|
||||
namespace catcher\exceptions;
|
||||
|
||||
class LoginFailedException extends \Exception
|
||||
class LoginFailedException extends CatchException
|
||||
{
|
||||
protected $code = 10002;
|
||||
protected $code = 10010;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user