Browse Source

项目初始化

master
453530270@qq.com 1 year ago
commit
6bb7422473
  1. 42
      .example.env
  2. 3
      .gitattributes
  3. 18
      .gitignore
  4. 1
      .htaccess
  5. 42
      .travis.yml
  6. 7
      404.html
  7. 21
      LICENSE
  8. 36
      README.en.md
  9. 128
      README.md
  10. 1
      app/.htaccess
  11. 94
      app/BaseController.php
  12. 58
      app/ExceptionHandle.php
  13. 10
      app/Request.php
  14. 38
      app/admin/config/admin.php
  15. 10
      app/admin/config/app.php
  16. 10
      app/admin/config/console.php
  17. 19
      app/admin/config/route.php
  18. 171
      app/admin/controller/Ajax.php
  19. 120
      app/admin/controller/Index.php
  20. 99
      app/admin/controller/Login.php
  21. 30
      app/admin/controller/mall/Cate.php
  22. 87
      app/admin/controller/mall/Goods.php
  23. 212
      app/admin/controller/system/Admin.php
  24. 91
      app/admin/controller/system/Auth.php
  25. 68
      app/admin/controller/system/Config.php
  26. 67
      app/admin/controller/system/Log.php
  27. 219
      app/admin/controller/system/Menu.php
  28. 121
      app/admin/controller/system/Node.php
  29. 43
      app/admin/controller/system/Quick.php
  30. 38
      app/admin/controller/system/Uploadfile.php
  31. 21
      app/admin/event.php
  32. 21
      app/admin/middleware.php
  33. 67
      app/admin/middleware/CheckAdmin.php
  34. 53
      app/admin/middleware/CsrfMiddleware.php
  35. 77
      app/admin/middleware/SystemLog.php
  36. 58
      app/admin/middleware/ViewInit.php
  37. 23
      app/admin/model/MallCate.php
  38. 30
      app/admin/model/MallGoods.php
  39. 31
      app/admin/model/SystemAdmin.php
  40. 64
      app/admin/model/SystemAuth.php
  41. 21
      app/admin/model/SystemAuthNode.php
  42. 22
      app/admin/model/SystemConfig.php
  43. 29
      app/admin/model/SystemLog.php
  44. 70
      app/admin/model/SystemMenu.php
  45. 47
      app/admin/model/SystemNode.php
  46. 23
      app/admin/model/SystemQuick.php
  47. 21
      app/admin/model/SystemUploadfile.php
  48. 31
      app/admin/service/ConfigService.php
  49. 37
      app/admin/service/NodeService.php
  50. 136
      app/admin/service/SystemLogService.php
  51. 61
      app/admin/service/TriggerService.php
  52. 172
      app/admin/traits/Curd.php
  53. 49
      app/admin/view/index/edit_admin.html
  54. 38
      app/admin/view/index/edit_password.html
  55. 110
      app/admin/view/index/index.html
  56. 258
      app/admin/view/index/welcome.html
  57. 32
      app/admin/view/layout/default.html
  58. 45
      app/admin/view/login/index.html
  59. 43
      app/admin/view/mall/cate/add.html
  60. 43
      app/admin/view/mall/cate/edit.html
  61. 10
      app/admin/view/mall/cate/index.html
  62. 89
      app/admin/view/mall/goods/add.html
  63. 90
      app/admin/view/mall/goods/edit.html
  64. 11
      app/admin/view/mall/goods/index.html
  65. 39
      app/admin/view/mall/goods/stock.html
  66. 54
      app/admin/view/system/admin/add.html
  67. 54
      app/admin/view/system/admin/edit.html
  68. 11
      app/admin/view/system/admin/index.html
  69. 34
      app/admin/view/system/admin/password.html
  70. 26
      app/admin/view/system/auth/add.html
  71. 27
      app/admin/view/system/auth/authorize.html
  72. 26
      app/admin/view/system/auth/edit.html
  73. 11
      app/admin/view/system/auth/index.html
  74. 24
      app/admin/view/system/config/index.html
  75. 28
      app/admin/view/system/config/logo.html
  76. 52
      app/admin/view/system/config/site.html
  77. 141
      app/admin/view/system/config/upload.html
  78. 7
      app/admin/view/system/log/index.html
  79. 75
      app/admin/view/system/menu/add.html
  80. 75
      app/admin/view/system/menu/edit.html
  81. 23
      app/admin/view/system/menu/index.html
  82. 9
      app/admin/view/system/node/index.html
  83. 52
      app/admin/view/system/quick/add.html
  84. 52
      app/admin/view/system/quick/edit.html
  85. 10
      app/admin/view/system/quick/index.html
  86. 16
      app/admin/view/system/uploadfile/add.html
  87. 54
      app/admin/view/system/uploadfile/edit.html
  88. 10
      app/admin/view/system/uploadfile/index.html
  89. 0
      app/api/config.php
  90. 13
      app/api/controller/Index.php
  91. 3
      app/api/event.php
  92. 124
      app/common.php
  93. 174
      app/common/command/Curd.php
  94. 75
      app/common/command/Node.php
  95. 58
      app/common/command/OssStatic.php
  96. 28
      app/common/constants/AdminConstant.php
  97. 33
      app/common/constants/MenuConstant.php
  98. 293
      app/common/controller/AdminController.php
  99. 52
      app/common/model/TimeModel.php
  100. 215
      app/common/service/AuthService.php

42
.example.env

@ -0,0 +1,42 @@
APP_DEBUG=true
[APP]
DEFAULT_TIMEZONE=Asia/Shanghai
[DATABASE]
TYPE=mysql
HOSTNAME=host.docker.internal
DATABASE=easyadmin
USERNAME=root
PASSWORD=root
HOSTPORT=3306
CHARSET=utf8
DEBUG=true
PREFIX=ea_
[LANG]
default_lang=zh-cn
# 后台配置项组
[EASYADMIN]
# 后台地址后缀名称
ADMIN=admin
# 后台登录验证码开关
#CAPTCHA=false
# 是否为演示环境
IS_DEMO=false
# CDN配置项组
CDN=
EXAMPLE=true
# 是否开启CSRF过滤
IS_CSRF=true
# 静态文件路径前缀
STATIC_PATH=/static
# OSS静态文件路径前缀
OSS_STATIC_PREFIX=static_easyadmin

3
.gitattributes

@ -0,0 +1,3 @@
*.js linguist-language=PHP
*.css linguist-language=PHP
*.html linguist-language=PHP

18
.gitignore

@ -0,0 +1,18 @@
/.idea
/.vscode
*.log
.env
config/install/lock/install.lock
/public/upload
/public/docs
runtime/admin
runtime/log
runtime/session
runtime/temp
runtime/cache
public/conf
public/WowOss.exe
app/index/controller/Test.php
composer.phar
app/test/
vendor

1
.htaccess

@ -0,0 +1 @@

42
.travis.yml

@ -0,0 +1,42 @@
sudo: false
language: php
branches:
only:
- stable
cache:
directories:
- $HOME/.composer/cache
before_install:
- composer self-update
install:
- composer install --no-dev --no-interaction --ignore-platform-reqs
- zip -r --exclude='*.git*' --exclude='*.zip' --exclude='*.travis.yml' ThinkPHP_Core.zip .
- composer require --update-no-dev --no-interaction "topthink/think-image:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-migration:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-captcha:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-mongo:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-worker:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-helper:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-queue:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-angular:^1.0"
- composer require --dev --update-no-dev --no-interaction "topthink/think-testing:^1.0"
- zip -r --exclude='*.git*' --exclude='*.zip' --exclude='*.travis.yml' ThinkPHP_Full.zip .
script:
- php think unit
deploy:
provider: releases
api_key:
secure: TSF6bnl2JYN72UQOORAJYL+CqIryP2gHVKt6grfveQ7d9rleAEoxlq6PWxbvTI4jZ5nrPpUcBUpWIJHNgVcs+bzLFtyh5THaLqm39uCgBbrW7M8rI26L8sBh/6nsdtGgdeQrO/cLu31QoTzbwuz1WfAVoCdCkOSZeXyT/CclH99qV6RYyQYqaD2wpRjrhA5O4fSsEkiPVuk0GaOogFlrQHx+C+lHnf6pa1KxEoN1A0UxxVfGX6K4y5g4WQDO5zT4bLeubkWOXK0G51XSvACDOZVIyLdjApaOFTwamPcD3S1tfvuxRWWvsCD5ljFvb2kSmx5BIBNwN80MzuBmrGIC27XLGOxyMerwKxB6DskNUO9PflKHDPI61DRq0FTy1fv70SFMSiAtUv9aJRT41NQh9iJJ0vC8dl+xcxrWIjU1GG6+l/ZcRqVx9V1VuGQsLKndGhja7SQ+X1slHl76fRq223sMOql7MFCd0vvvxVQ2V39CcFKao/LB1aPH3VhODDEyxwx6aXoTznvC/QPepgWsHOWQzKj9ftsgDbsNiyFlXL4cu8DWUty6rQy8zT2b4O8b1xjcwSUCsy+auEjBamzQkMJFNlZAIUrukL/NbUhQU37TAbwsFyz7X0E/u/VMle/nBCNAzgkMwAUjiHM6FqrKKBRWFbPrSIixjfjkCnrMEPw=
file:
- ThinkPHP_Core.zip
- ThinkPHP_Full.zip
skip_cleanup: true
on:
tags: true

7
404.html

@ -0,0 +1,7 @@
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx</center>
</body>
</html>

21
LICENSE

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 EasyAdmin
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

36
README.en.md

@ -0,0 +1,36 @@
# EasyAdmin
#### Description
{**When you're done, you can delete the content in this README and update the file with details for others getting started with your repository**}
#### Software Architecture
Software architecture description
#### Installation
1. xxxx
2. xxxx
3. xxxx
#### Instructions
1. xxxx
2. xxxx
3. xxxx
#### Contribution
1. Fork the repository
2. Create Feat_xxx branch
3. Commit your code
4. Create Pull Request
#### Gitee Feature
1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
2. Gitee blog [blog.gitee.com](https://blog.gitee.com)
3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
4. The most valuable open source project [GVP](https://gitee.com/gvp)
5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)

128
README.md

@ -0,0 +1,128 @@
![EasyAdmin-logo](public/static/common/images/logo-2.png)
[![Php Version](https://img.shields.io/badge/php-%3E=7.1.0-brightgreen.svg?maxAge=2592000&color=yellow)](https://github.com/php/php-src)
[![Mysql Version](https://img.shields.io/badge/mysql-%3E=5.7-brightgreen.svg?maxAge=2592000&color=orange)](https://www.mysql.com/)
[![Thinkphp Version](https://img.shields.io/badge/thinkphp-%3E=6.0.2-brightgreen.svg?maxAge=2592000)](https://github.com/top-think/framework)
[![Layui Version](https://img.shields.io/badge/layui-=2.5.5-brightgreen.svg?maxAge=2592000&color=critical)](https://github.com/sentsin/layui)
[![Layuimini Version](https://img.shields.io/badge/layuimini-%3E=2.0.4.2-brightgreen.svg?maxAge=2592000&color=ff69b4)](https://github.com/zhongshaofa/layuimini)
[![EasyAdmin Doc](https://img.shields.io/badge/docs-passing-green.svg?maxAge=2592000)](http://easyadmin.99php.cn/docs)
[![EasyAdmin License](https://img.shields.io/badge/license-MIT-green?maxAge=2592000&color=blue)](https://github.com/zhongshaofa/easyadmin/blob/v2/LICENSE)
## 项目介绍
基于ThinkPHP6.0和layui的快速开发的后台管理系统。
技术交流QQ群:[763822524](https://jq.qq.com/?_wv=1027&k=5IHJawE) `加群请备注来源:如gitee、github、官网等`
## 安装教程
>EasyAdmin 使用 Composer 来管理项目依赖。因此,在使用 EasyAdmin 之前,请确保你的机器已经安装了 Composer。
#### 通过 Composer 创建项目`建议`
`composer create-project --prefer-dist zhongshaofa/easyadmin blog`
#### 通过git下载安装包,composer安装依赖包
```bash
第一步,下载安装包
git clone https://github.com/zhongshaofa/easyadmin
或者
git clone https://gitee.com/zhongshaofa/easyadmin
第二步,安装依赖包
composer install
```
## 站点地址
* 官方网站:[http://easyadmin.99php.cn](http://easyadmin.99php.cn)
* 文档地址:[http://easyadmin.99php.cn/docs](http://easyadmin.99php.cn/docs)
* 演示地址:[http://easyadmin.99php.cn/admindemo](http://easyadmin.99php.cn/admindemo)(账号:admin,密码:123456。备注:只有查看信息的权限)
## 代码仓库
* GitHub地址:[https://github.com/zhongshaofa/easyadmin](https://github.com/zhongshaofa/easyadmin)
* Gitee地址:[https://gitee.com/zhongshaofa/easyadmin](https://gitee.com/zhongshaofa/easyadmin)
## 项目特性
* 快速CURD命令行
* 一键生成控制器、模型、视图、JS文件
* 支持关联查询、字段设置等等
* 基于`auth`的权限管理系统
* 通过`注解方式`来实现`auth`权限节点管理
* 具备一键更新`auth`权限节点,无需手动输入管理
* 完善的后端权限验证以及前面页面按钮显示、隐藏控制
* 完善的菜单管理
* 分模块管理
* 无限极菜单
* 菜单编辑会提示`权限节点`
* 完善的上传组件功能
* 本地存储
* 阿里云OSS`建议使用`
* 腾讯云COS
* 七牛云OSS
* 完善的前端组件功能
* 对layui的form表单重新封装,无需手动拼接数据请求
* 简单好用的`图片、文件`上传组件
* 简单好用的富文本编辑器`ckeditor`
* 对弹出层进行再次封装,以极简的方式使用
* 对table表格再次封装,在使用上更加舒服
* 根据table的`cols`参数再次进行封装,提供接口实现`image`、`switch`、`list`等功能,再次基础上可以自己再次扩展
* 根据table参数一键生成`搜索表单`,无需自己编写
* 完善的后台操作日志
* 记录用户的详细操作信息
* 按月份进行`分表记录`
* 一键部署静态资源到OSS上
* 所有在`public\static`目录下的文件都可以一键部署
* 一个配置项切换静态资源(oss/本地)
* 上传文件记录管理
* 后台路径自定义,防止别人找到对应的后台地址
## 特别感谢
以下项目排名不分先后
* ThinkPHP:[https://github.com/top-think/framework](https://github.com/top-think/framework)
* Layuimini:[https://github.com/zhongshaofa/layuimini](https://github.com/zhongshaofa/layuimini)
* Annotations:[https://github.com/doctrine/annotations](https://github.com/doctrine/annotations)
* Layui:[https://github.com/sentsin/layui](https://github.com/sentsin/layui)
* Jquery:[https://github.com/jquery/jquery](https://github.com/jquery/jquery)
* RequireJs:[https://github.com/requirejs/requirejs](https://github.com/requirejs/requirejs)
* CKEditor:[https://github.com/ckeditor/ckeditor4](https://github.com/ckeditor/ckeditor4)
* Echarts:[https://github.com/apache/incubator-echarts](https://github.com/apache/incubator-echarts)
## 免责声明
>任何用户在使用`EasyAdmin`后台框架前,请您仔细阅读并透彻理解本声明。您可以选择不使用`EasyAdmin`后台框架,若您一旦使用`EasyAdmin`后台框架,您的使用行为即被视为对本声明全部内容的认可和接受。
* `EasyAdmin`后台框架是一款开源免费的后台快速开发框架 ,主要用于更便捷地开发后台管理;其尊重并保护所有用户的个人隐私权,不窃取任何用户计算机中的信息。更不具备用户数据存储等网络传输功能。
* 您承诺秉着合法、合理的原则使用`EasyAdmin`后台框架,不利用`EasyAdmin`后台框架进行任何违法、侵害他人合法利益等恶意的行为,亦不将`EasyAdmin`后台框架运用于任何违反我国法律法规的 Web 平台。
* 任何单位或个人因下载使用`EasyAdmin`后台框架而产生的任何意外、疏忽、合约毁坏、诽谤、版权或知识产权侵犯及其造成的损失 (包括但不限于直接、间接、附带或衍生的损失等),本开源项目不承担任何法律责任。
* 用户明确并同意本声明条款列举的全部内容,对使用`EasyAdmin`后台框架可能存在的风险和相关后果将完全由用户自行承担,本开源项目不承担任何法律责任。
* 任何单位或个人在阅读本免责声明后,应在《MIT 开源许可证》所允许的范围内进行合法的发布、传播和使用`EasyAdmin`后台框架等行为,若违反本免责声明条款或违反法律法规所造成的法律责任(包括但不限于民事赔偿和刑事责任),由违约者自行承担。
* 如果本声明的任何部分被认为无效或不可执行,其余部分仍具有完全效力。不可执行的部分声明,并不构成我们放弃执行该声明的权利。
* 本开源项目有权随时对本声明条款及附件内容进行单方面的变更,并以消息推送、网页公告等方式予以公布,公布后立即自动生效,无需另行单独通知;若您在本声明内容公告变更后继续使用的,表示您已充分阅读、理解并接受修改后的声明内容。
## 捐赠支持
开源项目不易,若此项目能得到你的青睐,可以捐赠支持作者持续开发与维护,感谢所有支持开源的朋友。
![Image text](https://chung-common.oss-cn-beijing.aliyuncs.com/donate_qrcode.png)

1
app/.htaccess

@ -0,0 +1 @@
deny from all

94
app/BaseController.php

@ -0,0 +1,94 @@
<?php
declare (strict_types = 1);
namespace app;
use think\App;
use think\exception\ValidateException;
use think\Validate;
/**
* 控制器基础类
*/
abstract class BaseController
{
/**
* Request实例
* @var \think\Request
*/
protected $request;
/**
* 应用实例
* @var \think\App
*/
protected $app;
/**
* 是否批量验证
* @var bool
*/
protected $batchValidate = false;
/**
* 控制器中间件
* @var array
*/
protected $middleware = [];
/**
* 构造方法
* @access public
* @param App $app 应用对象
*/
public function __construct(App $app)
{
$this->app = $app;
$this->request = $this->app->request;
// 控制器初始化
$this->initialize();
}
// 初始化
protected function initialize()
{}
/**
* 验证数据
* @access protected
* @param array $data 数据
* @param string|array $validate 验证器名或者验证规则数组
* @param array $message 提示信息
* @param bool $batch 是否批量验证
* @return array|string|true
* @throws ValidateException
*/
protected function validate(array $data, $validate, array $message = [], bool $batch = false)
{
if (is_array($validate)) {
$v = new Validate();
$v->rule($validate);
} else {
if (strpos($validate, '.')) {
// 支持场景
list($validate, $scene) = explode('.', $validate);
}
$class = false !== strpos($validate, '\\') ? $validate : $this->app->parseClass('validate', $validate);
$v = new $class();
if (!empty($scene)) {
$v->scene($scene);
}
}
$v->message($message);
// 是否批量验证
if ($batch || $this->batchValidate) {
$v->batch(true);
}
return $v->failException(true)->check($data);
}
}

58
app/ExceptionHandle.php

@ -0,0 +1,58 @@
<?php
namespace app;
use think\db\exception\DataNotFoundException;
use think\db\exception\ModelNotFoundException;
use think\exception\Handle;
use think\exception\HttpException;
use think\exception\HttpResponseException;
use think\exception\ValidateException;
use think\Response;
use Throwable;
/**
* 应用异常处理类
*/
class ExceptionHandle extends Handle
{
/**
* 不需要记录信息(日志)的异常类列表
* @var array
*/
protected $ignoreReport = [
HttpException::class,
HttpResponseException::class,
ModelNotFoundException::class,
DataNotFoundException::class,
ValidateException::class,
];
/**
* 记录异常信息(包括日志或者其它方式记录)
*
* @access public
* @param Throwable $exception
* @return void
*/
public function report(Throwable $exception): void
{
// 使用内置的方式记录异常日志
parent::report($exception);
}
/**
* Render an exception into an HTTP response.
*
* @access public
* @param \think\Request $request
* @param Throwable $e
* @return Response
*/
public function render($request, Throwable $e): Response
{
// 添加自定义异常处理机制
// 其他错误交给系统处理
return parent::render($request, $e);
}
}

10
app/Request.php

@ -0,0 +1,10 @@
<?php
namespace app;
// 应用请求对象类
class Request extends \think\Request
{
protected $filter = ['htmlspecialchars'];
}

38
app/admin/config/admin.php

@ -0,0 +1,38 @@
<?php
// +----------------------------------------------------------------------
// | EasyAdmin
// +----------------------------------------------------------------------
// | PHP交流群: 763822524
// +----------------------------------------------------------------------
// | 开源协议 https://mit-license.org
// +----------------------------------------------------------------------
// | github开源项目:https://github.com/zhongshaofa/EasyAdmin
// +----------------------------------------------------------------------
return [
// 不需要验证登录的控制器
'no_login_controller' => [
'login',
],
// 不需要验证登录的节点
'no_login_node' => [
'login/index',
'login/out',
],
// 不需要验证权限的控制器
'no_auth_controller' => [
'ajax',
'login',
'index',
],
// 不需要验证权限的节点
'no_auth_node' => [
'login/index',
'login/out',
],
];

10
app/admin/config/app.php

@ -0,0 +1,10 @@
<?php
// +----------------------------------------------------------------------
// | 应用设置
// +----------------------------------------------------------------------
use think\facade\Env;
return [
];

10
app/admin/config/console.php

@ -0,0 +1,10 @@
<?php
// +----------------------------------------------------------------------
// | 控制台配置
// +----------------------------------------------------------------------
return [
// 指令定义
'commands' => [
'alioss' => 'addons\alioss\command\Alioss',
],
];

19
app/admin/config/route.php

@ -0,0 +1,19 @@
<?php
// +----------------------------------------------------------------------
// | 路由设置
// +----------------------------------------------------------------------
return [
// 路由中间件
'middleware' => [
// // 后台视图初始化
// \app\admin\middleware\ViewInit::class,
// 检测用户是否登录
// \app\admin\middleware\CheckAdmin::class,
],
];

171
app/admin/controller/Ajax.php

@ -0,0 +1,171 @@
<?php
// +----------------------------------------------------------------------
// | EasyAdmin
// +----------------------------------------------------------------------
// | PHP交流群: 763822524
// +----------------------------------------------------------------------
// | 开源协议 https://mit-license.org
// +----------------------------------------------------------------------
// | github开源项目:https://github.com/zhongshaofa/EasyAdmin
// +----------------------------------------------------------------------
namespace app\admin\controller;
use app\admin\model\SystemUploadfile;
use app\common\controller\AdminController;
use app\common\service\MenuService;
use EasyAdmin\upload\Uploadfile;
use think\db\Query;
use think\facade\Cache;
class Ajax extends AdminController
{
/**
* 初始化后台接口地址
* @return \think\response\Json
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function initAdmin()
{
$cacheData = Cache::get('initAdmin_' . session('admin.id'));
if (!empty($cacheData)) {
return json($cacheData);
}
$menuService = new MenuService(session('admin.id'));
$data = [
'logoInfo' => [
'title' => sysconfig('site', 'logo_title'),
'image' => sysconfig('site', 'logo_image'),
'href' => __url('index/index'),
],
'homeInfo' => $menuService->getHomeInfo(),
'menuInfo' => $menuService->getMenuTree(),
];
Cache::tag('initAdmin')->set('initAdmin_' . session('admin.id'), $data);
return json($data);
}
/**
* 清理缓存接口
*/
public function clearCache()
{
Cache::clear();
$this->success('清理缓存成功');
}
/**
* 上传文件
*/
public function upload()
{
$this->checkPostRequest();
$data = [
'upload_type' => $this->request->post('upload_type'),
'file' => $this->request->file('file'),
];
$uploadConfig = sysconfig('upload');
empty($data['upload_type']) && $data['upload_type'] = $uploadConfig['upload_type'];
$rule = [
'upload_type|指定上传类型有误' => "in:{$uploadConfig['upload_allow_type']}",
'file|文件' => "require|file|fileExt:{$uploadConfig['upload_allow_ext']}|fileSize:{$uploadConfig['upload_allow_size']}",
];
$this->validate($data, $rule);
try {
$upload = Uploadfile::instance()
->setUploadType($data['upload_type'])
->setUploadConfig($uploadConfig)
->setFile($data['file'])
->save();
} catch (\Exception $e) {
$this->error($e->getMessage());
}
if ($upload['save'] == true) {
$this->success($upload['msg'], ['url' => $upload['url']]);
} else {
$this->error($upload['msg']);
}
}
/**
* 上传图片至编辑器
* @return \think\response\Json
*/
public function uploadEditor()
{
$this->checkPostRequest();
$data = [
'upload_type' => $this->request->post('upload_type'),
'file' => $this->request->file('upload'),
];
$uploadConfig = sysconfig('upload');
empty($data['upload_type']) && $data['upload_type'] = $uploadConfig['upload_type'];
$rule = [
'upload_type|指定上传类型有误' => "in:{$uploadConfig['upload_allow_type']}",
'file|文件' => "require|file|fileExt:{$uploadConfig['upload_allow_ext']}|fileSize:{$uploadConfig['upload_allow_size']}",
];
$this->validate($data, $rule);
try {
$upload = Uploadfile::instance()
->setUploadType($data['upload_type'])
->setUploadConfig($uploadConfig)
->setFile($data['file'])
->save();
} catch (\Exception $e) {
$this->error($e->getMessage());
}
if ($upload['save'] == true) {
return json([
'error' => [
'message' => '上传成功',
'number' => 201,
],
'fileName' => '',
'uploaded' => 1,
'url' => $upload['url'],
]);
} else {
$this->error($upload['msg']);
}
}
/**
* 获取上传文件列表
* @return \think\response\Json
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getUploadFiles()
{
$get = $this->request->get();
$page = isset($get['page']) && !empty($get['page']) ? $get['page'] : 1;
$limit = isset($get['limit']) && !empty($get['limit']) ? $get['limit'] : 10;
$title = isset($get['title']) && !empty($get['title']) ? $get['title'] : null;
$this->model = new SystemUploadfile();
$count = $this->model
->where(function (Query $query) use ($title) {
!empty($title) && $query->where('original_name', 'like', "%{$title}%");
})
->count();
$list = $this->model
->where(function (Query $query) use ($title) {
!empty($title) && $query->where('original_name', 'like', "%{$title}%");
})
->page($page, $limit)
->order($this->sort)
->select();
$data = [
'code' => 0,
'msg' => '',
'count' => $count,
'data' => $list,
];
return json($data);
}
}

120
app/admin/controller/Index.php

@ -0,0 +1,120 @@
<?php
namespace app\admin\controller;
use app\admin\model\SystemAdmin;
use app\admin\model\SystemQuick;
use app\common\controller\AdminController;
use think\App;
use think\facade\Env;
class Index extends AdminController
{
/**
* 后台主页
* @return string
* @throws \Exception
*/
public function index()
{
return $this->fetch('', [
'admin' => session('admin'),
]);
}
/**
* 后台欢迎页
* @return string
* @throws \Exception
*/
public function welcome()
{
$quicks = SystemQuick::field('id,title,icon,href')
->where(['status' => 1])
->order('sort', 'desc')
->limit(8)
->select();
$this->assign('quicks', $quicks);
return $this->fetch();
}
/**
* 修改管理员信息
* @return string
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function editAdmin()
{
$id = session('admin.id');
$row = (new SystemAdmin())
->withoutField('password')
->find($id);
empty($row) && $this->error('用户信息不存在');
if ($this->request->isPost()) {
$post = $this->request->post();
$this->isDemo && $this->error('演示环境下不允许修改');
$rule = [];
$this->validate($post, $rule);
try {
$save = $row
->allowField(['head_img', 'phone', 'remark', 'update_time'])
->save($post);
} catch (\Exception $e) {
$this->error('保存失败');
}
$save ? $this->success('保存成功') : $this->error('保存失败');
}
$this->assign('row', $row);
return $this->fetch();
}
/**
* 修改密码
* @return string
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function editPassword()
{
$id = session('admin.id');
$row = (new SystemAdmin())
->withoutField('password')
->find($id);
if (!$row) {
$this->error('用户信息不存在');
}
if ($this->request->isPost()) {
$post = $this->request->post();
$this->isDemo && $this->error('演示环境下不允许修改');
$rule = [
'password|登录密码' => 'require',
'password_again|确认密码' => 'require',
];
$this->validate($post, $rule);
if ($post['password'] != $post['password_again']) {
$this->error('两次密码输入不一致');
}
try {
$save = $row->save([
'password' => password($post['password']),
]);
} catch (\Exception $e) {
$this->error('保存失败');
}
if ($save) {
$this->success('保存成功');
} else {
$this->error('保存失败');
}
}
$this->assign('row', $row);
return $this->fetch();
}
}

99
app/admin/controller/Login.php

@ -0,0 +1,99 @@
<?php
// +----------------------------------------------------------------------
// | EasyAdmin
// +----------------------------------------------------------------------
// | PHP交流群: 763822524
// +----------------------------------------------------------------------
// | 开源协议 https://mit-license.org
// +----------------------------------------------------------------------
// | github开源项目:https://github.com/zhongshaofa/EasyAdmin
// +----------------------------------------------------------------------
namespace app\admin\controller;
use app\admin\model\SystemAdmin;
use app\common\controller\AdminController;
use think\captcha\facade\Captcha;
use think\facade\Env;
/**
* Class Login
* @package app\admin\controller
*/
class Login extends AdminController
{
/**
* 初始化方法
*/
public function initialize()
{
parent::initialize();
$action = $this->request->action();
if (!empty(session('admin')) && !in_array($action, ['out'])) {
$adminModuleName = config('app.admin_alias_name');
$this->success('已登录,无需再次登录', [], __url("@{$adminModuleName}"));
}
}
/**
* 用户登录
* @return string
* @throws \Exception
*/
public function index()
{
$captcha = Env::get('easyadmin.captcha', 1);
if ($this->request->isPost()) {
$post = $this->request->post();
$rule = [
'username|用户名' => 'require',
'password|密码' => 'require',
'keep_login|是否保持登录' => 'require',
];
$captcha == 1 && $rule['captcha|验证码'] = 'require|captcha';
$this->validate($post, $rule);
$admin = SystemAdmin::where(['username' => $post['username']])->find();
if (empty($admin)) {
$this->error('用户不存在');
}
if (password($post['password']) != $admin->password) {
$this->error('密码输入有误');
}
if ($admin->status == 0) {
$this->error('账号已被禁用');
}
$admin->login_num += 1;
$admin->save();
$admin = $admin->toArray();
unset($admin['password']);
$admin['expire_time'] = $post['keep_login'] == 1 ? true : time() + 7200;
session('admin', $admin);
$this->success('登录成功');
}
$this->assign('captcha', $captcha);
$this->assign('demo', $this->isDemo);
return $this->fetch();
}
/**
* 用户退出
* @return mixed
*/
public function out()
{
session('admin', null);
$this->success('退出登录成功');
}
/**
* 验证码
* @return \think\Response
*/
public function captcha()
{
return Captcha::create();
}
}

30
app/admin/controller/mall/Cate.php

@ -0,0 +1,30 @@
<?php
namespace app\admin\controller\mall;
use app\admin\model\MallCate;
use app\admin\traits\Curd;
use app\common\controller\AdminController;
use EasyAdmin\annotation\ControllerAnnotation;
use EasyAdmin\annotation\NodeAnotation;
use think\App;
/**
* Class Admin
* @package app\admin\controller\system
* @ControllerAnnotation(title="商品分类管理")
*/
class Cate extends AdminController
{
use Curd;
public function __construct(App $app)
{
parent::__construct($app);
$this->model = new MallCate();
}
}

87
app/admin/controller/mall/Goods.php

@ -0,0 +1,87 @@
<?php
namespace app\admin\controller\mall;
use app\admin\model\MallGoods;
use app\admin\traits\Curd;
use app\common\controller\AdminController;
use EasyAdmin\annotation\ControllerAnnotation;
use EasyAdmin\annotation\NodeAnotation;
use think\App;
/**
* Class Goods
* @package app\admin\controller\mall
* @ControllerAnnotation(title="商城商品管理")
*/
class Goods extends AdminController
{
use Curd;
protected $relationSearch = true;
public function __construct(App $app)
{
parent::__construct($app);
$this->model = new MallGoods();
}
/**
* @NodeAnotation(title="列表")
*/
public function index()
{
if ($this->request->isAjax()) {
if (input('selectFields')) {
return $this->selectList();
}
list($page, $limit, $where) = $this->buildTableParames();
$count = $this->model
->withJoin('cate', 'LEFT')
->where($where)
->count();
$list = $this->model
->withJoin('cate', 'LEFT')
->where($where)
->page($page, $limit)
->order($this->sort)
->select();
$data = [
'code' => 0,
'msg' => '',
'count' => $count,
'data' => $list,
];
return json($data);
}
return $this->fetch();
}
/**
* @NodeAnotation(title="入库")
*/
public function stock($id)
{
$row = $this->model->find($id);
empty($row) && $this->error('数据不存在');
if ($this->request->isPost()) {
$post = $this->request->post();
$rule = [];
$this->validate($post, $rule);
try {
$post['total_stock'] = $row->total_stock + $post['stock'];
$post['stock'] = $row->stock + $post['stock'];
$save = $row->save($post);
} catch (\Exception $e) {
$this->error('保存失败');
}
$save ? $this->success('保存成功') : $this->error('保存失败');
}
$this->assign('row', $row);
return $this->fetch();
}
}

212
app/admin/controller/system/Admin.php

@ -0,0 +1,212 @@
<?php
// +----------------------------------------------------------------------
// | EasyAdmin
// +----------------------------------------------------------------------
// | PHP交流群: 763822524
// +----------------------------------------------------------------------
// | 开源协议 https://mit-license.org
// +----------------------------------------------------------------------
// | github开源项目:https://github.com/zhongshaofa/EasyAdmin
// +----------------------------------------------------------------------
namespace app\admin\controller\system;
use app\admin\model\SystemAdmin;
use app\admin\service\TriggerService;
use app\common\constants\AdminConstant;
use app\common\controller\AdminController;
use EasyAdmin\annotation\ControllerAnnotation;
use EasyAdmin\annotation\NodeAnotation;
use think\App;
/**
* Class Admin
* @package app\admin\controller\system
* @ControllerAnnotation(title="管理员管理")
*/
class Admin extends AdminController
{
use \app\admin\traits\Curd;
protected $sort = [
'sort' => 'desc',
'id' => 'desc',
];
public function __construct(App $app)
{
parent::__construct($app);
$this->model = new SystemAdmin();
$this->assign('auth_list', $this->model->getAuthList());
}
/**
* @NodeAnotation(title="列表")
*/
public function index()
{
if ($this->request->isAjax()) {
if (input('selectFields')) {
return $this->selectList();
}
list($page, $limit, $where) = $this->buildTableParames();
$count = $this->model
->where($where)
->count();
$list = $this->model
->withoutField('password')
->where($where)
->page($page, $limit)
->order($this->sort)
->select();
$data = [
'code' => 0,
'msg' => '',
'count' => $count,
'data' => $list,
];
return json($data);
}
return $this->fetch();
}
/**
* @NodeAnotation(title="添加")
*/
public function add()
{
if ($this->request->isPost()) {
$post = $this->request->post();
$authIds = $this->request->post('auth_ids', []);
$post['auth_ids'] = implode(',', array_keys($authIds));
$rule = [];
$this->validate($post, $rule);
try {
$save = $this->model->save($post);
} catch (\Exception $e) {
$this->error('保存失败');
}
$save ? $this->success('保存成功') : $this->error('保存失败');
}
return $this->fetch();
}
/**
* @NodeAnotation(title="编辑")
*/
public function edit($id)
{
$row = $this->model->find($id);
empty($row) && $this->error('数据不存在');
if ($this->request->isPost()) {
$post = $this->request->post();
$authIds = $this->request->post('auth_ids', []);
$post['auth_ids'] = implode(',', array_keys($authIds));
$rule = [];
$this->validate($post, $rule);
if (isset($row['password'])) {
unset($row['password']);
}
try {
$save = $row->save($post);
TriggerService::updateMenu($id);
} catch (\Exception $e) {
$this->error('保存失败');
}
$save ? $this->success('保存成功') : $this->error('保存失败');
}
$row->auth_ids = explode(',', $row->auth_ids);
$this->assign('row', $row);
return $this->fetch();
}
/**
* @NodeAnotation(title="编辑")
*/
public function password($id)
{
$this->checkPostRequest();
$row = $this->model->find($id);
empty($row) && $this->error('数据不存在');
if ($this->request->isAjax()) {
$post = $this->request->post();
$rule = [
'password|登录密码' => 'require',
'password_again|确认密码' => 'require',
];
$this->validate($post, $rule);
if ($post['password'] != $post['password_again']) {
$this->error('两次密码输入不一致');
}
try {
$save = $row->save([
'password' => password($post['password']),
]);
} catch (\Exception $e) {
$this->error('保存失败');
}
$save ? $this->success('保存成功') : $this->error('保存失败');
}
$row->auth_ids = explode(',', $row->auth_ids);
$this->assign('row', $row);
return $this->fetch();
}
/**
* @NodeAnotation(title="删除")
*/
public function delete($id)
{
$this->checkPostRequest();
$row = $this->model->whereIn('id', $id)->select();
$row->isEmpty() && $this->error('数据不存在');
$id == AdminConstant::SUPER_ADMIN_ID && $this->error('超级管理员不允许修改');
if (is_array($id)){
if (in_array(AdminConstant::SUPER_ADMIN_ID, $id)){
$this->error('超级管理员不允许修改');
}
}
try {
$save = $row->delete();
} catch (\Exception $e) {
$this->error('删除失败');
}
$save ? $this->success('删除成功') : $this->error('删除失败');
}
/**
* @NodeAnotation(title="属性修改")
*/
public function modify()
{
$this->checkPostRequest();
$post = $this->request->post();
$rule = [
'id|ID' => 'require',
'field|字段' => 'require',
'value|值' => 'require',
];
$this->validate($post, $rule);
if (!in_array($post['field'], $this->allowModifyFields)) {
$this->error('该字段不允许修改:' . $post['field']);
}
if ($post['id'] == AdminConstant::SUPER_ADMIN_ID && $post['field'] == 'status') {
$this->error('超级管理员状态不允许修改');
}
$row = $this->model->find($post['id']);
empty($row) && $this->error('数据不存在');
try {
$row->save([
$post['field'] => $post['value'],
]);
} catch (\Exception $e) {
$this->error($e->getMessage());
}
$this->success('保存成功');
}
}

91
app/admin/controller/system/Auth.php

@ -0,0 +1,91 @@
<?php
// +----------------------------------------------------------------------
// | EasyAdmin
// +----------------------------------------------------------------------
// | PHP交流群: 763822524
// +----------------------------------------------------------------------
// | 开源协议 https://mit-license.org
// +----------------------------------------------------------------------
// | github开源项目:https://github.com/zhongshaofa/EasyAdmin
// +----------------------------------------------------------------------
namespace app\admin\controller\system;
use app\admin\model\SystemAuth;
use app\admin\model\SystemAuthNode;
use app\admin\service\TriggerService;
use app\common\controller\AdminController;
use EasyAdmin\annotation\ControllerAnnotation;
use EasyAdmin\annotation\NodeAnotation;
use think\App;
/**
* @ControllerAnnotation(title="角色权限管理")
* Class Auth
* @package app\admin\controller\system
*/
class Auth extends AdminController
{
use \app\admin\traits\Curd;
protected $sort = [
'sort' => 'desc',
'id' => 'desc',
];
public function __construct(App $app)
{
parent::__construct($app);
$this->model = new SystemAuth();
}
/**
* @NodeAnotation(title="授权")
*/
public function authorize($id)
{
$row = $this->model->find($id);
empty($row) && $this->error('数据不存在');
if ($this->request->isAjax()) {
$list = $this->model->getAuthorizeNodeListByAdminId($id);
$this->success('获取成功', $list);
}
$this->assign('row', $row);
return $this->fetch();
}
/**
* @NodeAnotation(title="授权保存")
*/
public function saveAuthorize()
{
$this->checkPostRequest();
$id = $this->request->post('id');
$node = $this->request->post('node', "[]");
$node = json_decode($node, true);
$row = $this->model->find($id);
empty($row) && $this->error('数据不存在');
try {
$authNode = new SystemAuthNode();
$authNode->where('auth_id', $id)->delete();
if (!empty($node)) {
$saveAll = [];
foreach ($node as $vo) {
$saveAll[] = [
'auth_id' => $id,
'node_id' => $vo,
];
}
$authNode->saveAll($saveAll);
}
TriggerService::updateMenu();
} catch (\Exception $e) {
$this->error('保存失败');
}
$this->success('保存成功');
}
}

68
app/admin/controller/system/Config.php

@ -0,0 +1,68 @@
<?php
// +----------------------------------------------------------------------
// | EasyAdmin
// +----------------------------------------------------------------------
// | PHP交流群: 763822524
// +----------------------------------------------------------------------
// | 开源协议 https://mit-license.org
// +----------------------------------------------------------------------
// | github开源项目:https://github.com/zhongshaofa/EasyAdmin
// +----------------------------------------------------------------------
namespace app\admin\controller\system;
use app\admin\model\SystemConfig;
use app\admin\service\TriggerService;
use app\common\controller\AdminController;
use EasyAdmin\annotation\ControllerAnnotation;
use EasyAdmin\annotation\NodeAnotation;
use think\App;
/**
* Class Config
* @package app\admin\controller\system
* @ControllerAnnotation(title="系统配置管理")
*/
class Config extends AdminController
{
public function __construct(App $app)
{
parent::__construct($app);
$this->model = new SystemConfig();
}
/**
* @NodeAnotation(title="列表")
*/
public function index()
{
return $this->fetch();
}
/**
* @NodeAnotation(title="保存")
*/
public function save()
{
$this->checkPostRequest();
$post = $this->request->post();
try {
foreach ($post as $key => $val) {
$this->model
->where('name', $key)
->update([
'value' => $val,
]);
}
TriggerService::updateMenu();
TriggerService::updateSysconfig();
} catch (\Exception $e) {
$this->error('保存失败');
}
$this->success('保存成功');
}
}

67
app/admin/controller/system/Log.php

@ -0,0 +1,67 @@
<?php
namespace app\admin\controller\system;
use app\admin\model\SystemLog;
use app\common\controller\AdminController;
use EasyAdmin\annotation\ControllerAnnotation;
use EasyAdmin\annotation\NodeAnotation;
use think\App;
/**
* @ControllerAnnotation(title="操作日志管理")
* Class Auth
* @package app\admin\controller\system
*/
class Log extends AdminController
{
public function __construct(App $app)
{
parent::__construct($app);
$this->model = new SystemLog();
}
/**
* @NodeAnotation(title="列表")
*/
public function index()
{
if ($this->request->isAjax()) {
if (input('selectFields')) {
return $this->selectList();
}
[$page, $limit, $where, $excludeFields] = $this->buildTableParames(['month']);
$month = (isset($excludeFields['month']) && !empty($excludeFields['month']))
? date('Ym',strtotime($excludeFields['month']))
: date('Ym');
// todo TP6框架有一个BUG,非模型名与表名不对应时(name属性自定义),withJoin生成的sql有问题
$count = $this->model
->setMonth($month)
->with('admin')
->where($where)
->select();
$list = $this->model
->setMonth($month)
->with('admin')
->where($where)
->page($page, $limit)
->order($this->sort)
->select();
$data = [
'code' => 0,
'msg' => '',
'count' => $count,
'data' => $list,
];
return json($data);
}
return $this->fetch();
}
}

219
app/admin/controller/system/Menu.php

@ -0,0 +1,219 @@
<?php
// +----------------------------------------------------------------------
// | EasyAdmin
// +----------------------------------------------------------------------
// | PHP交流群: 763822524
// +----------------------------------------------------------------------
// | 开源协议 https://mit-license.org
// +----------------------------------------------------------------------
// | github开源项目:https://github.com/zhongshaofa/EasyAdmin
// +----------------------------------------------------------------------
namespace app\admin\controller\system;
use app\admin\model\SystemMenu;
use app\admin\model\SystemNode;
use app\admin\service\TriggerService;
use app\common\constants\MenuConstant;
use EasyAdmin\annotation\ControllerAnnotation;
use EasyAdmin\annotation\NodeAnotation;
use app\common\controller\AdminController;
use think\App;
/**
* Class Menu
* @package app\admin\controller\system
* @ControllerAnnotation(title="菜单管理",auth=true)
*/
class Menu extends AdminController
{
use \app\admin\traits\Curd;
protected $sort = [
'sort' => 'desc',
'id' => 'asc',
];
public function __construct(App $app)
{
parent::__construct($app);
$this->model = new SystemMenu();
}
/**
* @NodeAnotation(title="列表")
*/
public function index()
{
if ($this->request->isAjax()) {
if (input('selectFields')) {
return $this->selectList();
}
$count = $this->model->count();
$list = $this->model->order($this->sort)->select();
$data = [
'code' => 0,
'msg' => '',
'count' => $count,
'data' => $list,
];
return json($data);
}
return $this->fetch();
}
/**
* @NodeAnotation(title="添加")
*/
public function add($id = null)
{
$homeId = $this->model
->where([
'pid' => MenuConstant::HOME_PID,
])
->value('id');
if ($id == $homeId) {
$this->error('首页不能添加子菜单');
}
if ($this->request->isPost()) {
$post = $this->request->post();
$rule = [
'pid|上级菜单' => 'require',
'title|菜单名称' => 'require',
'icon|菜单图标' => 'require',
];
$this->validate($post, $rule);
try {
$save = $this->model->save($post);
} catch (\Exception $e) {
$this->error('保存失败');
}
if ($save) {
TriggerService::updateMenu();
$this->success('保存成功');
} else {
$this->error('保存失败');
}
}
$pidMenuList = $this->model->getPidMenuList();
$this->assign('id', $id);
$this->assign('pidMenuList', $pidMenuList);
return $this->fetch();
}
/**
* @NodeAnotation(title="编辑")
*/
public function edit($id)
{
$row = $this->model->find($id);
empty($row) && $this->error('数据不存在');
if ($this->request->isPost()) {
$post = $this->request->post();
$rule = [
'pid|上级菜单' => 'require',
'title|菜单名称' => 'require',
'icon|菜单图标' => 'require',
];
$this->validate($post, $rule);
try {
$save = $row->save($post);
} catch (\Exception $e) {
$this->error('保存失败');
}
if ($save) {
TriggerService::updateMenu();
$this->success('保存成功');
} else {
$this->error('保存失败');
}
}
$pidMenuList = $this->model->getPidMenuList();
$this->assign([
'id' => $id,
'pidMenuList' => $pidMenuList,
'row' => $row,
]);
return $this->fetch();
}
/**
* @NodeAnotation(title="删除")
*/
public function delete($id)
{
$this->checkPostRequest();
$row = $this->model->whereIn('id', $id)->select();
empty($row) && $this->error('数据不存在');
try {
$save = $row->delete();
} catch (\Exception $e) {
$this->error('删除失败');
}
if ($save) {
TriggerService::updateMenu();
$this->success('删除成功');
} else {
$this->error('删除失败');
}
}
/**
* @NodeAnotation(title="属性修改")
*/
public function modify()
{
$this->checkPostRequest();
$post = $this->request->post();
$rule = [
'id|ID' => 'require',
'field|字段' => 'require',
'value|值' => 'require',
];
$this->validate($post, $rule);
$row = $this->model->find($post['id']);
if (!$row) {
$this->error('数据不存在');
}
if (!in_array($post['field'], $this->allowModifyFields)) {
$this->error('该字段不允许修改:' . $post['field']);
}
$homeId = $this->model
->where([
'pid' => MenuConstant::HOME_PID,
])
->value('id');
if ($post['id'] == $homeId && $post['field'] == 'status') {
$this->error('首页状态不允许关闭');
}
try {
$row->save([
$post['field'] => $post['value'],
]);
} catch (\Exception $e) {
$this->error($e->getMessage());
}
TriggerService::updateMenu();
$this->success('保存成功');
}
/**
* @NodeAnotation(title="添加菜单提示")
*/
public function getMenuTips()
{
$node = input('get.keywords');
$list = SystemNode::whereLike('node', "%{$node}%")
->field('node,title')
->limit(10)
->select();
return json([
'code' => 0,
'content' => $list,
'type' => 'success',
]);
}
}

121
app/admin/controller/system/Node.php

@ -0,0 +1,121 @@
<?php
// +----------------------------------------------------------------------
// | EasyAdmin
// +----------------------------------------------------------------------
// | PHP交流群: 763822524
// +----------------------------------------------------------------------
// | 开源协议 https://mit-license.org
// +----------------------------------------------------------------------
// | github开源项目:https://github.com/zhongshaofa/EasyAdmin
// +----------------------------------------------------------------------
namespace app\admin\controller\system;
use app\admin\model\SystemNode;
use app\admin\service\TriggerService;
use app\common\controller\AdminController;
use EasyAdmin\annotation\ControllerAnnotation;
use EasyAdmin\annotation\NodeAnotation;
use app\admin\service\NodeService;
use think\App;
/**
* @ControllerAnnotation(title="系统节点管理")
* Class Node
* @package app\admin\controller\system
*/
class Node extends AdminController
{
use \app\admin\traits\Curd;
public function __construct(App $app)
{
parent::__construct($app);
$this->model = new SystemNode();
}
/**
* @NodeAnotation(title="列表")
*/
public function index()
{
if ($this->request->isAjax()) {
if (input('selectFields')) {
return $this->selectList();
}
$count = $this->model
->count();
$list = $this->model
->getNodeTreeList();
$data = [
'code' => 0,
'msg' => '',
'count' => $count,
'data' => $list,
];
return json($data);
}
return $this->fetch();
}
/**
* @NodeAnotation(title="系统节点更新")
*/
public function refreshNode($force = 0)
{
$this->checkPostRequest();
$nodeList = (new NodeService())->getNodelist();
empty($nodeList) && $this->error('暂无需要更新的系统节点');
$model = new SystemNode();
try {
if ($force == 1) {
$updateNodeList = $model->whereIn('node', array_column($nodeList, 'node'))->select();
$formatNodeList = array_format_key($nodeList, 'node');
foreach ($updateNodeList as $vo) {
isset($formatNodeList[$vo['node']]) && $model->where('id', $vo['id'])->update([
'title' => $formatNodeList[$vo['node']]['title'],
'is_auth' => $formatNodeList[$vo['node']]['is_auth'],
]);
}
}
$existNodeList = $model->field('node,title,type,is_auth')->select();
foreach ($nodeList as $key => $vo) {
foreach ($existNodeList as $v) {
if ($vo['node'] == $v->node) {
unset($nodeList[$key]);
break;
}
}
}
$model->saveAll($nodeList);
TriggerService::updateNode();
} catch (\Exception $e) {
$this->error('节点更新失败');
}
$this->success('节点更新成功');
}
/**
* @NodeAnotation(title="清除失效节点")
*/
public function clearNode()
{
$this->checkPostRequest();
$nodeList = (new NodeService())->getNodelist();
$model = new SystemNode();
try {
$existNodeList = $model->field('id,node,title,type,is_auth')->select()->toArray();
$formatNodeList = array_format_key($nodeList, 'node');
foreach ($existNodeList as $vo) {
!isset($formatNodeList[$vo['node']]) && $model->where('id', $vo['id'])->delete();
}
TriggerService::updateNode();
} catch (\Exception $e) {
$this->error('节点更新失败');
}
$this->success('节点更新成功');
}
}

43
app/admin/controller/system/Quick.php

@ -0,0 +1,43 @@
<?php
// +----------------------------------------------------------------------
// | EasyAdmin
// +----------------------------------------------------------------------
// | PHP交流群: 763822524
// +----------------------------------------------------------------------
// | 开源协议 https://mit-license.org
// +----------------------------------------------------------------------
// | github开源项目:https://github.com/zhongshaofa/EasyAdmin
// +----------------------------------------------------------------------
namespace app\admin\controller\system;
use app\admin\model\SystemQuick;
use app\common\controller\AdminController;
use EasyAdmin\annotation\ControllerAnnotation;
use EasyAdmin\annotation\NodeAnotation;
use think\App;
/**
* @ControllerAnnotation(title="快捷入口管理")
* Class Quick
* @package app\admin\controller\system
*/
class Quick extends AdminController
{
use \app\admin\traits\Curd;
protected $sort = [
'sort' => 'desc',
'id' => 'desc',
];
public function __construct(App $app)
{
parent::__construct($app);
$this->model = new SystemQuick();
}
}

38
app/admin/controller/system/Uploadfile.php

@ -0,0 +1,38 @@
<?php
// +----------------------------------------------------------------------
// | EasyAdmin
// +----------------------------------------------------------------------
// | PHP交流群: 763822524
// +----------------------------------------------------------------------
// | 开源协议 https://mit-license.org
// +----------------------------------------------------------------------
// | github开源项目:https://github.com/zhongshaofa/EasyAdmin
// +----------------------------------------------------------------------
namespace app\admin\controller\system;
use app\admin\model\SystemUploadfile;
use app\common\controller\AdminController;
use EasyAdmin\annotation\ControllerAnnotation;
use EasyAdmin\annotation\NodeAnotation;
use think\App;
/**
* @ControllerAnnotation(title="上传文件管理")
* Class Uploadfile
* @package app\admin\controller\system
*/
class Uploadfile extends AdminController
{
use \app\admin\traits\Curd;
public function __construct(App $app)
{
parent::__construct($app);
$this->model = new SystemUploadfile();
}
}

21
app/admin/event.php

@ -0,0 +1,21 @@
<?php
// 事件定义文件
return [
'bind' => [
],
'listen' => [
'AppInit' => [
\app\admin\listener\ViewInitListener::class,
],
'HttpRun' => [
\app\admin\listener\ViewInitListener::class,
],
'HttpEnd' => [],
'LogLevel' => [],
'LogWrite' => [],
],
'subscribe' => [
],
];

21
app/admin/middleware.php

@ -0,0 +1,21 @@
<?php
// 全局中间件定义文件
return [
// Session初始化
\think\middleware\SessionInit::class,
// 系统操作日志
\app\admin\middleware\SystemLog::class,
// Csrf安全校验
\app\admin\middleware\CsrfMiddleware::class,
// 后台视图初始化
// \app\admin\middleware\ViewInit::class,
// 检测用户是否登录
// \app\admin\middleware\CheckAdmin::class,
];

67
app/admin/middleware/CheckAdmin.php

@ -0,0 +1,67 @@
<?php
// +----------------------------------------------------------------------
// | EasyAdmin
// +----------------------------------------------------------------------
// | PHP交流群: 763822524
// +----------------------------------------------------------------------
// | 开源协议 https://mit-license.org
// +----------------------------------------------------------------------
// | github开源项目:https://github.com/zhongshaofa/EasyAdmin
// +----------------------------------------------------------------------
namespace app\admin\middleware;
use app\common\service\AuthService;
use think\Request;
/**
* @deprecated 废弃,新版TP不支持在中间件获取控制器相关信息
* 检测用户登录和节点权限
* Class CheckAdmin
* @package app\admin\middleware
*/
class CheckAdmin
{
use \app\common\traits\JumpTrait;
public function handle(Request $request, \Closure $next)
{
$adminConfig = config('admin');
$adminId = session('admin.id');
$expireTime = session('admin.expire_time');
/** @var AuthService $authService */
$authService = app(AuthService::class, ['adminId' => $adminId]);
$currentNode = $authService->getCurrentNode();
$currentController = parse_name($request->controller());
// 验证登录
if (!in_array($currentController, $adminConfig['no_login_controller']) &&
!in_array($currentNode, $adminConfig['no_login_node'])) {
empty($adminId) && $this->error('请先登录后台', [], __url('admin/login/index'));
// 判断是否登录过期
if ($expireTime !== true && time() > $expireTime) {
session('admin', null);
$this->error('登录已过期,请重新登录', [], __url('admin/login/index'));
}
}
// 验证权限
if (!in_array($currentController, $adminConfig['no_auth_controller']) &&
!in_array($currentNode, $adminConfig['no_auth_node'])) {
$check = $authService->checkNode($currentNode);
!$check && $this->error('无权限访问');
// 判断是否为演示环境
if(env('easyadmin.is_demo', false) && $request->isPost()){
$this->error('演示环境下不允许修改');
}
}
return $next($request);
}
}

53
app/admin/middleware/CsrfMiddleware.php

@ -0,0 +1,53 @@
<?php
// +----------------------------------------------------------------------
// | EasyAdmin
// +----------------------------------------------------------------------
// | PHP交流群: 763822524
// +----------------------------------------------------------------------
// | 开源协议 https://mit-license.org
// +----------------------------------------------------------------------
// | github开源项目:https://github.com/zhongshaofa/EasyAdmin
// +----------------------------------------------------------------------
namespace app\admin\middleware;
use app\Request;
use CsrfVerify\drive\ThinkphpCache;
use CsrfVerify\entity\CsrfVerifyEntity;
use CsrfVerify\interfaces\CsrfVerifyInterface;
use think\facade\Session;
class CsrfMiddleware
{
use \app\common\traits\JumpTrait;
public function handle(Request $request, \Closure $next)
{
if (env('EASYADMIN.IS_CSRF', true)) {
if (!in_array($request->method(), ['GET', 'HEAD', 'OPTIONS'])) {
// 跨域校验
$refererUrl = $request->header('REFERER', null);
$refererInfo = parse_url($refererUrl);
$host = $request->host(true);
if (!isset($refererInfo['host']) || $refererInfo['host'] != $host) {
$this->error('当前请求不合法!');
}
// CSRF校验
// @todo 兼容CK编辑器上传功能
$ckCsrfToken = $request->post('ckCsrfToken', null);
$data = !empty($ckCsrfToken) ? ['__token__' => $ckCsrfToken] : [];
$check = $request->checkToken('__token__', $data);
if (!$check) {
$this->error('请求验证失败,请重新刷新页面!');
}
}
}
return $next($request);
}
}

77
app/admin/middleware/SystemLog.php

@ -0,0 +1,77 @@
<?php
// +----------------------------------------------------------------------
// | EasyAdmin
// +----------------------------------------------------------------------
// | PHP交流群: 763822524
// +----------------------------------------------------------------------
// | 开源协议 https://mit-license.org
// +----------------------------------------------------------------------
// | github开源项目:https://github.com/zhongshaofa/EasyAdmin
// +----------------------------------------------------------------------
namespace app\admin\middleware;
use app\admin\service\SystemLogService;
use app\Request;
use EasyAdmin\tool\CommonTool;
use think\facade\Log;
/**
* 系统操作日志中间件
* Class SystemLog
* @package app\admin\middleware
*/
class SystemLog
{
/**
* 敏感信息字段,日志记录时需要加密
* @var array
*/
protected $sensitiveParams = [
'password',
'password_again',
'phone',
'mobile'
];
public function handle(Request $request, \Closure $next)
{
$params = $request->param();
if (isset($params['s'])) {
unset($params['s']);
}
foreach ($params as $key => $val) {
in_array($key, $this->sensitiveParams) && $params[$key] = "***********";
}
$method = strtolower($request->method());
$url = $request->url();
trace([
'url' => $url,
'method' => $method,
'params' => $params,
],
'requestDebugInfo'
);
if ($request->isAjax()) {
if (in_array($method, ['post', 'put', 'delete'])) {
$ip = CommonTool::getRealIp();
$data = [
'admin_id' => session('admin.id'),
'url' => $url,
'method' => $method,
'ip' => $ip,
'content' => json_encode($params, JSON_UNESCAPED_UNICODE),
'useragent' => $_SERVER['HTTP_USER_AGENT'],
'create_time' => time(),
];
SystemLogService::instance()->save($data);
}
}
return $next($request);
}
}

58
app/admin/middleware/ViewInit.php

@ -0,0 +1,58 @@
<?php
// +----------------------------------------------------------------------
// | EasyAdmin
// +----------------------------------------------------------------------
// | PHP交流群: 763822524
// +----------------------------------------------------------------------
// | 开源协议 https://mit-license.org
// +----------------------------------------------------------------------
// | github开源项目:https://github.com/zhongshaofa/EasyAdmin
// +----------------------------------------------------------------------
namespace app\admin\middleware;
use app\admin\service\ConfigService;
use app\common\constants\AdminConstant;
use think\App;
use think\facade\Request;
use think\facade\View;
/**
* @deprecated 废弃,新版TP不支持在中间件获取控制器相关信息
* Class ViewInit
* @package app\admin\middleware
*/
class ViewInit
{
public function handle(\app\Request $request, \Closure $next)
{
list($thisModule, $thisController, $thisAction) = [app('http')->getName(), Request::controller(), $request->action()];
list($thisControllerArr, $jsPath) = [explode('.', $thisController), null];
foreach ($thisControllerArr as $vo) {
empty($jsPath) ? $jsPath = parse_name($vo) : $jsPath .= '/' . parse_name($vo);
}
$autoloadJs = file_exists(root_path('public')."static/{$thisModule}/js/{$jsPath}.js") ? true : false;
$thisControllerJsPath = "{$thisModule}/js/{$jsPath}.js";
$adminModuleName = config('app.admin_alias_name');
$isSuperAdmin = session('admin.id') == AdminConstant::SUPER_ADMIN_ID ? true : false;
$data = [
'adminModuleName' => $adminModuleName,
'thisController' => parse_name($thisController),
'thisAction' => $thisAction,
'thisRequest' => parse_name("{$thisModule}/{$thisController}/{$thisAction}"),
'thisControllerJsPath' => "{$thisControllerJsPath}",
'autoloadJs' => $autoloadJs,
'isSuperAdmin' => $isSuperAdmin,
'version' => env('app_debug') ? time() : ConfigService::getVersion(),
];
View::assign($data);
$request->adminModuleName = $adminModuleName;
return $next($request);
}
}

23
app/admin/model/MallCate.php

@ -0,0 +1,23 @@
<?php
// +----------------------------------------------------------------------
// | EasyAdmin
// +----------------------------------------------------------------------
// | PHP交流群: 763822524
// +----------------------------------------------------------------------
// | 开源协议 https://mit-license.org
// +----------------------------------------------------------------------
// | github开源项目:https://github.com/zhongshaofa/EasyAdmin
// +----------------------------------------------------------------------
namespace app\admin\model;
use app\common\model\TimeModel;
class MallCate extends TimeModel
{
protected $deleteTime = 'delete_time';
}

30
app/admin/model/MallGoods.php

@ -0,0 +1,30 @@
<?php
// +----------------------------------------------------------------------
// | EasyAdmin
// +----------------------------------------------------------------------
// | PHP交流群: 763822524
// +----------------------------------------------------------------------
// | 开源协议 https://mit-license.org
// +----------------------------------------------------------------------
// | github开源项目:https://github.com/zhongshaofa/EasyAdmin
// +----------------------------------------------------------------------
namespace app\admin\model;
use app\common\model\TimeModel;
class MallGoods extends TimeModel
{
protected $table = "";
protected $deleteTime = 'delete_time';
public function cate()
{
return $this->belongsTo('app\admin\model\MallCate', 'cate_id', 'id');
}
}

31
app/admin/model/SystemAdmin.php

@ -0,0 +1,31 @@
<?php
// +----------------------------------------------------------------------
// | EasyAdmin
// +----------------------------------------------------------------------
// | PHP交流群: 763822524
// +----------------------------------------------------------------------
// | 开源协议 https://mit-license.org
// +----------------------------------------------------------------------
// | github开源项目:https://github.com/zhongshaofa/EasyAdmin
// +----------------------------------------------------------------------
namespace app\admin\model;
use app\common\model\TimeModel;
class SystemAdmin extends TimeModel
{
protected $deleteTime = 'delete_time';
public function getAuthList()
{
$list = (new SystemAuth())
->where('status', 1)
->column('title', 'id');
return $list;
}
}

64
app/admin/model/SystemAuth.php

@ -0,0 +1,64 @@
<?php
// +----------------------------------------------------------------------
// | EasyAdmin
// +----------------------------------------------------------------------
// | PHP交流群: 763822524
// +----------------------------------------------------------------------
// | 开源协议 https://mit-license.org
// +----------------------------------------------------------------------
// | github开源项目:https://github.com/zhongshaofa/EasyAdmin
// +----------------------------------------------------------------------
namespace app\admin\model;
use app\common\model\TimeModel;
class SystemAuth extends TimeModel
{
protected $deleteTime = 'delete_time';
/**
* 根据角色ID获取授权节点
* @param $authId
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getAuthorizeNodeListByAdminId($authId)
{
$checkNodeList = (new SystemAuthNode())
->where('auth_id', $authId)
->column('node_id');
$systemNode = new SystemNode();
$nodelList = $systemNode
->where('is_auth', 1)
->field('id,node,title,type,is_auth')
->select()
->toArray();
$newNodeList = [];
foreach ($nodelList as $vo) {
if ($vo['type'] == 1) {
$vo = array_merge($vo, ['field' => 'node', 'spread' => true]);
$vo['checked'] = false;
$vo['title'] = "{$vo['title']}【{$vo['node']}】";
$children = [];
foreach ($nodelList as $v) {
if ($v['type'] == 2 && strpos($v['node'], $vo['node'] . '/') !== false) {
$v = array_merge($v, ['field' => 'node', 'spread' => true]);
$v['checked'] = in_array($v['id'], $checkNodeList) ? true : false;
$v['title'] = "{$v['title']}【{$v['node']}】";
$children[] = $v;
}
}
!empty($children) && $vo['children'] = $children;
$newNodeList[] = $vo;
}
}
return $newNodeList;
}
}

21
app/admin/model/SystemAuthNode.php

@ -0,0 +1,21 @@
<?php
// +----------------------------------------------------------------------
// | EasyAdmin
// +----------------------------------------------------------------------
// | PHP交流群: 763822524
// +----------------------------------------------------------------------
// | 开源协议 https://mit-license.org
// +----------------------------------------------------------------------
// | github开源项目:https://github.com/zhongshaofa/EasyAdmin
// +----------------------------------------------------------------------
namespace app\admin\model;
use app\common\model\TimeModel;
class SystemAuthNode extends TimeModel
{
}

22
app/admin/model/SystemConfig.php

@ -0,0 +1,22 @@
<?php
// +----------------------------------------------------------------------
// | EasyAdmin
// +----------------------------------------------------------------------
// | PHP交流群: 763822524
// +----------------------------------------------------------------------
// | 开源协议 https://mit-license.org
// +----------------------------------------------------------------------
// | github开源项目:https://github.com/zhongshaofa/EasyAdmin
// +----------------------------------------------------------------------
namespace app\admin\model;
use app\common\model\TimeModel;
class SystemConfig extends TimeModel
{
}

29
app/admin/model/SystemLog.php

@ -0,0 +1,29 @@
<?php
namespace app\admin\model;
use app\common\model\TimeModel;
class SystemLog extends TimeModel
{
public function __construct(array $data = [])
{
parent::__construct($data);
$this->name = 'system_log_' . date('Ym');
}
public function setMonth($month)
{
$this->name = 'system_log_' . $month;
return $this;
}
public function admin()
{
return $this->belongsTo('app\admin\model\SystemAdmin', 'admin_id', 'id');
}
}

70
app/admin/model/SystemMenu.php

@ -0,0 +1,70 @@
<?php
// +----------------------------------------------------------------------
// | EasyAdmin
// +----------------------------------------------------------------------
// | PHP交流群: 763822524
// +----------------------------------------------------------------------
// | 开源协议 https://mit-license.org
// +----------------------------------------------------------------------
// | github开源项目:https://github.com/zhongshaofa/EasyAdmin
// +----------------------------------------------------------------------
namespace app\admin\model;
use app\common\constants\MenuConstant;
use app\common\model\TimeModel;
class SystemMenu extends TimeModel
{
protected $deleteTime = 'delete_time';
public function getPidMenuList()
{
$list = $this->field('id,pid,title')
->where([
['pid', '<>', MenuConstant::HOME_PID],
['status', '=', 1],
])
->select()
->toArray();
$pidMenuList = $this->buildPidMenu(0, $list);
$pidMenuList = array_merge([[
'id' => 0,
'pid' => 0,
'title' => '顶级菜单',
]], $pidMenuList);
return $pidMenuList;
}
protected function buildPidMenu($pid, $list, $level = 0)
{
$newList = [];
foreach ($list as $vo) {
if ($vo['pid'] == $pid) {
$level++;
foreach ($newList as $v) {
if ($vo['pid'] == $v['pid'] && isset($v['level'])) {
$level = $v['level'];
break;
}
}
$vo['level'] = $level;
if ($level > 1) {
$repeatString = "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
$markString = str_repeat("{$repeatString}├{$repeatString}", $level - 1);
$vo['title'] = $markString . $vo['title'];
}
$newList[] = $vo;
$childList = $this->buildPidMenu($vo['id'], $list, $level);
!empty($childList) && $newList = array_merge($newList, $childList);
}
}
return $newList;
}
}

47
app/admin/model/SystemNode.php

@ -0,0 +1,47 @@
<?php
// +----------------------------------------------------------------------
// | EasyAdmin
// +----------------------------------------------------------------------
// | PHP交流群: 763822524
// +----------------------------------------------------------------------
// | 开源协议 https://mit-license.org
// +----------------------------------------------------------------------
// | github开源项目:https://github.com/zhongshaofa/EasyAdmin
// +----------------------------------------------------------------------
namespace app\admin\model;
use app\common\model\TimeModel;
class SystemNode extends TimeModel
{
public function getNodeTreeList()
{
$list = $this->select()->toArray();
$list = $this->buildNodeTree($list);
return $list;
}
protected function buildNodeTree($list)
{
$newList = [];
$repeatString = "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
foreach ($list as $vo) {
if ($vo['type'] == 1) {
$newList[] = $vo;
foreach ($list as $v) {
if ($v['type'] == 2 && strpos($v['node'], $vo['node'] . '/') !== false) {
$v['node'] = "{$repeatString}├{$repeatString}" . $v['node'];
$newList[] = $v;
}
}
}
}
return $newList;
}
}

23
app/admin/model/SystemQuick.php

@ -0,0 +1,23 @@
<?php
// +----------------------------------------------------------------------
// | EasyAdmin
// +----------------------------------------------------------------------
// | PHP交流群: 763822524
// +----------------------------------------------------------------------
// | 开源协议 https://mit-license.org
// +----------------------------------------------------------------------
// | github开源项目:https://github.com/zhongshaofa/EasyAdmin
// +----------------------------------------------------------------------
namespace app\admin\model;
use app\common\model\TimeModel;
class SystemQuick extends TimeModel
{
protected $deleteTime = 'delete_time';
}

21
app/admin/model/SystemUploadfile.php

@ -0,0 +1,21 @@
<?php
// +----------------------------------------------------------------------
// | EasyAdmin
// +----------------------------------------------------------------------
// | PHP交流群: 763822524
// +----------------------------------------------------------------------
// | 开源协议 https://mit-license.org
// +----------------------------------------------------------------------
// | github开源项目:https://github.com/zhongshaofa/EasyAdmin
// +----------------------------------------------------------------------
namespace app\admin\model;
use app\common\model\TimeModel;
class SystemUploadfile extends TimeModel
{
}

31
app/admin/service/ConfigService.php

@ -0,0 +1,31 @@
<?php
// +----------------------------------------------------------------------
// | EasyAdmin
// +----------------------------------------------------------------------
// | PHP交流群: 763822524
// +----------------------------------------------------------------------
// | 开源协议 https://mit-license.org
// +----------------------------------------------------------------------
// | github开源项目:https://github.com/zhongshaofa/EasyAdmin
// +----------------------------------------------------------------------
namespace app\admin\service;
use think\facade\Cache;
class ConfigService
{
public static function getVersion()
{
$version = Cache('version');
if (empty($version)) {
$version = sysconfig('site', 'site_version');
cache('site_version', $version);
Cache::set('version', $version, 3600);
}
return $version;
}
}

37
app/admin/service/NodeService.php

@ -0,0 +1,37 @@
<?php
// +----------------------------------------------------------------------
// | EasyAdmin
// +----------------------------------------------------------------------
// | PHP交流群: 763822524
// +----------------------------------------------------------------------
// | 开源协议 https://mit-license.org
// +----------------------------------------------------------------------
// | github开源项目:https://github.com/zhongshaofa/EasyAdmin
// +----------------------------------------------------------------------
namespace app\admin\service;
use EasyAdmin\auth\Node;
class NodeService
{
/**
* 获取节点服务
* @return array
* @throws \Doctrine\Common\Annotations\AnnotationException
* @throws \ReflectionException
*/
public function getNodelist()
{
$basePath = base_path() . 'admin' . DIRECTORY_SEPARATOR . 'controller';
$baseNamespace = "app\admin\controller";
$nodeList = (new Node($basePath, $baseNamespace))
->getNodelist();
return $nodeList;
}
}

136
app/admin/service/SystemLogService.php

@ -0,0 +1,136 @@
<?php
// +----------------------------------------------------------------------
// | EasyAdmin
// +----------------------------------------------------------------------
// | PHP交流群: 763822524
// +----------------------------------------------------------------------
// | 开源协议 https://mit-license.org
// +----------------------------------------------------------------------
// | github开源项目:https://github.com/zhongshaofa/EasyAdmin
// +----------------------------------------------------------------------
namespace app\admin\service;
use think\facade\Db;
use think\facade\Config;
/**
* 系统日志表
* Class SystemLogService
* @package app\admin\service
*/
class SystemLogService
{
/**
* 当前实例
* @var object
*/
protected static $instance;
/**
* 表前缀
* @var string
*/
protected $tablePrefix;
/**
* 表后缀
* @var string
*/
protected $tableSuffix;
/**
* 表名
* @var string
*/
protected $tableName;
/**
* 构造方法
* SystemLogService constructor.
*/
protected function __construct()
{
$this->tablePrefix = Config::get('database.connections.mysql.prefix');
$this->tableSuffix = date('Ym', time());
$this->tableName = "{$this->tablePrefix}system_log_{$this->tableSuffix}";
return $this;
}
/**
* 获取实例对象
* @return SystemLogService|object
*/
public static function instance()
{
if (is_null(self::$instance)) {
self::$instance = new static();
}
return self::$instance;
}
/**
* 保存数据
* @param $data
* @return bool|string
*/
public function save($data)
{
Db::startTrans();
try {
$this->detectTable();
Db::table($this->tableName)->insert($data);
Db::commit();
} catch (\Exception $e) {
Db::rollback();
return $e->getMessage();
}
return true;
}
/**
* 检测数据表
* @return bool
*/
protected function detectTable()
{
$check = Db::query("show tables like '{$this->tableName}'");
if (empty($check)) {
$sql = $this->getCreateSql();
Db::execute($sql);
}
return true;
}
public function getAllTableList()
{
}
/**
* 根据后缀获取创建表的sql
* @return string
*/
protected function getCreateSql()
{
return <<<EOT
CREATE TABLE `{$this->tableName}` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
`admin_id` int(10) unsigned DEFAULT '0' COMMENT '管理员ID',
`url` varchar(1500) NOT NULL DEFAULT '' COMMENT '操作页面',
`method` varchar(50) NOT NULL COMMENT '请求方法',
`title` varchar(100) DEFAULT '' COMMENT '日志标题',
`content` text NOT NULL COMMENT '内容',
`ip` varchar(50) NOT NULL DEFAULT '' COMMENT 'IP',
`useragent` varchar(255) DEFAULT '' COMMENT 'User-Agent',
`create_time` int(10) DEFAULT NULL COMMENT '操作时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=630 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='后台操作日志表 - {$this->tableSuffix}';
EOT;
}
}

61
app/admin/service/TriggerService.php

@ -0,0 +1,61 @@
<?php
// +----------------------------------------------------------------------
// | EasyAdmin
// +----------------------------------------------------------------------
// | PHP交流群: 763822524
// +----------------------------------------------------------------------
// | 开源协议 https://mit-license.org
// +----------------------------------------------------------------------
// | github开源项目:https://github.com/zhongshaofa/EasyAdmin
// +----------------------------------------------------------------------
namespace app\admin\service;
use think\facade\Cache;
class TriggerService
{
/**
* 更新菜单缓存
* @param null $adminId
* @return bool
*/
public static function updateMenu($adminId = null)
{
if(empty($adminId)){
Cache::tag('initAdmin')->clear();
}else{
Cache::delete('initAdmin_' . $adminId);
}
return true;
}
/**
* 更新节点缓存
* @param null $adminId
* @return bool
*/
public static function updateNode($adminId = null)
{
if(empty($adminId)){
Cache::tag('authNode')->clear();
}else{
Cache::delete('allAuthNode_' . $adminId);
}
return true;
}
/**
* 更新系统设置缓存
* @return bool
*/
public static function updateSysconfig()
{
Cache::tag('sysconfig')->clear();
return true;
}
}

172
app/admin/traits/Curd.php

@ -0,0 +1,172 @@
<?php
// +----------------------------------------------------------------------
// | EasyAdmin
// +----------------------------------------------------------------------
// | PHP交流群: 763822524
// +----------------------------------------------------------------------
// | 开源协议 https://mit-license.org
// +----------------------------------------------------------------------
// | github开源项目:https://github.com/zhongshaofa/EasyAdmin
// +----------------------------------------------------------------------
namespace app\admin\traits;
use EasyAdmin\annotation\NodeAnotation;
use EasyAdmin\tool\CommonTool;
use jianyan\excel\Excel;
use think\facade\Db;
/**
* 后台CURD复用
* Trait Curd
* @package app\admin\traits
*/
trait Curd
{
/**
* @NodeAnotation(title="列表")
*/
public function index()
{
if ($this->request->isAjax()) {
if (input('selectFields')) {
return $this->selectList();
}
list($page, $limit, $where) = $this->buildTableParames();
$count = $this->model
->where($where)
->count();
$list = $this->model
->where($where)
->page($page, $limit)
->order($this->sort)
->select();
$data = [
'code' => 0,
'msg' => '',
'count' => $count,
'data' => $list,
];
return json($data);
}
return $this->fetch();
}
/**
* @NodeAnotation(title="添加")
*/
public function add()
{
if ($this->request->isPost()) {
$post = $this->request->post();
$rule = [];
$this->validate($post, $rule);
try {
$save = $this->model->save($post);
} catch (\Exception $e) {
$this->error('保存失败:'.$e->getMessage());
}
$save ? $this->success('保存成功') : $this->error('保存失败');
}
return $this->fetch();
}
/**
* @NodeAnotation(title="编辑")
*/
public function edit($id)
{
$row = $this->model->find($id);
empty($row) && $this->error('数据不存在');
if ($this->request->isPost()) {
$post = $this->request->post();
$rule = [];
$this->validate($post, $rule);
try {
$save = $row->save($post);
} catch (\Exception $e) {
$this->error('保存失败');
}
$save ? $this->success('保存成功') : $this->error('保存失败');
}
$this->assign('row', $row);
return $this->fetch();
}
/**
* @NodeAnotation(title="删除")
*/
public function delete($id)
{
$this->checkPostRequest();
$row = $this->model->whereIn('id', $id)->select();
$row->isEmpty() && $this->error('数据不存在');
try {
$save = $row->delete();
} catch (\Exception $e) {
$this->error('删除失败');
}
$save ? $this->success('删除成功') : $this->error('删除失败');
}
/**
* @NodeAnotation(title="导出")
*/
public function export()
{
list($page, $limit, $where) = $this->buildTableParames();
$tableName = $this->model->getName();
$tableName = CommonTool::humpToLine(lcfirst($tableName));
$prefix = config('database.connections.mysql.prefix');
$dbList = Db::query("show full columns from {$prefix}{$tableName}");
$header = [];
foreach ($dbList as $vo) {
$comment = !empty($vo['Comment']) ? $vo['Comment'] : $vo['Field'];
if (!in_array($vo['Field'], $this->noExportFields)) {
$header[] = [$comment, $vo['Field']];
}
}
$list = $this->model
->where($where)
->limit(100000)
->order('id', 'desc')
->select()
->toArray();
$fileName = time();
return Excel::exportData($list, $header, $fileName, 'xlsx');
}
/**
* @NodeAnotation(title="属性修改")
*/
public function modify()
{
$this->checkPostRequest();
$post = $this->request->post();
$rule = [
'id|ID' => 'require',
'field|字段' => 'require',
'value|值' => 'require',
];
$this->validate($post, $rule);
$row = $this->model->find($post['id']);
if (!$row) {
$this->error('数据不存在');
}
if (!in_array($post['field'], $this->allowModifyFields)) {
$this->error('该字段不允许修改:' . $post['field']);
}
try {
$row->save([
$post['field'] => $post['value'],
]);
} catch (\Exception $e) {
$this->error($e->getMessage());
}
$this->success('保存成功');
}
}

49
app/admin/view/index/edit_admin.html

@ -0,0 +1,49 @@
<div class="layuimini-container">
<div class="layuimini-main">
<form id="app-form" class="layui-form layuimini-form">
<div class="layui-form-item">
<label class="layui-form-label required">用户头像</label>
<div class="layui-input-block layuimini-upload">
<input name="head_img" class="layui-input layui-col-xs6" lay-reqtext="请上传用户头像" placeholder="请上传用户头像" value="{$row.head_img|default=''}">
<div class="layuimini-upload-btn">
<span><a class="layui-btn" data-upload="head_img" data-upload-number="one" data-upload-exts="png|jpg|ico|jpeg"><i class="fa fa-upload"></i> 上传</a></span>
<span><a class="layui-btn layui-btn-normal" id="select_head_img" data-upload-select="head_img" data-upload-number="one"><i class="fa fa-list"></i> 选择</a></span>
</div>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label required">登录账户</label>
<div class="layui-input-block">
<input type="text" name="username" class="layui-input" readonly value="{$row.username|default=''}">
<tip>填写登录账户。</tip>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">用户手机</label>
<div class="layui-input-block">
<input type="text" name="phone" class="layui-input" lay-reqtext="请输入用户手机" placeholder="请输入用户手机" value="{$row.username|default=''}">
<tip>填写用户手机。</tip>
</div>
</div>
<div class="layui-form-item layui-form-text">
<label class="layui-form-label">备注信息</label>
<div class="layui-input-block">
<textarea name="remark" class="layui-textarea" placeholder="请输入备注信息">{$row.username|default=''}</textarea>
</div>
</div>
<div class="hr-line"></div>
<div class="layui-form-item text-center">
<button type="submit" class="layui-btn layui-btn-normal layui-btn-sm" lay-submit>确认</button>
<button type="reset" class="layui-btn layui-btn-primary layui-btn-sm">重置</button>
</div>
</form>
</div>
</div>

38
app/admin/view/index/edit_password.html

@ -0,0 +1,38 @@
<div class="layuimini-container">
<div class="layuimini-main">
<form id="app-form" class="layui-form layuimini-form">
<div class="layui-form-item">
<label class="layui-form-label required">登录账户</label>
<div class="layui-input-block">
<input type="text" name="username" class="layui-input" readonly value="{$row.username|default=''}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">登录密码</label>
<div class="layui-input-block">
<input type="password" name="password" class="layui-input" lay-verify="required" lay-reqtext="请输入登录密码" placeholder="请输入登录密码" value="">
<tip>填写登录密码。</tip>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">确认密码</label>
<div class="layui-input-block">
<input type="password" name="password_again" class="layui-input" lay-verify="required" lay-reqtext="请输入确认密码" placeholder="请输入确认密码" value="">
<tip>填写再次登录密码。</tip>
</div>
</div>
<div class="hr-line"></div>
<div class="layui-form-item text-center">
<button type="submit" class="layui-btn layui-btn-normal layui-btn-sm" lay-submit>确认</button>
<button type="reset" class="layui-btn layui-btn-primary layui-btn-sm">重置</button>
</div>
</form>
</div>
</div>

110
app/admin/view/index/index.html

@ -0,0 +1,110 @@
<link rel="stylesheet" href="__STATIC__/plugs/lay-module/layuimini/layuimini.css?v={:time()}" media="all">
<link rel="stylesheet" href="__STATIC__/plugs/lay-module/layuimini/themes/default.css?v={:time()}" media="all">
<style id="layuimini-bg-color">
</style>
<body class="layui-layout-body layuimini-all">
<div class="layui-layout layui-layout-admin">
<div class="layui-header header">
<div class="layui-logo layuimini-logo"></div>
<div class="layuimini-header-content">
<a>
<div class="layuimini-tool"><i title="展开" class="fa fa-outdent" data-side-fold="1"></i></div>
</a>
<!--电脑端头部菜单-->
<ul class="layui-nav layui-layout-left layuimini-header-menu layuimini-menu-header-pc layuimini-pc-show">
</ul>
<!--手机端头部菜单-->
<ul class="layui-nav layui-layout-left layuimini-header-menu layuimini-mobile-show">
<li class="layui-nav-item">
<a href="javascript:;"><i class="fa fa-list-ul"></i> 选择模块</a>
<dl class="layui-nav-child layuimini-menu-header-mobile">
</dl>
</li>
</ul>
<ul class="layui-nav layui-layout-right">
<li class="layui-nav-item" lay-unselect>
<a href="javascript:;" data-refresh="刷新"><i class="fa fa-refresh"></i></a>
</li>
<li class="layui-nav-item" lay-unselect>
<a href="javascript:;" data-clear="清理" class="layuimini-clear"><i class="fa fa-trash-o"></i></a>
</li>
<li class="layui-nav-item mobile layui-hide-xs" lay-unselect>
<a href="javascript:;" data-check-screen="full"><i class="fa fa-arrows-alt"></i></a>
</li>
<li class="layui-nav-item layuimini-setting">
<a href="javascript:;">
<img src="{:session('admin.head_img')}" class="layui-nav-img" width="50" height="50">
<cite class="adminName">{:session('admin.username')}</cite>
<span class="layui-nav-more"></span>
</a>
<dl class="layui-nav-child">
<dd>
<a href="javascript:;" layuimini-content-href="{:__url('index/editAdmin')}" data-title="基本资料" data-icon="fa fa-gears">基本资料<span class="layui-badge-dot"></span></a>
</dd>
<dd>
<a href="javascript:;" layuimini-content-href="{:__url('index/editPassword')}" data-title="修改密码" data-icon="fa fa-gears">修改密码</a>
</dd>
<dd>
<hr>
</dd>
<dd>
<a href="javascript:;" class="login-out">退出登录</a>
</dd>
</dl>
</li>
<li class="layui-nav-item layuimini-select-bgcolor" lay-unselect>
<a href="javascript:;" data-bgcolor="配色方案"><i class="fa fa-ellipsis-v"></i></a>
</li>
</ul>
</div>
</div>
<!--无限极左侧菜单-->
<div class="layui-side layui-bg-black layuimini-menu-left">
</div>
<!--初始化加载层-->
<div class="layuimini-loader">
<div class="layuimini-loader-inner"></div>
</div>
<!--手机端遮罩层-->
<div class="layuimini-make"></div>
<!-- 移动导航 -->
<div class="layuimini-site-mobile"><i class="layui-icon"></i></div>
<div class="layui-body">
<div class="layuimini-tab layui-tab-rollTool layui-tab" lay-filter="layuiminiTab" lay-allowclose="true">
<ul class="layui-tab-title">
<li class="layui-this" id="layuiminiHomeTabId" lay-id=""></li>
</ul>
<div class="layui-tab-control">
<li class="layuimini-tab-roll-left layui-icon layui-icon-left"></li>
<li class="layuimini-tab-roll-right layui-icon layui-icon-right"></li>
<li class="layui-tab-tool layui-icon layui-icon-down">
<ul class="layui-nav close-box">
<li class="layui-nav-item">
<a href="javascript:;"><span class="layui-nav-more"></span></a>
<dl class="layui-nav-child">
<dd><a href="javascript:;" layuimini-tab-close="current">关 闭 当 前</a></dd>
<dd><a href="javascript:;" layuimini-tab-close="other">关 闭 其 他</a></dd>
<dd><a href="javascript:;" layuimini-tab-close="all">关 闭 全 部</a></dd>
</dl>
</li>
</ul>
</li>
</div>
<div class="layui-tab-content">
<div id="layuiminiHomeTabIframe" class="layui-tab-item layui-show"></div>
</div>
</div>
</div>
</div>
</body>

258
app/admin/view/index/welcome.html

@ -0,0 +1,258 @@
<link rel="stylesheet" href="__STATIC__/admin/css/welcome.css?v={:time()}" media="all">
<div class="layuimini-container">
<div class="layuimini-main">
<div class="layui-row layui-col-space15">
<div class="layui-col-md8">
<div class="layui-row layui-col-space15">
<div class="layui-col-md6">
<div class="layui-card">
<div class="layui-card-header"><i class="fa fa-warning icon"></i>数据统计</div>
<div class="layui-card-body">
<div class="welcome-module">
<div class="layui-row layui-col-space10">
<div class="layui-col-xs6">
<div class="panel layui-bg-number">
<div class="panel-body">
<div class="panel-title">
<span class="label pull-right layui-bg-blue">实时</span>
<h5>用户统计</h5>
</div>
<div class="panel-content">
<h1 class="no-margins">1234</h1>
<small>当前分类总记录数</small>
</div>
</div>
</div>
</div>
<div class="layui-col-xs6">
<div class="panel layui-bg-number">
<div class="panel-body">
<div class="panel-title">
<span class="label pull-right layui-bg-cyan">实时</span>
<h5>商品统计</h5>
</div>
<div class="panel-content">
<h1 class="no-margins">1234</h1>
<small>当前分类总记录数</small>
</div>
</div>
</div>
</div>
<div class="layui-col-xs6">
<div class="panel layui-bg-number">
<div class="panel-body">
<div class="panel-title">
<span class="label pull-right layui-bg-orange">实时</span>
<h5>浏览统计</h5>
</div>
<div class="panel-content">
<h1 class="no-margins">1234</h1>
<small>当前分类总记录数</small>
</div>
</div>
</div>
</div>
<div class="layui-col-xs6">
<div class="panel layui-bg-number">
<div class="panel-body">
<div class="panel-title">
<span class="label pull-right layui-bg-green">实时</span>
<h5>订单统计</h5>
</div>
<div class="panel-content">
<h1 class="no-margins">1234</h1>
<small>当前分类总记录数</small>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="layui-col-md6">
<div class="layui-card">
<div class="layui-card-header"><i class="fa fa-credit-card icon icon-blue"></i>快捷入口</div>
<div class="layui-card-body">
<div class="welcome-module">
<div class="layui-row layui-col-space10 layuimini-qiuck">
{foreach $quicks as $vo}
<div class="layui-col-xs3 layuimini-qiuck-module">
<a layuimini-content-href="{:url($vo['href'])}" data-title="{$vo['title']}">
<i class="{$vo['icon']|raw}"></i>
<cite>{$vo['title']}</cite>
</a>
</div>
{/foreach}
</div>
</div>
</div>
</div>
</div>
<div class="layui-col-md12">
<div class="layui-card">
<div class="layui-card-header"><i class="fa fa-line-chart icon"></i>报表统计</div>
<div class="layui-card-body">
<div id="echarts-records" style="width: 100%;min-height:500px"></div>
</div>
</div>
</div>
</div>
</div>
<div class="layui-col-md4">
<div class="layui-card">
<div class="layui-card-header"><i class="fa fa-bullhorn icon icon-tip"></i>系统公告</div>
<div class="layui-card-body layui-text">
<div class="layuimini-notice">
<div class="layuimini-notice-title">修改选项卡样式</div>
<div class="layuimini-notice-extra">2019-07-11 23:06</div>
<div class="layuimini-notice-content layui-hide">
界面足够简洁清爽。<br>
一个接口几行代码而已直接初始化整个框架,无需复杂操作。<br>
支持多tab,可以打开多窗口。<br>
支持无限级菜单和对font-awesome图标库的完美支持。<br>
失效以及报错菜单无法直接打开,并给出弹出层提示完美的线上用户体验。<br>
url地址hash定位,可以清楚看到当前tab的地址信息。<br>
刷新页面会保留当前的窗口,并且会定位当前窗口对应左侧菜单栏。<br>
移动端的友好支持。<br>
</div>
</div>
<div class="layuimini-notice">
<div class="layuimini-notice-title">新增系统404模板</div>
<div class="layuimini-notice-extra">2019-07-11 12:57</div>
<div class="layuimini-notice-content layui-hide">
界面足够简洁清爽。<br>
一个接口几行代码而已直接初始化整个框架,无需复杂操作。<br>
支持多tab,可以打开多窗口。<br>
支持无限级菜单和对font-awesome图标库的完美支持。<br>
失效以及报错菜单无法直接打开,并给出弹出层提示完美的线上用户体验。<br>
url地址hash定位,可以清楚看到当前tab的地址信息。<br>
刷新页面会保留当前的窗口,并且会定位当前窗口对应左侧菜单栏。<br>
移动端的友好支持。<br>
</div>
</div>
<div class="layuimini-notice">
<div class="layuimini-notice-title">新增treetable插件和菜单管理样式</div>
<div class="layuimini-notice-extra">2019-07-05 14:28</div>
<div class="layuimini-notice-content layui-hide">
界面足够简洁清爽。<br>
一个接口几行代码而已直接初始化整个框架,无需复杂操作。<br>
支持多tab,可以打开多窗口。<br>
支持无限级菜单和对font-awesome图标库的完美支持。<br>
失效以及报错菜单无法直接打开,并给出弹出层提示完美的线上用户体验。<br>
url地址hash定位,可以清楚看到当前tab的地址信息。<br>
刷新页面会保留当前的窗口,并且会定位当前窗口对应左侧菜单栏。<br>
移动端的友好支持。<br>
</div>
</div>
<div class="layuimini-notice">
<div class="layuimini-notice-title">修改logo缩放问题</div>
<div class="layuimini-notice-extra">2019-07-04 11:02</div>
<div class="layuimini-notice-content layui-hide">
界面足够简洁清爽。<br>
一个接口几行代码而已直接初始化整个框架,无需复杂操作。<br>
支持多tab,可以打开多窗口。<br>
支持无限级菜单和对font-awesome图标库的完美支持。<br>
失效以及报错菜单无法直接打开,并给出弹出层提示完美的线上用户体验。<br>
url地址hash定位,可以清楚看到当前tab的地址信息。<br>
刷新页面会保留当前的窗口,并且会定位当前窗口对应左侧菜单栏。<br>
移动端的友好支持。<br>
</div>
</div>
<div class="layuimini-notice">
<div class="layuimini-notice-title">修复左侧菜单缩放tab无法移动</div>
<div class="layuimini-notice-extra">2019-06-17 11:55</div>
<div class="layuimini-notice-content layui-hide">
界面足够简洁清爽。<br>
一个接口几行代码而已直接初始化整个框架,无需复杂操作。<br>
支持多tab,可以打开多窗口。<br>
支持无限级菜单和对font-awesome图标库的完美支持。<br>
失效以及报错菜单无法直接打开,并给出弹出层提示完美的线上用户体验。<br>
url地址hash定位,可以清楚看到当前tab的地址信息。<br>
刷新页面会保留当前的窗口,并且会定位当前窗口对应左侧菜单栏。<br>
移动端的友好支持。<br>
</div>
</div>
<div class="layuimini-notice">
<div class="layuimini-notice-title">修复多模块菜单栏展开有问题</div>
<div class="layuimini-notice-extra">2019-06-13 14:53</div>
<div class="layuimini-notice-content layui-hide">
界面足够简洁清爽。<br>
一个接口几行代码而已直接初始化整个框架,无需复杂操作。<br>
支持多tab,可以打开多窗口。<br>
支持无限级菜单和对font-awesome图标库的完美支持。<br>
失效以及报错菜单无法直接打开,并给出弹出层提示完美的线上用户体验。<br>
url地址hash定位,可以清楚看到当前tab的地址信息。<br>
刷新页面会保留当前的窗口,并且会定位当前窗口对应左侧菜单栏。<br>
移动端的友好支持。<br>
</div>
</div>
</div>
</div>
<div class="layui-card">
<div class="layui-card-header"><i class="fa fa-fire icon"></i>版本信息</div>
<div class="layui-card-body layui-text">
<table class="layui-table">
<colgroup>
<col width="100">
<col>
</colgroup>
<tbody>
<tr>
<td>框架名称</td>
<td>
EasyAdmin
</td>
</tr>
<tr>
<td>当前版本</td>
<td>v2.0.0</td>
</tr>
<tr>
<td>主要特色</td>
<td>零门槛 / 响应式 / 清爽 / 极简</td>
</tr>
<tr>
<td>Gitee</td>
<td style="padding-bottom: 0;">
<div class="layui-btn-container">
<a href="https://gitee.com/zhongshaofa/easyadmin" style="margin-right: 15px"><img src="https://gitee.com/zhongshaofa/easyadmin/badge/star.svg?theme=dark" alt="star"></a>
<a href="https://gitee.com/zhongshaofa/easyadmin"><img src="https://gitee.com/zhongshaofa/easyadmin/badge/fork.svg?theme=dark" alt="fork"></a>
</div>
</td>
</tr>
<tr>
<td>Github</td>
<td style="padding-bottom: 0;">
<div class="layui-btn-container">
<iframe src="https://ghbtns.com/github-btn.html?user=zhongshaofa&repo=easyadmin&type=star&count=true" frameborder="0" scrolling="0" width="100px" height="20px"></iframe>
<iframe src="https://ghbtns.com/github-btn.html?user=zhongshaofa&repo=easyadmin&type=fork&count=true" frameborder="0" scrolling="0" width="100px" height="20px"></iframe>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="layui-card">
<div class="layui-card-header"><i class="fa fa-paper-plane-o icon"></i>作者心语</div>
<div class="layui-card-body layui-text layadmin-text">
<p>本模板基于layui2.5.4以及font-awesome-4.7.0进行实现。layui开发文档地址:<a class="layui-btn layui-btn-xs layui-btn-danger" target="_blank" href="http://www.layui.com/doc">layui文档</a></p>
<p>技术交流QQ群:<a target="_blank" href="https://jq.qq.com/?_wv=1027&k=5JRGVfe"><img border="0" src="//pub.idqqimg.com/wpa/images/group.png" alt="layuimini" title="layuimini"></a>(加群请备注来源:如gitee、github、官网等)</p>
<p>喜欢此后台模板的可以给我的GitHub和Gitee加个Star支持一下</p>
<p class="layui-red">备注:此后台框架永久开源,但请勿进行出售或者上传到任何素材网站,否则将追究相应的责任。</p>
</div>
</div>
</div>
</div>
</div>
</div>

32
app/admin/view/layout/default.html

@ -0,0 +1,32 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>{:sysconfig('site','site_name')}</title>
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<!--[if lt IE 9]>
<script src="https://cdn.staticfile.org/html5shiv/r29/html5.min.js"></script>
<script src="https://cdn.staticfile.org/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
<link rel="stylesheet" href="__STATIC__/admin/css/public.css?v={$version}" media="all">
<script>
window.CONFIG = {
ADMIN: "{$adminModuleName|default='admin'}",
CONTROLLER_JS_PATH: "{$thisControllerJsPath|default=''}",
ACTION: "{$thisAction|default=''}",
AUTOLOAD_JS: "{$autoloadJs|default='false'}",
IS_SUPER_ADMIN: "{$isSuperAdmin|default='false'}",
VERSION: "{$version|default='1.0.0'}",
CSRF_TOKEN: "{:token()}",
};
</script>
<script src="__STATIC__/plugs/layui-v2.5.6/layui.all.js?v={$version}" charset="utf-8"></script>
<script src="__STATIC__/plugs/require-2.3.6/require.js?v={$version}" charset="utf-8"></script>
<script src="__STATIC__/config-admin.js?v={$version}" charset="utf-8"></script>
</head>
<body>
{__CONTENT__}
</body>
</html>

45
app/admin/view/login/index.html

@ -0,0 +1,45 @@
<link rel="stylesheet" href="__STATIC__/admin/css/login.css?v={$version}" media="all">
<div class="main-body">
<div class="login-main">
<div class="login-top">
<span>{:sysconfig('site','site_name')}</span>
<span class="bg1"></span>
<span class="bg2"></span>
</div>
<form class="layui-form login-bottom">
<div class="demo{if !$demo} layui-hide{/if}">用户名:admin 密码:123456</div>
<div class="center">
<div class="item">
<span class="icon icon-2"></span>
<input type="text" name="username" lay-verify="required" placeholder="请输入登录账号" maxlength="24"/>
</div>
<div class="item">
<span class="icon icon-3"></span>
<input type="password" name="password" lay-verify="required" placeholder="请输入密码" maxlength="20">
<span class="bind-password icon icon-4"></span>
</div>
{if $captcha == 1}
<div id="validatePanel" class="item" style="width: 137px;">
<input type="text" name="captcha" placeholder="请输入验证码" maxlength="4">
<img id="refreshCaptcha" class="validateImg" src="{:url('login/captcha')}" onclick="this.src='{:url(\'login/captcha\')}?seed='+Math.random()">
</div>
{/if}
</div>
<div class="tip">
<span class="icon-nocheck"></span>
<span class="login-tip">保持登录</span>
<a href="javascript:" class="forget-password">忘记密码?</a>
</div>
<div class="layui-form-item" style="text-align:center; width:100%;height:100%;margin:0px;">
<button class="login-btn" lay-submit>立即登录</button>
</div>
</form>
</div>
</div>
<div class="footer">
{:sysconfig('site','site_copyright')}<span class="padding-5">|</span><a target="_blank" href="http://www.miitbeian.gov.cn">{:sysconfig('site','site_beian')}</a>
</div>

43
app/admin/view/mall/cate/add.html

@ -0,0 +1,43 @@
<div class="layuimini-container">
<form id="app-form" class="layui-form layuimini-form">
<div class="layui-form-item">
<label class="layui-form-label">分类名称</label>
<div class="layui-input-block">
<input type="text" name="title" class="layui-input" lay-verify="required" placeholder="请输入分类名称" value="">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label required">分类图片</label>
<div class="layui-input-block layuimini-upload">
<input name="image" class="layui-input layui-col-xs6" lay-verify="required" placeholder="请上传分类图片" value="">
<div class="layuimini-upload-btn">
<span><a class="layui-btn" data-upload="image" data-upload-number="one" data-upload-exts="png|jpg|ico|jpeg" data-upload-icon="image"><i class="fa fa-upload"></i> 上传</a></span>
<span><a class="layui-btn layui-btn-normal" id="select_image" data-upload-select="image" data-upload-number="one" data-upload-mimetype="image/*"><i class="fa fa-list"></i> 选择</a></span>
</div>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">分类排序</label>
<div class="layui-input-block">
<input type="number" name="sort" class="layui-input" placeholder="请输入分类排序" value="0">
</div>
</div>
<div class="layui-form-item layui-form-text">
<label class="layui-form-label">备注信息</label>
<div class="layui-input-block">
<textarea name="remark" class="layui-textarea" placeholder="请输入备注信息"></textarea>
</div>
</div>
<div class="hr-line"></div>
<div class="layui-form-item text-center">
<button type="submit" class="layui-btn layui-btn-normal layui-btn-sm" lay-submit>确认</button>
<button type="reset" class="layui-btn layui-btn-primary layui-btn-sm">重置</button>
</div>
</form>
</div>

43
app/admin/view/mall/cate/edit.html

@ -0,0 +1,43 @@
<div class="layuimini-container">
<form id="app-form" class="layui-form layuimini-form">
<div class="layui-form-item">
<label class="layui-form-label">分类名称</label>
<div class="layui-input-block">
<input type="text" name="title" class="layui-input" lay-verify="required" placeholder="请输入分类名称" value="{$row.title|default=''}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label required">分类图片</label>
<div class="layui-input-block layuimini-upload">
<input name="image" class="layui-input layui-col-xs6" lay-verify="required" lay-reqtext="请上传分类图片" placeholder="请上传分类图片" value="{$row.image|default=''}">
<div class="layuimini-upload-btn">
<span><a class="layui-btn" data-upload="image" data-upload-number="one" data-upload-exts="png|jpg|ico|jpeg" data-upload-icon="image"><i class="fa fa-upload"></i> 上传</a></span>
<span><a class="layui-btn layui-btn-normal" id="select_head_img" data-upload-select="head_img" data-upload-number="one" data-upload-mimetype="image/*"><i class="fa fa-list"></i> 选择</a></span>
</div>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">分类排序</label>
<div class="layui-input-block">
<input type="number" name="sort" class="layui-input" placeholder="请输入分类排序" value="{$row.sort|default=''}">
</div>
</div>
<div class="layui-form-item layui-form-text">
<label class="layui-form-label">备注信息</label>
<div class="layui-input-block">
<textarea name="remark" class="layui-textarea" placeholder="请输入备注信息">{$row.remark|default=''}</textarea>
</div>
</div>
<div class="hr-line"></div>
<div class="layui-form-item text-center">
<button type="submit" class="layui-btn layui-btn-normal layui-btn-sm" lay-submit>确认</button>
<button type="reset" class="layui-btn layui-btn-primary layui-btn-sm">重置</button>
</div>
</form>
</div>

10
app/admin/view/mall/cate/index.html

@ -0,0 +1,10 @@
<div class="layuimini-container">
<div class="layuimini-main">
<table id="currentTable" class="layui-table layui-hide"
data-auth-add="{:auth('mall.cate/add')}"
data-auth-edit="{:auth('mall.cate/edit')}"
data-auth-delete="{:auth('mall.cate/delete')}"
lay-filter="currentTable">
</table>
</div>
</div>

89
app/admin/view/mall/goods/add.html

@ -0,0 +1,89 @@
<div class="layuimini-container">
<form id="app-form" class="layui-form layuimini-form">
<div class="layui-form-item">
<label class="layui-form-label">商品分类</label>
<div class="layui-input-block">
<select name="cate_id" lay-verify="required" data-select="{:url('mall.cate/index')}" data-fields="id,title">
</select>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">商品标题</label>
<div class="layui-input-block">
<input type="text" name="title" class="layui-input" lay-verify="required" placeholder="请输入商品标题" value="">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label required">商品LOGO</label>
<div class="layui-input-block layuimini-upload">
<input name="logo" class="layui-input layui-col-xs6" lay-verify="required" placeholder="请上传分类图片" value="">
<div class="layuimini-upload-btn">
<span><a class="layui-btn" data-upload="logo" data-upload-number="one" data-upload-exts="png|jpg|ico|jpeg" data-upload-icon="image"><i class="fa fa-upload"></i> 上传</a></span>
<span><a class="layui-btn layui-btn-normal" id="select_logo" data-upload-select="logo" data-upload-number="one" data-upload-mimetype="image/*"><i class="fa fa-list"></i> 选择</a></span>
</div>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label required">商品图片</label>
<div class="layui-input-block layuimini-upload">
<input name="images" class="layui-input layui-col-xs6" lay-verify="required" placeholder="请上传商品图片" value="">
<div class="layuimini-upload-btn">
<span><a class="layui-btn" data-upload="images" data-upload-number="more" data-upload-exts="png|jpg|ico|jpeg" data-upload-icon="image"><i class="fa fa-upload"></i> 上传</a></span>
<span><a class="layui-btn layui-btn-normal" id="select_images" data-upload-select="images" data-upload-number="more" data-upload-mimetype="image/*"><i class="fa fa-list"></i> 选择</a></span>
</div>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">市场价格</label>
<div class="layui-input-block">
<input type="text" name="market_price" class="layui-input" lay-verify="required" placeholder="请输入市场价格" value="0">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">折扣价格</label>
<div class="layui-input-block">
<input type="text" name="discount_price" class="layui-input" lay-verify="required" placeholder="请输入折扣价格" value="0">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">虚拟销量</label>
<div class="layui-input-block">
<input type="text" name="virtual_sales" class="layui-input" lay-verify="required" placeholder="请输入虚拟销量" value="0">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">商品描述</label>
<div class="layui-input-block">
<textarea name="describe" rows="20" class="layui-textarea editor" placeholder="请输入商品描述"></textarea>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">分类排序</label>
<div class="layui-input-block">
<input type="number" name="sort" class="layui-input" placeholder="请输入分类排序" value="0">
</div>
</div>
<div class="layui-form-item layui-form-text">
<label class="layui-form-label">备注信息</label>
<div class="layui-input-block">
<textarea name="remark" class="layui-textarea" placeholder="请输入备注信息"></textarea>
</div>
</div>
<div class="hr-line"></div>
<div class="layui-form-item text-center">
<button type="submit" class="layui-btn layui-btn-normal layui-btn-sm" lay-submit>确认</button>
<button type="reset" class="layui-btn layui-btn-primary layui-btn-sm">重置</button>
</div>
</form>
</div>

90
app/admin/view/mall/goods/edit.html

@ -0,0 +1,90 @@
<div class="layuimini-container">
<form id="app-form" class="layui-form layuimini-form">
<div class="layui-form-item">
<label class="layui-form-label">商品分类</label>
<div class="layui-input-block">
<select name="cate_id" lay-verify="required" data-select="{:url('mall.cate/index')}" data-fields="id,title" data-value="{$row.cate_id|default=''}">
</select>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">商品标题</label>
<div class="layui-input-block">
<input type="text" name="title" class="layui-input" lay-verify="required" placeholder="请输入商品标题" value="{$row.title|default=''}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label required">商品LOGO</label>
<div class="layui-input-block layuimini-upload">
<input name="logo" class="layui-input layui-col-xs6" lay-verify="required" placeholder="请上传分类图片" value="{$row.logo|default=''}">
<div class="layuimini-upload-btn">
<span><a class="layui-btn" data-upload="logo" data-upload-number="one" data-upload-exts="png|jpg|ico|jpeg" data-upload-icon="image"><i class="fa fa-upload"></i> 上传</a></span>
<span><a class="layui-btn layui-btn-normal" id="select_logo" data-upload-select="logo" data-upload-number="one" data-upload-mimetype="image/*"><i class="fa fa-list"></i> 选择</a></span>
</div>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label required">商品图片</label>
<div class="layui-input-block layuimini-upload">
<input name="images" class="layui-input layui-col-xs6" lay-verify="required" placeholder="请上传商品图片" value="{$row.images|default=''}">
<div class="layuimini-upload-btn">
<span><a class="layui-btn" data-upload="images" data-upload-number="more" data-upload-exts="png|jpg|ico|jpeg" data-upload-icon="image"><i class="fa fa-upload"></i> 上传</a></span>
<span><a class="layui-btn layui-btn-normal" id="select_images" data-upload-select="images" data-upload-number="more" data-upload-mimetype="image/*"><i class="fa fa-list"></i> 选择</a></span>
</div>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">市场价格</label>
<div class="layui-input-block">
<input type="text" name="market_price" class="layui-input" lay-verify="required" placeholder="请输入市场价格" value="{$row.market_price|default=''}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">折扣价格</label>
<div class="layui-input-block">
<input type="text" name="discount_price" class="layui-input" lay-verify="required" placeholder="请输入折扣价格" value="{$row.discount_price|default=''}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">虚拟销量</label>
<div class="layui-input-block">
<input type="text" name="virtual_sales" class="layui-input" lay-verify="required" placeholder="请输入虚拟销量" value="{$row.virtual_sales|default=''}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">商品描述</label>
<div class="layui-input-block">
<textarea name="describe" rows="20" class="layui-textarea editor" placeholder="请输入商品描述">{$row.describe|raw|default=''}</textarea>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">分类排序</label>
<div class="layui-input-block">
<input type="number" name="sort" class="layui-input" placeholder="请输入分类排序" value="{$row.sort|default=''}">
</div>
</div>
<div class="layui-form-item layui-form-text">
<label class="layui-form-label">备注信息</label>
<div class="layui-input-block">
<textarea name="remark" class="layui-textarea" placeholder="请输入备注信息">{$row.remark|default=''}</textarea>
</div>
</div>
<div class="hr-line"></div>
<div class="layui-form-item text-center">
<button type="submit" class="layui-btn layui-btn-normal layui-btn-sm" lay-submit>确认</button>
<button type="reset" class="layui-btn layui-btn-primary layui-btn-sm">重置</button>
</div>
</form>
</div>

11
app/admin/view/mall/goods/index.html

@ -0,0 +1,11 @@
<div class="layuimini-container">
<div class="layuimini-main">
<table id="currentTable" class="layui-table layui-hide"
data-auth-add="{:auth('mall.goods/add')}"
data-auth-edit="{:auth('mall.goods/edit')}"
data-auth-delete="{:auth('mall.goods/delete')}"
data-auth-stock="{:auth('mall.goods/stock')}"
lay-filter="currentTable">
</table>
</div>
</div>

39
app/admin/view/mall/goods/stock.html

@ -0,0 +1,39 @@
<div class="layuimini-container">
<form id="app-form" class="layui-form layuimini-form">
<div class="layui-form-item">
<label class="layui-form-label">商品标题</label>
<div class="layui-input-block">
<input type="text" class="layui-input" disabled value="{$row.title|default=''}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">库存统计</label>
<div class="layui-input-block">
<input type="text" class="layui-input" disabled value="{$row.total_stock|default=''}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">剩余库存</label>
<div class="layui-input-block">
<input type="text" class="layui-input" disabled value="{$row.stock|default=''}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">入库数量</label>
<div class="layui-input-block">
<input type="number" name="stock" class="layui-input" lay-verify="required" placeholder="请输入入库数量" value="0">
</div>
</div>
<div class="hr-line"></div>
<div class="layui-form-item text-center">
<button type="submit" class="layui-btn layui-btn-normal layui-btn-sm" lay-submit>确认</button>
<button type="reset" class="layui-btn layui-btn-primary layui-btn-sm">重置</button>
</div>
</form>
</div>

54
app/admin/view/system/admin/add.html

@ -0,0 +1,54 @@
<div class="layuimini-container">
<form id="app-form" class="layui-form layuimini-form">
<div class="layui-form-item">
<label class="layui-form-label required">用户头像</label>
<div class="layui-input-block layuimini-upload">
<input name="head_img" class="layui-input layui-col-xs6" lay-verify="required" lay-reqtext="请上传用户头像" placeholder="请上传用户头像" value="">
<div class="layuimini-upload-btn">
<span><a class="layui-btn" data-upload="head_img" data-upload-number="one" data-upload-exts="png|jpg|ico|jpeg" data-upload-icon="image"><i class="fa fa-upload"></i> 上传</a></span>
<span><a class="layui-btn layui-btn-normal" id="select_head_img" data-upload-select="head_img" data-upload-number="one" data-upload-mimetype="image/*"><i class="fa fa-list"></i> 选择</a></span>
</div>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label required">登录账户</label>
<div class="layui-input-block">
<input type="text" name="username" class="layui-input" lay-verify="required" lay-reqtext="请输入登录账户" placeholder="请输入登录账户" value="">
<tip>填写登录账户。</tip>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">用户手机</label>
<div class="layui-input-block">
<input type="text" name="phone" class="layui-input" lay-reqtext="请输入用户手机" placeholder="请输入用户手机" value="">
<tip>填写用户手机。</tip>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">角色权限</label>
<div class="layui-input-block">
{foreach auth_list as $key=>$val}
<input type="checkbox" name="auth_ids[{$key}]" lay-skin="primary" title="{$val}">
{/foreach}
</div>
</div>
<div class="layui-form-item layui-form-text">
<label class="layui-form-label">备注信息</label>
<div class="layui-input-block">
<textarea name="remark" class="layui-textarea" placeholder="请输入备注信息"></textarea>
</div>
</div>
<div class="hr-line"></div>
<div class="layui-form-item text-center">
<button type="submit" class="layui-btn layui-btn-normal layui-btn-sm" lay-submit>确认</button>
<button type="reset" class="layui-btn layui-btn-primary layui-btn-sm">重置</button>
</div>
</form>
</div>

54
app/admin/view/system/admin/edit.html

@ -0,0 +1,54 @@
<div class="layuimini-container">
<form id="app-form" class="layui-form layuimini-form">
<div class="layui-form-item">
<label class="layui-form-label required">用户头像</label>
<div class="layui-input-block layuimini-upload">
<input name="head_img" class="layui-input layui-col-xs6" lay-verify="required" lay-reqtext="请上传用户头像" placeholder="请上传用户头像" value="{$row.head_img|default=''}">
<div class="layuimini-upload-btn">
<span><a class="layui-btn" data-upload="head_img" data-upload-number="one" data-upload-exts="png|jpg|ico|jpeg"><i class="fa fa-upload"></i> 上传</a></span>
<span><a class="layui-btn layui-btn-normal" id="select_head_img" data-upload-select="head_img" data-upload-number="one"><i class="fa fa-list"></i> 选择</a></span>
</div>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label required">登录账户</label>
<div class="layui-input-block">
<input type="text" name="username" class="layui-input" readonly value="{$row.username|default=''}">
<tip>填写登录账户。</tip>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">用户手机</label>
<div class="layui-input-block">
<input type="text" name="phone" class="layui-input" lay-reqtext="请输入用户手机" placeholder="请输入用户手机" value="{$row.username|default=''}">
<tip>填写用户手机。</tip>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">角色权限</label>
<div class="layui-input-block">
{foreach auth_list as $key=>$val}
<input type="checkbox" name="auth_ids[{$key}]" lay-skin="primary" title="{$val}" {if in_array($key,$row.auth_ids)}checked="" {/if}>
{/foreach}
</div>
</div>
<div class="layui-form-item layui-form-text">
<label class="layui-form-label">备注信息</label>
<div class="layui-input-block">
<textarea name="remark" class="layui-textarea" placeholder="请输入备注信息">{$row.username|default=''}</textarea>
</div>
</div>
<div class="hr-line"></div>
<div class="layui-form-item text-center">
<button type="submit" class="layui-btn layui-btn-normal layui-btn-sm" lay-submit>确认</button>
<button type="reset" class="layui-btn layui-btn-primary layui-btn-sm">重置</button>
</div>
</form>
</div>

11
app/admin/view/system/admin/index.html

@ -0,0 +1,11 @@
<div class="layuimini-container">
<div class="layuimini-main">
<table id="currentTable" class="layui-table layui-hide"
data-auth-add="{:auth('system.admin/add')}"
data-auth-edit="{:auth('system.admin/edit')}"
data-auth-delete="{:auth('system.admin/delete')}"
data-auth-password="{:auth('system.admin/password')}"
lay-filter="currentTable">
</table>
</div>
</div>

34
app/admin/view/system/admin/password.html

@ -0,0 +1,34 @@
<div class="layuimini-container">
<form id="app-form" class="layui-form layuimini-form">
<div class="layui-form-item">
<label class="layui-form-label required">登录账户</label>
<div class="layui-input-block">
<input type="text" name="username" class="layui-input" readonly value="{$row.username|default=''}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">登录密码</label>
<div class="layui-input-block">
<input type="password" name="password" class="layui-input" lay-verify="required" lay-reqtext="请输入登录密码" placeholder="请输入登录密码" value="">
<tip>填写登录密码。</tip>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">确认密码</label>
<div class="layui-input-block">
<input type="password" name="password_again" class="layui-input" lay-verify="required" lay-reqtext="请输入确认密码" placeholder="请输入确认密码" value="">
<tip>填写再次登录密码。</tip>
</div>
</div>
<div class="hr-line"></div>
<div class="layui-form-item text-center">
<button type="submit" class="layui-btn layui-btn-normal layui-btn-sm" lay-submit>确认</button>
<button type="reset" class="layui-btn layui-btn-primary layui-btn-sm">重置</button>
</div>
</form>
</div>

26
app/admin/view/system/auth/add.html

@ -0,0 +1,26 @@
<div class="layuimini-container">
<form id="app-form" class="layui-form layuimini-form">
<div class="layui-form-item">
<label class="layui-form-label">权限名称</label>
<div class="layui-input-block">
<input type="text" name="title" class="layui-input" lay-verify="required" placeholder="请输入权限名称" value="">
<tip>填写权限名称。</tip>
</div>
</div>
<div class="layui-form-item layui-form-text">
<label class="layui-form-label">备注信息</label>
<div class="layui-input-block">
<textarea name="remark" class="layui-textarea" placeholder="请输入备注信息"></textarea>
</div>
</div>
<div class="hr-line"></div>
<div class="layui-form-item text-center">
<button type="submit" class="layui-btn layui-btn-normal layui-btn-sm" lay-submit>确认</button>
<button type="reset" class="layui-btn layui-btn-primary layui-btn-sm">重置</button>
</div>
</form>
</div>

27
app/admin/view/system/auth/authorize.html

@ -0,0 +1,27 @@
<div class="layuimini-container">
<form id="app-form" class="layui-form layuimini-form">
<div class="layui-form-item">
<label class="layui-form-label required">权限名称</label>
<div class="layui-input-block">
<input type="text" name="title" readonly class="layui-input" value="{$row.title|default=''}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label required">分配节点</label>
<div class="layui-input-block">
<div id="node_ids" class="demo-tree-more"></div>
</div>
</div>
<input type="hidden" name="id" readonly class="layui-input" value="{$row.id}">
<div class="hr-line"></div>
<div class="layui-form-item text-center">
<button type="submit" class="layui-btn layui-btn-normal layui-btn-sm" lay-submit="system.auth/saveAuthorize">确认</button>
<button type="reset" class="layui-btn layui-btn-primary layui-btn-sm">重置</button>
</div>
</form>
</div>

26
app/admin/view/system/auth/edit.html

@ -0,0 +1,26 @@
<div class="layuimini-container">
<form id="app-form" class="layui-form layuimini-form">
<div class="layui-form-item">
<label class="layui-form-label required">权限名称</label>
<div class="layui-input-block">
<input type="text" name="title" class="layui-input" lay-verify="required" lay-reqtext="请输入权限名称" placeholder="请输入权限名称" value="{$row.title|default=''}">
<tip>填写权限名称。</tip>
</div>
</div>
<div class="layui-form-item layui-form-text">
<label class="layui-form-label">备注信息</label>
<div class="layui-input-block">
<textarea name="remark" class="layui-textarea" placeholder="请输入备注信息">{$row.remark|default=''}</textarea>
</div>
</div>
<div class="hr-line"></div>
<div class="layui-form-item text-center">
<button type="submit" class="layui-btn layui-btn-normal layui-btn-sm" lay-submit>确认</button>
<button type="reset" class="layui-btn layui-btn-primary layui-btn-sm">重置</button>
</div>
</form>
</div>

11
app/admin/view/system/auth/index.html

@ -0,0 +1,11 @@
<div class="layuimini-container">
<div class="layuimini-main">
<table id="currentTable" class="layui-table layui-hide"
data-auth-add="{:auth('system.auth/add')}"
data-auth-edit="{:auth('system.auth/edit')}"
data-auth-delete="{:auth('system.auth/delete')}"
data-auth-authorize="{:auth('system.auth/authorize')}"
lay-filter="currentTable">
</table>
</div>
</div>

24
app/admin/view/system/config/index.html

@ -0,0 +1,24 @@
<div class="layuimini-container">
<div class="layuimini-main" id="app">
<div class="layui-tab layui-tab-brief" lay-filter="docDemoTabBrief">
<ul class="layui-tab-title">
<li class="layui-this">网站设置</li>
<li>LOGO配置</li>
<li>上传配置</li>
</ul>
<div class="layui-tab-content">
<div class="layui-tab-item layui-show">
{include file="system/config/site" /}
</div>
<div class="layui-tab-item">
{include file="system/config/logo" /}
</div>
<div class="layui-tab-item">
{include file="system/config/upload" /}
</div>
</div>
</div>
</div>
</div>

28
app/admin/view/system/config/logo.html

@ -0,0 +1,28 @@
<form id="app-form" class="layui-form layuimini-form">
<div class="layui-form-item">
<label class="layui-form-label">LOGO标题</label>
<div class="layui-input-block">
<input type="text" name="logo_title" class="layui-input" lay-verify="required" placeholder="请输入LOGO标题" value="{:sysconfig('site','logo_title')}">
<tip>填写站点名称。</tip>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">LOGO图标</label>
<div class="layui-input-block layuimini-upload">
<input name="logo_image" class="layui-input layui-col-xs6" lay-verify="required" placeholder="请上传LOGO图标" value="{:sysconfig('site','logo_image')}">
<div class="layuimini-upload-btn">
<span><a class="layui-btn" data-upload="logo_image" data-upload-number="one" data-upload-exts="ico|png|jpg|jpeg"><i class="fa fa-upload"></i> 上传</a></span>
<span><a class="layui-btn layui-btn-normal" id="select_logo_image" data-upload-select="logo_image" data-upload-number="one"><i class="fa fa-list"></i> 选择</a></span>
</div>
</div>
</div>
<div class="hr-line"></div>
<div class="layui-form-item text-center">
<button type="submit" class="layui-btn layui-btn-normal layui-btn-sm" lay-submit="system.config/save" data-refresh="false">确认</button>
<button type="reset" class="layui-btn layui-btn-primary layui-btn-sm">重置</button>
</div>
</form>

52
app/admin/view/system/config/site.html

@ -0,0 +1,52 @@
<form id="app-form" class="layui-form layuimini-form">
<div class="layui-form-item">
<label class="layui-form-label">站点名称</label>
<div class="layui-input-block">
<input type="text" name="site_name" class="layui-input" lay-verify="required" placeholder="请输入站点名称" value="{:sysconfig('site','site_name')}">
<tip>填写站点名称。</tip>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">浏览器图标</label>
<div class="layui-input-block layuimini-upload">
<input name="site_ico" class="layui-input layui-col-xs6" lay-verify="required" placeholder="请上传浏览器图标,ico类型" value="{:sysconfig('site','site_ico')}">
<div class="layuimini-upload-btn">
<span><a class="layui-btn" data-upload="site_ico" data-upload-number="one" data-upload-exts="ico"><i class="fa fa-upload"></i> 上传</a></span>
<span><a class="layui-btn layui-btn-normal" id="select_site_ico" data-upload-select="site_ico" data-upload-number="one"><i class="fa fa-list"></i> 选择</a></span>
</div>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">版本信息</label>
<div class="layui-input-block">
<input type="text" name="site_version" class="layui-input" lay-verify="required" placeholder="请输入版本信息" value="{:sysconfig('site','site_version')}">
<tip>填写版本信息。</tip>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">备案信息</label>
<div class="layui-input-block">
<input type="text" name="site_beian" class="layui-input" lay-verify="required" placeholder="请输入备案信息" value="{:sysconfig('site','site_beian')}">
<tip>填写备案信息。</tip>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">版权信息</label>
<div class="layui-input-block">
<input type="text" name="site_copyright" class="layui-input" lay-verify="required" placeholder="请输入版权信息" value="{:sysconfig('site','site_copyright')}">
<tip>填写版权信息。</tip>
</div>
</div>
<div class="hr-line"></div>
<div class="layui-form-item text-center">
<button type="submit" class="layui-btn layui-btn-normal layui-btn-sm" lay-submit="system.config/save" data-refresh="false">确认</button>
<button type="reset" class="layui-btn layui-btn-primary layui-btn-sm">重置</button>
</div>
</form>

141
app/admin/view/system/config/upload.html

@ -0,0 +1,141 @@
<form id="app-form" class="layui-form layuimini-form">
<div class="layui-form-item">
<label class="layui-form-label required">存储方式</label>
<div class="layui-input-block">
{foreach ['local'=>'本地存储','alioss'=>'阿里云oss','qnoss'=>'七牛云oss','txcos'=>'腾讯云cos'] as $key=>$val}
<input type="radio" v-model="upload_type" name="upload_type" lay-filter="upload_type" value="{$key}" title="{$val}" {if $key==sysconfig('upload','upload_type')}checked=""{/if}>
{/foreach}
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label required">允许类型</label>
<div class="layui-input-block">
<input type="text" name="upload_allow_ext" class="layui-input" lay-verify="required" lay-reqtext="请输入允许类型" placeholder="请输入允许类型" value="{:sysconfig('upload','upload_allow_ext')}">
<tip>英文逗号做分隔符。</tip>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label required">允许大小</label>
<div class="layui-input-block">
<input type="text" name="upload_allow_size" class="layui-input" lay-verify="required" lay-reqtext="请输入允许上传大小" placeholder="请输入允许上传大小" value="{:sysconfig('upload','upload_allow_size')}">
<tip>设置允许上传大小。</tip>
</div>
</div>
<div class="layui-form-item" v-if="upload_type == 'alioss'" v-cloak>
<label class="layui-form-label required">公钥信息</label>
<div class="layui-input-block">
<input type="text" name="alioss_access_key_id" class="layui-input" lay-verify="required" lay-reqtext="请输入公钥信息" placeholder="请输入公钥信息" value="{:sysconfig('upload','alioss_access_key_id')}">
<tip>例子:FSGGshu64642THSk</tip>
</div>
</div>
<div class="layui-form-item" v-if="upload_type == 'alioss'" v-cloak>
<label class="layui-form-label required">私钥信息</label>
<div class="layui-input-block">
<input type="text" name="alioss_access_key_secret" class="layui-input" lay-verify="required" lay-reqtext="请输入私钥信息" placeholder="请输入私钥信息" value="{:sysconfig('upload','alioss_access_key_secret')}">
<tip>例子:5fsfPReYKkFSGGshu64642THSkmTInaIm</tip>
</div>
</div>
<div class="layui-form-item" v-if="upload_type == 'alioss'" v-cloak>
<label class="layui-form-label required">数据中心</label>
<div class="layui-input-block">
<input type="text" name="alioss_endpoint" class="layui-input" lay-verify="required" lay-reqtext="请输入数据中心" placeholder="请输入数据中心" value="{:sysconfig('upload','alioss_endpoint')}">
<tip>例子:https://oss-cn-shenzhen.aliyuncs.com</tip>
</div>
</div>
<div class="layui-form-item" v-if="upload_type == 'alioss'" v-cloak>
<label class="layui-form-label required">空间名称</label>
<div class="layui-input-block">
<input type="text" name="alioss_bucket" class="layui-input" lay-verify="required" lay-reqtext="请输入空间名称" placeholder="请输入空间名称" value="{:sysconfig('upload','alioss_bucket')}">
<tip>例子:easy-admin</tip>
</div>
</div>
<div class="layui-form-item" v-if="upload_type == 'alioss'" v-cloak>
<label class="layui-form-label required">访问域名</label>
<div class="layui-input-block">
<input type="text" name="alioss_domain" class="layui-input" lay-verify="required" lay-reqtext="请输入访问域名" placeholder="请输入访问域名" value="{:sysconfig('upload','alioss_domain')}">
<tip>例子:easy-admin.oss-cn-shenzhen.aliyuncs.com</tip>
</div>
</div>
<div class="layui-form-item" v-if="upload_type == 'txcos'" v-cloak>
<label class="layui-form-label required">公钥信息</label>
<div class="layui-input-block">
<input type="text" name="txcos_secret_id" class="layui-input" lay-verify="required" lay-reqtext="请输入公钥信息" placeholder="请输入公钥信息" value="{:sysconfig('upload','txcos_secret_id')}">
<tip>例子:AKIDta6OQCbALQGrCI6ngKwQffR3dfsfrwrfs</tip>
</div>
</div>
<div class="layui-form-item" v-if="upload_type == 'txcos'" v-cloak>
<label class="layui-form-label required">私钥信息</label>
<div class="layui-input-block">
<input type="text" name="txcos_secret_key" class="layui-input" lay-verify="required" lay-reqtext="请输入私钥信息" placeholder="请输入私钥信息" value="{:sysconfig('upload','txcos_secret_key')}">
<tip>例子:VllEWYKtClAbpqfFdTqysXxGQM6dsfs</tip>
</div>
</div>
<div class="layui-form-item" v-if="upload_type == 'txcos'" v-cloak>
<label class="layui-form-label required">存储桶地域</label>
<div class="layui-input-block">
<input type="text" name="txcos_region" class="layui-input" lay-verify="required" lay-reqtext="请输入存储桶地域" placeholder="请输入存储桶地域" value="{:sysconfig('upload','txcos_region')}">
<tip>例子:ap-guangzhou</tip>
</div>
</div>
<div class="layui-form-item" v-if="upload_type == 'txcos'" v-cloak>
<label class="layui-form-label required">存储桶名称</label>
<div class="layui-input-block">
<input type="text" name="tecos_bucket" class="layui-input" lay-verify="required" lay-reqtext="请输入存储桶名称" placeholder="请输入存储桶名称" value="{:sysconfig('upload','tecos_bucket')}">
<tip>例子:easyadmin-1251997243</tip>
</div>
</div>
<div class="layui-form-item" v-if="upload_type == 'qnoss'" v-cloak>
<label class="layui-form-label required">公钥信息</label>
<div class="layui-input-block">
<input type="text" name="qnoss_access_key" class="layui-input" lay-verify="required" lay-reqtext="请输入公钥信息" placeholder="请输入公钥信息" value="{:sysconfig('upload','qnoss_access_key')}">
<tip>例子:v-lV3tXev7yyfsfa1jRc6_8rFOhFYGQvvjsAQxdrB</tip>
</div>
</div>
<div class="layui-form-item" v-if="upload_type == 'qnoss'" v-cloak>
<label class="layui-form-label required">私钥信息</label>
<div class="layui-input-block">
<input type="text" name="qnoss_secret_key" class="layui-input" lay-verify="required" lay-reqtext="请输入私钥信息" placeholder="请输入私钥信息" value="{:sysconfig('upload','qnoss_secret_key')}">
<tip>例子:XOhYRR9JNqxsWVEO-mHWB4193vfsfsQADuORaXzr</tip>
</div>
</div>
<div class="layui-form-item" v-if="upload_type == 'qnoss'" v-cloak>
<label class="layui-form-label required">存储空间</label>
<div class="layui-input-block">
<input type="text" name="qnoss_bucket" class="layui-input" lay-verify="required" lay-reqtext="请输入存储桶地域" placeholder="请输入存储桶地域" value="{:sysconfig('upload','qnoss_bucket')}">
<tip>例子:easyadmin</tip>
</div>
</div>
<div class="layui-form-item" v-if="upload_type == 'qnoss'" v-cloak>
<label class="layui-form-label required">访问域名</label>
<div class="layui-input-block">
<input type="text" name="qnoss_domain" class="layui-input" lay-verify="required" lay-reqtext="请输入访问域名" placeholder="请输入访问域名" value="{:sysconfig('upload','qnoss_domain')}">
<tip>例子:http://q0xqzappp.bkt.clouddn.com</tip>
</div>
</div>
<div class="hr-line"></div>
<div class="layui-form-item text-center">
<button type="submit" class="layui-btn layui-btn-normal layui-btn-sm" lay-submit="system.config/save" data-refresh="false">确认</button>
<button type="reset" class="layui-btn layui-btn-primary layui-btn-sm">重置</button>
</div>
</form>
<script>
var upload_type = "{:sysconfig('upload','upload_type')}";
</script>

7
app/admin/view/system/log/index.html

@ -0,0 +1,7 @@
<div class="layuimini-container">
<div class="layuimini-main">
<table id="currentTable" class="layui-table layui-hide"
lay-filter="currentTable">
</table>
</div>
</div>

75
app/admin/view/system/menu/add.html

@ -0,0 +1,75 @@
<style>
.layui-iconpicker-body.layui-iconpicker-body-page .hide {
display: none;
}
</style>
<link rel="stylesheet" href="__STATIC__/plugs/lay-module/autocomplete/autocomplete.css?v={$version}" media="all">
<div class="layuimini-container">
<form id="app-form" class="layui-form layuimini-form">
<div class="layui-form-item layui-row layui-col-xs12">
<label class="layui-form-label required">上级菜单</label>
<div class="layui-input-block">
<select name="pid">
{foreach $pidMenuList as $vo}
<option value="{$vo.id}" {if $id==$vo.id}selected=""{/if}>{$vo.title|raw}</option>
{/foreach}
</select>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label required">菜单名称</label>
<div class="layui-input-block">
<input type="text" name="title" class="layui-input" lay-verify="required" lay-reqtext="请输入菜单名称" placeholder="请输入菜单名称" value="">
<tip>填写菜单名称。</tip>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">菜单链接</label>
<div class="layui-input-block">
<input type="text" id="href" name="href" class="layui-input" lay-reqtext="请输入菜单链接" placeholder="请输入菜单链接" value="">
<tip>填写菜单链接。</tip>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">选择图标</label>
<div class="layui-input-block">
<input type="text" id="icon" name="icon" lay-filter="icon" class="hide" value="fa fa-list">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label required">target属性</label>
<div class="layui-input-block">
{foreach ['_self','_blank','_parent','_top'] as $vo}
<input type="radio" name="target" value="{$vo}" title="{$vo}" {if $vo=='_self'}checked=""{/if}>
{/foreach}
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">菜单排序</label>
<div class="layui-input-block">
<input type="number" name="sort" lay-reqtext="菜单排序不能为空" placeholder="请输入菜单排序" value="0" class="layui-input">
</div>
</div>
<div class="layui-form-item layui-form-text">
<label class="layui-form-label">备注信息</label>
<div class="layui-input-block">
<textarea name="remark" class="layui-textarea" placeholder="请输入备注信息"></textarea>
</div>
</div>
<div class="hr-line"></div>
<div class="layui-form-item text-center">
<button type="submit" class="layui-btn layui-btn-normal layui-btn-sm" lay-submit>确认</button>
<button type="reset" class="layui-btn layui-btn-primary layui-btn-sm">重置</button>
</div>
</form>
</div>

75
app/admin/view/system/menu/edit.html

@ -0,0 +1,75 @@
<style>
.layui-iconpicker-body.layui-iconpicker-body-page .hide {
display: none;
}
</style>
<link rel="stylesheet" href="__STATIC__/plugs/lay-module/autocomplete/autocomplete.css?v={:time()}" media="all">
<div class="layuimini-container">
<form id="app-form" class="layui-form layuimini-form">
<div class="layui-form-item layui-row layui-col-xs12">
<label class="layui-form-label required">上级菜单</label>
<div class="layui-input-block">
<select name="pid">
{foreach $pidMenuList as $vo}
<option value="{$vo.id}" {if $row.pid==$vo.id}selected=""{/if}>{$vo.title|raw}</option>
{/foreach}
</select>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label required">菜单名称</label>
<div class="layui-input-block">
<input type="text" name="title" class="layui-input" lay-verify="required" lay-reqtext="请输入菜单名称" placeholder="请输入菜单名称" value="{$row.title|default=''}">
<tip>填写菜单名称。</tip>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">菜单链接</label>
<div class="layui-input-block">
<input type="text" name="href" id="href" class="layui-input" lay-reqtext="请输入菜单链接" placeholder="请输入菜单链接" value="{$row.href|default=''}">
<tip>填写菜单链接。</tip>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">选择图标</label>
<div class="layui-input-block">
<input type="text" id="icon" name="icon" lay-filter="icon" class="hide" value="{$row.icon|default=''}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label required">target属性</label>
<div class="layui-input-block">
{foreach ['_self','_blank','_parent','_top'] as $vo}
<input type="radio" name="target" value="{$vo}" title="{$vo}" {if $row.target==$vo}checked=""{/if}>
{/foreach}
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">菜单排序</label>
<div class="layui-input-block">
<input type="number" name="sort" lay-reqtext="菜单排序不能为空" placeholder="请输入菜单排序" value="{$row.sort|default=''}" class="layui-input">
</div>
</div>
<div class="layui-form-item layui-form-text">
<label class="layui-form-label">备注信息</label>
<div class="layui-input-block">
<textarea name="remark" class="layui-textarea" placeholder="请输入备注信息">{$row.remark|default=''}</textarea>
</div>
</div>
<div class="hr-line"></div>
<div class="layui-form-item text-center">
<button type="submit" class="layui-btn layui-btn-normal layui-btn-sm" lay-submit>确认</button>
<button type="reset" class="layui-btn layui-btn-primary layui-btn-sm">重置</button>
</div>
</form>
</div>

23
app/admin/view/system/menu/index.html

@ -0,0 +1,23 @@
<link rel="stylesheet" href="__STATIC__/plugs/lay-module/treetable-lay/treetable.css?v={:time()}" media="all">
<style>
.layui-btn:not(.layui-btn-lg ):not(.layui-btn-sm):not(.layui-btn-xs) {
height: 34px;
line-height: 34px;
padding: 0 8px;
}
</style>
<div class="layuimini-container">
<div class="layuimini-main">
<table id="currentTable" class="layui-table layui-hide"
data-auth-add="{:auth('system.menu/add')}"
data-auth-edit="{:auth('system.menu/edit')}"
data-auth-delete="{:auth('system.menu/delete')}"
lay-filter="currentTable">
</table>
</div>
</div>
<script type="text/html" id="toolbar">
<button class="layui-btn layui-btn-sm layuimini-btn-primary" data-treetable-refresh><i class="fa fa-refresh"></i> </button>
<button class="layui-btn layui-btn-normal layui-btn-sm {if !auth('system.menu/add')}layui-hide{/if}" data-open="system.menu/add" data-title="添加" data-full="true"><i class="fa fa-plus"></i> 添加</button>
<button class="layui-btn layui-btn-sm layui-btn-danger {if !auth('system.menu/del')}layui-hide{/if}" data-url="system.menu/del" data-treetable-delete="currentTableRenderId"><i class="fa fa-trash-o"></i> 删除</button>
</script>

9
app/admin/view/system/node/index.html

@ -0,0 +1,9 @@
<div class="layuimini-container">
<div class="layuimini-main">
<table id="currentTable" class="layui-table layui-hide"
data-auth-refresh="{:auth('system.node/refreshNode')}"
data-auth-clear="{:auth('system.node/clearNode')}"
lay-filter="currentTable">
</table>
</div>
</div>

52
app/admin/view/system/quick/add.html

@ -0,0 +1,52 @@
<style>
.layui-iconpicker-body.layui-iconpicker-body-page .hide {
display: none;
}
</style>
<link rel="stylesheet" href="__STATIC__/plugs/lay-module/autocomplete/autocomplete.css?v={$version}" media="all">
<div class="layuimini-container">
<form id="app-form" class="layui-form layuimini-form">
<div class="layui-form-item">
<label class="layui-form-label">快捷名称</label>
<div class="layui-input-block">
<input type="text" name="title" class="layui-input" lay-verify="required" lay-reqtext="请输入快捷名称" placeholder="请输入快捷名称" value="">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">快捷链接</label>
<div class="layui-input-block">
<input type="text" id="href" name="href" class="layui-input" lay-verify="required" placeholder="请输入快捷链接" value="">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">选择图标</label>
<div class="layui-input-block">
<input type="text" id="icon" name="icon" lay-filter="icon" class="hide" value="fa fa-list">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">菜单排序</label>
<div class="layui-input-block">
<input type="number" name="sort" lay-reqtext="菜单排序不能为空" placeholder="请输入菜单排序" value="0" class="layui-input">
</div>
</div>
<div class="layui-form-item layui-form-text">
<label class="layui-form-label">备注信息</label>
<div class="layui-input-block">
<textarea name="remark" class="layui-textarea" placeholder="请输入备注信息"></textarea>
</div>
</div>
<div class="hr-line"></div>
<div class="layui-form-item text-center">
<button type="submit" class="layui-btn layui-btn-normal layui-btn-sm" lay-submit>确认</button>
<button type="reset" class="layui-btn layui-btn-primary layui-btn-sm">重置</button>
</div>
</form>
</div>

52
app/admin/view/system/quick/edit.html

@ -0,0 +1,52 @@
<style>
.layui-iconpicker-body.layui-iconpicker-body-page .hide {
display: none;
}
</style>
<link rel="stylesheet" href="__STATIC__/plugs/lay-module/autocomplete/autocomplete.css?v={$version}" media="all">
<div class="layuimini-container">
<form id="app-form" class="layui-form layuimini-form">
<div class="layui-form-item">
<label class="layui-form-label">快捷名称</label>
<div class="layui-input-block">
<input type="text" name="title" class="layui-input" lay-verify="required" lay-reqtext="请输入快捷名称" placeholder="请输入快捷名称" value="{$row.title|default=''}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">快捷链接</label>
<div class="layui-input-block">
<input type="text" id="href" name="href" class="layui-input" lay-verify="required" placeholder="请输入快捷链接" value="{$row.href|default=''}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">选择图标</label>
<div class="layui-input-block">
<input type="text" id="icon" name="icon" lay-filter="icon" class="hide" value="{$row.icon|default=''}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">菜单排序</label>
<div class="layui-input-block">
<input type="number" name="sort" lay-reqtext="菜单排序不能为空" placeholder="请输入菜单排序" value="{$row.sort|default=''}" class="layui-input">
</div>
</div>
<div class="layui-form-item layui-form-text">
<label class="layui-form-label">备注信息</label>
<div class="layui-input-block">
<textarea name="remark" class="layui-textarea" placeholder="请输入备注信息">{$row.remark|default=''}</textarea>
</div>
</div>
<div class="hr-line"></div>
<div class="layui-form-item text-center">
<button type="submit" class="layui-btn layui-btn-normal layui-btn-sm" lay-submit>确认</button>
<button type="reset" class="layui-btn layui-btn-primary layui-btn-sm">重置</button>
</div>
</form>
</div>

10
app/admin/view/system/quick/index.html

@ -0,0 +1,10 @@
<div class="layuimini-container">
<div class="layuimini-main">
<table id="currentTable" class="layui-table layui-hide"
data-auth-add="{:auth('system.quick/add')}"
data-auth-edit="{:auth('system.quick/edit')}"
data-auth-delete="{:auth('system.quick/delete')}"
lay-filter="currentTable">
</table>
</div>
</div>

16
app/admin/view/system/uploadfile/add.html

@ -0,0 +1,16 @@
<div class="layuimini-container">
<form id="app-form" class="layui-form layuimini-form">
<div class="layui-form-item">
<label class="layui-form-label required">文件信息</label>
<div class="layui-input-block layuimini-upload">
<input name="head_img" class="layui-input layui-col-xs6" lay-verify="required" lay-reqtext="请上传文件" placeholder="请上传文件" value="">
<div class="layuimini-upload-btn">
<span><a class="layui-btn" data-upload="head_img" data-upload-number="one" data-upload-exts="png|jpg|ico|jpeg"><i class="fa fa-upload"></i> 上传文件</a></span>
<span><a class="layui-btn layui-btn-normal"><i class="fa fa-list"></i> 选择文件</a></span>
</div>
</div>
</div>
</form>
</div>

54
app/admin/view/system/uploadfile/edit.html

@ -0,0 +1,54 @@
<div class="layuimini-container">
<form id="app-form" class="layui-form layuimini-form">
<div class="layui-form-item">
<label class="layui-form-label required">用户头像</label>
<div class="layui-input-block layuimini-upload">
<input name="head_img" class="layui-input layui-col-xs6" lay-verify="required" lay-reqtext="请上传用户头像" placeholder="请上传用户头像" value="{$row.head_img|default=''}">
<div class="layuimini-upload-btn">
<span><a class="layui-btn" data-upload="head_img" data-upload-number="one" data-upload-exts="png|jpg|ico|jpeg"><i class="fa fa-upload"></i> 上传文件</a></span>
<span><a class="layui-btn layui-btn-normal"><i class="fa fa-list"></i> 选择文件</a></span>
</div>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label required">登录账户</label>
<div class="layui-input-block">
<input type="text" name="username" class="layui-input" readonly value="{$row.username|default=''}">
<tip>填写登录账户。</tip>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">用户手机</label>
<div class="layui-input-block">
<input type="text" name="phone" class="layui-input" lay-reqtext="请输入用户手机" placeholder="请输入用户手机" value="{$row.username|default=''}">
<tip>填写用户手机。</tip>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">角色权限</label>
<div class="layui-input-block">
{foreach auth_list as $key=>$val}
<input type="checkbox" name="auth_ids[{$key}]" lay-skin="primary" title="{$val}" {if in_array($key,$row.auth_ids)}checked="" {/if}>
{/foreach}
</div>
</div>
<div class="layui-form-item layui-form-text">
<label class="layui-form-label">备注信息</label>
<div class="layui-input-block">
<textarea name="remark" class="layui-textarea" placeholder="请输入备注信息">{$row.username|default=''}</textarea>
</div>
</div>
<div class="hr-line"></div>
<div class="layui-form-item text-center">
<button type="submit" class="layui-btn layui-btn-normal layui-btn-sm" lay-submit>确认</button>
<button type="reset" class="layui-btn layui-btn-primary layui-btn-sm">重置</button>
</div>
</form>
</div>

10
app/admin/view/system/uploadfile/index.html

@ -0,0 +1,10 @@
<div class="layuimini-container">
<div class="layuimini-main">
<table id="currentTable" class="layui-table layui-hide"
data-auth-add="{:auth('system.menu/add')}"
data-auth-edit="{:auth('system.menu/edit')}"
data-auth-delete="{:auth('system.menu/delete')}"
lay-filter="currentTable">
</table>
</div>
</div>

0
app/api/config.php

13
app/api/controller/Index.php

@ -0,0 +1,13 @@
<?php
namespace app\api\controller;
use app\BaseController;
class Index extends BaseController{
//
public function index(){
$arr=["ver"=>"00","date"=>time()];
$ss= json_encode($arr);
return $ss;
}
}

3
app/api/event.php

@ -0,0 +1,3 @@
<?php
return [];
?>

124
app/common.php

@ -0,0 +1,124 @@
<?php
// 应用公共文件
use app\common\service\AuthService;
use think\facade\Cache;
if (!function_exists('__url')) {
/**
* 构建URL地址
* @param string $url
* @param array $vars
* @param bool $suffix
* @param bool $domain
* @return string
*/
function __url(string $url = '', array $vars = [], $suffix = true, $domain = false)
{
return url($url, $vars, $suffix, $domain)->build();
}
}
if (!function_exists('password')) {
/**
* 密码加密算法
* @param $value 需要加密的值
* @param $type 加密类型,默认为md5 (md5, hash)
* @return mixed
*/
function password($value)
{
$value = sha1('blog_') . md5($value) . md5('_encrypt') . sha1($value);
return sha1($value);
}
}
if (!function_exists('xdebug')) {
/**
* debug调试
* @deprecated 不建议使用,建议直接使用框架自带的log组件
* @param string|array $data 打印信息
* @param string $type 类型
* @param string $suffix 文件后缀名
* @param bool $force
* @param null $file
*/
function xdebug($data, $type = 'xdebug', $suffix = null, $force = false, $file = null)
{
!is_dir(runtime_path() . 'xdebug/') && mkdir(runtime_path() . 'xdebug/');
if (is_null($file)) {
$file = is_null($suffix) ? runtime_path() . 'xdebug/' . date('Ymd') . '.txt' : runtime_path() . 'xdebug/' . date('Ymd') . "_{$suffix}" . '.txt';
}
file_put_contents($file, "[" . date('Y-m-d H:i:s') . "] " . "========================= {$type} ===========================" . PHP_EOL, FILE_APPEND);
$str = (is_string($data) ? $data : (is_array($data) || is_object($data)) ? print_r($data, true) : var_export($data, true)) . PHP_EOL;
$force ? file_put_contents($file, $str) : file_put_contents($file, $str, FILE_APPEND);
}
}
if (!function_exists('sysconfig')) {
/**
* 获取系统配置信息
* @param $group
* @param null $name
* @return array|mixed
*/
function sysconfig($group, $name = null)
{
$where = ['group' => $group];
$value = empty($name) ? Cache::get("sysconfig_{$group}") : Cache::get("sysconfig_{$group}_{$name}");
if (empty($value)) {
if (!empty($name)) {
$where['name'] = $name;
$value = \app\admin\model\SystemConfig::where($where)->value('value');
Cache::tag('sysconfig')->set("sysconfig_{$group}_{$name}", $value, 3600);
} else {
$value = \app\admin\model\SystemConfig::where($where)->column('value', 'name');
Cache::tag('sysconfig')->set("sysconfig_{$group}", $value, 3600);
}
}
return $value;
}
}
if (!function_exists('array_format_key')) {
/**
* 二位数组重新组合数据
* @param $array
* @param $key
* @return array
*/
function array_format_key($array, $key)
{
$newArray = [];
foreach ($array as $vo) {
$newArray[$vo[$key]] = $vo;
}
return $newArray;
}
}
if (!function_exists('auth')) {
/**
* auth权限验证
* @param $node
* @return bool
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
function auth($node = null)
{
$authService = new AuthService(session('admin.id'));
$check = $authService->checkNode($node);
return $check;
}
}

174
app/common/command/Curd.php

@ -0,0 +1,174 @@
<?php
// +----------------------------------------------------------------------
// | EasyAdmin
// +----------------------------------------------------------------------
// | PHP交流群: 763822524
// +----------------------------------------------------------------------
// | 开源协议 https://mit-license.org
// +----------------------------------------------------------------------
// | github开源项目:https://github.com/zhongshaofa/EasyAdmin
// +----------------------------------------------------------------------
namespace app\common\command;
use app\admin\model\SystemNode;
use EasyAdmin\console\CliEcho;
use EasyAdmin\curd\BuildCurd;
use think\console\Command;
use think\console\Input;
use think\console\input\Option;
use think\console\Output;
use EasyAdmin\auth\Node as NodeService;
use think\Exception;
class Curd extends Command
{
protected function configure()
{
$this->setName('curd')
->addOption('table', 't', Option::VALUE_REQUIRED, '主表名', null)
->addOption('controllerFilename', 'c', Option::VALUE_REQUIRED, '控制器文件名', null)
->addOption('modelFilename', 'm', Option::VALUE_REQUIRED, '主表模型文件名', null)
#
->addOption('checkboxFieldSuffix', null, Option::VALUE_REQUIRED | Option::VALUE_IS_ARRAY, '复选框字段后缀', null)
->addOption('radioFieldSuffix', null, Option::VALUE_REQUIRED | Option::VALUE_IS_ARRAY, '单选框字段后缀', null)
->addOption('imageFieldSuffix', null, Option::VALUE_REQUIRED | Option::VALUE_IS_ARRAY, '单图片字段后缀', null)
->addOption('imagesFieldSuffix', null, Option::VALUE_REQUIRED | Option::VALUE_IS_ARRAY, '多图片字段后缀', null)
->addOption('fileFieldSuffix', null, Option::VALUE_REQUIRED | Option::VALUE_IS_ARRAY, '单文件字段后缀', null)
->addOption('filesFieldSuffix', null, Option::VALUE_REQUIRED | Option::VALUE_IS_ARRAY, '多文件字段后缀', null)
->addOption('dateFieldSuffix', null, Option::VALUE_REQUIRED | Option::VALUE_IS_ARRAY, '时间字段后缀', null)
->addOption('switchFields', null, Option::VALUE_REQUIRED | Option::VALUE_IS_ARRAY, '开关的字段', null)
->addOption('selectFileds', null, Option::VALUE_REQUIRED | Option::VALUE_IS_ARRAY, '下拉的字段', null)
->addOption('editorFields', null, Option::VALUE_REQUIRED | Option::VALUE_IS_ARRAY, '富文本的字段', null)
->addOption('sortFields', null, Option::VALUE_REQUIRED | Option::VALUE_IS_ARRAY, '排序的字段', null)
->addOption('ignoreFields', null, Option::VALUE_REQUIRED | Option::VALUE_IS_ARRAY, '忽略的字段', null)
#
->addOption('relationTable', 'r', Option::VALUE_REQUIRED | Option::VALUE_IS_ARRAY, '关联表名', null)
->addOption('foreignKey', null, Option::VALUE_REQUIRED | Option::VALUE_IS_ARRAY, '关联外键', null)
->addOption('primaryKey', null, Option::VALUE_REQUIRED | Option::VALUE_IS_ARRAY, '关联主键', null)
->addOption('relationModelFilename', null, Option::VALUE_REQUIRED | Option::VALUE_IS_ARRAY, '关联模型文件名', null)
->addOption('relationOnlyFileds', null, Option::VALUE_REQUIRED | Option::VALUE_IS_ARRAY, '关联模型中只显示的字段', null)
->addOption('relationBindSelect', null, Option::VALUE_REQUIRED | Option::VALUE_IS_ARRAY, '关联模型中的字段用于主表外键的表单下拉选择', null)
#
->addOption('force', 'f', Option::VALUE_REQUIRED, '强制覆盖模式', 0)
->addOption('delete', 'd', Option::VALUE_REQUIRED, '删除模式', 0)
->setDescription('一键curd命令服务');
}
protected function execute(Input $input, Output $output)
{
$table = $input->getOption('table');
$controllerFilename = $input->getOption('controllerFilename');
$modelFilename = $input->getOption('modelFilename');
$checkboxFieldSuffix = $input->getOption('checkboxFieldSuffix');
$radioFieldSuffix = $input->getOption('radioFieldSuffix');
$imageFieldSuffix = $input->getOption('imageFieldSuffix');
$imagesFieldSuffix = $input->getOption('imagesFieldSuffix');
$fileFieldSuffix = $input->getOption('fileFieldSuffix');
$filesFieldSuffix = $input->getOption('filesFieldSuffix');
$dateFieldSuffix = $input->getOption('dateFieldSuffix');
$switchFields = $input->getOption('switchFields');
$selectFileds = $input->getOption('selectFileds');
$sortFields = $input->getOption('sortFields');
$ignoreFields = $input->getOption('ignoreFields');
$relationTable = $input->getOption('relationTable');
$foreignKey = $input->getOption('foreignKey');
$primaryKey = $input->getOption('primaryKey');
$relationModelFilename = $input->getOption('relationModelFilename');
$relationOnlyFileds = $input->getOption('relationOnlyFileds');
$relationBindSelect = $input->getOption('relationBindSelect');
$force = $input->getOption('force');
$delete = $input->getOption('delete');
$relations = [];
foreach ($relationTable as $key => $val) {
$relations[] = [
'table' => $relationTable[$key],
'foreignKey' => isset($foreignKey[$key]) ? $foreignKey[$key] : null,
'primaryKey' => isset($primaryKey[$key]) ? $primaryKey[$key] : null,
'modelFilename' => isset($relationModelFilename[$key]) ? $relationModelFilename[$key] : null,
'onlyFileds' => isset($relationOnlyFileds[$key]) ? explode(",", $relationOnlyFileds[$key]) : [],
'relationBindSelect' => isset($relationBindSelect[$key]) ? $relationBindSelect[$key] : null,
];
}
if (empty($table)) {
CliEcho::error('请设置主表');
return false;
}
try {
$build = (new BuildCurd())
->setTable($table)
->setForce($force);
!empty($controllerFilename) && $build = $build->setControllerFilename($controllerFilename);
!empty($modelFilename) && $build = $build->setModelFilename($modelFilename);
!empty($checkboxFieldSuffix) && $build = $build->setCheckboxFieldSuffix($checkboxFieldSuffix);
!empty($radioFieldSuffix) && $build = $build->setRadioFieldSuffix($radioFieldSuffix);
!empty($imageFieldSuffix) && $build = $build->setImageFieldSuffix($imageFieldSuffix);
!empty($imagesFieldSuffix) && $build = $build->setImagesFieldSuffix($imagesFieldSuffix);
!empty($fileFieldSuffix) && $build = $build->setFileFieldSuffix($fileFieldSuffix);
!empty($filesFieldSuffix) && $build = $build->setFilesFieldSuffix($filesFieldSuffix);
!empty($dateFieldSuffix) && $build = $build->setDateFieldSuffix($dateFieldSuffix);
!empty($switchFields) && $build = $build->setSwitchFields($switchFields);
!empty($selectFileds) && $build = $build->setSelectFileds($selectFileds);
!empty($sortFields) && $build = $build->setSortFields($sortFields);
!empty($ignoreFields) && $build = $build->setIgnoreFields($ignoreFields);
foreach ($relations as $relation) {
$build = $build->setRelation($relation['table'], $relation['foreignKey'], $relation['primaryKey'], $relation['modelFilename'], $relation['onlyFileds'],$relation['relationBindSelect']);
}
$build = $build->render();
$fileList = $build->getFileList();
if (!$delete) {
$result = $build->create();
if($force){
$output->info(">>>>>>>>>>>>>>>");
foreach ($fileList as $key => $val) {
$output->info($key);
}
$output->info(">>>>>>>>>>>>>>>");
$output->info("确定强制生成上方所有文件? 如果文件存在会直接覆盖。 请输入 'yes' 按回车键继续操作: ");
$line = fgets(defined('STDIN') ? STDIN : fopen('php://stdin', 'r'));
if (trim($line) != 'yes') {
throw new Exception("取消文件CURD生成操作");
}
}
CliEcho::success('自动生成CURD成功');
} else {
$output->info(">>>>>>>>>>>>>>>");
foreach ($fileList as $key => $val) {
$output->info($key);
}
$output->info(">>>>>>>>>>>>>>>");
$output->info("确定删除上方所有文件? 请输入 'yes' 按回车键继续操作: ");
$line = fgets(defined('STDIN') ? STDIN : fopen('php://stdin', 'r'));
if (trim($line) != 'yes') {
throw new Exception("取消删除文件操作");
}
$result = $build->delete();
CliEcho::success('>>>>>>>>>>>>>>>');
CliEcho::success('删除自动生成CURD文件成功');
}
CliEcho::success('>>>>>>>>>>>>>>>');
foreach ($result as $vo) {
CliEcho::success($vo);
}
} catch (\Exception $e) {
CliEcho::error($e->getMessage());
return false;
}
}
}

75
app/common/command/Node.php

@ -0,0 +1,75 @@
<?php
// +----------------------------------------------------------------------
// | EasyAdmin
// +----------------------------------------------------------------------
// | PHP交流群: 763822524
// +----------------------------------------------------------------------
// | 开源协议 https://mit-license.org
// +----------------------------------------------------------------------
// | github开源项目:https://github.com/zhongshaofa/EasyAdmin
// +----------------------------------------------------------------------
namespace app\common\command;
use app\admin\model\SystemNode;
use think\console\Command;
use think\console\Input;
use think\console\input\Option;
use think\console\Output;
use app\admin\service\NodeService;
class Node extends Command
{
protected function configure()
{
$this->setName('node')
->addOption('force', null, Option::VALUE_REQUIRED, '是否强制刷新', 0)
->setDescription('系统节点刷新服务');
}
protected function execute(Input $input, Output $output)
{
$force = $input->getOption('force');
$output->writeln("========正在刷新节点服务:=====" . date('Y-m-d H:i:s'));
$check = $this->refresh($force);
$check !== true && $output->writeln("节点刷新失败:" . $check);
$output->writeln("刷新完成:" . date('Y-m-d H:i:s'));
}
protected function refresh($force)
{
$nodeList = (new NodeService())->getNodelist();
if (empty($nodeList)) {
return true;
}
$model = new SystemNode();
try {
if ($force == 1) {
$updateNodeList = $model->whereIn('node', array_column($nodeList, 'node'))->select();
$formatNodeList = array_format_key($nodeList, 'node');
foreach ($updateNodeList as $vo) {
isset($formatNodeList[$vo['node']]) && $model->where('id', $vo['id'])->update([
'title' => $formatNodeList[$vo['node']]['title'],
'is_auth' => $formatNodeList[$vo['node']]['is_auth'],
]);
}
}
$existNodeList = $model->field('node,title,type,is_auth')->select();
foreach ($nodeList as $key => $vo) {
foreach ($existNodeList as $v) {
if ($vo['node'] == $v->node) {
unset($nodeList[$key]);
break;
}
}
}
$model->insertAll($nodeList);
} catch (\Exception $e) {
return $e->getMessage();
}
return true;
}
}

58
app/common/command/OssStatic.php

@ -0,0 +1,58 @@
<?php
// +----------------------------------------------------------------------
// | EasyAdmin
// +----------------------------------------------------------------------
// | PHP交流群: 763822524
// +----------------------------------------------------------------------
// | 开源协议 https://mit-license.org
// +----------------------------------------------------------------------
// | github开源项目:https://github.com/zhongshaofa/EasyAdmin
// +----------------------------------------------------------------------
namespace app\common\command;
use EasyAdmin\console\CliEcho;
use EasyAdmin\tool\CommonTool;
use EasyAdmin\upload\driver\alioss\Oss;
use think\console\Command;
use think\console\Input;
use think\console\input\Option;
use think\console\Output;
class OssStatic extends Command
{
protected function configure()
{
$this->setName('OssStatic')
->setDescription('将静态资源上传到oss上');
}
protected function execute(Input $input, Output $output)
{
$output->writeln("========正在上传静态资源到OSS上:========" . date('Y-m-d H:i:s'));
$dir = root_path() . 'public' . DIRECTORY_SEPARATOR . 'static';
$list = CommonTool::readDirAllFiles($dir);
$uploadConfig = sysconfig('upload');
$uploadPrefix = config('app.oss_static_prefix', 'oss_static_prefix');
foreach ($list as $key => $val) {
list($objectName, $filePath) = [$uploadPrefix . DIRECTORY_SEPARATOR . $key, $val];
try {
$upload = Oss::instance($uploadConfig)
->save($objectName, $filePath);
} catch (\Exception $e) {
CliEcho::error('文件上传失败:' . $filePath . '。错误信息:' . $e->getMessage());
continue;
}
if ($upload['save'] == true) {
CliEcho::success('文件上传成功:' . $filePath . '。上传地址:' . $upload['url']);
} else {
CliEcho::error('文件上传失败:' . $filePath . '。错误信息:' . $upload['msg']);
}
}
$output->writeln("========已完成静态资源上传到OSS上:========" . date('Y-m-d H:i:s'));
}
}

28
app/common/constants/AdminConstant.php

@ -0,0 +1,28 @@
<?php
// +----------------------------------------------------------------------
// | EasyAdmin
// +----------------------------------------------------------------------
// | PHP交流群: 763822524
// +----------------------------------------------------------------------
// | 开源协议 https://mit-license.org
// +----------------------------------------------------------------------
// | github开源项目:https://github.com/zhongshaofa/EasyAdmin
// +----------------------------------------------------------------------
namespace app\common\constants;
/**
* 管理员常量
* Class AdminConstant
* @package app\common\constants
*/
class AdminConstant
{
/**
* 超级管理员,不受权限控制
*/
const SUPER_ADMIN_ID = 1;
}

33
app/common/constants/MenuConstant.php

@ -0,0 +1,33 @@
<?php
// +----------------------------------------------------------------------
// | EasyAdmin
// +----------------------------------------------------------------------
// | PHP交流群: 763822524
// +----------------------------------------------------------------------
// | 开源协议 https://mit-license.org
// +----------------------------------------------------------------------
// | github开源项目:https://github.com/zhongshaofa/EasyAdmin
// +----------------------------------------------------------------------
namespace app\common\constants;
/**
* 菜单常量
* Class MenuConstant
* @package app\common\constants
*/
class MenuConstant
{
/**
* 首页的PID
*/
const HOME_PID = 99999999;
/**
* 模块名前缀
*/
const MODULE_PREFIX = 'easyadmin_';
}

293
app/common/controller/AdminController.php

@ -0,0 +1,293 @@
<?php
// +----------------------------------------------------------------------
// | EasyAdmin
// +----------------------------------------------------------------------
// | PHP交流群: 763822524
// +----------------------------------------------------------------------
// | 开源协议 https://mit-license.org
// +----------------------------------------------------------------------
// | github开源项目:https://github.com/zhongshaofa/EasyAdmin
// +----------------------------------------------------------------------
namespace app\common\controller;
use app\admin\service\ConfigService;
use app\BaseController;
use app\common\constants\AdminConstant;
use app\common\service\AuthService;
use EasyAdmin\tool\CommonTool;
use think\facade\Env;
use think\facade\View;
use think\Model;
/**
* Class AdminController
* @package app\common\controller
*/
class AdminController extends BaseController
{
use \app\common\traits\JumpTrait;
/**
* 当前模型
* @Model
* @var object
*/
protected $model;
/**
* 字段排序
* @var array
*/
protected $sort = [
'id' => 'desc',
];
/**
* 允许修改的字段
* @var array
*/
protected $allowModifyFields = [
'status',
'sort',
'remark',
'is_delete',
'is_auth',
'title',
];
/**
* 不导出的字段信息
* @var array
*/
protected $noExportFields = ['delete_time', 'update_time'];
/**
* 下拉选择条件
* @var array
*/
protected $selectWhere = [];
/**
* 是否关联查询
* @var bool
*/
protected $relationSearch = false;
/**
* 模板布局, false取消
* @var string|bool
*/
protected $layout = 'layout/default';
/**
* 是否为演示环境
* @var bool
*/
protected $isDemo = false;
/**
* 初始化方法
*/
protected function initialize()
{
parent::initialize();
$this->layout && $this->app->view->engine()->layout($this->layout);
$this->isDemo = Env::get('easyadmin.is_demo', false);
$this->viewInit();
$this->checkAuth();
}
/**
* 模板变量赋值
* @param string|array $name 模板变量
* @param mixed $value 变量值
* @return mixed
*/
public function assign($name, $value = null)
{
return $this->app->view->assign($name, $value);
}
/**
* 解析和获取模板内容 用于输出
* @param string $template
* @param array $vars
* @return mixed
*/
public function fetch($template = '', $vars = [])
{
return $this->app->view->fetch($template, $vars);
}
/**
* 重写验证规则
* @param array $data
* @param array|string $validate
* @param array $message
* @param bool $batch
* @return array|bool|string|true
*/
public function validate(array $data, $validate, array $message = [], bool $batch = false)
{
try {
parent::validate($data, $validate, $message, $batch);
} catch (\Exception $e) {
$this->error($e->getMessage());
}
return true;
}
/**
* 构建请求参数
* @param array $excludeFields 忽略构建搜索的字段
* @return array
*/
protected function buildTableParames($excludeFields = [])
{
$get = $this->request->get('', null, null);
$page = isset($get['page']) && !empty($get['page']) ? $get['page'] : 1;
$limit = isset($get['limit']) && !empty($get['limit']) ? $get['limit'] : 15;
$filters = isset($get['filter']) && !empty($get['filter']) ? $get['filter'] : '{}';
$ops = isset($get['op']) && !empty($get['op']) ? $get['op'] : '{}';
// json转数组
$filters = json_decode($filters, true);
$ops = json_decode($ops, true);
$where = [];
$excludes = [];
// 判断是否关联查询
$tableName = CommonTool::humpToLine(lcfirst($this->model->getName()));
foreach ($filters as $key => $val) {
if (in_array($key, $excludeFields)) {
$excludes[$key] = $val;
continue;
}
$op = isset($ops[$key]) && !empty($ops[$key]) ? $ops[$key] : '%*%';
if ($this->relationSearch && count(explode('.', $key)) == 1) {
$key = "{$tableName}.{$key}";
}
switch (strtolower($op)) {
case '=':
$where[] = [$key, '=', $val];
break;
case '%*%':
$where[] = [$key, 'LIKE', "%{$val}%"];
break;
case '*%':
$where[] = [$key, 'LIKE', "{$val}%"];
break;
case '%*':
$where[] = [$key, 'LIKE', "%{$val}"];
break;
case 'range':
[$beginTime, $endTime] = explode(' - ', $val);
$where[] = [$key, '>=', strtotime($beginTime)];
$where[] = [$key, '<=', strtotime($endTime)];
break;
default:
$where[] = [$key, $op, "%{$val}"];
}
}
return [$page, $limit, $where, $excludes];
}
/**
* 下拉选择列表
* @return \think\response\Json
*/
public function selectList()
{
$fields = input('selectFields');
$data = $this->model
->where($this->selectWhere)
->field($fields)
->select();
$this->success(null, $data);
}
/**
* 初始化视图参数
*/
private function viewInit(){
$request = app()->request;
list($thisModule, $thisController, $thisAction) = [app('http')->getName(), app()->request->controller(), $request->action()];
list($thisControllerArr, $jsPath) = [explode('.', $thisController), null];
foreach ($thisControllerArr as $vo) {
empty($jsPath) ? $jsPath = parse_name($vo) : $jsPath .= '/' . parse_name($vo);
}
$autoloadJs = file_exists(root_path('public') . "static/{$thisModule}/js/{$jsPath}.js") ? true : false;
$thisControllerJsPath = "{$thisModule}/js/{$jsPath}.js";
$adminModuleName = config('app.admin_alias_name');
$isSuperAdmin = session('admin.id') == AdminConstant::SUPER_ADMIN_ID ? true : false;
$data = [
'adminModuleName' => $adminModuleName,
'thisController' => parse_name($thisController),
'thisAction' => $thisAction,
'thisRequest' => parse_name("{$thisModule}/{$thisController}/{$thisAction}"),
'thisControllerJsPath' => "{$thisControllerJsPath}",
'autoloadJs' => $autoloadJs,
'isSuperAdmin' => $isSuperAdmin,
'version' => env('app_debug') ? time() : ConfigService::getVersion(),
];
View::assign($data);
}
/**
* 检测权限
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function checkAuth(){
$adminConfig = config('admin');
$adminId = session('admin.id');
$expireTime = session('admin.expire_time');
/** @var AuthService $authService */
$authService = app(AuthService::class, ['adminId' => $adminId]);
$currentNode = $authService->getCurrentNode();
$currentController = parse_name(app()->request->controller());
// 验证登录
if (!in_array($currentController, $adminConfig['no_login_controller']) &&
!in_array($currentNode, $adminConfig['no_login_node'])) {
empty($adminId) && $this->error('请先登录后台', [], __url('admin/login/index'));
// 判断是否登录过期
if ($expireTime !== true && time() > $expireTime) {
session('admin', null);
$this->error('登录已过期,请重新登录', [], __url('admin/login/index'));
}
}
// 验证权限
if (!in_array($currentController, $adminConfig['no_auth_controller']) &&
!in_array($currentNode, $adminConfig['no_auth_node'])) {
$check = $authService->checkNode($currentNode);
!$check && $this->error('无权限访问');
// 判断是否为演示环境
if(env('easyadmin.is_demo', false) && app()->request->isPost()){
$this->error('演示环境下不允许修改');
}
}
}
/**
* 严格校验接口是否为POST请求
*/
protected function checkPostRequest(){
if (!$this->request->isPost()) {
$this->error("当前请求不合法!");
}
}
}

52
app/common/model/TimeModel.php

@ -0,0 +1,52 @@
<?php
// +----------------------------------------------------------------------
// | EasyAdmin
// +----------------------------------------------------------------------
// | PHP交流群: 763822524
// +----------------------------------------------------------------------
// | 开源协议 https://mit-license.org
// +----------------------------------------------------------------------
// | github开源项目:https://github.com/zhongshaofa/EasyAdmin
// +----------------------------------------------------------------------
namespace app\common\model;
use think\Model;
use think\model\concern\SoftDelete;
/**
* 有关时间的模型
* Class TimeModel
* @package app\common\model
*/
class TimeModel extends Model
{
/**
* 自动时间戳类型
* @var string
*/
protected $autoWriteTimestamp = true;
/**
* 添加时间
* @var string
*/
protected $createTime = 'create_time';
/**
* 更新时间
* @var string
*/
protected $updateTime = 'update_time';
/**
* 软删除
*/
use SoftDelete;
protected $deleteTime = false;
}

215
app/common/service/AuthService.php

@ -0,0 +1,215 @@
<?php
// +----------------------------------------------------------------------
// | EasyAdmin
// +----------------------------------------------------------------------
// | PHP交流群: 763822524
// +----------------------------------------------------------------------
// | 开源协议 https://mit-license.org
// +----------------------------------------------------------------------
// | github开源项目:https://github.com/zhongshaofa/EasyAdmin
// +----------------------------------------------------------------------
namespace app\common\service;
use app\common\constants\AdminConstant;
use EasyAdmin\tool\CommonTool;
use think\facade\Db;
/**
* 权限验证服务
* Class AuthService
* @package app\common\service
*/
class AuthService
{
/**
* 用户ID
* @var null
*/
protected $adminId = null;
/**
* 默认配置
* @var array
*/
protected $config = [
'auth_on' => true, // 权限开关
'system_admin' => 'system_admin', // 用户表
'system_auth' => 'system_auth', // 权限表
'system_node' => 'system_node', // 节点表
'system_auth_node' => 'system_auth_node',// 权限-节点表
];
/**
* 管理员信息
* @var array|\think\Model|null
*/
protected $adminInfo;
/**
* 所有节点信息
* @var array
*/
protected $nodeList;
/**
* 管理员所有授权节点
* @var array
*/
protected $adminNode;
/***
* 构造方法
* AuthService constructor.
* @param null $adminId
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function __construct($adminId = null)
{
$this->adminId = $adminId;
$this->adminInfo = $this->getAdminInfo();
$this->nodeList = $this->getNodeList();
$this->adminNode = $this->getAdminNode();
return $this;
}
/**
* 检测检测权限
* @param null $node
* @return bool
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function checkNode($node = null)
{
// 判断是否为超级管理员
if ($this->adminId == AdminConstant::SUPER_ADMIN_ID) {
return true;
}
// 判断权限验证开关
if ($this->config['auth_on'] == false) {
return true;
}
// 判断是否需要获取当前节点
if (empty($node)) {
$node = $this->getCurrentNode();
} else {
$node = $this->parseNodeStr($node);
}
// 判断是否加入节点控制,优先获取缓存信息
if (!isset($this->nodeList[$node])) {
return false;
}
$nodeInfo = $this->nodeList[$node];
if ($nodeInfo['is_auth'] == 0) {
return true;
}
// 用户验证,优先获取缓存信息
if (empty($this->adminInfo) || $this->adminInfo['status'] != 1 || empty($this->adminInfo['auth_ids'])) {
return false;
}
// 判断该节点是否允许访问
if (in_array($node, $this->adminNode)) {
return true;
}
return false;
}
/**
* 获取当前节点
* @return string
*/
public function getCurrentNode()
{
$node = $this->parseNodeStr(request()->controller() . '/' . request()->action());
return $node;
}
/**
* 获取当前管理员所有节点
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getAdminNode()
{
$nodeList = [];
$adminInfo = Db::name($this->config['system_admin'])
->where([
'id' => $this->adminId,
'status' => 1,
])->find();
if (!empty($adminInfo) && !empty($adminInfo['auth_ids'])) {
$buildAuthSql = Db::name($this->config['system_auth'])
->distinct(true)
->whereIn('id', $adminInfo['auth_ids'])
->field('id')
->buildSql(true);
$buildAuthNodeSql = Db::name($this->config['system_auth_node'])
->distinct(true)
->where("auth_id IN {$buildAuthSql}")
->field('node_id')
->buildSql(true);
$nodeList = Db::name($this->config['system_node'])
->distinct(true)
->where("id IN {$buildAuthNodeSql}")
->column('node');
}
return $nodeList;
}
/**
* 获取所有节点信息
* @time 2021-01-07
* @return array
* @author zhongshaofa <shaofa.zhong@happy-seed.com>
*/
public function getNodeList(){
return Db::name($this->config['system_node'])
->column('id,node,title,type,is_auth','node');
}
/**
* 获取管理员信息
* @time 2021-01-07
* @return array|\think\Model|null
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author zhongshaofa <shaofa.zhong@happy-seed.com>
*/
public function getAdminInfo(){
return Db::name($this->config['system_admin'])
->where('id', $this->adminId)
->find();
}
/**
* 驼峰转下划线规则
* @param string $node
* @return string
*/
public function parseNodeStr($node)
{
$array = explode('/', $node);
foreach ($array as $key => $val) {
if ($key == 0) {
$val = explode('.', $val);
foreach ($val as &$vo) {
$vo = CommonTool::humpToLine(lcfirst($vo));
}
$val = implode('.', $val);
$array[$key] = $val;
}
}
$node = implode('/', $array);
return $node;
}
}

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

Loading…
Cancel
Save