Ver Fonte

第一次提交

18315626215 há 5 anos atrás
commit
1db393e75a
100 ficheiros alterados com 22360 adições e 0 exclusões
  1. 4 0
      .gitignore
  2. 8 0
      .htaccess
  3. 42 0
      .travis.yml
  4. 26 0
      404.html
  5. 32 0
      LICENSE.txt
  6. 129 0
      README.md
  7. 3958 0
      api.html
  8. 1 0
      application/.htaccess
  9. 36 0
      application/404.html
  10. 36 0
      application/500.html
  11. 319 0
      application/admin/command/Addon.php
  12. 68 0
      application/admin/command/Addon/stubs/addon.stub
  13. 40 0
      application/admin/command/Addon/stubs/config.stub
  14. 15 0
      application/admin/command/Addon/stubs/controller.stub
  15. 7 0
      application/admin/command/Addon/stubs/info.stub
  16. 179 0
      application/admin/command/Api.php
  17. 22 0
      application/admin/command/Api/lang/zh-cn.php
  18. 207 0
      application/admin/command/Api/library/Builder.php
  19. 483 0
      application/admin/command/Api/library/Extractor.php
  20. 576 0
      application/admin/command/Api/template/index.html
  21. 1351 0
      application/admin/command/Crud.php
  22. 11 0
      application/admin/command/Crud/stubs/add.stub
  23. 35 0
      application/admin/command/Crud/stubs/controller.stub
  24. 42 0
      application/admin/command/Crud/stubs/controllerindex.stub
  25. 11 0
      application/admin/command/Crud/stubs/edit.stub
  26. 6 0
      application/admin/command/Crud/stubs/html/checkbox.stub
  27. 10 0
      application/admin/command/Crud/stubs/html/heading-html.stub
  28. 6 0
      application/admin/command/Crud/stubs/html/radio.stub
  29. 6 0
      application/admin/command/Crud/stubs/html/select.stub
  30. 5 0
      application/admin/command/Crud/stubs/html/switch.stub
  31. 33 0
      application/admin/command/Crud/stubs/index.stub
  32. 47 0
      application/admin/command/Crud/stubs/javascript.stub
  33. 5 0
      application/admin/command/Crud/stubs/lang.stub
  34. 8 0
      application/admin/command/Crud/stubs/mixins/checkbox.stub
  35. 6 0
      application/admin/command/Crud/stubs/mixins/datetime.stub
  36. 1 0
      application/admin/command/Crud/stubs/mixins/enum.stub
  37. 8 0
      application/admin/command/Crud/stubs/mixins/modelinit.stub
  38. 5 0
      application/admin/command/Crud/stubs/mixins/modelrelationmethod.stub
  39. 8 0
      application/admin/command/Crud/stubs/mixins/multiple.stub
  40. 7 0
      application/admin/command/Crud/stubs/mixins/radio.stub
  41. 7 0
      application/admin/command/Crud/stubs/mixins/select.stub
  42. 33 0
      application/admin/command/Crud/stubs/model.stub
  43. 12 0
      application/admin/command/Crud/stubs/relationmodel.stub
  44. 27 0
      application/admin/command/Crud/stubs/validate.stub
  45. 97 0
      application/admin/command/Install.php
  46. 579 0
      application/admin/command/Install/fastadmin.sql
  47. 1 0
      application/admin/command/Install/install.lock
  48. 289 0
      application/admin/command/Menu.php
  49. 182 0
      application/admin/command/Min.php
  50. 4699 0
      application/admin/command/Min/r.js
  51. 6 0
      application/admin/command/Min/stubs/css.stub
  52. 11 0
      application/admin/command/Min/stubs/js.stub
  53. 227 0
      application/admin/common.php
  54. 127 0
      application/admin/controller/Aipimagesearch.php
  55. 478 0
      application/admin/controller/Article.php
  56. 137 0
      application/admin/controller/Base.php
  57. 59 0
      application/admin/controller/Chart.php
  58. 37 0
      application/admin/controller/Company.php
  59. 225 0
      application/admin/controller/Config.php
  60. 346 0
      application/admin/controller/Data.php
  61. 55 0
      application/admin/controller/Email.php
  62. 47 0
      application/admin/controller/Index.php
  63. 83 0
      application/admin/controller/Log.php
  64. 178 0
      application/admin/controller/Login.php
  65. 192 0
      application/admin/controller/Menu.php
  66. 256 0
      application/admin/controller/Role.php
  67. 379 0
      application/admin/controller/Upload.php
  68. 393 0
      application/admin/controller/User.php
  69. 98 0
      application/admin/model/AipImageSearchModel.php
  70. 208 0
      application/admin/model/ArticleCateModel.php
  71. 194 0
      application/admin/model/ArticleModel.php
  72. 37 0
      application/admin/model/ChartModel.php
  73. 242 0
      application/admin/model/ConfigModel.php
  74. 41 0
      application/admin/model/LogModel.php
  75. 240 0
      application/admin/model/MenuModel.php
  76. 70 0
      application/admin/model/Node.php
  77. 278 0
      application/admin/model/UserModel.php
  78. 297 0
      application/admin/model/UserType.php
  79. 165 0
      application/admin/view/aipimagesearch/add.html
  80. 151 0
      application/admin/view/aipimagesearch/edit.html
  81. 195 0
      application/admin/view/aipimagesearch/index.html
  82. 444 0
      application/admin/view/article/add_article.html
  83. 321 0
      application/admin/view/article/edit_article.html
  84. 224 0
      application/admin/view/article/index.html
  85. 94 0
      application/admin/view/article/order.html
  86. 81 0
      application/admin/view/chart/add.html
  87. 82 0
      application/admin/view/chart/edit.html
  88. 159 0
      application/admin/view/chart/index.html
  89. 105 0
      application/admin/view/company/edit.html
  90. 147 0
      application/admin/view/company/index.html
  91. 137 0
      application/admin/view/config/add_config.html
  92. 131 0
      application/admin/view/config/edit_config.html
  93. 82 0
      application/admin/view/config/group.html
  94. 154 0
      application/admin/view/config/index.html
  95. 145 0
      application/admin/view/data/import.html
  96. 165 0
      application/admin/view/data/index.html
  97. 187 0
      application/admin/view/email/index.html
  98. 333 0
      application/admin/view/index.html
  99. 73 0
      application/admin/view/index/index.html
  100. 119 0
      application/admin/view/log/operate_log.html

+ 4 - 0
.gitignore

@@ -0,0 +1,4 @@
+.idea
+composer.lock
+*.log
+thinkphp

+ 8 - 0
.htaccess

@@ -0,0 +1,8 @@
+<IfModule mod_rewrite.c>
+  Options +FollowSymlinks -Multiviews
+  RewriteEngine On
+
+  RewriteCond %{REQUEST_FILENAME} !-d
+  RewriteCond %{REQUEST_FILENAME} !-f
+  RewriteRule ^(.*)$ index.php?/$1 [QSA,PT,L]
+</IfModule>

+ 42 - 0
.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

+ 26 - 0
404.html

@@ -0,0 +1,26 @@
+<!doctype html>
+<html>
+<head>
+<meta charset="utf-8">
+<meta http-equiv="X-UA-Compatible" content="IE=edge">
+<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
+<title>404</title>
+<style>
+	body{
+		background-color:#444;
+		font-size:14px;
+	}
+	h3{
+		font-size:60px;
+		color:#eee;
+		text-align:center;
+		padding-top:30px;
+		font-weight:normal;
+	}
+</style>
+</head>
+
+<body>
+<h3>404,您请求的文件不存在!</h3>
+</body>
+</html>

+ 32 - 0
LICENSE.txt

@@ -0,0 +1,32 @@
+
+ThinkPHP遵循Apache2开源协议发布,并提供免费使用。
+版权所有Copyright © 2006-2017 by ThinkPHP (http://thinkphp.cn)
+All rights reserved。
+ThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。
+
+Apache Licence是著名的非盈利开源组织Apache采用的协议。
+该协议和BSD类似,鼓励代码共享和尊重原作者的著作权,
+允许代码修改,再作为开源或商业软件发布。需要满足
+的条件: 
+1. 需要给代码的用户一份Apache Licence ;
+2. 如果你修改了代码,需要在被修改的文件中说明;
+3. 在延伸的代码中(修改和有源代码衍生的代码中)需要
+带有原来代码中的协议,商标,专利声明和其他原来作者规
+定需要包含的说明;
+4. 如果再发布的产品中包含一个Notice文件,则在Notice文
+件中需要带有本协议内容。你可以在Notice中增加自己的
+许可,但不可以表现为对Apache Licence构成更改。 
+具体的协议参考:http://www.apache.org/licenses/LICENSE-2.0
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.

+ 129 - 0
README.md

@@ -0,0 +1,129 @@
+ThinkPHP 5.0
+===============
+
+[![Total Downloads](https://poser.pugx.org/topthink/think/downloads)](https://packagist.org/packages/topthink/think)
+[![Latest Stable Version](https://poser.pugx.org/topthink/think/v/stable)](https://packagist.org/packages/topthink/think)
+[![Latest Unstable Version](https://poser.pugx.org/topthink/think/v/unstable)](https://packagist.org/packages/topthink/think)
+[![License](https://poser.pugx.org/topthink/think/license)](https://packagist.org/packages/topthink/think)
+
+ThinkPHP5在保持快速开发和大道至简的核心理念不变的同时,PHP版本要求提升到5.4,对已有的CBD模式做了更深的强化,优化核心,减少依赖,基于全新的架构思想和命名空间实现,是ThinkPHP突破原有框架思路的颠覆之作,其主要特性包括:
+
+ + 基于命名空间和众多PHP新特性
+ + 核心功能组件化
+ + 强化路由功能
+ + 更灵活的控制器
+ + 重构的模型和数据库类
+ + 配置文件可分离
+ + 重写的自动验证和完成
+ + 简化扩展机制
+ + API支持完善
+ + 改进的Log类
+ + 命令行访问支持
+ + REST支持
+ + 引导文件支持
+ + 方便的自动生成定义
+ + 真正惰性加载
+ + 分布式环境支持
+ + 更多的社交类库
+
+> ThinkPHP5的运行环境要求PHP5.4以上。
+
+详细开发文档参考 [ThinkPHP5完全开发手册](http://www.kancloud.cn/manual/thinkphp5)
+
+## 目录结构
+
+初始的目录结构如下:
+
+~~~
+www  WEB部署目录(或者子目录)
+├─application           应用目录
+│  ├─common             公共模块目录(可以更改)
+│  ├─module_name        模块目录
+│  │  ├─config.php      模块配置文件
+│  │  ├─common.php      模块函数文件
+│  │  ├─controller      控制器目录
+│  │  ├─model           模型目录
+│  │  ├─view            视图目录
+│  │  └─ ...            更多类库目录
+│  │
+│  ├─command.php        命令行工具配置文件
+│  ├─common.php         公共函数文件
+│  ├─config.php         公共配置文件
+│  ├─route.php          路由配置文件
+│  ├─tags.php           应用行为扩展定义文件
+│  └─database.php       数据库配置文件
+│
+├─public                WEB目录(对外访问目录)
+│  ├─index.php          入口文件
+│  ├─router.php         快速测试文件
+│  └─.htaccess          用于apache的重写
+│
+├─thinkphp              框架系统目录
+│  ├─lang               语言文件目录
+│  ├─library            框架类库目录
+│  │  ├─think           Think类库包目录
+│  │  └─traits          系统Trait目录
+│  │
+│  ├─tpl                系统模板目录
+│  ├─base.php           基础定义文件
+│  ├─console.php        控制台入口文件
+│  ├─convention.php     框架惯例配置文件
+│  ├─helper.php         助手函数文件
+│  ├─phpunit.xml        phpunit配置文件
+│  └─start.php          框架入口文件
+│
+├─extend                扩展类库目录
+├─runtime               应用的运行时目录(可写,可定制)
+├─vendor                第三方类库目录(Composer依赖库)
+├─build.php             自动生成定义文件(参考)
+├─composer.json         composer 定义文件
+├─LICENSE.txt           授权说明文件
+├─README.md             README 文件
+├─think                 命令行入口文件
+~~~
+
+> router.php用于php自带webserver支持,可用于快速测试
+> 切换到public目录后,启动命令:php -S localhost:8888  router.php
+> 上面的目录结构和名称是可以改变的,这取决于你的入口文件和配置参数。
+
+## 命名规范
+
+`ThinkPHP5`遵循PSR-2命名规范和PSR-4自动加载规范,并且注意如下规范:
+
+### 目录和文件
+
+*   目录不强制规范,驼峰和小写+下划线模式均支持;
+*   类库、函数文件统一以`.php`为后缀;
+*   类的文件名均以命名空间定义,并且命名空间的路径和类库文件所在路径一致;
+*   类名和类文件名保持一致,统一采用驼峰法命名(首字母大写);
+
+### 函数和类、属性命名
+*   类的命名采用驼峰法,并且首字母大写,例如 `User`、`UserType`,默认不需要添加后缀,例如`UserController`应该直接命名为`User`;
+*   函数的命名使用小写字母和下划线(小写字母开头)的方式,例如 `get_client_ip`;
+*   方法的命名使用驼峰法,并且首字母小写,例如 `getUserName`;
+*   属性的命名使用驼峰法,并且首字母小写,例如 `tableName`、`instance`;
+*   以双下划线“__”打头的函数或方法作为魔法方法,例如 `__call` 和 `__autoload`;
+
+### 常量和配置
+*   常量以大写字母和下划线命名,例如 `APP_PATH`和 `THINK_PATH`;
+*   配置参数以小写字母和下划线命名,例如 `url_route_on` 和`url_convert`;
+
+### 数据表和字段
+*   数据表和字段采用小写加下划线方式命名,并注意字段名不要以下划线开头,例如 `think_user` 表和 `user_name`字段,不建议使用驼峰和中文作为数据表字段命名。
+
+## 参与开发
+请参阅 [ThinkPHP5 核心框架包](https://github.com/top-think/framework)。
+
+## 版权信息
+
+ThinkPHP遵循Apache2开源协议发布,并提供免费使用。
+
+本项目包含的第三方源码和二进制文件之版权信息另行标注。
+
+版权所有Copyright © 2006-2017 by ThinkPHP (http://thinkphp.cn)
+
+All rights reserved。
+
+ThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。
+
+更多细节参阅 [LICENSE.txt](LICENSE.txt)

+ 3958 - 0
api.html

@@ -0,0 +1,3958 @@
+<!DOCTYPE html>
+<html lang="zh-cn">
+    <head>
+        <meta charset="utf-8">
+        <meta http-equiv="X-UA-Compatible" content="IE=edge">
+        <meta name="viewport" content="width=device-width, initial-scale=1.0">
+        <meta name="description" content="">
+        <meta name="author" content="">
+        <title></title>
+
+        <!-- Bootstrap Core CSS -->
+        <link href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
+
+        <!-- Plugin CSS -->
+        <link href="https://cdn.staticfile.org/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
+
+        <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
+        <!--[if lt IE 9]>
+        <script src="https://cdn.staticfile.org/html5shiv/3.7.3/html5shiv.min.js"></script>
+        <script src="https://cdn.staticfile.org/respond.js/1.4.2/respond.min.js"></script>
+        <![endif]-->
+
+        <style type="text/css">
+            body {
+                padding-top: 70px; margin-bottom: 15px;
+                -webkit-font-smoothing: antialiased;
+                -moz-osx-font-smoothing: grayscale;
+                font-family: "Roboto", "SF Pro SC", "SF Pro Display", "SF Pro Icons", "PingFang SC", BlinkMacSystemFont, -apple-system, "Segoe UI", "Microsoft Yahei", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", "Helvetica", "Arial", sans-serif;
+                font-weight: 400;
+            }
+            h2        { font-size: 1.6em; }
+            hr        { margin-top: 10px; }
+            .tab-pane { padding-top: 10px; }
+            .mt0      { margin-top: 0px; }
+            .footer   { font-size: 12px; color: #666; }
+            .label    { display: inline-block; min-width: 65px; padding: 0.3em 0.6em 0.3em; }
+            .string   { color: green; }
+            .number   { color: darkorange; }
+            .boolean  { color: blue; }
+            .null     { color: magenta; }
+            .key      { color: red; }
+            .popover  { max-width: 400px; max-height: 400px; overflow-y: auto;}
+            .list-group.panel > .list-group-item {
+            }
+            .list-group-item:last-child {
+                border-radius:0;
+            }
+            h4.panel-title a {
+                font-weight:normal;
+                font-size:14px;
+            }
+            h4.panel-title a .text-muted {
+                font-size:12px;
+                font-weight:normal;
+                font-family: 'Verdana';
+            }
+            #sidebar {
+                width: 220px;
+                position: fixed;
+                margin-left: -240px;
+                overflow-y:auto;
+            }
+            #sidebar > .list-group {
+                margin-bottom:0;
+            }
+            #sidebar > .list-group > a{
+                text-indent:0;
+            }
+            #sidebar .child {
+                border:1px solid #ddd;
+                border-bottom:none;
+            }
+            #sidebar .child > a {
+                border:0;
+            }
+            #sidebar .list-group a.current {
+                background:#f5f5f5;
+            }
+            @media (max-width: 1620px){
+                #sidebar {
+                    margin:0;
+                }
+                #accordion {
+                    padding-left:235px;
+                }
+            }
+            @media (max-width: 768px){
+                #sidebar {
+                    display: none;
+                }
+                #accordion {
+                    padding-left:0px;
+                }
+            }
+
+        </style>
+    </head>
+    <body>
+        <!-- Fixed navbar -->
+        <div class="navbar navbar-default navbar-fixed-top" role="navigation">
+            <div class="container">
+                <div class="navbar-header">
+                    <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
+                        <span class="sr-only">Toggle navigation</span>
+                        <span class="icon-bar"></span>
+                        <span class="icon-bar"></span>
+                        <span class="icon-bar"></span>
+                    </button>
+                    <a class="navbar-brand" href="https://www.fastadmin.net" target="_blank"></a>
+                </div>
+                <div class="navbar-collapse collapse">
+                    <form class="navbar-form navbar-right">
+                        <div class="form-group">
+                            Token:
+                        </div>
+                        <div class="form-group">
+                            <input type="text" class="form-control input-sm" data-toggle="tooltip" title="Token在会员注册或登录后都会返回,WEB端同时存在于Cookie中" placeholder="token" id="token" />
+                        </div>
+                        <div class="form-group">
+                            Apiurl:
+                        </div>
+                        <div class="form-group">
+                            <input id="apiUrl" type="text" class="form-control input-sm" data-toggle="tooltip" title="API接口URL" placeholder="https://api.mydomain.com" value="" />
+                        </div>
+                        <div class="form-group">
+                            <button type="button" class="btn btn-success btn-sm" data-toggle="tooltip" title="点击保存后Token和Api url都将保存在本地Localstorage中" id="save_data">
+                                <span class="glyphicon glyphicon-floppy-disk" aria-hidden="true"></span>
+                            </button>
+                        </div>
+                    </form>
+                </div><!--/.nav-collapse -->
+            </div>
+        </div>
+
+        <div class="container">
+            <!-- menu -->
+            <div id="sidebar">
+                <div class="list-group panel">
+                                        <a href="#公共接口" class="list-group-item" data-toggle="collapse" data-parent="#sidebar">公共接口  <i class="fa fa-caret-down"></i></a>
+                    <div class="child collapse" id="公共接口">
+                                                <a href="javascript:;" data-id="0" class="list-group-item">加载初始化</a>
+                                                <a href="javascript:;" data-id="1" class="list-group-item">上传文件</a>
+                                            </div>
+                                        <a href="#示例接口" class="list-group-item" data-toggle="collapse" data-parent="#sidebar">示例接口  <i class="fa fa-caret-down"></i></a>
+                    <div class="child collapse" id="示例接口">
+                                                <a href="javascript:;" data-id="2" class="list-group-item">测试名称</a>
+                                                <a href="javascript:;" data-id="3" class="list-group-item">无需登录的接口</a>
+                                                <a href="javascript:;" data-id="4" class="list-group-item">需要登录的接口</a>
+                                                <a href="javascript:;" data-id="5" class="list-group-item">需要登录且需要验证有相应组的权限</a>
+                                            </div>
+                                        <a href="#邮箱验证码接口" class="list-group-item" data-toggle="collapse" data-parent="#sidebar">邮箱验证码接口  <i class="fa fa-caret-down"></i></a>
+                    <div class="child collapse" id="邮箱验证码接口">
+                                                <a href="javascript:;" data-id="6" class="list-group-item">发送验证码</a>
+                                                <a href="javascript:;" data-id="7" class="list-group-item">检测验证码</a>
+                                            </div>
+                                        <a href="#首页接口" class="list-group-item" data-toggle="collapse" data-parent="#sidebar">首页接口  <i class="fa fa-caret-down"></i></a>
+                    <div class="child collapse" id="首页接口">
+                                                <a href="javascript:;" data-id="8" class="list-group-item">首页</a>
+                                            </div>
+                                        <a href="#手机短信接口" class="list-group-item" data-toggle="collapse" data-parent="#sidebar">手机短信接口  <i class="fa fa-caret-down"></i></a>
+                    <div class="child collapse" id="手机短信接口">
+                                                <a href="javascript:;" data-id="9" class="list-group-item">发送验证码</a>
+                                                <a href="javascript:;" data-id="10" class="list-group-item">检测验证码</a>
+                                            </div>
+                                        <a href="#Token接口" class="list-group-item" data-toggle="collapse" data-parent="#sidebar">Token接口  <i class="fa fa-caret-down"></i></a>
+                    <div class="child collapse" id="Token接口">
+                                                <a href="javascript:;" data-id="11" class="list-group-item">检测Token是否过期</a>
+                                                <a href="javascript:;" data-id="12" class="list-group-item">刷新Token</a>
+                                            </div>
+                                        <a href="#会员接口" class="list-group-item" data-toggle="collapse" data-parent="#sidebar">会员接口  <i class="fa fa-caret-down"></i></a>
+                    <div class="child collapse" id="会员接口">
+                                                <a href="javascript:;" data-id="13" class="list-group-item">会员中心</a>
+                                                <a href="javascript:;" data-id="14" class="list-group-item">会员登录</a>
+                                                <a href="javascript:;" data-id="15" class="list-group-item">手机验证码登录</a>
+                                                <a href="javascript:;" data-id="16" class="list-group-item">注册会员</a>
+                                                <a href="javascript:;" data-id="17" class="list-group-item">注销登录</a>
+                                                <a href="javascript:;" data-id="18" class="list-group-item">修改会员个人信息</a>
+                                                <a href="javascript:;" data-id="19" class="list-group-item">修改邮箱</a>
+                                                <a href="javascript:;" data-id="20" class="list-group-item">修改手机号</a>
+                                                <a href="javascript:;" data-id="21" class="list-group-item">第三方登录</a>
+                                                <a href="javascript:;" data-id="22" class="list-group-item">重置密码</a>
+                                            </div>
+                                        <a href="#验证接口" class="list-group-item" data-toggle="collapse" data-parent="#sidebar">验证接口  <i class="fa fa-caret-down"></i></a>
+                    <div class="child collapse" id="验证接口">
+                                                <a href="javascript:;" data-id="23" class="list-group-item">检测邮箱</a>
+                                                <a href="javascript:;" data-id="24" class="list-group-item">检测用户名</a>
+                                                <a href="javascript:;" data-id="25" class="list-group-item">检测手机</a>
+                                                <a href="javascript:;" data-id="26" class="list-group-item">检测手机</a>
+                                                <a href="javascript:;" data-id="27" class="list-group-item">检测邮箱</a>
+                                                <a href="javascript:;" data-id="28" class="list-group-item">检测手机验证码</a>
+                                                <a href="javascript:;" data-id="29" class="list-group-item">检测邮箱验证码</a>
+                                            </div>
+                                    </div>
+            </div>
+            <div class="panel-group" id="accordion">
+                                <h2>公共接口</h2>
+                <hr>
+                                <div class="panel panel-default">
+                    <div class="panel-heading" id="heading-0">
+                        <h4 class="panel-title">
+                            <span class="label label-success">GET</span>
+                            <a data-toggle="collapse" data-parent="#accordion0" href="#collapseOne0"> 加载初始化 <span class="text-muted">/api/common/init</span></a>
+                        </h4>
+                    </div>
+                    <div id="collapseOne0" class="panel-collapse collapse">
+                        <div class="panel-body">
+
+                            <!-- Nav tabs -->
+                            <ul class="nav nav-tabs" id="doctab0">
+                                <li class="active"><a href="#info0" data-toggle="tab">基础信息</a></li>
+                                <li><a href="#sandbox0" data-toggle="tab">在线测试</a></li>
+                                <li><a href="#sample0" data-toggle="tab">返回示例</a></li>
+                            </ul>
+
+                            <!-- Tab panes -->
+                            <div class="tab-content">
+
+                                <div class="tab-pane active" id="info0">
+                                    <div class="well">
+                                        加载初始化                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>Headers</strong></div>
+                                        <div class="panel-body">
+                                                                                        无
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>参数</strong></div>
+                                        <div class="panel-body">
+                                                                                        <table class="table table-hover">
+                                                <thead>
+                                                    <tr>
+                                                        <th>名称</th>
+                                                        <th>类型</th>
+                                                        <th>必选</th>
+                                                        <th>描述</th>
+                                                    </tr>
+                                                </thead>
+                                                <tbody>
+                                                                                                        <tr>
+                                                        <td>version</td>
+                                                        <td>string</td>
+                                                        <td>是</td>
+                                                        <td>版本号</td>
+                                                    </tr>
+                                                                                                        <tr>
+                                                        <td>lng</td>
+                                                        <td>string</td>
+                                                        <td>是</td>
+                                                        <td>经度</td>
+                                                    </tr>
+                                                                                                        <tr>
+                                                        <td>lat</td>
+                                                        <td>string</td>
+                                                        <td>是</td>
+                                                        <td>纬度</td>
+                                                    </tr>
+                                                                                                    </tbody>
+                                            </table>
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>正文</strong></div>
+                                        <div class="panel-body">
+                                            无                                        </div>
+                                    </div>
+                                </div><!-- #info -->
+
+                                <div class="tab-pane" id="sandbox0">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                                                                        <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>参数</strong></div>
+                                                <div class="panel-body">
+                                                    <form enctype="application/x-www-form-urlencoded" role="form" action="/api/common/init" method="get" name="form0" id="form0">
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="version">version</label>
+                                                            <input type="string" class="form-control input-sm" id="version" required placeholder="版本号" name="version">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="lng">lng</label>
+                                                            <input type="string" class="form-control input-sm" id="lng" required placeholder="经度" name="lng">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="lat">lat</label>
+                                                            <input type="string" class="form-control input-sm" id="lat" required placeholder="纬度" name="lat">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <button type="submit" class="btn btn-success send" rel="0">提交</button>
+                                                            <button type="reset" class="btn btn-info" rel="0">重置</button>
+                                                        </div>
+                                                    </form>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>响应输出</strong></div>
+                                                <div class="panel-body">
+                                                    <div class="row">
+                                                        <div class="col-md-12" style="overflow-x:auto">
+                                                            <pre id="response_headers0"></pre>
+                                                            <pre id="response0"></pre>
+                                                        </div>
+                                                    </div>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>返回参数</strong></div>
+                                                <div class="panel-body">
+                                                                                                        无
+                                                                                                    </div>
+                                            </div>
+                                        </div>
+                                    </div>
+                                </div><!-- #sandbox -->
+
+                                <div class="tab-pane" id="sample0">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                            <pre id="sample_response0">无</pre>
+                                        </div>
+                                    </div>
+                                </div><!-- #sample -->
+
+                            </div><!-- .tab-content -->
+                        </div>
+                    </div>
+                </div>
+                                <div class="panel panel-default">
+                    <div class="panel-heading" id="heading-1">
+                        <h4 class="panel-title">
+                            <span class="label label-primary">POST</span>
+                            <a data-toggle="collapse" data-parent="#accordion1" href="#collapseOne1"> 上传文件 <span class="text-muted">/api/common/upload</span></a>
+                        </h4>
+                    </div>
+                    <div id="collapseOne1" class="panel-collapse collapse">
+                        <div class="panel-body">
+
+                            <!-- Nav tabs -->
+                            <ul class="nav nav-tabs" id="doctab1">
+                                <li class="active"><a href="#info1" data-toggle="tab">基础信息</a></li>
+                                <li><a href="#sandbox1" data-toggle="tab">在线测试</a></li>
+                                <li><a href="#sample1" data-toggle="tab">返回示例</a></li>
+                            </ul>
+
+                            <!-- Tab panes -->
+                            <div class="tab-content">
+
+                                <div class="tab-pane active" id="info1">
+                                    <div class="well">
+                                        上传文件                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>Headers</strong></div>
+                                        <div class="panel-body">
+                                                                                        无
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>参数</strong></div>
+                                        <div class="panel-body">
+                                                                                        <table class="table table-hover">
+                                                <thead>
+                                                    <tr>
+                                                        <th>名称</th>
+                                                        <th>类型</th>
+                                                        <th>必选</th>
+                                                        <th>描述</th>
+                                                    </tr>
+                                                </thead>
+                                                <tbody>
+                                                                                                        <tr>
+                                                        <td>file</td>
+                                                        <td>File</td>
+                                                        <td>是</td>
+                                                        <td>文件流</td>
+                                                    </tr>
+                                                                                                    </tbody>
+                                            </table>
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>正文</strong></div>
+                                        <div class="panel-body">
+                                            无                                        </div>
+                                    </div>
+                                </div><!-- #info -->
+
+                                <div class="tab-pane" id="sandbox1">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                                                                        <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>参数</strong></div>
+                                                <div class="panel-body">
+                                                    <form enctype="application/x-www-form-urlencoded" role="form" action="/api/common/upload" method="POST" name="form1" id="form1">
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="file">file</label>
+                                                            <input type="File" class="form-control input-sm" id="file" required placeholder="文件流" name="file">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <button type="submit" class="btn btn-success send" rel="1">提交</button>
+                                                            <button type="reset" class="btn btn-info" rel="1">重置</button>
+                                                        </div>
+                                                    </form>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>响应输出</strong></div>
+                                                <div class="panel-body">
+                                                    <div class="row">
+                                                        <div class="col-md-12" style="overflow-x:auto">
+                                                            <pre id="response_headers1"></pre>
+                                                            <pre id="response1"></pre>
+                                                        </div>
+                                                    </div>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>返回参数</strong></div>
+                                                <div class="panel-body">
+                                                                                                        无
+                                                                                                    </div>
+                                            </div>
+                                        </div>
+                                    </div>
+                                </div><!-- #sandbox -->
+
+                                <div class="tab-pane" id="sample1">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                            <pre id="sample_response1">无</pre>
+                                        </div>
+                                    </div>
+                                </div><!-- #sample -->
+
+                            </div><!-- .tab-content -->
+                        </div>
+                    </div>
+                </div>
+                                <h2>示例接口</h2>
+                <hr>
+                                <div class="panel panel-default">
+                    <div class="panel-heading" id="heading-2">
+                        <h4 class="panel-title">
+                            <span class="label label-primary">POST</span>
+                            <a data-toggle="collapse" data-parent="#accordion2" href="#collapseOne2"> 测试名称 <span class="text-muted">/api/demo/test/id/{id}/name/{name}</span></a>
+                        </h4>
+                    </div>
+                    <div id="collapseOne2" class="panel-collapse collapse">
+                        <div class="panel-body">
+
+                            <!-- Nav tabs -->
+                            <ul class="nav nav-tabs" id="doctab2">
+                                <li class="active"><a href="#info2" data-toggle="tab">基础信息</a></li>
+                                <li><a href="#sandbox2" data-toggle="tab">在线测试</a></li>
+                                <li><a href="#sample2" data-toggle="tab">返回示例</a></li>
+                            </ul>
+
+                            <!-- Tab panes -->
+                            <div class="tab-content">
+
+                                <div class="tab-pane active" id="info2">
+                                    <div class="well">
+                                        测试描述信息                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>Headers</strong></div>
+                                        <div class="panel-body">
+                                                                                        <table class="table table-hover">
+                                                <thead>
+                                                    <tr>
+                                                        <th>名称</th>
+                                                        <th>类型</th>
+                                                        <th>必选</th>
+                                                        <th>描述</th>
+                                                    </tr>
+                                                </thead>
+                                                <tbody>
+                                                                                                        <tr>
+                                                        <td>token</td>
+                                                        <td>string</td>
+                                                        <td>是</td>
+                                                        <td>请求的Token</td>
+                                                    </tr>
+                                                                                                    </tbody>
+                                            </table>
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>参数</strong></div>
+                                        <div class="panel-body">
+                                                                                        <table class="table table-hover">
+                                                <thead>
+                                                    <tr>
+                                                        <th>名称</th>
+                                                        <th>类型</th>
+                                                        <th>必选</th>
+                                                        <th>描述</th>
+                                                    </tr>
+                                                </thead>
+                                                <tbody>
+                                                                                                        <tr>
+                                                        <td>id</td>
+                                                        <td>integer</td>
+                                                        <td>是</td>
+                                                        <td>会员ID</td>
+                                                    </tr>
+                                                                                                        <tr>
+                                                        <td>name</td>
+                                                        <td>string</td>
+                                                        <td>是</td>
+                                                        <td>用户名</td>
+                                                    </tr>
+                                                                                                        <tr>
+                                                        <td>data</td>
+                                                        <td>object</td>
+                                                        <td>是</td>
+                                                        <td>扩展数据</td>
+                                                    </tr>
+                                                                                                    </tbody>
+                                            </table>
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>正文</strong></div>
+                                        <div class="panel-body">
+                                            无                                        </div>
+                                    </div>
+                                </div><!-- #info -->
+
+                                <div class="tab-pane" id="sandbox2">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                                                                        <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>Headers</strong></div>
+                                                <div class="panel-body">
+                                                    <div class="headers">
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="token">token</label>
+                                                            <input type="string" class="form-control input-sm" id="token" required placeholder="请求的Token - Ex: " name="token">
+                                                        </div>
+                                                                                                            </div>
+                                                </div>
+                                            </div>
+                                                                                        <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>参数</strong></div>
+                                                <div class="panel-body">
+                                                    <form enctype="application/x-www-form-urlencoded" role="form" action="/api/demo/test/id/{id}/name/{name}" method="POST" name="form2" id="form2">
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="id">id</label>
+                                                            <input type="integer" class="form-control input-sm" id="id" required placeholder="会员ID" name="id">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="name">name</label>
+                                                            <input type="string" class="form-control input-sm" id="name" required placeholder="用户名" name="name">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="data">data</label>
+                                                            <input type="object" class="form-control input-sm" id="data" required placeholder="扩展数据 - 例: {'user_id':'int','user_name':'string','profile':{'email':'string','age':'integer'}}" name="data">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <button type="submit" class="btn btn-success send" rel="2">提交</button>
+                                                            <button type="reset" class="btn btn-info" rel="2">重置</button>
+                                                        </div>
+                                                    </form>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>响应输出</strong></div>
+                                                <div class="panel-body">
+                                                    <div class="row">
+                                                        <div class="col-md-12" style="overflow-x:auto">
+                                                            <pre id="response_headers2"></pre>
+                                                            <pre id="response2"></pre>
+                                                        </div>
+                                                    </div>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>返回参数</strong></div>
+                                                <div class="panel-body">
+                                                                                                        <table class="table table-hover">
+                                                        <thead>
+                                                            <tr>
+                                                                <th>名称</th>
+                                                                <th>类型</th>
+                                                                <th>描述</th>
+                                                            </tr>
+                                                        </thead>
+                                                        <tbody>
+                                                                                                                        <tr>
+                                                                <td>code</td>
+                                                                <td>integer</td>
+                                                                <td></td>
+                                                            </tr>
+                                                                                                                        <tr>
+                                                                <td>msg</td>
+                                                                <td>string</td>
+                                                                <td></td>
+                                                            </tr>
+                                                                                                                        <tr>
+                                                                <td>data</td>
+                                                                <td>object</td>
+                                                                <td>扩展数据返回</td>
+                                                            </tr>
+                                                                                                                    </tbody>
+                                                    </table>
+                                                                                                    </div>
+                                            </div>
+                                        </div>
+                                    </div>
+                                </div><!-- #sandbox -->
+
+                                <div class="tab-pane" id="sample2">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                            <pre id="sample_response2">{
+         'code':'1',
+         'msg':'返回成功'
+        }</pre>
+                                        </div>
+                                    </div>
+                                </div><!-- #sample -->
+
+                            </div><!-- .tab-content -->
+                        </div>
+                    </div>
+                </div>
+                                <div class="panel panel-default">
+                    <div class="panel-heading" id="heading-3">
+                        <h4 class="panel-title">
+                            <span class="label label-success">GET</span>
+                            <a data-toggle="collapse" data-parent="#accordion3" href="#collapseOne3"> 无需登录的接口 <span class="text-muted">/api/demo/test1</span></a>
+                        </h4>
+                    </div>
+                    <div id="collapseOne3" class="panel-collapse collapse">
+                        <div class="panel-body">
+
+                            <!-- Nav tabs -->
+                            <ul class="nav nav-tabs" id="doctab3">
+                                <li class="active"><a href="#info3" data-toggle="tab">基础信息</a></li>
+                                <li><a href="#sandbox3" data-toggle="tab">在线测试</a></li>
+                                <li><a href="#sample3" data-toggle="tab">返回示例</a></li>
+                            </ul>
+
+                            <!-- Tab panes -->
+                            <div class="tab-content">
+
+                                <div class="tab-pane active" id="info3">
+                                    <div class="well">
+                                        无需登录的接口                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>Headers</strong></div>
+                                        <div class="panel-body">
+                                                                                        无
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>参数</strong></div>
+                                        <div class="panel-body">
+                                                                                        无
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>正文</strong></div>
+                                        <div class="panel-body">
+                                            无                                        </div>
+                                    </div>
+                                </div><!-- #info -->
+
+                                <div class="tab-pane" id="sandbox3">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                                                                        <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>参数</strong></div>
+                                                <div class="panel-body">
+                                                    <form enctype="application/x-www-form-urlencoded" role="form" action="/api/demo/test1" method="get" name="form3" id="form3">
+                                                                                                                <div class="form-group">
+                                                            无
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <button type="submit" class="btn btn-success send" rel="3">提交</button>
+                                                            <button type="reset" class="btn btn-info" rel="3">重置</button>
+                                                        </div>
+                                                    </form>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>响应输出</strong></div>
+                                                <div class="panel-body">
+                                                    <div class="row">
+                                                        <div class="col-md-12" style="overflow-x:auto">
+                                                            <pre id="response_headers3"></pre>
+                                                            <pre id="response3"></pre>
+                                                        </div>
+                                                    </div>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>返回参数</strong></div>
+                                                <div class="panel-body">
+                                                                                                        无
+                                                                                                    </div>
+                                            </div>
+                                        </div>
+                                    </div>
+                                </div><!-- #sandbox -->
+
+                                <div class="tab-pane" id="sample3">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                            <pre id="sample_response3">无</pre>
+                                        </div>
+                                    </div>
+                                </div><!-- #sample -->
+
+                            </div><!-- .tab-content -->
+                        </div>
+                    </div>
+                </div>
+                                <div class="panel panel-default">
+                    <div class="panel-heading" id="heading-4">
+                        <h4 class="panel-title">
+                            <span class="label label-success">GET</span>
+                            <a data-toggle="collapse" data-parent="#accordion4" href="#collapseOne4"> 需要登录的接口 <span class="text-muted">/api/demo/test2</span></a>
+                        </h4>
+                    </div>
+                    <div id="collapseOne4" class="panel-collapse collapse">
+                        <div class="panel-body">
+
+                            <!-- Nav tabs -->
+                            <ul class="nav nav-tabs" id="doctab4">
+                                <li class="active"><a href="#info4" data-toggle="tab">基础信息</a></li>
+                                <li><a href="#sandbox4" data-toggle="tab">在线测试</a></li>
+                                <li><a href="#sample4" data-toggle="tab">返回示例</a></li>
+                            </ul>
+
+                            <!-- Tab panes -->
+                            <div class="tab-content">
+
+                                <div class="tab-pane active" id="info4">
+                                    <div class="well">
+                                        需要登录的接口                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>Headers</strong></div>
+                                        <div class="panel-body">
+                                                                                        无
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>参数</strong></div>
+                                        <div class="panel-body">
+                                                                                        无
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>正文</strong></div>
+                                        <div class="panel-body">
+                                            无                                        </div>
+                                    </div>
+                                </div><!-- #info -->
+
+                                <div class="tab-pane" id="sandbox4">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                                                                        <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>参数</strong></div>
+                                                <div class="panel-body">
+                                                    <form enctype="application/x-www-form-urlencoded" role="form" action="/api/demo/test2" method="get" name="form4" id="form4">
+                                                                                                                <div class="form-group">
+                                                            无
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <button type="submit" class="btn btn-success send" rel="4">提交</button>
+                                                            <button type="reset" class="btn btn-info" rel="4">重置</button>
+                                                        </div>
+                                                    </form>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>响应输出</strong></div>
+                                                <div class="panel-body">
+                                                    <div class="row">
+                                                        <div class="col-md-12" style="overflow-x:auto">
+                                                            <pre id="response_headers4"></pre>
+                                                            <pre id="response4"></pre>
+                                                        </div>
+                                                    </div>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>返回参数</strong></div>
+                                                <div class="panel-body">
+                                                                                                        无
+                                                                                                    </div>
+                                            </div>
+                                        </div>
+                                    </div>
+                                </div><!-- #sandbox -->
+
+                                <div class="tab-pane" id="sample4">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                            <pre id="sample_response4">无</pre>
+                                        </div>
+                                    </div>
+                                </div><!-- #sample -->
+
+                            </div><!-- .tab-content -->
+                        </div>
+                    </div>
+                </div>
+                                <div class="panel panel-default">
+                    <div class="panel-heading" id="heading-5">
+                        <h4 class="panel-title">
+                            <span class="label label-success">GET</span>
+                            <a data-toggle="collapse" data-parent="#accordion5" href="#collapseOne5"> 需要登录且需要验证有相应组的权限 <span class="text-muted">/api/demo/test3</span></a>
+                        </h4>
+                    </div>
+                    <div id="collapseOne5" class="panel-collapse collapse">
+                        <div class="panel-body">
+
+                            <!-- Nav tabs -->
+                            <ul class="nav nav-tabs" id="doctab5">
+                                <li class="active"><a href="#info5" data-toggle="tab">基础信息</a></li>
+                                <li><a href="#sandbox5" data-toggle="tab">在线测试</a></li>
+                                <li><a href="#sample5" data-toggle="tab">返回示例</a></li>
+                            </ul>
+
+                            <!-- Tab panes -->
+                            <div class="tab-content">
+
+                                <div class="tab-pane active" id="info5">
+                                    <div class="well">
+                                        需要登录且需要验证有相应组的权限                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>Headers</strong></div>
+                                        <div class="panel-body">
+                                                                                        无
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>参数</strong></div>
+                                        <div class="panel-body">
+                                                                                        无
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>正文</strong></div>
+                                        <div class="panel-body">
+                                            无                                        </div>
+                                    </div>
+                                </div><!-- #info -->
+
+                                <div class="tab-pane" id="sandbox5">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                                                                        <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>参数</strong></div>
+                                                <div class="panel-body">
+                                                    <form enctype="application/x-www-form-urlencoded" role="form" action="/api/demo/test3" method="get" name="form5" id="form5">
+                                                                                                                <div class="form-group">
+                                                            无
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <button type="submit" class="btn btn-success send" rel="5">提交</button>
+                                                            <button type="reset" class="btn btn-info" rel="5">重置</button>
+                                                        </div>
+                                                    </form>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>响应输出</strong></div>
+                                                <div class="panel-body">
+                                                    <div class="row">
+                                                        <div class="col-md-12" style="overflow-x:auto">
+                                                            <pre id="response_headers5"></pre>
+                                                            <pre id="response5"></pre>
+                                                        </div>
+                                                    </div>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>返回参数</strong></div>
+                                                <div class="panel-body">
+                                                                                                        无
+                                                                                                    </div>
+                                            </div>
+                                        </div>
+                                    </div>
+                                </div><!-- #sandbox -->
+
+                                <div class="tab-pane" id="sample5">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                            <pre id="sample_response5">无</pre>
+                                        </div>
+                                    </div>
+                                </div><!-- #sample -->
+
+                            </div><!-- .tab-content -->
+                        </div>
+                    </div>
+                </div>
+                                <h2>邮箱验证码接口</h2>
+                <hr>
+                                <div class="panel panel-default">
+                    <div class="panel-heading" id="heading-6">
+                        <h4 class="panel-title">
+                            <span class="label label-success">GET</span>
+                            <a data-toggle="collapse" data-parent="#accordion6" href="#collapseOne6"> 发送验证码 <span class="text-muted">/api/ems/send</span></a>
+                        </h4>
+                    </div>
+                    <div id="collapseOne6" class="panel-collapse collapse">
+                        <div class="panel-body">
+
+                            <!-- Nav tabs -->
+                            <ul class="nav nav-tabs" id="doctab6">
+                                <li class="active"><a href="#info6" data-toggle="tab">基础信息</a></li>
+                                <li><a href="#sandbox6" data-toggle="tab">在线测试</a></li>
+                                <li><a href="#sample6" data-toggle="tab">返回示例</a></li>
+                            </ul>
+
+                            <!-- Tab panes -->
+                            <div class="tab-content">
+
+                                <div class="tab-pane active" id="info6">
+                                    <div class="well">
+                                        发送验证码                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>Headers</strong></div>
+                                        <div class="panel-body">
+                                                                                        无
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>参数</strong></div>
+                                        <div class="panel-body">
+                                                                                        <table class="table table-hover">
+                                                <thead>
+                                                    <tr>
+                                                        <th>名称</th>
+                                                        <th>类型</th>
+                                                        <th>必选</th>
+                                                        <th>描述</th>
+                                                    </tr>
+                                                </thead>
+                                                <tbody>
+                                                                                                        <tr>
+                                                        <td>email</td>
+                                                        <td>string</td>
+                                                        <td>是</td>
+                                                        <td>邮箱</td>
+                                                    </tr>
+                                                                                                        <tr>
+                                                        <td>event</td>
+                                                        <td>string</td>
+                                                        <td>是</td>
+                                                        <td>事件名称</td>
+                                                    </tr>
+                                                                                                    </tbody>
+                                            </table>
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>正文</strong></div>
+                                        <div class="panel-body">
+                                            无                                        </div>
+                                    </div>
+                                </div><!-- #info -->
+
+                                <div class="tab-pane" id="sandbox6">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                                                                        <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>参数</strong></div>
+                                                <div class="panel-body">
+                                                    <form enctype="application/x-www-form-urlencoded" role="form" action="/api/ems/send" method="get" name="form6" id="form6">
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="email">email</label>
+                                                            <input type="string" class="form-control input-sm" id="email" required placeholder="邮箱" name="email">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="event">event</label>
+                                                            <input type="string" class="form-control input-sm" id="event" required placeholder="事件名称" name="event">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <button type="submit" class="btn btn-success send" rel="6">提交</button>
+                                                            <button type="reset" class="btn btn-info" rel="6">重置</button>
+                                                        </div>
+                                                    </form>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>响应输出</strong></div>
+                                                <div class="panel-body">
+                                                    <div class="row">
+                                                        <div class="col-md-12" style="overflow-x:auto">
+                                                            <pre id="response_headers6"></pre>
+                                                            <pre id="response6"></pre>
+                                                        </div>
+                                                    </div>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>返回参数</strong></div>
+                                                <div class="panel-body">
+                                                                                                        无
+                                                                                                    </div>
+                                            </div>
+                                        </div>
+                                    </div>
+                                </div><!-- #sandbox -->
+
+                                <div class="tab-pane" id="sample6">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                            <pre id="sample_response6">无</pre>
+                                        </div>
+                                    </div>
+                                </div><!-- #sample -->
+
+                            </div><!-- .tab-content -->
+                        </div>
+                    </div>
+                </div>
+                                <div class="panel panel-default">
+                    <div class="panel-heading" id="heading-7">
+                        <h4 class="panel-title">
+                            <span class="label label-success">GET</span>
+                            <a data-toggle="collapse" data-parent="#accordion7" href="#collapseOne7"> 检测验证码 <span class="text-muted">/api/ems/check</span></a>
+                        </h4>
+                    </div>
+                    <div id="collapseOne7" class="panel-collapse collapse">
+                        <div class="panel-body">
+
+                            <!-- Nav tabs -->
+                            <ul class="nav nav-tabs" id="doctab7">
+                                <li class="active"><a href="#info7" data-toggle="tab">基础信息</a></li>
+                                <li><a href="#sandbox7" data-toggle="tab">在线测试</a></li>
+                                <li><a href="#sample7" data-toggle="tab">返回示例</a></li>
+                            </ul>
+
+                            <!-- Tab panes -->
+                            <div class="tab-content">
+
+                                <div class="tab-pane active" id="info7">
+                                    <div class="well">
+                                        检测验证码                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>Headers</strong></div>
+                                        <div class="panel-body">
+                                                                                        无
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>参数</strong></div>
+                                        <div class="panel-body">
+                                                                                        <table class="table table-hover">
+                                                <thead>
+                                                    <tr>
+                                                        <th>名称</th>
+                                                        <th>类型</th>
+                                                        <th>必选</th>
+                                                        <th>描述</th>
+                                                    </tr>
+                                                </thead>
+                                                <tbody>
+                                                                                                        <tr>
+                                                        <td>email</td>
+                                                        <td>string</td>
+                                                        <td>是</td>
+                                                        <td>邮箱</td>
+                                                    </tr>
+                                                                                                        <tr>
+                                                        <td>event</td>
+                                                        <td>string</td>
+                                                        <td>是</td>
+                                                        <td>事件名称</td>
+                                                    </tr>
+                                                                                                        <tr>
+                                                        <td>captcha</td>
+                                                        <td>string</td>
+                                                        <td>是</td>
+                                                        <td>验证码</td>
+                                                    </tr>
+                                                                                                    </tbody>
+                                            </table>
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>正文</strong></div>
+                                        <div class="panel-body">
+                                            无                                        </div>
+                                    </div>
+                                </div><!-- #info -->
+
+                                <div class="tab-pane" id="sandbox7">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                                                                        <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>参数</strong></div>
+                                                <div class="panel-body">
+                                                    <form enctype="application/x-www-form-urlencoded" role="form" action="/api/ems/check" method="get" name="form7" id="form7">
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="email">email</label>
+                                                            <input type="string" class="form-control input-sm" id="email" required placeholder="邮箱" name="email">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="event">event</label>
+                                                            <input type="string" class="form-control input-sm" id="event" required placeholder="事件名称" name="event">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="captcha">captcha</label>
+                                                            <input type="string" class="form-control input-sm" id="captcha" required placeholder="验证码" name="captcha">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <button type="submit" class="btn btn-success send" rel="7">提交</button>
+                                                            <button type="reset" class="btn btn-info" rel="7">重置</button>
+                                                        </div>
+                                                    </form>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>响应输出</strong></div>
+                                                <div class="panel-body">
+                                                    <div class="row">
+                                                        <div class="col-md-12" style="overflow-x:auto">
+                                                            <pre id="response_headers7"></pre>
+                                                            <pre id="response7"></pre>
+                                                        </div>
+                                                    </div>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>返回参数</strong></div>
+                                                <div class="panel-body">
+                                                                                                        无
+                                                                                                    </div>
+                                            </div>
+                                        </div>
+                                    </div>
+                                </div><!-- #sandbox -->
+
+                                <div class="tab-pane" id="sample7">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                            <pre id="sample_response7">无</pre>
+                                        </div>
+                                    </div>
+                                </div><!-- #sample -->
+
+                            </div><!-- .tab-content -->
+                        </div>
+                    </div>
+                </div>
+                                <h2>首页接口</h2>
+                <hr>
+                                <div class="panel panel-default">
+                    <div class="panel-heading" id="heading-8">
+                        <h4 class="panel-title">
+                            <span class="label label-success">GET</span>
+                            <a data-toggle="collapse" data-parent="#accordion8" href="#collapseOne8"> 首页 <span class="text-muted">/api/index/index</span></a>
+                        </h4>
+                    </div>
+                    <div id="collapseOne8" class="panel-collapse collapse">
+                        <div class="panel-body">
+
+                            <!-- Nav tabs -->
+                            <ul class="nav nav-tabs" id="doctab8">
+                                <li class="active"><a href="#info8" data-toggle="tab">基础信息</a></li>
+                                <li><a href="#sandbox8" data-toggle="tab">在线测试</a></li>
+                                <li><a href="#sample8" data-toggle="tab">返回示例</a></li>
+                            </ul>
+
+                            <!-- Tab panes -->
+                            <div class="tab-content">
+
+                                <div class="tab-pane active" id="info8">
+                                    <div class="well">
+                                        首页                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>Headers</strong></div>
+                                        <div class="panel-body">
+                                                                                        无
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>参数</strong></div>
+                                        <div class="panel-body">
+                                                                                        无
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>正文</strong></div>
+                                        <div class="panel-body">
+                                            无                                        </div>
+                                    </div>
+                                </div><!-- #info -->
+
+                                <div class="tab-pane" id="sandbox8">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                                                                        <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>参数</strong></div>
+                                                <div class="panel-body">
+                                                    <form enctype="application/x-www-form-urlencoded" role="form" action="/api/index/index" method="get" name="form8" id="form8">
+                                                                                                                <div class="form-group">
+                                                            无
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <button type="submit" class="btn btn-success send" rel="8">提交</button>
+                                                            <button type="reset" class="btn btn-info" rel="8">重置</button>
+                                                        </div>
+                                                    </form>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>响应输出</strong></div>
+                                                <div class="panel-body">
+                                                    <div class="row">
+                                                        <div class="col-md-12" style="overflow-x:auto">
+                                                            <pre id="response_headers8"></pre>
+                                                            <pre id="response8"></pre>
+                                                        </div>
+                                                    </div>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>返回参数</strong></div>
+                                                <div class="panel-body">
+                                                                                                        无
+                                                                                                    </div>
+                                            </div>
+                                        </div>
+                                    </div>
+                                </div><!-- #sandbox -->
+
+                                <div class="tab-pane" id="sample8">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                            <pre id="sample_response8">无</pre>
+                                        </div>
+                                    </div>
+                                </div><!-- #sample -->
+
+                            </div><!-- .tab-content -->
+                        </div>
+                    </div>
+                </div>
+                                <h2>手机短信接口</h2>
+                <hr>
+                                <div class="panel panel-default">
+                    <div class="panel-heading" id="heading-9">
+                        <h4 class="panel-title">
+                            <span class="label label-success">GET</span>
+                            <a data-toggle="collapse" data-parent="#accordion9" href="#collapseOne9"> 发送验证码 <span class="text-muted">/api/sms/send</span></a>
+                        </h4>
+                    </div>
+                    <div id="collapseOne9" class="panel-collapse collapse">
+                        <div class="panel-body">
+
+                            <!-- Nav tabs -->
+                            <ul class="nav nav-tabs" id="doctab9">
+                                <li class="active"><a href="#info9" data-toggle="tab">基础信息</a></li>
+                                <li><a href="#sandbox9" data-toggle="tab">在线测试</a></li>
+                                <li><a href="#sample9" data-toggle="tab">返回示例</a></li>
+                            </ul>
+
+                            <!-- Tab panes -->
+                            <div class="tab-content">
+
+                                <div class="tab-pane active" id="info9">
+                                    <div class="well">
+                                        发送验证码                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>Headers</strong></div>
+                                        <div class="panel-body">
+                                                                                        无
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>参数</strong></div>
+                                        <div class="panel-body">
+                                                                                        <table class="table table-hover">
+                                                <thead>
+                                                    <tr>
+                                                        <th>名称</th>
+                                                        <th>类型</th>
+                                                        <th>必选</th>
+                                                        <th>描述</th>
+                                                    </tr>
+                                                </thead>
+                                                <tbody>
+                                                                                                        <tr>
+                                                        <td>mobile</td>
+                                                        <td>string</td>
+                                                        <td>是</td>
+                                                        <td>手机号</td>
+                                                    </tr>
+                                                                                                        <tr>
+                                                        <td>event</td>
+                                                        <td>string</td>
+                                                        <td>是</td>
+                                                        <td>事件名称</td>
+                                                    </tr>
+                                                                                                    </tbody>
+                                            </table>
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>正文</strong></div>
+                                        <div class="panel-body">
+                                            无                                        </div>
+                                    </div>
+                                </div><!-- #info -->
+
+                                <div class="tab-pane" id="sandbox9">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                                                                        <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>参数</strong></div>
+                                                <div class="panel-body">
+                                                    <form enctype="application/x-www-form-urlencoded" role="form" action="/api/sms/send" method="get" name="form9" id="form9">
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="mobile">mobile</label>
+                                                            <input type="string" class="form-control input-sm" id="mobile" required placeholder="手机号" name="mobile">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="event">event</label>
+                                                            <input type="string" class="form-control input-sm" id="event" required placeholder="事件名称" name="event">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <button type="submit" class="btn btn-success send" rel="9">提交</button>
+                                                            <button type="reset" class="btn btn-info" rel="9">重置</button>
+                                                        </div>
+                                                    </form>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>响应输出</strong></div>
+                                                <div class="panel-body">
+                                                    <div class="row">
+                                                        <div class="col-md-12" style="overflow-x:auto">
+                                                            <pre id="response_headers9"></pre>
+                                                            <pre id="response9"></pre>
+                                                        </div>
+                                                    </div>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>返回参数</strong></div>
+                                                <div class="panel-body">
+                                                                                                        无
+                                                                                                    </div>
+                                            </div>
+                                        </div>
+                                    </div>
+                                </div><!-- #sandbox -->
+
+                                <div class="tab-pane" id="sample9">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                            <pre id="sample_response9">无</pre>
+                                        </div>
+                                    </div>
+                                </div><!-- #sample -->
+
+                            </div><!-- .tab-content -->
+                        </div>
+                    </div>
+                </div>
+                                <div class="panel panel-default">
+                    <div class="panel-heading" id="heading-10">
+                        <h4 class="panel-title">
+                            <span class="label label-success">GET</span>
+                            <a data-toggle="collapse" data-parent="#accordion10" href="#collapseOne10"> 检测验证码 <span class="text-muted">/api/sms/check</span></a>
+                        </h4>
+                    </div>
+                    <div id="collapseOne10" class="panel-collapse collapse">
+                        <div class="panel-body">
+
+                            <!-- Nav tabs -->
+                            <ul class="nav nav-tabs" id="doctab10">
+                                <li class="active"><a href="#info10" data-toggle="tab">基础信息</a></li>
+                                <li><a href="#sandbox10" data-toggle="tab">在线测试</a></li>
+                                <li><a href="#sample10" data-toggle="tab">返回示例</a></li>
+                            </ul>
+
+                            <!-- Tab panes -->
+                            <div class="tab-content">
+
+                                <div class="tab-pane active" id="info10">
+                                    <div class="well">
+                                        检测验证码                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>Headers</strong></div>
+                                        <div class="panel-body">
+                                                                                        无
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>参数</strong></div>
+                                        <div class="panel-body">
+                                                                                        <table class="table table-hover">
+                                                <thead>
+                                                    <tr>
+                                                        <th>名称</th>
+                                                        <th>类型</th>
+                                                        <th>必选</th>
+                                                        <th>描述</th>
+                                                    </tr>
+                                                </thead>
+                                                <tbody>
+                                                                                                        <tr>
+                                                        <td>mobile</td>
+                                                        <td>string</td>
+                                                        <td>是</td>
+                                                        <td>手机号</td>
+                                                    </tr>
+                                                                                                        <tr>
+                                                        <td>event</td>
+                                                        <td>string</td>
+                                                        <td>是</td>
+                                                        <td>事件名称</td>
+                                                    </tr>
+                                                                                                        <tr>
+                                                        <td>captcha</td>
+                                                        <td>string</td>
+                                                        <td>是</td>
+                                                        <td>验证码</td>
+                                                    </tr>
+                                                                                                    </tbody>
+                                            </table>
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>正文</strong></div>
+                                        <div class="panel-body">
+                                            无                                        </div>
+                                    </div>
+                                </div><!-- #info -->
+
+                                <div class="tab-pane" id="sandbox10">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                                                                        <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>参数</strong></div>
+                                                <div class="panel-body">
+                                                    <form enctype="application/x-www-form-urlencoded" role="form" action="/api/sms/check" method="get" name="form10" id="form10">
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="mobile">mobile</label>
+                                                            <input type="string" class="form-control input-sm" id="mobile" required placeholder="手机号" name="mobile">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="event">event</label>
+                                                            <input type="string" class="form-control input-sm" id="event" required placeholder="事件名称" name="event">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="captcha">captcha</label>
+                                                            <input type="string" class="form-control input-sm" id="captcha" required placeholder="验证码" name="captcha">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <button type="submit" class="btn btn-success send" rel="10">提交</button>
+                                                            <button type="reset" class="btn btn-info" rel="10">重置</button>
+                                                        </div>
+                                                    </form>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>响应输出</strong></div>
+                                                <div class="panel-body">
+                                                    <div class="row">
+                                                        <div class="col-md-12" style="overflow-x:auto">
+                                                            <pre id="response_headers10"></pre>
+                                                            <pre id="response10"></pre>
+                                                        </div>
+                                                    </div>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>返回参数</strong></div>
+                                                <div class="panel-body">
+                                                                                                        无
+                                                                                                    </div>
+                                            </div>
+                                        </div>
+                                    </div>
+                                </div><!-- #sandbox -->
+
+                                <div class="tab-pane" id="sample10">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                            <pre id="sample_response10">无</pre>
+                                        </div>
+                                    </div>
+                                </div><!-- #sample -->
+
+                            </div><!-- .tab-content -->
+                        </div>
+                    </div>
+                </div>
+                                <h2>Token接口</h2>
+                <hr>
+                                <div class="panel panel-default">
+                    <div class="panel-heading" id="heading-11">
+                        <h4 class="panel-title">
+                            <span class="label label-success">GET</span>
+                            <a data-toggle="collapse" data-parent="#accordion11" href="#collapseOne11"> 检测Token是否过期 <span class="text-muted">/api/token/check</span></a>
+                        </h4>
+                    </div>
+                    <div id="collapseOne11" class="panel-collapse collapse">
+                        <div class="panel-body">
+
+                            <!-- Nav tabs -->
+                            <ul class="nav nav-tabs" id="doctab11">
+                                <li class="active"><a href="#info11" data-toggle="tab">基础信息</a></li>
+                                <li><a href="#sandbox11" data-toggle="tab">在线测试</a></li>
+                                <li><a href="#sample11" data-toggle="tab">返回示例</a></li>
+                            </ul>
+
+                            <!-- Tab panes -->
+                            <div class="tab-content">
+
+                                <div class="tab-pane active" id="info11">
+                                    <div class="well">
+                                        检测Token是否过期                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>Headers</strong></div>
+                                        <div class="panel-body">
+                                                                                        无
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>参数</strong></div>
+                                        <div class="panel-body">
+                                                                                        无
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>正文</strong></div>
+                                        <div class="panel-body">
+                                            无                                        </div>
+                                    </div>
+                                </div><!-- #info -->
+
+                                <div class="tab-pane" id="sandbox11">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                                                                        <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>参数</strong></div>
+                                                <div class="panel-body">
+                                                    <form enctype="application/x-www-form-urlencoded" role="form" action="/api/token/check" method="get" name="form11" id="form11">
+                                                                                                                <div class="form-group">
+                                                            无
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <button type="submit" class="btn btn-success send" rel="11">提交</button>
+                                                            <button type="reset" class="btn btn-info" rel="11">重置</button>
+                                                        </div>
+                                                    </form>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>响应输出</strong></div>
+                                                <div class="panel-body">
+                                                    <div class="row">
+                                                        <div class="col-md-12" style="overflow-x:auto">
+                                                            <pre id="response_headers11"></pre>
+                                                            <pre id="response11"></pre>
+                                                        </div>
+                                                    </div>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>返回参数</strong></div>
+                                                <div class="panel-body">
+                                                                                                        无
+                                                                                                    </div>
+                                            </div>
+                                        </div>
+                                    </div>
+                                </div><!-- #sandbox -->
+
+                                <div class="tab-pane" id="sample11">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                            <pre id="sample_response11">无</pre>
+                                        </div>
+                                    </div>
+                                </div><!-- #sample -->
+
+                            </div><!-- .tab-content -->
+                        </div>
+                    </div>
+                </div>
+                                <div class="panel panel-default">
+                    <div class="panel-heading" id="heading-12">
+                        <h4 class="panel-title">
+                            <span class="label label-success">GET</span>
+                            <a data-toggle="collapse" data-parent="#accordion12" href="#collapseOne12"> 刷新Token <span class="text-muted">/api/token/refresh</span></a>
+                        </h4>
+                    </div>
+                    <div id="collapseOne12" class="panel-collapse collapse">
+                        <div class="panel-body">
+
+                            <!-- Nav tabs -->
+                            <ul class="nav nav-tabs" id="doctab12">
+                                <li class="active"><a href="#info12" data-toggle="tab">基础信息</a></li>
+                                <li><a href="#sandbox12" data-toggle="tab">在线测试</a></li>
+                                <li><a href="#sample12" data-toggle="tab">返回示例</a></li>
+                            </ul>
+
+                            <!-- Tab panes -->
+                            <div class="tab-content">
+
+                                <div class="tab-pane active" id="info12">
+                                    <div class="well">
+                                        刷新Token                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>Headers</strong></div>
+                                        <div class="panel-body">
+                                                                                        无
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>参数</strong></div>
+                                        <div class="panel-body">
+                                                                                        无
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>正文</strong></div>
+                                        <div class="panel-body">
+                                            无                                        </div>
+                                    </div>
+                                </div><!-- #info -->
+
+                                <div class="tab-pane" id="sandbox12">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                                                                        <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>参数</strong></div>
+                                                <div class="panel-body">
+                                                    <form enctype="application/x-www-form-urlencoded" role="form" action="/api/token/refresh" method="get" name="form12" id="form12">
+                                                                                                                <div class="form-group">
+                                                            无
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <button type="submit" class="btn btn-success send" rel="12">提交</button>
+                                                            <button type="reset" class="btn btn-info" rel="12">重置</button>
+                                                        </div>
+                                                    </form>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>响应输出</strong></div>
+                                                <div class="panel-body">
+                                                    <div class="row">
+                                                        <div class="col-md-12" style="overflow-x:auto">
+                                                            <pre id="response_headers12"></pre>
+                                                            <pre id="response12"></pre>
+                                                        </div>
+                                                    </div>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>返回参数</strong></div>
+                                                <div class="panel-body">
+                                                                                                        无
+                                                                                                    </div>
+                                            </div>
+                                        </div>
+                                    </div>
+                                </div><!-- #sandbox -->
+
+                                <div class="tab-pane" id="sample12">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                            <pre id="sample_response12">无</pre>
+                                        </div>
+                                    </div>
+                                </div><!-- #sample -->
+
+                            </div><!-- .tab-content -->
+                        </div>
+                    </div>
+                </div>
+                                <h2>会员接口</h2>
+                <hr>
+                                <div class="panel panel-default">
+                    <div class="panel-heading" id="heading-13">
+                        <h4 class="panel-title">
+                            <span class="label label-success">GET</span>
+                            <a data-toggle="collapse" data-parent="#accordion13" href="#collapseOne13"> 会员中心 <span class="text-muted">/api/user/index</span></a>
+                        </h4>
+                    </div>
+                    <div id="collapseOne13" class="panel-collapse collapse">
+                        <div class="panel-body">
+
+                            <!-- Nav tabs -->
+                            <ul class="nav nav-tabs" id="doctab13">
+                                <li class="active"><a href="#info13" data-toggle="tab">基础信息</a></li>
+                                <li><a href="#sandbox13" data-toggle="tab">在线测试</a></li>
+                                <li><a href="#sample13" data-toggle="tab">返回示例</a></li>
+                            </ul>
+
+                            <!-- Tab panes -->
+                            <div class="tab-content">
+
+                                <div class="tab-pane active" id="info13">
+                                    <div class="well">
+                                        会员中心                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>Headers</strong></div>
+                                        <div class="panel-body">
+                                                                                        无
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>参数</strong></div>
+                                        <div class="panel-body">
+                                                                                        无
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>正文</strong></div>
+                                        <div class="panel-body">
+                                            无                                        </div>
+                                    </div>
+                                </div><!-- #info -->
+
+                                <div class="tab-pane" id="sandbox13">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                                                                        <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>参数</strong></div>
+                                                <div class="panel-body">
+                                                    <form enctype="application/x-www-form-urlencoded" role="form" action="/api/user/index" method="get" name="form13" id="form13">
+                                                                                                                <div class="form-group">
+                                                            无
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <button type="submit" class="btn btn-success send" rel="13">提交</button>
+                                                            <button type="reset" class="btn btn-info" rel="13">重置</button>
+                                                        </div>
+                                                    </form>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>响应输出</strong></div>
+                                                <div class="panel-body">
+                                                    <div class="row">
+                                                        <div class="col-md-12" style="overflow-x:auto">
+                                                            <pre id="response_headers13"></pre>
+                                                            <pre id="response13"></pre>
+                                                        </div>
+                                                    </div>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>返回参数</strong></div>
+                                                <div class="panel-body">
+                                                                                                        无
+                                                                                                    </div>
+                                            </div>
+                                        </div>
+                                    </div>
+                                </div><!-- #sandbox -->
+
+                                <div class="tab-pane" id="sample13">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                            <pre id="sample_response13">无</pre>
+                                        </div>
+                                    </div>
+                                </div><!-- #sample -->
+
+                            </div><!-- .tab-content -->
+                        </div>
+                    </div>
+                </div>
+                                <div class="panel panel-default">
+                    <div class="panel-heading" id="heading-14">
+                        <h4 class="panel-title">
+                            <span class="label label-success">GET</span>
+                            <a data-toggle="collapse" data-parent="#accordion14" href="#collapseOne14"> 会员登录 <span class="text-muted">/api/user/login</span></a>
+                        </h4>
+                    </div>
+                    <div id="collapseOne14" class="panel-collapse collapse">
+                        <div class="panel-body">
+
+                            <!-- Nav tabs -->
+                            <ul class="nav nav-tabs" id="doctab14">
+                                <li class="active"><a href="#info14" data-toggle="tab">基础信息</a></li>
+                                <li><a href="#sandbox14" data-toggle="tab">在线测试</a></li>
+                                <li><a href="#sample14" data-toggle="tab">返回示例</a></li>
+                            </ul>
+
+                            <!-- Tab panes -->
+                            <div class="tab-content">
+
+                                <div class="tab-pane active" id="info14">
+                                    <div class="well">
+                                        会员登录                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>Headers</strong></div>
+                                        <div class="panel-body">
+                                                                                        无
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>参数</strong></div>
+                                        <div class="panel-body">
+                                                                                        <table class="table table-hover">
+                                                <thead>
+                                                    <tr>
+                                                        <th>名称</th>
+                                                        <th>类型</th>
+                                                        <th>必选</th>
+                                                        <th>描述</th>
+                                                    </tr>
+                                                </thead>
+                                                <tbody>
+                                                                                                        <tr>
+                                                        <td>account</td>
+                                                        <td>string</td>
+                                                        <td>是</td>
+                                                        <td>账号</td>
+                                                    </tr>
+                                                                                                        <tr>
+                                                        <td>password</td>
+                                                        <td>string</td>
+                                                        <td>是</td>
+                                                        <td>密码</td>
+                                                    </tr>
+                                                                                                    </tbody>
+                                            </table>
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>正文</strong></div>
+                                        <div class="panel-body">
+                                            无                                        </div>
+                                    </div>
+                                </div><!-- #info -->
+
+                                <div class="tab-pane" id="sandbox14">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                                                                        <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>参数</strong></div>
+                                                <div class="panel-body">
+                                                    <form enctype="application/x-www-form-urlencoded" role="form" action="/api/user/login" method="get" name="form14" id="form14">
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="account">account</label>
+                                                            <input type="string" class="form-control input-sm" id="account" required placeholder="账号" name="account">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="password">password</label>
+                                                            <input type="string" class="form-control input-sm" id="password" required placeholder="密码" name="password">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <button type="submit" class="btn btn-success send" rel="14">提交</button>
+                                                            <button type="reset" class="btn btn-info" rel="14">重置</button>
+                                                        </div>
+                                                    </form>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>响应输出</strong></div>
+                                                <div class="panel-body">
+                                                    <div class="row">
+                                                        <div class="col-md-12" style="overflow-x:auto">
+                                                            <pre id="response_headers14"></pre>
+                                                            <pre id="response14"></pre>
+                                                        </div>
+                                                    </div>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>返回参数</strong></div>
+                                                <div class="panel-body">
+                                                                                                        无
+                                                                                                    </div>
+                                            </div>
+                                        </div>
+                                    </div>
+                                </div><!-- #sandbox -->
+
+                                <div class="tab-pane" id="sample14">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                            <pre id="sample_response14">无</pre>
+                                        </div>
+                                    </div>
+                                </div><!-- #sample -->
+
+                            </div><!-- .tab-content -->
+                        </div>
+                    </div>
+                </div>
+                                <div class="panel panel-default">
+                    <div class="panel-heading" id="heading-15">
+                        <h4 class="panel-title">
+                            <span class="label label-success">GET</span>
+                            <a data-toggle="collapse" data-parent="#accordion15" href="#collapseOne15"> 手机验证码登录 <span class="text-muted">/api/user/mobilelogin</span></a>
+                        </h4>
+                    </div>
+                    <div id="collapseOne15" class="panel-collapse collapse">
+                        <div class="panel-body">
+
+                            <!-- Nav tabs -->
+                            <ul class="nav nav-tabs" id="doctab15">
+                                <li class="active"><a href="#info15" data-toggle="tab">基础信息</a></li>
+                                <li><a href="#sandbox15" data-toggle="tab">在线测试</a></li>
+                                <li><a href="#sample15" data-toggle="tab">返回示例</a></li>
+                            </ul>
+
+                            <!-- Tab panes -->
+                            <div class="tab-content">
+
+                                <div class="tab-pane active" id="info15">
+                                    <div class="well">
+                                        手机验证码登录                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>Headers</strong></div>
+                                        <div class="panel-body">
+                                                                                        无
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>参数</strong></div>
+                                        <div class="panel-body">
+                                                                                        <table class="table table-hover">
+                                                <thead>
+                                                    <tr>
+                                                        <th>名称</th>
+                                                        <th>类型</th>
+                                                        <th>必选</th>
+                                                        <th>描述</th>
+                                                    </tr>
+                                                </thead>
+                                                <tbody>
+                                                                                                        <tr>
+                                                        <td>mobile</td>
+                                                        <td>string</td>
+                                                        <td>是</td>
+                                                        <td>手机号</td>
+                                                    </tr>
+                                                                                                        <tr>
+                                                        <td>captcha</td>
+                                                        <td>string</td>
+                                                        <td>是</td>
+                                                        <td>验证码</td>
+                                                    </tr>
+                                                                                                    </tbody>
+                                            </table>
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>正文</strong></div>
+                                        <div class="panel-body">
+                                            无                                        </div>
+                                    </div>
+                                </div><!-- #info -->
+
+                                <div class="tab-pane" id="sandbox15">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                                                                        <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>参数</strong></div>
+                                                <div class="panel-body">
+                                                    <form enctype="application/x-www-form-urlencoded" role="form" action="/api/user/mobilelogin" method="get" name="form15" id="form15">
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="mobile">mobile</label>
+                                                            <input type="string" class="form-control input-sm" id="mobile" required placeholder="手机号" name="mobile">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="captcha">captcha</label>
+                                                            <input type="string" class="form-control input-sm" id="captcha" required placeholder="验证码" name="captcha">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <button type="submit" class="btn btn-success send" rel="15">提交</button>
+                                                            <button type="reset" class="btn btn-info" rel="15">重置</button>
+                                                        </div>
+                                                    </form>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>响应输出</strong></div>
+                                                <div class="panel-body">
+                                                    <div class="row">
+                                                        <div class="col-md-12" style="overflow-x:auto">
+                                                            <pre id="response_headers15"></pre>
+                                                            <pre id="response15"></pre>
+                                                        </div>
+                                                    </div>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>返回参数</strong></div>
+                                                <div class="panel-body">
+                                                                                                        无
+                                                                                                    </div>
+                                            </div>
+                                        </div>
+                                    </div>
+                                </div><!-- #sandbox -->
+
+                                <div class="tab-pane" id="sample15">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                            <pre id="sample_response15">无</pre>
+                                        </div>
+                                    </div>
+                                </div><!-- #sample -->
+
+                            </div><!-- .tab-content -->
+                        </div>
+                    </div>
+                </div>
+                                <div class="panel panel-default">
+                    <div class="panel-heading" id="heading-16">
+                        <h4 class="panel-title">
+                            <span class="label label-success">GET</span>
+                            <a data-toggle="collapse" data-parent="#accordion16" href="#collapseOne16"> 注册会员 <span class="text-muted">/api/user/register</span></a>
+                        </h4>
+                    </div>
+                    <div id="collapseOne16" class="panel-collapse collapse">
+                        <div class="panel-body">
+
+                            <!-- Nav tabs -->
+                            <ul class="nav nav-tabs" id="doctab16">
+                                <li class="active"><a href="#info16" data-toggle="tab">基础信息</a></li>
+                                <li><a href="#sandbox16" data-toggle="tab">在线测试</a></li>
+                                <li><a href="#sample16" data-toggle="tab">返回示例</a></li>
+                            </ul>
+
+                            <!-- Tab panes -->
+                            <div class="tab-content">
+
+                                <div class="tab-pane active" id="info16">
+                                    <div class="well">
+                                        注册会员                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>Headers</strong></div>
+                                        <div class="panel-body">
+                                                                                        无
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>参数</strong></div>
+                                        <div class="panel-body">
+                                                                                        <table class="table table-hover">
+                                                <thead>
+                                                    <tr>
+                                                        <th>名称</th>
+                                                        <th>类型</th>
+                                                        <th>必选</th>
+                                                        <th>描述</th>
+                                                    </tr>
+                                                </thead>
+                                                <tbody>
+                                                                                                        <tr>
+                                                        <td>username</td>
+                                                        <td>string</td>
+                                                        <td>是</td>
+                                                        <td>用户名</td>
+                                                    </tr>
+                                                                                                        <tr>
+                                                        <td>password</td>
+                                                        <td>string</td>
+                                                        <td>是</td>
+                                                        <td>密码</td>
+                                                    </tr>
+                                                                                                        <tr>
+                                                        <td>email</td>
+                                                        <td>string</td>
+                                                        <td>是</td>
+                                                        <td>邮箱</td>
+                                                    </tr>
+                                                                                                        <tr>
+                                                        <td>mobile</td>
+                                                        <td>string</td>
+                                                        <td>是</td>
+                                                        <td>手机号</td>
+                                                    </tr>
+                                                                                                    </tbody>
+                                            </table>
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>正文</strong></div>
+                                        <div class="panel-body">
+                                            无                                        </div>
+                                    </div>
+                                </div><!-- #info -->
+
+                                <div class="tab-pane" id="sandbox16">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                                                                        <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>参数</strong></div>
+                                                <div class="panel-body">
+                                                    <form enctype="application/x-www-form-urlencoded" role="form" action="/api/user/register" method="get" name="form16" id="form16">
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="username">username</label>
+                                                            <input type="string" class="form-control input-sm" id="username" required placeholder="用户名" name="username">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="password">password</label>
+                                                            <input type="string" class="form-control input-sm" id="password" required placeholder="密码" name="password">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="email">email</label>
+                                                            <input type="string" class="form-control input-sm" id="email" required placeholder="邮箱" name="email">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="mobile">mobile</label>
+                                                            <input type="string" class="form-control input-sm" id="mobile" required placeholder="手机号" name="mobile">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <button type="submit" class="btn btn-success send" rel="16">提交</button>
+                                                            <button type="reset" class="btn btn-info" rel="16">重置</button>
+                                                        </div>
+                                                    </form>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>响应输出</strong></div>
+                                                <div class="panel-body">
+                                                    <div class="row">
+                                                        <div class="col-md-12" style="overflow-x:auto">
+                                                            <pre id="response_headers16"></pre>
+                                                            <pre id="response16"></pre>
+                                                        </div>
+                                                    </div>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>返回参数</strong></div>
+                                                <div class="panel-body">
+                                                                                                        无
+                                                                                                    </div>
+                                            </div>
+                                        </div>
+                                    </div>
+                                </div><!-- #sandbox -->
+
+                                <div class="tab-pane" id="sample16">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                            <pre id="sample_response16">无</pre>
+                                        </div>
+                                    </div>
+                                </div><!-- #sample -->
+
+                            </div><!-- .tab-content -->
+                        </div>
+                    </div>
+                </div>
+                                <div class="panel panel-default">
+                    <div class="panel-heading" id="heading-17">
+                        <h4 class="panel-title">
+                            <span class="label label-success">GET</span>
+                            <a data-toggle="collapse" data-parent="#accordion17" href="#collapseOne17"> 注销登录 <span class="text-muted">/api/user/logout</span></a>
+                        </h4>
+                    </div>
+                    <div id="collapseOne17" class="panel-collapse collapse">
+                        <div class="panel-body">
+
+                            <!-- Nav tabs -->
+                            <ul class="nav nav-tabs" id="doctab17">
+                                <li class="active"><a href="#info17" data-toggle="tab">基础信息</a></li>
+                                <li><a href="#sandbox17" data-toggle="tab">在线测试</a></li>
+                                <li><a href="#sample17" data-toggle="tab">返回示例</a></li>
+                            </ul>
+
+                            <!-- Tab panes -->
+                            <div class="tab-content">
+
+                                <div class="tab-pane active" id="info17">
+                                    <div class="well">
+                                        注销登录                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>Headers</strong></div>
+                                        <div class="panel-body">
+                                                                                        无
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>参数</strong></div>
+                                        <div class="panel-body">
+                                                                                        无
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>正文</strong></div>
+                                        <div class="panel-body">
+                                            无                                        </div>
+                                    </div>
+                                </div><!-- #info -->
+
+                                <div class="tab-pane" id="sandbox17">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                                                                        <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>参数</strong></div>
+                                                <div class="panel-body">
+                                                    <form enctype="application/x-www-form-urlencoded" role="form" action="/api/user/logout" method="get" name="form17" id="form17">
+                                                                                                                <div class="form-group">
+                                                            无
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <button type="submit" class="btn btn-success send" rel="17">提交</button>
+                                                            <button type="reset" class="btn btn-info" rel="17">重置</button>
+                                                        </div>
+                                                    </form>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>响应输出</strong></div>
+                                                <div class="panel-body">
+                                                    <div class="row">
+                                                        <div class="col-md-12" style="overflow-x:auto">
+                                                            <pre id="response_headers17"></pre>
+                                                            <pre id="response17"></pre>
+                                                        </div>
+                                                    </div>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>返回参数</strong></div>
+                                                <div class="panel-body">
+                                                                                                        无
+                                                                                                    </div>
+                                            </div>
+                                        </div>
+                                    </div>
+                                </div><!-- #sandbox -->
+
+                                <div class="tab-pane" id="sample17">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                            <pre id="sample_response17">无</pre>
+                                        </div>
+                                    </div>
+                                </div><!-- #sample -->
+
+                            </div><!-- .tab-content -->
+                        </div>
+                    </div>
+                </div>
+                                <div class="panel panel-default">
+                    <div class="panel-heading" id="heading-18">
+                        <h4 class="panel-title">
+                            <span class="label label-success">GET</span>
+                            <a data-toggle="collapse" data-parent="#accordion18" href="#collapseOne18"> 修改会员个人信息 <span class="text-muted">/api/user/profile</span></a>
+                        </h4>
+                    </div>
+                    <div id="collapseOne18" class="panel-collapse collapse">
+                        <div class="panel-body">
+
+                            <!-- Nav tabs -->
+                            <ul class="nav nav-tabs" id="doctab18">
+                                <li class="active"><a href="#info18" data-toggle="tab">基础信息</a></li>
+                                <li><a href="#sandbox18" data-toggle="tab">在线测试</a></li>
+                                <li><a href="#sample18" data-toggle="tab">返回示例</a></li>
+                            </ul>
+
+                            <!-- Tab panes -->
+                            <div class="tab-content">
+
+                                <div class="tab-pane active" id="info18">
+                                    <div class="well">
+                                        修改会员个人信息                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>Headers</strong></div>
+                                        <div class="panel-body">
+                                                                                        无
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>参数</strong></div>
+                                        <div class="panel-body">
+                                                                                        <table class="table table-hover">
+                                                <thead>
+                                                    <tr>
+                                                        <th>名称</th>
+                                                        <th>类型</th>
+                                                        <th>必选</th>
+                                                        <th>描述</th>
+                                                    </tr>
+                                                </thead>
+                                                <tbody>
+                                                                                                        <tr>
+                                                        <td>avatar</td>
+                                                        <td>string</td>
+                                                        <td>是</td>
+                                                        <td>头像地址</td>
+                                                    </tr>
+                                                                                                        <tr>
+                                                        <td>username</td>
+                                                        <td>string</td>
+                                                        <td>是</td>
+                                                        <td>用户名</td>
+                                                    </tr>
+                                                                                                        <tr>
+                                                        <td>nickname</td>
+                                                        <td>string</td>
+                                                        <td>是</td>
+                                                        <td>昵称</td>
+                                                    </tr>
+                                                                                                        <tr>
+                                                        <td>bio</td>
+                                                        <td>string</td>
+                                                        <td>是</td>
+                                                        <td>个人简介</td>
+                                                    </tr>
+                                                                                                    </tbody>
+                                            </table>
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>正文</strong></div>
+                                        <div class="panel-body">
+                                            无                                        </div>
+                                    </div>
+                                </div><!-- #info -->
+
+                                <div class="tab-pane" id="sandbox18">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                                                                        <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>参数</strong></div>
+                                                <div class="panel-body">
+                                                    <form enctype="application/x-www-form-urlencoded" role="form" action="/api/user/profile" method="get" name="form18" id="form18">
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="avatar">avatar</label>
+                                                            <input type="string" class="form-control input-sm" id="avatar" required placeholder="头像地址" name="avatar">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="username">username</label>
+                                                            <input type="string" class="form-control input-sm" id="username" required placeholder="用户名" name="username">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="nickname">nickname</label>
+                                                            <input type="string" class="form-control input-sm" id="nickname" required placeholder="昵称" name="nickname">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="bio">bio</label>
+                                                            <input type="string" class="form-control input-sm" id="bio" required placeholder="个人简介" name="bio">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <button type="submit" class="btn btn-success send" rel="18">提交</button>
+                                                            <button type="reset" class="btn btn-info" rel="18">重置</button>
+                                                        </div>
+                                                    </form>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>响应输出</strong></div>
+                                                <div class="panel-body">
+                                                    <div class="row">
+                                                        <div class="col-md-12" style="overflow-x:auto">
+                                                            <pre id="response_headers18"></pre>
+                                                            <pre id="response18"></pre>
+                                                        </div>
+                                                    </div>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>返回参数</strong></div>
+                                                <div class="panel-body">
+                                                                                                        无
+                                                                                                    </div>
+                                            </div>
+                                        </div>
+                                    </div>
+                                </div><!-- #sandbox -->
+
+                                <div class="tab-pane" id="sample18">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                            <pre id="sample_response18">无</pre>
+                                        </div>
+                                    </div>
+                                </div><!-- #sample -->
+
+                            </div><!-- .tab-content -->
+                        </div>
+                    </div>
+                </div>
+                                <div class="panel panel-default">
+                    <div class="panel-heading" id="heading-19">
+                        <h4 class="panel-title">
+                            <span class="label label-success">GET</span>
+                            <a data-toggle="collapse" data-parent="#accordion19" href="#collapseOne19"> 修改邮箱 <span class="text-muted">/api/user/changeemail</span></a>
+                        </h4>
+                    </div>
+                    <div id="collapseOne19" class="panel-collapse collapse">
+                        <div class="panel-body">
+
+                            <!-- Nav tabs -->
+                            <ul class="nav nav-tabs" id="doctab19">
+                                <li class="active"><a href="#info19" data-toggle="tab">基础信息</a></li>
+                                <li><a href="#sandbox19" data-toggle="tab">在线测试</a></li>
+                                <li><a href="#sample19" data-toggle="tab">返回示例</a></li>
+                            </ul>
+
+                            <!-- Tab panes -->
+                            <div class="tab-content">
+
+                                <div class="tab-pane active" id="info19">
+                                    <div class="well">
+                                        修改邮箱                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>Headers</strong></div>
+                                        <div class="panel-body">
+                                                                                        无
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>参数</strong></div>
+                                        <div class="panel-body">
+                                                                                        <table class="table table-hover">
+                                                <thead>
+                                                    <tr>
+                                                        <th>名称</th>
+                                                        <th>类型</th>
+                                                        <th>必选</th>
+                                                        <th>描述</th>
+                                                    </tr>
+                                                </thead>
+                                                <tbody>
+                                                                                                        <tr>
+                                                        <td>email</td>
+                                                        <td>string</td>
+                                                        <td>是</td>
+                                                        <td>邮箱</td>
+                                                    </tr>
+                                                                                                        <tr>
+                                                        <td>captcha</td>
+                                                        <td>string</td>
+                                                        <td>是</td>
+                                                        <td>验证码</td>
+                                                    </tr>
+                                                                                                    </tbody>
+                                            </table>
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>正文</strong></div>
+                                        <div class="panel-body">
+                                            无                                        </div>
+                                    </div>
+                                </div><!-- #info -->
+
+                                <div class="tab-pane" id="sandbox19">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                                                                        <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>参数</strong></div>
+                                                <div class="panel-body">
+                                                    <form enctype="application/x-www-form-urlencoded" role="form" action="/api/user/changeemail" method="get" name="form19" id="form19">
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="email">email</label>
+                                                            <input type="string" class="form-control input-sm" id="email" required placeholder="邮箱" name="email">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="captcha">captcha</label>
+                                                            <input type="string" class="form-control input-sm" id="captcha" required placeholder="验证码" name="captcha">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <button type="submit" class="btn btn-success send" rel="19">提交</button>
+                                                            <button type="reset" class="btn btn-info" rel="19">重置</button>
+                                                        </div>
+                                                    </form>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>响应输出</strong></div>
+                                                <div class="panel-body">
+                                                    <div class="row">
+                                                        <div class="col-md-12" style="overflow-x:auto">
+                                                            <pre id="response_headers19"></pre>
+                                                            <pre id="response19"></pre>
+                                                        </div>
+                                                    </div>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>返回参数</strong></div>
+                                                <div class="panel-body">
+                                                                                                        无
+                                                                                                    </div>
+                                            </div>
+                                        </div>
+                                    </div>
+                                </div><!-- #sandbox -->
+
+                                <div class="tab-pane" id="sample19">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                            <pre id="sample_response19">无</pre>
+                                        </div>
+                                    </div>
+                                </div><!-- #sample -->
+
+                            </div><!-- .tab-content -->
+                        </div>
+                    </div>
+                </div>
+                                <div class="panel panel-default">
+                    <div class="panel-heading" id="heading-20">
+                        <h4 class="panel-title">
+                            <span class="label label-success">GET</span>
+                            <a data-toggle="collapse" data-parent="#accordion20" href="#collapseOne20"> 修改手机号 <span class="text-muted">/api/user/changemobile</span></a>
+                        </h4>
+                    </div>
+                    <div id="collapseOne20" class="panel-collapse collapse">
+                        <div class="panel-body">
+
+                            <!-- Nav tabs -->
+                            <ul class="nav nav-tabs" id="doctab20">
+                                <li class="active"><a href="#info20" data-toggle="tab">基础信息</a></li>
+                                <li><a href="#sandbox20" data-toggle="tab">在线测试</a></li>
+                                <li><a href="#sample20" data-toggle="tab">返回示例</a></li>
+                            </ul>
+
+                            <!-- Tab panes -->
+                            <div class="tab-content">
+
+                                <div class="tab-pane active" id="info20">
+                                    <div class="well">
+                                        修改手机号                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>Headers</strong></div>
+                                        <div class="panel-body">
+                                                                                        无
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>参数</strong></div>
+                                        <div class="panel-body">
+                                                                                        <table class="table table-hover">
+                                                <thead>
+                                                    <tr>
+                                                        <th>名称</th>
+                                                        <th>类型</th>
+                                                        <th>必选</th>
+                                                        <th>描述</th>
+                                                    </tr>
+                                                </thead>
+                                                <tbody>
+                                                                                                        <tr>
+                                                        <td>email</td>
+                                                        <td>string</td>
+                                                        <td>是</td>
+                                                        <td>手机号</td>
+                                                    </tr>
+                                                                                                        <tr>
+                                                        <td>captcha</td>
+                                                        <td>string</td>
+                                                        <td>是</td>
+                                                        <td>验证码</td>
+                                                    </tr>
+                                                                                                    </tbody>
+                                            </table>
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>正文</strong></div>
+                                        <div class="panel-body">
+                                            无                                        </div>
+                                    </div>
+                                </div><!-- #info -->
+
+                                <div class="tab-pane" id="sandbox20">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                                                                        <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>参数</strong></div>
+                                                <div class="panel-body">
+                                                    <form enctype="application/x-www-form-urlencoded" role="form" action="/api/user/changemobile" method="get" name="form20" id="form20">
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="email">email</label>
+                                                            <input type="string" class="form-control input-sm" id="email" required placeholder="手机号" name="email">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="captcha">captcha</label>
+                                                            <input type="string" class="form-control input-sm" id="captcha" required placeholder="验证码" name="captcha">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <button type="submit" class="btn btn-success send" rel="20">提交</button>
+                                                            <button type="reset" class="btn btn-info" rel="20">重置</button>
+                                                        </div>
+                                                    </form>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>响应输出</strong></div>
+                                                <div class="panel-body">
+                                                    <div class="row">
+                                                        <div class="col-md-12" style="overflow-x:auto">
+                                                            <pre id="response_headers20"></pre>
+                                                            <pre id="response20"></pre>
+                                                        </div>
+                                                    </div>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>返回参数</strong></div>
+                                                <div class="panel-body">
+                                                                                                        无
+                                                                                                    </div>
+                                            </div>
+                                        </div>
+                                    </div>
+                                </div><!-- #sandbox -->
+
+                                <div class="tab-pane" id="sample20">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                            <pre id="sample_response20">无</pre>
+                                        </div>
+                                    </div>
+                                </div><!-- #sample -->
+
+                            </div><!-- .tab-content -->
+                        </div>
+                    </div>
+                </div>
+                                <div class="panel panel-default">
+                    <div class="panel-heading" id="heading-21">
+                        <h4 class="panel-title">
+                            <span class="label label-success">GET</span>
+                            <a data-toggle="collapse" data-parent="#accordion21" href="#collapseOne21"> 第三方登录 <span class="text-muted">/api/user/third</span></a>
+                        </h4>
+                    </div>
+                    <div id="collapseOne21" class="panel-collapse collapse">
+                        <div class="panel-body">
+
+                            <!-- Nav tabs -->
+                            <ul class="nav nav-tabs" id="doctab21">
+                                <li class="active"><a href="#info21" data-toggle="tab">基础信息</a></li>
+                                <li><a href="#sandbox21" data-toggle="tab">在线测试</a></li>
+                                <li><a href="#sample21" data-toggle="tab">返回示例</a></li>
+                            </ul>
+
+                            <!-- Tab panes -->
+                            <div class="tab-content">
+
+                                <div class="tab-pane active" id="info21">
+                                    <div class="well">
+                                        第三方登录                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>Headers</strong></div>
+                                        <div class="panel-body">
+                                                                                        无
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>参数</strong></div>
+                                        <div class="panel-body">
+                                                                                        <table class="table table-hover">
+                                                <thead>
+                                                    <tr>
+                                                        <th>名称</th>
+                                                        <th>类型</th>
+                                                        <th>必选</th>
+                                                        <th>描述</th>
+                                                    </tr>
+                                                </thead>
+                                                <tbody>
+                                                                                                        <tr>
+                                                        <td>platform</td>
+                                                        <td>string</td>
+                                                        <td>是</td>
+                                                        <td>平台名称</td>
+                                                    </tr>
+                                                                                                        <tr>
+                                                        <td>code</td>
+                                                        <td>string</td>
+                                                        <td>是</td>
+                                                        <td>Code码</td>
+                                                    </tr>
+                                                                                                    </tbody>
+                                            </table>
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>正文</strong></div>
+                                        <div class="panel-body">
+                                            无                                        </div>
+                                    </div>
+                                </div><!-- #info -->
+
+                                <div class="tab-pane" id="sandbox21">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                                                                        <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>参数</strong></div>
+                                                <div class="panel-body">
+                                                    <form enctype="application/x-www-form-urlencoded" role="form" action="/api/user/third" method="get" name="form21" id="form21">
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="platform">platform</label>
+                                                            <input type="string" class="form-control input-sm" id="platform" required placeholder="平台名称" name="platform">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="code">code</label>
+                                                            <input type="string" class="form-control input-sm" id="code" required placeholder="Code码" name="code">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <button type="submit" class="btn btn-success send" rel="21">提交</button>
+                                                            <button type="reset" class="btn btn-info" rel="21">重置</button>
+                                                        </div>
+                                                    </form>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>响应输出</strong></div>
+                                                <div class="panel-body">
+                                                    <div class="row">
+                                                        <div class="col-md-12" style="overflow-x:auto">
+                                                            <pre id="response_headers21"></pre>
+                                                            <pre id="response21"></pre>
+                                                        </div>
+                                                    </div>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>返回参数</strong></div>
+                                                <div class="panel-body">
+                                                                                                        无
+                                                                                                    </div>
+                                            </div>
+                                        </div>
+                                    </div>
+                                </div><!-- #sandbox -->
+
+                                <div class="tab-pane" id="sample21">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                            <pre id="sample_response21">无</pre>
+                                        </div>
+                                    </div>
+                                </div><!-- #sample -->
+
+                            </div><!-- .tab-content -->
+                        </div>
+                    </div>
+                </div>
+                                <div class="panel panel-default">
+                    <div class="panel-heading" id="heading-22">
+                        <h4 class="panel-title">
+                            <span class="label label-success">GET</span>
+                            <a data-toggle="collapse" data-parent="#accordion22" href="#collapseOne22"> 重置密码 <span class="text-muted">/api/user/resetpwd</span></a>
+                        </h4>
+                    </div>
+                    <div id="collapseOne22" class="panel-collapse collapse">
+                        <div class="panel-body">
+
+                            <!-- Nav tabs -->
+                            <ul class="nav nav-tabs" id="doctab22">
+                                <li class="active"><a href="#info22" data-toggle="tab">基础信息</a></li>
+                                <li><a href="#sandbox22" data-toggle="tab">在线测试</a></li>
+                                <li><a href="#sample22" data-toggle="tab">返回示例</a></li>
+                            </ul>
+
+                            <!-- Tab panes -->
+                            <div class="tab-content">
+
+                                <div class="tab-pane active" id="info22">
+                                    <div class="well">
+                                        重置密码                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>Headers</strong></div>
+                                        <div class="panel-body">
+                                                                                        无
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>参数</strong></div>
+                                        <div class="panel-body">
+                                                                                        <table class="table table-hover">
+                                                <thead>
+                                                    <tr>
+                                                        <th>名称</th>
+                                                        <th>类型</th>
+                                                        <th>必选</th>
+                                                        <th>描述</th>
+                                                    </tr>
+                                                </thead>
+                                                <tbody>
+                                                                                                        <tr>
+                                                        <td>mobile</td>
+                                                        <td>string</td>
+                                                        <td>是</td>
+                                                        <td>手机号</td>
+                                                    </tr>
+                                                                                                        <tr>
+                                                        <td>newpassword</td>
+                                                        <td>string</td>
+                                                        <td>是</td>
+                                                        <td>新密码</td>
+                                                    </tr>
+                                                                                                        <tr>
+                                                        <td>captcha</td>
+                                                        <td>string</td>
+                                                        <td>是</td>
+                                                        <td>验证码</td>
+                                                    </tr>
+                                                                                                    </tbody>
+                                            </table>
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>正文</strong></div>
+                                        <div class="panel-body">
+                                            无                                        </div>
+                                    </div>
+                                </div><!-- #info -->
+
+                                <div class="tab-pane" id="sandbox22">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                                                                        <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>参数</strong></div>
+                                                <div class="panel-body">
+                                                    <form enctype="application/x-www-form-urlencoded" role="form" action="/api/user/resetpwd" method="get" name="form22" id="form22">
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="mobile">mobile</label>
+                                                            <input type="string" class="form-control input-sm" id="mobile" required placeholder="手机号" name="mobile">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="newpassword">newpassword</label>
+                                                            <input type="string" class="form-control input-sm" id="newpassword" required placeholder="新密码" name="newpassword">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="captcha">captcha</label>
+                                                            <input type="string" class="form-control input-sm" id="captcha" required placeholder="验证码" name="captcha">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <button type="submit" class="btn btn-success send" rel="22">提交</button>
+                                                            <button type="reset" class="btn btn-info" rel="22">重置</button>
+                                                        </div>
+                                                    </form>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>响应输出</strong></div>
+                                                <div class="panel-body">
+                                                    <div class="row">
+                                                        <div class="col-md-12" style="overflow-x:auto">
+                                                            <pre id="response_headers22"></pre>
+                                                            <pre id="response22"></pre>
+                                                        </div>
+                                                    </div>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>返回参数</strong></div>
+                                                <div class="panel-body">
+                                                                                                        无
+                                                                                                    </div>
+                                            </div>
+                                        </div>
+                                    </div>
+                                </div><!-- #sandbox -->
+
+                                <div class="tab-pane" id="sample22">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                            <pre id="sample_response22">无</pre>
+                                        </div>
+                                    </div>
+                                </div><!-- #sample -->
+
+                            </div><!-- .tab-content -->
+                        </div>
+                    </div>
+                </div>
+                                <h2>验证接口</h2>
+                <hr>
+                                <div class="panel panel-default">
+                    <div class="panel-heading" id="heading-23">
+                        <h4 class="panel-title">
+                            <span class="label label-success">GET</span>
+                            <a data-toggle="collapse" data-parent="#accordion23" href="#collapseOne23"> 检测邮箱 <span class="text-muted">/api/validate/check_email_available</span></a>
+                        </h4>
+                    </div>
+                    <div id="collapseOne23" class="panel-collapse collapse">
+                        <div class="panel-body">
+
+                            <!-- Nav tabs -->
+                            <ul class="nav nav-tabs" id="doctab23">
+                                <li class="active"><a href="#info23" data-toggle="tab">基础信息</a></li>
+                                <li><a href="#sandbox23" data-toggle="tab">在线测试</a></li>
+                                <li><a href="#sample23" data-toggle="tab">返回示例</a></li>
+                            </ul>
+
+                            <!-- Tab panes -->
+                            <div class="tab-content">
+
+                                <div class="tab-pane active" id="info23">
+                                    <div class="well">
+                                        检测邮箱                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>Headers</strong></div>
+                                        <div class="panel-body">
+                                                                                        无
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>参数</strong></div>
+                                        <div class="panel-body">
+                                                                                        <table class="table table-hover">
+                                                <thead>
+                                                    <tr>
+                                                        <th>名称</th>
+                                                        <th>类型</th>
+                                                        <th>必选</th>
+                                                        <th>描述</th>
+                                                    </tr>
+                                                </thead>
+                                                <tbody>
+                                                                                                        <tr>
+                                                        <td>email</td>
+                                                        <td>string</td>
+                                                        <td>是</td>
+                                                        <td>邮箱</td>
+                                                    </tr>
+                                                                                                        <tr>
+                                                        <td>id</td>
+                                                        <td>string</td>
+                                                        <td>是</td>
+                                                        <td>排除会员ID</td>
+                                                    </tr>
+                                                                                                    </tbody>
+                                            </table>
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>正文</strong></div>
+                                        <div class="panel-body">
+                                            无                                        </div>
+                                    </div>
+                                </div><!-- #info -->
+
+                                <div class="tab-pane" id="sandbox23">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                                                                        <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>参数</strong></div>
+                                                <div class="panel-body">
+                                                    <form enctype="application/x-www-form-urlencoded" role="form" action="/api/validate/check_email_available" method="get" name="form23" id="form23">
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="email">email</label>
+                                                            <input type="string" class="form-control input-sm" id="email" required placeholder="邮箱" name="email">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="id">id</label>
+                                                            <input type="string" class="form-control input-sm" id="id" required placeholder="排除会员ID" name="id">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <button type="submit" class="btn btn-success send" rel="23">提交</button>
+                                                            <button type="reset" class="btn btn-info" rel="23">重置</button>
+                                                        </div>
+                                                    </form>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>响应输出</strong></div>
+                                                <div class="panel-body">
+                                                    <div class="row">
+                                                        <div class="col-md-12" style="overflow-x:auto">
+                                                            <pre id="response_headers23"></pre>
+                                                            <pre id="response23"></pre>
+                                                        </div>
+                                                    </div>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>返回参数</strong></div>
+                                                <div class="panel-body">
+                                                                                                        无
+                                                                                                    </div>
+                                            </div>
+                                        </div>
+                                    </div>
+                                </div><!-- #sandbox -->
+
+                                <div class="tab-pane" id="sample23">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                            <pre id="sample_response23">无</pre>
+                                        </div>
+                                    </div>
+                                </div><!-- #sample -->
+
+                            </div><!-- .tab-content -->
+                        </div>
+                    </div>
+                </div>
+                                <div class="panel panel-default">
+                    <div class="panel-heading" id="heading-24">
+                        <h4 class="panel-title">
+                            <span class="label label-success">GET</span>
+                            <a data-toggle="collapse" data-parent="#accordion24" href="#collapseOne24"> 检测用户名 <span class="text-muted">/api/validate/check_username_available</span></a>
+                        </h4>
+                    </div>
+                    <div id="collapseOne24" class="panel-collapse collapse">
+                        <div class="panel-body">
+
+                            <!-- Nav tabs -->
+                            <ul class="nav nav-tabs" id="doctab24">
+                                <li class="active"><a href="#info24" data-toggle="tab">基础信息</a></li>
+                                <li><a href="#sandbox24" data-toggle="tab">在线测试</a></li>
+                                <li><a href="#sample24" data-toggle="tab">返回示例</a></li>
+                            </ul>
+
+                            <!-- Tab panes -->
+                            <div class="tab-content">
+
+                                <div class="tab-pane active" id="info24">
+                                    <div class="well">
+                                        检测用户名                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>Headers</strong></div>
+                                        <div class="panel-body">
+                                                                                        无
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>参数</strong></div>
+                                        <div class="panel-body">
+                                                                                        <table class="table table-hover">
+                                                <thead>
+                                                    <tr>
+                                                        <th>名称</th>
+                                                        <th>类型</th>
+                                                        <th>必选</th>
+                                                        <th>描述</th>
+                                                    </tr>
+                                                </thead>
+                                                <tbody>
+                                                                                                        <tr>
+                                                        <td>username</td>
+                                                        <td>string</td>
+                                                        <td>是</td>
+                                                        <td>用户名</td>
+                                                    </tr>
+                                                                                                        <tr>
+                                                        <td>id</td>
+                                                        <td>string</td>
+                                                        <td>是</td>
+                                                        <td>排除会员ID</td>
+                                                    </tr>
+                                                                                                    </tbody>
+                                            </table>
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>正文</strong></div>
+                                        <div class="panel-body">
+                                            无                                        </div>
+                                    </div>
+                                </div><!-- #info -->
+
+                                <div class="tab-pane" id="sandbox24">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                                                                        <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>参数</strong></div>
+                                                <div class="panel-body">
+                                                    <form enctype="application/x-www-form-urlencoded" role="form" action="/api/validate/check_username_available" method="get" name="form24" id="form24">
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="username">username</label>
+                                                            <input type="string" class="form-control input-sm" id="username" required placeholder="用户名" name="username">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="id">id</label>
+                                                            <input type="string" class="form-control input-sm" id="id" required placeholder="排除会员ID" name="id">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <button type="submit" class="btn btn-success send" rel="24">提交</button>
+                                                            <button type="reset" class="btn btn-info" rel="24">重置</button>
+                                                        </div>
+                                                    </form>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>响应输出</strong></div>
+                                                <div class="panel-body">
+                                                    <div class="row">
+                                                        <div class="col-md-12" style="overflow-x:auto">
+                                                            <pre id="response_headers24"></pre>
+                                                            <pre id="response24"></pre>
+                                                        </div>
+                                                    </div>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>返回参数</strong></div>
+                                                <div class="panel-body">
+                                                                                                        无
+                                                                                                    </div>
+                                            </div>
+                                        </div>
+                                    </div>
+                                </div><!-- #sandbox -->
+
+                                <div class="tab-pane" id="sample24">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                            <pre id="sample_response24">无</pre>
+                                        </div>
+                                    </div>
+                                </div><!-- #sample -->
+
+                            </div><!-- .tab-content -->
+                        </div>
+                    </div>
+                </div>
+                                <div class="panel panel-default">
+                    <div class="panel-heading" id="heading-25">
+                        <h4 class="panel-title">
+                            <span class="label label-success">GET</span>
+                            <a data-toggle="collapse" data-parent="#accordion25" href="#collapseOne25"> 检测手机 <span class="text-muted">/api/validate/check_mobile_available</span></a>
+                        </h4>
+                    </div>
+                    <div id="collapseOne25" class="panel-collapse collapse">
+                        <div class="panel-body">
+
+                            <!-- Nav tabs -->
+                            <ul class="nav nav-tabs" id="doctab25">
+                                <li class="active"><a href="#info25" data-toggle="tab">基础信息</a></li>
+                                <li><a href="#sandbox25" data-toggle="tab">在线测试</a></li>
+                                <li><a href="#sample25" data-toggle="tab">返回示例</a></li>
+                            </ul>
+
+                            <!-- Tab panes -->
+                            <div class="tab-content">
+
+                                <div class="tab-pane active" id="info25">
+                                    <div class="well">
+                                        检测手机                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>Headers</strong></div>
+                                        <div class="panel-body">
+                                                                                        无
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>参数</strong></div>
+                                        <div class="panel-body">
+                                                                                        <table class="table table-hover">
+                                                <thead>
+                                                    <tr>
+                                                        <th>名称</th>
+                                                        <th>类型</th>
+                                                        <th>必选</th>
+                                                        <th>描述</th>
+                                                    </tr>
+                                                </thead>
+                                                <tbody>
+                                                                                                        <tr>
+                                                        <td>mobile</td>
+                                                        <td>string</td>
+                                                        <td>是</td>
+                                                        <td>手机号</td>
+                                                    </tr>
+                                                                                                        <tr>
+                                                        <td>id</td>
+                                                        <td>string</td>
+                                                        <td>是</td>
+                                                        <td>排除会员ID</td>
+                                                    </tr>
+                                                                                                    </tbody>
+                                            </table>
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>正文</strong></div>
+                                        <div class="panel-body">
+                                            无                                        </div>
+                                    </div>
+                                </div><!-- #info -->
+
+                                <div class="tab-pane" id="sandbox25">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                                                                        <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>参数</strong></div>
+                                                <div class="panel-body">
+                                                    <form enctype="application/x-www-form-urlencoded" role="form" action="/api/validate/check_mobile_available" method="get" name="form25" id="form25">
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="mobile">mobile</label>
+                                                            <input type="string" class="form-control input-sm" id="mobile" required placeholder="手机号" name="mobile">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="id">id</label>
+                                                            <input type="string" class="form-control input-sm" id="id" required placeholder="排除会员ID" name="id">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <button type="submit" class="btn btn-success send" rel="25">提交</button>
+                                                            <button type="reset" class="btn btn-info" rel="25">重置</button>
+                                                        </div>
+                                                    </form>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>响应输出</strong></div>
+                                                <div class="panel-body">
+                                                    <div class="row">
+                                                        <div class="col-md-12" style="overflow-x:auto">
+                                                            <pre id="response_headers25"></pre>
+                                                            <pre id="response25"></pre>
+                                                        </div>
+                                                    </div>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>返回参数</strong></div>
+                                                <div class="panel-body">
+                                                                                                        无
+                                                                                                    </div>
+                                            </div>
+                                        </div>
+                                    </div>
+                                </div><!-- #sandbox -->
+
+                                <div class="tab-pane" id="sample25">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                            <pre id="sample_response25">无</pre>
+                                        </div>
+                                    </div>
+                                </div><!-- #sample -->
+
+                            </div><!-- .tab-content -->
+                        </div>
+                    </div>
+                </div>
+                                <div class="panel panel-default">
+                    <div class="panel-heading" id="heading-26">
+                        <h4 class="panel-title">
+                            <span class="label label-success">GET</span>
+                            <a data-toggle="collapse" data-parent="#accordion26" href="#collapseOne26"> 检测手机 <span class="text-muted">/api/validate/check_mobile_exist</span></a>
+                        </h4>
+                    </div>
+                    <div id="collapseOne26" class="panel-collapse collapse">
+                        <div class="panel-body">
+
+                            <!-- Nav tabs -->
+                            <ul class="nav nav-tabs" id="doctab26">
+                                <li class="active"><a href="#info26" data-toggle="tab">基础信息</a></li>
+                                <li><a href="#sandbox26" data-toggle="tab">在线测试</a></li>
+                                <li><a href="#sample26" data-toggle="tab">返回示例</a></li>
+                            </ul>
+
+                            <!-- Tab panes -->
+                            <div class="tab-content">
+
+                                <div class="tab-pane active" id="info26">
+                                    <div class="well">
+                                        检测手机                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>Headers</strong></div>
+                                        <div class="panel-body">
+                                                                                        无
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>参数</strong></div>
+                                        <div class="panel-body">
+                                                                                        <table class="table table-hover">
+                                                <thead>
+                                                    <tr>
+                                                        <th>名称</th>
+                                                        <th>类型</th>
+                                                        <th>必选</th>
+                                                        <th>描述</th>
+                                                    </tr>
+                                                </thead>
+                                                <tbody>
+                                                                                                        <tr>
+                                                        <td>mobile</td>
+                                                        <td>string</td>
+                                                        <td>是</td>
+                                                        <td>手机号</td>
+                                                    </tr>
+                                                                                                    </tbody>
+                                            </table>
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>正文</strong></div>
+                                        <div class="panel-body">
+                                            无                                        </div>
+                                    </div>
+                                </div><!-- #info -->
+
+                                <div class="tab-pane" id="sandbox26">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                                                                        <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>参数</strong></div>
+                                                <div class="panel-body">
+                                                    <form enctype="application/x-www-form-urlencoded" role="form" action="/api/validate/check_mobile_exist" method="get" name="form26" id="form26">
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="mobile">mobile</label>
+                                                            <input type="string" class="form-control input-sm" id="mobile" required placeholder="手机号" name="mobile">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <button type="submit" class="btn btn-success send" rel="26">提交</button>
+                                                            <button type="reset" class="btn btn-info" rel="26">重置</button>
+                                                        </div>
+                                                    </form>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>响应输出</strong></div>
+                                                <div class="panel-body">
+                                                    <div class="row">
+                                                        <div class="col-md-12" style="overflow-x:auto">
+                                                            <pre id="response_headers26"></pre>
+                                                            <pre id="response26"></pre>
+                                                        </div>
+                                                    </div>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>返回参数</strong></div>
+                                                <div class="panel-body">
+                                                                                                        无
+                                                                                                    </div>
+                                            </div>
+                                        </div>
+                                    </div>
+                                </div><!-- #sandbox -->
+
+                                <div class="tab-pane" id="sample26">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                            <pre id="sample_response26">无</pre>
+                                        </div>
+                                    </div>
+                                </div><!-- #sample -->
+
+                            </div><!-- .tab-content -->
+                        </div>
+                    </div>
+                </div>
+                                <div class="panel panel-default">
+                    <div class="panel-heading" id="heading-27">
+                        <h4 class="panel-title">
+                            <span class="label label-success">GET</span>
+                            <a data-toggle="collapse" data-parent="#accordion27" href="#collapseOne27"> 检测邮箱 <span class="text-muted">/api/validate/check_email_exist</span></a>
+                        </h4>
+                    </div>
+                    <div id="collapseOne27" class="panel-collapse collapse">
+                        <div class="panel-body">
+
+                            <!-- Nav tabs -->
+                            <ul class="nav nav-tabs" id="doctab27">
+                                <li class="active"><a href="#info27" data-toggle="tab">基础信息</a></li>
+                                <li><a href="#sandbox27" data-toggle="tab">在线测试</a></li>
+                                <li><a href="#sample27" data-toggle="tab">返回示例</a></li>
+                            </ul>
+
+                            <!-- Tab panes -->
+                            <div class="tab-content">
+
+                                <div class="tab-pane active" id="info27">
+                                    <div class="well">
+                                        检测邮箱                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>Headers</strong></div>
+                                        <div class="panel-body">
+                                                                                        无
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>参数</strong></div>
+                                        <div class="panel-body">
+                                                                                        <table class="table table-hover">
+                                                <thead>
+                                                    <tr>
+                                                        <th>名称</th>
+                                                        <th>类型</th>
+                                                        <th>必选</th>
+                                                        <th>描述</th>
+                                                    </tr>
+                                                </thead>
+                                                <tbody>
+                                                                                                        <tr>
+                                                        <td>mobile</td>
+                                                        <td>string</td>
+                                                        <td>是</td>
+                                                        <td>邮箱</td>
+                                                    </tr>
+                                                                                                    </tbody>
+                                            </table>
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>正文</strong></div>
+                                        <div class="panel-body">
+                                            无                                        </div>
+                                    </div>
+                                </div><!-- #info -->
+
+                                <div class="tab-pane" id="sandbox27">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                                                                        <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>参数</strong></div>
+                                                <div class="panel-body">
+                                                    <form enctype="application/x-www-form-urlencoded" role="form" action="/api/validate/check_email_exist" method="get" name="form27" id="form27">
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="mobile">mobile</label>
+                                                            <input type="string" class="form-control input-sm" id="mobile" required placeholder="邮箱" name="mobile">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <button type="submit" class="btn btn-success send" rel="27">提交</button>
+                                                            <button type="reset" class="btn btn-info" rel="27">重置</button>
+                                                        </div>
+                                                    </form>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>响应输出</strong></div>
+                                                <div class="panel-body">
+                                                    <div class="row">
+                                                        <div class="col-md-12" style="overflow-x:auto">
+                                                            <pre id="response_headers27"></pre>
+                                                            <pre id="response27"></pre>
+                                                        </div>
+                                                    </div>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>返回参数</strong></div>
+                                                <div class="panel-body">
+                                                                                                        无
+                                                                                                    </div>
+                                            </div>
+                                        </div>
+                                    </div>
+                                </div><!-- #sandbox -->
+
+                                <div class="tab-pane" id="sample27">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                            <pre id="sample_response27">无</pre>
+                                        </div>
+                                    </div>
+                                </div><!-- #sample -->
+
+                            </div><!-- .tab-content -->
+                        </div>
+                    </div>
+                </div>
+                                <div class="panel panel-default">
+                    <div class="panel-heading" id="heading-28">
+                        <h4 class="panel-title">
+                            <span class="label label-success">GET</span>
+                            <a data-toggle="collapse" data-parent="#accordion28" href="#collapseOne28"> 检测手机验证码 <span class="text-muted">/api/validate/check_sms_correct</span></a>
+                        </h4>
+                    </div>
+                    <div id="collapseOne28" class="panel-collapse collapse">
+                        <div class="panel-body">
+
+                            <!-- Nav tabs -->
+                            <ul class="nav nav-tabs" id="doctab28">
+                                <li class="active"><a href="#info28" data-toggle="tab">基础信息</a></li>
+                                <li><a href="#sandbox28" data-toggle="tab">在线测试</a></li>
+                                <li><a href="#sample28" data-toggle="tab">返回示例</a></li>
+                            </ul>
+
+                            <!-- Tab panes -->
+                            <div class="tab-content">
+
+                                <div class="tab-pane active" id="info28">
+                                    <div class="well">
+                                        检测手机验证码                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>Headers</strong></div>
+                                        <div class="panel-body">
+                                                                                        无
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>参数</strong></div>
+                                        <div class="panel-body">
+                                                                                        <table class="table table-hover">
+                                                <thead>
+                                                    <tr>
+                                                        <th>名称</th>
+                                                        <th>类型</th>
+                                                        <th>必选</th>
+                                                        <th>描述</th>
+                                                    </tr>
+                                                </thead>
+                                                <tbody>
+                                                                                                        <tr>
+                                                        <td>mobile</td>
+                                                        <td>string</td>
+                                                        <td>是</td>
+                                                        <td>手机号</td>
+                                                    </tr>
+                                                                                                        <tr>
+                                                        <td>captcha</td>
+                                                        <td>string</td>
+                                                        <td>是</td>
+                                                        <td>验证码</td>
+                                                    </tr>
+                                                                                                        <tr>
+                                                        <td>event</td>
+                                                        <td>string</td>
+                                                        <td>是</td>
+                                                        <td>事件</td>
+                                                    </tr>
+                                                                                                    </tbody>
+                                            </table>
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>正文</strong></div>
+                                        <div class="panel-body">
+                                            无                                        </div>
+                                    </div>
+                                </div><!-- #info -->
+
+                                <div class="tab-pane" id="sandbox28">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                                                                        <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>参数</strong></div>
+                                                <div class="panel-body">
+                                                    <form enctype="application/x-www-form-urlencoded" role="form" action="/api/validate/check_sms_correct" method="get" name="form28" id="form28">
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="mobile">mobile</label>
+                                                            <input type="string" class="form-control input-sm" id="mobile" required placeholder="手机号" name="mobile">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="captcha">captcha</label>
+                                                            <input type="string" class="form-control input-sm" id="captcha" required placeholder="验证码" name="captcha">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="event">event</label>
+                                                            <input type="string" class="form-control input-sm" id="event" required placeholder="事件" name="event">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <button type="submit" class="btn btn-success send" rel="28">提交</button>
+                                                            <button type="reset" class="btn btn-info" rel="28">重置</button>
+                                                        </div>
+                                                    </form>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>响应输出</strong></div>
+                                                <div class="panel-body">
+                                                    <div class="row">
+                                                        <div class="col-md-12" style="overflow-x:auto">
+                                                            <pre id="response_headers28"></pre>
+                                                            <pre id="response28"></pre>
+                                                        </div>
+                                                    </div>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>返回参数</strong></div>
+                                                <div class="panel-body">
+                                                                                                        无
+                                                                                                    </div>
+                                            </div>
+                                        </div>
+                                    </div>
+                                </div><!-- #sandbox -->
+
+                                <div class="tab-pane" id="sample28">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                            <pre id="sample_response28">无</pre>
+                                        </div>
+                                    </div>
+                                </div><!-- #sample -->
+
+                            </div><!-- .tab-content -->
+                        </div>
+                    </div>
+                </div>
+                                <div class="panel panel-default">
+                    <div class="panel-heading" id="heading-29">
+                        <h4 class="panel-title">
+                            <span class="label label-success">GET</span>
+                            <a data-toggle="collapse" data-parent="#accordion29" href="#collapseOne29"> 检测邮箱验证码 <span class="text-muted">/api/validate/check_ems_correct</span></a>
+                        </h4>
+                    </div>
+                    <div id="collapseOne29" class="panel-collapse collapse">
+                        <div class="panel-body">
+
+                            <!-- Nav tabs -->
+                            <ul class="nav nav-tabs" id="doctab29">
+                                <li class="active"><a href="#info29" data-toggle="tab">基础信息</a></li>
+                                <li><a href="#sandbox29" data-toggle="tab">在线测试</a></li>
+                                <li><a href="#sample29" data-toggle="tab">返回示例</a></li>
+                            </ul>
+
+                            <!-- Tab panes -->
+                            <div class="tab-content">
+
+                                <div class="tab-pane active" id="info29">
+                                    <div class="well">
+                                        检测邮箱验证码                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>Headers</strong></div>
+                                        <div class="panel-body">
+                                                                                        无
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>参数</strong></div>
+                                        <div class="panel-body">
+                                                                                        <table class="table table-hover">
+                                                <thead>
+                                                    <tr>
+                                                        <th>名称</th>
+                                                        <th>类型</th>
+                                                        <th>必选</th>
+                                                        <th>描述</th>
+                                                    </tr>
+                                                </thead>
+                                                <tbody>
+                                                                                                        <tr>
+                                                        <td>email</td>
+                                                        <td>string</td>
+                                                        <td>是</td>
+                                                        <td>邮箱</td>
+                                                    </tr>
+                                                                                                        <tr>
+                                                        <td>captcha</td>
+                                                        <td>string</td>
+                                                        <td>是</td>
+                                                        <td>验证码</td>
+                                                    </tr>
+                                                                                                        <tr>
+                                                        <td>event</td>
+                                                        <td>string</td>
+                                                        <td>是</td>
+                                                        <td>事件</td>
+                                                    </tr>
+                                                                                                    </tbody>
+                                            </table>
+                                                                                    </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>正文</strong></div>
+                                        <div class="panel-body">
+                                            无                                        </div>
+                                    </div>
+                                </div><!-- #info -->
+
+                                <div class="tab-pane" id="sandbox29">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                                                                        <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>参数</strong></div>
+                                                <div class="panel-body">
+                                                    <form enctype="application/x-www-form-urlencoded" role="form" action="/api/validate/check_ems_correct" method="get" name="form29" id="form29">
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="email">email</label>
+                                                            <input type="string" class="form-control input-sm" id="email" required placeholder="邮箱" name="email">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="captcha">captcha</label>
+                                                            <input type="string" class="form-control input-sm" id="captcha" required placeholder="验证码" name="captcha">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <label class="control-label" for="event">event</label>
+                                                            <input type="string" class="form-control input-sm" id="event" required placeholder="事件" name="event">
+                                                        </div>
+                                                                                                                <div class="form-group">
+                                                            <button type="submit" class="btn btn-success send" rel="29">提交</button>
+                                                            <button type="reset" class="btn btn-info" rel="29">重置</button>
+                                                        </div>
+                                                    </form>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>响应输出</strong></div>
+                                                <div class="panel-body">
+                                                    <div class="row">
+                                                        <div class="col-md-12" style="overflow-x:auto">
+                                                            <pre id="response_headers29"></pre>
+                                                            <pre id="response29"></pre>
+                                                        </div>
+                                                    </div>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>返回参数</strong></div>
+                                                <div class="panel-body">
+                                                                                                        无
+                                                                                                    </div>
+                                            </div>
+                                        </div>
+                                    </div>
+                                </div><!-- #sandbox -->
+
+                                <div class="tab-pane" id="sample29">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                            <pre id="sample_response29">无</pre>
+                                        </div>
+                                    </div>
+                                </div><!-- #sample -->
+
+                            </div><!-- .tab-content -->
+                        </div>
+                    </div>
+                </div>
+                            </div>
+
+            <hr>
+
+            <div class="row mt0 footer">
+                <div class="col-md-6" align="left">
+                    Generated on 2019-01-26 11:32:33                </div>
+                <div class="col-md-6" align="right">
+                    <a href="https://www.fastadmin.net" target="_blank">FastAdmin</a>
+                </div>
+            </div>
+
+        </div> <!-- /container -->
+
+        <!-- jQuery -->
+        <script src="https://cdn.staticfile.org/jquery/2.1.4/jquery.min.js"></script>
+
+        <!-- Bootstrap Core JavaScript -->
+        <script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
+
+        <script type="text/javascript">
+            function syntaxHighlight(json) {
+                if (typeof json != 'string') {
+                    json = JSON.stringify(json, undefined, 2);
+                }
+                json = json.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
+                return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
+                    var cls = 'number';
+                    if (/^"/.test(match)) {
+                        if (/:$/.test(match)) {
+                            cls = 'key';
+                        } else {
+                            cls = 'string';
+                        }
+                    } else if (/true|false/.test(match)) {
+                        cls = 'boolean';
+                    } else if (/null/.test(match)) {
+                        cls = 'null';
+                    }
+                    return '<span class="' + cls + '">' + match + '</span>';
+                });
+            }
+
+            function prepareStr(str) {
+                try {
+                    return syntaxHighlight(JSON.stringify(JSON.parse(str.replace(/'/g, '"')), null, 2));
+                } catch (e) {
+                    return str;
+                }
+            }
+            var storage = (function () {
+                var uid = new Date;
+                var storage;
+                var result;
+                try {
+                    (storage = window.localStorage).setItem(uid, uid);
+                    result = storage.getItem(uid) == uid;
+                    storage.removeItem(uid);
+                    return result && storage;
+                } catch (exception) {
+                }
+            }());
+
+            $.fn.serializeObject = function ()
+            {
+                var o = {};
+                var a = this.serializeArray();
+                $.each(a, function () {
+                    if (!this.value) {
+                        return;
+                    }
+                    if (o[this.name] !== undefined) {
+                        if (!o[this.name].push) {
+                            o[this.name] = [o[this.name]];
+                        }
+                        o[this.name].push(this.value || '');
+                    } else {
+                        o[this.name] = this.value || '';
+                    }
+                });
+                return o;
+            };
+
+            $(document).ready(function () {
+
+                if (storage) {
+                    $('#token').val(storage.getItem('token'));
+                    $('#apiUrl').val(storage.getItem('apiUrl'));
+                }
+
+                $('[data-toggle="tooltip"]').tooltip({
+                    placement: 'bottom'
+                });
+
+                $(window).on("resize", function(){
+                    $("#sidebar").css("max-height", $(window).height()-80);
+                });
+
+                $(window).trigger("resize");
+
+                $(document).on("click", "#sidebar .list-group > .list-group-item", function(){
+                    $("#sidebar .list-group > .list-group-item").removeClass("current");
+                    $(this).addClass("current");
+                });
+                $(document).on("click", "#sidebar .child a", function(){
+                    var heading = $("#heading-"+$(this).data("id"));
+                    if(!heading.next().hasClass("in")){
+                        $("a", heading).trigger("click");
+                    }
+                    $("html,body").animate({scrollTop:heading.offset().top-70});
+                });
+
+                $('code[id^=response]').hide();
+
+                $.each($('pre[id^=sample_response],pre[id^=sample_post_body]'), function () {
+                    if ($(this).html() == 'NA') {
+                        return;
+                    }
+                    var str = prepareStr($(this).html());
+                    $(this).html(str);
+                });
+
+                $("[data-toggle=popover]").popover({placement: 'right'});
+
+                $('[data-toggle=popover]').on('shown.bs.popover', function () {
+                    var $sample = $(this).parent().find(".popover-content"),
+                            str = $(this).data('content');
+                    if (typeof str == "undefined" || str === "") {
+                        return;
+                    }
+                    var str = prepareStr(str);
+                    $sample.html('<pre>' + str + '</pre>');
+                });
+
+                $('body').on('click', '#save_data', function (e) {
+                    if (storage) {
+                        storage.setItem('token', $('#token').val());
+                        storage.setItem('apiUrl', $('#apiUrl').val());
+                    } else {
+                        alert('Your browser does not support local storage');
+                    }
+                });
+
+                $('body').on('click', '.send', function (e) {
+                    e.preventDefault();
+                    var form = $(this).closest('form');
+                    //added /g to get all the matched params instead of only first
+                    var matchedParamsInRoute = $(form).attr('action').match(/[^{]+(?=\})/g);
+                    var theId = $(this).attr('rel');
+                    //keep a copy of action attribute in order to modify the copy
+                    //instead of the initial attribute
+                    var url = $(form).attr('action');
+                    var method = $(form).prop('method').toLowerCase() || 'get';
+
+                    var formData = new FormData();
+
+                    $(form).find('input').each(function (i, input) {
+                        if ($(input).attr('type').toLowerCase() == 'file') {
+                            formData.append($(input).attr('name'), $(input)[0].files[0]);
+                            method = 'post';
+                        } else {
+                            formData.append($(input).attr('name'), $(input).val())
+                        }
+                    });
+
+                    var index, key, value;
+
+                    if (matchedParamsInRoute) {
+                        var params = {};
+                        formData.forEach(function(value, key){
+                            params[key] = value;
+                        });
+                        for (index = 0; index < matchedParamsInRoute.length; ++index) {
+                            try {
+                                key = matchedParamsInRoute[index];
+                                value = params[key];
+                                if (typeof value == "undefined")
+                                    value = "";
+                                url = url.replace("\{" + key + "\}", value);
+                                formData.delete(key);
+                            } catch (err) {
+                                console.log(err);
+                            }
+                        }
+                    }
+
+                    var headers = {};
+
+                    var token = $('#token').val();
+                    if (token.length > 0) {
+                        headers['token'] = token;
+                    }
+
+                    $("#sandbox" + theId + " .headers input[type=text]").each(function () {
+                        val = $(this).val();
+                        if (val.length > 0) {
+                            headers[$(this).prop('name')] = val;
+                        }
+                    });
+
+                    $.ajax({
+                        url: $('#apiUrl').val() + url,
+                        data: method == 'get' ? $(form).serialize() : formData,
+                        type: method,
+                        dataType: 'json',
+                        contentType: false,
+                        processData: false,
+                        headers: headers,
+                        success: function (data, textStatus, xhr) {
+                            if (typeof data === 'object') {
+                                var str = JSON.stringify(data, null, 2);
+                                $('#response' + theId).html(syntaxHighlight(str));
+                            } else {
+                                $('#response' + theId).html(data || '');
+                            }
+                            $('#response_headers' + theId).html('HTTP ' + xhr.status + ' ' + xhr.statusText + '<br/><br/>' + xhr.getAllResponseHeaders());
+                            $('#response' + theId).show();
+                        },
+                        error: function (xhr, textStatus, error) {
+                            try {
+                                var str = JSON.stringify($.parseJSON(xhr.responseText), null, 2);
+                            } catch (e) {
+                                var str = xhr.responseText;
+                            }
+                            $('#response_headers' + theId).html('HTTP ' + xhr.status + ' ' + xhr.statusText + '<br/><br/>' + xhr.getAllResponseHeaders());
+                            $('#response' + theId).html(syntaxHighlight(str));
+                            $('#response' + theId).show();
+                        }
+                    });
+                    return false;
+                });
+            });
+        </script>
+    </body>
+</html>

+ 1 - 0
application/.htaccess

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

+ 36 - 0
application/404.html

@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <title>404 页面不存在</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.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
+    <link rel="stylesheet" href="__JS__/layui/css/layui.css" media="all">
+    <link rel="stylesheet" href="__CSS__/admin.css" media="all">
+</head>
+<body>
+
+
+<div class="layui-fluid">
+    <div class="layadmin-tips">
+        <i class="layui-icon " face=""></i>
+        <div class="layui-text">
+            <h1>
+                <span class="layui-anim layui-anim-loop layui-anim-">4</span>
+                <span class="layui-anim layui-anim-loop layui-anim-">0</span>
+                <span class="layui-anim layui-anim-loop layui-anim-">4</span>
+            </h1>
+        </div>
+    </div>
+</div>
+<script src="__JS__/layui/layui.js"></script>
+<script>
+    layui.config({
+        base: '/src/' //静态资源所在路径
+    }).extend({
+        index: 'index' //主入口模块
+    }).use(['index']);
+</script>
+</body>
+</html>

+ 36 - 0
application/500.html

@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <title>500 页面不存在</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.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
+    <link rel="stylesheet" href="__JS__/layui/css/layui.css" media="all">
+    <link rel="stylesheet" href="__CSS__/admin.css" media="all">
+</head>
+<body>
+
+
+<div class="layui-fluid">
+    <div class="layadmin-tips">
+        <i class="layui-icon" face=""></i>
+        <div class="layui-text">
+            <h1>
+                <span class="layui-anim layui-anim-loop layui-anim-">5</span>
+                <span class="layui-anim layui-anim-loop layui-anim-">0</span>
+                <span class="layui-anim layui-anim-loop layui-anim-">0</span>
+            </h1>
+        </div>
+    </div>
+</div>
+<script src="__JS__/layui/layui.js"></script>
+<script>
+    layui.config({
+        base: '/src/' //静态资源所在路径
+    }).extend({
+        index: 'index' //主入口模块
+    }).use(['index']);
+</script>
+</body>
+</html>

+ 319 - 0
application/admin/command/Addon.php

@@ -0,0 +1,319 @@
+<?php
+
+namespace app\admin\command;
+
+use think\addons\AddonException;
+use think\addons\Service;
+use think\Config;
+use think\console\Command;
+use think\console\Input;
+use think\console\input\Option;
+use think\console\Output;
+use think\Db;
+use think\Exception;
+use think\exception\PDOException;
+
+class Addon extends Command
+{
+
+    protected function configure()
+    {
+        $this
+            ->setName('addon')
+            ->addOption('name', 'a', Option::VALUE_REQUIRED, 'addon name', null)
+            ->addOption('action', 'c', Option::VALUE_REQUIRED, 'action(create/enable/disable/install/uninstall/refresh/upgrade/package)', 'create')
+            ->addOption('force', 'f', Option::VALUE_OPTIONAL, 'force override', null)
+            ->addOption('release', 'r', Option::VALUE_OPTIONAL, 'addon release version', null)
+            ->addOption('uid', 'u', Option::VALUE_OPTIONAL, 'fastadmin uid', null)
+            ->addOption('token', 't', Option::VALUE_OPTIONAL, 'fastadmin token', null)
+            ->setDescription('Addon manager');
+    }
+
+    protected function execute(Input $input, Output $output)
+    {
+        $name = $input->getOption('name') ?: '';
+        $action = $input->getOption('action') ?: '';
+        if (stripos($name, 'addons/') !== false) {
+            $name = explode('/', $name)[1];
+        }
+        //强制覆盖
+        $force = $input->getOption('force');
+        //版本
+        $release = $input->getOption('release') ?: '';
+        //uid
+        $uid = $input->getOption('uid') ?: '';
+        //token
+        $token = $input->getOption('token') ?: '';
+
+        include dirname(__DIR__) . DS . 'common.php';
+
+        if (!$name) {
+            throw new Exception('Addon name could not be empty');
+        }
+        if (!$action || !in_array($action, ['create', 'disable', 'enable', 'install', 'uninstall', 'refresh', 'upgrade', 'package'])) {
+            throw new Exception('Please input correct action name');
+        }
+
+        // 查询一次SQL,判断连接是否正常
+        Db::execute("SELECT 1");
+
+        $addonDir = ADDON_PATH . $name . DS;
+        switch ($action) {
+            case 'create':
+                //非覆盖模式时如果存在则报错
+                if (is_dir($addonDir) && !$force) {
+                    throw new Exception("addon already exists!\nIf you need to create again, use the parameter --force=true ");
+                }
+                //如果存在先移除
+                if (is_dir($addonDir)) {
+                    rmdirs($addonDir);
+                }
+                mkdir($addonDir, 0755, true);
+                mkdir($addonDir . DS . 'controller', 0755, true);
+                $menuList = \app\common\library\Menu::export($name);
+                $createMenu = $this->getCreateMenu($menuList);
+                $prefix = Config::get('database.prefix');
+                $createTableSql = '';
+                try {
+                    $result = Db::query("SHOW CREATE TABLE `" . $prefix . $name . "`;");
+                    if (isset($result[0]) && isset($result[0]['Create Table'])) {
+                        $createTableSql = $result[0]['Create Table'];
+                    }
+                } catch (PDOException $e) {
+
+                }
+
+                $data = [
+                    'name'               => $name,
+                    'addon'              => $name,
+                    'addonClassName'     => ucfirst($name),
+                    'addonInstallMenu'   => $createMenu ? "\$menu = " . var_export_short($createMenu, "\t") . ";\n\tMenu::create(\$menu);" : '',
+                    'addonUninstallMenu' => $menuList ? 'Menu::delete("' . $name . '");' : '',
+                    'addonEnableMenu'    => $menuList ? 'Menu::enable("' . $name . '");' : '',
+                    'addonDisableMenu'   => $menuList ? 'Menu::disable("' . $name . '");' : '',
+                ];
+                $this->writeToFile("addon", $data, $addonDir . ucfirst($name) . '.php');
+                $this->writeToFile("config", $data, $addonDir . 'config.php');
+                $this->writeToFile("info", $data, $addonDir . 'info.ini');
+                $this->writeToFile("controller", $data, $addonDir . 'controller' . DS . 'Index.php');
+                if ($createTableSql) {
+                    $createTableSql = str_replace("`" . $prefix, '`__PREFIX__', $createTableSql);
+                    file_put_contents($addonDir . 'install.sql', $createTableSql);
+                }
+
+                $output->info("Create Successed!");
+                break;
+            case 'disable':
+            case 'enable':
+                try {
+                    //调用启用、禁用的方法
+                    Service::$action($name, 0);
+                } catch (AddonException $e) {
+                    if ($e->getCode() != -3) {
+                        throw new Exception($e->getMessage());
+                    }
+                    if (!$force) {
+                        //如果有冲突文件则提醒
+                        $data = $e->getData();
+                        foreach ($data['conflictlist'] as $k => $v) {
+                            $output->warning($v);
+                        }
+                        $output->info("Are you sure you want to " . ($action == 'enable' ? 'override' : 'delete') . " all those files?  Type 'yes' to continue: ");
+                        $line = fgets(STDIN);
+                        if (trim($line) != 'yes') {
+                            throw new Exception("Operation is aborted!");
+                        }
+                    }
+                    //调用启用、禁用的方法
+                    Service::$action($name, 1);
+                } catch (Exception $e) {
+                    throw new Exception($e->getMessage());
+                }
+                $output->info(ucfirst($action) . " Successed!");
+                break;
+            case 'install':
+                //非覆盖模式时如果存在则报错
+                if (is_dir($addonDir) && !$force) {
+                    throw new Exception("addon already exists!\nIf you need to install again, use the parameter --force=true ");
+                }
+                //如果存在先移除
+                if (is_dir($addonDir)) {
+                    rmdirs($addonDir);
+                }
+                try {
+                    Service::install($name, 0, ['version' => $release]);
+                } catch (AddonException $e) {
+                    if ($e->getCode() != -3) {
+                        throw new Exception($e->getMessage());
+                    }
+                    if (!$force) {
+                        //如果有冲突文件则提醒
+                        $data = $e->getData();
+                        foreach ($data['conflictlist'] as $k => $v) {
+                            $output->warning($v);
+                        }
+                        $output->info("Are you sure you want to override all those files?  Type 'yes' to continue: ");
+                        $line = fgets(STDIN);
+                        if (trim($line) != 'yes') {
+                            throw new Exception("Operation is aborted!");
+                        }
+                    }
+                    Service::install($name, 1, ['version' => $release, 'uid' => $uid, 'token' => $token]);
+                } catch (Exception $e) {
+                    throw new Exception($e->getMessage());
+                }
+
+                $output->info("Install Successed!");
+                break;
+            case 'uninstall':
+                //非覆盖模式时如果存在则报错
+                if (!$force) {
+                    throw new Exception("If you need to uninstall addon, use the parameter --force=true ");
+                }
+                try {
+                    Service::uninstall($name, 0);
+                } catch (AddonException $e) {
+                    if ($e->getCode() != -3) {
+                        throw new Exception($e->getMessage());
+                    }
+                    if (!$force) {
+                        //如果有冲突文件则提醒
+                        $data = $e->getData();
+                        foreach ($data['conflictlist'] as $k => $v) {
+                            $output->warning($v);
+                        }
+                        $output->info("Are you sure you want to delete all those files?  Type 'yes' to continue: ");
+                        $line = fgets(STDIN);
+                        if (trim($line) != 'yes') {
+                            throw new Exception("Operation is aborted!");
+                        }
+                    }
+                    Service::uninstall($name, 1);
+                } catch (Exception $e) {
+                    throw new Exception($e->getMessage());
+                }
+
+                $output->info("Uninstall Successed!");
+                break;
+            case 'refresh':
+                Service::refresh();
+                $output->info("Refresh Successed!");
+                break;
+            case 'upgrade':
+                Service::upgrade($name, ['version' => $release, 'uid' => $uid, 'token' => $token]);
+                $output->info("Upgrade Successed!");
+                break;
+            case 'package':
+                $infoFile = $addonDir . 'info.ini';
+                if (!is_file($infoFile)) {
+                    throw new Exception(__('Addon info file was not found'));
+                }
+
+                $info = get_addon_info($name);
+                if (!$info) {
+                    throw new Exception(__('Addon info file data incorrect'));
+                }
+                $infoname = isset($info['name']) ? $info['name'] : '';
+                if (!$infoname || !preg_match("/^[a-z]+$/i", $infoname) || $infoname != $name) {
+                    throw new Exception(__('Addon info name incorrect'));
+                }
+
+                $infoversion = isset($info['version']) ? $info['version'] : '';
+                if (!$infoversion || !preg_match("/^\d+\.\d+\.\d+$/i", $infoversion)) {
+                    throw new Exception(__('Addon info version incorrect'));
+                }
+
+                $addonTmpDir = RUNTIME_PATH . 'addons' . DS;
+                if (!is_dir($addonTmpDir)) {
+                    @mkdir($addonTmpDir, 0755, true);
+                }
+                $addonFile = $addonTmpDir . $infoname . '-' . $infoversion . '.zip';
+                if (!class_exists('ZipArchive')) {
+                    throw new Exception(__('ZinArchive not install'));
+                }
+                $zip = new \ZipArchive;
+                $zip->open($addonFile, \ZipArchive::CREATE | \ZipArchive::OVERWRITE);
+
+                $files = new \RecursiveIteratorIterator(
+                    new \RecursiveDirectoryIterator($addonDir), \RecursiveIteratorIterator::LEAVES_ONLY
+                );
+
+                foreach ($files as $name => $file) {
+                    if (!$file->isDir()) {
+                        $filePath = $file->getRealPath();
+                        $relativePath = str_replace(DS, '/', substr($filePath, strlen($addonDir)));
+                        if (!in_array($file->getFilename(), ['.git', '.DS_Store', 'Thumbs.db'])) {
+                            $zip->addFile($filePath, $relativePath);
+                        }
+                    }
+                }
+                $zip->close();
+                $output->info("Package Successed!");
+                break;
+
+            default :
+                break;
+        }
+    }
+
+    /**
+     * 获取创建菜单的数组
+     * @param array $menu
+     * @return array
+     */
+    protected function getCreateMenu($menu)
+    {
+        $result = [];
+        foreach ($menu as $k => & $v) {
+            $arr = [
+                'name'  => $v['name'],
+                'title' => $v['title'],
+            ];
+            if ($v['icon'] != 'fa fa-circle-o') {
+                $arr['icon'] = $v['icon'];
+            }
+            if ($v['ismenu']) {
+                $arr['ismenu'] = $v['ismenu'];
+            }
+            if (isset($v['childlist']) && $v['childlist']) {
+                $arr['sublist'] = $this->getCreateMenu($v['childlist']);
+            }
+            $result[] = $arr;
+        }
+        return $result;
+    }
+
+    /**
+     * 写入到文件
+     * @param string $name
+     * @param array $data
+     * @param string $pathname
+     * @return mixed
+     */
+    protected function writeToFile($name, $data, $pathname)
+    {
+        $search = $replace = [];
+        foreach ($data as $k => $v) {
+            $search[] = "{%{$k}%}";
+            $replace[] = $v;
+        }
+        $stub = file_get_contents($this->getStub($name));
+        $content = str_replace($search, $replace, $stub);
+
+        if (!is_dir(dirname($pathname))) {
+            mkdir(strtolower(dirname($pathname)), 0755, true);
+        }
+        return file_put_contents($pathname, $content);
+    }
+
+    /**
+     * 获取基础模板
+     * @param string $name
+     * @return string
+     */
+    protected function getStub($name)
+    {
+        return __DIR__ . '/Addon/stubs/' . $name . '.stub';
+    }
+
+}

+ 68 - 0
application/admin/command/Addon/stubs/addon.stub

@@ -0,0 +1,68 @@
+<?php
+
+namespace addons\{%name%};
+
+use app\common\library\Menu;
+use think\Addons;
+
+/**
+ * 插件
+ */
+class {%addonClassName%} extends Addons
+{
+
+    /**
+     * 插件安装方法
+     * @return bool
+     */
+    public function install()
+    {
+        {%addonInstallMenu%}
+        return true;
+    }
+
+    /**
+     * 插件卸载方法
+     * @return bool
+     */
+    public function uninstall()
+    {
+        {%addonUninstallMenu%}
+        return true;
+    }
+
+    /**
+     * 插件启用方法
+     * @return bool
+     */
+    public function enable()
+    {
+        {%addonEnableMenu%}
+        return true;
+    }
+
+    /**
+     * 插件禁用方法
+     * @return bool
+     */
+    public function disable()
+    {
+        {%addonDisableMenu%}
+        return true;
+    }
+
+    /**
+     * 实现钩子方法
+     * @return mixed
+     */
+    public function testhook($param)
+    {
+        // 调用钩子时候的参数信息
+        print_r($param);
+        // 当前插件的配置信息,配置信息存在当前目录的config.php文件中,见下方
+        print_r($this->getConfig());
+        // 可以返回模板,模板文件默认读取的为插件目录中的文件。模板名不能为空!
+        //return $this->fetch('view/info');
+    }
+
+}

+ 40 - 0
application/admin/command/Addon/stubs/config.stub

@@ -0,0 +1,40 @@
+<?php
+
+return [
+    [
+        //配置唯一标识
+        'name'    => 'usernmae',
+        //显示的标题
+        'title'   => '用户名',
+        //类型
+        'type'    => 'string',
+        //数据字典
+        'content' => [
+        ],
+        //值
+        'value'   => '',
+        //验证规则 
+        'rule'    => 'required',
+        //错误消息
+        'msg'     => '',
+        //提示消息
+        'tip'     => '',
+        //成功消息
+        'ok'      => '',
+        //扩展信息
+        'extend'  => ''
+    ],
+    [
+        'name'    => 'password',
+        'title'   => '密码',
+        'type'    => 'string',
+        'content' => [
+        ],
+        'value'   => '',
+        'rule'    => 'required',
+        'msg'     => '',
+        'tip'     => '',
+        'ok'      => '',
+        'extend'  => ''
+    ],
+];

+ 15 - 0
application/admin/command/Addon/stubs/controller.stub

@@ -0,0 +1,15 @@
+<?php
+
+namespace addons\{%addon%}\controller;
+
+use think\addons\Controller;
+
+class Index extends Controller
+{
+
+    public function index()
+    {
+        $this->error("当前插件暂无前台页面");
+    }
+
+}

+ 7 - 0
application/admin/command/Addon/stubs/info.stub

@@ -0,0 +1,7 @@
+name = {%name%}
+title = 插件名称{%name%}
+intro = FastAdmin插件
+author = yourname
+website = https://www.fastadmin.net
+version = 1.0.0
+state = 1

+ 179 - 0
application/admin/command/Api.php

@@ -0,0 +1,179 @@
+<?php
+
+namespace app\admin\command;
+
+use app\admin\command\Api\library\Builder;
+use think\Config;
+use think\console\Command;
+use think\console\Input;
+use think\console\input\Option;
+use think\console\Output;
+use think\Exception;
+
+class Api extends Command
+{
+
+    protected function configure()
+    {
+        $site = Config::get('site');
+        $this
+            ->setName('api')
+            ->addOption('url', 'u', Option::VALUE_OPTIONAL, 'default api url', '')
+            ->addOption('module', 'm', Option::VALUE_OPTIONAL, 'module name(admin/index/api)', 'api')
+            ->addOption('output', 'o', Option::VALUE_OPTIONAL, 'output index file name', 'api.html')
+            ->addOption('template', 'e', Option::VALUE_OPTIONAL, '', 'index.html')
+            ->addOption('force', 'f', Option::VALUE_OPTIONAL, 'force override general file', false)
+            ->addOption('title', 't', Option::VALUE_OPTIONAL, 'document title', $site['name'])
+            ->addOption('author', 'a', Option::VALUE_OPTIONAL, 'document author', $site['name'])
+            ->addOption('class', 'c', Option::VALUE_OPTIONAL | Option::VALUE_IS_ARRAY, 'extend class', null)
+            ->addOption('language', 'l', Option::VALUE_OPTIONAL, 'language', 'zh-cn')
+            ->setDescription('Compress js and css file');
+    }
+
+    protected function execute(Input $input, Output $output)
+    {
+        $apiDir = __DIR__ . DS . 'Api' . DS;
+
+        $force = $input->getOption('force');
+        $url = $input->getOption('url');
+        $language = $input->getOption('language');
+        $language = $language ? $language : 'zh-cn';
+        $langFile = $apiDir . 'lang' . DS . $language . '.php';
+        if (!is_file($langFile)) {
+            throw new Exception('language file not found');
+        }
+        $lang = include_once $langFile;
+        // 目标目录
+        $output_dir = ROOT_PATH . 'public' . DS;
+        $output_file = $output_dir . $input->getOption('output');
+        if (is_file($output_file) && !$force) {
+            throw new Exception("api index file already exists!\nIf you need to rebuild again, use the parameter --force=true ");
+        }
+        // 模板文件
+        $template_dir = $apiDir . 'template' . DS;
+        $template_file = $template_dir . $input->getOption('template');
+        if (!is_file($template_file)) {
+            throw new Exception('template file not found');
+        }
+        // 额外的类
+        $classes = $input->getOption('class');
+        // 标题
+        $title = $input->getOption('title');
+        // 作者
+        $author = $input->getOption('author');
+        // 模块
+        $module = $input->getOption('module');
+
+        $moduleDir = APP_PATH . $module . DS;
+        if (!is_dir($moduleDir)) {
+            throw new Exception('module not found');
+        }
+
+        if (version_compare(PHP_VERSION, '7.0.0', '<')) {
+            if (extension_loaded('Zend OPcache')) {
+                $configuration = opcache_get_configuration();
+                $directives = $configuration['directives'];
+                $configName = request()->isCli() ? 'opcache.enable_cli' : 'opcache.enable';
+                if (!$directives[$configName]) {
+                    throw new Exception("Please make sure {$configName} is turned on, Get help:https://forum.fastadmin.net/d/1321");
+                }
+            } else {
+                throw new Exception("Please make sure opcache already enabled, Get help:https://forum.fastadmin.net/d/1321");
+            }
+        }
+
+        $controllerDir = $moduleDir . Config::get('url_controller_layer') . DS;
+        $files = new \RecursiveIteratorIterator(
+            new \RecursiveDirectoryIterator($controllerDir), \RecursiveIteratorIterator::LEAVES_ONLY
+        );
+
+        foreach ($files as $name => $file) {
+            if (!$file->isDir() && $file->getExtension() == 'php') {
+                $filePath = $file->getRealPath();
+                $classes[] = $this->get_class_from_file($filePath);
+            }
+        }
+        $classes = array_unique(array_filter($classes));
+
+        $config = [
+            'title'       => $title,
+            'author'      => $author,
+            'description' => '',
+            'apiurl'      => $url,
+            'language'    => $language,
+        ];
+        $builder = new Builder($classes);
+        $content = $builder->render($template_file, ['config' => $config, 'lang' => $lang]);
+
+        if (!file_put_contents($output_file, $content)) {
+            throw new Exception('Cannot save the content to ' . $output_file);
+        }
+        $output->info("Build Successed!");
+    }
+
+    /**
+     * get full qualified class name
+     *
+     * @param string $path_to_file
+     * @author JBYRNE http://jarretbyrne.com/2015/06/197/
+     * @return string
+     */
+    protected function get_class_from_file($path_to_file)
+    {
+        //Grab the contents of the file
+        $contents = file_get_contents($path_to_file);
+
+        //Start with a blank namespace and class
+        $namespace = $class = "";
+
+        //Set helper values to know that we have found the namespace/class token and need to collect the string values after them
+        $getting_namespace = $getting_class = false;
+
+        //Go through each token and evaluate it as necessary
+        foreach (token_get_all($contents) as $token) {
+
+            //If this token is the namespace declaring, then flag that the next tokens will be the namespace name
+            if (is_array($token) && $token[0] == T_NAMESPACE) {
+                $getting_namespace = true;
+            }
+
+            //If this token is the class declaring, then flag that the next tokens will be the class name
+            if (is_array($token) && $token[0] == T_CLASS) {
+                $getting_class = true;
+            }
+
+            //While we're grabbing the namespace name...
+            if ($getting_namespace === true) {
+
+                //If the token is a string or the namespace separator...
+                if (is_array($token) && in_array($token[0], [T_STRING, T_NS_SEPARATOR])) {
+
+                    //Append the token's value to the name of the namespace
+                    $namespace .= $token[1];
+                } else if ($token === ';') {
+
+                    //If the token is the semicolon, then we're done with the namespace declaration
+                    $getting_namespace = false;
+                }
+            }
+
+            //While we're grabbing the class name...
+            if ($getting_class === true) {
+
+                //If the token is a string, it's the name of the class
+                if (is_array($token) && $token[0] == T_STRING) {
+
+                    //Store the token's value as the class name
+                    $class = $token[1];
+
+                    //Got what we need, stope here
+                    break;
+                }
+            }
+        }
+
+        //Build the fully-qualified class name and return it
+        return $namespace ? $namespace . '\\' . $class : $class;
+    }
+
+}

+ 22 - 0
application/admin/command/Api/lang/zh-cn.php

@@ -0,0 +1,22 @@
+<?php
+
+return [
+    'Info'             => '基础信息',
+    'Sandbox'          => '在线测试',
+    'Sampleoutput'     => '返回示例',
+    'Headers'          => 'Headers',
+    'Parameters'       => '参数',
+    'Body'             => '正文',
+    'Name'             => '名称',
+    'Type'             => '类型',
+    'Required'         => '必选',
+    'Description'      => '描述',
+    'Send'             => '提交',
+    'Reset'            => '重置',
+    'Tokentips'        => 'Token在会员注册或登录后都会返回,WEB端同时存在于Cookie中',
+    'Apiurltips'       => 'API接口URL',
+    'Savetips'         => '点击保存后Token和Api url都将保存在本地Localstorage中',
+    'ReturnHeaders'    => '响应头',
+    'ReturnParameters' => '返回参数',
+    'Response'         => '响应输出',
+];

+ 207 - 0
application/admin/command/Api/library/Builder.php

@@ -0,0 +1,207 @@
+<?php
+
+namespace app\admin\command\Api\library;
+
+use think\Config;
+
+/**
+ * @website https://github.com/calinrada/php-apidoc
+ * @author  Calin Rada <rada.calin@gmail.com>
+ * @author  Karson <karsonzhang@163.com>
+ */
+class Builder
+{
+
+    /**
+     *
+     * @var \think\View
+     */
+    public $view = null;
+
+    /**
+     * parse classes
+     * @var array
+     */
+    protected $classes = [];
+
+    /**
+     *
+     * @param array $classes
+     */
+    public function __construct($classes = [])
+    {
+        $this->classes = array_merge($this->classes, $classes);
+        $this->view = new \think\View(Config::get('template'), Config::get('view_replace_str'));
+    }
+
+    protected function extractAnnotations()
+    {
+        $st_output = [];
+        foreach ($this->classes as $class) {
+            $classAnnotation = Extractor::getClassAnnotations($class);
+            // 如果忽略
+            if (isset($classAnnotation['ApiInternal'])) {
+                continue;
+            }
+            $st_output[] = Extractor::getAllClassAnnotations($class);
+        }
+        return end($st_output);
+    }
+
+    protected function generateHeadersTemplate($docs)
+    {
+        if (!isset($docs['ApiHeaders'])) {
+            return [];
+        }
+
+        $headerslist = array();
+        foreach ($docs['ApiHeaders'] as $params) {
+            $tr = array(
+                'name'        => $params['name'],
+                'type'        => $params['type'],
+                'sample'      => isset($params['sample']) ? $params['sample'] : '',
+                'required'    => isset($params['required']) ? $params['required'] : false,
+                'description' => isset($params['description']) ? $params['description'] : '',
+            );
+            $headerslist[] = $tr;
+        }
+
+        return $headerslist;
+    }
+
+    protected function generateParamsTemplate($docs)
+    {
+        if (!isset($docs['ApiParams'])) {
+            return [];
+        }
+
+        $paramslist = array();
+        foreach ($docs['ApiParams'] as $params) {
+            $tr = array(
+                'name'        => $params['name'],
+                'type'        => isset($params['type']) ? $params['type'] : 'string',
+                'sample'      => isset($params['sample']) ? $params['sample'] : '',
+                'required'    => isset($params['required']) ? $params['required'] : true,
+                'description' => isset($params['description']) ? $params['description'] : '',
+            );
+            $paramslist[] = $tr;
+        }
+
+        return $paramslist;
+    }
+
+    protected function generateReturnHeadersTemplate($docs)
+    {
+        if (!isset($docs['ApiReturnHeaders'])) {
+            return [];
+        }
+
+        $headerslist = array();
+        foreach ($docs['ApiReturnHeaders'] as $params) {
+            $tr = array(
+                'name'        => $params['name'],
+                'type'        => 'string',
+                'sample'      => isset($params['sample']) ? $params['sample'] : '',
+                'required'    => isset($params['required']) && $params['required'] ? 'Yes' : 'No',
+                'description' => isset($params['description']) ? $params['description'] : '',
+            );
+            $headerslist[] = $tr;
+        }
+
+        return $headerslist;
+    }
+
+    protected function generateReturnParamsTemplate($st_params)
+    {
+        if (!isset($st_params['ApiReturnParams'])) {
+            return [];
+        }
+
+        $paramslist = array();
+        foreach ($st_params['ApiReturnParams'] as $params) {
+            $tr = array(
+                'name'        => $params['name'],
+                'type'        => isset($params['type']) ? $params['type'] : 'string',
+                'sample'      => isset($params['sample']) ? $params['sample'] : '',
+                'description' => isset($params['description']) ? $params['description'] : '',
+            );
+            $paramslist[] = $tr;
+        }
+
+        return $paramslist;
+    }
+
+    protected function generateBadgeForMethod($data)
+    {
+        $method = strtoupper(is_array($data['ApiMethod'][0]) ? $data['ApiMethod'][0]['data'] : $data['ApiMethod'][0]);
+        $labes = array(
+            'POST'    => 'label-primary',
+            'GET'     => 'label-success',
+            'PUT'     => 'label-warning',
+            'DELETE'  => 'label-danger',
+            'PATCH'   => 'label-default',
+            'OPTIONS' => 'label-info'
+        );
+
+        return isset($labes[$method]) ? $labes[$method] : $labes['GET'];
+    }
+
+    public function parse()
+    {
+        $annotations = $this->extractAnnotations();
+
+        $counter = 0;
+        $section = null;
+        $docslist = [];
+        foreach ($annotations as $class => $methods) {
+            foreach ($methods as $name => $docs) {
+                if (isset($docs['ApiSector'][0])) {
+                    $section = is_array($docs['ApiSector'][0]) ? $docs['ApiSector'][0]['data'] : $docs['ApiSector'][0];
+                } else {
+                    $section = $class;
+                }
+                if (0 === count($docs)) {
+                    continue;
+                }
+
+                $docslist[$section][] = [
+                    'id'                => $counter,
+                    'method'            => is_array($docs['ApiMethod'][0]) ? $docs['ApiMethod'][0]['data'] : $docs['ApiMethod'][0],
+                    'method_label'      => $this->generateBadgeForMethod($docs),
+                    'section'           => $section,
+                    'route'             => is_array($docs['ApiRoute'][0]) ? $docs['ApiRoute'][0]['data'] : $docs['ApiRoute'][0],
+                    'title'           => is_array($docs['ApiTitle'][0]) ? $docs['ApiTitle'][0]['data'] : $docs['ApiTitle'][0],
+                    'summary'           => is_array($docs['ApiSummary'][0]) ? $docs['ApiSummary'][0]['data'] : $docs['ApiSummary'][0],
+                    'body'              => isset($docs['ApiBody'][0]) ? is_array($docs['ApiBody'][0]) ? $docs['ApiBody'][0]['data'] : $docs['ApiBody'][0] : '',
+                    'headerslist'       => $this->generateHeadersTemplate($docs),
+                    'paramslist'        => $this->generateParamsTemplate($docs),
+                    'returnheaderslist' => $this->generateReturnHeadersTemplate($docs),
+                    'returnparamslist'  => $this->generateReturnParamsTemplate($docs),
+                    'return'            => isset($docs['ApiReturn']) ? is_array($docs['ApiReturn'][0]) ? $docs['ApiReturn'][0]['data'] : $docs['ApiReturn'][0] : '',
+                ];
+                $counter++;
+            }
+        }
+
+        return $docslist;
+    }
+
+    public function getView()
+    {
+        return $this->view;
+    }
+
+    /**
+     * 渲染
+     * @param string $template
+     * @param array $vars
+     * @return string
+     */
+    public function render($template, $vars = [])
+    {
+        $docslist = $this->parse();
+
+        return $this->view->display(file_get_contents($template), array_merge($vars, ['docslist' => $docslist]));
+    }
+
+}

+ 483 - 0
application/admin/command/Api/library/Extractor.php

@@ -0,0 +1,483 @@
+<?php
+
+namespace app\admin\command\Api\library;
+
+use Exception;
+
+/**
+ * Class imported from https://github.com/eriknyk/Annotations
+ * @author  Erik Amaru Ortiz https://github.com/eriknyk‎
+ *
+ * @license http://opensource.org/licenses/bsd-license.php The BSD License
+ * @author  Calin Rada <rada.calin@gmail.com>
+ */
+class Extractor
+{
+
+    /**
+     * Static array to store already parsed annotations
+     * @var array
+     */
+    private static $annotationCache;
+
+    /**
+     * Indicates that annotations should has strict behavior, 'false' by default
+     * @var boolean
+     */
+    private $strict = false;
+
+    /**
+     * Stores the default namespace for Objects instance, usually used on methods like getMethodAnnotationsObjects()
+     * @var string
+     */
+    public $defaultNamespace = '';
+
+    /**
+     * Sets strict variable to true/false
+     * @param bool $value boolean value to indicate that annotations to has strict behavior
+     */
+    public function setStrict($value)
+    {
+        $this->strict = (bool)$value;
+    }
+
+    /**
+     * Sets default namespace to use in object instantiation
+     * @param string $namespace default namespace
+     */
+    public function setDefaultNamespace($namespace)
+    {
+        $this->defaultNamespace = $namespace;
+    }
+
+    /**
+     * Gets default namespace used in object instantiation
+     * @return string $namespace default namespace
+     */
+    public function getDefaultAnnotationNamespace()
+    {
+        return $this->defaultNamespace;
+    }
+
+    /**
+     * Gets all anotations with pattern @SomeAnnotation() from a given class
+     *
+     * @param  string $className class name to get annotations
+     * @return array  self::$annotationCache all annotated elements
+     */
+    public static function getClassAnnotations($className)
+    {
+        if (!isset(self::$annotationCache[$className])) {
+            $class = new \ReflectionClass($className);
+            self::$annotationCache[$className] = self::parseAnnotations($class->getDocComment());
+        }
+
+        return self::$annotationCache[$className];
+    }
+
+    public static function getAllClassAnnotations($className)
+    {
+        $class = new \ReflectionClass($className);
+
+        foreach ($class->getMethods() as $object) {
+            self::$annotationCache['annotations'][$className][$object->name] = self::getMethodAnnotations($className, $object->name);
+        }
+
+        return self::$annotationCache['annotations'];
+    }
+
+    /**
+     * Gets all anotations with pattern @SomeAnnotation() from a determinated method of a given class
+     *
+     * @param  string $className class name
+     * @param  string $methodName method name to get annotations
+     * @return array  self::$annotationCache all annotated elements of a method given
+     */
+    public static function getMethodAnnotations($className, $methodName)
+    {
+        if (!isset(self::$annotationCache[$className . '::' . $methodName])) {
+            try {
+                $method = new \ReflectionMethod($className, $methodName);
+                $class = new \ReflectionClass($className);
+                if (!$method->isPublic() || $method->isConstructor()) {
+                    $annotations = array();
+                } else {
+                    $annotations = self::consolidateAnnotations($method, $class);
+                }
+            } catch (\ReflectionException $e) {
+                $annotations = array();
+            }
+
+            self::$annotationCache[$className . '::' . $methodName] = $annotations;
+        }
+
+        return self::$annotationCache[$className . '::' . $methodName];
+    }
+
+    /**
+     * Gets all anotations with pattern @SomeAnnotation() from a determinated method of a given class
+     * and instance its abcAnnotation class
+     *
+     * @param  string $className class name
+     * @param  string $methodName method name to get annotations
+     * @return array  self::$annotationCache all annotated objects of a method given
+     */
+    public function getMethodAnnotationsObjects($className, $methodName)
+    {
+        $annotations = $this->getMethodAnnotations($className, $methodName);
+        $objects = array();
+
+        $i = 0;
+
+        foreach ($annotations as $annotationClass => $listParams) {
+            $annotationClass = ucfirst($annotationClass);
+            $class = $this->defaultNamespace . $annotationClass . 'Annotation';
+
+            // verify is the annotation class exists, depending if Annotations::strict is true
+            // if not, just skip the annotation instance creation.
+            if (!class_exists($class)) {
+                if ($this->strict) {
+                    throw new Exception(sprintf('Runtime Error: Annotation Class Not Found: %s', $class));
+                } else {
+                    // silent skip & continue
+                    continue;
+                }
+            }
+
+            if (empty($objects[$annotationClass])) {
+                $objects[$annotationClass] = new $class();
+            }
+
+            foreach ($listParams as $params) {
+                if (is_array($params)) {
+                    foreach ($params as $key => $value) {
+                        $objects[$annotationClass]->set($key, $value);
+                    }
+                } else {
+                    $objects[$annotationClass]->set($i++, $params);
+                }
+            }
+        }
+
+        return $objects;
+    }
+
+    private static function consolidateAnnotations($method, $class)
+    {
+        $dockblockClass = $class->getDocComment();
+        $docblockMethod = $method->getDocComment();
+        $methodName = $method->getName();
+
+        $methodAnnotations = self::parseAnnotations($docblockMethod);
+        $classAnnotations = self::parseAnnotations($dockblockClass);
+        if (isset($methodAnnotations['ApiInternal']) || $methodName == '_initialize' || $methodName == '_empty') {
+            return [];
+        }
+
+        $properties = $class->getDefaultProperties();
+        $noNeedLogin = isset($properties['noNeedLogin']) ? is_array($properties['noNeedLogin']) ? $properties['noNeedLogin'] : [$properties['noNeedLogin']] : [];
+        $noNeedRight = isset($properties['noNeedRight']) ? is_array($properties['noNeedRight']) ? $properties['noNeedRight'] : [$properties['noNeedRight']] : [];
+
+        preg_match_all("/\*[\s]+(.*)(\\r\\n|\\r|\\n)/U", str_replace('/**', '', $docblockMethod), $methodArr);
+        preg_match_all("/\*[\s]+(.*)(\\r\\n|\\r|\\n)/U", str_replace('/**', '', $dockblockClass), $classArr);
+
+        $methodTitle = isset($methodArr[1]) && isset($methodArr[1][0]) ? $methodArr[1][0] : '';
+        $classTitle = isset($classArr[1]) && isset($classArr[1][0]) ? $classArr[1][0] : '';
+
+        if (!isset($methodAnnotations['ApiMethod'])) {
+            $methodAnnotations['ApiMethod'] = ['get'];
+        }
+        if (!isset($methodAnnotations['ApiSummary'])) {
+            $methodAnnotations['ApiSummary'] = [$methodTitle];
+        }
+
+        if ($methodAnnotations) {
+            foreach ($classAnnotations as $name => $valueClass) {
+                if (count($valueClass) !== 1) {
+                    continue;
+                }
+
+                if ($name === 'ApiRoute') {
+                    if (isset($methodAnnotations[$name])) {
+                        $methodAnnotations[$name] = [rtrim($valueClass[0], '/') . $methodAnnotations[$name][0]];
+                    } else {
+                        $methodAnnotations[$name] = [rtrim($valueClass[0], '/') . '/' . $method->getName()];
+                    }
+                }
+
+                if ($name === 'ApiSector') {
+                    $methodAnnotations[$name] = $valueClass;
+                }
+            }
+        }
+        if (!isset($methodAnnotations['ApiTitle'])) {
+            $methodAnnotations['ApiTitle'] = [$methodTitle];
+        }
+        if (!isset($methodAnnotations['ApiRoute'])) {
+            $urlArr = [];
+            $className = $class->getName();
+
+            list($prefix, $suffix) = explode('\\' . \think\Config::get('url_controller_layer') . '\\', $className);
+            $prefixArr = explode('\\', $prefix);
+            $suffixArr = explode('\\', $suffix);
+            if ($prefixArr[0] == \think\Config::get('app_namespace')) {
+                $prefixArr[0] = '';
+            }
+            $urlArr = array_merge($urlArr, $prefixArr);
+            $urlArr[] = implode('.', array_map(function ($item) {
+                return \think\Loader::parseName($item);
+            }, $suffixArr));
+            $urlArr[] = $method->getName();
+            $methodAnnotations['ApiRoute'] = [implode('/', $urlArr)];
+        }
+        if (!isset($methodAnnotations['ApiSector'])) {
+            $methodAnnotations['ApiSector'] = isset($classAnnotations['ApiSector']) ? $classAnnotations['ApiSector'] : [$classTitle];
+        }
+        if (!isset($methodAnnotations['ApiParams'])) {
+            $params = self::parseCustomAnnotations($docblockMethod, 'param');
+            foreach ($params as $k => $v) {
+                $arr = explode(' ', preg_replace("/[\s]+/", " ", $v));
+                $methodAnnotations['ApiParams'][] = [
+                    'name'        => isset($arr[1]) ? str_replace('$', '', $arr[1]) : '',
+                    'nullable'    => false,
+                    'type'        => isset($arr[0]) ? $arr[0] : 'string',
+                    'description' => isset($arr[2]) ? $arr[2] : ''
+                ];
+            }
+        }
+        $methodAnnotations['ApiPermissionLogin'] = [!in_array('*', $noNeedLogin) && !in_array($methodName, $noNeedLogin)];
+        $methodAnnotations['ApiPermissionRight'] = [!in_array('*', $noNeedRight) && !in_array($methodName, $noNeedRight)];
+        return $methodAnnotations;
+    }
+
+    /**
+     * Parse annotations
+     *
+     * @param  string $docblock
+     * @param  string $name
+     * @return array  parsed annotations params
+     */
+    private static function parseCustomAnnotations($docblock, $name = 'param')
+    {
+        $annotations = array();
+
+        $docblock = substr($docblock, 3, -2);
+        if (preg_match_all('/@' . $name . '(?:\s*(?:\(\s*)?(.*?)(?:\s*\))?)??\s*(?:\n|\*\/)/', $docblock, $matches)) {
+            foreach ($matches[1] as $k => $v) {
+                $annotations[] = $v;
+            }
+        }
+        return $annotations;
+    }
+
+    /**
+     * Parse annotations
+     *
+     * @param  string $docblock
+     * @return array  parsed annotations params
+     */
+    private static function parseAnnotations($docblock)
+    {
+        $annotations = array();
+
+        // Strip away the docblock header and footer to ease parsing of one line annotations
+        $docblock = substr($docblock, 3, -2);
+        if (preg_match_all('/@(?<name>[A-Za-z_-]+)[\s\t]*\((?<args>(?:(?!\)).)*)\)\r?/s', $docblock, $matches)) {
+            $numMatches = count($matches[0]);
+            for ($i = 0; $i < $numMatches; ++$i) {
+                $name = $matches['name'][$i];
+                $value = '';
+                // annotations has arguments
+                if (isset($matches['args'][$i])) {
+                    $argsParts = trim($matches['args'][$i]);
+                    if ($name == 'ApiReturn') {
+                        $value = $argsParts;
+                    } else if ($matches['args'][$i] != '') {
+                        $argsParts = preg_replace("/\{(\w+)\}/", '#$1#', $argsParts);
+                        $value = self::parseArgs($argsParts);
+                        if (is_string($value)) {
+                            $value = preg_replace("/\#(\w+)\#/", '{$1}', $argsParts);
+                        }
+                    }
+                }
+
+                $annotations[$name][] = $value;
+            }
+        }
+        if (stripos($docblock, '@ApiInternal') !== false) {
+            $annotations['ApiInternal'] = [true];
+        }
+
+        return $annotations;
+    }
+
+    /**
+     * Parse individual annotation arguments
+     *
+     * @param  string $content arguments string
+     * @return array  annotated arguments
+     */
+    private static function parseArgs($content)
+    {
+        // Replace initial stars
+        $content = preg_replace('/^\s*\*/m', '', $content);
+
+        $data = array();
+        $len = strlen($content);
+        $i = 0;
+        $var = '';
+        $val = '';
+        $level = 1;
+
+        $prevDelimiter = '';
+        $nextDelimiter = '';
+        $nextToken = '';
+        $composing = false;
+        $type = 'plain';
+        $delimiter = null;
+        $quoted = false;
+        $tokens = array('"', '"', '{', '}', ',', '=');
+
+        while ($i <= $len) {
+            $prev_c = substr($content, $i - 1, 1);
+            $c = substr($content, $i++, 1);
+
+            if ($c === '"' && $prev_c !== "\\") {
+                $delimiter = $c;
+                //open delimiter
+                if (!$composing && empty($prevDelimiter) && empty($nextDelimiter)) {
+                    $prevDelimiter = $nextDelimiter = $delimiter;
+                    $val = '';
+                    $composing = true;
+                    $quoted = true;
+                } else {
+                    // close delimiter
+                    if ($c !== $nextDelimiter) {
+                        throw new Exception(sprintf(
+                            "Parse Error: enclosing error -> expected: [%s], given: [%s]", $nextDelimiter, $c
+                        ));
+                    }
+
+                    // validating syntax
+                    if ($i < $len) {
+                        if (',' !== substr($content, $i, 1) && '\\' !== $prev_c) {
+                            throw new Exception(sprintf(
+                                "Parse Error: missing comma separator near: ...%s<--", substr($content, ($i - 10), $i)
+                            ));
+                        }
+                    }
+
+                    $prevDelimiter = $nextDelimiter = '';
+                    $composing = false;
+                    $delimiter = null;
+                }
+            } elseif (!$composing && in_array($c, $tokens)) {
+                switch ($c) {
+                    case '=':
+                        $prevDelimiter = $nextDelimiter = '';
+                        $level = 2;
+                        $composing = false;
+                        $type = 'assoc';
+                        $quoted = false;
+                        break;
+                    case ',':
+                        $level = 3;
+
+                        // If composing flag is true yet,
+                        // it means that the string was not enclosed, so it is parsing error.
+                        if ($composing === true && !empty($prevDelimiter) && !empty($nextDelimiter)) {
+                            throw new Exception(sprintf(
+                                "Parse Error: enclosing error -> expected: [%s], given: [%s]", $nextDelimiter, $c
+                            ));
+                        }
+
+                        $prevDelimiter = $nextDelimiter = '';
+                        break;
+                    case '{':
+                        $subc = '';
+                        $subComposing = true;
+
+                        while ($i <= $len) {
+                            $c = substr($content, $i++, 1);
+
+                            if (isset($delimiter) && $c === $delimiter) {
+                                throw new Exception(sprintf(
+                                    "Parse Error: Composite variable is not enclosed correctly."
+                                ));
+                            }
+
+                            if ($c === '}') {
+                                $subComposing = false;
+                                break;
+                            }
+                            $subc .= $c;
+                        }
+
+                        // if the string is composing yet means that the structure of var. never was enclosed with '}'
+                        if ($subComposing) {
+                            throw new Exception(sprintf(
+                                "Parse Error: Composite variable is not enclosed correctly. near: ...%s'", $subc
+                            ));
+                        }
+
+                        $val = self::parseArgs($subc);
+                        break;
+                }
+            } else {
+                if ($level == 1) {
+                    $var .= $c;
+                } elseif ($level == 2) {
+                    $val .= $c;
+                }
+            }
+
+            if ($level === 3 || $i === $len) {
+                if ($type == 'plain' && $i === $len) {
+                    $data = self::castValue($var);
+                } else {
+                    $data[trim($var)] = self::castValue($val, !$quoted);
+                }
+
+                $level = 1;
+                $var = $val = '';
+                $composing = false;
+                $quoted = false;
+            }
+        }
+
+        return $data;
+    }
+
+    /**
+     * Try determinate the original type variable of a string
+     *
+     * @param  string $val string containing possibles variables that can be cast to bool or int
+     * @param  boolean $trim indicate if the value passed should be trimmed after to try cast
+     * @return mixed   returns the value converted to original type if was possible
+     */
+    private static function castValue($val, $trim = false)
+    {
+        if (is_array($val)) {
+            foreach ($val as $key => $value) {
+                $val[$key] = self::castValue($value);
+            }
+        } elseif (is_string($val)) {
+            if ($trim) {
+                $val = trim($val);
+            }
+            $val = stripslashes($val);
+            $tmp = strtolower($val);
+
+            if ($tmp === 'false' || $tmp === 'true') {
+                $val = $tmp === 'true';
+            } elseif (is_numeric($val)) {
+                return $val + 0;
+            }
+
+            unset($tmp);
+        }
+
+        return $val;
+    }
+
+}

+ 576 - 0
application/admin/command/Api/template/index.html

@@ -0,0 +1,576 @@
+<!DOCTYPE html>
+<html lang="{$config.language}">
+    <head>
+        <meta charset="utf-8">
+        <meta http-equiv="X-UA-Compatible" content="IE=edge">
+        <meta name="viewport" content="width=device-width, initial-scale=1.0">
+        <meta name="description" content="">
+        <meta name="author" content="{$config.author}">
+        <title>{$config.title}</title>
+
+        <!-- Bootstrap Core CSS -->
+        <link href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
+
+        <!-- Plugin CSS -->
+        <link href="https://cdn.staticfile.org/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
+
+        <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
+        <!--[if lt IE 9]>
+        <script src="https://cdn.staticfile.org/html5shiv/3.7.3/html5shiv.min.js"></script>
+        <script src="https://cdn.staticfile.org/respond.js/1.4.2/respond.min.js"></script>
+        <![endif]-->
+
+        <style type="text/css">
+            body {
+                padding-top: 70px; margin-bottom: 15px;
+                -webkit-font-smoothing: antialiased;
+                -moz-osx-font-smoothing: grayscale;
+                font-family: "Roboto", "SF Pro SC", "SF Pro Display", "SF Pro Icons", "PingFang SC", BlinkMacSystemFont, -apple-system, "Segoe UI", "Microsoft Yahei", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", "Helvetica", "Arial", sans-serif;
+                font-weight: 400;
+            }
+            h2        { font-size: 1.6em; }
+            hr        { margin-top: 10px; }
+            .tab-pane { padding-top: 10px; }
+            .mt0      { margin-top: 0px; }
+            .footer   { font-size: 12px; color: #666; }
+            .label    { display: inline-block; min-width: 65px; padding: 0.3em 0.6em 0.3em; }
+            .string   { color: green; }
+            .number   { color: darkorange; }
+            .boolean  { color: blue; }
+            .null     { color: magenta; }
+            .key      { color: red; }
+            .popover  { max-width: 400px; max-height: 400px; overflow-y: auto;}
+            .list-group.panel > .list-group-item {
+            }
+            .list-group-item:last-child {
+                border-radius:0;
+            }
+            h4.panel-title a {
+                font-weight:normal;
+                font-size:14px;
+            }
+            h4.panel-title a .text-muted {
+                font-size:12px;
+                font-weight:normal;
+                font-family: 'Verdana';
+            }
+            #sidebar {
+                width: 220px;
+                position: fixed;
+                margin-left: -240px;
+                overflow-y:auto;
+            }
+            #sidebar > .list-group {
+                margin-bottom:0;
+            }
+            #sidebar > .list-group > a{
+                text-indent:0;
+            }
+            #sidebar .child {
+                border:1px solid #ddd;
+                border-bottom:none;
+            }
+            #sidebar .child > a {
+                border:0;
+            }
+            #sidebar .list-group a.current {
+                background:#f5f5f5;
+            }
+            @media (max-width: 1620px){
+                #sidebar {
+                    margin:0;
+                }
+                #accordion {
+                    padding-left:235px;
+                }
+            }
+            @media (max-width: 768px){
+                #sidebar {
+                    display: none;
+                }
+                #accordion {
+                    padding-left:0px;
+                }
+            }
+
+        </style>
+    </head>
+    <body>
+        <!-- Fixed navbar -->
+        <div class="navbar navbar-default navbar-fixed-top" role="navigation">
+            <div class="container">
+                <div class="navbar-header">
+                    <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
+                        <span class="sr-only">Toggle navigation</span>
+                        <span class="icon-bar"></span>
+                        <span class="icon-bar"></span>
+                        <span class="icon-bar"></span>
+                    </button>
+                    <a class="navbar-brand" href="https://www.fastadmin.net" target="_blank">{$config.title}</a>
+                </div>
+                <div class="navbar-collapse collapse">
+                    <form class="navbar-form navbar-right">
+                        <div class="form-group">
+                            Token:
+                        </div>
+                        <div class="form-group">
+                            <input type="text" class="form-control input-sm" data-toggle="tooltip" title="{$lang.Tokentips}" placeholder="token" id="token" />
+                        </div>
+                        <div class="form-group">
+                            Apiurl:
+                        </div>
+                        <div class="form-group">
+                            <input id="apiUrl" type="text" class="form-control input-sm" data-toggle="tooltip" title="{$lang.Apiurltips}" placeholder="https://api.mydomain.com" value="{$config.apiurl}" />
+                        </div>
+                        <div class="form-group">
+                            <button type="button" class="btn btn-success btn-sm" data-toggle="tooltip" title="{$lang.Savetips}" id="save_data">
+                                <span class="glyphicon glyphicon-floppy-disk" aria-hidden="true"></span>
+                            </button>
+                        </div>
+                    </form>
+                </div><!--/.nav-collapse -->
+            </div>
+        </div>
+
+        <div class="container">
+            <!-- menu -->
+            <div id="sidebar">
+                <div class="list-group panel">
+                    {foreach name="docslist" id="docs"}
+                    <a href="#{$key}" class="list-group-item" data-toggle="collapse" data-parent="#sidebar">{$key}  <i class="fa fa-caret-down"></i></a>
+                    <div class="child collapse" id="{$key}">
+                        {foreach name="docs" id="api" }
+                        <a href="javascript:;" data-id="{$api.id}" class="list-group-item">{$api.title}</a>
+                        {/foreach}
+                    </div>
+                    {/foreach}
+                </div>
+            </div>
+            <div class="panel-group" id="accordion">
+                {foreach name="docslist" id="docs"}
+                <h2>{$key}</h2>
+                <hr>
+                {foreach name="docs" id="api" }
+                <div class="panel panel-default">
+                    <div class="panel-heading" id="heading-{$api.id}">
+                        <h4 class="panel-title">
+                            <span class="label {$api.method_label}">{$api.method|strtoupper}</span>
+                            <a data-toggle="collapse" data-parent="#accordion{$api.id}" href="#collapseOne{$api.id}"> {$api.title} <span class="text-muted">{$api.route}</span></a>
+                        </h4>
+                    </div>
+                    <div id="collapseOne{$api.id}" class="panel-collapse collapse">
+                        <div class="panel-body">
+
+                            <!-- Nav tabs -->
+                            <ul class="nav nav-tabs" id="doctab{$api.id}">
+                                <li class="active"><a href="#info{$api.id}" data-toggle="tab">{$lang.Info}</a></li>
+                                <li><a href="#sandbox{$api.id}" data-toggle="tab">{$lang.Sandbox}</a></li>
+                                <li><a href="#sample{$api.id}" data-toggle="tab">{$lang.Sampleoutput}</a></li>
+                            </ul>
+
+                            <!-- Tab panes -->
+                            <div class="tab-content">
+
+                                <div class="tab-pane active" id="info{$api.id}">
+                                    <div class="well">
+                                        {$api.summary}
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>{$lang.Headers}</strong></div>
+                                        <div class="panel-body">
+                                            {if $api.headerslist}
+                                            <table class="table table-hover">
+                                                <thead>
+                                                    <tr>
+                                                        <th>{$lang.Name}</th>
+                                                        <th>{$lang.Type}</th>
+                                                        <th>{$lang.Required}</th>
+                                                        <th>{$lang.Description}</th>
+                                                    </tr>
+                                                </thead>
+                                                <tbody>
+                                                    {foreach name="api['headerslist']" id="header"}
+                                                    <tr>
+                                                        <td>{$header.name}</td>
+                                                        <td>{$header.type}</td>
+                                                        <td>{$header.required?'是':'否'}</td>
+                                                        <td>{$header.description}</td>
+                                                    </tr>
+                                                    {/foreach}
+                                                </tbody>
+                                            </table>
+                                            {else /}
+                                            无
+                                            {/if}
+                                        </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>{$lang.Parameters}</strong></div>
+                                        <div class="panel-body">
+                                            {if $api.paramslist}
+                                            <table class="table table-hover">
+                                                <thead>
+                                                    <tr>
+                                                        <th>{$lang.Name}</th>
+                                                        <th>{$lang.Type}</th>
+                                                        <th>{$lang.Required}</th>
+                                                        <th>{$lang.Description}</th>
+                                                    </tr>
+                                                </thead>
+                                                <tbody>
+                                                    {foreach name="api['paramslist']" id="param"}
+                                                    <tr>
+                                                        <td>{$param.name}</td>
+                                                        <td>{$param.type}</td>
+                                                        <td>{:$param.required?'是':'否'}</td>
+                                                        <td>{$param.description}</td>
+                                                    </tr>
+                                                    {/foreach}
+                                                </tbody>
+                                            </table>
+                                            {else /}
+                                            无
+                                            {/if}
+                                        </div>
+                                    </div>
+                                    <div class="panel panel-default">
+                                        <div class="panel-heading"><strong>{$lang.Body}</strong></div>
+                                        <div class="panel-body">
+                                            {$api.body|default='无'}
+                                        </div>
+                                    </div>
+                                </div><!-- #info -->
+
+                                <div class="tab-pane" id="sandbox{$api.id}">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                            {if $api.headerslist}
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>{$lang.Headers}</strong></div>
+                                                <div class="panel-body">
+                                                    <div class="headers">
+                                                        {foreach name="api['headerslist']" id="param"}
+                                                        <div class="form-group">
+                                                            <label class="control-label" for="{$param.name}">{$param.name}</label>
+                                                            <input type="{$param.type}" class="form-control input-sm" id="{$param.name}" {if $param.required}required{/if} placeholder="{$param.description} - Ex: {$param.sample}" name="{$param.name}">
+                                                        </div>
+                                                        {/foreach}
+                                                    </div>
+                                                </div>
+                                            </div>
+                                            {/if}
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>{$lang.Parameters}</strong></div>
+                                                <div class="panel-body">
+                                                    <form enctype="application/x-www-form-urlencoded" role="form" action="{$api.route}" method="{$api.method}" name="form{$api.id}" id="form{$api.id}">
+                                                        {if $api.paramslist}
+                                                        {foreach name="api['paramslist']" id="param"}
+                                                        <div class="form-group">
+                                                            <label class="control-label" for="{$param.name}">{$param.name}</label>
+                                                            <input type="{$param.type}" class="form-control input-sm" id="{$param.name}" {if $param.required}required{/if} placeholder="{$param.description}{if $param.sample} - 例: {$param.sample}{/if}" name="{$param.name}">
+                                                        </div>
+                                                        {/foreach}
+                                                        {else /}
+                                                        <div class="form-group">
+                                                            无
+                                                        </div>
+                                                        {/if}
+                                                        <div class="form-group">
+                                                            <button type="submit" class="btn btn-success send" rel="{$api.id}">{$lang.Send}</button>
+                                                            <button type="reset" class="btn btn-info" rel="{$api.id}">{$lang.Reset}</button>
+                                                        </div>
+                                                    </form>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>{$lang.Response}</strong></div>
+                                                <div class="panel-body">
+                                                    <div class="row">
+                                                        <div class="col-md-12" style="overflow-x:auto">
+                                                            <pre id="response_headers{$api.id}"></pre>
+                                                            <pre id="response{$api.id}"></pre>
+                                                        </div>
+                                                    </div>
+                                                </div>
+                                            </div>
+                                            <div class="panel panel-default">
+                                                <div class="panel-heading"><strong>{$lang.ReturnParameters}</strong></div>
+                                                <div class="panel-body">
+                                                    {if $api.returnparamslist}
+                                                    <table class="table table-hover">
+                                                        <thead>
+                                                            <tr>
+                                                                <th>{$lang.Name}</th>
+                                                                <th>{$lang.Type}</th>
+                                                                <th>{$lang.Description}</th>
+                                                            </tr>
+                                                        </thead>
+                                                        <tbody>
+                                                            {foreach name="api['returnparamslist']" id="param"}
+                                                            <tr>
+                                                                <td>{$param.name}</td>
+                                                                <td>{$param.type}</td>
+                                                                <td>{$param.description}</td>
+                                                            </tr>
+                                                            {/foreach}
+                                                        </tbody>
+                                                    </table>
+                                                    {else /}
+                                                    无
+                                                    {/if}
+                                                </div>
+                                            </div>
+                                        </div>
+                                    </div>
+                                </div><!-- #sandbox -->
+
+                                <div class="tab-pane" id="sample{$api.id}">
+                                    <div class="row">
+                                        <div class="col-md-12">
+                                            <pre id="sample_response{$api.id}">{$api.return|default='无'}</pre>
+                                        </div>
+                                    </div>
+                                </div><!-- #sample -->
+
+                            </div><!-- .tab-content -->
+                        </div>
+                    </div>
+                </div>
+                {/foreach}
+                {/foreach}
+            </div>
+
+            <hr>
+
+            <div class="row mt0 footer">
+                <div class="col-md-6" align="left">
+                    Generated on {:date('Y-m-d H:i:s')}
+                </div>
+                <div class="col-md-6" align="right">
+                    <a href="https://www.fastadmin.net" target="_blank">FastAdmin</a>
+                </div>
+            </div>
+
+        </div> <!-- /container -->
+
+        <!-- jQuery -->
+        <script src="https://cdn.staticfile.org/jquery/2.1.4/jquery.min.js"></script>
+
+        <!-- Bootstrap Core JavaScript -->
+        <script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
+
+        <script type="text/javascript">
+            function syntaxHighlight(json) {
+                if (typeof json != 'string') {
+                    json = JSON.stringify(json, undefined, 2);
+                }
+                json = json.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
+                return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
+                    var cls = 'number';
+                    if (/^"/.test(match)) {
+                        if (/:$/.test(match)) {
+                            cls = 'key';
+                        } else {
+                            cls = 'string';
+                        }
+                    } else if (/true|false/.test(match)) {
+                        cls = 'boolean';
+                    } else if (/null/.test(match)) {
+                        cls = 'null';
+                    }
+                    return '<span class="' + cls + '">' + match + '</span>';
+                });
+            }
+
+            function prepareStr(str) {
+                try {
+                    return syntaxHighlight(JSON.stringify(JSON.parse(str.replace(/'/g, '"')), null, 2));
+                } catch (e) {
+                    return str;
+                }
+            }
+            var storage = (function () {
+                var uid = new Date;
+                var storage;
+                var result;
+                try {
+                    (storage = window.localStorage).setItem(uid, uid);
+                    result = storage.getItem(uid) == uid;
+                    storage.removeItem(uid);
+                    return result && storage;
+                } catch (exception) {
+                }
+            }());
+
+            $.fn.serializeObject = function ()
+            {
+                var o = {};
+                var a = this.serializeArray();
+                $.each(a, function () {
+                    if (!this.value) {
+                        return;
+                    }
+                    if (o[this.name] !== undefined) {
+                        if (!o[this.name].push) {
+                            o[this.name] = [o[this.name]];
+                        }
+                        o[this.name].push(this.value || '');
+                    } else {
+                        o[this.name] = this.value || '';
+                    }
+                });
+                return o;
+            };
+
+            $(document).ready(function () {
+
+                if (storage) {
+                    $('#token').val(storage.getItem('token'));
+                    $('#apiUrl').val(storage.getItem('apiUrl'));
+                }
+
+                $('[data-toggle="tooltip"]').tooltip({
+                    placement: 'bottom'
+                });
+
+                $(window).on("resize", function(){
+                    $("#sidebar").css("max-height", $(window).height()-80);
+                });
+
+                $(window).trigger("resize");
+
+                $(document).on("click", "#sidebar .list-group > .list-group-item", function(){
+                    $("#sidebar .list-group > .list-group-item").removeClass("current");
+                    $(this).addClass("current");
+                });
+                $(document).on("click", "#sidebar .child a", function(){
+                    var heading = $("#heading-"+$(this).data("id"));
+                    if(!heading.next().hasClass("in")){
+                        $("a", heading).trigger("click");
+                    }
+                    $("html,body").animate({scrollTop:heading.offset().top-70});
+                });
+
+                $('code[id^=response]').hide();
+
+                $.each($('pre[id^=sample_response],pre[id^=sample_post_body]'), function () {
+                    if ($(this).html() == 'NA') {
+                        return;
+                    }
+                    var str = prepareStr($(this).html());
+                    $(this).html(str);
+                });
+
+                $("[data-toggle=popover]").popover({placement: 'right'});
+
+                $('[data-toggle=popover]').on('shown.bs.popover', function () {
+                    var $sample = $(this).parent().find(".popover-content"),
+                            str = $(this).data('content');
+                    if (typeof str == "undefined" || str === "") {
+                        return;
+                    }
+                    var str = prepareStr(str);
+                    $sample.html('<pre>' + str + '</pre>');
+                });
+
+                $('body').on('click', '#save_data', function (e) {
+                    if (storage) {
+                        storage.setItem('token', $('#token').val());
+                        storage.setItem('apiUrl', $('#apiUrl').val());
+                    } else {
+                        alert('Your browser does not support local storage');
+                    }
+                });
+
+                $('body').on('click', '.send', function (e) {
+                    e.preventDefault();
+                    var form = $(this).closest('form');
+                    //added /g to get all the matched params instead of only first
+                    var matchedParamsInRoute = $(form).attr('action').match(/[^{]+(?=\})/g);
+                    var theId = $(this).attr('rel');
+                    //keep a copy of action attribute in order to modify the copy
+                    //instead of the initial attribute
+                    var url = $(form).attr('action');
+                    var method = $(form).prop('method').toLowerCase() || 'get';
+
+                    var formData = new FormData();
+
+                    $(form).find('input').each(function (i, input) {
+                        if ($(input).attr('type').toLowerCase() == 'file') {
+                            formData.append($(input).attr('name'), $(input)[0].files[0]);
+                            method = 'post';
+                        } else {
+                            formData.append($(input).attr('name'), $(input).val())
+                        }
+                    });
+
+                    var index, key, value;
+
+                    if (matchedParamsInRoute) {
+                        var params = {};
+                        formData.forEach(function(value, key){
+                            params[key] = value;
+                        });
+                        for (index = 0; index < matchedParamsInRoute.length; ++index) {
+                            try {
+                                key = matchedParamsInRoute[index];
+                                value = params[key];
+                                if (typeof value == "undefined")
+                                    value = "";
+                                url = url.replace("\{" + key + "\}", value);
+                                formData.delete(key);
+                            } catch (err) {
+                                console.log(err);
+                            }
+                        }
+                    }
+
+                    var headers = {};
+
+                    var token = $('#token').val();
+                    if (token.length > 0) {
+                        headers['token'] = token;
+                    }
+
+                    $("#sandbox" + theId + " .headers input[type=text]").each(function () {
+                        val = $(this).val();
+                        if (val.length > 0) {
+                            headers[$(this).prop('name')] = val;
+                        }
+                    });
+
+                    $.ajax({
+                        url: $('#apiUrl').val() + url,
+                        data: method == 'get' ? $(form).serialize() : formData,
+                        type: method,
+                        dataType: 'json',
+                        contentType: false,
+                        processData: false,
+                        headers: headers,
+                        success: function (data, textStatus, xhr) {
+                            if (typeof data === 'object') {
+                                var str = JSON.stringify(data, null, 2);
+                                $('#response' + theId).html(syntaxHighlight(str));
+                            } else {
+                                $('#response' + theId).html(data || '');
+                            }
+                            $('#response_headers' + theId).html('HTTP ' + xhr.status + ' ' + xhr.statusText + '<br/><br/>' + xhr.getAllResponseHeaders());
+                            $('#response' + theId).show();
+                        },
+                        error: function (xhr, textStatus, error) {
+                            try {
+                                var str = JSON.stringify($.parseJSON(xhr.responseText), null, 2);
+                            } catch (e) {
+                                var str = xhr.responseText;
+                            }
+                            $('#response_headers' + theId).html('HTTP ' + xhr.status + ' ' + xhr.statusText + '<br/><br/>' + xhr.getAllResponseHeaders());
+                            $('#response' + theId).html(syntaxHighlight(str));
+                            $('#response' + theId).show();
+                        }
+                    });
+                    return false;
+                });
+            });
+        </script>
+    </body>
+</html>

+ 1351 - 0
application/admin/command/Crud.php

@@ -0,0 +1,1351 @@
+<?php
+
+namespace app\admin\command;
+
+use fast\Form;
+use think\Config;
+use think\console\Command;
+use think\console\Input;
+use think\console\input\Option;
+use think\console\Output;
+use think\Db;
+use think\Exception;
+use think\Lang;
+use think\Loader;
+
+class Crud extends Command
+{
+
+    protected $stubList = [];
+
+    /**
+     * Selectpage搜索字段关联
+     */
+    protected $fieldSelectpageMap = [
+        'nickname' => ['user_id', 'user_ids', 'admin_id', 'admin_ids']
+    ];
+
+    /**
+     * Enum类型识别为单选框的结尾字符,默认会识别为单选下拉列表
+     */
+    protected $enumRadioSuffix = ['data', 'state', 'status'];
+
+    /**
+     * Set类型识别为复选框的结尾字符,默认会识别为多选下拉列表
+     */
+    protected $setCheckboxSuffix = ['data', 'state', 'status'];
+
+    /**
+     * Int类型识别为日期时间的结尾字符,默认会识别为日期文本框
+     */
+    protected $intDateSuffix = ['time'];
+
+    /**
+     * 开关后缀
+     */
+    protected $switchSuffix = ['switch'];
+
+    /**
+     * 富文本后缀
+     */
+    protected $editorSuffix = ['content'];
+
+    /**
+     * 城市后缀
+     */
+    protected $citySuffix = ['city'];
+
+    /**
+     * Selectpage对应的后缀
+     */
+    protected $selectpageSuffix = ['_id', '_ids'];
+
+    /**
+     * Selectpage多选对应的后缀
+     */
+    protected $selectpagesSuffix = ['_ids'];
+
+    /**
+     * 以指定字符结尾的字段格式化函数
+     */
+    protected $fieldFormatterSuffix = [
+        'status' => ['type' => ['varchar', 'enum'], 'name' => 'status'],
+        'icon'   => 'icon',
+        'flag'   => 'flag',
+        'url'    => 'url',
+        'image'  => 'image',
+        'images' => 'images',
+        'switch' => 'toggle',
+        'time'   => ['type' => ['int', 'timestamp'], 'name' => 'datetime']
+    ];
+
+    /**
+     * 识别为图片字段
+     */
+    protected $imageField = ['image', 'images', 'avatar', 'avatars'];
+
+    /**
+     * 识别为文件字段
+     */
+    protected $fileField = ['file', 'files'];
+
+    /**
+     * 保留字段
+     */
+    protected $reservedField = ['admin_id', 'createtime', 'updatetime'];
+
+    /**
+     * 排除字段
+     */
+    protected $ignoreFields = [];
+
+    /**
+     * 排序字段
+     */
+    protected $sortField = 'weigh';
+
+    /**
+     * 筛选字段
+     * @var string
+     */
+    protected $headingFilterField = 'status';
+
+    /**
+     * 编辑器的Class
+     */
+    protected $editorClass = 'editor';
+
+    protected function configure()
+    {
+        $this
+            ->setName('crud')
+            ->addOption('table', 't', Option::VALUE_REQUIRED, 'table name without prefix', null)
+            ->addOption('controller', 'c', Option::VALUE_OPTIONAL, 'controller name', null)
+            ->addOption('model', 'm', Option::VALUE_OPTIONAL, 'model name', null)
+            ->addOption('fields', 'i', Option::VALUE_OPTIONAL, 'model visible fields', null)
+            ->addOption('force', 'f', Option::VALUE_OPTIONAL, 'force override or force delete,without tips', null)
+            ->addOption('local', 'l', Option::VALUE_OPTIONAL, 'local model', 1)
+            ->addOption('relation', 'r', Option::VALUE_OPTIONAL | Option::VALUE_IS_ARRAY, 'relation table name without prefix', null)
+            ->addOption('relationmodel', 'e', Option::VALUE_OPTIONAL | Option::VALUE_IS_ARRAY, 'relation model name', null)
+            ->addOption('relationforeignkey', 'k', Option::VALUE_OPTIONAL | Option::VALUE_IS_ARRAY, 'relation foreign key', null)
+            ->addOption('relationprimarykey', 'p', Option::VALUE_OPTIONAL | Option::VALUE_IS_ARRAY, 'relation primary key', null)
+            ->addOption('relationfields', 's', Option::VALUE_OPTIONAL | Option::VALUE_IS_ARRAY, 'relation table fields', null)
+            ->addOption('relationmode', 'o', Option::VALUE_OPTIONAL | Option::VALUE_IS_ARRAY, 'relation table mode,hasone or belongsto', null)
+            ->addOption('delete', 'd', Option::VALUE_OPTIONAL, 'delete all files generated by CRUD', null)
+            ->addOption('menu', 'u', Option::VALUE_OPTIONAL, 'create menu when CRUD completed', null)
+            ->addOption('setcheckboxsuffix', null, Option::VALUE_OPTIONAL | Option::VALUE_IS_ARRAY, 'automatically generate checkbox component with suffix', null)
+            ->addOption('enumradiosuffix', null, Option::VALUE_OPTIONAL | Option::VALUE_IS_ARRAY, 'automatically generate radio component with suffix', null)
+            ->addOption('imagefield', null, Option::VALUE_OPTIONAL | Option::VALUE_IS_ARRAY, 'automatically generate image component with suffix', null)
+            ->addOption('filefield', null, Option::VALUE_OPTIONAL | Option::VALUE_IS_ARRAY, 'automatically generate file component with suffix', null)
+            ->addOption('intdatesuffix', null, Option::VALUE_OPTIONAL | Option::VALUE_IS_ARRAY, 'automatically generate date component with suffix', null)
+            ->addOption('switchsuffix', null, Option::VALUE_OPTIONAL | Option::VALUE_IS_ARRAY, 'automatically generate switch component with suffix', null)
+            ->addOption('citysuffix', null, Option::VALUE_OPTIONAL | Option::VALUE_IS_ARRAY, 'automatically generate citypicker component with suffix', null)
+            ->addOption('selectpagesuffix', null, Option::VALUE_OPTIONAL | Option::VALUE_IS_ARRAY, 'automatically generate selectpage component with suffix', null)
+            ->addOption('selectpagessuffix', null, Option::VALUE_OPTIONAL | Option::VALUE_IS_ARRAY, 'automatically generate multiple selectpage component with suffix', null)
+            ->addOption('ignorefields', null, Option::VALUE_OPTIONAL | Option::VALUE_IS_ARRAY, 'ignore fields', null)
+            ->addOption('sortfield', null, Option::VALUE_OPTIONAL, 'sort field', null)
+            ->addOption('headingfilterfield', null, Option::VALUE_OPTIONAL, 'heading filter field', null)
+            ->addOption('editorclass', null, Option::VALUE_OPTIONAL, 'automatically generate editor class', null)
+            ->setDescription('Build CRUD controller and model from table');
+    }
+
+    protected function execute(Input $input, Output $output)
+    {
+        $adminPath = dirname(__DIR__) . DS;
+        //表名
+        $table = $input->getOption('table') ?: '';
+        //自定义控制器
+        $controller = $input->getOption('controller');
+        //自定义模型
+        $model = $input->getOption('model');
+        //验证器类
+        $validate = $model;
+        //自定义显示字段
+        $fields = $input->getOption('fields');
+        //强制覆盖
+        $force = $input->getOption('force');
+        //是否为本地model,为0时表示为全局model将会把model放在app/common/model中
+        $local = $input->getOption('local');
+        if (!$table) {
+            throw new Exception('table name can\'t empty');
+        }
+        //是否生成菜单
+        $menu = $input->getOption("menu");
+        //关联表
+        $relation = $input->getOption('relation');
+        //自定义关联表模型
+        $relationModel = $input->getOption('relationmodel');
+        //模式
+        $relationMode = $mode = $input->getOption('relationmode');
+        //外键
+        $relationForeignKey = $input->getOption('relationforeignkey');
+        //主键
+        $relationPrimaryKey = $input->getOption('relationprimarykey');
+        //关联表显示字段
+        $relationFields = $input->getOption('relationfields');
+        //复选框后缀
+        $setcheckboxsuffix = $input->getOption('setcheckboxsuffix');
+        //单选框后缀
+        $enumradiosuffix = $input->getOption('enumradiosuffix');
+        //图片后缀
+        $imagefield = $input->getOption('imagefield');
+        //文件后缀
+        $filefield = $input->getOption('filefield');
+        //日期后缀
+        $intdatesuffix = $input->getOption('intdatesuffix');
+        //开关后缀
+        $switchsuffix = $input->getOption('switchsuffix');
+        //城市后缀
+        $citysuffix = $input->getOption('citysuffix');
+        //selectpage后缀
+        $selectpagesuffix = $input->getOption('selectpagesuffix');
+        //selectpage多选后缀
+        $selectpagessuffix = $input->getOption('selectpagessuffix');
+        //排除字段
+        $ignoreFields = $input->getOption('ignorefields');
+        //排序字段
+        $sortfield = $input->getOption('sortfield');
+        //顶部筛选过滤字段
+        $headingfilterfield = $input->getOption('headingfilterfield');
+        //编辑器Class
+        $editorclass = $input->getOption('editorclass');
+        if ($setcheckboxsuffix)
+            $this->setCheckboxSuffix = $setcheckboxsuffix;
+        if ($enumradiosuffix)
+            $this->enumRadioSuffix = $enumradiosuffix;
+        if ($imagefield)
+            $this->imageField = $imagefield;
+        if ($filefield)
+            $this->fileField = $filefield;
+        if ($intdatesuffix)
+            $this->intDateSuffix = $intdatesuffix;
+        if ($switchsuffix)
+            $this->switchSuffix = $switchsuffix;
+        if ($citysuffix)
+            $this->citySuffix = $citysuffix;
+        if ($selectpagesuffix)
+            $this->selectpageSuffix = $selectpagesuffix;
+        if ($selectpagessuffix)
+            $this->selectpagesSuffix = $selectpagessuffix;
+        if ($ignoreFields)
+            $this->ignoreFields = $ignoreFields;
+        if ($editorclass)
+            $this->editorClass = $editorclass;
+        if ($sortfield)
+            $this->sortField = $sortfield;
+        if ($headingfilterfield)
+            $this->headingFilterField = $headingfilterfield;
+
+        $dbname = Config::get('database.database');
+        $prefix = Config::get('database.prefix');
+
+        //模块
+        $moduleName = 'admin';
+        $modelModuleName = $local ? $moduleName : 'common';
+        $validateModuleName = $local ? $moduleName : 'common';
+
+        //检查主表
+        $modelName = $table = stripos($table, $prefix) === 0 ? substr($table, strlen($prefix)) : $table;
+        $modelTableType = 'table';
+        $modelTableTypeName = $modelTableName = $modelName;
+        $modelTableInfo = Db::query("SHOW TABLE STATUS LIKE '{$modelTableName}'", [], TRUE);
+        if (!$modelTableInfo) {
+            $modelTableType = 'name';
+            $modelTableName = $prefix . $modelName;
+            $modelTableInfo = Db::query("SHOW TABLE STATUS LIKE '{$modelTableName}'", [], TRUE);
+            if (!$modelTableInfo) {
+                throw new Exception("table not found");
+            }
+        }
+        $modelTableInfo = $modelTableInfo[0];
+
+        $relations = [];
+        //检查关联表
+        if ($relation) {
+            $relationArr = $relation;
+            $relations = [];
+
+            foreach ($relationArr as $index => $relationTable) {
+                $relationName = stripos($relationTable, $prefix) === 0 ? substr($relationTable, strlen($prefix)) : $relationTable;
+                $relationTableType = 'table';
+                $relationTableTypeName = $relationTableName = $relationName;
+                $relationTableInfo = Db::query("SHOW TABLE STATUS LIKE '{$relationTableName}'", [], TRUE);
+                if (!$relationTableInfo) {
+                    $relationTableType = 'name';
+                    $relationTableName = $prefix . $relationName;
+                    $relationTableInfo = Db::query("SHOW TABLE STATUS LIKE '{$relationTableName}'", [], TRUE);
+                    if (!$relationTableInfo) {
+                        throw new Exception("relation table not found");
+                    }
+                }
+                $relationTableInfo = $relationTableInfo[0];
+                $relationModel = isset($relationModel[$index]) ? $relationModel[$index] : '';
+
+                list($relationNamespace, $relationName, $relationFile) = $this->getModelData($modelModuleName, $relationModel, $relationName);
+
+                $relations[] = [
+                    //关联表基础名
+                    'relationName'          => $relationName,
+                    //关联模型名
+                    'relationModel'         => $relationModel,
+                    //关联文件
+                    'relationFile'          => $relationFile,
+                    //关联表名称
+                    'relationTableName'     => $relationTableName,
+                    //关联表信息
+                    'relationTableInfo'     => $relationTableInfo,
+                    //关联模型表类型(name或table)
+                    'relationTableType'     => $relationTableType,
+                    //关联模型表类型名称
+                    'relationTableTypeName' => $relationTableTypeName,
+                    //关联模式
+                    'relationFields'        => isset($relationFields[$index]) ? explode(',', $relationFields[$index]) : [],
+                    //关联模式
+                    'relationMode'          => isset($relationMode[$index]) ? $relationMode[$index] : 'belongsto',
+                    //关联表外键
+                    'relationForeignKey'    => isset($relationForeignKey[$index]) ? $relationForeignKey[$index] : Loader::parseName($relationName) . '_id',
+                    //关联表主键
+                    'relationPrimaryKey'    => isset($relationPrimaryKey[$index]) ? $relationPrimaryKey[$index] : '',
+                ];
+            }
+        }
+
+        //根据表名匹配对应的Fontawesome图标
+        $iconPath = ROOT_PATH . str_replace('/', DS, '/public/assets/libs/font-awesome/less/variables.less');
+        $iconName = is_file($iconPath) && stripos(file_get_contents($iconPath), '@fa-var-' . $table . ':') ? 'fa fa-' . $table : 'fa fa-circle-o';
+
+        //控制器
+        list($controllerNamespace, $controllerName, $controllerFile, $controllerArr) = $this->getControllerData($moduleName, $controller, $table);
+        //模型
+        list($modelNamespace, $modelName, $modelFile, $modelArr) = $this->getModelData($modelModuleName, $model, $table);
+        //验证器
+        list($validateNamespace, $validateName, $validateFile, $validateArr) = $this->getValidateData($validateModuleName, $validate, $table);
+
+        $controllerUrl = strtolower(implode('/', $controllerArr));
+        $controllerBaseName = strtolower(implode(DS, $controllerArr));
+
+        //视图文件
+        $viewDir = $adminPath . 'view' . DS . $controllerBaseName . DS;
+
+        //最终将生成的文件路径
+        $javascriptFile = ROOT_PATH . 'public' . DS . 'assets' . DS . 'js' . DS . 'backend' . DS . $controllerBaseName . '.js';
+        $addFile = $viewDir . 'add.html';
+        $editFile = $viewDir . 'edit.html';
+        $indexFile = $viewDir . 'index.html';
+        $langFile = $adminPath . 'lang' . DS . Lang::detect() . DS . $controllerBaseName . '.php';
+
+        //是否为删除模式
+        $delete = $input->getOption('delete');
+        if ($delete) {
+            $readyFiles = [$controllerFile, $modelFile, $validateFile, $addFile, $editFile, $indexFile, $langFile, $javascriptFile];
+            foreach ($readyFiles as $k => $v) {
+                $output->warning($v);
+            }
+            if (!$force) {
+                $output->info("Are you sure you want to delete all those files?  Type 'yes' to continue: ");
+                $line = fgets(defined('STDIN') ? STDIN : fopen('php://stdin', 'r'));
+                if (trim($line) != 'yes') {
+                    throw new Exception("Operation is aborted!");
+                }
+            }
+            foreach ($readyFiles as $k => $v) {
+                if (file_exists($v))
+                    unlink($v);
+                //删除空文件夹
+                if ($v == $modelFile) {
+                    $this->removeEmptyBaseDir($v, $modelArr);
+                } else if ($v == $validateFile) {
+                    $this->removeEmptyBaseDir($v, $validateArr);
+                } else {
+                    $this->removeEmptyBaseDir($v, $controllerArr);
+                }
+            }
+
+            $output->info("Delete Successed");
+            return;
+        }
+
+        //非覆盖模式时如果存在控制器文件则报错
+        if (is_file($controllerFile) && !$force) {
+            throw new Exception("controller already exists!\nIf you need to rebuild again, use the parameter --force=true ");
+        }
+
+        //非覆盖模式时如果存在模型文件则报错
+        if (is_file($modelFile) && !$force) {
+            throw new Exception("model already exists!\nIf you need to rebuild again, use the parameter --force=true ");
+        }
+
+        //非覆盖模式时如果存在验证文件则报错
+        if (is_file($validateFile) && !$force) {
+            throw new Exception("validate already exists!\nIf you need to rebuild again, use the parameter --force=true ");
+        }
+
+        require $adminPath . 'common.php';
+
+        //从数据库中获取表字段信息
+        $sql = "SELECT * FROM `information_schema`.`columns` "
+            . "WHERE TABLE_SCHEMA = ? AND table_name = ? "
+            . "ORDER BY ORDINAL_POSITION";
+        //加载主表的列
+        $columnList = Db::query($sql, [$dbname, $modelTableName]);
+        $fieldArr = [];
+        foreach ($columnList as $k => $v) {
+            $fieldArr[] = $v['COLUMN_NAME'];
+        }
+
+        // 加载关联表的列
+        foreach ($relations as $index => &$relation) {
+            $relationColumnList = Db::query($sql, [$dbname, $relation['relationTableName']]);
+
+            $relationFieldList = [];
+            foreach ($relationColumnList as $k => $v) {
+                $relationFieldList[] = $v['COLUMN_NAME'];
+            }
+            if (!$relation['relationPrimaryKey']) {
+                foreach ($relationColumnList as $k => $v) {
+                    if ($v['COLUMN_KEY'] == 'PRI') {
+                        $relation['relationPrimaryKey'] = $v['COLUMN_NAME'];
+                        break;
+                    }
+                }
+            }
+            // 如果主键为空
+            if (!$relation['relationPrimaryKey']) {
+                throw new Exception('Relation Primary key not found!');
+            }
+            // 如果主键不在表字段中
+            if (!in_array($relation['relationPrimaryKey'], $relationFieldList)) {
+                throw new Exception('Relation Primary key not found in table!');
+            }
+            $relation['relationColumnList'] = $relationColumnList;
+            $relation['relationFieldList'] = $relationFieldList;
+        }
+        unset($relation);
+
+        $addList = [];
+        $editList = [];
+        $javascriptList = [];
+        $langList = [];
+        $field = 'id';
+        $order = 'id';
+        $priDefined = FALSE;
+        $priKey = '';
+        $relationPrimaryKey = '';
+        foreach ($columnList as $k => $v) {
+            if ($v['COLUMN_KEY'] == 'PRI') {
+                $priKey = $v['COLUMN_NAME'];
+                break;
+            }
+        }
+        if (!$priKey) {
+            throw new Exception('Primary key not found!');
+        }
+
+        $order = $priKey;
+
+        //如果是关联模型
+        foreach ($relations as $index => &$relation) {
+            if ($relation['relationMode'] == 'hasone') {
+                $relationForeignKey = $relation['relationForeignKey'] ? $relation['relationForeignKey'] : $table . "_id";
+                $relationPrimaryKey = $relation['relationPrimaryKey'] ? $relation['relationPrimaryKey'] : $priKey;
+
+                if (!in_array($relationForeignKey, $relation['relationFieldList'])) {
+                    throw new Exception('relation table [' . $relation['relationTableName'] . '] must be contain field [' . $relationForeignKey . ']');
+                }
+                if (!in_array($relationPrimaryKey, $fieldArr)) {
+                    throw new Exception('table [' . $modelTableName . '] must be contain field [' . $relationPrimaryKey . ']');
+                }
+            } else {
+                $relationForeignKey = $relation['relationForeignKey'] ? $relation['relationForeignKey'] : Loader::parseName($relation['relationName']) . "_id";
+                $relationPrimaryKey = $relation['relationPrimaryKey'] ? $relation['relationPrimaryKey'] : $relation['relationPriKey'];
+                if (!in_array($relationForeignKey, $fieldArr)) {
+                    throw new Exception('table [' . $modelTableName . '] must be contain field [' . $relationForeignKey . ']');
+                }
+                if (!in_array($relationPrimaryKey, $relation['relationFieldList'])) {
+                    throw new Exception('relation table [' . $relation['relationTableName'] . '] must be contain field [' . $relationPrimaryKey . ']');
+                }
+            }
+            $relation['relationForeignKey'] = $relationForeignKey;
+            $relation['relationPrimaryKey'] = $relationPrimaryKey;
+        }
+        unset($relation);
+
+        try {
+            Form::setEscapeHtml(false);
+            $setAttrArr = [];
+            $getAttrArr = [];
+            $getEnumArr = [];
+            $appendAttrList = [];
+            $controllerAssignList = [];
+            $headingHtml = '{:build_heading()}';
+
+            //循环所有字段,开始构造视图的HTML和JS信息
+            foreach ($columnList as $k => $v) {
+                $field = $v['COLUMN_NAME'];
+                $itemArr = [];
+                // 这里构建Enum和Set类型的列表数据
+                if (in_array($v['DATA_TYPE'], ['enum', 'set', 'tinyint'])) {
+                    if ($v['DATA_TYPE'] !== 'tinyint') {
+                        $itemArr = substr($v['COLUMN_TYPE'], strlen($v['DATA_TYPE']) + 1, -1);
+                        $itemArr = explode(',', str_replace("'", '', $itemArr));
+                    }
+                    $itemArr = $this->getItemArray($itemArr, $field, $v['COLUMN_COMMENT']);
+                    //如果类型为tinyint且有使用备注数据
+                    if ($itemArr && $v['DATA_TYPE'] == 'tinyint') {
+                        $v['DATA_TYPE'] = 'enum';
+                    }
+                }
+                // 语言列表
+                if ($v['COLUMN_COMMENT'] != '') {
+                    $langList[] = $this->getLangItem($field, $v['COLUMN_COMMENT']);
+                }
+                $inputType = '';
+                //createtime和updatetime是保留字段不能修改和添加
+                if ($v['COLUMN_KEY'] != 'PRI' && !in_array($field, $this->reservedField) && !in_array($field, $this->ignoreFields)) {
+                    $inputType = $this->getFieldType($v);
+
+                    // 如果是number类型时增加一个步长
+                    $step = $inputType == 'number' && $v['NUMERIC_SCALE'] > 0 ? "0." . str_repeat(0, $v['NUMERIC_SCALE'] - 1) . "1" : 0;
+
+                    $attrArr = ['id' => "c-{$field}"];
+                    $cssClassArr = ['form-control'];
+                    $fieldName = "row[{$field}]";
+                    $defaultValue = $v['COLUMN_DEFAULT'];
+                    $editValue = "{\$row.{$field}}";
+                    // 如果默认值非null,则是一个必选项
+                    if ($v['IS_NULLABLE'] == 'NO') {
+                        $attrArr['data-rule'] = 'required';
+                    }
+
+                    if ($inputType == 'select') {
+                        $cssClassArr[] = 'selectpicker';
+                        $attrArr['class'] = implode(' ', $cssClassArr);
+                        if ($v['DATA_TYPE'] == 'set') {
+                            $attrArr['multiple'] = '';
+                            $fieldName .= "[]";
+                        }
+                        $attrArr['name'] = $fieldName;
+
+                        $this->getEnum($getEnumArr, $controllerAssignList, $field, $itemArr, $v['DATA_TYPE'] == 'set' ? 'multiple' : 'select');
+
+                        $itemArr = $this->getLangArray($itemArr, FALSE);
+                        //添加一个获取器
+                        $this->getAttr($getAttrArr, $field, $v['DATA_TYPE'] == 'set' ? 'multiple' : 'select');
+                        if ($v['DATA_TYPE'] == 'set') {
+                            $this->setAttr($setAttrArr, $field, $inputType);
+                        }
+                        $this->appendAttr($appendAttrList, $field);
+                        $formAddElement = $this->getReplacedStub('html/select', ['field' => $field, 'fieldName' => $fieldName, 'fieldList' => $this->getFieldListName($field), 'attrStr' => Form::attributes($attrArr), 'selectedValue' => $defaultValue]);
+                        $formEditElement = $this->getReplacedStub('html/select', ['field' => $field, 'fieldName' => $fieldName, 'fieldList' => $this->getFieldListName($field), 'attrStr' => Form::attributes($attrArr), 'selectedValue' => "\$row.{$field}"]);
+                    } else if ($inputType == 'datetime') {
+                        $cssClassArr[] = 'datetimepicker';
+                        $attrArr['class'] = implode(' ', $cssClassArr);
+                        $format = "YYYY-MM-DD HH:mm:ss";
+                        $phpFormat = "Y-m-d H:i:s";
+                        $fieldFunc = '';
+                        switch ($v['DATA_TYPE']) {
+                            case 'year';
+                                $format = "YYYY";
+                                $phpFormat = 'Y';
+                                break;
+                            case 'date';
+                                $format = "YYYY-MM-DD";
+                                $phpFormat = 'Y-m-d';
+                                break;
+                            case 'time';
+                                $format = "HH:mm:ss";
+                                $phpFormat = 'H:i:s';
+                                break;
+                            case 'timestamp';
+                                $fieldFunc = 'datetime';
+                            case 'datetime';
+                                $format = "YYYY-MM-DD HH:mm:ss";
+                                $phpFormat = 'Y-m-d H:i:s';
+                                break;
+                            default:
+                                $fieldFunc = 'datetime';
+                                $this->getAttr($getAttrArr, $field, $inputType);
+                                $this->setAttr($setAttrArr, $field, $inputType);
+                                $this->appendAttr($appendAttrList, $field);
+                                break;
+                        }
+                        $defaultDateTime = "{:date('{$phpFormat}')}";
+                        $attrArr['data-date-format'] = $format;
+                        $attrArr['data-use-current'] = "true";
+                        $fieldFunc = $fieldFunc ? "|{$fieldFunc}" : "";
+                        $formAddElement = Form::text($fieldName, $defaultDateTime, $attrArr);
+                        $formEditElement = Form::text($fieldName, "{\$row.{$field}{$fieldFunc}}", $attrArr);
+                    } else if ($inputType == 'checkbox' || $inputType == 'radio') {
+                        unset($attrArr['data-rule']);
+                        $fieldName = $inputType == 'checkbox' ? $fieldName .= "[]" : $fieldName;
+                        $attrArr['name'] = "row[{$fieldName}]";
+
+                        $this->getEnum($getEnumArr, $controllerAssignList, $field, $itemArr, $inputType);
+                        $itemArr = $this->getLangArray($itemArr, FALSE);
+                        //添加一个获取器
+                        $this->getAttr($getAttrArr, $field, $inputType);
+                        if ($inputType == 'checkbox') {
+                            $this->setAttr($setAttrArr, $field, $inputType);
+                        }
+                        $this->appendAttr($appendAttrList, $field);
+                        $defaultValue = $inputType == 'radio' && !$defaultValue ? key($itemArr) : $defaultValue;
+
+                        $formAddElement = $this->getReplacedStub('html/' . $inputType, ['field' => $field, 'fieldName' => $fieldName, 'fieldList' => $this->getFieldListName($field), 'attrStr' => Form::attributes($attrArr), 'selectedValue' => $defaultValue]);
+                        $formEditElement = $this->getReplacedStub('html/' . $inputType, ['field' => $field, 'fieldName' => $fieldName, 'fieldList' => $this->getFieldListName($field), 'attrStr' => Form::attributes($attrArr), 'selectedValue' => "\$row.{$field}"]);
+                    } else if ($inputType == 'textarea') {
+                        $cssClassArr[] = $this->isMatchSuffix($field, $this->editorSuffix) ? $this->editorClass : '';
+                        $attrArr['class'] = implode(' ', $cssClassArr);
+                        $attrArr['rows'] = 5;
+                        $formAddElement = Form::textarea($fieldName, $defaultValue, $attrArr);
+                        $formEditElement = Form::textarea($fieldName, $editValue, $attrArr);
+                    } else if ($inputType == 'switch') {
+                        unset($attrArr['data-rule']);
+                        if ($defaultValue === '1' || $defaultValue === 'Y') {
+                            $yes = $defaultValue;
+                            $no = $defaultValue === '1' ? '0' : 'N';
+                        } else {
+                            $no = $defaultValue;
+                            $yes = $defaultValue === '0' ? '1' : 'Y';
+                        }
+                        if (!$itemArr) {
+                            $itemArr = [$yes => 'Yes', $no => 'No'];
+                        }
+                        $stateNoClass = 'fa-flip-horizontal text-gray';
+                        $formAddElement = $this->getReplacedStub('html/' . $inputType, ['field' => $field, 'fieldName' => $fieldName, 'fieldYes' => $yes, 'fieldNo' => $no, 'attrStr' => Form::attributes($attrArr), 'fieldValue' => $defaultValue, 'fieldSwitchClass' => $defaultValue == $no ? $stateNoClass : '']);
+                        $formEditElement = $this->getReplacedStub('html/' . $inputType, ['field' => $field, 'fieldName' => $fieldName, 'fieldYes' => $yes, 'fieldNo' => $no, 'attrStr' => Form::attributes($attrArr), 'fieldValue' => "{\$row.{$field}}", 'fieldSwitchClass' => "{eq name=\"\$row.{$field}\" value=\"{$no}\"}fa-flip-horizontal text-gray{/eq}"]);
+                    } else if ($inputType == 'citypicker') {
+                        $attrArr['class'] = implode(' ', $cssClassArr);
+                        $attrArr['data-toggle'] = "city-picker";
+                        $formAddElement = sprintf("<div class='control-relative'>%s</div>", Form::input('text', $fieldName, $defaultValue, $attrArr));
+                        $formEditElement = sprintf("<div class='control-relative'>%s</div>", Form::input('text', $fieldName, $editValue, $attrArr));
+                    } else {
+                        $search = $replace = '';
+                        //特殊字段为关联搜索
+                        if ($this->isMatchSuffix($field, $this->selectpageSuffix)) {
+                            $inputType = 'text';
+                            $defaultValue = '';
+                            $attrArr['data-rule'] = 'required';
+                            $cssClassArr[] = 'selectpage';
+                            $selectpageController = str_replace('_', '/', substr($field, 0, strripos($field, '_')));
+                            $attrArr['data-source'] = $selectpageController . "/index";
+                            //如果是类型表需要特殊处理下
+                            if ($selectpageController == 'category') {
+                                $attrArr['data-source'] = 'category/selectpage';
+                                $attrArr['data-params'] = '##replacetext##';
+                                $search = '"##replacetext##"';
+                                $replace = '\'{"custom[type]":"' . $table . '"}\'';
+                            } elseif ($selectpageController == 'admin') {
+                                $attrArr['data-source'] = 'auth/admin/selectpage';
+                            } elseif ($selectpageController == 'user') {
+                                $attrArr['data-source'] = 'user/user/index';
+                            }
+                            if ($this->isMatchSuffix($field, $this->selectpagesSuffix)) {
+                                $attrArr['data-multiple'] = 'true';
+                            }
+                            foreach ($this->fieldSelectpageMap as $m => $n) {
+                                if (in_array($field, $n)) {
+                                    $attrArr['data-field'] = $m;
+                                    break;
+                                }
+                            }
+                        }
+                        //因为有自动完成可输入其它内容
+                        $step = array_intersect($cssClassArr, ['selectpage']) ? 0 : $step;
+                        $attrArr['class'] = implode(' ', $cssClassArr);
+                        $isUpload = false;
+                        if ($this->isMatchSuffix($field, array_merge($this->imageField, $this->fileField))) {
+                            $isUpload = true;
+                        }
+                        //如果是步长则加上步长
+                        if ($step) {
+                            $attrArr['step'] = $step;
+                        }
+                        //如果是图片加上个size
+                        if ($isUpload) {
+                            $attrArr['size'] = 50;
+                        }
+
+                        $formAddElement = Form::input($inputType, $fieldName, $defaultValue, $attrArr);
+                        $formEditElement = Form::input($inputType, $fieldName, $editValue, $attrArr);
+                        if ($search && $replace) {
+                            $formAddElement = str_replace($search, $replace, $formAddElement);
+                            $formEditElement = str_replace($search, $replace, $formEditElement);
+                        }
+                        //如果是图片或文件
+                        if ($isUpload) {
+                            $formAddElement = $this->getImageUpload($field, $formAddElement);
+                            $formEditElement = $this->getImageUpload($field, $formEditElement);
+                        }
+                    }
+                    //构造添加和编辑HTML信息
+                    $addList[] = $this->getFormGroup($field, $formAddElement);
+                    $editList[] = $this->getFormGroup($field, $formEditElement);
+                }
+
+                //过滤text类型字段
+                if ($v['DATA_TYPE'] != 'text') {
+                    //主键
+                    if ($v['COLUMN_KEY'] == 'PRI' && !$priDefined) {
+                        $priDefined = TRUE;
+                        $javascriptList[] = "{checkbox: true}";
+                    }
+                    if (!$fields || in_array($field, explode(',', $fields))) {
+                        //构造JS列信息
+                        $javascriptList[] = $this->getJsColumn($field, $v['DATA_TYPE'], $inputType && in_array($inputType, ['select', 'checkbox', 'radio']) ? '_text' : '', $itemArr);
+                    }
+                    if ($this->headingFilterField && $this->headingFilterField == $field && $itemArr) {
+                        $headingHtml = $this->getReplacedStub('html/heading-html', ['field' => $field]);
+                    }
+                    //排序方式,如果有指定排序字段,否则按主键排序
+                    $order = $field == $this->sortField ? $this->sortField : $order;
+                }
+            }
+
+            //循环关联表,追加语言包和JS列
+            foreach ($relations as $index => $relation) {
+                foreach ($relation['relationColumnList'] as $k => $v) {
+                    // 不显示的字段直接过滤掉
+                    if ($relation['relationFields'] && !in_array($v['COLUMN_NAME'], $relation['relationFields'])) {
+                        continue;
+                    }
+
+                    $relationField = strtolower($relation['relationName']) . "." . $v['COLUMN_NAME'];
+                    // 语言列表
+                    if ($v['COLUMN_COMMENT'] != '') {
+                        $langList[] = $this->getLangItem($relationField, $v['COLUMN_COMMENT']);
+                    }
+
+                    //过滤text类型字段
+                    if ($v['DATA_TYPE'] != 'text') {
+                        //构造JS列信息
+                        $javascriptList[] = $this->getJsColumn($relationField, $v['DATA_TYPE']);
+                    }
+                }
+            }
+
+            //JS最后一列加上操作列
+            $javascriptList[] = str_repeat(" ", 24) . "{field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate}";
+            $addList = implode("\n", array_filter($addList));
+            $editList = implode("\n", array_filter($editList));
+            $javascriptList = implode(",\n", array_filter($javascriptList));
+            $langList = implode(",\n", array_filter($langList));
+
+            //表注释
+            $tableComment = $modelTableInfo['Comment'];
+            $tableComment = mb_substr($tableComment, -1) == '表' ? mb_substr($tableComment, 0, -1) . '管理' : $tableComment;
+
+            $modelInit = '';
+            if ($priKey != $order) {
+                $modelInit = $this->getReplacedStub('mixins' . DS . 'modelinit', ['order' => $order]);
+            }
+
+
+            $data = [
+                'controllerNamespace'     => $controllerNamespace,
+                'modelNamespace'          => $modelNamespace,
+                'validateNamespace'       => $validateNamespace,
+                'controllerUrl'           => $controllerUrl,
+                'controllerName'          => $controllerName,
+                'controllerAssignList'    => implode("\n", $controllerAssignList),
+                'modelName'               => $modelName,
+                'modelTableName'          => $modelTableName,
+                'modelTableType'          => $modelTableType,
+                'modelTableTypeName'      => $modelTableTypeName,
+                'validateName'            => $validateName,
+                'tableComment'            => $tableComment,
+                'iconName'                => $iconName,
+                'pk'                      => $priKey,
+                'order'                   => $order,
+                'table'                   => $table,
+                'tableName'               => $modelTableName,
+                'addList'                 => $addList,
+                'editList'                => $editList,
+                'javascriptList'          => $javascriptList,
+                'langList'                => $langList,
+                'modelAutoWriteTimestamp' => in_array('createtime', $fieldArr) || in_array('updatetime', $fieldArr) ? "'int'" : 'false',
+                'createTime'              => in_array('createtime', $fieldArr) ? "'createtime'" : 'false',
+                'updateTime'              => in_array('updatetime', $fieldArr) ? "'updatetime'" : 'false',
+                'relationSearch'          => $relations ? 'true' : 'false',
+                'relationWithList'        => '',
+                'relationMethodList'      => '',
+                'controllerIndex'         => '',
+                'headingHtml'             => $headingHtml,
+                'visibleFieldList'        => $fields ? "\$row->visible(['" . implode("','", array_filter(explode(',', $fields))) . "']);" : '',
+                'appendAttrList'          => implode(",\n", $appendAttrList),
+                'getEnumList'             => implode("\n\n", $getEnumArr),
+                'getAttrList'             => implode("\n\n", $getAttrArr),
+                'setAttrList'             => implode("\n\n", $setAttrArr),
+                'modelInit'               => $modelInit,
+            ];
+
+            //如果使用关联模型
+            if ($relations) {
+                $relationWithList = $relationMethodList = $relationVisibleFieldList = [];
+                foreach ($relations as $index => $relation) {
+                    //需要构造关联的方法
+                    $relation['relationMethod'] = strtolower($relation['relationName']);
+
+                    //关联的模式
+                    $relation['relationMode'] = $relation['relationMode'] == 'hasone' ? 'hasOne' : 'belongsTo';
+
+                    //关联字段
+                    $relation['relationForeignKey'] = $relation['relationForeignKey'];
+                    $relation['relationPrimaryKey'] = $relation['relationPrimaryKey'] ? $relation['relationPrimaryKey'] : $priKey;
+
+                    //预载入的方法
+                    $relationWithList[] = $relation['relationMethod'];
+
+                    unset($relation['relationColumnList'], $relation['relationFieldList'], $relation['relationTableInfo']);
+
+                    //构造关联模型的方法
+                    $relationMethodList[] = $this->getReplacedStub('mixins' . DS . 'modelrelationmethod', $relation);
+
+                    //如果设置了显示主表字段,则必须显式将关联表字段显示
+                    if ($fields) {
+                        $relationVisibleFieldList[] = "\$row->visible(['{$relation['relationMethod']}']);";
+                    }
+
+                    //显示的字段
+                    if ($relation['relationFields']) {
+                        $relationVisibleFieldList[] = "\$row->getRelation('" . $relation['relationMethod'] . "')->visible(['" . implode("','", $relation['relationFields']) . "']);";
+                    }
+                }
+
+                $data['relationWithList'] = "->with(['" . implode("','", $relationWithList) . "'])";
+                $data['relationMethodList'] = implode("\n\n", $relationMethodList);
+                $data['relationVisibleFieldList'] = implode("\n\t\t\t\t", $relationVisibleFieldList);
+
+                //需要重写index方法
+                $data['controllerIndex'] = $this->getReplacedStub('controllerindex', $data);
+
+            } else if ($fields) {
+                $data = array_merge($data, ['relationWithList' => '', 'relationMethodList' => '', 'relationVisibleFieldList' => '']);
+                //需要重写index方法
+                $data['controllerIndex'] = $this->getReplacedStub('controllerindex', $data);
+            }
+
+            // 生成控制器文件
+            $result = $this->writeToFile('controller', $data, $controllerFile);
+            // 生成模型文件
+            $result = $this->writeToFile('model', $data, $modelFile);
+
+            if ($relations) {
+                foreach ($relations as $i => $relation) {
+                    $relation['modelNamespace'] = $data['modelNamespace'];
+                    if (!is_file($relation['relationFile'])) {
+                        // 生成关联模型文件
+                        $result = $this->writeToFile('relationmodel', $relation, $relation['relationFile']);
+                    }
+                }
+
+            }
+            // 生成验证文件
+            $result = $this->writeToFile('validate', $data, $validateFile);
+            // 生成视图文件
+            $result = $this->writeToFile('add', $data, $addFile);
+            $result = $this->writeToFile('edit', $data, $editFile);
+            $result = $this->writeToFile('index', $data, $indexFile);
+            // 生成JS文件
+            $result = $this->writeToFile('javascript', $data, $javascriptFile);
+            // 生成语言文件
+            if ($langList) {
+                $result = $this->writeToFile('lang', $data, $langFile);
+            }
+        } catch (\think\exception\ErrorException $e) {
+            throw new Exception("Code: " . $e->getCode() . "\nLine: " . $e->getLine() . "\nMessage: " . $e->getMessage() . "\nFile: " . $e->getFile());
+        }
+
+        //继续生成菜单
+        if ($menu) {
+            exec("php think menu -c {$controllerUrl}");
+        }
+
+        $output->info("Build Successed");
+    }
+
+    protected function getEnum(&$getEnum, &$controllerAssignList, $field, $itemArr = '', $inputType = '')
+    {
+        if (!in_array($inputType, ['datetime', 'select', 'multiple', 'checkbox', 'radio']))
+            return;
+        $fieldList = $this->getFieldListName($field);
+        $methodName = 'get' . ucfirst($fieldList);
+        foreach ($itemArr as $k => &$v) {
+            $v = "__('" . mb_ucfirst($v) . "')";
+        }
+        unset($v);
+        $itemString = $this->getArrayString($itemArr);
+        $getEnum[] = <<<EOD
+    public function {$methodName}()
+    {
+        return [{$itemString}];
+    }     
+EOD;
+        $controllerAssignList[] = <<<EOD
+        \$this->view->assign("{$fieldList}", \$this->model->{$methodName}());
+EOD;
+    }
+
+    protected function getAttr(&$getAttr, $field, $inputType = '')
+    {
+        if (!in_array($inputType, ['datetime', 'select', 'multiple', 'checkbox', 'radio']))
+            return;
+        $attrField = ucfirst($this->getCamelizeName($field));
+        $getAttr[] = $this->getReplacedStub("mixins" . DS . $inputType, ['field' => $field, 'methodName' => "get{$attrField}TextAttr", 'listMethodName' => "get{$attrField}List"]);
+    }
+
+    protected function setAttr(&$setAttr, $field, $inputType = '')
+    {
+        if (!in_array($inputType, ['datetime', 'checkbox', 'select']))
+            return;
+        $attrField = ucfirst($this->getCamelizeName($field));
+        if ($inputType == 'datetime') {
+            $return = <<<EOD
+return \$value && !is_numeric(\$value) ? strtotime(\$value) : \$value;
+EOD;
+        } else if (in_array($inputType, ['checkbox', 'select'])) {
+            $return = <<<EOD
+return is_array(\$value) ? implode(',', \$value) : \$value;
+EOD;
+        }
+        $setAttr[] = <<<EOD
+    protected function set{$attrField}Attr(\$value)
+    {
+        $return
+    }
+EOD;
+    }
+
+    protected function appendAttr(&$appendAttrList, $field)
+    {
+        $appendAttrList[] = <<<EOD
+        '{$field}_text'
+EOD;
+    }
+
+    /**
+     * 移除相对的空目录
+     * @param $parseFile
+     * @param $parseArr
+     * @return bool
+     */
+    protected function removeEmptyBaseDir($parseFile, $parseArr)
+    {
+        if (count($parseArr) > 1) {
+            $parentDir = dirname($parseFile);
+            for ($i = 0; $i < count($parseArr); $i++) {
+                $iterator = new \FilesystemIterator($parentDir);
+                $isDirEmpty = !$iterator->valid();
+                if ($isDirEmpty) {
+                    rmdir($parentDir);
+                    $parentDir = dirname($parentDir);
+                } else {
+                    return true;
+                }
+            }
+        }
+        return true;
+    }
+
+    /**
+     * 获取控制器相关信息
+     * @param $module
+     * @param $controller
+     * @param $table
+     * @return array
+     */
+    protected function getControllerData($module, $controller, $table)
+    {
+        return $this->getParseNameData($module, $controller, $table, 'controller');
+    }
+
+    /**
+     * 获取模型相关信息
+     * @param $module
+     * @param $model
+     * @param $table
+     * @return array
+     */
+    protected function getModelData($module, $model, $table)
+    {
+        return $this->getParseNameData($module, $model, $table, 'model');
+    }
+
+    /**
+     * 获取验证器相关信息
+     * @param $module
+     * @param $validate
+     * @param $table
+     * @return array
+     */
+    protected function getValidateData($module, $validate, $table)
+    {
+        return $this->getParseNameData($module, $validate, $table, 'validate');
+    }
+
+    /**
+     * 获取已解析相关信息
+     * @param $module
+     * @param $name
+     * @param $table
+     * @param $type
+     * @return array
+     */
+    protected function getParseNameData($module, $name, $table, $type)
+    {
+        $arr = [];
+        if (!$name) {
+            $arr = explode('_', strtolower($table));
+        } else {
+            $name = str_replace(['.', '/', '\\'], '/', $name);
+            $arr = explode('/', $name);
+        }
+        $parseName = ucfirst(array_pop($arr));
+        $appNamespace = Config::get('app_namespace');
+        $parseNamespace = "{$appNamespace}\\{$module}\\{$type}" . ($arr ? "\\" . implode("\\", $arr) : "");
+        $moduleDir = APP_PATH . $module . DS;
+        $parseFile = $moduleDir . $type . DS . ($arr ? implode(DS, $arr) . DS : '') . $parseName . '.php';
+        $parseArr = $arr;
+        $parseArr[] = $parseName;
+        return [$parseNamespace, $parseName, $parseFile, $parseArr];
+    }
+
+    /**
+     * 写入到文件
+     * @param string $name
+     * @param array $data
+     * @param string $pathname
+     * @return mixed
+     */
+    protected function writeToFile($name, $data, $pathname)
+    {
+        foreach ($data as $index => &$datum) {
+            $datum = is_array($datum) ? '' : $datum;
+        }
+        unset($datum);
+        $content = $this->getReplacedStub($name, $data);
+
+        if (!is_dir(dirname($pathname))) {
+            mkdir(dirname($pathname), 0755, true);
+        }
+        return file_put_contents($pathname, $content);
+    }
+
+    /**
+     * 获取替换后的数据
+     * @param string $name
+     * @param array $data
+     * @return string
+     */
+    protected function getReplacedStub($name, $data)
+    {
+        foreach ($data as $index => &$datum) {
+            $datum = is_array($datum) ? '' : $datum;
+        }
+        unset($datum);
+        $search = $replace = [];
+        foreach ($data as $k => $v) {
+            $search[] = "{%{$k}%}";
+            $replace[] = $v;
+        }
+        $stubname = $this->getStub($name);
+        if (isset($this->stubList[$stubname])) {
+            $stub = $this->stubList[$stubname];
+        } else {
+            $this->stubList[$stubname] = $stub = file_get_contents($stubname);
+        }
+        $content = str_replace($search, $replace, $stub);
+        return $content;
+    }
+
+    /**
+     * 获取基础模板
+     * @param string $name
+     * @return string
+     */
+    protected function getStub($name)
+    {
+        return __DIR__ . DS . 'Crud' . DS . 'stubs' . DS . $name . '.stub';
+    }
+
+    protected function getLangItem($field, $content)
+    {
+        if ($content || !Lang::has($field)) {
+            $itemArr = [];
+            $content = str_replace(',', ',', $content);
+            if (stripos($content, ':') !== false && stripos($content, ',') && stripos($content, '=') !== false) {
+                list($fieldLang, $item) = explode(':', $content);
+                $itemArr = [$field => $fieldLang];
+                foreach (explode(',', $item) as $k => $v) {
+                    $valArr = explode('=', $v);
+                    if (count($valArr) == 2) {
+                        list($key, $value) = $valArr;
+                        $itemArr[$field . ' ' . $key] = $value;
+                    }
+                }
+            } else {
+                $itemArr = [$field => $content];
+            }
+            $resultArr = [];
+            foreach ($itemArr as $k => $v) {
+                $resultArr[] = "    '" . mb_ucfirst($k) . "'  =>  '{$v}'";
+            }
+            return implode(",\n", $resultArr);
+        } else {
+            return '';
+        }
+    }
+
+    /**
+     * 读取数据和语言数组列表
+     * @param array $arr
+     * @param boolean $withTpl
+     * @return array
+     */
+    protected function getLangArray($arr, $withTpl = TRUE)
+    {
+        $langArr = [];
+        foreach ($arr as $k => $v) {
+            $langArr[$k] = is_numeric($k) ? ($withTpl ? "{:" : "") . "__('" . mb_ucfirst($v) . "')" . ($withTpl ? "}" : "") : $v;
+        }
+        return $langArr;
+    }
+
+    /**
+     * 将数据转换成带字符串
+     * @param array $arr
+     * @return string
+     */
+    protected function getArrayString($arr)
+    {
+        if (!is_array($arr))
+            return $arr;
+        $stringArr = [];
+        foreach ($arr as $k => $v) {
+            $is_var = in_array(substr($v, 0, 1), ['$', '_']);
+            if (!$is_var) {
+                $v = str_replace("'", "\'", $v);
+                $k = str_replace("'", "\'", $k);
+            }
+            $stringArr[] = "'" . $k . "' => " . ($is_var ? $v : "'{$v}'");
+        }
+        return implode(",", $stringArr);
+    }
+
+    protected function getItemArray($item, $field, $comment)
+    {
+        $itemArr = [];
+        $comment = str_replace(',', ',', $comment);
+        if (stripos($comment, ':') !== false && stripos($comment, ',') && stripos($comment, '=') !== false) {
+            list($fieldLang, $item) = explode(':', $comment);
+            $itemArr = [];
+            foreach (explode(',', $item) as $k => $v) {
+                $valArr = explode('=', $v);
+                if (count($valArr) == 2) {
+                    list($key, $value) = $valArr;
+                    $itemArr[$key] = $field . ' ' . $key;
+                }
+            }
+        } else {
+            foreach ($item as $k => $v) {
+                $itemArr[$v] = is_numeric($v) ? $field . ' ' . $v : $v;
+            }
+        }
+        return $itemArr;
+    }
+
+    protected function getFieldType(& $v)
+    {
+        $inputType = 'text';
+        switch ($v['DATA_TYPE']) {
+            case 'bigint':
+            case 'int':
+            case 'mediumint':
+            case 'smallint':
+            case 'tinyint':
+                $inputType = 'number';
+                break;
+            case 'enum':
+            case 'set':
+                $inputType = 'select';
+                break;
+            case 'decimal':
+            case 'double':
+            case 'float':
+                $inputType = 'number';
+                break;
+            case 'longtext':
+            case 'text':
+            case 'mediumtext':
+            case 'smalltext':
+            case 'tinytext':
+                $inputType = 'textarea';
+                break;
+            case 'year';
+            case 'date';
+            case 'time';
+            case 'datetime';
+            case 'timestamp';
+                $inputType = 'datetime';
+                break;
+            default:
+                break;
+        }
+        $fieldsName = $v['COLUMN_NAME'];
+        // 指定后缀说明也是个时间字段
+        if ($this->isMatchSuffix($fieldsName, $this->intDateSuffix)) {
+            $inputType = 'datetime';
+        }
+        // 指定后缀结尾且类型为enum,说明是个单选框
+        if ($this->isMatchSuffix($fieldsName, $this->enumRadioSuffix) && $v['DATA_TYPE'] == 'enum') {
+            $inputType = "radio";
+        }
+        // 指定后缀结尾且类型为set,说明是个复选框
+        if ($this->isMatchSuffix($fieldsName, $this->setCheckboxSuffix) && $v['DATA_TYPE'] == 'set') {
+            $inputType = "checkbox";
+        }
+        // 指定后缀结尾且类型为char或tinyint且长度为1,说明是个Switch复选框
+        if ($this->isMatchSuffix($fieldsName, $this->switchSuffix) && ($v['COLUMN_TYPE'] == 'tinyint(1)' || $v['COLUMN_TYPE'] == 'char(1)') && $v['COLUMN_DEFAULT'] !== '' && $v['COLUMN_DEFAULT'] !== null) {
+            $inputType = "switch";
+        }
+        // 指定后缀结尾城市选择框
+        if ($this->isMatchSuffix($fieldsName, $this->citySuffix) && ($v['DATA_TYPE'] == 'varchar' || $v['DATA_TYPE'] == 'char')) {
+            $inputType = "citypicker";
+        }
+        return $inputType;
+    }
+
+    /**
+     * 判断是否符合指定后缀
+     * @param string $field 字段名称
+     * @param mixed $suffixArr 后缀
+     * @return boolean
+     */
+    protected function isMatchSuffix($field, $suffixArr)
+    {
+        $suffixArr = is_array($suffixArr) ? $suffixArr : explode(',', $suffixArr);
+        foreach ($suffixArr as $k => $v) {
+            if (preg_match("/{$v}$/i", $field)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 获取表单分组数据
+     * @param string $field
+     * @param string $content
+     * @return string
+     */
+    protected function getFormGroup($field, $content)
+    {
+        $langField = mb_ucfirst($field);
+        return <<<EOD
+    <div class="form-group">
+        <label class="control-label col-xs-12 col-sm-2">{:__('{$langField}')}:</label>
+        <div class="col-xs-12 col-sm-8">
+            {$content}
+        </div>
+    </div>
+EOD;
+    }
+
+    /**
+     * 获取图片模板数据
+     * @param string $field
+     * @param string $content
+     * @return string
+     */
+    protected function getImageUpload($field, $content)
+    {
+        $uploadfilter = $selectfilter = '';
+        if ($this->isMatchSuffix($field, $this->imageField)) {
+            $uploadfilter = ' data-mimetype="image/gif,image/jpeg,image/png,image/jpg,image/bmp"';
+            $selectfilter = ' data-mimetype="image/*"';
+        }
+        $multiple = substr($field, -1) == 's' ? ' data-multiple="true"' : ' data-multiple="false"';
+        $preview = ' data-preview-id="p-' . $field . '"';
+        $previewcontainer = $preview ? '<ul class="row list-inline plupload-preview" id="p-' . $field . '"></ul>' : '';
+        return <<<EOD
+<div class="input-group">
+                {$content}
+                <div class="input-group-addon no-border no-padding">
+                    <span><button type="button" id="plupload-{$field}" class="btn btn-danger plupload" data-input-id="c-{$field}"{$uploadfilter}{$multiple}{$preview}><i class="fa fa-upload"></i> {:__('Upload')}</button></span>
+                    <span><button type="button" id="fachoose-{$field}" class="btn btn-primary fachoose" data-input-id="c-{$field}"{$selectfilter}{$multiple}><i class="fa fa-list"></i> {:__('Choose')}</button></span>
+                </div>
+                <span class="msg-box n-right" for="c-{$field}"></span>
+            </div>
+            {$previewcontainer}
+EOD;
+    }
+
+    /**
+     * 获取JS列数据
+     * @param string $field
+     * @param string $datatype
+     * @param string $extend
+     * @param array $itemArr
+     * @return string
+     */
+    protected function getJsColumn($field, $datatype = '', $extend = '', $itemArr = [])
+    {
+        $lang = mb_ucfirst($field);
+        $formatter = '';
+        foreach ($this->fieldFormatterSuffix as $k => $v) {
+            if (preg_match("/{$k}$/i", $field)) {
+                if (is_array($v)) {
+                    if (in_array($datatype, $v['type'])) {
+                        $formatter = $v['name'];
+                        break;
+                    }
+                } else {
+                    $formatter = $v;
+                    break;
+                }
+            }
+        }
+        $html = str_repeat(" ", 24) . "{field: '{$field}', title: __('{$lang}')";
+
+        if ($datatype == 'set') {
+            $formatter = 'label';
+        }
+        foreach ($itemArr as $k => &$v) {
+            if (substr($v, 0, 3) !== '__(')
+                $v = "__('" . mb_ucfirst($v) . "')";
+        }
+        unset($v);
+        $searchList = json_encode($itemArr, JSON_FORCE_OBJECT | JSON_UNESCAPED_UNICODE);
+        $searchList = str_replace(['":"', '"}', ')","'], ['":', '}', '),"'], $searchList);
+        if ($itemArr) {
+            $html .= ", searchList: " . $searchList;
+        }
+        if (in_array($datatype, ['date', 'datetime']) || $formatter === 'datetime') {
+            $html .= ", operate:'RANGE', addclass:'datetimerange'";
+        } else if (in_array($datatype, ['float', 'double', 'decimal'])) {
+            $html .= ", operate:'BETWEEN'";
+        }
+        if (in_array($datatype, ['set'])) {
+            $html .= ", operate:'FIND_IN_SET'";
+        }
+        if ($itemArr && !$formatter) {
+            $formatter = 'normal';
+        }
+        if ($formatter)
+            $html .= ", formatter: Table.api.formatter." . $formatter . "}";
+        else
+            $html .= "}";
+        return $html;
+    }
+
+    protected function getCamelizeName($uncamelized_words, $separator = '_')
+    {
+        $uncamelized_words = $separator . str_replace($separator, " ", strtolower($uncamelized_words));
+        return ltrim(str_replace(" ", "", ucwords($uncamelized_words)), $separator);
+    }
+
+    protected function getFieldListName($field)
+    {
+        return $this->getCamelizeName($field) . 'List';
+    }
+
+}

+ 11 - 0
application/admin/command/Crud/stubs/add.stub

@@ -0,0 +1,11 @@
+<form id="add-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action="">
+
+{%addList%}
+    <div class="form-group layer-footer">
+        <label class="control-label col-xs-12 col-sm-2"></label>
+        <div class="col-xs-12 col-sm-8">
+            <button type="submit" class="btn btn-success btn-embossed disabled">{:__('OK')}</button>
+            <button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
+        </div>
+    </div>
+</form>

+ 35 - 0
application/admin/command/Crud/stubs/controller.stub

@@ -0,0 +1,35 @@
+<?php
+
+namespace {%controllerNamespace%};
+
+use app\common\controller\Backend;
+
+/**
+ * {%tableComment%}
+ *
+ * @icon {%iconName%}
+ */
+class {%controllerName%} extends Backend
+{
+    
+    /**
+     * {%modelName%}模型对象
+     * @var \{%modelNamespace%}\{%modelName%}
+     */
+    protected $model = null;
+
+    public function _initialize()
+    {
+        parent::_initialize();
+        $this->model = new \{%modelNamespace%}\{%modelName%};
+{%controllerAssignList%}
+    }
+    
+    /**
+     * 默认生成的控制器所继承的父类中有index/add/edit/del/multi五个基础方法、destroy/restore/recyclebin三个回收站方法
+     * 因此在当前控制器中可不用编写增删改查的代码,除非需要自己控制这部分逻辑
+     * 需要将application/admin/library/traits/Backend.php中对应的方法复制到当前控制器,然后进行修改
+     */
+    
+{%controllerIndex%}
+}

+ 42 - 0
application/admin/command/Crud/stubs/controllerindex.stub

@@ -0,0 +1,42 @@
+
+    /**
+     * 查看
+     */
+    public function index()
+    {
+        //当前是否为关联查询
+        $this->relationSearch = {%relationSearch%};
+        //设置过滤方法
+        $this->request->filter(['strip_tags']);
+        if ($this->request->isAjax())
+        {
+            //如果发送的来源是Selectpage,则转发到Selectpage
+            if ($this->request->request('keyField'))
+            {
+                return $this->selectpage();
+            }
+            list($where, $sort, $order, $offset, $limit) = $this->buildparams();
+            $total = $this->model
+                    {%relationWithList%}
+                    ->where($where)
+                    ->order($sort, $order)
+                    ->count();
+
+            $list = $this->model
+                    {%relationWithList%}
+                    ->where($where)
+                    ->order($sort, $order)
+                    ->limit($offset, $limit)
+                    ->select();
+
+            foreach ($list as $row) {
+                {%visibleFieldList%}
+                {%relationVisibleFieldList%}
+            }
+            $list = collection($list)->toArray();
+            $result = array("total" => $total, "rows" => $list);
+
+            return json($result);
+        }
+        return $this->view->fetch();
+    }

+ 11 - 0
application/admin/command/Crud/stubs/edit.stub

@@ -0,0 +1,11 @@
+<form id="edit-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action="">
+
+{%editList%}
+    <div class="form-group layer-footer">
+        <label class="control-label col-xs-12 col-sm-2"></label>
+        <div class="col-xs-12 col-sm-8">
+            <button type="submit" class="btn btn-success btn-embossed disabled">{:__('OK')}</button>
+            <button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
+        </div>
+    </div>
+</form>

+ 6 - 0
application/admin/command/Crud/stubs/html/checkbox.stub

@@ -0,0 +1,6 @@
+
+            <div class="checkbox">
+            {foreach name="{%fieldList%}" item="vo"}
+            <label for="{%fieldName%}-{$key}"><input id="{%fieldName%}-{$key}" name="{%fieldName%}" type="checkbox" value="{$key}" {in name="key" value="{%selectedValue%}"}checked{/in} /> {$vo}</label> 
+            {/foreach}
+            </div>

+ 10 - 0
application/admin/command/Crud/stubs/html/heading-html.stub

@@ -0,0 +1,10 @@
+
+    <div class="panel-heading">
+        {:build_heading(null,FALSE)}
+        <ul class="nav nav-tabs" data-field="{%field%}">
+            <li class="active"><a href="#t-all" data-value="" data-toggle="tab">{:__('All')}</a></li>
+            {foreach name="{%field%}List" item="vo"}
+            <li><a href="#t-{$key}" data-value="{$key}" data-toggle="tab">{$vo}</a></li>
+            {/foreach}
+        </ul>
+    </div>

+ 6 - 0
application/admin/command/Crud/stubs/html/radio.stub

@@ -0,0 +1,6 @@
+
+            <div class="radio">
+            {foreach name="{%fieldList%}" item="vo"}
+            <label for="{%fieldName%}-{$key}"><input id="{%fieldName%}-{$key}" name="{%fieldName%}" type="radio" value="{$key}" {in name="key" value="{%selectedValue%}"}checked{/in} /> {$vo}</label> 
+            {/foreach}
+            </div>

+ 6 - 0
application/admin/command/Crud/stubs/html/select.stub

@@ -0,0 +1,6 @@
+            
+            <select {%attrStr%}>
+                {foreach name="{%fieldList%}" item="vo"}
+                    <option value="{$key}" {in name="key" value="{%selectedValue%}"}selected{/in}>{$vo}</option>
+                {/foreach}
+            </select>

+ 5 - 0
application/admin/command/Crud/stubs/html/switch.stub

@@ -0,0 +1,5 @@
+
+            <input {%attrStr%} name="{%fieldName%}" type="hidden" value="{%fieldValue%}">
+            <a href="javascript:;" data-toggle="switcher" class="btn-switcher" data-input-id="c-{%field%}" data-yes="{%fieldYes%}" data-no="{%fieldNo%}" >
+                <i class="fa fa-toggle-on text-success {%fieldSwitchClass%} fa-2x"></i>
+            </a>

+ 33 - 0
application/admin/command/Crud/stubs/index.stub

@@ -0,0 +1,33 @@
+<div class="panel panel-default panel-intro">
+    {%headingHtml%}
+
+    <div class="panel-body">
+        <div id="myTabContent" class="tab-content">
+            <div class="tab-pane fade active in" id="one">
+                <div class="widget-body no-padding">
+                    <div id="toolbar" class="toolbar">
+                        <a href="javascript:;" class="btn btn-primary btn-refresh" title="{:__('Refresh')}" ><i class="fa fa-refresh"></i> </a>
+                        <a href="javascript:;" class="btn btn-success btn-add {:$auth->check('{%controllerUrl%}/add')?'':'hide'}" title="{:__('Add')}" ><i class="fa fa-plus"></i> {:__('Add')}</a>
+                        <a href="javascript:;" class="btn btn-success btn-edit btn-disabled disabled {:$auth->check('{%controllerUrl%}/edit')?'':'hide'}" title="{:__('Edit')}" ><i class="fa fa-pencil"></i> {:__('Edit')}</a>
+                        <a href="javascript:;" class="btn btn-danger btn-del btn-disabled disabled {:$auth->check('{%controllerUrl%}/del')?'':'hide'}" title="{:__('Delete')}" ><i class="fa fa-trash"></i> {:__('Delete')}</a>
+                        <a href="javascript:;" class="btn btn-danger btn-import {:$auth->check('{%controllerUrl%}/import')?'':'hide'}" title="{:__('Import')}" id="btn-import-file" data-url="ajax/upload" data-mimetype="csv,xls,xlsx" data-multiple="false"><i class="fa fa-upload"></i> {:__('Import')}</a>
+
+                        <div class="dropdown btn-group {:$auth->check('{%controllerUrl%}/multi')?'':'hide'}">
+                            <a class="btn btn-primary btn-more dropdown-toggle btn-disabled disabled" data-toggle="dropdown"><i class="fa fa-cog"></i> {:__('More')}</a>
+                            <ul class="dropdown-menu text-left" role="menu">
+                                <li><a class="btn btn-link btn-multi btn-disabled disabled" href="javascript:;" data-params="status=normal"><i class="fa fa-eye"></i> {:__('Set to normal')}</a></li>
+                                <li><a class="btn btn-link btn-multi btn-disabled disabled" href="javascript:;" data-params="status=hidden"><i class="fa fa-eye-slash"></i> {:__('Set to hidden')}</a></li>
+                            </ul>
+                        </div>
+                    </div>
+                    <table id="table" class="table table-striped table-bordered table-hover table-nowrap"
+                           data-operate-edit="{:$auth->check('{%controllerUrl%}/edit')}" 
+                           data-operate-del="{:$auth->check('{%controllerUrl%}/del')}" 
+                           width="100%">
+                    </table>
+                </div>
+            </div>
+
+        </div>
+    </div>
+</div>

+ 47 - 0
application/admin/command/Crud/stubs/javascript.stub

@@ -0,0 +1,47 @@
+define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) {
+
+    var Controller = {
+        index: function () {
+            // 初始化表格参数配置
+            Table.api.init({
+                extend: {
+                    index_url: '{%controllerUrl%}/index',
+                    add_url: '{%controllerUrl%}/add',
+                    edit_url: '{%controllerUrl%}/edit',
+                    del_url: '{%controllerUrl%}/del',
+                    multi_url: '{%controllerUrl%}/multi',
+                    table: '{%table%}',
+                }
+            });
+
+            var table = $("#table");
+
+            // 初始化表格
+            table.bootstrapTable({
+                url: $.fn.bootstrapTable.defaults.extend.index_url,
+                pk: '{%pk%}',
+                sortName: '{%order%}',
+                columns: [
+                    [
+                        {%javascriptList%}
+                    ]
+                ]
+            });
+
+            // 为表格绑定事件
+            Table.api.bindevent(table);
+        },
+        add: function () {
+            Controller.api.bindevent();
+        },
+        edit: function () {
+            Controller.api.bindevent();
+        },
+        api: {
+            bindevent: function () {
+                Form.api.bindevent($("form[role=form]"));
+            }
+        }
+    };
+    return Controller;
+});

+ 5 - 0
application/admin/command/Crud/stubs/lang.stub

@@ -0,0 +1,5 @@
+<?php
+
+return [
+{%langList%}
+];

+ 8 - 0
application/admin/command/Crud/stubs/mixins/checkbox.stub

@@ -0,0 +1,8 @@
+
+    public function {%methodName%}($value, $data)
+    {
+        $value = $value ? $value : (isset($data['{%field%}']) ? $data['{%field%}'] : '');
+        $valueArr = explode(',', $value);
+        $list = $this->{%listMethodName%}();
+        return implode(',', array_intersect_key($list, array_flip($valueArr)));
+    }

+ 6 - 0
application/admin/command/Crud/stubs/mixins/datetime.stub

@@ -0,0 +1,6 @@
+
+    public function {%methodName%}($value, $data)
+    {
+        $value = $value ? $value : (isset($data['{%field%}']) ? $data['{%field%}'] : '');
+        return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value;
+    }

+ 1 - 0
application/admin/command/Crud/stubs/mixins/enum.stub

@@ -0,0 +1 @@
+

+ 8 - 0
application/admin/command/Crud/stubs/mixins/modelinit.stub

@@ -0,0 +1,8 @@
+
+    protected static function init()
+    {
+        self::afterInsert(function ($row) {
+            $pk = $row->getPk();
+            $row->getQuery()->where($pk, $row[$pk])->update(['{%order%}' => $row[$pk]]);
+        });
+    }

+ 5 - 0
application/admin/command/Crud/stubs/mixins/modelrelationmethod.stub

@@ -0,0 +1,5 @@
+
+    public function {%relationMethod%}()
+    {
+        return $this->{%relationMode%}('{%relationName%}', '{%relationForeignKey%}', '{%relationPrimaryKey%}', [], 'LEFT')->setEagerlyType(0);
+    }

+ 8 - 0
application/admin/command/Crud/stubs/mixins/multiple.stub

@@ -0,0 +1,8 @@
+
+    public function {%methodName%}($value, $data)
+    {
+        $value = $value ? $value : (isset($data['{%field%}']) ? $data['{%field%}'] : '');
+        $valueArr = explode(',', $value);
+        $list = $this->{%listMethodName%}();
+        return implode(',', array_intersect_key($list, array_flip($valueArr)));
+    }

+ 7 - 0
application/admin/command/Crud/stubs/mixins/radio.stub

@@ -0,0 +1,7 @@
+
+    public function {%methodName%}($value, $data)
+    {        
+        $value = $value ? $value : (isset($data['{%field%}']) ? $data['{%field%}'] : '');
+        $list = $this->{%listMethodName%}();
+        return isset($list[$value]) ? $list[$value] : '';
+    }

+ 7 - 0
application/admin/command/Crud/stubs/mixins/select.stub

@@ -0,0 +1,7 @@
+
+    public function {%methodName%}($value, $data)
+    {        
+        $value = $value ? $value : (isset($data['{%field%}']) ? $data['{%field%}'] : '');
+        $list = $this->{%listMethodName%}();
+        return isset($list[$value]) ? $list[$value] : '';
+    }

+ 33 - 0
application/admin/command/Crud/stubs/model.stub

@@ -0,0 +1,33 @@
+<?php
+
+namespace {%modelNamespace%};
+
+use think\Model;
+
+class {%modelName%} extends Model
+{
+    // 表名
+    protected ${%modelTableType%} = '{%modelTableTypeName%}';
+    
+    // 自动写入时间戳字段
+    protected $autoWriteTimestamp = {%modelAutoWriteTimestamp%};
+
+    // 定义时间戳字段名
+    protected $createTime = {%createTime%};
+    protected $updateTime = {%updateTime%};
+    
+    // 追加属性
+    protected $append = [
+{%appendAttrList%}
+    ];
+    
+{%modelInit%}
+    
+{%getEnumList%}
+
+{%getAttrList%}
+
+{%setAttrList%}
+
+{%relationMethodList%}
+}

+ 12 - 0
application/admin/command/Crud/stubs/relationmodel.stub

@@ -0,0 +1,12 @@
+<?php
+
+namespace {%modelNamespace%};
+
+use think\Model;
+
+class {%relationName%} extends Model
+{
+    // 表名
+    protected ${%relationTableType%} = '{%relationTableTypeName%}';
+    
+}

+ 27 - 0
application/admin/command/Crud/stubs/validate.stub

@@ -0,0 +1,27 @@
+<?php
+
+namespace {%validateNamespace%};
+
+use think\Validate;
+
+class {%validateName%} extends Validate
+{
+    /**
+     * 验证规则
+     */
+    protected $rule = [
+    ];
+    /**
+     * 提示消息
+     */
+    protected $message = [
+    ];
+    /**
+     * 验证场景
+     */
+    protected $scene = [
+        'add'  => [],
+        'edit' => [],
+    ];
+    
+}

+ 97 - 0
application/admin/command/Install.php

@@ -0,0 +1,97 @@
+<?php
+
+namespace app\admin\command;
+
+use PDO;
+use think\Config;
+use think\console\Command;
+use think\console\Input;
+use think\console\input\Option;
+use think\console\Output;
+use think\Db;
+use think\Exception;
+
+class Install extends Command
+{
+
+    protected $model = null;
+
+    protected function configure()
+    {
+        $config = Config::get('database');
+        $this
+            ->setName('install')
+            ->addOption('hostname', 'a', Option::VALUE_OPTIONAL, 'mysql hostname', $config['hostname'])
+            ->addOption('hostport', 'o', Option::VALUE_OPTIONAL, 'mysql hostport', $config['hostport'])
+            ->addOption('database', 'd', Option::VALUE_OPTIONAL, 'mysql database', $config['database'])
+            ->addOption('prefix', 'r', Option::VALUE_OPTIONAL, 'table prefix', $config['prefix'])
+            ->addOption('username', 'u', Option::VALUE_OPTIONAL, 'mysql username', $config['username'])
+            ->addOption('password', 'p', Option::VALUE_OPTIONAL, 'mysql password', $config['password'])
+            ->addOption('force', 'f', Option::VALUE_OPTIONAL, 'force override', FALSE)
+            ->setDescription('New installation of FastAdmin');
+    }
+
+    protected function execute(Input $input, Output $output)
+    {
+        // 覆盖安装
+        $force = $input->getOption('force');
+        $hostname = $input->getOption('hostname');
+        $hostport = $input->getOption('hostport');
+        $database = $input->getOption('database');
+        $prefix = $input->getOption('prefix');
+        $username = $input->getOption('username');
+        $password = $input->getOption('password');
+
+        $installLockFile = __DIR__ . "/Install/install.lock";
+        if (is_file($installLockFile) && !$force) {
+            throw new Exception("\nFastAdmin already installed!\nIf you need to reinstall again, use the parameter --force=true ");
+        }
+
+        $sql = file_get_contents(__DIR__ . '/Install/fastadmin.sql');
+
+        $sql = str_replace("`fa_", "`{$prefix}", $sql);
+
+        // 先尝试能否自动创建数据库
+        $config = Config::get('database');
+        $pdo = new PDO("{$config['type']}:host={$hostname}" . ($hostport ? ";port={$hostport}" : ''), $username, $password);
+        $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+        $pdo->query("CREATE DATABASE IF NOT EXISTS `{$database}` CHARACTER SET utf8 COLLATE utf8_general_ci;");
+
+        // 连接install命令中指定的数据库
+        $instance = Db::connect([
+            'type' => "{$config['type']}",
+            'hostname' => "{$hostname}",
+            'hostport' => "{$hostport}",
+            'database' => "{$database}",
+            'username' => "{$username}",
+            'password' => "{$password}",
+        ]);
+
+        // 查询一次SQL,判断连接是否正常
+        $instance->execute("SELECT 1");
+
+        // 调用原生PDO对象进行批量查询
+        $instance->getPdo()->exec($sql);
+
+        file_put_contents($installLockFile, 1);
+
+        $dbConfigFile = APP_PATH . 'database.php';
+        $config = @file_get_contents($dbConfigFile);
+        $callback = function ($matches) use ($hostname, $hostport, $username, $password, $database, $prefix) {
+            $field = $matches[1];
+            $replace = $$field;
+            if ($matches[1] == 'hostport' && $hostport == 3306) {
+                $replace = '';
+            }
+            return "'{$matches[1]}'{$matches[2]}=>{$matches[3]}Env::get('database.{$matches[1]}', '{$replace}'),";
+        };
+        $config = preg_replace_callback("/'(hostname|database|username|password|hostport|prefix)'(\s+)=>(\s+)Env::get\((.*)\)\,/", $callback, $config);
+        // 写入数据库配置
+        file_put_contents($dbConfigFile, $config);
+
+        \think\Cache::rm('__menu__');
+
+        $output->info("Install Successed!");
+    }
+
+}

+ 579 - 0
application/admin/command/Install/fastadmin.sql

@@ -0,0 +1,579 @@
+/*
+ FastAdmin Install SQL
+
+ 官网: https://www.fastadmin.net
+ 演示: https://demo.fastadmin.net
+
+ Date: 2018年05月26日
+*/
+
+SET FOREIGN_KEY_CHECKS = 0;
+
+-- ----------------------------
+-- Table structure for fa_admin
+-- ----------------------------
+DROP TABLE IF EXISTS `fa_admin`;
+CREATE TABLE `fa_admin` (
+  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
+  `username` varchar(20) NOT NULL DEFAULT '' COMMENT '用户名',
+  `nickname` varchar(50) NOT NULL DEFAULT '' COMMENT '昵称',
+  `password` varchar(32) NOT NULL DEFAULT '' COMMENT '密码',
+  `salt` varchar(30) NOT NULL DEFAULT '' COMMENT '密码盐',
+  `avatar` varchar(100) NOT NULL DEFAULT '' COMMENT '头像',
+  `email` varchar(100) NOT NULL DEFAULT '' COMMENT '电子邮箱',
+  `loginfailure` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '失败次数',
+  `logintime` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '登录时间',
+  `createtime` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
+  `updatetime` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '更新时间',
+  `token` varchar(59) NOT NULL DEFAULT '' COMMENT 'Session标识',
+  `status` varchar(30) NOT NULL DEFAULT 'normal' COMMENT '状态',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `username` (`username`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='管理员表';
+
+-- ----------------------------
+-- Records of fa_admin
+-- ----------------------------
+BEGIN;
+INSERT INTO `fa_admin` VALUES (1, 'admin', 'Admin', '075eaec83636846f51c152f29b98a2fd', 's4f3', '/assets/img/avatar.png', 'admin@fastadmin.net', 0, 1502029281, 1492186163, 1502029281, 'd3992c3b-5ecc-4ecb-9dc2-8997780fcadc', 'normal');
+COMMIT;
+
+-- ----------------------------
+-- Table structure for fa_admin_log
+-- ----------------------------
+DROP TABLE IF EXISTS `fa_admin_log`;
+CREATE TABLE `fa_admin_log` (
+  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
+  `admin_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '管理员ID',
+  `username` varchar(30) NOT NULL DEFAULT '' COMMENT '管理员名字',
+  `url` varchar(1500) NOT NULL DEFAULT '' COMMENT '操作页面',
+  `title` varchar(100) NOT NULL DEFAULT '' COMMENT '日志标题',
+  `content` text NOT NULL COMMENT '内容',
+  `ip` varchar(50) NOT NULL DEFAULT '' COMMENT 'IP',
+  `useragent` varchar(255) NOT NULL DEFAULT '' COMMENT 'User-Agent',
+  `createtime` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '操作时间',
+  PRIMARY KEY (`id`),
+  KEY `name` (`username`)
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='管理员日志表';
+
+-- ----------------------------
+-- Table structure for fa_attachment
+-- ----------------------------
+DROP TABLE IF EXISTS `fa_attachment`;
+CREATE TABLE `fa_attachment` (
+  `id` int(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
+  `admin_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '管理员ID',
+  `user_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '会员ID',
+  `url` varchar(255) NOT NULL DEFAULT '' COMMENT '物理路径',
+  `imagewidth` varchar(30) NOT NULL DEFAULT '' COMMENT '宽度',
+  `imageheight` varchar(30) NOT NULL DEFAULT '' COMMENT '高度',
+  `imagetype` varchar(30) NOT NULL DEFAULT '' COMMENT '图片类型',
+  `imageframes` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '图片帧数',
+  `filesize` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '文件大小',
+  `mimetype` varchar(100) NOT NULL DEFAULT '' COMMENT 'mime类型',
+  `extparam` varchar(255) NOT NULL DEFAULT '' COMMENT '透传数据',
+  `createtime` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '创建日期',
+  `updatetime` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '更新时间',
+  `uploadtime` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '上传时间',
+  `storage` varchar(100) NOT NULL DEFAULT 'local' COMMENT '存储位置',
+  `sha1` varchar(40) NOT NULL DEFAULT '' COMMENT '文件 sha1编码',
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='附件表';
+
+-- ----------------------------
+-- Records of fa_attachment
+-- ----------------------------
+BEGIN;
+INSERT INTO `fa_attachment` VALUES (1, 1, 0, '/assets/img/qrcode.png', '150', '150', 'png', 0, 21859, 'image/png', '', 1499681848, 1499681848, 1499681848, 'local', '17163603d0263e4838b9387ff2cd4877e8b018f6');
+COMMIT;
+
+-- ----------------------------
+-- Table structure for fa_auth_group
+-- ----------------------------
+DROP TABLE IF EXISTS `fa_auth_group`;
+CREATE TABLE `fa_auth_group` (
+  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `pid` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '父组别',
+  `name` varchar(100) NOT NULL DEFAULT '' COMMENT '组名',
+  `rules` text NOT NULL COMMENT '规则ID',
+  `createtime` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
+  `updatetime` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '更新时间',
+  `status` varchar(30) NOT NULL DEFAULT '' COMMENT '状态',
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='分组表';
+
+-- ----------------------------
+-- Records of fa_auth_group
+-- ----------------------------
+BEGIN;
+INSERT INTO `fa_auth_group` VALUES (1, 0, 'Admin group', '*', 1490883540, 149088354, 'normal');
+INSERT INTO `fa_auth_group` VALUES (2, 1, 'Second group', '13,14,16,15,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,40,41,42,43,44,45,46,47,48,49,50,55,56,57,58,59,60,61,62,63,64,65,1,9,10,11,7,6,8,2,4,5', 1490883540, 1505465692, 'normal');
+INSERT INTO `fa_auth_group` VALUES (3, 2, 'Third group', '1,4,9,10,11,13,14,15,16,17,40,41,42,43,44,45,46,47,48,49,50,55,56,57,58,59,60,61,62,63,64,65,5', 1490883540, 1502205322, 'normal');
+INSERT INTO `fa_auth_group` VALUES (4, 1, 'Second group 2', '1,4,13,14,15,16,17,55,56,57,58,59,60,61,62,63,64,65', 1490883540, 1502205350, 'normal');
+INSERT INTO `fa_auth_group` VALUES (5, 2, 'Third group 2', '1,2,6,7,8,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34', 1490883540, 1502205344, 'normal');
+COMMIT;
+
+-- ----------------------------
+-- Table structure for fa_auth_group_access
+-- ----------------------------
+DROP TABLE IF EXISTS `fa_auth_group_access`;
+CREATE TABLE `fa_auth_group_access` (
+  `uid` int(10) unsigned NOT NULL COMMENT '会员ID',
+  `group_id` int(10) unsigned NOT NULL COMMENT '级别ID',
+  UNIQUE KEY `uid_group_id` (`uid`,`group_id`),
+  KEY `uid` (`uid`),
+  KEY `group_id` (`group_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='权限分组表';
+
+-- ----------------------------
+-- Records of fa_auth_group_access
+-- ----------------------------
+BEGIN;
+INSERT INTO `fa_auth_group_access` VALUES (1, 1);
+COMMIT;
+
+-- ----------------------------
+-- Table structure for fa_auth_rule
+-- ----------------------------
+DROP TABLE IF EXISTS `fa_auth_rule`;
+CREATE TABLE `fa_auth_rule` (
+  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `type` enum('menu','file') NOT NULL DEFAULT 'file' COMMENT 'menu为菜单,file为权限节点',
+  `pid` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '父ID',
+  `name` varchar(100) NOT NULL DEFAULT '' COMMENT '规则名称',
+  `title` varchar(50) NOT NULL DEFAULT '' COMMENT '规则名称',
+  `icon` varchar(50) NOT NULL DEFAULT '' COMMENT '图标',
+  `condition` varchar(255) NOT NULL DEFAULT '' COMMENT '条件',
+  `remark` varchar(255) NOT NULL DEFAULT '' COMMENT '备注',
+  `ismenu` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '是否为菜单',
+  `createtime` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
+  `updatetime` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '更新时间',
+  `weigh` int(10) NOT NULL DEFAULT '0' COMMENT '权重',
+  `status` varchar(30) NOT NULL DEFAULT '' COMMENT '状态',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `name` (`name`) USING BTREE,
+  KEY `pid` (`pid`),
+  KEY `weigh` (`weigh`)
+) ENGINE=InnoDB AUTO_INCREMENT=66 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='节点表';
+
+-- ----------------------------
+-- Records of fa_auth_rule
+-- ----------------------------
+BEGIN;
+INSERT INTO `fa_auth_rule` VALUES (1, 'file', 0, 'dashboard', 'Dashboard', 'fa fa-dashboard', '', 'Dashboard tips', 1, 1497429920, 1497429920, 143, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (2, 'file', 0, 'general', 'General', 'fa fa-cogs', '', '', 1, 1497429920, 1497430169, 137, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (3, 'file', 0, 'category', 'Category', 'fa fa-list', '', 'Category tips', 1, 1497429920, 1497429920, 119, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (4, 'file', 0, 'addon', 'Addon', 'fa fa-rocket', '', 'Addon tips', 1, 1502035509, 1502035509, 0, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (5, 'file', 0, 'auth', 'Auth', 'fa fa-group', '', '', 1, 1497429920, 1497430092, 99, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (6, 'file', 2, 'general/config', 'Config', 'fa fa-cog', '', 'Config tips', 1, 1497429920, 1497430683, 60, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (7, 'file', 2, 'general/attachment', 'Attachment', 'fa fa-file-image-o', '', 'Attachment tips', 1, 1497429920, 1497430699, 53, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (8, 'file', 2, 'general/profile', 'Profile', 'fa fa-user', '', '', 1, 1497429920, 1497429920, 34, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (9, 'file', 5, 'auth/admin', 'Admin', 'fa fa-user', '', 'Admin tips', 1, 1497429920, 1497430320, 118, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (10, 'file', 5, 'auth/adminlog', 'Admin log', 'fa fa-list-alt', '', 'Admin log tips', 1, 1497429920, 1497430307, 113, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (11, 'file', 5, 'auth/group', 'Group', 'fa fa-group', '', 'Group tips', 1, 1497429920, 1497429920, 109, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (12, 'file', 5, 'auth/rule', 'Rule', 'fa fa-bars', '', 'Rule tips', 1, 1497429920, 1497430581, 104, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (13, 'file', 1, 'dashboard/index', 'View', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 136, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (14, 'file', 1, 'dashboard/add', 'Add', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 135, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (15, 'file', 1, 'dashboard/del', 'Delete', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 133, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (16, 'file', 1, 'dashboard/edit', 'Edit', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 134, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (17, 'file', 1, 'dashboard/multi', 'Multi', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 132, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (18, 'file', 6, 'general/config/index', 'View', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 52, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (19, 'file', 6, 'general/config/add', 'Add', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 51, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (20, 'file', 6, 'general/config/edit', 'Edit', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 50, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (21, 'file', 6, 'general/config/del', 'Delete', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 49, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (22, 'file', 6, 'general/config/multi', 'Multi', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 48, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (23, 'file', 7, 'general/attachment/index', 'View', 'fa fa-circle-o', '', 'Attachment tips', 0, 1497429920, 1497429920, 59, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (24, 'file', 7, 'general/attachment/select', 'Select attachment', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 58, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (25, 'file', 7, 'general/attachment/add', 'Add', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 57, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (26, 'file', 7, 'general/attachment/edit', 'Edit', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 56, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (27, 'file', 7, 'general/attachment/del', 'Delete', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 55, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (28, 'file', 7, 'general/attachment/multi', 'Multi', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 54, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (29, 'file', 8, 'general/profile/index', 'View', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 33, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (30, 'file', 8, 'general/profile/update', 'Update profile', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 32, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (31, 'file', 8, 'general/profile/add', 'Add', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 31, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (32, 'file', 8, 'general/profile/edit', 'Edit', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 30, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (33, 'file', 8, 'general/profile/del', 'Delete', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 29, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (34, 'file', 8, 'general/profile/multi', 'Multi', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 28, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (35, 'file', 3, 'category/index', 'View', 'fa fa-circle-o', '', 'Category tips', 0, 1497429920, 1497429920, 142, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (36, 'file', 3, 'category/add', 'Add', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 141, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (37, 'file', 3, 'category/edit', 'Edit', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 140, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (38, 'file', 3, 'category/del', 'Delete', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 139, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (39, 'file', 3, 'category/multi', 'Multi', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 138, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (40, 'file', 9, 'auth/admin/index', 'View', 'fa fa-circle-o', '', 'Admin tips', 0, 1497429920, 1497429920, 117, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (41, 'file', 9, 'auth/admin/add', 'Add', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 116, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (42, 'file', 9, 'auth/admin/edit', 'Edit', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 115, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (43, 'file', 9, 'auth/admin/del', 'Delete', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 114, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (44, 'file', 10, 'auth/adminlog/index', 'View', 'fa fa-circle-o', '', 'Admin log tips', 0, 1497429920, 1497429920, 112, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (45, 'file', 10, 'auth/adminlog/detail', 'Detail', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 111, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (46, 'file', 10, 'auth/adminlog/del', 'Delete', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 110, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (47, 'file', 11, 'auth/group/index', 'View', 'fa fa-circle-o', '', 'Group tips', 0, 1497429920, 1497429920, 108, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (48, 'file', 11, 'auth/group/add', 'Add', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 107, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (49, 'file', 11, 'auth/group/edit', 'Edit', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 106, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (50, 'file', 11, 'auth/group/del', 'Delete', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 105, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (51, 'file', 12, 'auth/rule/index', 'View', 'fa fa-circle-o', '', 'Rule tips', 0, 1497429920, 1497429920, 103, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (52, 'file', 12, 'auth/rule/add', 'Add', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 102, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (53, 'file', 12, 'auth/rule/edit', 'Edit', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 101, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (54, 'file', 12, 'auth/rule/del', 'Delete', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 100, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (55, 'file', 4, 'addon/index', 'View', 'fa fa-circle-o', '', 'Addon tips', 0, 1502035509, 1502035509, 0, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (56, 'file', 4, 'addon/add', 'Add', 'fa fa-circle-o', '', '', 0, 1502035509, 1502035509, 0, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (57, 'file', 4, 'addon/edit', 'Edit', 'fa fa-circle-o', '', '', 0, 1502035509, 1502035509, 0, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (58, 'file', 4, 'addon/del', 'Delete', 'fa fa-circle-o', '', '', 0, 1502035509, 1502035509, 0, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (59, 'file', 4, 'addon/local', 'Local install', 'fa fa-circle-o', '', '', 0, 1502035509, 1502035509, 0, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (60, 'file', 4, 'addon/state', 'Update state', 'fa fa-circle-o', '', '', 0, 1502035509, 1502035509, 0, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (61, 'file', 4, 'addon/install', 'Install', 'fa fa-circle-o', '', '', 0, 1502035509, 1502035509, 0, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (62, 'file', 4, 'addon/uninstall', 'Uninstall', 'fa fa-circle-o', '', '', 0, 1502035509, 1502035509, 0, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (63, 'file', 4, 'addon/config', 'Setting', 'fa fa-circle-o', '', '', 0, 1502035509, 1502035509, 0, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (64, 'file', 4, 'addon/refresh', 'Refresh', 'fa fa-circle-o', '', '', 0, 1502035509, 1502035509, 0, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (65, 'file', 4, 'addon/multi', 'Multi', 'fa fa-circle-o', '', '', 0, 1502035509, 1502035509, 0, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (66, 'file', 0, 'user', 'User', 'fa fa-list', '', '', 1, 1516374729, 1516374729, 0, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (67, 'file', 66, 'user/user', 'User', 'fa fa-user', '', '', 1, 1516374729, 1516374729, 0, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (68, 'file', 67, 'user/user/index', 'View', 'fa fa-circle-o', '', '', 0, 1516374729, 1516374729, 0, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (69, 'file', 67, 'user/user/edit', 'Edit', 'fa fa-circle-o', '', '', 0, 1516374729, 1516374729, 0, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (70, 'file', 67, 'user/user/add', 'Add', 'fa fa-circle-o', '', '', 0, 1516374729, 1516374729, 0, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (71, 'file', 67, 'user/user/del', 'Del', 'fa fa-circle-o', '', '', 0, 1516374729, 1516374729, 0, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (72, 'file', 67, 'user/user/multi', 'Multi', 'fa fa-circle-o', '', '', 0, 1516374729, 1516374729, 0, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (73, 'file', 66, 'user/group', 'User group', 'fa fa-users', '', '', 1, 1516374729, 1516374729, 0, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (74, 'file', 73, 'user/group/add', 'Add', 'fa fa-circle-o', '', '', 0, 1516374729, 1516374729, 0, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (75, 'file', 73, 'user/group/edit', 'Edit', 'fa fa-circle-o', '', '', 0, 1516374729, 1516374729, 0, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (76, 'file', 73, 'user/group/index', 'View', 'fa fa-circle-o', '', '', 0, 1516374729, 1516374729, 0, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (77, 'file', 73, 'user/group/del', 'Del', 'fa fa-circle-o', '', '', 0, 1516374729, 1516374729, 0, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (78, 'file', 73, 'user/group/multi', 'Multi', 'fa fa-circle-o', '', '', 0, 1516374729, 1516374729, 0, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (79, 'file', 66, 'user/rule', 'User rule', 'fa fa-circle-o', '', '', 1, 1516374729, 1516374729, 0, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (80, 'file', 79, 'user/rule/index', 'View', 'fa fa-circle-o', '', '', 0, 1516374729, 1516374729, 0, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (81, 'file', 79, 'user/rule/del', 'Del', 'fa fa-circle-o', '', '', 0, 1516374729, 1516374729, 0, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (82, 'file', 79, 'user/rule/add', 'Add', 'fa fa-circle-o', '', '', 0, 1516374729, 1516374729, 0, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (83, 'file', 79, 'user/rule/edit', 'Edit', 'fa fa-circle-o', '', '', 0, 1516374729, 1516374729, 0, 'normal');
+INSERT INTO `fa_auth_rule` VALUES (84, 'file', 79, 'user/rule/multi', 'Multi', 'fa fa-circle-o', '', '', 0, 1516374729, 1516374729, 0, 'normal');
+COMMIT;
+
+-- ----------------------------
+-- Table structure for fa_category
+-- ----------------------------
+DROP TABLE IF EXISTS `fa_category`;
+CREATE TABLE `fa_category` (
+  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `pid` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '父ID',
+  `type` varchar(30) NOT NULL DEFAULT '' COMMENT '栏目类型',
+  `name` varchar(30) NOT NULL DEFAULT '',
+  `nickname` varchar(50) NOT NULL DEFAULT '',
+  `flag` set('hot','index','recommend') NOT NULL DEFAULT '',
+  `image` varchar(100) NOT NULL DEFAULT '' COMMENT '图片',
+  `keywords` varchar(255) NOT NULL DEFAULT '' COMMENT '关键字',
+  `description` varchar(255) NOT NULL DEFAULT '' COMMENT '描述',
+  `diyname` varchar(30) NOT NULL DEFAULT '' COMMENT '自定义名称',
+  `createtime` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
+  `updatetime` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '更新时间',
+  `weigh` int(10) NOT NULL DEFAULT '0' COMMENT '权重',
+  `status` varchar(30) NOT NULL DEFAULT '' COMMENT '状态',
+  PRIMARY KEY (`id`),
+  KEY `weigh` (`weigh`,`id`),
+  KEY `pid` (`pid`)
+) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='分类表';
+
+-- ----------------------------
+-- Records of fa_category
+-- ----------------------------
+BEGIN;
+INSERT INTO `fa_category` VALUES (1, 0, 'page', '官方新闻', 'news', 'recommend', '/assets/img/qrcode.png', '', '', 'news', 1495262190, 1495262190, 1, 'normal');
+INSERT INTO `fa_category` VALUES (2, 0, 'page', '移动应用', 'mobileapp', 'hot', '/assets/img/qrcode.png', '', '', 'mobileapp', 1495262244, 1495262244, 2, 'normal');
+INSERT INTO `fa_category` VALUES (3, 2, 'page', '微信公众号', 'wechatpublic', 'index', '/assets/img/qrcode.png', '', '', 'wechatpublic', 1495262288, 1495262288, 3, 'normal');
+INSERT INTO `fa_category` VALUES (4, 2, 'page', 'Android开发', 'android', 'recommend', '/assets/img/qrcode.png', '', '', 'android', 1495262317, 1495262317, 4, 'normal');
+INSERT INTO `fa_category` VALUES (5, 0, 'page', '软件产品', 'software', 'recommend', '/assets/img/qrcode.png', '', '', 'software', 1495262336, 1499681850, 5, 'normal');
+INSERT INTO `fa_category` VALUES (6, 5, 'page', '网站建站', 'website', 'recommend', '/assets/img/qrcode.png', '', '', 'website', 1495262357, 1495262357, 6, 'normal');
+INSERT INTO `fa_category` VALUES (7, 5, 'page', '企业管理软件', 'company', 'index', '/assets/img/qrcode.png', '', '', 'company', 1495262391, 1495262391, 7, 'normal');
+INSERT INTO `fa_category` VALUES (8, 6, 'page', 'PC端', 'website-pc', 'recommend', '/assets/img/qrcode.png', '', '', 'website-pc', 1495262424, 1495262424, 8, 'normal');
+INSERT INTO `fa_category` VALUES (9, 6, 'page', '移动端', 'website-mobile', 'recommend', '/assets/img/qrcode.png', '', '', 'website-mobile', 1495262456, 1495262456, 9, 'normal');
+INSERT INTO `fa_category` VALUES (10, 7, 'page', 'CRM系统 ', 'company-crm', 'recommend', '/assets/img/qrcode.png', '', '', 'company-crm', 1495262487, 1495262487, 10, 'normal');
+INSERT INTO `fa_category` VALUES (11, 7, 'page', 'SASS平台软件', 'company-sass', 'recommend', '/assets/img/qrcode.png', '', '', 'company-sass', 1495262515, 1495262515, 11, 'normal');
+INSERT INTO `fa_category` VALUES (12, 0, 'test', '测试1', 'test1', 'recommend', '/assets/img/qrcode.png', '', '', 'test1', 1497015727, 1497015727, 12, 'normal');
+INSERT INTO `fa_category` VALUES (13, 0, 'test', '测试2', 'test2', 'recommend', '/assets/img/qrcode.png', '', '', 'test2', 1497015738, 1497015738, 13, 'normal');
+COMMIT;
+
+-- ----------------------------
+-- Table structure for fa_config
+-- ----------------------------
+DROP TABLE IF EXISTS `fa_config`;
+CREATE TABLE `fa_config` (
+  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `name` varchar(30) NOT NULL DEFAULT '' COMMENT '变量名',
+  `group` varchar(30) NOT NULL DEFAULT '' COMMENT '分组',
+  `title` varchar(100) NOT NULL DEFAULT '' COMMENT '变量标题',
+  `tip` varchar(100) NOT NULL DEFAULT '' COMMENT '变量描述',
+  `type` varchar(30) NOT NULL DEFAULT '' COMMENT '类型:string,text,int,bool,array,datetime,date,file',
+  `value` text NOT NULL COMMENT '变量值',
+  `content` text NOT NULL COMMENT '变量字典数据',
+  `rule` varchar(100) NOT NULL DEFAULT '' COMMENT '验证规则',
+  `extend` varchar(255) NOT NULL DEFAULT '' COMMENT '扩展属性',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `name` (`name`)
+) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='系统配置';
+
+-- ----------------------------
+-- Records of fa_config
+-- ----------------------------
+BEGIN;
+INSERT INTO `fa_config` VALUES (1, 'name', 'basic', 'Site name', '请填写站点名称', 'string', 'FastAdmin', '', 'required', '');
+INSERT INTO `fa_config` VALUES (2, 'beian', 'basic', 'Beian', '粤ICP备15054802号-4', 'string', '', '', '', '');
+INSERT INTO `fa_config` VALUES (3, 'cdnurl', 'basic', 'Cdn url', '如果静态资源使用第三方云储存请配置该值', 'string', '', '', '', '');
+INSERT INTO `fa_config` VALUES (4, 'version', 'basic', 'Version', '如果静态资源有变动请重新配置该值', 'string', '1.0.1', '', 'required', '');
+INSERT INTO `fa_config` VALUES (5, 'timezone', 'basic', 'Timezone', '', 'string', 'Asia/Shanghai', '', 'required', '');
+INSERT INTO `fa_config` VALUES (6, 'forbiddenip', 'basic', 'Forbidden ip', '一行一条记录', 'text', '', '', '', '');
+INSERT INTO `fa_config` VALUES (7, 'languages', 'basic', 'Languages', '', 'array', '{\"backend\":\"zh-cn\",\"frontend\":\"zh-cn\"}', '', 'required', '');
+INSERT INTO `fa_config` VALUES (8, 'fixedpage', 'basic', 'Fixed page', '请尽量输入左侧菜单栏存在的链接', 'string', 'dashboard', '', 'required', '');
+INSERT INTO `fa_config` VALUES (9, 'categorytype', 'dictionary', 'Category type', '', 'array', '{\"default\":\"Default\",\"page\":\"Page\",\"article\":\"Article\",\"test\":\"Test\"}', '', '', '');
+INSERT INTO `fa_config` VALUES (10, 'configgroup', 'dictionary', 'Config group', '', 'array', '{\"basic\":\"Basic\",\"email\":\"Email\",\"dictionary\":\"Dictionary\",\"user\":\"User\",\"example\":\"Example\"}', '', '', '');
+INSERT INTO `fa_config` VALUES (11, 'mail_type', 'email', 'Mail type', '选择邮件发送方式', 'select', '1', '[\"Please select\",\"SMTP\",\"Mail\"]', '', '');
+INSERT INTO `fa_config` VALUES (12, 'mail_smtp_host', 'email', 'Mail smtp host', '错误的配置发送邮件会导致服务器超时', 'string', 'smtp.qq.com', '', '', '');
+INSERT INTO `fa_config` VALUES (13, 'mail_smtp_port', 'email', 'Mail smtp port', '(不加密默认25,SSL默认465,TLS默认587)', 'string', '465', '', '', '');
+INSERT INTO `fa_config` VALUES (14, 'mail_smtp_user', 'email', 'Mail smtp user', '(填写完整用户名)', 'string', '10000', '', '', '');
+INSERT INTO `fa_config` VALUES (15, 'mail_smtp_pass', 'email', 'Mail smtp password', '(填写您的密码)', 'string', 'password', '', '', '');
+INSERT INTO `fa_config` VALUES (16, 'mail_verify_type', 'email', 'Mail vertify type', '(SMTP验证方式[推荐SSL])', 'select', '2', '[\"None\",\"TLS\",\"SSL\"]', '', '');
+INSERT INTO `fa_config` VALUES (17, 'mail_from', 'email', 'Mail from', '', 'string', '10000@qq.com', '', '', '');
+COMMIT;
+
+-- ----------------------------
+-- Table structure for fa_ems
+-- ----------------------------
+DROP TABLE IF EXISTS `fa_ems`;
+CREATE TABLE `fa_ems`  (
+  `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'ID',
+  `event` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '事件',
+  `email` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '邮箱',
+  `code` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '验证码',
+  `times` int(10) UNSIGNED NOT NULL DEFAULT 0 COMMENT '验证次数',
+  `ip` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT 'IP',
+  `createtime` int(10) UNSIGNED NULL DEFAULT 0 COMMENT '创建时间',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='邮箱验证码表';
+
+-- ----------------------------
+-- Table structure for fa_sms
+-- ----------------------------
+DROP TABLE IF EXISTS `fa_sms`;
+CREATE TABLE `fa_sms` (
+  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
+  `event` varchar(30) NOT NULL DEFAULT '' COMMENT '事件',
+  `mobile` varchar(20) NOT NULL DEFAULT '' COMMENT '手机号',
+  `code` varchar(10) NOT NULL DEFAULT '' COMMENT '验证码',
+  `times` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '验证次数',
+  `ip` varchar(30) NOT NULL DEFAULT '' COMMENT 'IP',
+  `createtime` int(10) unsigned DEFAULT '0' COMMENT '创建时间',
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='短信验证码表';
+
+-- ----------------------------
+-- Table structure for fa_test
+-- ----------------------------
+DROP TABLE IF EXISTS `fa_test`;
+CREATE TABLE `fa_test` (
+  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
+  `admin_id` int(10) NOT NULL DEFAULT '0' COMMENT '管理员ID',
+  `category_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '分类ID(单选)',
+  `category_ids` varchar(100) NOT NULL COMMENT '分类ID(多选)',
+  `week` enum('monday','tuesday','wednesday') NOT NULL COMMENT '星期(单选):monday=星期一,tuesday=星期二,wednesday=星期三',
+  `flag` set('hot','index','recommend') NOT NULL DEFAULT '' COMMENT '标志(多选):hot=热门,index=首页,recommend=推荐',
+  `genderdata` enum('male','female') NOT NULL DEFAULT 'male' COMMENT '性别(单选):male=男,female=女',
+  `hobbydata` set('music','reading','swimming') NOT NULL COMMENT '爱好(多选):music=音乐,reading=读书,swimming=游泳',
+  `title` varchar(50) NOT NULL DEFAULT '' COMMENT '标题',
+  `content` text NOT NULL COMMENT '内容',
+  `image` varchar(100) NOT NULL DEFAULT '' COMMENT '图片',
+  `images` varchar(1500) NOT NULL DEFAULT '' COMMENT '图片组',
+  `attachfile` varchar(100) NOT NULL DEFAULT '' COMMENT '附件',
+  `keywords` varchar(100) NOT NULL DEFAULT '' COMMENT '关键字',
+  `description` varchar(255) NOT NULL DEFAULT '' COMMENT '描述',
+  `city` varchar(100) NOT NULL DEFAULT '' COMMENT '省市',
+  `price` float(10,2) unsigned NOT NULL DEFAULT '0.00' COMMENT '价格',
+  `views` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '点击',
+  `startdate` date DEFAULT NULL COMMENT '开始日期',
+  `activitytime` datetime DEFAULT NULL COMMENT '活动时间(datetime)',
+  `year` year(4) DEFAULT NULL COMMENT '年',
+  `times` time DEFAULT NULL COMMENT '时间',
+  `refreshtime` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '刷新时间(int)',
+  `createtime` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
+  `updatetime` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '更新时间',
+  `weigh` int(10) NOT NULL DEFAULT '0' COMMENT '权重',
+  `switch` tinyint(1) NOT NULL DEFAULT '0' COMMENT '开关',
+  `status` enum('normal','hidden') NOT NULL DEFAULT 'normal' COMMENT '状态',
+  `state` enum('0','1','2') NOT NULL DEFAULT '1' COMMENT '状态值:0=禁用,1=正常,2=推荐',
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='测试表';
+
+-- ----------------------------
+-- Records of fa_test
+-- ----------------------------
+BEGIN;
+INSERT INTO `fa_test` VALUES (1, 0, 12, '12,13', 'monday', 'hot,index', 'male', 'music,reading', '我是一篇测试文章', '<p>我是测试内容</p>', '/assets/img/avatar.png', '/assets/img/avatar.png,/assets/img/qrcode.png', '/assets/img/avatar.png', '关键字', '描述', '广西壮族自治区/百色市/平果县', 0.00, 0, '2017-07-10', '2017-07-10 18:24:45', 2017, '18:24:45', 1499682285, 1499682526, 1499682526, 0, 1, 'normal', '1');
+COMMIT;
+
+-- ----------------------------
+-- Table structure for fa_user
+-- ----------------------------
+DROP TABLE IF EXISTS `fa_user`;
+CREATE TABLE `fa_user` (
+  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
+  `group_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '组别ID',
+  `username` varchar(32) NOT NULL DEFAULT '' COMMENT '用户名',
+  `nickname` varchar(50) NOT NULL DEFAULT '' COMMENT '昵称',
+  `password` varchar(32) NOT NULL DEFAULT '' COMMENT '密码',
+  `salt` varchar(30) NOT NULL DEFAULT '' COMMENT '密码盐',
+  `email` varchar(100) NOT NULL DEFAULT '' COMMENT '电子邮箱',
+  `mobile` varchar(11) NOT NULL DEFAULT '' COMMENT '手机号',
+  `avatar` varchar(255) NOT NULL DEFAULT '' COMMENT '头像',
+  `level` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '等级',
+  `gender` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '性别',
+  `birthday` date COMMENT '生日',
+  `bio` varchar(100) NOT NULL DEFAULT '' COMMENT '格言',
+  `money` decimal(10,2) unsigned NOT NULL DEFAULT '0.00' COMMENT '余额',
+  `score` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '积分',
+  `successions` int(10) unsigned NOT NULL DEFAULT '1' COMMENT '连续登录天数',
+  `maxsuccessions` int(10) unsigned NOT NULL DEFAULT '1' COMMENT '最大连续登录天数',
+  `prevtime` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '上次登录时间',
+  `logintime` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '登录时间',
+  `loginip` varchar(50) NOT NULL DEFAULT '' COMMENT '登录IP',
+  `loginfailure` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '失败次数',
+  `joinip` varchar(50) NOT NULL DEFAULT '' COMMENT '加入IP',
+  `jointime` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '加入时间',
+  `createtime` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
+  `updatetime` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '更新时间',
+  `token` varchar(50) NOT NULL DEFAULT '' COMMENT 'Token',
+  `status` varchar(30) NOT NULL DEFAULT '' COMMENT '状态',
+  `verification` varchar(255) NOT NULL DEFAULT '' COMMENT '验证',
+  PRIMARY KEY (`id`),
+  KEY `username` (`username`),
+  KEY `email` (`email`),
+  KEY `mobile` (`mobile`)
+) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='会员表';
+
+-- ----------------------------
+-- Records of fa_user
+-- ----------------------------
+BEGIN;
+INSERT INTO `fa_user` VALUES (1, 1, 'admin', 'admin', 'c13f62012fd6a8fdf06b3452a94430e5', 'rpR6Bv', 'admin@163.com', '13888888888', '/assets/img/avatar.png', 0, 0, '2017-04-15', '', 0, 0, 1, 1, 1516170492, 1516171614, '127.0.0.1', 0, '127.0.0.1', 1491461418, 0, 1516171614, '', 'normal','');
+COMMIT;
+
+-- ----------------------------
+-- Table structure for fa_user_group
+-- ----------------------------
+DROP TABLE IF EXISTS `fa_user_group`;
+CREATE TABLE `fa_user_group` (
+  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `name` varchar(50) DEFAULT '' COMMENT '组名',
+  `rules` text COMMENT '权限节点',
+  `createtime` int(10) DEFAULT NULL COMMENT '添加时间',
+  `updatetime` int(10) DEFAULT NULL COMMENT '更新时间',
+  `status` enum('normal','hidden') DEFAULT NULL COMMENT '状态',
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='会员组表';
+
+-- ----------------------------
+-- Records of fa_user_group
+-- ----------------------------
+BEGIN;
+INSERT INTO `fa_user_group` VALUES (1, '默认组', '1,2,3,4,5,6,7,8,9,10,11,12', 1515386468, 1516168298, 'normal');
+COMMIT;
+
+-- ----------------------------
+-- Table structure for fa_user_money_log
+-- ----------------------------
+DROP TABLE IF EXISTS `fa_user_money_log`;
+CREATE TABLE `fa_user_money_log` (
+  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `user_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '会员ID',
+  `money` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '变更余额',
+  `before` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '变更前余额',
+  `after` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '变更后余额',
+  `memo` varchar(255) NOT NULL DEFAULT '' COMMENT '备注',
+  `createtime` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='会员余额变动表';
+
+-- ----------------------------
+-- Table structure for fa_user_rule
+-- ----------------------------
+DROP TABLE IF EXISTS `fa_user_rule`;
+CREATE TABLE `fa_user_rule` (
+  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `pid` int(10) DEFAULT NULL COMMENT '父ID',
+  `name` varchar(50) DEFAULT NULL COMMENT '名称',
+  `title` varchar(50) DEFAULT '' COMMENT '标题',
+  `remark` varchar(100) DEFAULT NULL COMMENT '备注',
+  `ismenu` tinyint(1) DEFAULT NULL COMMENT '是否菜单',
+  `createtime` int(10) DEFAULT NULL COMMENT '创建时间',
+  `updatetime` int(10) DEFAULT NULL COMMENT '更新时间',
+  `weigh` int(10) DEFAULT '0' COMMENT '权重',
+  `status` enum('normal','hidden') DEFAULT NULL COMMENT '状态',
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='会员规则表';
+
+-- ----------------------------
+-- Records of fa_user_rule
+-- ----------------------------
+BEGIN;
+INSERT INTO `fa_user_rule` VALUES (1, 0, 'index', '前台', '', 1, 1516168079, 1516168079, 1, 'normal');
+INSERT INTO `fa_user_rule` VALUES (2, 0, 'api', 'API接口', '', 1, 1516168062, 1516168062, 2, 'normal');
+INSERT INTO `fa_user_rule` VALUES (3, 1, 'user', '会员模块', '', 1, 1515386221, 1516168103, 12, 'normal');
+INSERT INTO `fa_user_rule` VALUES (4, 2, 'user', '会员模块', '', 1, 1515386221, 1516168092, 11, 'normal');
+INSERT INTO `fa_user_rule` VALUES (5, 3, 'index/user/login', '登录', '', 0, 1515386247, 1515386247, 5, 'normal');
+INSERT INTO `fa_user_rule` VALUES (6, 3, 'index/user/register', '注册', '', 0, 1515386262, 1516015236, 7, 'normal');
+INSERT INTO `fa_user_rule` VALUES (7, 3, 'index/user/index', '会员中心', '', 0, 1516015012, 1516015012, 9, 'normal');
+INSERT INTO `fa_user_rule` VALUES (8, 3, 'index/user/profile', '个人资料', '', 0, 1516015012, 1516015012, 4, 'normal');
+INSERT INTO `fa_user_rule` VALUES (9, 4, 'api/user/login', '登录', '', 0, 1515386247, 1515386247, 6, 'normal');
+INSERT INTO `fa_user_rule` VALUES (10, 4, 'api/user/register', '注册', '', 0, 1515386262, 1516015236, 8, 'normal');
+INSERT INTO `fa_user_rule` VALUES (11, 4, 'api/user/index', '会员中心', '', 0, 1516015012, 1516015012, 10, 'normal');
+INSERT INTO `fa_user_rule` VALUES (12, 4, 'api/user/profile', '个人资料', '', 0, 1516015012, 1516015012, 3, 'normal');
+COMMIT;
+
+-- ----------------------------
+-- Table structure for fa_user_score_log
+-- ----------------------------
+DROP TABLE IF EXISTS `fa_user_score_log`;
+CREATE TABLE `fa_user_score_log` (
+  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `user_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '会员ID',
+  `score` int(10) NOT NULL DEFAULT '0' COMMENT '变更积分',
+  `before` int(10) NOT NULL DEFAULT '0' COMMENT '变更前积分',
+  `after` int(10) NOT NULL DEFAULT '0' COMMENT '变更后积分',
+  `memo` varchar(255) NOT NULL DEFAULT '' COMMENT '备注',
+  `createtime` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='会员积分变动表';
+
+-- ----------------------------
+-- Table structure for fa_user_token
+-- ----------------------------
+DROP TABLE IF EXISTS `fa_user_token`;
+CREATE TABLE `fa_user_token` (
+  `token` varchar(50) NOT NULL COMMENT 'Token',
+  `user_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '会员ID',
+  `createtime` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
+  `expiretime` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '过期时间',
+  PRIMARY KEY (`token`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='会员Token表';
+
+-- ----------------------------
+-- Table structure for fa_version
+-- ----------------------------
+DROP TABLE IF EXISTS `fa_version`;
+CREATE TABLE `fa_version`  (
+  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',
+  `oldversion` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '旧版本号',
+  `newversion` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '新版本号',
+  `packagesize` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '包大小',
+  `content` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '升级内容',
+  `downloadurl` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '下载地址',
+  `enforce` tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT '强制更新',
+  `createtime` int(10) NOT NULL DEFAULT 0 COMMENT '创建时间',
+  `updatetime` int(10) UNSIGNED NOT NULL DEFAULT 0 COMMENT '更新时间',
+  `weigh` int(10) NOT NULL DEFAULT 0 COMMENT '权重',
+  `status` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '状态',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 1 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT = '版本表';
+
+-- ----------------------------
+-- Table structure for fa_version
+-- ----------------------------
+BEGIN;
+INSERT INTO `fa_version` (`id`, `oldversion`, `newversion`, `packagesize`, `content`, `downloadurl`, `enforce`, `createtime`, `updatetime`, `weigh`, `status`) VALUES
+(1, '1.1.1,2', '1.2.1', '20M', '更新内容', 'https://www.fastadmin.net/download.html', 1, 1520425318, 0, 0, 'normal');
+COMMIT;
+SET FOREIGN_KEY_CHECKS = 1;

+ 1 - 0
application/admin/command/Install/install.lock

@@ -0,0 +1 @@
+1

+ 289 - 0
application/admin/command/Menu.php

@@ -0,0 +1,289 @@
+<?php
+
+namespace app\admin\command;
+
+use app\admin\model\AuthRule;
+use ReflectionClass;
+use ReflectionMethod;
+use think\Cache;
+use think\Config;
+use think\console\Command;
+use think\console\Input;
+use think\console\input\Option;
+use think\console\Output;
+use think\Exception;
+
+class Menu extends Command
+{
+
+    protected $model = null;
+
+    protected function configure()
+    {
+        $this
+            ->setName('menu')
+            ->addOption('controller', 'c', Option::VALUE_REQUIRED | Option::VALUE_IS_ARRAY, 'controller name,use \'all-controller\' when build all menu', null)
+            ->addOption('delete', 'd', Option::VALUE_OPTIONAL, 'delete the specified menu', '')
+            ->addOption('force', 'f', Option::VALUE_OPTIONAL, 'force delete menu,without tips', null)
+            ->addOption('equal', 'e', Option::VALUE_OPTIONAL, 'the controller must be equal', null)
+            ->setDescription('Build auth menu from controller');
+        //要执行的controller必须一样,不适用模糊查询
+    }
+
+    protected function execute(Input $input, Output $output)
+    {
+
+        $this->model = new AuthRule();
+        $adminPath = dirname(__DIR__) . DS;
+        //控制器名
+        $controller = $input->getOption('controller') ?: '';
+        if (!$controller) {
+            throw new Exception("please input controller name");
+        }
+        $force = $input->getOption('force');
+        //是否为删除模式
+        $delete = $input->getOption('delete');
+        //是否控制器完全匹配
+        $equal = $input->getOption('equal');
+
+
+        if ($delete) {
+            if (in_array('all-controller', $controller)) {
+                throw new Exception("could not delete all menu");
+            }
+            $ids = [];
+            $list = $this->model->where(function ($query) use ($controller, $equal) {
+                foreach ($controller as $index => $item) {
+                    if ($equal)
+                        $query->whereOr('name', 'eq', $item);
+                    else
+                        $query->whereOr('name', 'like', strtolower($item) . "%");
+                }
+            })->select();
+            foreach ($list as $k => $v) {
+                $output->warning($v->name);
+                $ids[] = $v->id;
+            }
+            if (!$ids) {
+                throw new Exception("There is no menu to delete");
+            }
+            if (!$force) {
+                $output->info("Are you sure you want to delete all those menu?  Type 'yes' to continue: ");
+                $line = fgets(STDIN);
+                if (trim($line) != 'yes') {
+                    throw new Exception("Operation is aborted!");
+                }
+            }
+            AuthRule::destroy($ids);
+
+            Cache::rm("__menu__");
+            $output->info("Delete Successed");
+            return;
+        }
+
+        if (!in_array('all-controller', $controller)) {
+            foreach ($controller as $index => $item) {
+                $controllerArr = explode('/', $item);
+                end($controllerArr);
+                $key = key($controllerArr);
+                $controllerArr[$key] = ucfirst($controllerArr[$key]);
+                $adminPath = dirname(__DIR__) . DS . 'controller' . DS . implode(DS, $controllerArr) . '.php';
+                if (!is_file($adminPath)) {
+                    $output->error("controller not found");
+                    return;
+                }
+                $this->importRule($item);
+            }
+
+        } else {
+            $this->model->where('id', '>', 0)->delete();
+            $controllerDir = $adminPath . 'controller' . DS;
+            // 扫描新的节点信息并导入
+            $treelist = $this->import($this->scandir($controllerDir));
+        }
+        Cache::rm("__menu__");
+        $output->info("Build Successed!");
+    }
+
+    /**
+     * 递归扫描文件夹
+     * @param string $dir
+     * @return array
+     */
+    public function scandir($dir)
+    {
+        $result = [];
+        $cdir = scandir($dir);
+        foreach ($cdir as $value) {
+            if (!in_array($value, array(".", ".."))) {
+                if (is_dir($dir . DS . $value)) {
+                    $result[$value] = $this->scandir($dir . DS . $value);
+                } else {
+                    $result[] = $value;
+                }
+            }
+        }
+        return $result;
+    }
+
+    /**
+     * 导入规则节点
+     * @param array $dirarr
+     * @param array $parentdir
+     * @return array
+     */
+    public function import($dirarr, $parentdir = [])
+    {
+        $menuarr = [];
+        foreach ($dirarr as $k => $v) {
+            if (is_array($v)) {
+                //当前是文件夹
+                $nowparentdir = array_merge($parentdir, [$k]);
+                $this->import($v, $nowparentdir);
+            } else {
+                //只匹配PHP文件
+                if (!preg_match('/^(\w+)\.php$/', $v, $matchone)) {
+                    continue;
+                }
+                //导入文件
+                $controller = ($parentdir ? implode('/', $parentdir) . '/' : '') . $matchone[1];
+                $this->importRule($controller);
+            }
+        }
+
+        return $menuarr;
+    }
+
+    protected function importRule($controller)
+    {
+        $controller = str_replace('\\', '/', $controller);
+        $controllerArr = explode('/', $controller);
+        end($controllerArr);
+        $key = key($controllerArr);
+        $controllerArr[$key] = ucfirst($controllerArr[$key]);
+        $classSuffix = Config::get('controller_suffix') ? ucfirst(Config::get('url_controller_layer')) : '';
+        $className = "\\app\\admin\\controller\\" . implode("\\", $controllerArr) . $classSuffix;
+
+        $pathArr = $controllerArr;
+        array_unshift($pathArr, '', 'application', 'admin', 'controller');
+        $classFile = ROOT_PATH . implode(DS, $pathArr) . $classSuffix . ".php";
+        $classContent = file_get_contents($classFile);
+        $uniqueName = uniqid("FastAdmin") . $classSuffix;
+        $classContent = str_replace("class " . $controllerArr[$key] . $classSuffix . " ", 'class ' . $uniqueName . ' ', $classContent);
+        $classContent = preg_replace("/namespace\s(.*);/", 'namespace ' . __NAMESPACE__ . ";", $classContent);
+
+        //临时的类文件
+        $tempClassFile = __DIR__ . DS . $uniqueName . ".php";
+        file_put_contents($tempClassFile, $classContent);
+        $className = "\\app\\admin\\command\\" . $uniqueName;
+        //反射机制调用类的注释和方法名
+        $reflector = new ReflectionClass($className);
+
+        if (isset($tempClassFile)) {
+            //删除临时文件
+            @unlink($tempClassFile);
+        }
+
+        //只匹配公共的方法
+        $methods = $reflector->getMethods(ReflectionMethod::IS_PUBLIC);
+        $classComment = $reflector->getDocComment();
+        //判断是否有启用软删除
+        $softDeleteMethods = ['destroy', 'restore', 'recyclebin'];
+        $withSofeDelete = false;
+        preg_match_all("/\\\$this\->model\s*=\s*model\('(\w+)'\);/", $classContent, $matches);
+        if (isset($matches[1]) && isset($matches[1][0]) && $matches[1][0]) {
+            \think\Request::instance()->module('admin');
+            $model = model($matches[1][0]);
+            if (in_array('trashed', get_class_methods($model))) {
+                $withSofeDelete = true;
+            }
+        }
+        //忽略的类
+        if (stripos($classComment, "@internal") !== FALSE) {
+            return;
+        }
+        preg_match_all('#(@.*?)\n#s', $classComment, $annotations);
+        $controllerIcon = 'fa fa-circle-o';
+        $controllerRemark = '';
+        //判断注释中是否设置了icon值
+        if (isset($annotations[1])) {
+            foreach ($annotations[1] as $tag) {
+                if (stripos($tag, '@icon') !== FALSE) {
+                    $controllerIcon = substr($tag, stripos($tag, ' ') + 1);
+                }
+                if (stripos($tag, '@remark') !== FALSE) {
+                    $controllerRemark = substr($tag, stripos($tag, ' ') + 1);
+                }
+            }
+        }
+        //过滤掉其它字符
+        $controllerTitle = trim(preg_replace(array('/^\/\*\*(.*)[\n\r\t]/u', '/[\s]+\*\//u', '/\*\s@(.*)/u', '/[\s|\*]+/u'), '', $classComment));
+
+        //导入中文语言包
+        \think\Lang::load(dirname(__DIR__) . DS . 'lang/zh-cn.php');
+
+        //先导入菜单的数据
+        $pid = 0;
+        foreach ($controllerArr as $k => $v) {
+            $key = $k + 1;
+            $name = strtolower(implode('/', array_slice($controllerArr, 0, $key)));
+            $title = (!isset($controllerArr[$key]) ? $controllerTitle : '');
+            $icon = (!isset($controllerArr[$key]) ? $controllerIcon : 'fa fa-list');
+            $remark = (!isset($controllerArr[$key]) ? $controllerRemark : '');
+            $title = $title ? $title : $v;
+            $rulemodel = $this->model->get(['name' => $name]);
+            if (!$rulemodel) {
+                $this->model
+                    ->data(['pid' => $pid, 'name' => $name, 'title' => $title, 'icon' => $icon, 'remark' => $remark, 'ismenu' => 1, 'status' => 'normal'])
+                    ->isUpdate(false)
+                    ->save();
+                $pid = $this->model->id;
+            } else {
+                $pid = $rulemodel->id;
+            }
+        }
+        $ruleArr = [];
+        foreach ($methods as $m => $n) {
+            //过滤特殊的类
+            if (substr($n->name, 0, 2) == '__' || $n->name == '_initialize') {
+                continue;
+            }
+            //未启用软删除时过滤相关方法
+            if (!$withSofeDelete && in_array($n->name, $softDeleteMethods)) {
+                continue;
+            }
+            //只匹配符合的方法
+            if (!preg_match('/^(\w+)' . Config::get('action_suffix') . '/', $n->name, $matchtwo)) {
+                unset($methods[$m]);
+                continue;
+            }
+            $comment = $reflector->getMethod($n->name)->getDocComment();
+            //忽略的方法
+            if (stripos($comment, "@internal") !== FALSE) {
+                continue;
+            }
+            //过滤掉其它字符
+            $comment = preg_replace(array('/^\/\*\*(.*)[\n\r\t]/u', '/[\s]+\*\//u', '/\*\s@(.*)/u', '/[\s|\*]+/u'), '', $comment);
+
+            $title = $comment ? $comment : ucfirst($n->name);
+
+            //获取主键,作为AuthRule更新依据
+            $id = $this->getAuthRulePK($name . "/" . strtolower($n->name));
+
+            $ruleArr[] = array('id' => $id, 'pid' => $pid, 'name' => $name . "/" . strtolower($n->name), 'icon' => 'fa fa-circle-o', 'title' => $title, 'ismenu' => 0, 'status' => 'normal');
+        }
+        $this->model->isUpdate(false)->saveAll($ruleArr);
+    }
+
+    //获取主键
+    protected function getAuthRulePK($name)
+    {
+        if (!empty($name)) {
+            $id = $this->model
+                ->where('name', $name)
+                ->value('id');
+            return $id ? $id : null;
+        }
+    }
+
+}

+ 182 - 0
application/admin/command/Min.php

@@ -0,0 +1,182 @@
+<?php
+
+namespace app\admin\command;
+
+use think\console\Command;
+use think\console\Input;
+use think\console\input\Option;
+use think\console\Output;
+use think\Exception;
+
+class Min extends Command
+{
+
+    /**
+     * 路径和文件名配置
+     */
+    protected $options = [
+        'cssBaseUrl'  => 'public/assets/css/',
+        'cssBaseName' => '{module}',
+        'jsBaseUrl'   => 'public/assets/js/',
+        'jsBaseName'  => 'require-{module}',
+    ];
+
+    protected function configure()
+    {
+        $this
+                ->setName('min')
+                ->addOption('module', 'm', Option::VALUE_REQUIRED, 'module name(frontend or backend),use \'all\' when build all modules', null)
+                ->addOption('resource', 'r', Option::VALUE_REQUIRED, 'resource name(js or css),use \'all\' when build all resources', null)
+                ->addOption('optimize', 'o', Option::VALUE_OPTIONAL, 'optimize type(uglify|closure|none)', 'none')
+                ->setDescription('Compress js and css file');
+    }
+
+    protected function execute(Input $input, Output $output)
+    {
+        $module = $input->getOption('module') ?: '';
+        $resource = $input->getOption('resource') ?: '';
+        $optimize = $input->getOption('optimize') ?: 'none';
+
+        if (!$module || !in_array($module, ['frontend', 'backend', 'all']))
+        {
+            throw new Exception('Please input correct module name');
+        }
+        if (!$resource || !in_array($resource, ['js', 'css', 'all']))
+        {
+            throw new Exception('Please input correct resource name');
+        }
+
+        $moduleArr = $module == 'all' ? ['frontend', 'backend'] : [$module];
+        $resourceArr = $resource == 'all' ? ['js', 'css'] : [$resource];
+
+        $minPath = __DIR__ . DS . 'Min' . DS;
+        $publicPath = ROOT_PATH . 'public' . DS;
+        $tempFile = $minPath . 'temp.js';
+
+        $nodeExec = '';
+
+        if (!$nodeExec)
+        {
+            if (IS_WIN)
+            {
+                // Winsows下请手动配置配置该值,一般将该值配置为 '"C:\Program Files\nodejs\node.exe"',除非你的Node安装路径有变更
+                $nodeExec = 'C:\Program Files\nodejs\node.exe';
+                if (file_exists($nodeExec)){
+                    $nodeExec = '"' . $nodeExec . '"';
+                }else{
+                    // 如果 '"C:\Program Files\nodejs\node.exe"' 不存在,可能是node安装路径有变更
+                    // 但安装node会自动配置环境变量,直接执行 '"node.exe"' 提高第一次使用压缩打包的成功率
+                    $nodeExec = '"node.exe"';
+                }
+            }
+            else
+            {
+                try
+                {
+                    $nodeExec = exec("which node");
+                    if (!$nodeExec)
+                    {
+                        throw new Exception("node environment not found!please install node first!");
+                    }
+                }
+                catch (Exception $e)
+                {
+                    throw new Exception($e->getMessage());
+                }
+            }
+        }
+
+        foreach ($moduleArr as $mod)
+        {
+            foreach ($resourceArr as $res)
+            {
+                $data = [
+                    'publicPath'  => $publicPath,
+                    'jsBaseName'  => str_replace('{module}', $mod, $this->options['jsBaseName']),
+                    'jsBaseUrl'   => $this->options['jsBaseUrl'],
+                    'cssBaseName' => str_replace('{module}', $mod, $this->options['cssBaseName']),
+                    'cssBaseUrl'  => $this->options['cssBaseUrl'],
+                    'jsBasePath'  => str_replace(DS, '/', ROOT_PATH . $this->options['jsBaseUrl']),
+                    'cssBasePath' => str_replace(DS, '/', ROOT_PATH . $this->options['cssBaseUrl']),
+                    'optimize'    => $optimize,
+                    'ds'          => DS,
+                ];
+
+                //源文件
+                $from = $data["{$res}BasePath"] . $data["{$res}BaseName"] . '.' . $res;
+                if (!is_file($from))
+                {
+                    $output->error("{$res} source file not found!file:{$from}");
+                    continue;
+                }
+                if ($res == "js")
+                {
+                    $content = file_get_contents($from);
+                    preg_match("/require\.config\(\{[\r\n]?[\n]?+(.*?)[\r\n]?[\n]?}\);/is", $content, $matches);
+                    if (!isset($matches[1]))
+                    {
+                        $output->error("js config not found!");
+                        continue;
+                    }
+                    $config = preg_replace("/(urlArgs|baseUrl):(.*)\n/", '', $matches[1]);
+                    $data['config'] = $config;
+                }
+                // 生成压缩文件
+                $this->writeToFile($res, $data, $tempFile);
+
+                $output->info("Compress " . $data["{$res}BaseName"] . ".{$res}");
+
+                // 执行压缩
+                $command = "{$nodeExec} \"{$minPath}r.js\" -o \"{$tempFile}\" >> \"{$minPath}node.log\"";
+                if ($output->isDebug())
+                {
+                    $output->warning($command);
+                }
+                echo exec($command);
+            }
+        }
+
+        if (!$output->isDebug())
+        {
+            @unlink($tempFile);
+        }
+
+        $output->info("Build Successed!");
+    }
+
+    /**
+     * 写入到文件
+     * @param string $name
+     * @param array $data
+     * @param string $pathname
+     * @return mixed
+     */
+    protected function writeToFile($name, $data, $pathname)
+    {
+        $search = $replace = [];
+        foreach ($data as $k => $v)
+        {
+            $search[] = "{%{$k}%}";
+            $replace[] = $v;
+        }
+        $stub = file_get_contents($this->getStub($name));
+        $content = str_replace($search, $replace, $stub);
+
+        if (!is_dir(dirname($pathname)))
+        {
+            mkdir(strtolower(dirname($pathname)), 0755, true);
+        }
+        return file_put_contents($pathname, $content);
+    }
+
+    /**
+     * 获取基础模板
+     * @param string $name
+     * @return string
+     */
+    protected function getStub($name)
+    {
+        return __DIR__ . DS . 'Min' . DS . 'stubs' . DS . $name . '.stub';
+    }
+
+}

Diff do ficheiro suprimidas por serem muito extensas
+ 4699 - 0
application/admin/command/Min/r.js


+ 6 - 0
application/admin/command/Min/stubs/css.stub

@@ -0,0 +1,6 @@
+({
+  cssIn: "{%cssBasePath%}{%cssBaseName%}.css",
+  out: "{%cssBasePath%}{%cssBaseName%}.min.css",
+  optimizeCss: "default",
+  optimize: "{%optimize%}"
+})

+ 11 - 0
application/admin/command/Min/stubs/js.stub

@@ -0,0 +1,11 @@
+({
+    {%config%}
+    ,
+    optimizeCss: "standard",
+    optimize: "{%optimize%}",   //可使用uglify|closure|none
+    preserveLicenseComments: false,
+    removeCombined: false,
+    baseUrl: "{%jsBasePath%}",    //JS文件所在的基础目录
+    name: "{%jsBaseName%}", //来源文件,不包含后缀
+    out: "{%jsBasePath%}{%jsBaseName%}.min.js"  //目标文件
+});

+ 227 - 0
application/admin/common.php

@@ -0,0 +1,227 @@
+<?php
+use think\Db;
+
+/**
+ * 压缩图片
+ * @param $imgsrc 压缩图片地址
+ * @param $imgdst 生成地址
+ */
+function image_png_size_add($imgsrc,$imgdst){
+    list($width,$height,$type)=getimagesize($imgsrc);
+//    $new_width = ($width>600?600:$width)*0.9;
+//    $new_height =($height>600?600:$height)*0.9;
+    $new_width = $width;
+    $new_height =$height;
+    switch($type){
+        case 1:
+            break;
+        case 2:
+            header('Content-Type:image/jpeg');
+            $image_wp=imagecreatetruecolor($new_width, $new_height);
+            $image = imagecreatefromjpeg($imgsrc);
+            imagecopyresampled($image_wp, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
+            imagejpeg($image_wp, $imgdst,config('quality'));
+            imagedestroy($image_wp);
+            break;
+        case 3:
+            header('Content-Type:image/png');
+            $image_wp=imagecreatetruecolor($new_width, $new_height);
+            $image = imagecreatefrompng($imgsrc);
+            imagecopyresampled($image_wp, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
+            imagejpeg($image_wp, $imgdst,config('quality'));
+            imagedestroy($image_wp);
+            break;
+    }
+}
+
+/**
+ * 将字符解析成数组
+ * @param $str
+ */
+function parseParams($str)
+{
+    $arrParams = [];
+    parse_str(html_entity_decode(urldecode($str)), $arrParams);
+    return $arrParams;
+}
+
+
+/**
+ * 子孙树 用于菜单整理
+ * @param $param
+ * @param int $pid
+ */
+function subTree($param, $pid = 0)
+{
+    static $res = [];
+    foreach($param as $key=>$vo){
+
+        if( $pid == $vo['pid'] ){
+            $res[] = $vo;
+            subTree($param, $vo['id']);
+        }
+    }
+
+    return $res;
+}
+
+
+/**
+ * 记录日志
+ * @param  [type] $uid         [用户id]
+ * @param  [type] $username    [用户名]
+ * @param  [type] $description [描述]
+ * @param  [type] $status      [状态] 200 操作成功  100 操作失败
+ * @param  [type] $type        [删除日志启用]
+ *///$uid,$username,$description,$status,$type=''
+function writelog($description,$status,$uid = '',$username = '',$type='')
+{
+    $id = $uid ? $uid : session('uid');
+    $name = $username ? : session('username');
+    $ip = request()->ip();
+    $ipaddr = get_ip_area($ip);//根据ip地址获取地域信息
+    /****************************日志存入数据库*******************************/
+    if($type == ''){
+        $data['admin_id'] = $id;
+        $data['admin_name'] = $name;
+        $data['description'] = $description;
+        $data['status'] = $status;
+        $data['ip'] = $ip;
+        $data['add_time'] = time();
+        $data['ipaddr'] = $ipaddr;
+        $logId = Db::name('Log')->insertGetId($data);
+    }else{
+        $logId = '空';
+    }
+    /****************************日志存入数据库*******************************/
+
+    /****************************日志存入文件*******************************/
+    if(config('log_std')){
+        $dir = 'log/'.date('Ymd',time());
+        if(!is_dir($dir)){
+            if(!mkdir($dir,0777,true)){
+                return false;
+            }
+        }
+        $file = 'log/'.date('Ymd',time()).'/'.date('Ymd',time()).'.txt';
+        if(!is_file($file)){
+            $word=fopen($file,"a+");
+            //        fwrite($word,' ID +----------+ 用户ID +----------+ 操作用户 +----------+ 描述 +----------+ 操作IP +----------+ 地址 +----------+ 状态 +----------+ 操作时间');
+            fwrite($word,"\r\n".'+-------------+--------------+--------------+----------------------------------------------------------+----------------------+-------------------+-----------------+-----------------------+');
+            fwrite($word,"\r\n".'|             |              |              |                                                          |                      |                   |                 |                       |');
+            fwrite($word,"\r\n".'|     ID      |    用户ID    |   操作用户   |                     描述                                 |        操作IP        |        地址       |      状态       |        操作时间       |');
+            fwrite($word,"\r\n".'|             |              |              |                                                          |                      |                   |                 |                       |');
+            fwrite($word,"\r\n".'+-------------+--------------+--------------+----------------------------------------------------------+----------------------+-------------------+-----------------+-----------------------+');
+            fclose($word);
+        }
+        $add_time=date('Y-m-d H:i:s',time());
+        if($status == 200){
+            $sta = '成功';
+        }else{
+            $sta = '失败';
+        }
+        file_put_contents($file,  "\r\n ".$logId.' +----------+ '.$uid.' +----------+ '.$username.' +----------+ '.$description.' +----------+ '.$ip.' +----------+ '.$ipaddr.' +----------+ '.$sta.' +----------+ '.$add_time,FILE_APPEND);
+        //    file_put_contents($file,  "\r\n".'| '.$logId.'          '.$uid.'              '.$username.'         '.$description.'                                       '.$ip.'              '.$ipaddr['country'].$ipaddr['place'].'            '.$sta.'              '.$add_time.'    |',FILE_APPEND);
+        file_put_contents($file,  "\r\n".'+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+',FILE_APPEND);
+    }
+    /****************************日志存入文件*******************************/
+}
+
+
+/**
+ * 整理菜单树方法
+ * @param $param
+ * @return array
+ */
+function prepareMenu($param)
+{
+//    dump($param);die;
+    $parent = []; //父类
+    $child = [];  //子类
+    foreach($param as $key=>$vo) {
+        if ( $vo[ 'pid' ] == 0 && $vo[ 'name' ] == '#' ) {
+            $vo[ 'href' ] = '#';
+            $parent[] = $vo;
+        }else if($vo[ 'pid' ] == 0 && $vo[ 'name' ] != '#' ){
+            if(!preg_match ("/^((https|http|ftp|rtsp|mms){0,1}(:\/\/){0,1})www\.(([A-Za-z0-9-~]+)\.)+([A-Za-z0-9-~\/])+$/",$vo['name'])){
+                $vo[ 'href' ] = url($vo['name']); //跳转地址
+            }else{
+                $vo[ 'href' ] = $vo['name']; //跳转地址
+            }
+            $parent[] = $vo;
+        }else{
+            if(!preg_match ("/^((https|http|ftp|rtsp|mms){0,1}(:\/\/){0,1})www\.(([A-Za-z0-9-~]+)\.)+([A-Za-z0-9-~\/])+$/",$vo['name'])){
+                $vo[ 'href' ] = url($vo['name']); //跳转地址
+            }else{
+                $vo[ 'href' ] = $vo['name']; //跳转地址
+            }
+            $child[] = $vo;
+        }
+    }
+
+    foreach($parent as $key=>$vo){
+        foreach($child as $k=>$v){
+            if($v['pid'] == $vo['id']){
+                $parent[$key]['child'][] = $v;
+            }
+        }
+    }
+
+    for($i=0;$i<count($parent);$i++){
+        if(isset($parent[$i]['child'])){
+            for($j=0;$j<count($parent[$i]['child']);$j++){
+                if($parent[$i]['child'][$j]['name'] == '##'){
+                    for($a=0;$a<count($child);$a++){
+                        if($child[$a]['pid'] == $parent[$i]['child'][$j]['id']){
+                            $parent[$i]['child'][$j]['child'][] = $child[$a];
+                        }
+                    }
+                }
+            }
+        }
+    }
+    unset($child);
+    return $parent;
+}
+
+
+/**
+ * 格式化字节大小
+ * @param  number $size      字节数
+ * @param  string $delimiter 数字和单位分隔符
+ * @return string            格式化后的带单位的大小
+ */
+function format_bytes($size, $delimiter = '') {
+    $units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
+    for ($i = 0; $size >= 1024 && $i < 5; $i++) {
+        $size /= 1024;
+    }
+    return $size . $delimiter . $units[$i];
+}
+
+// 分析枚举类型配置值 格式 a:名称1,b:名称2
+function parse_config_attr($string) {
+    $array = preg_split('/[,;\r\n]+/', trim($string, ",;\r\n"));
+    if(strpos($string,':')){
+        $value  =   array();
+        foreach ($array as $val) {
+            list($k, $v) = explode(':', $val);
+            $value[$k]   = $v;
+        }
+    }else{
+        $value  =   $array;
+    }
+    return $value;
+}
+
+/**
+ * trim & explode
+ * @param $d 符号
+ * @param $str 字符串
+ * @return array
+ */
+function trim_explode($d,$str){
+    $str = trim($str,$d);
+    $res = explode($d,$str);
+    return $res;
+}

+ 127 - 0
application/admin/controller/Aipimagesearch.php

@@ -0,0 +1,127 @@
+<?php
+
+namespace app\admin\controller;
+
+use think\Db;
+use think\Controller;
+use app\admin\model\AipImageSearchModel;
+use AipImageSearch as ocrApi;
+
+require VENDOR_PATH . 'qiniu/autoload.php';
+
+use Qiniu\Auth;
+use Qiniu\Storage\UploadManager;
+
+
+class Aipimagesearch extends Controller
+{
+    //图片添加
+    public function add()
+    {
+        if (request()->isPost()) {
+            $data = input("post.");
+            //halt($data);
+            $AipImageSearchModel = new AipImageSearchModel();
+            $add                 = $AipImageSearchModel->add($data);
+            return $add;
+        }
+        return $this->fetch("add");
+    }
+
+    //图片显示
+    public function index()
+    {
+        if (request()->isAjax()) {
+            extract(input());
+            $map = [];
+            if (isset($key) && $key != "") {
+                $map['o.product_name'] = ['like', "%" . $key . "%"];
+            }
+            if (isset($start) && $start != "" && isset($end) && $end == "") {
+                $map['o.create_time'] = ['>= time', $start];
+            }
+            if (isset($end) && $end != "" && isset($start) && $start == "") {
+                $map['o.create_time'] = ['<= time', $end];
+            }
+            if (isset($start) && $start != "" && isset($end) && $end != "") {
+                $map['o.create_time'] = ['between time', [$start, $end]];
+            }
+            $field = input('field');//字段
+            $order = input('order');//排序方式
+            if ($field && $order) {
+                $od = "o." . $field . " " . $order;
+            } else {
+                $od = "o.create_time desc";
+            }
+            //echo 111;die;
+            $Nowpage             = input('get.page') ? input('get.page') : 1;
+            $limits              = input("limit") ? input("limit") : 10;
+            $count               = Db::name('ocrimage')->alias('o')->where($map)->count();//计算总页面
+            $AipImageSearchModel = new AipImageSearchModel();
+            $lists               = $AipImageSearchModel->index($map, $Nowpage, $limits, $od);
+            /*foreach($lists as $v){
+                $v["product_image"]=config("site.webSiteUrl");
+                $v["product_image"]=config("site.webSiteUrl");
+                $v["product_image"]=config("site.webSiteUrl");
+                $v["product_image"]=config("site.webSiteUrl");
+                $v["product_image"]=config("site.webSiteUrl");
+            }*/
+            return json(['code' => 220, 'msg' => '', 'count' => $count, 'data' => $lists]);
+        }
+        return $this->fetch("index");
+    }
+
+    //图库修改
+    public function edit()
+    {
+        if (request()->isPost()) {
+            $data                = input("post.");
+            $AipImageSearchModel = new AipImageSearchModel();
+            $edit                = $AipImageSearchModel->edit($data);
+            return $edit;
+        }
+        $id   = input("id");
+        $data = Db::name("ocrimage")->where("oid", $id)->find();
+        //halt($data);
+        return $this->fetch("edit", ["data" => $data]);
+    }
+
+    //删除图库
+    public function del()
+    {
+        $oid                 = input("id");
+        $AipImageSearchModel = new AipImageSearchModel();
+        $del                 = $AipImageSearchModel->del($oid);
+        return $del;
+
+    }
+
+    //富文本图片上传
+    public function upload()
+    {
+        //$file = request()->file('file');
+        $file      = $_FILES['file'];
+        $imageinfo = getimagesize($_FILES['file']['tmp_name']);
+        /*if($imageinfo[0]>375){
+            return json(["code"=>0,'msg'=>"文件图片宽高不合适","data"=>""]);
+         }*/
+        $imageName     = $file['name'];
+        $fileName      = uniqid();
+        $ext           = strtolower(substr(strrchr($imageName, '.'), 1));
+        $imageSavePath = ROOT_PATH . 'public' . DS . 'uploads/fuwenben/' . $fileName . '.' . $ext;
+        $tmp           = $file['tmp_name'];
+//        $url = http_type ();
+        $info = move_uploaded_file($tmp, $imageSavePath);
+        if ($info) {
+            //image_png_size_add(ROOT_PATH . 'public' . DS . 'uploads/images/'.$newName,ROOT_PATH . 'public' . DS . 'uploads/images/'.$newName);
+            //$path="http://china.chenhao98.top/uploads/fuwenben/{$newName}";
+            $path = "http://china.chenhao98.top/uploads/fuwenben/" . $fileName . '.' . $ext;
+            /*$size=getimagesize($path);
+            halt($size);*/
+            $data = ["src" => $path];
+            return json(["code" => 0, 'msg' => "上传成功", "data" => $data]);
+        } else {
+            echo $file->getError();
+        }
+    }
+}

+ 478 - 0
application/admin/controller/Article.php

@@ -0,0 +1,478 @@
+<?php
+
+namespace app\admin\controller;
+use app\admin\model\ArticleModel;
+use app\admin\model\ArticleCateModel;
+use think\Db;
+use org\Qiniu;
+
+class Article extends Base
+{
+    /**
+     * [index 文章列表]
+     * @author
+     */
+    public function index(){
+        if(request()->isAjax ()){
+            extract(input());
+            $map = [];
+            if(isset($key)&&$key!=""){
+                $map['r.title'] = ['like',"%" . $key . "%"];
+            }
+            if(isset($start)&&$start!=""&&isset($end)&&$end=="")
+            {
+                $map['r.create_time'] = ['>= time',$start];
+            }
+            if(isset($end)&&$end!=""&&isset($start)&&$start=="")
+            {
+                $map['r.create_time'] = ['<= time',$end];
+            }
+            if(isset($start)&&$start!=""&&isset($end)&&$end!="")
+            {
+                $map['r.create_time'] = ['between time',[$start,$end]];
+            }
+            $field=input('field');//字段
+            $order=input('order');//排序方式
+            if($field && $order){
+                $od="r.".$field." ".$order;
+            }else{
+                $od="r.create_time desc";
+            }
+            $Nowpage = input('get.page') ? input('get.page'):1;
+            $limits = input("limit")?input("limit"):10;
+            $count = Db::name('article')->alias('r')->where($map)->count();//计算总页面
+            $article = new ArticleModel();
+            $lists = $article->getArticleByWhere($map, $Nowpage, $limits,$od);
+            for($i=0;$i<count($lists);$i++){
+                $photo = explode(',',$lists[$i]['photo']);
+                $lists[$i]['photo'] = array_values($photo);
+            }
+            return json(['code'=>220,'msg'=>'','count'=>$count,'data'=>$lists]);
+        }
+        return $this->fetch("article/index");
+    }
+
+    //tableSelect测试数据
+    public function getUserData(){
+        if(request()->isGet ()){
+            extract(input());
+            $map = [];
+            if(isset($keyword)&&$keyword!=""){
+                $map['name'] = ['like',"%" . $keyword . "%"];
+            }
+            $Nowpage = input('get.page') ? input('get.page'):1;
+            $limits = input("limit")?input("limit"):10;
+            $count = Db::name('test')->where($map)->count();//计算总页面
+            $lists = Db::name('test')
+                ->where($map)
+                ->page($Nowpage,$limits)
+                ->select();
+            return json(['code'=>220,'msg'=>'','count'=>$count,'data'=>$lists]);
+        }
+        if(request()->isPost ()){
+            $data = Db::name('test')
+                ->where('id','in',input('id'))
+                ->select();
+            return json(['code'=>200,'data'=>$data]);
+        }
+    }
+
+//    public function insertData(){
+//        set_time_limit (0);
+//        for($i=0;$i<100000;$i++){
+//            $param = ['name'=>'kevin'.($i+1)];
+//            Db::name('test')->insert($param);
+//        }
+//    }
+
+
+    /**
+     * [add_article 添加文章]
+     * @return [type] [description]
+     * @author
+     */
+    public function add_article()
+    {
+        if(request()->isPost()){
+            extract(input());
+            $param = input('post.');
+            if(!isset($status)){
+                $param['status'] = 2;
+            }
+            $param['photo'] = trim($param['photo'],',');
+            $article = new ArticleModel();
+            $flag = $article->insertArticle($param);
+            return json(['code' => $flag['code'], 'data' => $flag['data'], 'msg' => $flag['msg']]);
+        }
+        $cate = new ArticleCateModel();
+        $area = new \app\common\place\Area;
+        return $this->fetch('article/add_article',['province'=>$area->province(),'cate'=>$cate->getCate()]);
+    }
+
+
+    /**
+     * [edit_article 编辑文章]
+     * @return [type] [description]
+     * @author
+     */
+    public function edit_article()
+    {
+        $article = new ArticleModel();
+        if(request()->isPost()){
+            $param = input('post.');
+            $imgs = explode(',',$param['del']);
+            foreach($imgs as $vo){
+                $add = str_replace ('http://p73q8jzf0.bkt.clouddn.com/','',$vo);
+                $up = new Qiniu();
+                $up->delFile($add,'kevin');
+            }
+            $param['photo'] = trim($param['photo'],',');
+            $flag = $article->updateArticle($param);
+            return json(['code' => $flag['code'], 'data' => $flag['data'], 'msg' => $flag['msg']]);
+        }
+
+        $id = input('param.id');
+        $cate = new ArticleCateModel();
+        $data = $article->getOneArticle($id);
+        if(!empty($data['photo'])){
+            $data['photo'] = trim($data['photo'],',');
+//            $img = explode(',',$data['photo']);
+//            foreach($img as $vo){
+//                $photo[] = '/uploads/images/'.$vo;
+//            }
+            $data['imges'] = $data['photo'];
+        }else{
+            $data['photo'] = '';
+            $data['imges'] = '';
+        }
+        $this->assign('cate',$cate->getCate());
+        $this->assign('article',$data);
+        return $this->fetch();
+    }
+
+//    /**
+//     * imgDelete 删除图片
+//     * @return \think\response\Json
+//     * @throws \think\Exception
+//     * @throws \think\exception\PDOException
+//     */
+//    public function imgDelete(){
+//        extract(input());
+//        $photo = Db::name('article')->where('id',$id)->value('photo');
+//        $add = str_replace('/uploads/images/',"",$add);
+//        $imgs = explode(',',$photo);;
+//        if(in_array($add,$imgs)){
+//            $key = array_search ($add,$imgs);
+//            $place  = 'uploads/images/'.$imgs[$key];
+//            unset($imgs[$key]);
+//            $img = implode(',',$imgs);
+//            trim($img,',');
+//            $res = Db::name('article')->where('id',$id)->update(['photo'=>$img]);
+//            if($res){
+//                unlink ($place);
+//                return json(['code'=>200,'msg'=>'删除成功']);
+//            }else{
+//                return json(['code'=>100,'msg'=>'删除失败!']);
+//            }
+//        }
+//    }
+//
+//    /**
+//     * updatePhoto 修改图片
+//     * @return \think\response\Json
+//     */
+//    public function updatePhoto(){
+//        extract(input());
+//        $photo = Db::name('article')->where('id',$id)->value('photo');
+//        if($photo != ""){
+//            $photo = $photo.",".$add;
+//        }else{
+//            $photo = $add;
+//        }
+//        $res = Db::name('article')->where('id',$id)->setField ('photo',$photo);
+//        if($res){
+//            return json(['code'=>200,'msg'=>'']);
+//        }else{
+//            return json(['code'=>100,'msg'=>'']);
+//        }
+//    }
+
+    /**
+     * [del_article 删除文章]
+     * @return [type] [description]
+     * @author
+     */
+    public function del_article()
+    {
+        $id = input('param.id');
+        $cate = new ArticleModel();
+        $flag = $cate->delArticle($id);
+        return json(['code' => $flag['code'], 'data' => $flag['data'], 'msg' => $flag['msg']]);
+    }
+
+
+
+    /**
+     * [article_state 文章状态]
+     * @return [type] [description]
+     * @author
+     */
+    public function article_state()
+    {
+        extract(input());
+        $cate = new ArticleModel();
+        $flag = $cate->articleState($id,$num);
+        return json(['code' => $flag['code'], 'data' => $flag['data'], 'msg' => $flag['msg']]);
+    }
+    /**
+     * batchDelArticle 批量删除文章
+     * @return \think\response\Json
+     */
+    public function batchDelArticle(){
+        extract(input());
+        if(empty($ids)){
+            return json(['code'=>100,'msg'=>'请选择要删除的记录!']);
+        }
+        $article = new ArticleModel();
+        $flag = $article->batchDelArticle($ids);
+        return json(['code' => $flag['code'], 'msg' => $flag['msg']]);
+    }
+
+    /**
+     * 批量启用文章
+     * @return \think\response\Json
+     */
+    public function usingArticle(){
+        extract(input());
+        $list = [];
+        if($ids){
+            $ids = explode(',',$ids);
+            for($i=0;$i<count($ids);$i++){
+                $param = [
+                    'id'=>$ids[$i],
+                    'status'=>1
+                ];
+                $list[] = $param;
+            }
+        }
+        $article = new ArticleModel();
+        $flag = $article->usingArticle($list);
+        return json(['code' => $flag['code'], 'msg' => $flag['msg']]);
+    }
+
+    /**
+     * 批量禁用文章
+     * @return \think\response\Json
+     */
+    public function forbiddenArticle(){
+        extract(input());
+        $list = [];
+        if($ids){
+            $ids = explode(',',$ids);
+            for($i=0;$i<count($ids);$i++){
+                $param = [
+                    'id'=>$ids[$i],
+                    'status'=>2
+                ];
+                $list[] = $param;
+            }
+        }
+        $article = new ArticleModel();
+        $flag = $article->forbiddenArticle($list);
+        return json(['code' => $flag['code'], 'msg' => $flag['msg']]);
+    }
+
+
+//    /**
+//     * showImg 多图预览
+//     * @return mixed
+//     */
+//    public function showImg(){
+//        $imgs = Db::name('article')->where('id',input('id'))->value('photo');
+//        $imgs = explode(',',$imgs);
+////        $this->assign('imgs',$imgs);
+////        return $this->fetch('article/show_img');
+//        return json(['msg'=>$imgs,'one'=>$imgs[0]]);
+//
+//    }
+
+
+
+    //*********************************************分类管理*********************************************//
+
+    /**
+     * [index_cate 分类列表]
+     * @return [type] [description]
+     * @author
+     */
+    public function index_cate(){
+        if(request()->isAjax ()){
+            extract(input());
+            $map = [];
+            if(isset($key)&&$key!=""){
+                $map['name'] = ['like',"%" . $key . "%"];
+            }
+            if(isset($start)&&$start!=""&&isset($end)&&$end=="")
+            {
+                $map['create_time'] = ['>= time',$start];
+            }
+            if(isset($end)&&$end!=""&&isset($start)&&$start=="")
+            {
+                $map['create_time'] = ['<= time',$end];
+            }
+            if(isset($start)&&$start!=""&&isset($end)&&$end!="")
+            {
+                $map['create_time'] = ['between time',[$start,$end]];
+            }
+            $field=input('field');//字段
+            $order=input('order');//排序方式
+            if($field && $order){
+                $od=$field." ".$order;
+            }else{
+                $od="create_time desc";
+            }
+            $cate = new ArticleCateModel();
+            $nowpage = input('get.page') ? input('get.page'):1;
+            $limits = input("limit")?input("limit"):10;
+            $count = $cate->getAllCount($map);//计算总页面
+            $lists = $cate->getAllCate($map, $nowpage, $limits,$od);
+            return json(['code'=>0,'msg'=>'','count'=>$count,'data'=>$lists]);
+        }
+        return $this->fetch("article/index_cate");
+    }
+
+
+    /**
+     * [add_cate 添加分类]
+     * @return [type] [description]
+     * @author
+     */
+    public function add_cate()
+    {
+        if(request()->isPost()){
+            extract(input());
+            $param = input('post.');
+            if(!isset($status)){
+                $param['status'] = 2;
+            }
+            $cate = new ArticleCateModel();
+            $flag = $cate->insertCate($param);
+            return json(['code' => $flag['code'], 'data' => $flag['data'], 'msg' => $flag['msg']]);
+        }
+
+        return $this->fetch();
+    }
+
+
+    /**
+     * [edit_cate 编辑分类]
+     * @return [type] [description]
+     * @author
+     */
+    public function edit_cate()
+    {
+        $cate = new ArticleCateModel();
+
+        if(request()->isPost()){
+
+            $param = input('post.');
+            $flag = $cate->editCate($param);
+            return json(['code' => $flag['code'], 'data' => $flag['data'], 'msg' => $flag['msg']]);
+        }
+
+        $id = input('param.id');
+        $this->assign('cate',$cate->getOneCate($id));
+        return $this->fetch();
+    }
+
+
+    /**
+     * [del_cate 删除分类]
+     * @return [type] [description]
+     * @author
+     */
+    public function del_cate()
+    {
+        $id = input('param.id');
+        $cate = new ArticleCateModel();
+        $flag = $cate->delCate($id);
+        return json(['code' => $flag['code'], 'data' => $flag['data'], 'msg' => $flag['msg']]);
+    }
+
+
+
+    /**
+     * [cate_state 分类状态]
+     * @return [type] [description]
+     * @author
+     */
+    public function cate_state()
+    {
+        extract(input());
+        $cate = new ArticleCateModel();
+        $flag = $cate->cateState($id,$num);
+        return json(['code' => $flag['code'], 'data' => $flag['data'], 'msg' => $flag['msg']]);
+    }
+
+    /**
+     * batchDelCate 批量删除文章分类
+     * @return \think\response\Json
+     */
+    public function batchDelCate(){
+        extract(input());
+        if(empty($ids)){
+            return json(['code'=>100,'msg'=>'请选择要删除的记录!']);
+        }
+        $cate = new ArticleCateModel();
+        $flag = $cate->batchDelCate($ids);
+        return json(['code' => $flag['code'], 'msg' => $flag['msg']]);
+    }
+
+    /**
+     * 批量启用分类
+     * @return \think\response\Json
+     */
+    public function usingCate(){
+        extract(input());
+        $list = [];
+        if($ids){
+            $ids = explode(',',$ids);
+            for($i=0;$i<count($ids);$i++){
+                $param = [
+                    'id'=>$ids[$i],
+                    'status'=>1
+                ];
+                $list[] = $param;
+            }
+        }
+        $cate = new ArticleCateModel();
+        $flag = $cate->usingCate($list);
+        return json(['code' => $flag['code'], 'msg' => $flag['msg']]);
+    }
+
+    /**
+     * 批量禁用分类
+     * @return \think\response\Json
+     */
+    public function forbiddenCate(){
+        extract(input());
+        $list = [];
+        if($ids){
+            $ids = explode(',',$ids);
+            for($i=0;$i<count($ids);$i++){
+                $param = [
+                    'id'=>$ids[$i],
+                    'status'=>2
+                ];
+                $list[] = $param;
+            }
+        }
+        $cate = new ArticleCateModel();
+        $flag = $cate->forbiddenCate($list);
+        return json(['code' => $flag['code'], 'msg' => $flag['msg']]);
+    }
+
+    public function printOrder(){
+        return $this->fetch('article/order');
+    }
+}

+ 137 - 0
application/admin/controller/Base.php

@@ -0,0 +1,137 @@
+<?php
+/**
+ * Created by PhpStorm.
+ * User: Kevin
+ * Date: 2018/8/2
+ * Time: 22:28
+ */
+namespace app\admin\controller;
+use think\Controller;
+use app\admin\model\Node;
+use think\Db;
+use think\session;
+class Base  extends Controller
+{
+    public function _initialize()
+    {
+        if(!session('?uid')||!session('?username')){
+            $this->redirect(url('admin/login/index'));
+        }
+        if(request()->controller() != 'Data' && request()->action () != 'revert') {
+            $adminSta = Db::name ('admin')->where ('id' , session ('uid'))->field ('status,username')->find ();
+            $roleSta = Db::name ('admin')->alias ('a')->join ('auth_group g' , 'a.groupid=g.id' , 'left')->where ('a.id' , session ('uid'))->field ('g.status,g.title')->find ();
+            if ( is_null ($adminSta[ 'username' ]) ) {
+                writelog (session ('username') . '账号不存在,强制下线!' , 200);
+                $this->error ('抱歉,账号不存在,强制下线' , 'admin/login/loginout');
+            }
+            if ( is_null ($roleSta[ 'title' ]) ) {
+                writelog (session ('rolename') . '身份不存在,强制下线!' , 200);
+                $this->error ('抱歉,身份不存在,强制下线' , 'admin/login/loginout');
+            }
+            if ( $adminSta[ 'status' ] == 2 ) {
+                writelog ($adminSta[ 'username' ] . '账号被禁用,强制下线!' , 200);
+                $this->error ('抱歉,该账号被禁用,强制下线' , 'admin/login/loginout');
+            }
+            if ( $roleSta[ 'status' ] == 2 ) {
+                writelog ($roleSta[ 'title' ] . '角色被禁用,强制下线!' , 200);
+                $this->error ('抱歉,该账号角色被禁用,强制下线' , 'admin/login/loginout');
+            }
+        }
+
+        $auth = new \com\Auth();
+        $module     = strtolower(request()->module());
+        $controller = strtolower(request()->controller());
+        $action     = strtolower(request()->action());
+        $url        = $module."/".$controller."/".$action;
+        //跳过检测以及主页权限
+        if(session('uid')!=1){
+            foreach(config('auth_pass') as $vo){
+                $pass[] = strtolower($vo);
+            }
+            if(!in_array($url,$pass)){
+                if(!$auth->check($url,session('uid'))){
+                    $this->error('抱歉,您没有操作权限');
+                }
+            }
+        }
+
+        //首页展示用户&菜单信息
+        $node = new Node();
+        $this->assign([
+            'username' => session('username'),
+            'portrait' => session('portrait'),
+            'rolename' => session('rolename'),
+            'menu' => $node->getMenu(session('rule'))
+        ]);
+
+        $config = cache('db_config_data');
+        if(!$config){
+            $config = api('Config/lists');
+            cache('db_config_data',$config);
+        }
+        config($config);
+        if(config('web_site_close') == 0 && session('uid') !=1 ){
+            $this->error('站点已经关闭,请稍后访问~');
+        }
+        if(config('admin_allow_ip') && session('uid') !=1 ){
+            if(in_array(request()->ip(),explode(',',config('admin_allow_ip')))){
+                $this->error('403:禁止访问');
+            }
+        }
+    }
+
+    /**
+     * place 三级联动
+     * @return \think\response\Json
+     */
+    public function place()
+    {
+        $area = new \app\common\place\Area;
+        $data = $area->area();
+        return json($data);
+    }
+
+
+    /**
+     * 极光推送
+     * @param $type 1:推送个人  2:推送全体
+     * @param $alias 别名 user_id OR token
+     * @param $message 推送消息内容
+     * @param $extras 扩展字段接受数组
+     * @return array
+     */
+    public function Jpush($type,$alias,$message,$extras)
+    {
+        $alias = (string)$alias;
+        import('jpush.autoload', EXTEND_PATH);
+        //初始化JPushClient
+        $client = new \JPush\Client(config('jpush.appKey'),config('jpush.masterSecret'));
+        //生成推送Payload构建器
+        $push = $client->push();
+        //推送平台 'all'  OR  ['ios','android']  OR  'ios','android'
+        $push->setPlatform('all');
+        //1:推送个人  2:推送全体
+        if($type==1){
+            $push->addAlias($alias);//按别名推送
+        }else{
+            $push->addAllAudience();//广播消息推送
+        }
+        //IOS推送
+        $push->iosNotification($message, [
+                'alert'=>$message,
+                'badge' => '+1',
+                'extras' => $extras,
+                'sound'=>'default'
+            ]
+        );
+        //Android推送
+        $push->androidNotification($message, [
+                'alert'=>$message,
+                'extras' => $extras
+            ]
+        );
+        return $push->send();
+    }
+
+
+}

+ 59 - 0
application/admin/controller/Chart.php

@@ -0,0 +1,59 @@
+<?PHP
+
+namespace app\admin\controller;
+
+use app\admin\controller\Base;
+use app\admin\model\ChartModel;
+use think\Db;
+
+class Chart extends Base
+{
+    public function index()
+    {
+        if (request()->isAjax()) {
+            $model = new ChartModel();
+            $count = Db::name("chart")->count();
+            $lists = $model->index();
+            //halt($lists);
+            return json(['code' => 220, 'count' => $count, 'data' => $lists]);
+        }
+        return $this->fetch("index");
+    }
+
+    public function add()
+    {
+        if (request()->isAjax()) {
+            $data = input("post.");
+            $model = new ChartModel();
+            $add = $model->add($data);
+            return $add;
+        }
+        return $this->fetch("add");
+    }
+
+    public function edit()
+    {
+        if (request()->isPost()) {
+            $data = input("post.");
+            //halt($data);
+            $model = new ChartModel();
+            $edit = $model->edit($data);
+            return $edit;
+        }
+        $id = input("id");
+        //echo $id;die;
+        $data = Db::name("chart")->where("cid", $id)->find();
+        return $this->fetch("edit", ["data" => $data]);
+    }
+
+    public function del()
+    {
+        $id = input("id");
+        $del = Db::name("chart")->where("cid", $id)->delete();
+        if ($del) {
+            return json(["code" => 200, "msg" => "删除成功"]);
+        } else {
+            return json(["code" => 200, "msg" => "删除失败"]);
+        }
+    }
+}

+ 37 - 0
application/admin/controller/Company.php

@@ -0,0 +1,37 @@
+<?php
+
+namespace app\admin\controller;
+
+use think\Controller;
+use think\Db;
+
+class Company extends Controller
+{
+
+    public function index()
+    {
+        if (request()->isAjax()) {
+            $lists = Db::name("company")->select();
+            return json(['code' => 220, 'msg' => '', 'count' => 1, 'data' => $lists]);
+        }
+        return $this->fetch("index");
+    }
+
+    public function edit()
+    {
+        if (request()->isPost()) {
+            //die;
+            $data = input("text");
+            $add = Db:: name("company")->where("cid", 1)->update(["text" => $data]);
+            if ($add) {
+                return json(["code" => 200, "msg" => "修改成功"]);
+            } else {
+                return json(["code" => 100, "msg" => "修改失败"]);
+            }
+        }
+        $id = input("id");
+        $data = Db::name("company")->where("cid", $id)->find();
+        //halt($data);
+        return $this->fetch("edit", ["data" => $data]);
+    }
+}

+ 225 - 0
application/admin/controller/Config.php

@@ -0,0 +1,225 @@
+<?php
+
+namespace app\admin\controller;
+use app\admin\model\ConfigModel;
+use think\Db;
+
+class Config extends Base
+{
+
+    /**
+     * [index 配置列表]
+     */
+    public function index(){
+        if(request()->isAjax ()){
+            extract(input());
+            $map = [];
+            if(isset($type)&&$type!=""){
+                $map['type'] = $type;
+            }
+            if(isset($group)&&$group!=""){
+                $map['group'] = $group;
+            }
+            if(isset($key)&&$key!="")
+            {
+                $map['title|name'] = ['like',"%" . $key . "%"];
+            }
+            if(isset($start)&&$start!=""&&isset($end)&&$end=="")
+            {
+                $map['create_time'] = ['>= time',$start];
+            }
+            if(isset($end)&&$end!=""&&isset($start)&&$start=="")
+            {
+                $map['create_time'] = ['<= time',$end];
+            }
+            if(isset($start)&&$start!=""&&isset($end)&&$end!="")
+            {
+                $map['create_time'] = ['between time',[$start,$end]];
+            }
+            $field=input('field');//字段
+            $order=input('order');//排序方式
+            if($field && $order){
+                $od=$field." ".$order;
+            }else{
+                $od="create_time desc";
+            }
+            $config = new ConfigModel();
+            $Nowpage = input('page') ? input('page'):1;
+            $limits = input("limit")?input("limit"):10;
+            $lists = $config->getAllConfig($map, $Nowpage, $limits,$od);
+            $count = $config->getAllCount($map);//计算总页面
+            return json(['code'=>220,'msg'=>'','count'=>$count,'data'=>$lists]);
+        }
+        $this->assign ('type',config('config_type_list'));
+        $this->assign ('group',config('config_group_list'));
+        return $this->fetch("config/index");
+    }
+
+
+    /**
+     * [add_config 添加配置]
+     */
+    public function add_config()
+    {
+        if(request()->isPost()){
+            extract(input());
+            $param = input('post.');
+            if(!isset($status)){
+                $param['status'] = 2;
+            }
+            $config = new ConfigModel();
+            $flag = $config->insertConfig($param);
+            cache('db_config_data',null);
+            return json(['code' => $flag['code'], 'data' => $flag['data'], 'msg' => $flag['msg']]);
+        }
+        return $this->fetch();
+    }
+
+    /**
+     * 验证配置标识的唯一性
+     */
+    public function checkConfig(){
+        extract(input());
+        $user = new ConfigModel();
+        if(isset($id)&&$id!=""){
+            $uid = $id;
+        }else{
+            $uid = '';
+        }
+        $flag = $user->checkConfig($name,$uid);
+        return json(['code' => $flag['code'], 'msg' => $flag['msg']]);
+    }
+
+    /**
+     * [edit_config 编辑配置]
+     */
+    public function edit_config()
+    {
+        $config = new ConfigModel();
+        if(request()->isPost()){
+            $param = input('post.');
+            $flag = $config->editConfig($param);
+            return json(['code' => $flag['code'], 'data' => $flag['data'], 'msg' => $flag['msg']]);
+        }
+        $id = input('param.id');
+        $info = $config->getOneConfig($id);
+        $this->assign('info', $info);
+//        dump($info);die;
+        return $this->fetch();
+    }
+
+
+    /**
+     * [del_config 删除配置]
+     * @author
+     */
+    public function del_config()
+    {
+        $id = input('param.id');
+        $config = new ConfigModel();
+        $flag = $config->delConfig($id);
+        return json(['code' => $flag['code'], 'data' => $flag['data'], 'msg' => $flag['msg']]);
+    }
+
+
+
+    /**
+     * [user_state 配置状态]
+     * @author
+     */
+    public function status_config()
+    {
+        extract(input());
+        $config = new ConfigModel();
+        $flag = $config->configState($id,$num);
+        return json(['code' => $flag['code'], 'data' => $flag['data'], 'msg' => $flag['msg']]);
+    }
+
+
+    /**
+     * [获取某个标签的配置参数]
+     * @author
+     */
+    public function group() {
+        $id   = input('id',1);
+        $type = config('config_group_list'); 
+        $list = Db::name("Config")->where(array('status'=>1,'group'=>$id))->field('id,name,title,extra,value,remark,type')->order('sort')->select();
+        $this->assign('list',$list);
+        $this->assign('id',$id);
+        return $this->fetch();
+    }
+
+
+
+    /**
+     * [批量保存配置]
+     * @author
+     */
+    public function save($config){
+        $id = input('param.id');
+        $conf = new ConfigModel();
+        $flag = $conf->configSave($config);
+        if($flag['code']==200){
+            cache('db_config_data',null);
+        }
+        return json(['code' => $flag['code'], 'data' => $flag['data'], 'msg' => $flag['msg']]);
+    }
+
+    /**
+     * batchDelConfig 批量删除配置
+     * @return \think\response\Json
+     */
+    public function batchDelConfig(){
+        extract(input());
+        $config = new ConfigModel();
+        if(empty($ids)){
+            return json(['code'=>100,'msg'=>'请选择要删除的记录!']);
+        }
+        $flag = $config->batchDelConfig($ids);
+        return json(['code' => $flag['code'], 'msg' => $flag['msg']]);
+    }
+
+    /**
+     * usingConfig 批量启用
+     * @return \think\response\Json
+     */
+    public function usingConfig(){
+        extract(input());
+        $list = [];
+        if($ids){
+            $ids = explode(',',$ids);
+            for($i=0;$i<count($ids);$i++){
+                $param = [
+                    'id'=>$ids[$i],
+                    'status'=>1
+                ];
+                $list[] = $param;
+            }
+        }
+        $conf = new ConfigModel();
+        $flag = $conf->usingConfig($list);
+        return json(['code' => $flag['code'], 'msg' => $flag['msg']]);
+    }
+
+    /**
+     * 批量禁用配置
+     * @return \think\response\Json
+     */
+    public function forbiddenConfig(){
+        extract(input());
+        $list = [];
+        if($ids){
+            $ids = explode(',',$ids);
+            for($i=0;$i<count($ids);$i++){
+                $param = [
+                    'id'=>$ids[$i],
+                    'status'=>2
+                ];
+                $list[] = $param;
+            }
+        }
+        $conf = new ConfigModel();
+        $flag = $conf->forbiddenConfig($list);
+        return json(['code' => $flag['code'], 'msg' => $flag['msg']]);
+    }
+}

+ 346 - 0
application/admin/controller/Data.php

@@ -0,0 +1,346 @@
+<?php
+namespace app\admin\controller;
+use think\Config;
+use think\Db;
+use think\Session;
+use think\Request;
+use com\Database;
+
+class Data extends Base
+{
+    /**
+     * 数据备份首页
+     * @author
+     */
+    public function index() {
+        if(request()->isAjax ()){
+            $tmp = Db::query('SHOW TABLE STATUS');
+            $data = array_map('array_change_key_case', $tmp);
+            foreach($data as $key=>$vo){
+                if($vo['name'] == config('database.prefix')."backups"){
+                    unset($data[$key]);
+                }
+                if($vo['name'] == config('database.prefix')."log"){
+                    unset($data[$key]);
+                }
+            }
+            $data = array_merge ($data);;
+            return json(['code'=>220,'msg'=>'','count'=>count($data),'data'=>$data]);
+        }
+        return $this->fetch("data/index");
+    }
+
+
+
+    /**
+     * 备份数据库
+     * @param  String  $ids 表名
+     * @param  Integer $id     表ID
+     * @param  Integer $start  起始行数
+     * @author
+     */
+    public function export($ids = null, $id = null, $start = null) {
+        $Request = Request::instance();
+        if ($Request->isPost() && !empty($ids) && is_array($ids)) { //初始化
+            $path = Config::get('data_backup_path');
+            is_dir($path) || mkdir($path, 0755, true);
+            //读取备份配置
+            $config = [
+                'path' => realpath($path) . DIRECTORY_SEPARATOR,
+                'part' => Config::get('data_backup_part_size'),
+                'compress' => Config::get('data_backup_compress'),
+                'level' => Config::get('data_backup_compress_level'),
+            ];
+
+            //检查是否有正在执行的任务
+            $lock = "{$config['path']}backup.lock";
+//            if (is_file($lock)) {
+//                return $this->error('检测到有一个备份任务正在执行,请稍后再试!');
+//            }
+            file_put_contents($lock, $Request->time()); //创建锁文件
+            //检查备份目录是否可写
+            is_writeable($config['path']) || $this->error('备份目录不存在或不可写,请检查后重试!');
+            Session::set('backup_config', $config);
+            //生成备份文件信息
+            $file = [
+                'name' => date('Ymd-His', $Request->time()),
+                'part' => 1
+            ];
+            Session::set('backup_file', $file);
+            //缓存要备份的表
+            Session::set('backup_tables', $ids);
+            //创建备份文件
+            $Database = new \com\Database($file, $config);
+            if (false !== $Database->create()) {
+                $tab = ['id' => 0, 'start' => 0];
+                return $this->success('初始化成功!', '', ['tables' => $ids, 'tab' => $tab]);
+            } else {
+                return $this->error('初始化失败,备份文件创建失败!');
+            }
+        } elseif ($Request->isGet() && is_numeric($id) && is_numeric($start)) { //备份数据
+            $tables = Session::get('backup_tables');
+            //备份指定表
+            $Database = new \com\Database(Session::get('backup_file'), Session::get('backup_config'));
+            $start = $Database->backup($tables[(int) $id], $start);
+            if (false === $start) { //出错
+                $this->error('备份出错!');
+            } elseif (0 === $start) { //下一表
+                if (isset($tables[++$id])) {
+                    $tab = ['id' => $id, 'start' => 0];
+                    return $this->success('备份完成!', '', ['tab' => $tab]);
+                } else { //备份完成,清空缓存
+                    unlink(Session::get('backup_config.path') . 'backup.lock');
+                    $tab = implode ('|',session('backup_tables'));
+                    $time = session('backup_file')['name'];
+                    writelog('备份数据库【'.$time.'】成功',200);
+                    Session::set('backup_tables', null);
+                    Session::set('backup_file', null);
+                    Session::set('backup_config', null);
+                    return $this->success('备份完成!');
+                }
+            } else {
+                $tab = ['id' => $id, 'start' => $start[0]];
+                $rate = floor(100 * ($start[0] / $start[1]));
+                return $this->success("正在备份...({$rate}%)", '', ['tab' => $tab]);
+            }
+        } else {
+            return json(['msg' => '请选择要备份的数据表!']);
+        }
+    }
+
+    /**
+     * 优化表
+     * @param  String $ids 表名
+     */
+    public function optimize($ids = null) {
+        if (empty($ids)) {
+            return $this->error("请指定要优化的表!");
+        }
+        $table = trim_explode(',',$ids);
+        $Db = Db::connect();
+        if (count($table) > 1) {
+            $tables = implode('`,`', $table);
+            $list = $Db->query("OPTIMIZE TABLE `{$tables}`");
+            if($list){
+                writelog('用户【'.session('username').'】优化数据库成功',200);
+//                $this->success("数据表优化完成!");
+                return json(['code'=>200,'msg'=>"数据表优化完成!"]);
+            } else {
+                writelog('用户【'.session('username').'】优化数据库失败',100);
+//                $this->error("数据表优化出错请重试!");
+                return json(['code'=>100,'msg'=>"数据表优化出错请重试!"]);
+            }
+        } else {
+
+            $list = $Db->query("OPTIMIZE TABLE `{$ids}`");
+            if($list){
+//                $this->success("数据表'{$ids}'优化完成!");
+                writelog('用户【'.session('username').'】优化【'.$ids.'】表成功',200);
+                return json(['code'=>200,'msg'=>"数据表'{$ids}'优化完成!"]);
+                //return json("数据表'{$ids}'优化完成!");
+            } else {
+//                $this->error("数据表'{$ids}'优化出错请重试!");
+                writelog('用户【'.session('username').'】优化【'.$ids.'】表失败',100);
+                return json(['code'=>100,'msg'=>"数据表'{$ids}'优化出错请重试!"]);
+            }
+        }
+    }
+
+
+
+    /**
+     * 修复表
+     * @param  String $ids 表名
+     * @author
+     */
+    public function repair($ids = null) {
+        if (empty($ids)) {
+            return $this->error("请指定要修复的表!");
+        }
+        $table = trim_explode(',',$ids);
+        $Db = Db::connect();
+        if (count($table) > 1) {
+            $tables = implode('`,`', $table);
+            $list = $Db->query("REPAIR TABLE `{$tables}`");
+            if($list){
+                writelog('用户【'.session('username').'】修复数据库成功',200);
+//                $this->success("数据表修复完成!");
+                return json(['code'=>200,'msg'=>"数据表修复完成!"]);
+            } else {
+                writelog('用户【'.session('username').'】修复数据库失败',100);
+//                $this->error("数据表修复出错请重试!");
+                return json(['code'=>100,'msg'=>"数据表修复出错请重试!"]);
+            }
+        } else {
+            $list = $Db->query("REPAIR TABLE `{$ids}`");
+            if($list){
+//                $this->success("数据表'{$ids}'修复完成!");
+                writelog('用户【'.session('username').'】修复【'.$ids.'】表成功',200);
+                return json(['code'=>200,'msg'=>"数据表'{$ids}'修复完成!"]);
+            } else {
+//                $this->error("数据表'{$ids}'修复出错请重试!");
+                writelog('用户【'.session('username').'】修复【'.$ids.'】表失败',100);
+                return json(['code'=>100,'msg'=>"数据表'{$ids}'修复出错请重试!"]);
+            }
+        }
+    }
+
+
+
+
+    /**
+     * 还原数据库首页
+     * @param 类型 参数 参数说明
+     * @author staitc7 <static7@qq.com>
+     */
+    public function import() {
+        if(request()->isAjax ()) {
+            //列出备份文件列表
+            $path_tmp = Config::get ('data_backup_path');
+            is_dir ($path_tmp) || mkdir ($path_tmp , 0755 , true);
+            $path = realpath ($path_tmp);
+            $flag = \FilesystemIterator::KEY_AS_FILENAME;
+            $glob = new \FilesystemIterator($path , $flag);
+            $list = array();
+            foreach ($glob as $name => $file) {
+                if ( preg_match ('/^\d{8,8}-\d{6,6}-\d+\.sql(?:\.gz)?$/' , $name) ) {
+                    $name = sscanf ($name , '%4s%2s%2s-%2s%2s%2s-%d');
+                    $date = "{$name[0]}-{$name[1]}-{$name[2]}";
+                    $time = "{$name[3]}:{$name[4]}:{$name[5]}";
+                    $part = $name[ 6 ];
+                    if ( isset($list[ "{$date} {$time}" ]) ) {
+                        $info = $list[ "{$date} {$time}" ];
+                        $info[ 'part' ] = max ($info[ 'part' ] , $part);
+                        $info[ 'size' ] = $info[ 'size' ] + $file->getSize ();
+                    } else {
+                        $info[ 'part' ] = $part;
+                        $info[ 'size' ] = format_bytes($file->getSize ());
+                    }
+                    $extension = strtoupper (pathinfo ($file->getFilename () , PATHINFO_EXTENSION));
+                    $info[ 'compress' ] = ($extension === 'SQL') ? '-' : $extension;
+                    $info[ 'time' ] = date('Ymd-His' ,strtotime ("{$date} {$time}"));
+                    $info['date'] = "{$date} {$time}" ;
+                    $list[] = $info;
+                }
+            }
+            return json (['code' => 220 , 'msg' => '' , 'count' => count($list) , 'data' => arrayToSort($list,'date','SORT_DESC')]);
+        }
+        return $this->fetch('data/import');
+    }
+
+    /**
+     * 删除备份文件
+     * @param  Integer $time 备份时间
+     * @author
+     */
+    public function delData() {
+        $time = input('id');
+        empty($time) && $this->error('参数错误!');
+        $name = $time . '-*.sql*';
+        $path = realpath(Config::get('data_backup_path')) . DIRECTORY_SEPARATOR . $name;
+        array_map("unlink", glob($path));
+        if (count(glob($path))) {
+            writelog('删除【'.$time.'】备份文件失败',100);
+//            return $this->error('备份文件删除失败,请检查权限!');
+            return json(['code'=>100,'msg'=>'备份文件删除失败,请检查权限!']);
+        } else {
+            writelog('删除【'.$time.'】备份文件成功',200);
+//            return $this->success('备份文件删除成功!');
+            return json(['code'=>200,'msg'=>'备份文件删除成功!']);
+        }
+    }
+
+    /**
+     * 还原数据库
+     * @author
+     */
+    public function revert($time = 0, $part = null, $start = null) {
+        if (!empty($time) && is_null($part) && is_null($start)) { //初始化
+            //获取备份文件信息
+            $name = $time . '-*.sql*';
+            $path = realpath(Config::get('data_backup_path')) . DIRECTORY_SEPARATOR . $name;
+            $files = glob($path);
+            $list = [];
+            foreach ($files as $name) {
+                $basename = basename($name);
+                $match = sscanf($basename, '%4s%2s%2s-%2s%2s%2s-%d');
+                $gz = preg_match('/^\d{8,8}-\d{6,6}-\d+\.sql.gz$/', $basename);
+                $list[$match[6]] = array($match[6], $name, $gz);
+            }
+            ksort($list);
+            $last = end($list);//检测文件正确性
+            if (count($list) === $last[0]) {
+                Session::set('backup_list', $list); //缓存备份列表
+                return $this->success('初始化完成,请等待!', '', ['part' => 1, 'start' => 0]);
+            } else {
+                return $this->error('备份文件可能已经损坏,请检查!');
+            }
+        } elseif (is_numeric($part) && is_numeric($start)) {
+            set_time_limit(0);
+            $list = Session::get('backup_list');
+            $db = new \com\Database($list[$part], [
+                    'path' => realpath(Config::get('data_backup_path')) . DIRECTORY_SEPARATOR,
+                    'compress' => $list[$part][2]
+                ]
+            );
+            $start = $db->import($start);
+            if (false === $start) {
+                writelog('还原数据库【'.date('Ymd-His',$time).'】失败',100);
+                return $this->error('还原数据出错!');
+            } elseif (0 === $start) { //下一卷
+                if (isset($list[++$part])) {
+                    $data = array('part' => $part, 'start' => 0);
+                    $this->success("正在还原... ", '', $data);
+                } else {
+                    writelog('还原数据库【'.date('Ymd-His',$time).'】成功',200);
+                    Session::set('backup_list', null);
+                    $this->success('数据库还原完成!','', 'success');
+                }
+            } else {
+                $data = array('part' => $part, 'start' => $start[0]);
+                if ($start[1]) {
+                    $rate = floor(100 * ($start[0] / $start[1]));
+                    return $this->success("正在还原... ({$rate}%)", '', $data);
+                } else {
+                    $data['gz'] = 1;
+                    return $this->success("正在还原... ", '', $data);
+                }
+            }
+        } else {
+            return $this->error('参数错误!');
+        }
+    }
+
+    /**
+     * batchDelData 批量删除备份文件
+     * @return \think\response\Json
+     */
+    public function batchDelData(){
+        extract(input());
+        if(empty($ids)){
+            return json(['code'=>100,'msg'=>'请选择要删除的备份文件']);
+        }
+        $ids = trim_explode(',',$ids);
+        $error = [];//储存删除失败文件
+        $success = [];//储存删除成功文件
+        foreach($ids as $vo){
+            $name = $vo . '-*.sql*';
+            $path = realpath(Config::get('data_backup_path')) . DIRECTORY_SEPARATOR . $name;
+            array_map("unlink", glob($path));
+            if (count(glob($path))) {
+                $error[] = $vo;
+            }else{
+                $success[] = $vo;
+            }
+        }
+        if (!empty($error)) {
+            $error = implode (',',$error);
+            writelog('批量删除【'.$error.'】备份文件失败',100);
+            return json(['code'=>100,'msg'=>'批量删除失败']);
+        } else {
+            writelog('批量删除备份文件成功',200);
+            return json(['code'=>200,'data'=>$success,'msg'=>'批量删除成功']);
+        }
+    }
+
+}

+ 55 - 0
application/admin/controller/Email.php

@@ -0,0 +1,55 @@
+<?php
+/**
+ * Created by PhpStorm.
+ * User: Kevin
+ * Date: 2018/11/14
+ * Time: 15:51
+ */
+namespace app\admin\controller;
+use think\Db;
+class Email extends Base
+{
+    public function index(){
+        return $this->fetch('email/index');
+    }
+
+    /*
+     * 发送邮件
+     */
+    public function sendEmail(){
+        extract(input());
+        $res = sendMail($mailTo,$subject,$body);
+        if($res == true){
+            return json(['code'=>200,'msg'=>'发送成功']);
+        }else{
+            return json(['code'=>100,'msg'=>'发送失败']);
+        }
+    }
+
+    /*
+     * 发送云之讯短信
+     */
+    public function sendYzxCode(){
+        extract(input());
+        $res = YzxSms($code,$phone);
+        if($res['code'] == 000000){
+            return json(['code'=>200,'msg'=>'发送成功']);
+        }else{
+            return json(['code'=>100,'msg'=>$res['msg']]);
+        }
+    }
+
+    /*
+     * 发送阿里短信
+     */
+    public function sendAliCode(){
+        extract(input());
+        $res = alisms($phone,$code);
+        if($res['Code'] == 'OK'){
+            return json(['code'=>200,'msg'=>'发送成功']);
+        }else{
+            return json(['code'=>100,'msg'=>$res['Message']]);
+        }
+    }
+
+}

+ 47 - 0
application/admin/controller/Index.php

@@ -0,0 +1,47 @@
+<?php
+/**
+ * Created by PhpStorm.
+ * User: Kevin
+ * Date: 2018/8/2
+ * Time: 21:54
+ */
+namespace app\admin\controller;
+use think\Controller;
+use think\Db;
+class Index extends  Base
+{
+    /**
+     * 框架页面
+     * @return mixed
+     */
+    public function index()
+    {
+        return $this->fetch('/index');
+    }
+
+    /**
+     * 首页
+     * @return mixed|\think\response\Json
+     */
+    public function indexPage()
+    {
+        return $this->fetch('index/index');
+    }
+
+    /**
+     * 清除缓存
+     */
+    public function clear() {
+        if (delete_dir_file(CACHE_PATH) && delete_dir_file(TEMP_PATH)) {
+            writelog('清除缓存成功',200);
+            return json(['code' => 200, 'msg' => '清除缓存成功']);
+        } else {
+            writelog('清除缓存失败',100);
+            return json(['code' => 100, 'msg' => '清除缓存失败']);
+        }
+    }
+
+    public function webuploader(){
+        return $this->fetch('/webuploader');
+    }
+}

+ 83 - 0
application/admin/controller/Log.php

@@ -0,0 +1,83 @@
+<?php
+
+namespace app\admin\controller;
+use app\admin\model\LogModel;
+use think\Db;
+ 
+class Log extends Base
+{
+
+    /**
+     * [operate_log 操作日志]
+     * @return [type] [description]
+     * @author
+     */
+    public function operate_log()
+    {
+        $key = input('key');
+        $start = input('start');
+        $end = input('end');
+        $arr=Db::name("admin")->column("id,username"); //获取用户列表
+        if(request()->isAjax ()){
+            $map = [];
+            if($key&&$key!==""){
+                $map['admin_id'] =  $key;
+            }
+            if($start&&$start!==""&&$end=="")
+            {
+                $map['add_time'] = ['>= time',$start];
+            }
+            if($end&&$end!==""&&$start=="")
+            {
+                $map['add_time'] = ['<= time',$end];
+            }
+            if($start&&$start!==""&&$end&&$end!=="")
+            {
+                $map['add_time'] = ['between time',[$start,$end]];
+            }
+            $field=input('field');//字段
+            $order=input('order');//排序方式
+            if($field && $order){
+                $od=$field." ".$order;
+            }else{
+                $od="add_time desc";
+            }
+            $Nowpage = input('get.page') ? input('get.page'):1;
+            $limits = input("limit")?input("limit"):10;// 获取总条数;
+            $count = Db::name('log')->where($map)->count();//计算总页面
+            $lists = Db::name('log')->where($map)->page($Nowpage, $limits)->order($od)->select();
+            return json(['code'=>220,'msg'=>'','count'=>$count,'data'=>$lists]);
+        }
+        $this->assign('val', $key);
+        $this->assign("search_user",$arr);
+        return $this->fetch();
+    }
+
+
+    /**
+     * [del_log 删除日志]
+     * @return [type] [description]
+     * @author
+     */
+    public function del_log()
+    {
+        $id = input('param.id');
+        $log = new LogModel();
+        $flag = $log->delLog($id);
+        return json(['code' => $flag['code'], 'data' => $flag['data'], 'msg' => $flag['msg']]);
+    }
+
+    /**
+     * batchDelLog 批量删除日志
+     * @return \think\response\Json
+     */
+    public function batchDelLog(){
+        extract(input());
+        if(empty($ids)){
+            return json(['code'=>100,'msg'=>'请选择要删除的记录!']);
+        }
+        $log = new LogModel();
+        $flag = $log->batchDelLog($ids);
+        return json(['code' => $flag['code'], 'msg' => $flag['msg']]);
+    }
+}

+ 178 - 0
application/admin/controller/Login.php

@@ -0,0 +1,178 @@
+<?php
+/**
+ * Created by PhpStorm.
+ * User: Kevin
+ * Date: 2018/8/2
+ * Time: 22:30
+ */
+namespace app\admin\controller;
+use think\Controller;
+use think\Db;
+use org\Verify;
+use com\Geetestlib;
+use app\admin\model\UserType;
+class Login extends Controller
+{
+    /**
+     * 登录页面
+     * @return mixed
+     */
+    public function index()
+    {
+        return $this->fetch('/login');
+    }
+
+    /**
+     * 生成验证码
+     * @return mixed
+     */
+    public function checkVerify()
+    {
+        $config =    [
+            'imageH' => 38,// 验证码图片高度
+            'imageW' => 120,// 验证码图片宽度
+            'codeSet' => '02345689',// 验证码字符集合
+            'useZh' => false,//使用中文验证码
+            'length' => 4,// 验证码位数
+            'useNoise' => true,//是否添加杂点
+            'useCurve' => false,//是否画混淆曲线
+            'useImgBg' => false,//使用背景图片
+            'fontSize' => 16// 验证码字体大小(px)
+        ];
+        $verify = new Verify($config);
+        return $verify->entry();
+    }
+
+    /**
+     * 极验验证
+     */
+    public function getVerify()
+    {
+        $GtSdk = new Geetestlib(config('gee.gee_id'), config('gee.gee_key'));
+        $user_id = "web";
+        $status = $GtSdk->pre_process($user_id);
+        session('gtserver',$status);
+        session('user_id',$user_id);
+        echo $GtSdk->get_response_str();
+    }
+
+    /**
+     * 验证验证码
+     * @return \think\response\Json
+     */
+    public function doLogin()
+    {
+        $username = input("param.username");
+        $password = input("param.password");
+        $verify = new Verify();
+        if (config('verify_type') == 1) {
+            $code = input("param.vercode");
+            if (!$verify->check($code)) {
+                return json(['code' => -4, 'url' => '', 'msg' => '验证码错误']);
+            }
+            return  $this->checkAdmin($username,$password);
+        }elseif (config('verify_type') == 2) {
+            $GtSdk = new Geetestlib(config('gee.gee_id'), config('gee.gee_key'));
+            $user_id = session('user_id');
+            if (session('gtserver') == 1) {
+                $result = $GtSdk->success_validate(input('param.geetest_challenge'), input('param.geetest_validate'), input('param.geetest_seccode'), $user_id);
+                //极验服务器状态正常的二次验证接口
+                if (!$result) {
+                    return json(['code' => -3, 'url' => '', 'msg' => '请先拖动图片到相应位置']);
+                }
+            }else{
+                if (!$GtSdk->fail_validate(input('param.geetest_challenge'), input('param.geetest_validate'), input('param.geetest_seccode'))) {
+                    //极验服务器状态宕机的二次验证接口
+                    return json(['code' => -3, 'url' => '', 'msg' => '请先拖动图片到相应位置']);
+                }
+            }
+            return  $this->checkAdmin($username,$password);
+        }else{
+            return  $this->checkAdmin($username,$password);
+        }
+    }
+
+    /**
+     * 验证帐号和密码
+     * @param $username
+     * @param $password
+     * @return \think\response\Json
+     */
+    public function checkAdmin($username,$password){
+        $hasUser = Db::name('admin a')
+            ->join('auth_group ag','a.groupid=ag.id','left')
+            ->where('username', $username)
+            ->field('a.id,a.username,a.password,a.portrait,a.phone,a.loginnum,a.last_login_ip,a.last_login_time,a.real_name,a.status,a.groupid,ag.id agid,ag.title,ag.status ags')
+            ->find();
+        if(empty($hasUser)){
+            return json(['code' => -1, 'url' => '', 'msg' => '管理员不存在']);
+        }
+
+        $config = api('Config/lists');
+        if($config['web_site_close'] == 0 && $hasUser['id'] !=1 ){
+            $this->error('后台已经关闭,请稍后访问');
+            return json(['code' => -7, 'url' => '', 'msg' =>'后台已经关闭,请稍后访问']);
+        }
+        if($config['admin_allow_ip'] && $hasUser['id'] !=1 ){
+            if(in_array(request()->ip(),explode(',',$config['admin_allow_ip']))){
+                return json(['code' => -8, 'url' => '', 'msg' =>'IP禁止访问']);
+            }
+        }
+
+        if(md5(md5($password) . config('auth_key')) != $hasUser['password']){
+            writelog('管理员【'.$username.'】登录失败:密码错误',100,$hasUser['id'] , $username);
+            return json(['code' => -2, 'url' => '', 'msg' => '密码错误']);
+        }
+
+        if(1 != $hasUser['status']){
+            writelog('管理员【'.$username.'】登录失败:该账号被禁用',100,$hasUser['id'], $username);
+            return json(['code' => -5, 'url' => '', 'msg' => '抱歉,该账号被禁用']);
+        }
+        if($hasUser['ags'] == 2){
+            writelog('管理员【'.$username.'】登录失败:'.$hasUser['title'].'身份被禁用',100,$hasUser['id'], $username);
+            return json(['code' => -6, 'url' => '', 'msg' =>'抱歉,'.$hasUser['title'].'身份被禁用']);
+        }
+
+        if($hasUser['ags'] == null){
+            writelog('管理员【'.$username.'】登录失败:所属身份不存在',100,$hasUser['id'],$username);
+            return json(['code' => -7, 'url' => '', 'msg' =>'抱歉,所属身份不存在']);
+        }
+
+        //获取该管理员的角色信息
+        $user = new UserType();
+        $info = $user->getRoleInfo($hasUser['groupid']);
+
+        session('uid', $hasUser['id']);             //用户ID
+        session('username', $hasUser['username']);  //用户名
+        session('portrait', $hasUser['portrait']);  //用户头像
+        session('phone', $hasUser['phone']);        //手机号
+        session('agid', $hasUser['agid']);          //角色id
+        session('rolename', $info['title']);        //角色名
+        session('describe', $info['describe']);     //角色描述
+        session('rule', $info['rules']);            //角色节点
+        session('name', $info['name']);             //角色权限
+        session('last_time',time());                //角色登录时间点
+
+        //更新管理员状态
+        $param = [
+            'loginnum' => $hasUser['loginnum'] + 1,
+            'last_login_ip' => request()->ip(),
+            'last_login_time' => time()
+        ];
+
+        Db::name('admin')->where('id', $hasUser['id'])->update($param);
+        writelog('管理员【'.session('username').'】登录成功',200);
+        return json(['code' => 1, 'url' => url('admin/index/index'), 'msg' => '登录成功!']);
+    }
+
+    /**
+     * 退出登录
+     */
+    public function loginOut()
+    {
+        writelog('退出登录',200);
+        session(null);
+        cache('db_config_data',null);
+        $this->redirect(url('admin/index/index'));
+    }
+}

+ 192 - 0
application/admin/controller/Menu.php

@@ -0,0 +1,192 @@
+<?php
+
+namespace app\admin\controller;
+use app\admin\model\MenuModel;
+use think\Db;
+
+class Menu extends Base
+{	
+    /**
+     * [index 菜单列表]
+     * @return [type] [description]
+     * @author
+     */
+    public function index()
+    {
+        if(request()->isAjax ()){
+            extract(input());
+            $map = [];
+            if(isset($key)&&$key!="")
+            {
+                $map['title'] = ['like',"%" . $key . "%"];
+            }
+            if(isset($start)&&$start!=""&&isset($end)&&$end=="")
+            {
+                $map['create_time'] = ['>= time',$start];
+            }
+            if(isset($end)&&$end!=""&&isset($start)&&$start=="")
+            {
+                $map['create_time'] = ['<= time',$end];
+            }
+            if(isset($start)&&$start!=""&&isset($end)&&$end!="")
+            {
+                $map['create_time'] = ['between time',[$start,$end]];
+            }
+            $nav = new \org\Leftnav;
+            $menu = new MenuModel();
+            $Nowpage = 1;
+            $limits = 1000;
+            $count = Db::name('auth_rule')->where($map)->count();//计算总页面
+            $admin_rule = $menu->getMenus($map, $Nowpage, $limits);
+            foreach($admin_rule  as $key=>$vo){
+                $admin_rule[$key]['placeholder'] = '';
+            }
+            $nav->init($admin_rule);
+            $lists = $nav->get_tree(0);
+            return json(['code'=>220,'msg'=>'','count'=>$count,'data'=>$lists]);
+        }
+        return $this->fetch('menu/index');
+    }
+
+	
+    /**
+     * [add_rule 添加菜单]
+     * @return [type] [description]
+     * @author
+     */
+	public function add_rule()
+    {
+        if(request()->isPost()){
+            extract(input());
+            $pid = trim_explode(',',$pid);
+            $title = trim_explode(',',$title);
+            $name = trim_explode(',',$name);
+            $css = trim_explode(',',$css);
+            $sort = trim_explode(',',$sort);
+            $menu = new MenuModel();
+            $flag = $menu->insertMenu($pid,$title,$name,$css,$sort,$status);
+            return json(['code' => $flag['code'], 'data' => $flag['data'], 'msg' => $flag['msg']]);
+        }
+        $id = input('id');
+        $nav = new \org\Leftnav;
+        $menu = new MenuModel();
+        $map = [];
+        $admin_rule = $menu->getAllMenu($map);
+        $nav->init($admin_rule);
+        $lists = $nav->get_tree(0);
+        $this->assign ([
+            'admin_rule'=>$lists,
+            'id'=>$id
+        ]);
+        return $this->fetch();
+    }
+
+    /**
+     * [edit_rule 编辑菜单]
+     * @return [type] [description]
+     * @author
+     */
+    public function edit_rule()
+    {
+        $nav = new \org\Leftnav;
+        $menu = new MenuModel();
+        if(request()->isPost()){
+            $param = input('param.');
+//            $param['name'] = strtolower($param['name']);
+            $flag = $menu->editMenu($param);
+            return json(['code' => $flag['code'], 'data' => $flag['data'], 'msg' => $flag['msg']]);
+        }
+        $id = input('id');
+        $map = [];
+        $admin_rule = $menu->getAllMenu($map);
+        $nav->init($admin_rule);
+        $arr = $nav->get_tree(0);
+//        $arr = $nav::rule($admin_rule);
+        $this->assign ('admin_rule',$arr);
+        $this->assign('menu',$menu->getOneMenu($id));
+        return $this->fetch();
+    }
+
+    //根据节点查询出所有子节点
+    static public $childNode=array();//存放父节点和父节点下面的子节点
+    public function findArrayNode($id,$list){
+        foreach ($list as $key => $val){
+            if ($id==$val['pid']){
+                self::$childNode[]=(int)$val['id'];
+                self::findArrayNode($val['id'], $list);     //递归,传入新节点ID
+            }
+        }
+    }
+
+
+    /**
+     * [del_menu 删除菜单]
+     * @return [type] [description]
+     * @author
+     */
+    public function del_menu()
+    {
+        $tid = input('param.id');
+        $allTree = Db::name('auth_rule')
+            ->field('id,pid')
+            ->select();
+        self::$childNode[]=(int)$tid;
+        self::findArrayNode($tid, $allTree);
+        $menu = new MenuModel();
+        $flag = $menu->delMenu($tid,self::$childNode);
+        return json(['code' => $flag['code'], 'data' => $flag['data'], 'msg' => $flag['msg']]);
+    }
+
+
+    /**
+     * editField 快捷编辑
+     * @return \think\response\Json
+     */
+    public function editField(){
+        extract(input());
+        $res = Db::name($table)->where(['id' => $id ])->setField($field , $value);
+        if($res){
+            writelog('更新字段成功',200);
+            return json(['code' => 200,'data' => '', 'msg' => '更新字段成功']);
+        }else{
+            writelog('更新字段失败',100);
+            return json(['code' => 100,'data' => '', 'msg' => '更新字段失败']);
+        }
+    }
+
+    /**
+     * [rule_state 菜单状态]
+     * @return [type] [description]
+     * @author
+     */
+    public function rule_state()
+    {
+        extract(input());
+        $menu = new MenuModel();
+        $flag = $menu->ruleState($id,$num);
+        return json(['code' => $flag['code'], 'data' => $flag['data'], 'msg' => $flag['msg']]);
+    }
+
+    /**
+     * batchDelMenu 批量删除菜单
+     * @return \think\response\Json
+     */
+    public function batchDelMenu(){
+        extract(input());
+        if(empty($ids)){
+            return json(['code'=>100,'msg'=>'请选择要删除的记录!']);
+        }
+        $ids = explode(',',$ids);
+        $allTree = Db::name('auth_rule')
+            ->field('id,pid')
+            ->select();
+        foreach($ids as $key=>$vo){
+            self::$childNode[]=(int)$vo;
+            self::findArrayNode($vo, $allTree);
+        }
+        $menu = new MenuModel();
+        $flag = $menu->batchDelMenu(array_unique(self::$childNode));
+        return json(['code' => $flag['code'],'data' => $flag['data'],'msg' => $flag['msg']]);
+    }
+
+}

+ 256 - 0
application/admin/controller/Role.php

@@ -0,0 +1,256 @@
+<?php
+
+namespace app\admin\controller;
+use app\admin\model\Node;
+use app\admin\model\UserType;
+use think\Db;
+
+class Role extends Base
+{
+
+    /**
+     * [index 角色列表]
+     */
+    public function index(){
+        if(request()->isAjax ()){
+            extract(input());
+            $map = [];
+            if(isset($key)&&$key!="")
+            {
+                $map['title'] = ['like',"%" . $key . "%"];
+            }
+            if(isset($start)&&$start!=""&&isset($end)&&$end=="")
+            {
+                $map['create_time'] = ['>= time',$start];
+            }
+            if(isset($end)&&$end!=""&&isset($start)&&$start=="")
+            {
+                $map['create_time'] = ['<= time',$end];
+            }
+            if(isset($start)&&$start!=""&&isset($end)&&$end!="")
+            {
+                $map['create_time'] = ['between time',[$start,$end]];
+            }
+            $field=input('field');//字段
+            $order=input('order');//排序方式
+            if($field && $order){
+                $od=$field." ".$order;
+            }else{
+                $od="create_time desc";
+            }
+            $user = new UserType();
+            $Nowpage = input('page') ? input('page'):1;
+            $limits = input("limit")?input("limit"):10;// 获取总条数;
+            $count = $user->getAllRole($map);  //总数据
+            $lists = $user->getRoleByWhere($map, $Nowpage, $limits,$od);
+            return json(['code'=>220,'msg'=>'','count'=>$count,'data'=>$lists]);
+        }
+        return $this->fetch("role/index");
+    }
+
+
+
+    /**
+     * [roleAdd 添加角色]
+     */
+    public function roleAdd()
+    {
+        if(request()->isPost()){
+            extract(input());
+            $param = input('post.');
+            $role = new UserType();
+            $flag = $role->insertRole($param);
+            return json(['code' => $flag['code'], 'data' => $flag['data'], 'msg' => $flag['msg']]);
+        }
+        return $this->fetch('role/roleadd');
+    }
+
+    /**
+     * checkRole 验证角色名称唯一性
+     */
+    public function checkRole(){
+        extract(input());
+        if(isset($id)&&$id!=""){
+            $uid = $id;
+        }else{
+            $uid = '';
+        }
+        $role = new UserType();
+        $flag = $role->checkRole ($title,$uid);
+        return json(['code' => $flag['code'], 'msg' => $flag['msg']]);
+    }
+
+    /**
+     * [roleEdit 编辑角色]
+     */
+    public function roleEdit()
+    {
+        $role = new UserType();
+        if(request()->isPost()){
+            $param = input('post.');
+            $flag = $role->editRole($param);
+            return json(['code' => $flag['code'], 'data' => $flag['data'], 'msg' => $flag['msg']]);
+        }
+
+        $id = input('param.id');
+        $this->assign([
+            'role' => $role->getOneRole($id)
+        ]);
+        return $this->fetch('role/roleedit');
+    }
+
+
+
+    /**
+     * [roleDel 删除角色]
+     * @return [type] [description]
+     * @author
+     */
+    public function roleDel()
+    {
+        $id = input('param.id');
+        if($id == session('agid')){
+            return json(['code'=>100,'msg'=>'不能删除自己的角色']);
+        }else{
+            $role = new UserType();
+            $flag = $role->delRole($id);
+            return json(['code' => $flag['code'], 'data' => $flag['data'], 'msg' => $flag['msg']]);
+        }
+    }
+
+    /**
+     * [role_state 用户状态]
+     * @return [type] [description]
+     * @author
+     */
+    public function role_state()
+    {
+        extract(input());
+        $role = new UserType();
+        $flag = $role->roleState($id,$num);
+        return json(['code' => $flag['code'], 'data' => $flag['data'], 'msg' => $flag['msg']]);
+    }
+
+
+
+    /**
+     * [giveAccess 分配权限]
+     * @return [type] [description]
+     * @author
+     */
+    public function giveAccess()
+    {
+        $param = input('param.');
+        $node = new Node();
+        //获取现在的权限
+        if('get' == $param['type']){
+            $nodeStr = $node->getNodeInfo($param['id']);
+            return json(['code' => 200, 'data' => $nodeStr, 'msg' => 'success']);
+        }
+        //分配新权限
+        if('give' == $param['type']){
+
+            $doparam = [
+                'id' => $param['id'],
+                'rules' => $param['rule']
+            ];
+            $user = new UserType();
+            $flag = $user->editAccess($doparam);
+            return json(['code' => $flag['code'], 'data' => $flag['data'], 'msg' => $flag['msg']]);
+        }
+    }
+
+    /**
+     * batchDelRole 批量删除角色
+     * @return \think\response\Json
+     */
+    public function batchDelRole(){
+        extract(input());
+        if(empty($ids)){
+            return json(['code'=>100,'msg'=>'请选择要删除的记录!']);
+        }
+        $ids = explode(',',$ids);
+        if(in_array('1',$ids)){
+            $key = array_search ('1',$ids);
+            unset($ids[$key]);
+            if(empty($ids)){
+                return json(['code'=>100,'msg'=>'不可删除超级管理员角色']);
+                die;
+            }
+        }
+        if(in_array(session('agid'),$ids)){
+            $key = array_search (session('agid'),$ids);
+            unset($ids[$key]);
+            if(empty($ids)){
+                return json(['code'=>100,'msg'=>'不可删除自己的角色']);
+                die;
+            }
+        }
+        $ids = array_merge($ids);
+        $user = new UserType();
+        $flag = $user->batchDelRole($ids);
+        return json(['code' => $flag['code'], 'msg' => $flag['msg']]);
+    }
+
+    /**
+     * usingAll 批量启用
+     * @return \think\response\Json
+     */
+    public function usingRole(){
+        extract(input());
+        $list = [];
+        if($ids){
+            $ids = explode(',',$ids);
+            for($i=0;$i<count($ids);$i++){
+                $param = [
+                    'id'=>$ids[$i],
+                    'status'=>1
+                ];
+                $list[] = $param;
+            }
+        }
+        $user = new UserType();
+        $flag = $user->usingRole($list);
+        return json(['code' => $flag['code'], 'msg' => $flag['msg']]);
+    }
+
+    /**
+     * batchForbidden 批量禁用
+     * @return \think\response\Json
+     */
+    public function forbiddenRole(){
+        extract(input());
+        $list = [];
+        if($ids){
+            $ids = explode(',',$ids);
+            if(in_array('1',$ids)){
+                $key = array_search ('1',$ids);
+                unset($ids[$key]);
+                if(empty($ids)){
+                    return json(['code'=>100,'msg'=>'不可禁用超级管理员']);
+                    die;
+                }
+            }
+            if(in_array(session('agid'),$ids)){
+                $key = array_search (session('agid'),$ids);
+                unset($ids[$key]);
+                if(empty($ids)){
+                    return json(['code'=>100,'msg'=>'不可禁用自己的角色']);
+                    die;
+                }
+            }
+            $ids = array_merge($ids);
+            for($i=0;$i<count($ids);$i++){
+                $param = [
+                    'id'=>$ids[$i],
+                    'status'=>2
+                ];
+                $list[] = $param;
+            }
+        }
+        $user = new UserType();
+        $flag = $user->forbiddenRole($list);
+        return json(['code' => $flag['code'], 'msg' => $flag['msg']]);
+    }
+
+}

+ 379 - 0
application/admin/controller/Upload.php

@@ -0,0 +1,379 @@
+<?php
+
+namespace app\admin\controller;
+use think\Controller;
+use think\File;
+use think\Request;
+use think\Seeeion;
+use think\Db;
+use org\Qiniu;
+use org\Upayun;
+class Upload extends Base
+{
+    /**
+     * 上传图片到又拍云
+     * @throws \Exception
+     */
+    public function uploadOnYpy(){
+        $filePath = $_FILES['file']['tmp_name'];
+        //取出图片后缀
+        $type = explode(".",$_FILES['file']['name']);
+        $type = end($type);
+        //组装图片名
+        $key = md5(time().uuid()).'.'.$type;
+        $up = new Upayun();
+        $data = $up->uploadFile($filePath,$key,'/up/');
+        echo $data;
+    }
+
+    /**
+     * 删除又拍云图片文件
+     * @return \think\response\
+     */
+    public function deleteYpy(){
+        $add = input('add');
+        $up = new Upayun();
+        $res = $up->delFile($add);
+        if($res){
+            return json(['code'=>200,'msg'=>'删除成功!']);
+        }else{
+            return json(['code'=>100,'msg'=>'删除失败!']);
+        }
+    }
+
+    /**
+     * deleteImg 删除七牛图片文件
+     * @return \think\response\
+     */
+    public function deleteImg(){
+        $add = input('add');
+        $up = new Qiniu();
+        $res = $up->delFile($add,'kevin');
+        if($res){
+            return json(['code'=>100,'msg'=>'删除失败!']);
+        }else{
+            return json(['code'=>200,'msg'=>'删除成功!']);
+        }
+    }
+
+
+    /**
+     * upload 上传图片到七牛云
+     * @throws \Exception
+     */
+    public function upload(){
+        //echo 111;die;
+        //halt($_FILES);
+        $filePath = $_FILES['file']['tmp_name'];
+        //取出图片后缀
+        $type = explode(".",$_FILES['file']['name']);
+        $type = end($type);
+        //组装图片名
+        $key = md5(time().uuid()).'.'.$type;
+        $up = new Qiniu();
+        $data = $up->uploadFile($filePath,$key);
+        echo $data;
+    }
+
+    /*
+     * layui上传图片&音频
+     */
+    public function layUpload(){
+        set_time_limit (0);
+        $filePath = $_FILES['file']['tmp_name'];
+        //取出图片后缀
+        $type = explode(".",$_FILES['file']['name']);
+        $type = end($type);
+        //组装图片名
+        $key = md5(time().uuid()).'.'.$type;
+        $up = new Qiniu();
+        $data = $up->uploadFile($filePath,$key);
+        halt($data);
+        /*$APP_ID = config('site.app_id');
+        $API_KEY = config('site.api_key');
+        $SRCRET_KEY = config('site.srcret_key');
+        $client = new AipImageSearch($APP_ID, $API_KEY, $SRCRET_KEY);
+        $url = config("site.webSiteUrl");
+        // 如果有可选参数
+        $options = array();
+        $options["brief"] = "{'name':'周杰伦' , 'id':'1'}";
+        $options["tags"] = "100,11";
+        // 带参数调用相似图检索—入库, 图片参数为远程url图片
+        $client->similarAddUrl($url, $options);
+        return json(['code'=>0,'msg'=>'','data'=>['src'=>config('qiniu.domain').$data]]);*/
+    }
+
+    /*
+     * 上传视频
+     */
+    public function layUploadVideo(){
+        set_time_limit (0);
+        $filePath = $_FILES['file']['tmp_name'];
+        //取出文件后缀
+        $type = explode(".",$_FILES['file']['name']);
+        $type = end($type);
+        //组装文件名
+        $key = md5(time().uuid()).'.'.$type;
+        $up = new Qiniu();
+        $data = $up->uploadVideo($filePath,$key);
+        echo $data;
+    }
+
+
+    /*
+     * wangEditor图片上传
+     */
+    public function wangUpload(){
+        foreach($_FILES as $key=>$vo){
+            $filePath = $vo['tmp_name'];
+            //取出图片后缀
+            $type = explode(".",$vo['name']);
+            $type = end($type);
+            //组装图片名
+            $key = md5(time().uuid()).'.'.$type;
+            $up = new Qiniu();
+            $name = $up->uploadFile($filePath,$key);
+            $data[] = config('qiniu.domain').$name;
+        }
+        return json(['errno'=>0,'data'=>$data]);
+    }
+
+
+    /**
+     * 百度富文本上传图片至第三方CDN接口
+     * @throws \Exception
+     */
+    public function ueditorUpload(){
+        $file = request()->file('upfile');
+        $info  = $file->getInfo();
+        //取出图片后缀
+        $type = explode(".",$info['name']);
+        $type = end($type);
+        //组装图片名
+        $key = md5(time().uuid()).'.'.$type;
+        $up = new Qiniu();
+        $data = $up->uploadFile($info['tmp_name'],$key);
+        //百度富文本上传文件到CDN upFile
+        $res = array(
+            "state"    => "SUCCESS",          //上传状态,上传成功时必须返回"SUCCESS"
+            "url"      => config('qiniu.domain').$data,            //CDN地址
+            "title"    => $key,          //新文件名
+            "original" => $info['tmp_name'],       //原始文件名
+            "type"     => ".".$type,           //文件类型
+            "size"     => $info['size'],           //文件大小
+        );
+        echo json_encode($res);
+    }
+
+    /**
+     * uploadLocality图片上传至本地&压缩
+     */
+    public function uploadLocality(){
+       // echo 1111; die;
+        $file = request()->file('file');
+        $dir = ROOT_PATH . 'public' . DS . 'uploads/images';
+        if(!file_exists($dir)){
+            //检查是否有该文件夹,如果没有就创建,并给予最高权限
+            mkdir($dir, 0700,true);
+        }
+//        $url = http_type ();
+        $info = $file->move($dir);
+        if($info){
+            $newName = $info->getSaveName();
+            //压缩图片
+//            image_png_size_add(ROOT_PATH . 'public' . DS . 'uploads/images/'.$newName,ROOT_PATH . 'public' . DS . 'uploads/images/'.$newName);
+            $path="/uploads/images/{$newName}";
+
+
+            return json(["code"=>200,"url"=>$path]);
+        }else{
+            echo $file->getError();
+        }
+    }
+    /**
+     * 后台图片上传至本地&压缩
+     */
+    public function uploadbackstage(){
+        $file = request()->file('file');
+        $dir = ROOT_PATH . 'public' . DS . 'uploads/images';
+        if(!file_exists($dir)){
+            //检查是否有该文件夹,如果没有就创建,并给予最高权限
+            mkdir($dir, 0700,true);
+        }
+//        $url = http_type ();
+        $info = $file->move($dir);
+        if($info){
+            $newName = $info->getSaveName();
+            //压缩图片
+//            image_png_size_add(ROOT_PATH . 'public' . DS . 'uploads/images/'.$newName,ROOT_PATH . 'public' . DS . 'uploads/images/'.$newName);
+            $path="/uploads/images/{$newName}";
+
+
+            return json(["code"=>200,"url"=>$path]);
+        }else{
+            echo $file->getError();
+        }
+    }
+    /**
+     * deleteLocality 删除本地图片
+     * @return \think\response\Json
+     */
+    public function deleteLocality(){
+        $add  = input('add');
+        $add = substr ($add,1);
+        if(unlink($add)){
+            return json(['code'=>200,'msg'=>'删除成功!']);
+        }else{
+            return json(['code'=>100,'msg'=>'删除失败!']);
+        }
+    }
+
+
+    /**
+     * video 视频文件上传至本地
+     */
+    public function video(){
+        @set_time_limit(5 * 60);
+        $targetDir = ROOT_PATH . 'public' . DS . 'uploads/video_tmp';
+        $uploadDir = ROOT_PATH . 'public' . DS . 'uploads/video/'.date('Ymd');
+        $cleanupTargetDir = true; // Remove old files
+        $maxFileAge = 5 * 3600; // Temp file age in seconds
+// Create target dir
+        if (!file_exists($targetDir)) {
+            @mkdir($targetDir,0700,true);
+        }
+
+// Create target dir
+        if (!file_exists($uploadDir)) {
+            @mkdir($uploadDir,0700,true);
+        }
+
+// Get a file name
+        if (!empty($_FILES)) {
+            $fileName = $_FILES["file"]["name"];
+        } else {
+            $fileName = uniqid("file_");
+        }
+
+        $filePath = $targetDir . DS . iconv("UTF-8","gb2312",$fileName);
+//        $uploadPath = $uploadDir . DS . iconv("UTF-8","gb2312",$fileName);
+
+// Chunking might be enabled
+        $chunk = isset($_REQUEST["chunk"]) ? intval($_REQUEST["chunk"]) : 0;
+        $chunks = isset($_REQUEST["chunks"]) ? intval($_REQUEST["chunks"]) : 1;
+
+// Remove old temp files
+        if ($cleanupTargetDir) {
+            if (!is_dir($targetDir) || !$dir = opendir($targetDir)) {
+                die('{"jsonrpc" : "2.0", "error" : {"code": 100, "message": "Failed to open temp directory."}, "id" : "id"}');
+            }
+
+            while (($file = readdir($dir)) !== false) {
+                $tmpfilePath = $targetDir . DS . $file;
+
+                // If temp file is current file proceed to the next
+                if ($tmpfilePath == "{$filePath}_{$chunk}.part" || $tmpfilePath == "{$filePath}_{$chunk}.parttmp") {
+                    continue;
+                }
+
+                // Remove temp file if it is older than the max age and is not the current file
+                if (preg_match('/\.(part|parttmp)$/', $file) && (@filemtime($tmpfilePath) < time() - $maxFileAge)) {
+                    @unlink($tmpfilePath);
+                }
+            }
+            closedir($dir);
+        }
+
+
+// Open temp file
+        if (!$out = @fopen("{$filePath}_{$chunk}.parttmp", "wb")) {
+            die('{"jsonrpc" : "2.0", "error" : {"code": 102, "message": "Failed to open output stream."}, "id" : "id"}');
+        }
+
+        if (!empty($_FILES)) {
+            if ($_FILES["file"]["error"] || !is_uploaded_file($_FILES["file"]["tmp_name"])) {
+                die('{"jsonrpc" : "2.0", "error" : {"code": 103, "message": "Failed to move uploaded file."}, "id" : "id"}');
+            }
+            // Read binary input stream and append it to temp file
+            if (!$in = @fopen($_FILES["file"]["tmp_name"], "rb")) {
+                die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": "Failed to open input stream."}, "id" : "id"}');
+            }
+        } else {
+            if (!$in = @fopen("php://input", "rb")) {
+                die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": "Failed to open input stream."}, "id" : "id"}');
+            }
+        }
+        while ($buff = fread($in, 4096)) {
+            fwrite($out, $buff);
+        }
+        @fclose($out);
+        @fclose($in);
+        rename("{$filePath}_{$chunk}.parttmp", "{$filePath}_{$chunk}.part");
+        $index = 0;
+        $done = true;
+        for( $index = 0; $index < $chunks; $index++ ) {
+            if ( !file_exists("{$filePath}_{$index}.part") ) {
+                $done = false;
+                break;
+            }
+        }
+        if ( $done ) {
+            $name = uuid();
+//            if (!file_exists($uploadDir . DS . $name)) {
+                @mkdir($uploadDir . DS . $name,0700,true);
+//            }
+            $uploadPath = $uploadDir . DS . $name . DS . iconv("UTF-8","gb2312",$fileName);
+            if (!$out = @fopen($uploadPath, "wb")) {
+                die('{"jsonrpc" : "2.0", "error" : {"code": 102, "message": "Failed to open output stream."}, "id" : "id"}');
+            }
+
+            if ( flock($out, LOCK_EX) ) {
+                for( $index = 0; $index < $chunks; $index++ ) {
+                    if (!$in = @fopen("{$filePath}_{$index}.part", "rb")) {
+                        break;
+                    }
+
+                    while ($buff = fread($in, 4096)) {
+                        fwrite($out, $buff);
+                    }
+
+                    @fclose($in);
+                    @unlink("{$filePath}_{$index}.part");
+                }
+
+                flock($out, LOCK_UN);
+            }
+            @fclose($out);
+            echo 'uploads/video/'.date('Ymd'). '/' .$name. '/' .$fileName;
+        }
+    }
+
+
+
+    //后台用户修改头像上传
+    public function updateFace(){
+        $base64url = input('base64url');
+        $arr = base64_img($base64url,true);
+        if($arr['code'] == 200){
+            $res = Db::name('admin')->where('id',input('id'))->update(["portrait"=>$arr['msg']]);
+            if($res){
+                session('portrait', $arr['msg']); //用户头像
+                return json(['code'=>200,'msg'=>"上传成功"]);
+            }else{
+                return json(['code'=>100,'msg'=>"上传失败"]);
+            }
+        }elseif($arr['code'] == 100){
+            writelog('管理员上传头像失败',100);
+            return json($arr);
+        }
+    }
+
+    //多图修改测试页面
+    public function showImg(){
+        $photo = Db::name('img')->where('id',1)->value('img');
+        $arr = explode(',',$photo);
+        $this->assign ('photo',$photo);
+        $this->assign ('arr',$arr);
+        return $this->fetch('/webuploader2');
+    }
+}

+ 393 - 0
application/admin/controller/User.php

@@ -0,0 +1,393 @@
+<?php
+
+namespace app\admin\controller;
+use app\admin\model\UserModel;
+use app\admin\model\UserType;
+use think\Db;
+use think\Session;
+
+class User extends Base
+{
+
+    /**
+     * [index 用户列表]
+     * @return [type] [description]
+     * @author
+     */
+    public function index(){
+        if(request()->isAjax ()){
+            extract(input());
+            $map = [];
+            if(isset($role)&&$role != ""){
+                $map['ag.id'] = $role;
+            }
+            if(isset($key)&&$key!="")
+            {
+                $map['a.username|a.real_name'] = ['like',"%" . $key . "%"];
+            }
+            if(isset($start)&&$start!=""&&isset($end)&&$end=="")
+            {
+                $map['a.last_login_time'] = ['>= time',$start];
+            }
+            if(isset($end)&&$end!=""&&isset($start)&&$start=="")
+            {
+                $map['a.last_login_time'] = ['<= time',$end];
+            }
+            if(isset($start)&&$start!=""&&isset($end)&&$end!="")
+            {
+                $map['a.last_login_time'] = ['between time',[$start,$end]];
+            }
+            $Nowpage = input('page') ? input('page'):1;
+            $limits = input("limit")?input("limit"):10;// 获取总条数;
+            $field=input('field');//字段
+            $order=input('order');//排序方式
+            if($field && $order){
+                $od="a.".$field." ".$order;
+            }else{
+                $od="a.create_time desc";
+            }
+            $user = new UserModel();
+            $count = $user->getUserCount($map);
+            $lists = $user->getUsersByWhere($map,$od, $Nowpage, $limits);
+            return json(['code'=>220,'msg'=>'','count'=>$count,'data'=>$lists]);
+        }
+        $role = Db::name('auth_group')->field('id,title')->order('create_time desc')->select();
+        $this->assign ('role',$role);
+        return $this->fetch("user/index");
+    }
+
+
+    /**
+     * [userAdd 添加用户]
+     * @return [type] [description]
+     * @author
+     */
+    public function userAdd()
+    {
+        if(request()->isPost()){
+            $param = input('post.');
+            $user = new UserModel();
+            $param['password'] = md5(md5($param['password']) . config('auth_key'));
+            $base64url = $param['portrait'];
+            $res = base64_img($base64url,true);
+            if($res['code'] == 200){
+                $param['portrait'] = $res['msg'];
+            }elseif($res['code'] == 100){
+                writelog('添加管理员【'.$param['username'].'】上传头像失败',100);
+                return json($res);
+            }
+            $flag = $user->insertUser($param);
+            return json(['code' => $flag['code'], 'data' => $flag['data'], 'msg' => $flag['msg']]);
+        }
+        $role = new UserType();
+        $this->assign('role',$role->getRole());
+        return $this->fetch('user/useradd');
+    }
+
+    /**
+     * checkName 验证管理员名称唯一性
+     */
+    public function checkName(){
+        extract(input());
+        if(isset($id)&&$id!=""){
+            $uid = $id;
+        }else{
+            $uid = '';
+        }
+        $user = new UserModel();
+        $flag =  $user->checkName ($username,$uid);
+        return json(['code' => $flag['code'], 'msg' => $flag['msg']]);
+    }
+
+    /**
+     * [userEdit 编辑用户]
+     * @return [type] [description]
+     * @author
+     */
+    public function userEdit()
+    {
+        $user = new UserModel();
+        if(request()->isPost()){
+            $param = input('post.');
+            if(empty($param['password'])){
+                unset($param['password']);
+            }else{
+                $param['password'] = md5(md5($param['password']) . config('auth_key'));
+            }
+            $base64url = $param['portrait'];
+            $res = base64_img($base64url,true);
+            $have = "";
+            if($res['code'] == 200){
+                $param['portrait'] = $res['msg'];
+                //判断编辑的是不是自己的头像
+                if(session('uid')==$param['id']){
+                    $have = "have";
+                }
+            }elseif($res['code'] == 100){
+                writelog('编辑管理员【'.$param['username'].'】上传头像失败',100);
+                return json($res);
+            }
+            $flag = $user->editUser($param);
+            return json(['code' => $flag['code'], 'data' => $flag['data'], 'msg' => $flag['msg'],'type'=>$have]);
+        }
+
+        $id = input('param.id');
+        if($id != "1"){
+            $role = new UserType();
+            $this->assign([
+                'user' => $user->getOneUser($id),
+                'role' => $role->getRole()
+            ]);
+            //普通管理员编辑页面
+            return $this->fetch("user/useredit");
+        }else{
+            $this->assign([
+                'user' => $user->getOneUser($id)
+            ]);
+            //超级管理员编辑页面
+            return $this->fetch("user/editadmin");
+        }
+
+    }
+
+    /**
+     * [adminEdit 编辑超级管理员]
+     * @return [type] [description]
+     * @author
+     */
+    public function adminEdit(){
+        $user = new UserModel();
+        $oldpassword = md5(md5(input('oldpassword')).config('auth_key'));
+        if(input('type')=="checkPassword"){
+            $flag =  $user->checkOldPassword ($oldpassword,session('uid'));
+            return json(['code' => $flag['code'], 'data' => $flag['data'], 'msg' => $flag['msg']]);
+        }else{
+            $param = input('post.');
+            if(empty($param['password'])){
+                unset($param['password']);
+            }else{
+                $param['password'] = md5(md5($param['password']) . config('auth_key'));
+            }
+            $base64url = $param['portrait'];
+            $res = base64_img($base64url,true);
+            $have = "";
+            if($res['code'] == 200){
+                $param['portrait'] = $res['msg'];
+                //判断编辑的是不是自己的头像
+                if(session('uid')==$param['id']){
+                    $have = "have";
+                }
+            }elseif($res['code'] == 100){
+                writelog('编辑管理员【'.$param['username'].'】上传头像失败',100);
+                return json($res);
+            }
+            $flag = $user->editUser($param);
+            return json(['code' => $flag['code'], 'data' => $flag['data'], 'msg' => $flag['msg'],'type'=>$have]);
+        }
+    }
+
+    /**
+     * [UserDel 删除用户]
+     * @return [type] [description]
+     * @author
+     */
+    public function UserDel()
+    {
+        $id = input('param.id');
+        if(session('uid')==$id){
+            return json(['code'=>100,'msg'=>'不能删除自己']);
+        }else{
+            $role = new UserModel();
+            $flag = $role->delUser($id);
+            return json(['code' => $flag['code'], 'data' => $flag['data'], 'msg' => $flag['msg']]);
+        }
+    }
+    
+
+    /**
+     * [user_state 用户状态]
+     * @return [type] [description]
+     * @author
+     */
+    public function user_state()
+    {
+        extract(input());
+        $role = new UserModel();
+        $flag = $role->userState($id,$num);
+        return json(['code' => $flag['code'], 'data' => $flag['data'], 'msg' => $flag['msg']]);
+    }
+
+
+    /**
+     * editPwd 修改管理员密码
+     * @return \think\response\Json
+     */
+    public function editPwd(){
+        extract(input());
+        $user = new UserModel();
+        if(isset($type) && $type=='checkPassword'){
+            $old_pwd = md5(md5($old_pwd).config('auth_key'));
+            $flag =  $user->checkOldPassword ($old_pwd,session('uid'));
+            return json(['code'=>$flag['code'],'msg'=>$flag['msg']]);
+        }else{
+            $param['password'] = md5(md5($new_pwd).config('auth_key'));
+            $flag = $user->editPassword($param);
+            return json(['code'=>$flag['code'],'msg'=>$flag['msg']]);
+        }
+    }
+
+    /**
+     * batchDelUser 批量删除管理员
+     * @return \think\response\Json
+     */
+    public function batchDelUser(){
+        extract(input());
+        if(empty($ids)){
+            return json(['code'=>100,'msg'=>'请选择要删除的记录!']);
+        }
+        $ids = explode(',',$ids);
+        if(in_array('1',$ids)){
+            $key = array_search ('1',$ids);
+            unset($ids[$key]);
+            if(empty($ids)){
+                return json(['code'=>100,'msg'=>'不可删除超级管理员']);
+                die;
+            }
+        }
+        if(in_array(session('uid'),$ids)){
+            $key = array_search (session('uid'),$ids);
+            unset($ids[$key]);
+            if(empty($ids)){
+                return json(['code'=>100,'msg'=>'不可删除自己']);
+                die;
+            }
+        }
+        $ids = array_merge($ids);
+        $user = new UserModel();
+        $flag = $user->batchDelUser($ids);
+        return json(['code' => $flag['code'], 'msg' => $flag['msg']]);
+    }
+
+
+    /**
+     * usingAdmin 批量启用管理员
+     * @return \think\response\Json
+     */
+    public function usingAdmin(){
+        extract(input());
+        $list = [];
+        if($ids){
+            $ids = explode(',',$ids);
+            for($i=0;$i<count($ids);$i++){
+                $param = [
+                    'id'=>$ids[$i],
+                    'status'=>1
+                ];
+                $list[] = $param;
+            }
+        }
+        $user = new UserModel();
+        $flag = $user->usingAdmin($list);
+        return json(['code' => $flag['code'], 'msg' => $flag['msg']]);
+    }
+
+    /**
+     * forbiddenAdmin 批量禁用管理员
+     * @return \think\response\Json
+     */
+    public function forbiddenAdmin(){
+        extract(input());
+        $list = [];
+        if($ids){
+            $ids = explode(',',$ids);
+            if(in_array('1',$ids)){
+                $key = array_search ('1',$ids);
+                unset($ids[$key]);
+                if(empty($ids)){
+                    return json(['code'=>100,'msg'=>'不可禁用超级管理员']);
+                    die;
+                }
+            }
+            if(in_array(session('uid'),$ids)){
+                $key = array_search (session('uid'),$ids);
+                unset($ids[$key]);
+                if(empty($ids)){
+                    return json(['code'=>100,'msg'=>'不可禁用自己']);
+                    die;
+                }
+            }
+            $ids = array_merge($ids);
+            for($i=0;$i<count($ids);$i++){
+                $param = [
+                    'id'=>$ids[$i],
+                    'status'=>2
+                ];
+                $list[] = $param;
+            }
+        }
+        $user = new UserModel();
+        $flag = $user->forbiddenAdmin($list);
+        return json(['code' => $flag['code'], 'msg' => $flag['msg']]);
+    }
+
+    /**
+     * 导出Excel
+     * @return \think\response\Json
+     */
+    public function excelAdmin(){
+        extract(input());
+        if($ids =="" && $key == "" && $start == "" && $end == "" && $role ==""){
+            $data = Db::name('admin')->select();
+        }
+        if($ids != ""){
+            $ids = trim($ids,',');
+            $ids = explode(',',$ids);
+            $data = Db::name('admin')->where('id','in',$ids)->select();
+        }else{
+            $map = [];
+            if($role != ""){
+                $map['ag.id'] = $role;
+            }
+            if($key!="")
+            {
+                $map['a.username|a.real_name'] = ['like',"%" . $key . "%"];
+            }
+            if($start!=""&&$end=="")
+            {
+                $map['a.last_login_time'] = ['>= time',$start];
+            }
+            if($end!=""&&$start=="")
+            {
+                $map['a.last_login_time'] = ['<= time',$end];
+            }
+            if($start!=""&&$end!="")
+            {
+                $map['a.last_login_time'] = ['between time',[$start,$end]];
+            }
+            $data = Db::name('admin')
+                ->alias ('a')
+                ->join('auth_group ag', 'a.groupid = ag.id','left')
+                ->field('a.id,username,a.password,a.portrait,a.loginnum,a.last_login_ip,a.last_login_time,a.real_name,phone,a.status,a.groupid,a.create_time,a.update_time')
+                ->where($map)
+                ->select();
+        }
+        $cellname = [
+            ['id','ID',15,'LEFT'],
+            ['username','昵称',15,'LEFT'],
+            ['password','密码',15,'LEFT'],
+            ['portrait','头像',20,'LEFT'],
+            ['loginnum','登录次数',15,'LEFT'],
+            ['last_login_ip','上次登录ip',15,'LEFT'],
+            ['last_login_time','上次登录时间',15,'LEFT'],
+            ['real_name','真实姓名',15,'LEFT'],
+            ['phone','手机号',15,'LEFT'],
+            ['status','状态',15,'LEFT'],
+            ['groupid','角色id',15,'LEFT'],
+            ['create_time','创建时间',15,'LEFT'],
+            ['update_time','修改时间',15,'LEFT']
+        ];
+        $res = exportExcel('管理员信息','admin',$cellname,$data);
+        return json($res);
+    }
+
+}

+ 98 - 0
application/admin/model/AipImageSearchModel.php

@@ -0,0 +1,98 @@
+<?php
+
+namespace app\admin\model;
+
+use think\Model;
+use think\Db;
+use ocr\AipImageSearch;
+use org\Qiniu;
+
+class AipImageSearchModel extends Model
+{
+    protected $name = 'ocrimage';
+    // 开启自动写入时间戳字段
+    protected $autoWriteTimestamp = true;
+
+    //显示
+    public function index($map, $Nowpage, $limits, $od)
+    {
+        return $this->alias('o')
+            //field('r.id,r.title,r.cate_id,r.photo,r.remark,r.keyword,r.content,r.views,r.type,r.is_tui,r.from,r.writer,r.ip,r.create_time,r.update_time,r.status,rc.name,r.music')
+            //->join('article_cate rc', 'r.cate_id = rc.id')
+            ->where($map)
+            ->page($Nowpage, $limits)
+            ->order($od)
+            ->select();
+    }
+
+    //图片添加
+    public function add($data)
+    {
+
+        $add = $this->allowField(true)->save($data);
+        //$add=1;
+        $oid = $this->oid;
+        //halt($data);
+        if ($add) {
+            $APP_ID = "17529719";
+            $API_KEY = "xSNZEGbH8BmG84b4UBcOjIm5";
+            $SRCRET_KEY = "0PEGcgmGQnTPWb7mqWSAZvBRqHcDEz9Z";
+            $client = new AipImageSearch($APP_ID, $API_KEY, $SRCRET_KEY);
+            //$image=$data["product_image"];
+            $image = file_get_contents(ROOT_PATH . 'public' . DS . $data["product_image"]);
+            //$image = ROOT_PATH . 'public' . DS . $data["product_image"];
+            //echo $dir;die;
+            // 如果有可选参数
+            $options = [];
+            $arr = ["name" => $data["pruduct_name"], "id" => $oid];
+            $options["brief"] = json_encode($arr);
+            $options["class_id1"] = 1;
+            $options["class_id2"] = 1;
+            //halt($options);
+            // 带参数调用商品图检索—入库, 图片参数为本地图片
+            $res = $client->productAdd($image, $options);
+            //halt($res);
+            if (isset($res["error_code"])) {
+                return json(["code" => 100, "msg" => "上传失败"]);
+            }
+            if ($res) {
+                return json(["code" => 200, "msg" => "上传成功"]);
+            } else {
+                return json(["code" => 100, "msg" => "上传失败"]);
+            }
+        } else {
+            return json(["code" => 100, "msg" => "添加失败"]);
+        }
+    }
+
+    //图库信息修改
+    public function edit($data)
+    {
+        $edit = $this->allowField(true)->save($data, ["oid" => $data['oid']]);
+        if ($edit) {
+            return json(["code" => 200, "msg" => "修改成功"]);
+        } else {
+            return json(["code" => 100, "msg" => "修改失败"]);
+        }
+    }
+
+    //图库删除
+    public function del($oid)
+    {
+        $data = $this->where("oid", $oid)->find();
+        $del = $this->where("oid", $oid)->delete();
+        $APP_ID = "17529719";
+        $API_KEY = "xSNZEGbH8BmG84b4UBcOjIm5";
+        $SRCRET_KEY = "0PEGcgmGQnTPWb7mqWSAZvBRqHcDEz9Z";
+        $client = new AipImageSearch($APP_ID, $API_KEY, $SRCRET_KEY);
+        $image = file_get_contents(ROOT_PATH . 'public' . DS . $data["product_image"]);
+        // 调用删除商品,传入参数为图片
+        $res = $client->productDeleteByImage($image);
+        if ($del && $res) {
+            return json(["code" => 200, "data" => "删除成功"]);
+        } else {
+            return json(["code" => 100, "data" => "删除失败"]);
+        }
+
+    }
+}

+ 208 - 0
application/admin/model/ArticleCateModel.php

@@ -0,0 +1,208 @@
+<?php
+
+namespace app\admin\model;
+use think\Model;
+use think\Db;
+
+class ArticleCateModel extends Model
+{
+    protected $name = 'article_cate';
+    
+    // 开启自动写入时间戳
+    protected $autoWriteTimestamp = true;
+
+
+    /**
+     * [getAllCate 获取全部分类]
+     * @author
+     */
+    public function getAllCate($map, $Nowpage, $limits,$od)
+    {
+        return $this->where($map)->page($Nowpage, $limits)->order($od)->select();
+    }
+
+    /**
+     * [getCate 获取全部分类]
+     * @author
+     */
+    public function getCate()
+    {
+        return $this->order('create_time desc')->select();
+    }
+
+    /**
+     * 根据条件获取所有配置信息数量
+     * @param $map
+     */
+    public function getAllCount($map)
+    {
+        return $this->where($map)->count();
+    }
+
+    /**
+     * [insertCate 添加分类]
+     * @author
+     */
+    public function insertCate($param)
+    {
+        Db::startTrans();// 启动事务
+        try{
+            $this->save($param);
+            Db::commit();// 提交事务
+            writelog(session('uid'),session('username'),'文章分类【'.$param['name'].'】添加成功',1);
+            return ['code' => 200, 'data' => '', 'msg' => '分类添加成功'];
+        }catch( \Exception $e){
+            Db::rollback();// 回滚事务
+            writelog(session('uid'),session('username'),'文章分类【'.$param['name'].'】添加失败',2);
+            return ['code' => 100, 'data' => '', 'msg' => '分类添加失败'];
+        }
+    }
+
+
+
+    /**
+     * [editMenu 编辑分类]
+     * @author
+     */
+    public function editCate($param)
+    {
+        Db::startTrans();// 启动事务
+        try{
+            $this->save($param, ['id' => $param['id']]);
+            Db::commit();// 提交事务
+            writelog(session('uid'),session('username'),'文章分类【'.$param['name'].'】编辑成功',1);
+            return ['code' => 200, 'data' => '', 'msg' => '分类编辑成功'];
+        }catch( \Exception $e){
+            Db::rollback();// 回滚事务
+            writelog(session('uid'),session('username'),'文章分类【'.$param['name'].'】编辑失败',2);
+            return ['code' => 100, 'data' => '', 'msg' => '分类编辑失败'];
+        }
+    }
+
+
+
+    /**
+     * [getOneMenu 根据分类id获取一条信息]
+     * @return [type] [description]
+     * @author
+     */
+    public function getOneCate($id)
+    {
+        return $this->where('id', $id)->find();
+    }
+
+
+
+    /**
+     * [delMenu 删除分类]
+     * @return [type] [description]
+     * @author
+     */
+    public function delCate($id)
+    {
+        $name = $this->where('id',$id)->value('name');
+        Db::startTrans();// 启动事务
+        try{
+            $this->where('id', $id)->delete();
+            Db::commit();// 提交事务
+            writelog(session('uid'),session('username'),'文章分类【'.$name.'】删除成功',1);
+            return ['code' => 200, 'data' => '', 'msg' => '分类删除成功'];
+        }catch( \Exception $e){
+            Db::rollback();// 回滚事务
+            writelog(session('uid'),session('username'),'文章分类【'.$name.'】删除失败',2);
+            return ['code' => 100, 'data' => '', 'msg' => '分类删除失败'];
+        }
+    }
+
+    /**
+     * batchDelCate 批量删除文章分类
+     * @param $param
+     * @return array
+     */
+    public function batchDelCate($param){
+        Db::startTrans();// 启动事务
+        try{
+            ArticleCateModel::destroy($param);
+            Db::commit();// 提交事务
+            writelog(session('uid'),session('username'),'文章分类批量删除成功',1);
+            return ['code' => 200, 'data' => '', 'msg' => '批量删除成功'];
+        }catch( \Exception $e){
+            Db::rollback();// 回滚事务
+            writelog(session('uid'),session('username'),'文章分类批量删除失败',2);
+            return ['code' => 100, 'data' => '', 'msg' => '批量删除失败'];
+        }
+    }
+
+    /**
+     * [cateState 文章分类状态]
+     * @param $param
+     * @return array
+     */
+    public function cateState($id,$num)
+    {
+        $name = Db::name('article_cate')->where(['id'=>$id])->value('name');//判断当前状态情况
+        if($num == 2){
+            $msg = '禁用';
+        }else{
+            $msg = '启用';
+        }
+        Db::startTrans();// 启动事务
+        try {
+            $this->where ('id' , $id)->setField (['status' => $num]);
+            Db::commit();// 提交事务
+            writelog (session ('uid') , session ('username') , '文章分类【' . $name . '】'.$msg.'成功' , 1);
+//                return ['code' => 200 , 'data' => '' , 'msg' => '已'.$msg];
+        } catch (\Exception $e) {
+            Db::rollback();// 回滚事务
+            writelog (session ('uid') , session ('username') , '文章分类【' . $name . '】'.$msg.'失败' , 2);
+            return ['code' => 100 , 'data' => '' , 'msg' => $msg.'失败'];
+        }
+    }
+
+    /**
+     * 批量禁用分类
+     * @param $param
+     * @return array
+     */
+    public function forbiddenCate($param){
+        Db::startTrans();// 启动事务
+        try{
+            if($param){
+                $this->saveAll($param);
+            }else{
+                $this->where('1=1')->update(['status'=>2]);
+            }
+            Db::commit();// 提交事务
+            writelog(session('uid'),session('username'),'批量禁用文章分类成功',1);
+            return ['code' => 200, 'data' => '', 'msg' => '批量禁用成功'];
+        }catch( \Exception $e){
+            Db::rollback ();//回滚事务
+            writelog(session('uid'),session('username'),'批量禁用文章分类失败',2);
+            return ['code' => 100, 'data' => '', 'msg' => '批量禁用失败'];
+        }
+    }
+
+    /**
+     * 批量启用分类
+     * @param $param
+     * @return array
+     */
+    public function usingCate($param){
+        Db::startTrans();// 启动事务
+        try{
+            if($param){
+                $this->saveAll($param);
+            }else{
+                $this->where('1=1')->update(['status'=>1]);
+            }
+            Db::commit();// 提交事务
+            writelog(session('uid'),session('username'),'批量启用文章分类成功',1);
+            return ['code' => 200, 'data' => '', 'msg' => '批量启用成功'];
+        }catch( \Exception $e){
+            Db::rollback ();//回滚事务
+            writelog(session('uid'),session('username'),'批量启用文章分类失败',2);
+            return ['code' => 100, 'data' => '', 'msg' => '批量启用失败'];
+        }
+    }
+
+}

+ 194 - 0
application/admin/model/ArticleModel.php

@@ -0,0 +1,194 @@
+<?php
+
+namespace app\admin\model;
+use think\Model;
+use think\Db;
+
+class ArticleModel extends Model
+{
+    protected $name = 'article';
+    
+    // 开启自动写入时间戳字段
+    protected $autoWriteTimestamp = true;
+
+
+    /**
+     * 根据搜索条件获取文章列表信息
+     * @author
+     */
+    public function getArticleByWhere($map, $Nowpage, $limits,$od)
+    {
+        return $this->alias ('r')
+            ->field('r.id,r.title,r.cate_id,r.photo,r.remark,r.keyword,r.content,r.views,r.type,r.is_tui,r.from,r.writer,r.ip,r.create_time,r.update_time,r.status,rc.name,r.music')
+            ->join('article_cate rc', 'r.cate_id = rc.id')
+            ->where($map)
+            ->page($Nowpage, $limits)
+            ->order($od)
+            ->select();
+    }
+    
+    
+    /**
+     * [insertArticle 添加文章]
+     * @author
+     */
+    public function insertArticle($param)
+    {
+        Db::startTrans();// 启动事务
+        try{
+            $this->allowField(true)->save($param);
+            Db::commit();// 提交事务
+            writelog(session('uid'),session('username'),'文章【'.$param['title'].'】添加成功',1);
+            return ['code' => 200, 'data' => '', 'msg' => '文章添加成功'];
+        }catch( \Exception $e){
+            Db::rollback();// 回滚事务
+            writelog(session('uid'),session('username'),'文章【'.$param['title'].'】添加失败',2);
+            return ['code' => 100, 'data' => '', 'msg' =>'文章添加失败'];
+        }
+    }
+
+
+
+    /**
+     * [updateArticle 编辑文章]
+     * @author
+     */
+    public function updateArticle($param)
+    {
+        Db::startTrans();// 启动事务
+        try{
+            $this->allowField(true)->save($param, ['id' => $param['id']]);
+            Db::commit();// 提交事务
+            writelog(session('uid'),session('username'),'文章【'.$param['title'].'】编辑成功',1);
+            return ['code' => 200, 'data' => '', 'msg' => '文章编辑成功'];
+        }catch( \Exception $e){
+            Db::rollback();// 回滚事务
+            writelog(session('uid'),session('username'),'文章【'.$param['title'].'】编辑失败',2);
+            return ['code' => 100, 'data' => '', 'msg' => '文章编辑失败'];
+        }
+    }
+
+
+
+    /**
+     * [getOneArticle 根据文章id获取一条信息]
+     * @author
+     */
+    public function getOneArticle($id)
+    {
+        return $this->where('id', $id)->find();
+    }
+
+
+
+    /**
+     * [delArticle 删除文章]
+     * @author
+     */
+    public function delArticle($id)
+    {
+        $title = $this->where('id',$id)->value('title');
+        Db::startTrans();// 启动事务
+        try{
+            $this->where('id', $id)->delete();
+            Db::commit();// 提交事务
+            writelog(session('uid'),session('username'),'文章【'.$title.'】删除成功',1);
+            return ['code' => 200, 'data' => '', 'msg' => '文章删除成功'];
+        }catch( \Exception $e){
+            Db::rollback();// 回滚事务
+            writelog(session('uid'),session('username'),'文章【'.$title.'】删除失败',2);
+            return ['code' => 100, 'data' => '', 'msg' =>  '文章删除失败'];
+        }
+    }
+
+    /**
+     * batchDelArticle 批量删除文章
+     * @param $param
+     * @return array
+     */
+    public function batchDelArticle($param){
+        Db::startTrans();// 启动事务
+        try{
+            ArticleModel::destroy($param);
+            Db::commit();// 提交事务
+            writelog(session('uid'),session('username'),'文章批量删除成功',1);
+            return ['code' => 200, 'data' => '', 'msg' => '批量删除成功'];
+        }catch( \Exception $e){
+            Db::rollback();// 回滚事务
+            writelog(session('uid'),session('username'),'文章批量删除失败',1);
+            return ['code' => 100, 'data' => '', 'msg' => '批量删除失败'];
+        }
+    }
+
+    /**
+     * [articleState 文章状态]
+     * @param $param
+     * @return array
+     */
+    public function articleState($id,$num){
+        $title = $this->where('id',$id)->value('title');
+        if($num == 2){
+            $msg = '禁用';
+        }else{
+            $msg = '启用';
+        }
+        Db::startTrans();// 启动事务
+        try{
+            $this->where('id',$id)->setField(['status'=>$num]);
+            Db::commit();// 提交事务
+            writelog(session('uid'),session('username'),'文章【'.$title.'】'.$msg.'成功',1);
+//                return ['code' => 200, 'data' => '', 'msg' => '已'.$msg];
+        }catch( \Exception $e){
+            Db::rollback();// 回滚事务
+            writelog(session('uid'),session('username'),'文章【'.$title.'】'.$msg.'失败',2);
+            return ['code' => 100, 'data' => '', 'msg' => $msg.'失败'];
+        }
+    }
+
+    /**
+     * 批量禁用文章
+     * @param $param
+     * @return array
+     */
+    public function forbiddenArticle($param){
+        Db::startTrans();// 启动事务
+        try{
+            if($param){
+                $this->saveAll($param);
+            }else{
+                $this->where('1=1')->update(['status'=>2]);
+            }
+            Db::commit();// 提交事务
+            writelog(session('uid'),session('username'),'批量禁用文章成功',1);
+            return ['code' => 200, 'data' => '', 'msg' => '批量禁用成功'];
+        }catch( \Exception $e){
+            Db::rollback ();//回滚事务
+            writelog(session('uid'),session('username'),'批量禁用文章失败',2);
+            return ['code' => 100, 'data' => '', 'msg' => '批量禁用失败'];
+        }
+    }
+
+    /**
+     * 批量启用文章
+     * @param $param
+     * @return array
+     */
+    public function usingArticle($param){
+        Db::startTrans();// 启动事务
+        try{
+            if($param){
+                $this->saveAll($param);
+            }else{
+                $this->where('1=1')->update(['status'=>1]);
+            }
+            Db::commit();// 提交事务
+            writelog(session('uid'),session('username'),'批量启用文章成功',1);
+            return ['code' => 200, 'data' => '', 'msg' => '批量启用成功'];
+        }catch( \Exception $e){
+            Db::rollback ();//回滚事务
+            writelog(session('uid'),session('username'),'批量启用文章失败',2);
+            return ['code' => 100, 'data' => '', 'msg' => '批量启用失败'];
+        }
+    }
+
+}

+ 37 - 0
application/admin/model/ChartModel.php

@@ -0,0 +1,37 @@
+<?php
+namespace app\admin\model;
+
+use think\Controller;
+use think\Db;
+use think\Model;
+class ChartModel extends Model
+{
+    protected $name = 'chart';
+    // 开启自动写入时间戳字段
+    protected $autoWriteTimestamp = true;
+    public function index()
+    {
+        return $data=$this->select();
+    }
+    public function add($data)
+    {
+
+        $add=$this->allowField(true)->save($data);
+        if($add){
+            return json(["code"=>200,"msg"=>"添加成功"]);
+        }else{
+            return json(["code"=>100,"msg"=>"添加失败"]);
+        }
+    }
+    public function edit($data)
+    {
+        //echo $data["cid"];
+        $edit=$this->allowField(true)->save($data,['cid'=>$data['cid']]);
+        if($edit){
+            return json(["code"=>200,"msg"=>"修改成功"]);
+        }else{
+            return json(["code"=>100,"msg"=>"修改失败"]);
+        }
+    }
+
+}

+ 242 - 0
application/admin/model/ConfigModel.php

@@ -0,0 +1,242 @@
+<?php
+
+namespace app\admin\model;
+use think\Model;
+use think\Db;
+
+class ConfigModel extends Model
+{
+    protected $name = 'config';
+
+    // 开启自动写入时间戳
+    protected $autoWriteTimestamp = true;
+
+    /**
+     * 根据条件获取配置列表信息
+     */
+    public function getAllConfig($map, $nowpage, $limits,$od)
+    {
+        $data = $this->where($map)->page($nowpage, $limits)->order($od)->select();
+        for($i=0;$i<count($data);$i++){
+            $data[$i]['type'] =  get_config_type( $data[$i]['type']);
+            $data[$i]['group'] =  get_config_group( $data[$i]['group']);
+        }
+        return $data;
+    }
+
+    /**
+     * 根据条件获取所有配置信息数量
+     * @param $map
+     */
+    public function getAllCount($map)
+    {
+        return $this->where($map)->count();
+    }
+
+    /**
+     * 验证配置标识的唯一性
+     */
+    public function checkConfig($name,$uid){
+        if($uid != ''){
+            $uname = $this->where('id',$uid)->value('name');
+            if($uname == $name){
+                return ['code' => 200, 'msg' => 'true'];
+            }
+        }
+        $result = $this->where('name',$name)->find();
+        if($result){
+            return ['code' => 100, 'msg' => 'false'];
+        }else{
+            return ['code' => 200, 'msg' => 'true'];
+        }
+    }
+
+    /**
+     * [insertConfig 添加配置信息]
+     * @param $param
+     */
+    public function insertConfig($param)
+    {
+        Db::startTrans();// 启动事务
+        try{
+            $this->allowField(true)->save($param);
+            Db::commit();// 提交事务
+            writelog('配置【'.$param['name'].'】添加成功',200);
+            return ['code' => 200, 'data' => '', 'msg' => '添加成功'];
+        }catch( \Exception $e){
+            Db::rollback();// 回滚事务
+            writelog('配置【'.$param['name'].'】添加失败',100);
+            return ['code' => 100, 'data' => '', 'msg' => '添加失败'];
+        }
+    }
+
+    /**
+     * 编辑信息
+     * @param $param
+     */
+    public function editConfig($param)
+    {
+        Db::startTrans();// 启动事务
+        try{
+            $this->allowField(true)->save($param, ['id' => $param['id']]);
+            Db::commit();// 提交事务
+            writelog('配置【'.$param['name'].'】编辑成功',200);
+            return ['code' => 200, 'data' => '', 'msg' => '编辑成功'];
+        }catch( \Exception $e){
+            Db::rollback();// 回滚事务
+            writelog('配置【'.$param['name'].'】编辑失败',100);
+            return ['code' => 100, 'data' => '', 'msg' => '编辑失败'];
+        }
+    }
+
+
+    /**
+     * 根据id获取配置信息
+     * @param $id
+     */
+    public function getOneConfig($id)
+    {
+        return $this->where('id', $id)->find();
+    }
+
+
+    /**
+     * 删除配置
+     * @param $id
+     */
+    public function delConfig($id)
+    {
+        $name = $this->where('id',$id)->value('name');
+        Db::startTrans();// 启动事务
+        try{
+            $this->where('id', $id)->delete();
+            Db::commit();// 提交事务
+            writelog('配置【'.$name.'】删除成功',200);
+            return ['code' => 200, 'data' => '', 'msg' => '删除成功'];
+        }catch( \Exception $e){
+            Db::rollback();// 回滚事务
+            writelog('配置【'.$name.'】删除失败',100);
+            return ['code' => 100, 'data' => '', 'msg' => '删除失败'];
+        }
+    }
+
+    /**
+     * batchDelConfig 批量删除配置
+     * @param $param
+     * @return array
+     */
+    public function batchDelConfig($param){
+        Db::startTrans();// 启动事务
+        try{
+            ConfigModel::destroy($param);
+            Db::commit();// 提交事务
+            writelog('配置批量删除成功',200);
+            return ['code' => 200, 'data' => '', 'msg' => '批量删除成功'];
+        }catch( \Exception $e){
+            Db::rollback();// 回滚事务
+            writelog('配置批量删除失败',100);
+            return ['code' => 100, 'data' => '', 'msg' => '批量删除失败'];
+        }
+    }
+
+    /**
+     * [configState 配置状态]
+     * @param $param
+     * @return array
+     */
+    public function configState($id,$num){
+        $name = $this->where('id',$id)->value('name');
+        if($num == 2){
+            $msg = '禁用';
+        }else{
+            $msg = '启用';
+        }
+        Db::startTrans();// 启动事务
+        try{
+            $this->where('id',$id)->setField(['status'=>$num]);
+            Db::commit();// 提交事务
+            writelog('配置【'.$name.'】'.$msg.'成功',200);
+//                return ['code' => 200, 'data' => '', 'msg' => '已'.$msg];
+        }catch( \Exception $e){
+            Db::rollback();// 回滚事务
+            writelog('配置【'.$name.'】'.$msg.'失败',100);
+            return ['code' => 100, 'data' => '', 'msg' => $msg.'失败'];
+        }
+    }
+
+    /**
+     * configSave 保存配置
+     * @param $config
+     * @return array
+     */
+    public function configSave($config){
+        Db::startTrans();// 启动事务
+        try{
+            if($config && is_array($config)){
+                foreach ($config as $name => $value) {
+                    if($name == "list_rows"){
+                        if($value<=0){
+                            $value = 1;
+                        }
+                    }
+                    $map = array('name' => $name);
+                    $this->where($map)->setField('value', $value);
+                }
+            }
+            Db::commit();// 提交事务
+            writelog('配置保存成功',200);
+            return ['code' => 200, 'data' => '', 'msg' => '保存成功'];
+        }catch( \Exception $e){
+            Db::rollback();// 回滚事务
+            writelog('配置保存失败',100);
+            return ['code' => 100, 'data' => '', 'msg' => '保存失败'];
+        }
+    }
+
+    /**
+     * 批量禁用配置
+     * @param $param
+     * @return array
+     */
+    public function forbiddenConfig($param){
+        Db::startTrans();// 启动事务
+        try{
+            if($param){
+                $this->saveAll($param);
+            }else{
+                $this->where('1=1')->update(['status'=>2]);
+            }
+            Db::commit();// 提交事务
+            writelog('批量禁用配置成功',200);
+            return ['code' => 200, 'data' => '', 'msg' => '批量禁用成功'];
+        }catch( \Exception $e){
+            Db::rollback ();//回滚事务
+            writelog('批量禁用配置失败',100);
+            return ['code' => 100, 'data' => '', 'msg' => '批量禁用失败'];
+        }
+    }
+
+    /**
+     * 批量启用配置
+     * @param $param
+     * @return array
+     */
+    public function usingConfig($param){
+        Db::startTrans();// 启动事务
+        try{
+            if($param){
+                $this->saveAll($param);
+            }else{
+                $this->where('1=1')->update(['status'=>1]);
+            }
+            Db::commit();// 提交事务
+            writelog('批量启用配置成功',200);
+            return ['code' => 200, 'data' => '', 'msg' => '批量启用成功'];
+        }catch( \Exception $e){
+            Db::rollback ();//回滚事务
+            writelog('批量启用配置失败',100);
+            return ['code' => 100, 'data' => '', 'msg' => '批量启用失败'];
+        }
+    }
+
+}

+ 41 - 0
application/admin/model/LogModel.php

@@ -0,0 +1,41 @@
+<?php
+
+namespace app\admin\model;
+use think\Model;
+
+class LogModel extends Model
+{
+    protected $name = 'log';
+
+    /**
+     * 删除日志
+     */
+    public function delLog($log_id)
+    {
+        try{
+            $this->where('log_id', $log_id)->delete();
+            writelog('日志【ID='.$log_id.'】删除成功',200,'','','true');
+            return ['code' => 200, 'data' => '', 'msg' => '删除日志成功'];
+        }catch( PDOException $e){
+            writelog('日志【ID='.$log_id.'】删除失败',100,'','','true');
+            return ['code' => 100, 'data' => '', 'msg' => '删除日志失败'];
+        }
+    }
+
+    /**
+     * batchDelLog 批量删除日志
+     * @param $param
+     * @return array
+     */
+    public function batchDelLog($param){
+        try{
+            LogModel::destroy($param);
+            writelog('日志批量删除成功',200,'','','true');
+            return ['code' => 200, 'data' => '', 'msg' => '批量删除成功'];
+        }catch( PDOException $e){
+            writelog('日志批量删除失败',100,'','','true');
+            return ['code' => 100, 'data' => '', 'msg' => '批量删除失败'];
+        }
+    }
+
+}

+ 240 - 0
application/admin/model/MenuModel.php

@@ -0,0 +1,240 @@
+<?php
+
+namespace app\admin\model;
+use think\Model;
+use think\Db;
+
+class MenuModel extends Model
+{
+    protected $name = 'auth_rule';
+    
+    // 开启自动写入时间戳字段
+    protected $autoWriteTimestamp = true;
+
+
+    /**
+     * [getMenus 获取全部菜单]
+     * @author
+     */
+    public function getMenus($map,$Nowpage,$limits)
+    {
+        return $this->where($map)->page($Nowpage,$limits)->order('id asc')->select()->toArray();
+    }
+
+    /**
+     * [getAllMenu 获取全部菜单]
+     * @author
+     */
+    public function getAllMenu($map)
+    {
+        return $this->where($map)->order('id asc')->select()->toArray ();
+    }
+
+    /**
+     * [insertMenu 添加菜单]
+     * @author
+     */
+    public function insertMenu($pid,$title,$name,$css,$sort,$status)
+    {
+        if(count($pid) == 1){
+            Db::startTrans();// 启动事务
+            try{
+                if(count($name) != count($title) || count($name) != count($css) || count($name) != count($sort)){
+                    return ['code'=>100, 'data' => '','msg'=>'参数格式错误!'];
+                }
+                for($i=0;$i<count($name);$i++){
+                    $t = $title[$i];
+//                    $n = strtolower($name[$i]);
+                    $n = $name[$i];
+                    $c = $css[$i];
+                    $id = $pid[0];
+                    $s = $sort[$i];
+                    $param = [
+                        'pid'=>$id,
+                        'title'=>$t,
+                        'name'=>$n,
+                        'css'=>$c,
+                        'sort'=>$s,
+                        'status'=>$status
+                    ];
+                    $list[] = $param;
+                }
+                $this->saveAll($list);
+                writelog('多菜单添加成功',200);
+                Db::commit();// 提交事务
+                return ['code' => 200, 'data' => '', 'msg' => '添加菜单成功'];
+            }catch( \Exception $e){
+                Db::rollback ();//回滚事务
+                writelog('多菜单添加失败',100);
+                return ['code' => 100, 'data' => '', 'msg' => '菜单添加失败'];
+            }
+        }else{
+            Db::startTrans();// 启动事务
+            try{
+                if(count($pid) != count($title) || count($pid) != count($name) || count($pid) != count($css) || count($pid) != count($sort)){
+                    return ['code'=>100, 'data' => '','msg'=>'参数格式错误!'];
+                }
+                for($i=0;$i<count($pid);$i++){
+                    $t = $title[$i];
+//                    $n = strtolower($name[$i]);
+                    $n = $name[$i];
+                    $c = $css[$i];
+                    $id = $pid[$i];
+                    $s = $sort[$i];
+                    $param = [
+                        'pid'=>$id,
+                        'title'=>$t,
+                        'name'=>$n,
+                        'css'=>$c,
+                        'sort'=>$s,
+                        'status'=>$status
+                    ];
+                    $list[] = $param;
+                }
+                $this->saveAll($list);
+                writelog('多菜单添加成功',200);
+                Db::commit();// 提交事务
+                return ['code' => 200, 'data' => '', 'msg' => '添加菜单成功'];
+            }catch( \Exception $e){
+                Db::rollback ();//回滚事务
+                writelog('多菜单添加失败',100);
+                return ['code' => 100, 'data' => '', 'msg' => '菜单添加失败'];
+            }
+        }
+    }
+
+
+
+    /**
+     * [editMenu 编辑菜单]
+     * @author
+     */
+    public function editMenu($param)
+    {
+        Db::startTrans();// 启动事务
+        try{
+            $this->allowField(true)->save($param, ['id' => $param['id']]);
+            Db::commit();// 提交事务
+            writelog('菜单【'.$param['title'].'】编辑成功',200);
+            return ['code' => 200, 'data' => '', 'msg' => '编辑菜单成功'];
+        }catch( \Exception $e){
+            Db::rollback ();//回滚事务
+            writelog('菜单【'.$param['title'].'】编辑失败',100);
+            return ['code' => 100, 'data' => '', 'msg' => '编辑菜单失败'];
+        }
+    }
+
+
+
+    /**
+     * [getOneMenu 根据菜单id获取一条信息]
+     * @author
+     */
+    public function getOneMenu($id)
+    {
+        return $this->where('id', $id)->find();
+    }
+
+
+
+    /**
+     * [delMenu 删除菜单]
+     * @author
+     */
+    public function delMenu($id,$param)
+    {
+        $title = $this->where('id', $id)->value('title');
+        Db::startTrans();// 启动事务
+        try{
+//            $this->where('id', $id)->delete();
+            MenuModel::destroy($param);
+            Db::commit();// 提交事务
+            $ids = implode(',',$param);
+            writelog('菜单【'.$title.'】删除成功',200);
+            return ['code' => 200, 'data' => $ids, 'msg' => '删除菜单成功'];
+        }catch( \Exception $e){
+            Db::rollback ();//回滚事务
+            writelog('菜单【'.$title.'】删除失败',100);
+            return ['code' => 100, 'data' => '', 'msg' => '删除菜单失败'];
+        }
+    }
+
+    /**
+     * batchDelMenu 批量删除菜单
+     * @param $param
+     * @return array
+     */
+    public function batchDelMenu($param){
+        Db::startTrans();// 启动事务
+        try{
+            MenuModel::destroy($param);
+            Db::commit();// 提交事务
+            $ids = implode(',',$param);
+            writelog('菜单批量删除成功',200);
+            return ['code' => 200, 'data' => $ids, 'msg' => '批量删除成功'];
+        }catch( \Exception $e){
+            Db::rollback ();//回滚事务
+            writelog('菜单批量删除失败',100);
+            return ['code' => 100, 'data' => '', 'msg' => '批量删除失败'];
+        }
+    }
+
+//    /**
+//     * [ruleSort 菜单排序]
+//     * @param $param
+//     * @return array
+//     */
+//    public function ruleSort($id,$field,$value){
+//        Db::startTrans();// 启动事务
+//        try{
+//            $this->where(['id' => $id ])->setField($field , $value);
+//            Db::commit();// 提交事务
+//            writelog('菜单排序更新成功',200);
+//            return ['code' => 200,'data' => '', 'msg' => '排序更新成功'];
+//        }catch( \Exception $e){
+//            Db::rollback ();//回滚事务
+//            writelog('菜单排序更新失败',100);
+//            return ['code' => 100, 'data' => '', 'msg' => '排序更新失败'];
+//        }
+//    }
+
+//    public function editField($id,$field,$value){
+//        Db::startTrans();// 启动事务
+//        try{
+//            $this->where(['id' => $id ])->setField($field , $value);
+//            Db::commit();// 提交事务
+//            writelog('更新字段成功',200);
+//            return ['code' => 200,'data' => '', 'msg' => '更新字段成功'];
+//        }catch( \Exception $e){
+//            Db::rollback ();//回滚事务
+//            writelog('更新字段失败',100);
+//            return ['code' => 100, 'data' => '', 'msg' => '更新字段失败'];
+//        }
+//    }
+
+    /**
+     * [ruleState 菜单状态]
+     * @param $param
+     * @return array
+     */
+    public function ruleState($id,$num){
+        $title = $this->where('id',$id)->value('title');
+        if($num == 2){
+            $msg = '禁用';
+        }else{
+            $msg = '启用';
+        }
+        Db::startTrans();// 启动事务
+        try{
+            $this->where('id',$id)->setField(['status'=>$num]);
+            Db::commit();// 提交事务
+            writelog('菜单【'.$title.'】'.$msg.'成功',200);
+//                return ['code' => 200, 'data' => '', 'msg' => '已'.$msg];
+        }catch( \Exception $e){
+            Db::rollback ();//回滚事务
+            writelog('菜单【'.$title.'】'.$msg.'失败',100);
+            return ['code' => 100, 'data' => '', 'msg' => $msg.'失败'];
+        }
+    }
+
+}

+ 70 - 0
application/admin/model/Node.php

@@ -0,0 +1,70 @@
+<?php
+
+namespace app\admin\model;
+use think\Model;
+use think\Db;
+
+class Node extends Model
+{
+
+    protected $name = "auth_rule";
+
+
+    /**
+     * [getNodeInfo 获取节点数据]
+     * @author
+     */
+    public function getNodeInfo($id)
+    {
+        $result = $this->field('id,title,pid,sort')->select()->toArray ();
+        for($i=0;$i<count($result);$i++){
+            $sort[] = $result[$i]['sort'];
+        }
+        array_multisort($sort, SORT_ASC, $result);
+        $str = "";
+        $role = new UserType();
+        $rule = $role->getRuleById($id);
+
+        if(!empty($rule)){
+            $rule = explode(',', $rule);
+        }
+        foreach($result as $key=>$vo){
+            $str .= '{ "id": "' . $vo['id'] . '", "pId":"' . $vo['pid'] . '", "name":"' . $vo['title'].'"';
+
+            if(!empty($rule) && in_array($vo['id'], $rule)){
+                $str .= ' ,"checked":1';
+            }
+
+            $str .= '},';
+        }
+
+        return "[" . substr($str, 0, -1) . "]";
+    }
+
+
+    /**
+     * [getMenu 根据节点数据获取对应的菜单]
+     * @author
+     */
+    public function getMenu($nodeStr="")
+    {
+        //超级管理员没有节点数组
+        if($nodeStr == "SUPERAUTH"){
+            if(session('?security') && session('security') == 010){
+                $where = array();
+            }else{
+                $where = 'status = 1';
+            }
+            $result = Db::name('auth_rule')->where($where)->order('sort')->select();
+        }elseif(empty($nodeStr)){
+            $result = array();
+        }else{
+            $where = 'status = 1 and id in('.$nodeStr.')';
+            $result = Db::name('auth_rule')->where($where)->order('sort')->select();
+        }
+//        $where = empty($nodeStr) ? array() : 'status = 1 and id in('.$nodeStr.')';
+
+        $menu = prepareMenu($result);
+        return $menu;
+    }
+}

+ 278 - 0
application/admin/model/UserModel.php

@@ -0,0 +1,278 @@
+<?php
+
+namespace app\admin\model;
+use think\Model;
+use think\Db;
+
+class UserModel extends Model
+{
+    protected $name = 'admin';
+    protected $autoWriteTimestamp = true;   // 开启自动写入时间戳
+    /**
+     * 根据搜索条件获取用户列表信息
+     */
+    public function getUsersByWhere($map,$od, $Nowpage, $limits)
+    {
+        return $this->alias ('a')
+            ->join('auth_group ag', 'a.groupid = ag.id','left')
+            ->field('a.id,a.username,a.password,a.portrait,a.loginnum,a.last_login_ip,a.last_login_time,a.real_name,a.status,a.phone,a.groupid,a.create_time,a.update_time,ag.title')
+            ->where($map)
+            ->page($Nowpage, $limits)
+            ->order($od)
+            ->select();
+    }
+
+    /*
+     * 总页面数
+     */
+    public function getUserCount($map){
+       return $this->alias('a')
+            ->join('auth_group ag', 'a.groupid = ag.id','left')
+            ->where($map)
+            ->count();
+    }
+
+    /**
+     * 根据搜索条件获取所有的用户数量
+     * @param $where
+     */
+    public function getAllUsers($where)
+    {
+        return $this->where($where)->count();
+    }
+
+    /**
+     * 插入管理员信息
+     * @param $param
+     */
+    public function insertUser($param)
+    {
+        Db::startTrans();// 启动事务
+        try{
+            $this->allowField(true)->save($param);
+            Db::name('auth_group_access')->insert(['uid'=> $this->id,'group_id'=> $param['groupid']]);
+            Db::commit();// 提交事务
+            writelog('管理员【'.$param['username'].'】添加成功',200);
+            return ['code' => 200, 'data' =>"", 'msg' => '添加管理员成功'];
+        }catch( \Exception $e){
+            Db::rollback ();//回滚事务
+            writelog('管理员【'.$param['username'].'】添加失败',100);
+            return ['code' => 100, 'data' => '', 'msg' => '添加管理员失败'];
+        }
+    }
+
+    /**
+     * 编辑管理员信息
+     * @param $param
+     */
+    public function editUser($param)
+    {
+        Db::startTrans();// 启动事务
+        try{
+            $this->allowField(true)->save($param, ['id' => $param['id']]);
+            if($param['id'] != 1){
+                Db::name('auth_group_access')->where('uid',$param['id'])->setField ('group_id',$param['groupid']);
+            }
+            Db::commit();// 提交事务
+            writelog('管理员【'.$param['username'].'】编辑成功',200);
+            $status = '';
+            if($param['id']==session('uid')){
+                session('portrait', $param['portrait']); //用户头像
+                if(isset($param['password']) && $param['password'] != ""){
+                    $status = 100;
+                }
+            }
+            return ['code' => 200, 'data' => $status, 'msg' => '编辑用户成功'];
+        }catch( \Exception $e){
+            Db::rollback ();//回滚事务
+            writelog('管理员【'.$param['username'].'】编辑失败',100);
+            return ['code' => 100, 'data' => '', 'msg' =>'编辑用户失败'];
+        }
+    }
+
+
+    /**
+     * 验证原始密码
+     * @param $param
+     */
+    public function checkOldPassword($oldpassword,$id){
+        $password =  $this->where("id",$id)->value("password");
+        if($password === $oldpassword){
+            return ['code' => 200, 'data' => '', 'msg' =>'true'];
+        }else{
+            return ['code' => 100, 'data' => '', 'msg' =>'false'];
+        }
+
+    }
+
+    /**
+     * checkName 验证管理员名称唯一性
+     * @param $username
+     * @return string
+     */
+    public function checkName($username,$uid){
+        if($uid != ''){
+            $uname = $this->where('id',$uid)->value('username');
+            if($uname == $username){
+                return ['code' => 200, 'msg' => 'true'];
+            }
+        }
+        $result = $this->where('username',$username)->find();
+        if($result){
+            return ['code' => 100, 'msg' => 'false'];
+        }else{
+            return ['code' => 200, 'msg' => 'true'];
+        }
+    }
+
+
+    /**
+     * 根据管理员id获取角色信息
+     * @param $id
+     */
+    public function getOneUser($id)
+    {
+        return $this->where('id', $id)->find();
+    }
+
+
+    /**
+     * 删除管理员
+     * @param $id
+     */
+    public function delUser($id)
+    {
+        $name = $this->where('id', $id)->value('username');
+        Db::startTrans();// 启动事务
+        try{
+            $this->where('id', $id)->delete();
+            Db::name('auth_group_access')->where('uid', $id)->delete();
+            Db::commit();// 提交事务
+            writelog('管理员【'.$name.'】删除成功(ID='.$id.')',200);
+            return ['code' => 200, 'data' => '', 'msg' => '删除用户成功'];
+        }catch( \Exception $e){
+            Db::rollback ();//回滚事务
+            writelog('管理员【'.$name.'】删除失败(ID='.$id.')',100);
+            return ['code' => 100, 'data' => '', 'msg' => '删除用户失败'];
+        }
+    }
+
+
+    /**
+     * editPassword 修改管理员密码
+     * @param $param
+     * @return array
+     */
+    public function editPassword($param){
+        $name = $this->where('id',session('uid'))->value('username');
+        Db::startTrans();// 启动事务
+        try{
+            $this->allowField (true)->save($param,['id'=>session('uid')]);
+            Db::commit();// 提交事务
+            writelog('管理员【'.$name.'】修改密码成功',200);
+            return ['code'=>200,'msg'=>'密码修改成功,请重新登录!'];
+        }catch( \Exception $e){
+            Db::rollback ();//回滚事务
+            writelog('管理员【'.$name.'】修改密码失败',100);
+            return ['code'=>100,'msg'=>'密码修改失败'];
+        }
+    }
+
+    /**
+     * batchDelUser 批量删除管理员
+     * @param $param
+     * @return array
+     */
+    public function batchDelUser($param){
+        Db::startTrans();// 启动事务
+        try{
+            UserModel::destroy($param);
+            for($i=0;$i<count($param);$i++){
+                Db::name('auth_group_access')->where('uid','in',$param)->delete();
+            }
+            Db::commit();// 提交事务
+            writelog('批量删除管理员成功',200);
+            return ['code' => 200, 'data' => '', 'msg' => '批量删除成功'];
+        }catch( \Exception $e){
+            Db::rollback ();//回滚事务
+            writelog('批量删除管理员失败',100);
+            return ['code' => 100, 'data' => '', 'msg' => '批量删除失败'];
+        }
+    }
+
+    /**
+     * forbiddenAdmin 批量禁用管理员
+     * @param $param
+     * @return array
+     */
+    public function forbiddenAdmin($param){
+        Db::startTrans();// 启动事务
+        try{
+            if($param){
+                $this->saveAll($param);
+            }else{
+                $this->where('id','not in',[1,session('uid')])->update(['status'=>2]);
+            }
+            Db::commit();// 提交事务
+            writelog('批量禁用管理员成功',200);
+            return ['code' => 200, 'data' => '', 'msg' => '批量禁用成功'];
+        }catch( \Exception $e){
+            Db::rollback ();//回滚事务
+            writelog('批量禁用管理员失败',100);
+            return ['code' => 100, 'data' => '', 'msg' => '批量禁用失败'];
+        }
+    }
+
+    /**
+     * usingAdmin 批量启用管理员
+     * @param $param
+     * @return array
+     */
+    public function usingAdmin($param){
+        Db::startTrans();// 启动事务
+        try{
+            if($param){
+                $this->saveAll($param);
+            }else{
+                $this->where('1=1')->update(['status'=>1]);
+            }
+            Db::commit();// 提交事务
+            writelog('批量启用管理员成功',200);
+            return ['code' => 200, 'data' => '', 'msg' => '批量启用成功'];
+        }catch( \Exception $e){
+            Db::rollback ();//回滚事务
+            writelog('批量启用管理员失败',100);
+            return ['code' => 100, 'data' => '', 'msg' => '批量启用失败'];
+        }
+    }
+
+    /**
+     * [userState 用户状态]
+     * @param $id
+     * @return array
+     */
+    public function userState($id,$num){
+        $username = $this->where('id',$id)->value('username');
+        if($num == 2){
+            $msg = '禁用';
+        }else{
+            $msg = '启用';
+        }
+        Db::startTrans();// 启动事务
+        try{
+            if($id == session('uid')){
+                return ['code'=>100,'data' => '','msg'=>'不可禁用自己','type'=>'no'];
+            }else {
+                $this->where ('id' , $id)->setField (['status' => $num]);
+                Db::commit();// 提交事务
+                writelog('管理员【'.$username.'】'.$msg.'成功',200);
+//                    return ['code' => 200, 'data' => '', 'msg' => '已'.$msg];
+            }
+        }catch( \Exception $e){
+            Db::rollback ();//回滚事务
+            writelog('管理员【'.$username.'】'.$msg.'失败',100);
+            return ['code' => 100, 'data' => '', 'msg' => $msg.'失败'];
+        }
+    }
+
+}

+ 297 - 0
application/admin/model/UserType.php

@@ -0,0 +1,297 @@
+<?php
+
+namespace app\admin\model;
+use think\Model;
+use think\Db;
+
+class UserType extends Model
+{
+    protected  $name = 'auth_group';
+
+    // 开启自动写入时间戳字段
+    protected $autoWriteTimestamp = true;
+
+    /**
+     * [getRoleByWhere 根据条件获取角色列表信息]
+     * @author
+     */
+    public function getRoleByWhere($map, $Nowpage, $limits,$od)
+    {
+        return $this->where($map)->page($Nowpage, $limits)->order($od)->select();
+    }
+
+
+    /**
+     * [getRoleByWhere 根据条件获取所有的角色数量]
+     * @author
+     */
+    public function getAllRole($where)
+    {
+        return $this->where($where)->count();
+    }
+
+    /**
+     * checkName 验证角色名称唯一性
+     * @param $username
+     * @return string
+     */
+    public function checkRole($title,$uid){
+        if($uid != ''){
+            $uname = $this->where('id',$uid)->value('title');
+            if($uname == $title){
+                return ['code' => 200, 'msg' => 'true'];
+            }
+        }
+        $result = $this->where('title',$title)->find();
+        if($result){
+            return ['code' => 100, 'msg' => 'false'];
+        }else{
+            return ['code' => 200, 'msg' => 'true'];
+        }
+    }
+
+    /**
+     * [insertRole 插入角色信息]
+     * @author
+     */    
+    public function insertRole($param)
+    {
+        Db::startTrans();// 启动事务
+        try{
+            $this->save($param);
+            Db::commit();// 提交事务
+            writelog('角色【'.$param['title'].'】添加成功',200);
+            return ['code' => 200, 'data' => '', 'msg' => '添加角色成功'];
+        }catch( \Exception $e){
+            Db::rollback();// 回滚事务
+            writelog('角色【'.$param['title'].'】添加失败',100);
+            return ['code' => 100, 'data' => '', 'msg' => '添加角色失败'];
+        }
+    }
+
+
+
+    /**
+     * [editRole 编辑角色信息]
+     * @author
+     */  
+    public function editRole($param)
+    {
+        Db::startTrans();// 启动事务
+        try{
+            $this->save($param, ['id' => $param['id']]);
+            Db::commit();// 提交事务
+            writelog('角色【'.$param['title'].'】编辑成功',200);
+            return ['code' => 200, 'data' => '', 'msg' => '编辑角色成功'];
+        }catch( \Exception $e){
+            Db::rollback();// 回滚事务
+            writelog('角色【'.$param['title'].'】编辑失败',100);
+            return ['code' => 100, 'data' => '', 'msg' => '编辑角色失败'];
+        }
+    }
+
+
+
+    /**
+     * [getOneRole 根据角色id获取角色信息]
+     * @author
+     */ 
+    public function getOneRole($id)
+    {
+        return $this->where('id', $id)->find();
+    }
+
+
+
+    /**
+     * [delRole 删除角色]
+     * @author
+     */ 
+    public function delRole($id)
+    {
+        $title = $this->where('id',$id)->value('title');
+        Db::startTrans();// 启动事务
+        try{
+            $this->where('id', $id)->delete();
+            Db::commit();// 提交事务
+            writelog('角色【'.$title.'】删除成功',200);
+            return ['code' => 200, 'data' => '', 'msg' => '删除角色成功'];
+        }catch( \Exception $e){
+            Db::rollback();// 回滚事务
+            writelog('角色【'.$title.'】删除失败',100);
+            return ['code' => 100, 'data' => '', 'msg' => '删除角色失败'];
+        }
+    }
+
+
+
+    /**
+     * [getRole 获取所有的角色信息]
+     * @author
+     */ 
+    public function getRole()
+    {
+        return $this->where('id','<>',1)->select();
+    }
+
+
+    /**
+     * [getRole 获取角色的权限节点]
+     * @author
+     */ 
+    public function getRuleById($id)
+    {
+        $res = $this->field('rules')->where('id', $id)->find();
+        return $res['rules'];
+    }
+
+
+    /**
+     * [editAccess 分配权限]
+     * @author
+     */ 
+    public function editAccess($param)
+    {
+        $title = $this->where('id',$param['id'])->value('title');
+        Db::startTrans();// 启动事务
+        try{
+            $this->save($param, ['id' => $param['id']]);
+            Db::commit();// 提交事务
+            writelog('角色【'.$title.'】分配权限成功',200);
+            return ['code' => 200, 'data' => '', 'msg' => '分配权限成功'];
+        }catch( \Exception $e){
+            Db::rollback();// 回滚事务
+            writelog('角色【'.$title.'】分配权限失败',100);
+            return ['code' => 100, 'data' => '', 'msg' => '分配权限失败'];
+        }
+    }
+
+
+
+    /**
+     * [getRoleInfo 获取角色信息]
+     * @author
+     */ 
+    public function getRoleInfo($id){
+
+        $result = Db::name('auth_group')->where('id', $id)->find();
+        if($result['rules'] == "SUPERAUTH"){
+            $res = Db::name('auth_rule')->field('name')->select();
+
+            foreach($res as $key=>$vo){
+                if('#' != $vo['name']){
+                    $result['name'][] = $vo['name'];
+                }
+            }
+        }elseif(empty($result['rules'])){
+            $result['title'] ="";
+            $result['rules'] ="";
+            $result['name'] ="";
+        }else{
+            $where = 'id in('.$result['rules'].')';
+            $res = Db::name('auth_rule')->field('name')->where($where)->select();
+
+            foreach($res as $key=>$vo){
+                if('#' != $vo['name']){
+                    $result['name'][] = $vo['name'];
+                }
+            }
+        }
+        return $result;
+    }
+
+    /**
+     * batchDelRole 批量删除角色
+     * @param $param
+     * @return array
+     */
+    public function batchDelRole($param){
+        Db::startTrans();// 启动事务
+        try{
+            UserType::destroy($param);
+            Db::commit();// 提交事务
+            writelog('角色批量删除成功',200);
+            return ['code' => 200, 'data' => '', 'msg' => '批量删除成功'];
+        }catch( \Exception $e){
+            Db::rollback();// 回滚事务
+            writelog('角色批量删除成功',100);
+            return ['code' => 100, 'data' => '', 'msg' => '批量删除失败'];
+        }
+    }
+
+    /**
+     * [roleState 角色状态]
+     * @param $param
+     * @return array
+     */
+    public function roleState($id,$num){
+        $title = $this->where('id',$id)->value('title');
+        if($num == 2){
+            $msg = '禁用';
+        }else{
+            $msg = '启用';
+        }
+        Db::startTrans();// 启动事务
+        try{
+            if($id == session('agid')){
+                return ['code'=>100,'data' => '','msg'=>'不可禁用自己的角色','type'=>'no'];
+            }else {
+                $this->where ('id' , $id)->setField (['status' => $num]);
+                Db::commit();// 提交事务
+                writelog('角色【'.$title.'】'.$msg.'成功',200);
+//                    return ['code' => 200 , 'data' => '' , 'msg' => '已'.$msg];
+            }
+        }catch( \Exception $e){
+            Db::rollback();// 回滚事务
+            writelog('角色【'.$title.'】'.$msg.'失败',100);
+            return ['code' => 100, 'data' => '', 'msg' => $msg.'失败'];
+        }
+    }
+
+    /**
+     * forbiddenRole 批量禁用角色
+     * @param $param
+     * @return array
+     */
+    public function forbiddenRole($param){
+        Db::startTrans();// 启动事务
+        try{
+            if($param){
+                $this->saveAll($param);
+            }else{
+                $this->where('id','not in',[1,session('agid')])->update(['status'=>2]);
+            }
+            Db::commit();// 提交事务
+            writelog('批量禁用角色成功',200);
+            return ['code' => 200, 'data' => '', 'msg' => '批量禁用成功'];
+        }catch( \Exception $e){
+            Db::rollback ();//回滚事务
+            writelog('批量禁用角色失败',100);
+            return ['code' => 100, 'data' => '', 'msg' => '批量禁用失败'];
+        }
+    }
+
+    /**
+     * usingRole 批量启用角色
+     * @param $param
+     * @return array
+     */
+    public function usingRole($param){
+        Db::startTrans();// 启动事务
+        try{
+            if($param){
+                $this->saveAll($param);
+            }else{
+                $this->where('1=1')->update(['status'=>1]);
+            }
+            Db::commit();// 提交事务
+            writelog('批量启用角色成功',200);
+            return ['code' => 200, 'data' => '', 'msg' => '批量启用成功'];
+        }catch( \Exception $e){
+            Db::rollback ();//回滚事务
+            writelog('批量启用角色失败',100);
+            return ['code' => 100, 'data' => '', 'msg' => '批量启用失败'];
+        }
+    }
+
+}

+ 165 - 0
application/admin/view/aipimagesearch/add.html

@@ -0,0 +1,165 @@
+{include file="public/header" /}
+<body class="gray-bg">
+<div class="layui-fluid layui-col-md12">
+    <div class="layui-card">
+        <div class="layui-card-header">添加图库</div>
+        <div class="layui-card-body layui-form">
+            <div class="layui-row layui-col-space10 layui-form-item ">
+
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">图库名</label>
+                    <div class="layui-input-block">
+                        <input type="text" class="layui-input " name="pruduct_name" lay-verify="required" placeholder="课程标题">
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">参数图</label>
+                    <input type="hidden" name="product_parameter" id="product_parameter">
+                    <button type="button" class="layui-btn" id="test2">
+                        选择文件
+                    </button>
+                    <div class="layui-input-block">
+                        <blockquote class="layui-elem-quote layui-quote-nm" style="margin-top: 10px;">
+                            预览图:
+                            <div class="layui-upload-list" >
+                                <img src="" id="lay-img-list2" style="width:100px;height:100px;">
+                            </div>
+                        </blockquote>
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">产品图片</label>
+                    <input type="hidden" name="product_image" id="product_image">
+                    <button type="button" class="layui-btn" id="test1">
+                        选择文件
+                    </button>
+                    <div class="layui-input-block">
+                        <blockquote class="layui-elem-quote layui-quote-nm" style="margin-top: 10px;">
+                            预览图:
+                            <div class="layui-upload-list" >
+                                <img src="" id="lay-img-list1" style="width:100px;height:100px;">
+                            </div>
+                        </blockquote>
+                    </div>
+                </div>
+
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">富文本1 (图片规则 宽小于375,高小于500)</label>
+                    <div class="layui-input-block">
+                        <textarea id="demo" style="display: none;"></textarea>
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">产品优势 (图片规则 宽小于375,高小于500)</label>
+                    <div class="layui-input-block">
+                        <textarea id="demo2" style="display: none;"></textarea>
+
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">产品实拍 (图片规则 宽小于375,高小于500)</label>
+                    <div class="layui-input-block">
+                        <textarea id="demo3" style="display: none;"></textarea>
+
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <div class="layui-input-block">
+                        <button class="layui-btn" lay-submit="" lay-filter="component-form-element">保存
+                        </button>
+                        <button class="layui-btn layui-btn-primary" onclick="history.back()">关闭</button>
+                    </div>
+                </div>
+
+            </div>
+        </div>
+    </div>
+</div>
+{include file="public/footer" /}
+<script>
+    layui.use(['form','upload','element','layedit'], function() {
+        var form = layui.form
+            , upload = layui.upload
+            , element = layui.element
+        //富文本
+        var layedit = layui.layedit;
+        layedit.set({
+            uploadImage: {
+                url: '/admin/Aipimagesearch/Upload',
+                type: 'post'
+            }
+        });
+        var index =layedit.build('demo'); //建立编辑器
+        var index2 =layedit.build('demo2'); //建立编辑器
+        var index3 =layedit.build('demo3'); //建立编辑器
+        form.on('submit(component-form-element)', function (data) {
+            $('.layui-btn').addClass('layui-disabled').attr('disabled','disabled');
+            var layeditcontent=layedit.getContent(index);
+            var layeditcontent2=layedit.getContent(index2);
+            var layeditcontent3=layedit.getContent(index3);
+               //alert(layeditcontent);
+                data.field.product_fuwenben=layeditcontent;
+                data.field.product_youshi=layeditcontent2;
+                data.field.product_shipai=layeditcontent3
+               // console.log(data.field);
+            $.ajax({
+                url:"{:url('add')}",
+                type:'post',
+                dataType:'json',
+                data:data.field,
+                success:function(res){
+                    if (res.code == 200) {
+                        layer.msg(res.msg,{icon:1,time:1500,shade:0.1},function(index){
+                            wk.layer_close();
+                            setTimeout(function () {
+                                location.reload();
+                            },1000);
+                        })
+                    } else {
+                        $(".layui-btn").removeClass('layui-disabled').removeAttr('disabled');
+                        wk.error(res.msg);
+                        return false;
+                    }
+                }
+            })
+        });
+    });
+</script>
+<script>
+    layui.use('upload', function(){
+        var upload = layui.upload;
+        var uploadInst = upload.render({
+            elem: '#test1'
+            ,url: "{:url('admin/upload/uploadLocality')}"
+            ,accept: 'images'
+            ,multiple:false
+            ,done: function(res){
+                $('#lay-img-list1').attr("src",res.url);
+                $('#product_image').val(res.url);
+            }
+            ,error: function(){
+
+            }
+        });
+    });
+</script>
+<script>
+    layui.use('upload', function(){
+        var upload = layui.upload;
+        var uploadInst = upload.render({
+            elem: '#test2'
+            ,url: "{:url('admin/upload/uploadLocality')}"
+            ,accept: 'images'
+            ,multiple:false
+            ,done: function(res){
+                $('#lay-img-list2').attr("src",res.url);
+                $('#product_parameter').val(res.url);
+            }
+            ,error: function(){
+
+            }
+        });
+    });
+</script>
+</body>
+</html>

+ 151 - 0
application/admin/view/aipimagesearch/edit.html

@@ -0,0 +1,151 @@
+{include file="public/header" /}
+<body class="gray-bg">
+<div class="layui-fluid layui-col-md12">
+    <div class="layui-card">
+        <div class="layui-card-header">添加图库</div>
+        <div class="layui-card-body layui-form">
+            <div class="layui-row layui-col-space10 layui-form-item ">
+
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">图库名</label>
+                    <div class="layui-input-block">
+                        <input type="text" class="layui-input " name="pruduct_name" lay-verify="required" placeholder="课程标题" value="{$data.pruduct_name}">
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">参数图</label>
+                    <input type="hidden" name="product_parameter" id="product_parameter" value="{$data.product_parameter}">
+                    <button type="button" class="layui-btn" id="test2">
+                        选择文件
+                    </button>
+                    <div class="layui-input-block">
+                        <blockquote class="layui-elem-quote layui-quote-nm" style="margin-top: 10px;">
+                            预览图:
+                            <div class="layui-upload-list" >
+                                <img src="{$data.product_parameter}" id="lay-img-list2" style="width:100px;height:100px;">
+                            </div>
+                        </blockquote>
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">富文本1</label>
+                    <div class="layui-input-block">
+                        <textarea id="demo" style="display: none;">{$data.product_fuwenben}</textarea>
+
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">产品优势</label>
+                    <div class="layui-input-block">
+                        <textarea id="demo2" style="display: none;">{$data.product_youshi}</textarea>
+
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">产品实拍</label>
+                    <div class="layui-input-block">
+                        <textarea id="demo3" style="display: none;">{$data.product_shipai}</textarea>
+
+                    </div>
+                </div>
+                <input type="hidden" name="oid" value="{$data.oid}">
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <div class="layui-input-block">
+                        <button class="layui-btn" lay-submit="" lay-filter="component-form-element">保存
+                        </button>
+                        <button class="layui-btn layui-btn-primary" onclick="history.back()">关闭</button>
+                    </div>
+                </div>
+
+            </div>
+        </div>
+    </div>
+</div>
+{include file="public/footer" /}
+<script>
+    layui.use(['form','upload','element','layedit'], function() {
+        var form = layui.form
+            , upload = layui.upload
+            , element = layui.element
+        //富文本
+        var layedit = layui.layedit;
+        layedit.set({
+            uploadImage: {
+                url: '/admin/Aipimagesearch/Upload',
+                type: 'post'
+            }
+        });
+        var index =layedit.build('demo'); //建立编辑器
+        var index2 =layedit.build('demo2'); //建立编辑器
+        var index3 =layedit.build('demo3'); //建立编辑器
+        form.on('submit(component-form-element)', function (data) {
+            $('.layui-btn').addClass('layui-disabled').attr('disabled','disabled');
+            var layeditcontent=layedit.getContent(index);
+            var layeditcontent2=layedit.getContent(index2);
+            var layeditcontent3=layedit.getContent(index3);
+            //alert(layeditcontent);
+            data.field.product_fuwenben=layeditcontent;
+            data.field.product_youshi=layeditcontent2;
+            data.field.product_shipai=layeditcontent3
+            // console.log(data.field);
+            $.ajax({
+                url:"{:url('edit')}",
+                type:'post',
+                dataType:'json',
+                data:data.field,
+                success:function(res){
+                    if (res.code == 200) {
+                        layer.msg(res.msg,{icon:1,time:1500,shade:0.1},function(index){
+                            wk.layer_close();
+                            setTimeout(function () {
+                                location.reload();
+                            },1000);
+                        })
+                    } else {
+                        $(".layui-btn").removeClass('layui-disabled').removeAttr('disabled');
+                        wk.error(res.msg);
+                        return false;
+                    }
+                }
+            })
+        });
+    });
+</script>
+<script>
+    layui.use('upload', function(){
+        var upload = layui.upload;
+        var uploadInst = upload.render({
+            elem: '#test1'
+            ,url: "{:url('admin/upload/uploadLocality')}"
+            ,accept: 'images'
+            ,multiple:false
+            ,done: function(res){
+                $('#lay-img-list1').attr("src",res.url);
+                $('#product_image').val(res.url);
+            }
+            ,error: function(){
+
+            }
+        });
+    });
+</script>
+<script>
+    layui.use('upload', function(){
+        var upload = layui.upload;
+        var uploadInst = upload.render({
+            elem: '#test2'
+            ,url: "{:url('admin/upload/uploadLocality')}"
+            ,accept: 'images'
+            ,multiple:false
+            ,done: function(res){
+                $('#lay-img-list2').attr("src",res.url);
+                $('#product_parameter').val(res.url);
+            }
+            ,error: function(){
+
+            }
+        });
+    });
+</script>
+</body>
+</html>

+ 195 - 0
application/admin/view/aipimagesearch/index.html

@@ -0,0 +1,195 @@
+{include file="public/header" /}
+<style>
+    .layui-table-view .layui-table[lay-size=lg] .layui-table-cell {height: 58px;line-height: 58px;}
+    .wx-audio-content{padding:0px;border:0px;}
+    .wx-audio-content .wx-audio-left .wx-audio-state{margin-bottom:15px;}
+    .wx-audio-content .wx-audio-right .wx-audio-time{padding-top:0px;position: relative;bottom:6px;}
+    .wx-audio-content .wx-audio-right .wx-audio-progrees{top:6px;}
+</style>
+<body>
+<div class="layui-fluid">
+    <div class="layui-card">
+        <div class="layui-form layui-card-header layuiadmin-card-header-auto">
+            <div class="layui-form-item">
+                <div class="layui-inline">
+                    <div class="layui-input-inline">
+                        <input type="text" name="start" class="layui-input" onclick="wk.lay_date(this);" placeholder="创建开始日期">
+                    </div>
+                    <div class="layui-form-mid">
+                        -
+                    </div>
+                    <div class="layui-input-inline">
+                        <input type="text" name="end" class="layui-input" onclick="wk.lay_date(this);" placeholder="创建结束日期">
+                    </div>
+                </div>
+                <div class="layui-inline">
+                    <div class="layui-input-inline">
+                        <input type="text" id="key" class="layui-input" name="product_name" placeholder="图库名称"/>
+                    </div>
+                </div>
+                <div class="layui-inline">
+                    <div class="layui-input-inline">
+                        <button class="layui-btn" lay-submit="" lay-filter="LAY-search">立即搜索</button>
+                        <button  class="layui-btn layui-btn-normal" id="empty"  lay-submit="" lay-filter="LAY-search">重置</button>
+                    </div>
+                </div>
+            </div>
+
+            <div>
+                <button class="layui-btn" data-type="add" onclick="wk.href('{:url('add')}')">
+                    <i class="fa fa-plus"></i> 添加图库
+                </button>
+            </div>
+        </div>
+
+        <div class="layui-card-body">
+            <table id="LAY-table-manage" lay-filter="LAY-table-manage"></table>
+            <!--图片模板-->
+            <script type="text/html" id="imgTpl">
+                <ul class="layui-cricle">
+                    <li><img src="{{d.product_image}}" class="layui-table-img layui-circle"onerror="this.src='/static/admin/images/timg.jpg'" /></li>
+                </ul>
+            </script>
+            <!--图片模板-->
+            <script type="text/html" id="imgTp2">
+                <ul class="layui-cricle">
+                    <li><img src="{{d.product_parameter}}" class="layui-table-img layui-circle"onerror="this.src='/static/admin/images/timg.jpg'" /></li>
+                </ul>
+            </script>
+            <!--操作模板-->
+            <script type="text/html" id="opeBar">
+                <a onclick="wk.layer_show('编辑文章','{:url('edit')}?id={{d.oid}}')" class="layui-btn layui-btn-xs" title="编辑"><i class="fa fa-pencil"></i></a>
+                <a href="javascript:;" onclick="wk.confirm('{{d.oid}}','{:url('del')}')" class="layui-btn layui-btn-danger layui-btn-xs" title="删除"><i class="fa fa-trash-o"></i></a>
+            </script>
+        </div>
+    </div>
+</div>
+{include file="public/footer" /}
+<script>
+    var music = function(){
+        if($('#music').length == 0){
+            $('body').append('<div id="music"></div>');
+        }
+        var wxAudio = wk.lay_audio({elem:'#music',src:'/static/admin/images/default.mp3'});
+        $('#music').hide();
+        wxAudio.audioPlay();
+    }
+
+    layui.use(['index', 'table','util'], function () {
+        var $ = layui.$
+            , form = layui.form
+            , table = layui.table
+        table.render({
+            elem: '#LAY-table-manage'
+            , url: '{:url("admin/Aipimagesearch/index")}'
+            ,response: {
+                statusCode: 220 //成功的状态码,默认:0
+            }
+            , page: true
+            , even: false //开启隔行背景
+            , size: 'lg' //sm小尺寸的表格 lg大尺寸
+            // ,width:100
+            , cellMinWidth: 150
+            , height: "full-220"
+            , limits: [10, 20, 30, 40, 50]
+            , limit: "{:config('pages')}"
+            , loading: true
+            , toolbar:'#123'
+            , id: 'LAY-table'
+            , cols: [[
+                {type: 'checkbox', fixed: 'left',}
+                , {field: 'oid', width: 60, title: 'ID', sort: true, align: 'center'}
+                , {field: 'product_image', width: 300, title: '产品图片', align: 'center',templet: '#imgTpl'}
+                , {field: 'pruduct_name', width: 300, title: '产品名', align: 'center'}
+                , {field: 'product_parameter', width: 300, title: '参数图', align: 'center',templet: '#imgTp2'}
+                , {field: 'create_time', width: 300, title: '创建时间',sort: true, align: 'center',templet:"<div>{{layui.util.toDateString(d.create_time,'yyyy年MM月dd日')}}</div>"}
+                , {fixed: 'right', width: 300, title: '操作', align: 'center', toolbar: '#opeBar'}
+            ]]
+            ,done: function (res, curr, count) {
+                $('.layui-cricle').viewer({
+                    url: 'data-original',
+                });
+                $.each(res.data,function(index,item) {
+                    wk.lay_audio({elem:'#music_'+item['id'],src:item['music'],width:'250px'});
+                });
+            }
+        });
+        //监听状态开关操作
+        form.on('switch(OnOff)', function (obj) {
+            var num = '';
+            obj.elem.checked == true? num = 1: num = 2;
+            //用户状态
+            wk.status(this.value,num, '{:url("user_state")}',obj);
+        });
+        //事件
+        var active = {
+            getCheckData: function(){
+                //批量删除
+                wk.batchDel(getIds(),"{:url('batchDelUser')}");
+            }
+            ,forbiddenAll: function(){
+                //批量禁用
+                wk.batchForbidden(getIds(),2,"{:url('forbiddenAdmin')}");
+            }
+            ,usingAll: function(){
+                //批量启用
+                wk.usingAll(getIds(),1,"{:url('usingAdmin')}");
+            }
+            ,excelAll: function(){
+                //导出Excel
+                wk.excelAll(getIds(),$("form").serialize(),"{:url('excelAdmin')}");
+            }
+        };
+
+        $('.layuiBtn').on('click', function () {
+            var type = $(this).data('type');
+            active[type] ? active[type].call(this) : '';
+        });
+        var getIds = function () {
+            var ids = [];
+            var checkStatus = table.checkStatus('LAY-table')
+                ,data = checkStatus.data;
+            $.each(data,function(index,item){
+                ids.push(item['id'])
+            });
+            return ids;
+        }
+
+        //倒计时
+        // var thisTimer, setCountdown = function(){
+        //     lay('#test3').addClass('layui-disabled').attr('disabled').text('完了');
+        //     var endTime = new Date(new Date().getFullYear(),new Date().getMonth(),new Date().getDate(),new Date().getHours(),new Date().getMinutes(),new Date().getSeconds() + 60).getTime() //结束日期
+        //         ,serverTime = new Date().getTime(); //假设为当前服务器时间,这里采用的是本地时间,实际使用一般是取服务端的
+        //     clearTimeout(thisTimer);
+        //     util.countdown(endTime, serverTime, function(date, serverTime, timer){
+        //         var str = date[3] + '秒';
+        //         if(date[3] == 0){
+        //             lay('#test3').removeClass('layui-disabled').removeAttr('disabled').text('完了');
+        //         }else{
+        //             lay('#test2').html(str);
+        //         }
+        //         thisTimer = timer;
+        //     });
+        // };
+        // var date = new Date();
+        // setCountdown(date.getFullYear(),date.getMonth(),date.getDate(),date.getHours(),date.getMinutes(),date.getSeconds() + 60);
+    });
+    var thisTimer, setCountdown = function(){
+        $('#test3').addClass('layui-disabled').attr('disabled','disabled');
+        var endTime = new Date(new Date().getFullYear(),new Date().getMonth(),new Date().getDate(),new Date().getHours(),new Date().getMinutes(),new Date().getSeconds() + 60).getTime() //结束日期
+            ,serverTime = new Date().getTime(); //假设为当前服务器时间,这里采用的是本地时间,实际使用一般是取服务端的
+        clearTimeout(thisTimer);
+        layui.util.countdown(endTime, serverTime, function(date, serverTime, timer){
+            var str = date[3];
+            if(date[3] == 0){
+                $('#test3').removeClass('layui-disabled').removeAttr('disabled');
+                $('#test2').html(60);
+            }else{
+                $('#test2').html(str);
+            }
+            thisTimer = timer;
+        });
+    };
+</script>
+</body>
+</html>

+ 444 - 0
application/admin/view/article/add_article.html

@@ -0,0 +1,444 @@
+{include file="public/header" /}
+<body class="gray-bg">
+<div class="layui-fluid layui-col-md12">
+    <div class="layui-card">
+        <div class="layui-card-header">添加文章</div>
+        <div class="layui-card-body layui-form">
+            <div class="layui-row layui-col-space10 layui-form-item ">
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">TableSelect</label>
+                    <div class="layui-input-block">
+                        <input type="text" class="layui-input layui-hide" id="layTables" name="title" lay-verify="required" placeholder="文章标题" value="1,3,5,7,9,11,13,14" >
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">一键粘贴</label>
+                    <div class="layui-input-block">
+                        <input type="text" class="layui-input layui-disabled" name="title" lay-verify="required" placeholder="文章标题" value="123123e214" readonly>
+                        <div class="layui-copy" onclick="wk.lay_copy(this)" title="复制" alt="复制"><span><i class="fa fa-paste"></i></span></div>
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">所属分类</label>
+                    <div class="layui-input-block">
+                        <select name="cate_id" lay-verify="required" lay-search="">
+                            <option value="">请选择分类</option>
+                            {if !empty($cate)}
+                                {foreach name="cate" item="vo"}
+                                    <option value="{$vo.id}">{$vo.name}</option>
+                                {/foreach}
+                            {/if}
+                        </select>
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">三级联动</label>
+                    <div class="layui-input-inline">
+                        <select name="province" lay-search="" id="province" lay-filter="province">
+                            <option value="">---- 请选择省 ----</option>
+                            {foreach name="province" item="vo"}
+                                <option value="{$vo.district_id}">{$vo.district}</option>
+                            {/foreach}
+                        </select>
+                    </div>
+                    <div class="layui-input-inline">
+                        <select name="city" lay-search=""  id="city" lay-filter="city">
+                            <option value="">---- 请选择市 ----</option>
+                        </select>
+                    </div>
+                    <div class="layui-input-inline">
+                        <select name="district" lay-search="" id="district" lay-filter="district">
+                            <option value="">---- 请选择区 ----</option>
+                        </select>
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">关键字</label>
+                    <div class="layui-input-block">
+                        <input type="text" class="layui-input " name="keyword" lay-verify="required" placeholder="文章关键字">
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">描述</label>
+                    <div class="layui-input-block">
+                        <textarea name="remark" class="layui-textarea" lay-verify="required" placeholder="文章描述"></textarea>
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">单图片上传</label>
+                    <input type="hidden" name="lay-img" id="lay-img" lay-verify="image">
+                    <div class="layui-input-block">
+                        <div id="lay-upload">上传图片</div>
+                        <blockquote class="layui-elem-quote layui-quote-nm" style="margin-top: 10px;">
+                            预览图:
+                            <div class="layui-upload-list" id="lay-img-list">
+                            </div>
+                        </blockquote>
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">单图片上传</label>
+                    <input type="hidden" name="lay-img1" id="lay-img1" lay-verify="image">
+                    <div class="layui-input-block">
+                        <div id="lay-upload1">上传图片</div>
+                        <blockquote class="layui-elem-quote layui-quote-nm" style="margin-top: 10px;">
+                            预览图:
+                            <div class="layui-upload-list" id="lay-img-list1">
+                            </div>
+                        </blockquote>
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">音频上传</label>
+                    <input type="hidden" name="lay-music" id="lay-music" lay-verify="music">
+                    <div class="layui-input-block">
+                        <div id="lay-music-upload">上传音频</div>
+                        <blockquote class="layui-elem-quote layui-quote-nm" style="margin-top: 10px;">
+                            预览音频:
+                            <div class="layui-upload-list" id="lay-music-list">
+                            </div>
+                        </blockquote>
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">音频上传</label>
+                    <input type="hidden" name="lay-music" id="lay-music1" lay-verify="music">
+                    <div class="layui-input-block">
+                        <div id="lay-music-upload1">上传音频</div>
+                        <blockquote class="layui-elem-quote layui-quote-nm" style="margin-top: 10px;">
+                            预览音频:
+                            <div class="layui-upload-list" id="lay-music-list1">
+                            </div>
+                        </blockquote>
+                    </div>
+                </div>
+                <!--<div class="layui-form-item layui-col-md-offset1 layui-col-md8">-->
+                    <!--<label class="layui-form-label">上传视频:</label>-->
+                    <!--<div class="layui-input-block">-->
+                        <!--<button type="button" class="layui-btn" id="lay-upload2">上传视频</button>-->
+                        <!--<blockquote class="layui-elem-quote layui-quote-nm" style="margin-top: 10px;">-->
+                            <!--预览视频:-->
+                            <!--<div class="layui-upload-list" id="lay-video-list">-->
+                                <!--<span id="lay-msg" style="display: none;">-->
+                                    <!--<div class="layui-progress layui-progress-big" lay-showpercent="true" lay-filter="lay-video">-->
+                                        <!--<div class="layui-progress-bar" lay-percent="0%"></div>-->
+                                    <!--</div>-->
+                                    <!--<p>正在上传... <i class="layui-icon layui-icon-loading-1 layui-icon layui-anim layui-anim-rotate layui-anim-loop"></i></p>-->
+                                <!--</span>-->
+                            <!--</div>-->
+                        <!--</blockquote>-->
+                    <!--</div>-->
+                <!--</div>-->
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">上传视频:</label>
+                    <input type="hidden" name="lay-video" >
+                    <div class="layui-input-block">
+                        <div id="lay-upload2">上传视频</div>
+                        <blockquote class="layui-elem-quote layui-quote-nm" style="margin-top: 10px;">
+                            预览视频:
+                            <div class="layui-upload-list" id="lay-video-list">
+                            </div>
+                        </blockquote>
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md10">
+                    <label class="layui-form-label">多图片上传</label>
+                    <div class="layui-input-block">
+                        <input type="hidden" name="photo" id="photo" lay-verify="image">
+                        <div id="uploader" class="container">
+                            <div class="queueList">
+                                <div class="placeholder">
+                                    <div id="filePicker"></div>
+                                    <p>或将照片拖到这里</p>
+                                </div>
+                            </div>
+                            <div class="statusBar" style="display:none;">
+                                <div class="layui-progress layui-progress-big active" lay-showpercent="true">
+                                    <div class="layui-progress-bar layui-bg-blue" lay-percent="0%">
+                                    </div>
+                                    <span></span>
+                                </div>
+                                <div class="info"></div>
+                                <div class="btns">
+                                    <div id="goPicker" class="filePicker2"></div>
+                                    <div class="uploadBtn">开始上传</div>
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md10">
+                    <label class="layui-form-label">多图片上传1</label>
+                    <div class="layui-input-block">
+                        <input type="hidden" name="photo" id="photo1" lay-verify="image">
+                        <div id="uploader1" class="container">
+                            <div class="queueList">
+                                <div class="placeholder">
+                                    <div id="filePicker1"></div>
+                                    <p>或将照片拖到这里</p>
+                                </div>
+                            </div>
+                            <div class="statusBar" style="display:none;">
+                                <div class="layui-progress layui-progress-big active" lay-showpercent="true">
+                                    <div class="layui-progress-bar layui-bg-blue" lay-percent="0%">
+                                    </div>
+                                    <span></span>
+                                </div>
+                                <div class="info"></div>
+                                <div class="btns">
+                                    <div id="goPicker1" class="filePicker2"></div>
+                                    <div class="uploadBtn">开始上传</div>
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md10">
+                    <label class="layui-form-label">多图片上传2</label>
+                    <div class="layui-input-block">
+                        <input type="hidden" name="photo" id="photo2" lay-verify="image">
+                        <div id="uploader2" class="container">
+                            <div class="queueList">
+                                <div class="placeholder">
+                                    <div id="filePicker2"></div>
+                                    <p>或将照片拖到这里</p>
+                                </div>
+                            </div>
+                            <div class="statusBar" style="display:none;">
+                                <div class="layui-progress layui-progress-big active" lay-showpercent="true">
+                                    <div class="layui-progress-bar layui-bg-blue" lay-percent="0%">
+                                    </div>
+                                    <span></span>
+                                </div>
+                                <div class="info"></div>
+                                <div class="btns">
+                                    <div id="goPicker2" class="filePicker2"></div>
+                                    <div class="uploadBtn">开始上传</div>
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">所属分类</label>
+                    <div class="layui-input-block">
+                        <select name="cate_id" lay-verify="required" lay-search="">
+                            <option value="">请选择分类</option>
+                            {if !empty($cate)}
+                            {foreach name="cate" item="vo"}
+                            <option value="{$vo.id}">{$vo.name}</option>
+                            {/foreach}
+                            {/if}
+                        </select>
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md10">
+                    <label class="layui-form-label">wangEditor编辑器</label>
+                    <div class="layui-input-block" id="LAY_editor" lay-verify="editor">
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md10">
+                    <label class="layui-form-label">layEdit</label>
+                    <div class="layui-input-block" >
+                        <textarea class="layui-textarea" name="lay_content" id="LAY_editor1" placeholder="文章描述"></textarea>
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md10">
+                    <label class="layui-form-label">百度富文本:</label>
+                    <div class="layui-input-block" >
+                        <textarea name="lay_content" id="LAY_editor2" placeholder="文章描述"></textarea>
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">浏览量</label>
+                    <div class="layui-input-block">
+                        <input type="text" class="layui-input " name="views" lay-verify="required" placeholder="文章浏览量" onkeyup="value=value.replace(/[^\d]/g,'')">
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">作者</label>
+                    <div class="layui-input-block">
+                        <input type="text" class="layui-input " name="views" lay-verify="required" placeholder="文章作者">
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">是否推荐</label>
+                    <div class="layui-input-block">
+                        <input type="radio" name="is_tui" value="1" title="是" checked>
+                        <input type="radio" name="is_tui" value="2" title="否" >
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <div class="layui-input-block">
+                        <button class="layui-btn" lay-submit="" lay-filter="component-form-element">保存
+                        </button>
+                        <button class="layui-btn layui-btn-primary" onclick="history.back()">关闭</button>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+{include file="public/footer" /}
+<script>
+
+    //百度富文本编辑器
+    var editor = UE.getEditor('LAY_editor2', {
+        initialFrameHeight:450,
+        autoHeight: false,
+        autoHeightEnabled:false,
+        autoFloatEnabled:false
+    });
+    //自定义上传接口
+    UE.Editor.prototype._bkGetActionUrl = UE.Editor.prototype.getActionUrl;
+    UE.Editor.prototype.getActionUrl = function(action) {
+        if (action == 'uploadimage' || action == 'uploadscrawl') {
+            return '/admin/upload/ueditorUpload';//这就是自定义的上传地址
+        } else {
+            return this._bkGetActionUrl.call(this, action);
+        }
+    }
+
+
+    var n = wk.uploads({num:3,type:'png',url:"{:url('admin/upload/uploadLocality')}"});
+    var n1 = wk.uploads({num:4,type:'jpg',attr:1});
+    var n2 = wk.uploads({num:6,type:'jpg,png',attr:2});
+    function imgDel(e,obj){
+        wk.uploads_del(e,obj,n,"{:url('admin/upload/deleteLocality')}");
+    }
+    function imgDel1(e,obj){
+        wk.uploads_del(e,obj,n1);
+    }
+    function imgDel2(e,obj){
+        wk.uploads_del(e,obj,n2);
+    }
+
+    var editor = wk.wang({elem:'#LAY_editor'});
+    var index = wk.layeditor('LAY_editor1');
+    wk.uploadImg({size:2,type:'png',url:"{:url('Upload/upload')}",domain:"{:config('qiniu.domain')}"});
+    wk.uploadImg({size:5,num:1,type:'jpg',url:"{:url('Upload/upload')}",domain:"{:config('qiniu.domain')}"});
+    wk.uploadMusic({size:100,type:'mp3',url:"{:url('Upload/upload')}",domain:"{:config('qiniu.domain')}"});
+    wk.uploadMusic({size:100,num:1,type:'mp3',url:"{:url('Upload/upload')}",domain:"{:config('qiniu.domain')}"});
+    wk.tableSelect({elem:'#layTables',field:'id',name:'name',key:'keyword',splaceholder:'昵称',iplaceholder:'请选择数据',url:"{:url('getUserData')}",cols:[{type: 'checkbox'}, {field: 'id', width: '', title: 'ID', align: 'center'}, {field: 'name', width: '', title: '用户名', align: 'center'}]});
+
+    var uploader = WebUploader.create({
+        auto: true,// 选完文件后,是否自动上传。
+        server: '/admin/Upload/video',// 文件接收服务端。
+        duplicate :true,// 重复上传文件,true为可重复false为不可重复
+        chunked: true,// 分片上传大文件
+        pick: {
+            id: "#lay-upload2",// 选择文件的按钮
+            multiple: false,//true多文件上传 false单文件上传
+            label: "选择视频"
+        },
+        fileSingleSizeLimit: 200*1024*1024, //限制上传单个文件大小,单位是B,1M=1024000B
+        accept: {
+            title: 'Video',
+            extensions: 'mp4',
+            mimeTypes: '.mp4'
+        },
+        //上传成功
+        'onUploadSuccess': function(file, data, response) {
+            layui.config({
+                base: '/src/' //静态资源所在路径
+            }).extend({
+                ckplayer: 'modules/ckplayer'
+            }).use(['ckplayer'], function() {
+                var ckplayer = layui.ckplayer
+                var videoObject = {
+                    container: '#' + file.id,
+                    loop: false,
+                    autoplay: false,
+                    video: [
+                        [data._raw, 'video/mp4']
+                    ]
+                };
+                var player = new ckplayer(videoObject);
+            })
+            $( '#'+file.id ).show();
+            $( '#'+file.id ).next('div').hide();
+            $( '#'+file.id ).next().next('p').html('<span style="color: #009688;">上传成功!</span>');
+        },
+        //上传失败
+        'uploadError':function(file){
+            $( '#'+file.id ).next('div').hide();
+            $( '#'+file.id ).next().next('p').html('<span style="color: #FF5722;">上传失败!</span>');
+        }
+    });
+
+    //上传进度
+    uploader.on( 'uploadProgress' ,function(file,percentage){
+        layui.element.progress('lay-video', Math.round(100 * percentage)+'%');
+    });
+    //视频加入队列
+    uploader.on( 'fileQueued', function( file ) {
+        $('#lay-video-list').html('<div id="' + file.id + '" style="width: 80%;height: auto;display:none;"></div><div class="layui-progress layui-progress-big" lay-showpercent="true" lay-filter="lay-video"><div class="layui-progress-bar" lay-percent="0%"></div></div><p id="lay-msg">正在上传... <i class="layui-icon layui-icon-loading-1 layui-icon layui-anim layui-anim-rotate layui-anim-loop"></i></p>')
+    });
+
+
+    //错误信息提示
+    uploader.on('error', function (code) {
+        switch (code) {
+            case 'F_EXCEED_SIZE':
+                layer.msg('视频大小不得超过'+  uploader.options.fileSingleSizeLimit/1024/1024 + 'MB',{icon:2,time:1500,shade:0.1});
+                break;
+            case 'Q_TYPE_DENIED':
+                layer.msg('请上传正确的视频格式',{icon:2,time:1500,shade:0.1});
+                break;
+            default:
+                layer.msg('上传错误,请刷新',{icon:2,time:1500,shade:0.1});
+                break;
+        }
+    });
+    layui.use(['form','upload','layedit','element'], function() {
+        var form = layui.form
+            , layedit = layui.layedit
+            , upload = layui.upload
+            , element = layui.element
+
+        //layedit富文本
+        layedit.set({
+            uploadImage: {
+                url: '/admin/Upload/layUpload',
+                type: 'post'
+            }
+        });
+        var index = layedit.build('LAY_editor1', {height: 400});
+
+
+        form.verify({
+            image:[/\S/,'请上传图片'],
+            music:[/\S/,'请上传音频'],
+            editor:function(value,item){
+                if(editor.txt.html() == '<p><br></p>'){
+                    return '请填写内容';
+                }
+            }
+        });
+        form.on('submit(component-form-element)', function (data) {
+            $('.layui-btn').addClass('layui-disabled').attr('disabled','disabled');
+            data.field.html = editor.txt.html();
+            layedit.sync(index);
+            // data.field.lay_content = layedit.getContent(index);
+            $.ajax({
+                url:"{:url('add_article')}",
+                type:'post',
+                dataType:'json',
+                data:data.field,
+                success:function(res){
+                    if (res.code == 200) {
+                        layer.msg(res.msg,{icon:1,time:1500,shade:0.1},function(index){
+                            wk.layer_close();
+                        })
+                    } else {
+                        $(".layui-btn").removeClass('layui-disabled').removeAttr('disabled');
+                        wk.error(res.msg);
+                        return false;
+                    }
+                }
+            })
+        });
+    });
+</script>
+</body>
+</html>

+ 321 - 0
application/admin/view/article/edit_article.html

@@ -0,0 +1,321 @@
+{include file="public/header" /}
+<body class="gray-bg">
+<div class="layui-fluid layui-col-md12">
+    <div class="layui-card">
+        <div class="layui-card-body layui-form">
+            <div class="layui-row layui-col-space10 layui-form-item ">
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">标题</label>
+                    <div class="layui-input-block">
+                        <input type="text" class="layui-input" name="title" lay-verify="required" placeholder="文章标题">
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">所属分类</label>
+                    <div class="layui-input-block">
+                        <select name="cate_id" lay-verify="required" lay-search="">
+                            <option value="">请选择分类</option>
+                            {if !empty($cate)}
+                            {foreach name="cate" item="vo"}
+                            <option value="{$vo.id}">{$vo.name}</option>
+                            {/foreach}
+                            {/if}
+                        </select>
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">关键字</label>
+                    <div class="layui-input-block">
+                        <input type="text" class="layui-input " name="keyword" lay-verify="required" placeholder="文章关键字">
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">描述</label>
+                    <div class="layui-input-block">
+                        <textarea name="remark" class="layui-textarea" lay-verify="required" placeholder="文章描述"></textarea>
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">单图片上传</label>
+                    <input type="hidden" name="lay-img" id="lay-img">
+                    <div class="layui-input-block">
+                        <div id="lay-upload">上传图片</div>
+                        <blockquote class="layui-elem-quote layui-quote-nm" style="margin-top: 10px;">
+                            预览图:
+                            <div class="layui-upload-list" id="lay-list">
+                                <img class="layui-append-img" src="http://p73q8jzf0.bkt.clouddn.com/88b9d56b955bf005f447e54712c00bb2.jpg" onerror="this.src='/static/admin/images/no_img.jpg'">
+                            </div>
+                        </blockquote>
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">单图片上传</label>
+                    <input type="hidden" name="lay-img" id="lay-img1">
+                    <div class="layui-input-block">
+                        <div id="lay-upload1">上传图片</div>
+                        <blockquote class="layui-elem-quote layui-quote-nm" style="margin-top: 10px;">
+                            预览图:
+                            <div class="layui-upload-list" id="lay-list1">
+                            </div>
+                        </blockquote>
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">音频上传</label>
+                    <input type="hidden" name="lay-music" id="lay-music">
+                    <div class="layui-input-block">
+                        <div id="lay-music-upload">上传音频</div>
+                        <blockquote class="layui-elem-quote layui-quote-nm" style="margin-top: 10px;">
+                            预览音频:
+                            <div class="layui-upload-list" id="lay-music-list">
+                                <div id="layui-audio" style="margin: 0 10px 10px 0;" ></div>
+                            </div>
+                        </blockquote>
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">音频上传</label>
+                    <input type="hidden" name="lay-music" id="lay-music1">
+                    <div class="layui-input-block">
+                        <div id="lay-music-upload1">上传音频</div>
+                        <blockquote class="layui-elem-quote layui-quote-nm" style="margin-top: 10px;">
+                            预览音频:
+                            <div class="layui-upload-list" id="lay-music-list1">
+                            </div>
+                        </blockquote>
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">上传视频</label>
+                    <div class="layui-input-block">
+                        <button type="button" class="layui-btn" id="lay-upload2">上传视频</button>
+                        <blockquote class="layui-elem-quote layui-quote-nm" style="margin-top: 10px;">
+                            预览视频:
+                            <div class="layui-upload-list" id="lay-video-list">
+                                <div style="display: block;width: 80%;height: auto;" id="video" data-url="http://img.ksbbs.com/asset/Mon_1703/05cacb4e02f9d9e.mp4" ></div>
+                                <!--<span id="lay-msg" style="display: none;">-->
+                                    <!--<div class="layui-progress layui-progress-big" lay-showpercent="true" lay-filter="lay-video">-->
+                                        <!--<div class="layui-progress-bar" lay-percent="0%"></div>-->
+                                    <!--</div>-->
+                                    <!--<p>正在上传... <i class="layui-icon layui-icon-loading-1 layui-icon layui-anim layui-anim-rotate layui-anim-loop"></i></p>-->
+                                <!--</span>-->
+                            </div>
+                        </blockquote>
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md10">
+                    <label class="layui-form-label">多图片上传</label>
+                    <div class="layui-input-block">
+                        <input type="hidden" name="del" id="del" value="">
+                        <input type="hidden" id="hid" value="{$article.photo}">
+                        <input type="hidden" name="photo" id="photo" value="{$article.photo}">
+                        <div id="uploader" class="container">
+                            <div class="queueList">
+                                <div class="placeholder">
+                                    <div id="filePicker"></div>
+                                    <p>或将照片拖到这里</p>
+                                </div>
+                            </div>
+                            <div class="statusBar" style="display:none;">
+                                <div class="layui-progress layui-progress-big active" lay-showpercent="true">
+                                    <div class="layui-progress-bar layui-bg-blue" lay-percent="0%">
+                                    </div>
+                                </div>
+                                <div class="info"></div>
+                                <div class="btns">
+                                    <div id="goPicker" class="filePicker2"></div>
+                                    <div class="uploadBtn">开始上传</div>
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md10">
+                    <label class="layui-form-label">多图片上传</label>
+                    <div class="layui-input-block">
+                        <input type="hidden" name="del" id="del1" value="">
+                        <input type="hidden" id="hid1" value="{$article.photo}">
+                        <input type="hidden" name="photo" id="photo1" value="{$article.photo}">
+                        <div id="uploader1" class="container">
+                            <div class="queueList">
+                                <div class="placeholder">
+                                    <div id="filePicker1"></div>
+                                    <p>或将照片拖到这里</p>
+                                </div>
+                            </div>
+                            <div class="statusBar" style="display:none;">
+                                <div class="layui-progress layui-progress-big active" lay-showpercent="true">
+                                    <div class="layui-progress-bar layui-bg-blue" lay-percent="0%">
+                                    </div>
+                                </div>
+                                <div class="info"></div>
+                                <div class="btns">
+                                    <div id="goPicker1" class="filePicker2"></div>
+                                    <div class="uploadBtn">开始上传</div>
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md10">
+                    <label class="layui-form-label">内容</label>
+                    <div class="layui-input-block" id="LAY_editor">
+                        <p>{$article.content}</p>
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">浏览量</label>
+                    <div class="layui-input-block">
+                        <input type="text" class="layui-input " name="views" lay-verify="required" placeholder="文章浏览量">
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">作者</label>
+                    <div class="layui-input-block">
+                        <input type="text" class="layui-input " name="views" lay-verify="required" placeholder="文章作者">
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">是否推荐</label>
+                    <div class="layui-input-block">
+                        <input type="radio" name="is_tui" value="1" title="是" checked>
+                        <input type="radio" name="is_tui" value="2" title="否" >
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <div class="layui-input-block">
+                        <button class="layui-btn" lay-submit="" lay-filter="component-form-element">保存
+                        </button>
+                        <button class="layui-btn layui-btn-primary" onclick="wk.layer_close('close')">关闭</button>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+{include file="public/footer" /}
+<!--<script type="text/javascript" src="__JS__/webupload/webuploader_update.js"></script>-->
+<!--<script src="__JS__/we.js"></script>-->
+<script>
+    var n = wk.uploads({num:8,type:'png,jpg,gif',status:'update'})
+    var l = wk.uploads({num:8,type:'png,jpg,gif',attr:1,status:'update'})
+    function imgDel(e,obj,hid,del){
+        wk.update_del(e,obj,hid,del,n);
+    }
+    function imgDel1(e,obj,hid,del){
+        wk.update_del(e,obj,hid,del,l);
+    }
+    var editor = wk.wang({elem:'#LAY_editor'});
+    wk.lay_audio({elem:'#layui-audio',name:'b45030df9212d398a433610736ea8a51.mp3',src:'http://pi7sdygmd.bkt.clouddn.com/c38b5b14db26f742d782a09072a5edf2.mp3'});
+    wk.uploadImg({size:2,type:'png',url:"{:url('Upload/upload')}"});
+    wk.uploadImg({size:5,num:1,type:'jpg',url:"{:url('Upload/upload')}"});
+    wk.uploadMusic({size:10,type:'mp3',url:"{:url('Upload/upload')}"});
+    wk.uploadMusic({size:10,num:1,type:'mp3',url:"{:url('Upload/upload')}"});
+
+    layui.config({
+        base: '/src/' //静态资源所在路径
+    }).extend({
+         ckplayer: 'modules/ckplayer'
+    }).use(['form','upload','ckplayer'], function() {
+        var form = layui.form
+            , upload = layui.upload
+            , ckplayer = layui.ckplayer
+
+        var vUrl = $('#video').data('url'),
+            videoObject = {
+                container: '#video',
+                loop: false,
+                autoplay: false,
+                video: [
+                    [vUrl, 'video/mp4']
+                ]
+            };
+        var player = new ckplayer(videoObject);
+
+        //普通图片上传
+        // var uploadInst = upload.render({
+        //     elem: '#lay-upload'
+        //     ,url: '/admin/Upload/upload'
+        //     ,accept: 'images' //上传文件类型images(图片)、file(所有文件)、video(视频)、audio(音频)
+        //     ,acceptMime: '.png,.jpg' //筛选出指定文件类型
+        //     ,exts: 'png|jpg' //允许上传的文件后缀,结合 accept 参数类设定
+        //     ,auto: true //是否选完文件后自动上传
+        //     ,size: 2*1024 //文件最大可允许上传的大小,单位 KB(0即不限制)
+        //     ,field: 'file' //设定文件域的字段名
+        //    ,progress : function(index, value) {
+        //         element.progress('model' + index, value + '%');
+        //     }
+        //     ,before: function(obj){
+        //         //预读本地文件示例,不支持ie8
+        //         obj.preview(function(index, file, result){
+        //             $('#lay-list').attr('src', result); //图片链接(base64)
+        //         });
+        //     }
+        //     ,done: function(res){
+        //         //上传成功
+        //         if(res.code == 300){
+        //             layer.msg('上传成功');
+        //         }
+        //     }
+        //     ,error: function(){
+        //         //重传
+        //         var layMsg = $('#lay-msg');
+        //         layMsg.html('<span style="color: #FF5722;">上传失败</span> <a class="layui-btn layui-btn-xs lay-reload">重试</a>');
+        //         layMsg.find('.lay-reload').on('click', function(){
+        //             uploadInst.upload();
+        //         });
+        //     }
+        // });
+        form.verify({
+            username:function(value,item){
+                if(!/^[\S]{2,10}$/.test(value)){
+                    return '名称必须2到10字符,且不能出现空格';
+                }
+                var checkResult = "";
+                $.ajax({
+                    url:"{:url('User/checkName')}",
+                    type:'post',
+                    data:"username="+value,
+                    async: false,//必须同步
+                    success:function(res){
+                        if(res.code == 100){
+                            checkResult = "该名称已存在";
+                        }
+                    }
+                })
+                return checkResult;
+            },
+            pass: [/^[\S]{6,12}$/,'密码必须6到12位,且不能出现空格'],
+            // headCrop:[/^[\S]$/,'头像不能为空'],
+            // headCrop:function(value,item){
+            //     if(value == ""){
+            //         return '头像不能为空';
+            //     }
+            // },
+            realname:[/^[\S]{2,10}$/,'真实姓名必须2到10字符,且不能出现空格']
+
+        });
+        form.on('submit(component-form-element)', function (data) {
+            $('.layui-btn').addClass('layui-disabled').attr('disabled','disabled');
+            $.ajax({
+                url:"{:url('userAdd')}",
+                type:'post',
+                dataType:'json',
+                data:data.field,
+                success:function(res){
+                    if (res.code == 200) {
+                        layer.msg(res.msg,{icon:1,time:1500,shade:0.1},function(index){
+                            wk.layer_close();
+                        })
+                    } else {
+                        $(".layui-btn").removeClass('layui-disabled').removeAttr('disabled');
+                        wk.error(res.msg);
+                        return false;
+                    }
+                }
+            })
+        });
+    });
+</script>
+</body>
+</html>

+ 224 - 0
application/admin/view/article/index.html

@@ -0,0 +1,224 @@
+{include file="public/header" /}
+<style>
+    .layui-table-view .layui-table[lay-size=lg] .layui-table-cell {height: 58px;line-height: 58px;}
+    .wx-audio-content{padding:0px;border:0px;}
+    .wx-audio-content .wx-audio-left .wx-audio-state{margin-bottom:15px;}
+    .wx-audio-content .wx-audio-right .wx-audio-time{padding-top:0px;position: relative;bottom:6px;}
+    .wx-audio-content .wx-audio-right .wx-audio-progrees{top:6px;}
+</style>
+<body>
+<div class="layui-fluid">
+    <div class="layui-card">
+        <div class="layui-form layui-card-header layuiadmin-card-header-auto">
+            <div class="layui-form-item">
+                <div class="layui-inline">
+                    <div class="layui-input-inline">
+                        <input type="text" name="start" class="layui-input" onclick="wk.lay_date(this);" placeholder="创建开始日期">
+                    </div>
+                    <div class="layui-form-mid">
+                        -
+                    </div>
+                    <div class="layui-input-inline">
+                        <input type="text" name="end" class="layui-input" onclick="wk.lay_date(this);" placeholder="创建结束日期">
+                    </div>
+                </div>
+                <div class="layui-inline">
+                    <div class="layui-input-inline">
+                        <input type="text" id="key" class="layui-input" name="key" placeholder="文章名称"/>
+                    </div>
+                </div>
+                <div class="layui-inline">
+                    <div class="layui-input-inline">
+                        <button class="layui-btn" lay-submit="" lay-filter="LAY-search">立即搜索</button>
+                        <button  class="layui-btn layui-btn-normal" id="empty"  lay-submit="" lay-filter="LAY-search">重置</button>
+                    </div>
+                </div>
+            </div>
+            <blockquote class="layui-elem-quote" style="margin-top: 10px;">
+                <button class="layui-btn" id="test3" onclick="setCountdown()">倒计时<span id="test2" >60</span>秒</button>
+                <button class="layui-btn" onclick="wk.msg('速度框架萨达成卡萨打可承受的擦上档次萨达初三党测试导出砂垫层坚')">提示信息</button>
+                <button class="layui-btn" onclick="wk.layer_show('打印订单','{:url('printOrder')}')">打印订单</button>
+                <button class="layui-btn layui-btn-normal" onclick="toastr.success('你有新消息了!','消息提示');wk.voice_msg();">成功消息</button>
+                <button class="layui-btn layui-btn-warm" onclick="toastr.warning('你有新消息了!','消息提示');">警告消息</button>
+                <button class="layui-btn layui-btn-danger" onclick="toastr.error('你有新消息了!','消息提示');">失败消息</button>
+                <button class="layui-btn layui-btn-info" onclick="toastr.info('你有新消息了!','消息提示');">信息消息</button>
+                <button class="layui-btn " onclick="wk.voice_msg()">声音消息</button>
+            </blockquote>
+            <div>
+                <button class="layui-btn" data-type="add" onclick="wk.href('{:url('add_article')}')">
+                    <i class="fa fa-plus"></i> 添加文章
+                </button>
+                <span class="layui-btn-dropdown" style="display:inline-block;">
+                    <button class="layui-btn layui-btn-danger" data-toggle="dropdown"><i class="fa fa-wrench"></i> 批量操作 <i class="fa fa-caret-down"></i></button>
+                    <ul class="layui-dropdown-menu layui-anim layui-anim-upbit">
+                        <li><a href="javascript:;" class="layuiBtn" data-type="getCheckData"><i class="fa fa-trash-o"></i> 批量删除 </a></li>
+                        <li><a  href="javascript:;" class="layuiBtn" data-type="usingAll" id="onAll"><i class="fa fa-check-circle"></i> 批量启用</a></li>
+                        <li><a  href="javascript:;" class="layuiBtn" data-type="forbiddenAll" id="offAll"><i class="fa fa-ban"></i> 批量禁用</a></li>
+                    </ul>
+                </span>
+            </div>
+        </div>
+
+        <div class="layui-card-body">
+            <table id="LAY-table-manage" lay-filter="LAY-table-manage"></table>
+            <!--图片模板-->
+            <script type="text/html" id="imgTpl">
+                <ul class="layui-cricle">
+                    <li><img src="{{d.photo[0]}}" class="layui-table-img layui-circle"onerror="this.src='/static/admin/images/timg.jpg'" /></li>
+                    {{# if(d.photo.length >= 1){ }}
+                        {{# for(var i=1;i<d.photo.length;i++){  }}
+                            <li style="display:none;"><img src="{{d.photo[i]}}" onerror="this.src='/static/admin/images/timg.jpg'" ></li>
+                        {{# } }}
+                    {{# } }}
+                </ul>
+            </script>
+            <!--音频模板-->
+            <script type="text/html" id="musicTpl">
+                <div id="music_{{d.id}}" style=""></div>
+            </script>
+            <!--状态模板-->
+            <script type="text/html" id="staBar">
+                <input type="checkbox" value="{{d.id}}"  lay-skin="switch"  lay-text="ON|OFF" lay-filter="OnOff"{{d.status == 1 ? 'checked' : '' }}  >
+            </script>
+            <!--操作模板-->
+            <script type="text/html" id="opeBar">
+                <a onclick="wk.layer_show('编辑文章','{:url('edit_article')}?id={{d.id}}')" class="layui-btn layui-btn-xs" title="编辑"><i class="fa fa-pencil"></i></a>
+                <a href="javascript:;" onclick="wk.confirm('{{d.id}}','{:url('del_article')}')" class="layui-btn layui-btn-danger layui-btn-xs" title="删除"><i class="fa fa-trash-o"></i></a>
+            </script>
+        </div>
+    </div>
+</div>
+{include file="public/footer" /}
+<script>
+    var music = function(){
+        if($('#music').length == 0){
+            $('body').append('<div id="music"></div>');
+        }
+        var wxAudio = wk.lay_audio({elem:'#music',src:'/static/admin/images/default.mp3'});
+        $('#music').hide();
+        wxAudio.audioPlay();
+    }
+
+    layui.use(['index', 'table','util'], function () {
+        var $ = layui.$
+            , form = layui.form
+            , table = layui.table
+        table.render({
+            elem: '#LAY-table-manage'
+            , url: '{:url("Article/index")}'
+            ,response: {
+                statusCode: 220 //成功的状态码,默认:0
+            }
+            , page: true
+            , even: false //开启隔行背景
+            , size: 'lg' //sm小尺寸的表格 lg大尺寸
+            // ,width:100
+            , cellMinWidth: 150
+            , height: "full-220"
+            , limits: [10, 20, 30, 40, 50]
+            , limit: "{:config('pages')}"
+            , loading: true
+            , toolbar:'#123'
+            , id: 'LAY-table'
+            , cols: [[
+                {type: 'checkbox', fixed: 'left',}
+                , {field: 'id', width: 60, title: 'ID', sort: true, align: 'center'}
+                , {field: 'title', width: '', title: '标题', align: 'center'}
+                , {field: 'name', width: '', title: '所属分类', align: 'center'}
+                , {field: 'picture', width: 80, title: '封面', align: 'center',templet: '#imgTpl'}
+                , {field: 'views', width: '', title: '浏览量',sort: true, align: 'center'}
+                , {field: 'music', width: 290, title: '音频', align: 'center',templet:'#musicTpl'}
+                , {field: 'is_tui', width: 100, title: '是否推荐', align: 'center',templet: "<div>{{ d.is_tui==1?'是':'否'}}</div>"}
+                , {field: 'create_time', width: 180, title: '创建时间',sort: true, align: 'center',templet:"<div>{{layui.util.toDateString(d.create_time,'yyyy年MM月dd日')}}</div>"}
+                , {field: 'update_time', width: 180, title: '更新时间',sort: true, align: 'center'}
+                , {field: 'status',fixed: 'right', width: 100, title: '状态',sort: true, align: 'center', templet: '#staBar'}
+                , {fixed: 'right', width: 120, title: '操作', align: 'center', toolbar: '#opeBar'}
+            ]]
+            ,done: function (res, curr, count) {
+                $('.layui-cricle').viewer({
+                    url: 'data-original',
+                });
+                $.each(res.data,function(index,item) {
+                    wk.lay_audio({elem:'#music_'+item['id'],src:item['music'],width:'250px'});
+                });
+            }
+        });
+        //监听状态开关操作
+        form.on('switch(OnOff)', function (obj) {
+            var num = '';
+            obj.elem.checked == true? num = 1: num = 2;
+            //用户状态
+            wk.status(this.value,num, '{:url("user_state")}',obj);
+        });
+        //事件
+        var active = {
+            getCheckData: function(){
+                //批量删除
+                wk.batchDel(getIds(),"{:url('batchDelUser')}");
+            }
+            ,forbiddenAll: function(){
+                //批量禁用
+                wk.batchForbidden(getIds(),2,"{:url('forbiddenAdmin')}");
+            }
+            ,usingAll: function(){
+                //批量启用
+                wk.usingAll(getIds(),1,"{:url('usingAdmin')}");
+            }
+            ,excelAll: function(){
+                //导出Excel
+                wk.excelAll(getIds(),$("form").serialize(),"{:url('excelAdmin')}");
+            }
+        };
+
+        $('.layuiBtn').on('click', function () {
+            var type = $(this).data('type');
+            active[type] ? active[type].call(this) : '';
+        });
+        var getIds = function () {
+            var ids = [];
+            var checkStatus = table.checkStatus('LAY-table')
+                ,data = checkStatus.data;
+            $.each(data,function(index,item){
+                ids.push(item['id'])
+            });
+            return ids;
+        }
+
+        //倒计时
+        // var thisTimer, setCountdown = function(){
+        //     lay('#test3').addClass('layui-disabled').attr('disabled').text('完了');
+        //     var endTime = new Date(new Date().getFullYear(),new Date().getMonth(),new Date().getDate(),new Date().getHours(),new Date().getMinutes(),new Date().getSeconds() + 60).getTime() //结束日期
+        //         ,serverTime = new Date().getTime(); //假设为当前服务器时间,这里采用的是本地时间,实际使用一般是取服务端的
+        //     clearTimeout(thisTimer);
+        //     util.countdown(endTime, serverTime, function(date, serverTime, timer){
+        //         var str = date[3] + '秒';
+        //         if(date[3] == 0){
+        //             lay('#test3').removeClass('layui-disabled').removeAttr('disabled').text('完了');
+        //         }else{
+        //             lay('#test2').html(str);
+        //         }
+        //         thisTimer = timer;
+        //     });
+        // };
+        // var date = new Date();
+        // setCountdown(date.getFullYear(),date.getMonth(),date.getDate(),date.getHours(),date.getMinutes(),date.getSeconds() + 60);
+    });
+    var thisTimer, setCountdown = function(){
+        $('#test3').addClass('layui-disabled').attr('disabled','disabled');
+        var endTime = new Date(new Date().getFullYear(),new Date().getMonth(),new Date().getDate(),new Date().getHours(),new Date().getMinutes(),new Date().getSeconds() + 60).getTime() //结束日期
+            ,serverTime = new Date().getTime(); //假设为当前服务器时间,这里采用的是本地时间,实际使用一般是取服务端的
+        clearTimeout(thisTimer);
+        layui.util.countdown(endTime, serverTime, function(date, serverTime, timer){
+            var str = date[3];
+            if(date[3] == 0){
+                $('#test3').removeClass('layui-disabled').removeAttr('disabled');
+                $('#test2').html(60);
+            }else{
+                $('#test2').html(str);
+            }
+            thisTimer = timer;
+        });
+    };
+</script>
+</body>
+</html>

+ 94 - 0
application/admin/view/article/order.html

@@ -0,0 +1,94 @@
+{include file="public/header" /}
+<body class="gray-bg">
+<div class="layui-fluid layui-col-xs12">
+    <div class="layui-card">
+        <div class="layui-card-header">打印订单</div>
+        <div class="layui-card-body layui-form">
+            <div id="print">
+                <table class="layui-table">
+                    <colgroup>
+                        <col width="150">
+                        <col width="150">
+                        <col width="200">
+                        <col>
+                    </colgroup>
+                    <thead>
+                    <tr>
+                        <th>人物</th>
+                        <th>民族</th>
+                        <th>出场时间</th>
+                        <th>格言</th>
+                    </tr>
+                    </thead>
+                    <tbody>
+                    <tr>
+                        <td><img src="/uploads/face/20181116/63a0f7d99db522e14873f9b0b4e7ff85.png" alt=""></td>
+                        <td><span class="zzz">汉族</span></td>
+                        <td>1989-10-14</td>
+                        <td>人生似修行</td>
+                    </tr>
+                    <tr>
+                        <td>张爱玲</td>
+                        <td>汉族</td>
+                        <td>1920-09-30</td>
+                        <td>于千万人之中遇见你所遇见的人,于千万年之中,时间的无涯的荒野里…</td>
+                    </tr>
+                    <tr>
+                        <td>Helen Keller</td>
+                        <td>拉丁美裔</td>
+                        <td>1880-06-27</td>
+                        <td> Life is either a daring adventure or nothing.</td>
+                    </tr>
+                    <tr>
+                        <td>岳飞</td>
+                        <td>汉族</td>
+                        <td>1103-北宋崇宁二年</td>
+                        <td>教科书再滥改,也抹不去“民族英雄”的事实</td>
+                    </tr>
+                    <tr>
+                        <td>孟子</td>
+                        <td>华夏族(汉族)</td>
+                        <td>公元前-372年</td>
+                        <td>猿强,则国强。国强,则猿更强! </td>
+                    </tr>
+                    </tbody>
+                </table>
+                <div class="layui-form-item">
+                    <label class="layui-form-label">TableSelect</label>
+                    <div class="layui-input-block">
+                        <input type="text" class="layui-input" name="title" lay-verify="required" placeholder="文章标题" value="1,3,5,7,9,11,13,14" >
+                    </div>
+                </div>
+            </div>
+            <div class="layui-row layui-col-space10 layui-form-item ">
+                <div class="layui-form-item layui-col-xs-offset1 layui-col-xs8">
+                    <div class="layui-input-block">
+                        <button class="layui-btn"  onclick="wk.lay_print({obj:'#print'})">打印</button>
+                        <button class="layui-btn layui-btn-primary" onclick="wk.layer_close()">关闭</button>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+{include file="public/footer" /}
+<script>
+    // function test(){
+    //     // $.print();
+    //     $('#print').print({
+    //         globalStyles : true,//是否启用自身样式
+    //         mediaPrint : false,
+    //         stylesheet : null,//外部样式链接
+    //         iframe : true,
+    //         noPrintSelector : ".avoid-this",//不打印什么元素,支持多个属性逗号连接
+    //         prepend : null,//头部添加内容,支持html
+    //         append : null,//尾部添加内容,支持html
+    //         //打印完成回调
+    //         deferred : $.Deferred().done(function() {
+    //             console.log('Printing done', arguments);
+    //         })
+    //     });
+    // }
+</script>
+</body>
+</html>

+ 81 - 0
application/admin/view/chart/add.html

@@ -0,0 +1,81 @@
+{include file="public/header" /}
+<body class="gray-bg">
+<div class="layui-fluid layui-col-md12">
+    <div class="layui-card">
+        <div class="layui-card-body layui-form">
+            <div class="layui-row layui-col-space10 layui-form-item ">
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">轮播图片</label>
+                    <input type="hidden" name="image" id="image">
+                    <button type="button" class="layui-btn" id="test5">
+                        选择文件
+                    </button>
+                    <div class="layui-input-block">
+                        <blockquote class="layui-elem-quote layui-quote-nm" style="margin-top: 10px;">
+                            预览图:
+                            <div class="layui-upload-list" >
+                                <img src="" id="images" style="width:100px;height:100px;">
+                            </div>
+                        </blockquote>
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">url(可为空)</label>
+                    <div class="layui-input-block">
+                        <textarea name="url" placeholder="图片地址(为空请填0)" lay-verify="required" class="layui-textarea" maxlength="200"></textarea>
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <div class="layui-input-block">
+                        <button class="layui-btn" lay-submit="" lay-filter="component-form-element">保存
+                        </button>
+                        <button class="layui-btn layui-btn-primary" onclick="wk.layer_close('close')">关闭</button>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+
+{include file="public/footer" /}
+<script>
+    layui.use(['form'], function() {
+        var form = layui.form;
+        form.on('submit(component-form-element)', function (data) {
+            $('.layui-btn').addClass('layui-disabled').attr('disabled','disabled');
+            $.ajax({
+                url:"{:url('Add')}",
+                type:'post',
+                dataType:'json',
+                data:data.field,
+                success:function(res){
+                    if (res.code == 200) {
+                        wk.success(res.msg,'wk.layer_close()');
+                    } else {
+                        wk.error(res.msg,'$(".layui-btn").removeClass(\'layui-disabled\').removeAttr(\'disabled\')');
+                    }
+                }
+            })
+        });
+    });
+</script>
+<script>
+    layui.use('upload', function(){
+        var upload = layui.upload;
+        var uploadInst = upload.render({
+            elem: '#test5'
+            ,url: "{:url('admin/upload/uploadLocality')}"
+            ,accept: 'images'
+            ,multiple:false
+            ,done: function(res){
+                $('#images').attr("src",res.url);
+                $('#image').val(res.url);
+            }
+            ,error: function(){
+
+            }
+        });
+    });
+</script>
+</body>
+</html>

+ 82 - 0
application/admin/view/chart/edit.html

@@ -0,0 +1,82 @@
+{include file="public/header" /}
+<body class="gray-bg">
+<div class="layui-fluid layui-col-md12">
+    <div class="layui-card">
+        <div class="layui-card-body layui-form">
+            <div class="layui-row layui-col-space10 layui-form-item ">
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">轮播图片</label>
+                    <input type="hidden" name="image" id="image" value="{$data.image}">
+                    <button type="button" class="layui-btn" id="test5">
+                        选择文件
+                    </button>
+                    <div class="layui-input-block">
+                        <blockquote class="layui-elem-quote layui-quote-nm" style="margin-top: 10px;">
+                            预览图:
+                            <div class="layui-upload-list" >
+                                <img src="{$data.image}" id="images" style="width:100px;height:100px;">
+                            </div>
+                        </blockquote>
+                    </div>
+                </div>
+                <input type="hidden" name="cid" value="{$data.cid}">
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">url(可为空)</label>
+                    <div class="layui-input-block">
+                        <textarea name="url" placeholder="图片地址(为空请填0)" lay-verify="required" class="layui-textarea" maxlength="200">{$data.url}</textarea>
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <div class="layui-input-block">
+                        <button class="layui-btn" lay-submit="" lay-filter="component-form-element">保存
+                        </button>
+                        <button class="layui-btn layui-btn-primary" onclick="wk.layer_close('close')">关闭</button>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+
+{include file="public/footer" /}
+<script>
+    layui.use(['form'], function() {
+        var form = layui.form;
+        form.on('submit(component-form-element)', function (data) {
+            $('.layui-btn').addClass('layui-disabled').attr('disabled','disabled');
+            $.ajax({
+                url:"{:url('edit')}",
+                type:'post',
+                dataType:'json',
+                data:data.field,
+                success:function(res){
+                    if (res.code == 200) {
+                        wk.success(res.msg,'wk.layer_close()');
+                    } else {
+                        wk.error(res.msg,'$(".layui-btn").removeClass(\'layui-disabled\').removeAttr(\'disabled\')');
+                    }
+                }
+            })
+        });
+    });
+</script>
+<script>
+    layui.use('upload', function(){
+        var upload = layui.upload;
+        var uploadInst = upload.render({
+            elem: '#test5'
+            ,url: "{:url('admin/upload/uploadLocality')}"
+            ,accept: 'images'
+            ,multiple:false
+            ,done: function(res){
+                $('#images').attr("src",res.url);
+                $('#image').val(res.url);
+            }
+            ,error: function(){
+
+            }
+        });
+    });
+</script>
+</body>
+</html>

+ 159 - 0
application/admin/view/chart/index.html

@@ -0,0 +1,159 @@
+{include file="public/header" /}
+<style>
+    .layui-table-view .layui-table[lay-size=lg] .layui-table-cell {height: 58px;line-height: 58px;}
+    .wx-audio-content{padding:0px;border:0px;}
+    .wx-audio-content .wx-audio-left .wx-audio-state{margin-bottom:15px;}
+    .wx-audio-content .wx-audio-right .wx-audio-time{padding-top:0px;position: relative;bottom:6px;}
+    .wx-audio-content .wx-audio-right .wx-audio-progrees{top:6px;}
+</style>
+<body>
+
+<div class="layui-fluid">
+    <div class="layui-card">
+        <div class="layui-form layui-card-header layuiadmin-card-header-auto">
+            <button class="layui-btn" data-type="add" onclick="wk.href('{:url('add')}')">
+                <i class="fa fa-plus"></i> 添加图片
+            </button>
+            <!--图片模板-->
+            <script type="text/html" id="imgTpl">
+                <ul class="layui-cricle">
+                    <li><img src="{{d.image}}" class="layui-table-img layui-circle"onerror="this.src='/static/admin/images/timg.jpg'" /></li>
+                </ul>
+            </script>
+            <div class="layui-card-body">
+                <table id="LAY-table-manage" lay-filter="LAY-table-manage"></table>
+                <!--操作模板-->
+                <script type="text/html" id="opeBar">
+                    <a onclick="wk.layer_show('编辑内容','{:url('edit')}?id={{d.cid}}')" class="layui-btn layui-btn-xs" title="编辑"><i class="fa fa-pencil"></i></a>
+                    <a class="layui-btn layui-btn-danger layui-btn-xs" title="删除" onclick="wk.confirm('{{d.cid}}','{:url('del')}')"><i class="fa fa-trash-o"></i></a>
+                </script>
+            </div>
+        </div>
+    </div>
+    {include file="public/footer" /}
+    <script>
+        var music = function(){
+            if($('#music').length == 0){
+                $('body').append('<div id="music"></div>');
+            }
+            var wxAudio = wk.lay_audio({elem:'#music',src:'/static/admin/images/default.mp3'});
+            $('#music').hide();
+            wxAudio.audioPlay();
+        }
+
+        layui.use(['index', 'table','util'], function () {
+            var $ = layui.$
+                , form = layui.form
+                , table = layui.table
+            table.render({
+                elem: '#LAY-table-manage'
+                , url: '{:url("admin/Chart/index")}'
+                ,response: {
+                    statusCode: 220 //成功的状态码,默认:0
+                }
+                , page: true
+                , even: false //开启隔行背景
+                , size: 'lg' //sm小尺寸的表格 lg大尺寸
+                // ,width:100
+                , cellMinWidth: 150
+                , height: "full-220"
+                , limits: [10, 20, 30, 40, 50]
+                , limit: "{:config('pages')}"
+                , loading: true
+                , toolbar:'#123'
+                , id: 'LAY-table'
+                , cols: [[
+                    {type: 'checkbox', fixed: 'left',}
+                    , {field: 'cid', width: 120, title: 'ID', sort: true, align: 'center'}
+                    , {field: 'url', width: 300, title: '地址', sort: true, align: 'center'}
+                    , {field: 'image', width: 300, title: '图片', sort: true, align: 'center',templet: '#imgTpl'}
+                    , {fixed: 'right', width: 200, title: '操作', align: 'center', toolbar: '#opeBar'}
+                ]]
+                ,done: function (res, curr, count) {
+                    $('.layui-cricle').viewer({
+                        url: 'data-original',
+                    });
+                    $.each(res.data,function(index,item) {
+                        wk.lay_audio({elem:'#music_'+item['id'],src:item['music'],width:'250px'});
+                    });
+                }
+            });
+            //监听状态开关操作
+            form.on('switch(OnOff)', function (obj) {
+                var num = '';
+                obj.elem.checked == true? num = 1: num = 2;
+                //用户状态
+                wk.status(this.value,num, '{:url("user_state")}',obj);
+            });
+            //事件
+            var active = {
+                getCheckData: function(){
+                    //批量删除
+                    wk.batchDel(getIds(),"{:url('batchDelUser')}");
+                }
+                ,forbiddenAll: function(){
+                    //批量禁用
+                    wk.batchForbidden(getIds(),2,"{:url('forbiddenAdmin')}");
+                }
+                ,usingAll: function(){
+                    //批量启用
+                    wk.usingAll(getIds(),1,"{:url('usingAdmin')}");
+                }
+                ,excelAll: function(){
+                    //导出Excel
+                    wk.excelAll(getIds(),$("form").serialize(),"{:url('excelAdmin')}");
+                }
+            };
+
+            $('.layuiBtn').on('click', function () {
+                var type = $(this).data('type');
+                active[type] ? active[type].call(this) : '';
+            });
+            var getIds = function () {
+                var ids = [];
+                var checkStatus = table.checkStatus('LAY-table')
+                    ,data = checkStatus.data;
+                $.each(data,function(index,item){
+                    ids.push(item['id'])
+                });
+                return ids;
+            }
+
+            //倒计时
+            // var thisTimer, setCountdown = function(){
+            //     lay('#test3').addClass('layui-disabled').attr('disabled').text('完了');
+            //     var endTime = new Date(new Date().getFullYear(),new Date().getMonth(),new Date().getDate(),new Date().getHours(),new Date().getMinutes(),new Date().getSeconds() + 60).getTime() //结束日期
+            //         ,serverTime = new Date().getTime(); //假设为当前服务器时间,这里采用的是本地时间,实际使用一般是取服务端的
+            //     clearTimeout(thisTimer);
+            //     util.countdown(endTime, serverTime, function(date, serverTime, timer){
+            //         var str = date[3] + '秒';
+            //         if(date[3] == 0){
+            //             lay('#test3').removeClass('layui-disabled').removeAttr('disabled').text('完了');
+            //         }else{
+            //             lay('#test2').html(str);
+            //         }
+            //         thisTimer = timer;
+            //     });
+            // };
+            // var date = new Date();
+            // setCountdown(date.getFullYear(),date.getMonth(),date.getDate(),date.getHours(),date.getMinutes(),date.getSeconds() + 60);
+        });
+        var thisTimer, setCountdown = function(){
+            $('#test3').addClass('layui-disabled').attr('disabled','disabled');
+            var endTime = new Date(new Date().getFullYear(),new Date().getMonth(),new Date().getDate(),new Date().getHours(),new Date().getMinutes(),new Date().getSeconds() + 60).getTime() //结束日期
+                ,serverTime = new Date().getTime(); //假设为当前服务器时间,这里采用的是本地时间,实际使用一般是取服务端的
+            clearTimeout(thisTimer);
+            layui.util.countdown(endTime, serverTime, function(date, serverTime, timer){
+                var str = date[3];
+                if(date[3] == 0){
+                    $('#test3').removeClass('layui-disabled').removeAttr('disabled');
+                    $('#test2').html(60);
+                }else{
+                    $('#test2').html(str);
+                }
+                thisTimer = timer;
+            });
+        };
+    </script>
+</body>
+</html>

+ 105 - 0
application/admin/view/company/edit.html

@@ -0,0 +1,105 @@
+{include file="public/header" /}
+<body class="gray-bg">
+<div class="layui-fluid layui-col-md12">
+    <div class="layui-card">
+        <div class="layui-card-body layui-form">
+            <div class="layui-row layui-col-space10 layui-form-item ">
+
+
+
+
+
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">编辑公司信息</label>
+                    <div class="layui-input-block">
+                        <textarea name="text" required lay-verify="required" placeholder="请输入"  class="layui-textarea">{$data.text}</textarea>
+                    </div>
+                </div>
+
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <div class="layui-input-block">
+                        <button class="layui-btn" lay-submit="" lay-filter="component-form-element">保存
+                        </button>
+                        <button class="layui-btn layui-btn-primary" onclick="wk.layer_close('close')">关闭</button>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+
+{include file="public/footer" /}
+<script type="text/javascript" src="__JS__/plugins/cropper/Crop.js"></script>
+<script>
+    //裁剪后的处理
+    $("#sureCut").on("click",function () {
+        if ($("#tailoringImg").attr("src") == null ){
+            layer.msg('请先选择头像',{anim:6})
+        }else{
+            var cas = $('#tailoringImg').cropper('getCroppedCanvas');//获取被裁剪后的canvas
+            var base64url = cas.toDataURL('image/png'); //转换为base64地址形式
+            $("#img_data").attr('src',base64url).show();
+            $('#data_photo').val(base64url);
+            //关闭裁剪框
+            layer.closeAll();
+        }
+    });
+</script>
+<script>
+    layui.use(['form'], function() {
+        var form = layui.form;
+        form.verify({
+            username:function(value,item){
+                if(!/^[\S]{2,10}$/.test(value)){
+                    return '名称必须2到10字符,且不能出现空格';
+                }
+                var checkResult = "";
+                $.ajax({
+                    url:"{:url('User/checkName')}",
+                    type:'post',
+                    data:"username="+value,
+                    async: false,//必须同步
+                    success:function(res){
+                        if(res.code == 100){
+                            checkResult = "该名称已存在";
+                        }
+                    }
+                })
+                return checkResult;
+            },
+            pass: [/^[\S]{6,16}$/,'密码必须6到16位,且不能出现空格'],
+            // headCrop:[/^[\S]$/,'头像不能为空'],
+            // headCrop:function(value,item){
+            //     if(value == ""){
+            //         return '头像不能为空';
+            //     }
+            // },
+            realname:[/^[\S]{2,10}$/,'真实姓名必须2到10字符,且不能出现空格']
+
+        });
+        form.on('submit(component-form-element)', function (data) {
+            $('.layui-btn').addClass('layui-disabled').attr('disabled','disabled');
+            $.ajax({
+                url:"{:url('edit')}",
+                type:'post',
+                dataType:'json',
+                data:data.field,
+                success:function(res){
+                    if (res.code == 200) {
+                        wk.success(res.msg,'wk.layer_close()');
+                    } else {
+                        wk.error(res.msg,'$(".layui-btn").removeClass(\'layui-disabled\').removeAttr(\'disabled\')');
+                    }
+                }
+            })
+        });
+    });
+</script>
+<script>
+    layui.use('layedit', function(){
+        var layedit = layui.layedit;
+        layedit.build('demo'); //建立编辑器
+    });
+</script>
+</body>
+</html>

+ 147 - 0
application/admin/view/company/index.html

@@ -0,0 +1,147 @@
+{include file="public/header" /}
+<style>
+    .layui-table-view .layui-table[lay-size=lg] .layui-table-cell {height: 58px;line-height: 58px;}
+    .wx-audio-content{padding:0px;border:0px;}
+    .wx-audio-content .wx-audio-left .wx-audio-state{margin-bottom:15px;}
+    .wx-audio-content .wx-audio-right .wx-audio-time{padding-top:0px;position: relative;bottom:6px;}
+    .wx-audio-content .wx-audio-right .wx-audio-progrees{top:6px;}
+</style>
+<body>
+<div class="layui-fluid">
+    <div class="layui-card">
+        <div class="layui-form layui-card-header layuiadmin-card-header-auto">
+        <div class="layui-card-body">
+            <table id="LAY-table-manage" lay-filter="LAY-table-manage"></table>
+            <!--操作模板-->
+            <script type="text/html" id="opeBar">
+                <a onclick="wk.layer_show('编辑内容','{:url('edit')}?id={{d.cid}}')" class="layui-btn layui-btn-xs" title="编辑"><i class="fa fa-pencil"></i></a>
+            </script>
+        </div>
+    </div>
+</div>
+{include file="public/footer" /}
+<script>
+    var music = function(){
+        if($('#music').length == 0){
+            $('body').append('<div id="music"></div>');
+        }
+        var wxAudio = wk.lay_audio({elem:'#music',src:'/static/admin/images/default.mp3'});
+        $('#music').hide();
+        wxAudio.audioPlay();
+    }
+
+    layui.use(['index', 'table','util'], function () {
+        var $ = layui.$
+            , form = layui.form
+            , table = layui.table
+        table.render({
+            elem: '#LAY-table-manage'
+            , url: '{:url("admin/Company/index")}'
+            ,response: {
+                statusCode: 220 //成功的状态码,默认:0
+            }
+            , page: true
+            , even: false //开启隔行背景
+            , size: 'lg' //sm小尺寸的表格 lg大尺寸
+            // ,width:100
+            , cellMinWidth: 150
+            , height: "full-220"
+            , limits: [10, 20, 30, 40, 50]
+            , limit: "{:config('pages')}"
+            , loading: true
+            , toolbar:'#123'
+            , id: 'LAY-table'
+            , cols: [[
+                {type: 'checkbox', fixed: 'left',}
+                , {field: 'cid', width: 120, title: 'ID', sort: true, align: 'center'}
+                , {field: 'text', width: 120, title: '公司简介', sort: true, align: 'center'}
+                , {fixed: 'right', width: 120, title: '操作', align: 'center', toolbar: '#opeBar'}
+            ]]
+            ,done: function (res, curr, count) {
+                $('.layui-cricle').viewer({
+                    url: 'data-original',
+                });
+                $.each(res.data,function(index,item) {
+                    wk.lay_audio({elem:'#music_'+item['id'],src:item['music'],width:'250px'});
+                });
+            }
+        });
+        //监听状态开关操作
+        form.on('switch(OnOff)', function (obj) {
+            var num = '';
+            obj.elem.checked == true? num = 1: num = 2;
+            //用户状态
+            wk.status(this.value,num, '{:url("user_state")}',obj);
+        });
+        //事件
+        var active = {
+            getCheckData: function(){
+                //批量删除
+                wk.batchDel(getIds(),"{:url('batchDelUser')}");
+            }
+            ,forbiddenAll: function(){
+                //批量禁用
+                wk.batchForbidden(getIds(),2,"{:url('forbiddenAdmin')}");
+            }
+            ,usingAll: function(){
+                //批量启用
+                wk.usingAll(getIds(),1,"{:url('usingAdmin')}");
+            }
+            ,excelAll: function(){
+                //导出Excel
+                wk.excelAll(getIds(),$("form").serialize(),"{:url('excelAdmin')}");
+            }
+        };
+
+        $('.layuiBtn').on('click', function () {
+            var type = $(this).data('type');
+            active[type] ? active[type].call(this) : '';
+        });
+        var getIds = function () {
+            var ids = [];
+            var checkStatus = table.checkStatus('LAY-table')
+                ,data = checkStatus.data;
+            $.each(data,function(index,item){
+                ids.push(item['id'])
+            });
+            return ids;
+        }
+
+        //倒计时
+        // var thisTimer, setCountdown = function(){
+        //     lay('#test3').addClass('layui-disabled').attr('disabled').text('完了');
+        //     var endTime = new Date(new Date().getFullYear(),new Date().getMonth(),new Date().getDate(),new Date().getHours(),new Date().getMinutes(),new Date().getSeconds() + 60).getTime() //结束日期
+        //         ,serverTime = new Date().getTime(); //假设为当前服务器时间,这里采用的是本地时间,实际使用一般是取服务端的
+        //     clearTimeout(thisTimer);
+        //     util.countdown(endTime, serverTime, function(date, serverTime, timer){
+        //         var str = date[3] + '秒';
+        //         if(date[3] == 0){
+        //             lay('#test3').removeClass('layui-disabled').removeAttr('disabled').text('完了');
+        //         }else{
+        //             lay('#test2').html(str);
+        //         }
+        //         thisTimer = timer;
+        //     });
+        // };
+        // var date = new Date();
+        // setCountdown(date.getFullYear(),date.getMonth(),date.getDate(),date.getHours(),date.getMinutes(),date.getSeconds() + 60);
+    });
+    var thisTimer, setCountdown = function(){
+        $('#test3').addClass('layui-disabled').attr('disabled','disabled');
+        var endTime = new Date(new Date().getFullYear(),new Date().getMonth(),new Date().getDate(),new Date().getHours(),new Date().getMinutes(),new Date().getSeconds() + 60).getTime() //结束日期
+            ,serverTime = new Date().getTime(); //假设为当前服务器时间,这里采用的是本地时间,实际使用一般是取服务端的
+        clearTimeout(thisTimer);
+        layui.util.countdown(endTime, serverTime, function(date, serverTime, timer){
+            var str = date[3];
+            if(date[3] == 0){
+                $('#test3').removeClass('layui-disabled').removeAttr('disabled');
+                $('#test2').html(60);
+            }else{
+                $('#test2').html(str);
+            }
+            thisTimer = timer;
+        });
+    };
+</script>
+</body>
+</html>

+ 137 - 0
application/admin/view/config/add_config.html

@@ -0,0 +1,137 @@
+{include file="public/header" /}
+<body class="gray-bg">
+<div class="layui-fluid layui-col-md12">
+    <div class="layui-card">
+        <div class="layui-card-body layui-form">
+            <div class="layui-row layui-col-space10 layui-form-item ">
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">配置标识</label>
+                    <div class="layui-input-block">
+                        <input type="text" name="name" lay-verify="required|name" placeholder="用于config函数调用,只能使用英文且不能重复" class="layui-input ">
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">配置标题</label>
+                    <div class="layui-input-block">
+                        <input type="text" name="title" lay-verify="required" placeholder="用于后台显示的配置标题" class="layui-input ">
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">配置类型</label>
+                    <div class="layui-input-block">
+                        <select name="type"  id="type" lay-verify="required" lay-search="" lay-filter="types" >
+                            <option value="">请选择类型</option>
+                            {if !empty($Think.config.config_type_list)}
+                                {volist name="Think.config.config_type_list" id="type"}
+                                    <option value="{$key}">{$type}</option>
+                                {/volist}
+                            {/if}
+                        </select>
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">配置分组</label>
+                    <div class="layui-input-block">
+                        <select name="group" lay-verify="required" lay-search="">
+                            <option value="">请选择分组</option>
+                            {if !empty($Think.config.config_group_list)}
+                                {volist name="Think.config.config_group_list" id="type"}
+                                    <option value="{$key}">{$type}</option>
+                                {/volist}
+                            {/if}
+                        </select>
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">配置值</label>
+                    <div class="layui-input-block">
+                        <input type="text" name="value" lay-verify="required" placeholder="用于config函数调用显示的值" class="layui-input ">
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">配置项</label>
+                    <div class="layui-input-block">
+                        <textarea name="extra" placeholder="如果是枚举型,需要配置该项" lay-verify="extra" class="layui-textarea"></textarea>
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">配置描述</label>
+                    <div class="layui-input-block">
+                        <textarea name="remark" lay-verify="required" placeholder="配置详细说明" class="layui-textarea"></textarea>
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">排序</label>
+                    <div class="layui-input-block">
+                        <input type="text" name="sort" lay-verify="required|sort" placeholder="用于显示的顺序" class="layui-input " value="50">
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">状态</label>
+                    <div class="layui-input-block">
+                        <input type="radio" name="status" value="1" title="启用" checked>
+                        <input type="radio" name="status" value="2" title="禁用" >
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <div class="layui-input-block">
+                        <button class="layui-btn" lay-submit="" lay-filter="component-form-element">保存
+                        </button>
+                        <button class="layui-btn layui-btn-primary" onclick="wk.layer_close('close')">关闭</button>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+{include file="public/footer" /}
+<script>
+    layui.use(['form'], function() {
+        var form = layui.form;
+        form.verify({
+            name:function(value,item){
+                if(!/^[a-zA-Z_]*$/.test(value)){
+                    return '只能使用英文和下划线且不能重复';
+                }
+                var checkResult = "";
+                $.ajax({
+                    url:"{:url('Config/checkConfig')}",
+                    type:'post',
+                    data:"name="+value,
+                    async: false,//必须同步
+                    success:function(res){
+                        if(res.code == 100){
+                            checkResult = "该配置标识已存在";
+                        }
+                    }
+                })
+                return checkResult;
+            },
+            extra: function(value,item){
+                var type = $('#type').find("option:selected").text();
+                if(type == "枚举" && value == ""){
+                    return "配置类型为枚举,配置项必填";
+                }
+            },
+            sort:[/^(0|[1-9]\d*)$/,'排序值只能为非负整数']
+        });
+        form.on('submit(component-form-element)', function (data) {
+            $('.layui-btn').addClass('layui-disabled').attr('disabled','disabled');
+            $.ajax({
+                url:"{:url('add_config')}",
+                type:'post',
+                dataType:'json',
+                data:data.field,
+                success:function(res){
+                    if (res.code == 200) {
+                        wk.success(res.msg,'wk.layer_close()');
+                    } else {
+                        wk.error(res.msg,'$(".layui-btn").removeClass(\'layui-disabled\').removeAttr(\'disabled\')');
+                    }
+                }
+            })
+        });
+    });
+</script>
+</body>
+</html>

+ 131 - 0
application/admin/view/config/edit_config.html

@@ -0,0 +1,131 @@
+{include file="public/header" /}
+<body class="gray-bg">
+<div class="layui-fluid layui-col-md12">
+    <div class="layui-card">
+        <div class="layui-card-body layui-form">
+            <input type="hidden" name="id" value="{$info.id}">
+            <div class="layui-row layui-col-space10 layui-form-item ">
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">配置标识</label>
+                    <div class="layui-input-block">
+                        <input type="text" name="name" lay-verify="required|name" placeholder="用于config函数调用,只能使用英文且不能重复" class="layui-input " value="{$info.name}">
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">配置标题</label>
+                    <div class="layui-input-block">
+                        <input type="text" name="title" lay-verify="required" placeholder="用于后台显示的配置标题" class="layui-input " value="{$info.title}" >
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">配置类型</label>
+                    <div class="layui-input-block">
+                        <select name="type"  id="type" lay-verify="required" lay-search="" lay-filter="types" >
+                            <option value="">请选择类型</option>
+                            {if !empty($Think.config.config_type_list)}
+                                {volist name="Think.config.config_type_list" id="type"}
+                                    <option value="{$key}" {eq name="$key" value="$info.type"}selected{/eq}>{$type}</option>
+                                {/volist}
+                            {/if}
+                        </select>
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">配置分组</label>
+                    <div class="layui-input-block">
+                        <select name="group" lay-verify="required" lay-search="">
+                            <option value="">请选择分组</option>
+                            {if !empty($Think.config.config_group_list)}
+                                {volist name="Think.config.config_group_list" id="type"}
+                                    <option value="{$key}" {eq name="$key" value="$info.group"}selected{/eq}  >{$type}</option>
+                                {/volist}
+                            {/if}
+                        </select>
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">配置值</label>
+                    <div class="layui-input-block">
+                        <input type="text" name="value" lay-verify="required" placeholder="用于config函数调用显示的值" class="layui-input " value="{$info.value}">
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">配置项</label>
+                    <div class="layui-input-block">
+                        <textarea name="extra" placeholder="如果是枚举型,需要配置该项" lay-verify="extra" class="layui-textarea">{$info.extra}</textarea>
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">配置描述</label>
+                    <div class="layui-input-block">
+                        <textarea name="remark" lay-verify="required" placeholder="配置详细说明" class="layui-textarea">{$info.remark}</textarea>
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <label class="layui-form-label">排序</label>
+                    <div class="layui-input-block">
+                        <input type="text" name="sort" lay-verify="required|sort" placeholder="用于显示的顺序" class="layui-input " value="{$info.sort}">
+                    </div>
+                </div>
+                <div class="layui-form-item layui-col-md-offset1 layui-col-md8">
+                    <div class="layui-input-block">
+                        <button class="layui-btn" lay-submit="" lay-filter="component-form-element">保存
+                        </button>
+                        <button class="layui-btn layui-btn-primary" onclick="wk.layer_close('close')">关闭</button>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+{include file="public/footer" /}
+<script>
+    layui.use(['form'], function() {
+        var form = layui.form;
+        form.verify({
+            name:function(value,item){
+                if(!/^[a-zA-Z_]*$/.test(value)){
+                    return '只能使用英文和下划线且不能重复';
+                }
+                var checkResult = "";
+                $.ajax({
+                    url:"{:url('Config/checkConfig')}",
+                    type:'post',
+                    data:"name="+value + "&id=" + $('input[name=id]').val(),
+                    async: false,//必须同步
+                    success:function(res){
+                        if(res.code == 100){
+                            checkResult = "该配置标识已存在";
+                        }
+                    }
+                })
+                return checkResult;
+            },
+            extra: function(value,item){
+                var type = $('#type').find("option:selected").text();
+                if(type == "枚举" && value == ""){
+                    return "配置类型为枚举,配置项必填";
+                }
+            },
+            sort:[/^(0|[1-9]\d*)$/,'排序值只能为非负整数']
+        });
+        form.on('submit(component-form-element)', function (data) {
+            $('.layui-btn').addClass('layui-disabled').attr('disabled','disabled');
+            $.ajax({
+                url:"{:url('edit_config')}",
+                type:'post',
+                dataType:'json',
+                data:data.field,
+                success:function(res){
+                    if (res.code == 200) {
+                        wk.success(res.msg,'wk.layer_close()');
+                    } else {
+                        wk.error(res.msg,'$(".layui-btn").removeClass(\'layui-disabled\').removeAttr(\'disabled\')');
+                    }
+                }
+            })
+        });
+    });
+</script>
+</body>
+</html>

+ 82 - 0
application/admin/view/config/group.html

@@ -0,0 +1,82 @@
+{include file="public/header" /}
+<body class="gray-bg">
+<div class="layui-fluid layui-col-xs12">
+    <div class="layui-card">
+        <div class="layui-tab layui-tab-card">
+            <ul class="layui-tab-title">
+                {volist name="Think.config.config_group_list" id="group"}
+                <a href="{:url('?id='.$key)}"><li {eq name="id" value="$key"}class="layui-this"{/eq}>{$group}配置</li></a>
+                {/volist}
+            </ul>
+            <div class="layui-tab-content">
+                <div class="layui-tab-item layui-show ">
+                    <div class="layui-form">
+                        <div class="layui-row layui-col-space10 layui-form-item ">
+                            {volist name="list" id="config"}
+                                <div class="layui-form-item layui-col-xs-offset1 layui-col-xs8">
+                                    <label class="layui-form-label">{$config.title}</label>
+                                    <div class="layui-input-block">
+                                        {switch name="config.type"}
+                                        {case value="0"}
+                                            <input type="text"name="config[{$config.name}]" value="{$config.value}" lay-verify="required|number" placeholder="{$config.remark}" class="layui-input ">
+                                        {/case}
+                                        {case value="1"}
+                                            <input type="text" name="config[{$config.name}]" value="{$config.value}" lay-verify="required" placeholder="{$config.remark}" class="layui-input ">
+                                        {/case}
+                                        {case value="2"}
+                                            <textarea name="config[{$config.name}]" placeholder="{$config.remark}" lay-verify="required" class="layui-textarea">{$config.value}</textarea>
+                                        {/case}
+                                        {case value="3"}
+                                            <textarea name="config[{$config.name}]" placeholder="{$config.remark}" lay-verify="required" class="layui-textarea">{$config.value}</textarea>
+                                        {/case}
+                                        {case value="4"}
+                                            <select name="config[{$config.name}]" lay-verify="required" lay-search="">
+                                                {volist name=":parse_config_attr($config['extra'])" id="vo"}
+                                                <option value="{$key}" {eq name="config.value" value="$key"}selected{/eq}>{$vo}</option>
+                                                {/volist}
+                                            </select>
+                                        {/case}
+                                        {/switch}
+                                    </div>
+                                </div>
+                            {/volist}
+                            {if condition='!empty($list)'}
+                            <div class="layui-form-item layui-col-xs-offset1 layui-col-xs8">
+                                <div class="layui-input-block">
+                                    <button class="layui-btn" lay-submit="" lay-filter="component-form-element">保存
+                                    </button>
+                                </div>
+                            </div>
+                            {/if}
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+{include file="public/footer" /}
+<script>
+    layui.use(['form'], function() {
+        var form = layui.form;
+        form.on('submit(component-form-element)', function (data) {
+            $('.layui-btn').addClass('layui-disabled').attr('disabled','disabled');
+            $.ajax({
+                url:"{:url('save')}",
+                type:'post',
+                dataType:'json',
+                data:data.field,
+                success:function(res){
+                    if (res.code == 200) {
+                        wk.success(res.msg);
+                    } else {
+                        wk.error(res.msg);
+                    }
+                    $(".layui-btn").removeClass('layui-disabled').removeAttr('disabled');
+                }
+            })
+        });
+    });
+</script>
+</body>
+</html>

+ 154 - 0
application/admin/view/config/index.html

@@ -0,0 +1,154 @@
+{include file="public/header" /}
+<body>
+<div class="layui-fluid">
+    <div class="layui-card">
+        <div class="layui-form layui-card-header layuiadmin-card-header-auto">
+            <div class="layui-form-item">
+                <!--<div class="layui-inline">-->
+                    <!--<div class="layui-input-inline">-->
+                        <!--<input type="text" name="start" class="layui-input" onfocus="wk.lay_date(this);" placeholder="创建开始日期">-->
+                    <!--</div>-->
+                    <!--<div class="layui-form-mid">-->
+                        <!-- - -->
+                    <!--</div>-->
+                    <!--<div class="layui-input-inline">-->
+                        <!--<input type="text" name="end" class="layui-input" onfocus="wk.lay_date(this);" placeholder="创建结束日期">-->
+                    <!--</div>-->
+                <!--</div>-->
+                <div class="layui-inline">
+                    <div class="layui-input-inline">
+                        <select name="type"  lay-search="">
+                            <option  value="">不限类型</option>
+                            {foreach name="type" item="vo" key="key"}
+                                <option  value="{$key}">{$vo}</option>
+                            {/foreach}
+                        </select>
+                    </div>
+                </div>
+                <div class="layui-inline">
+                    <div class="layui-input-inline">
+                        <select name="group"  lay-search="">
+                            <option  value="">不限分组</option>
+                            {foreach name="group" item="vo" key="key"}
+                                <option  value="{$key}">{$vo}</option>
+                            {/foreach}
+                        </select>
+                    </div>
+                </div>
+                <div class="layui-inline">
+                    <div class="layui-input-inline">
+                        <input type="text" class="layui-input" name="key" placeholder="输入需查询的标题/名称"/>
+                    </div>
+                </div>
+                <div class="layui-inline">
+                    <div class="layui-input-inline">
+                        <button class="layui-btn" lay-submit="" lay-filter="LAY-search">立即搜索</button>
+                        <button  class="layui-btn layui-btn-normal" id="empty"  lay-submit="" lay-filter="LAY-search">重置</button>
+                    </div>
+                </div>
+            </div>
+            <div>
+                <button class="layui-btn" data-type="add" onclick="wk.layer_show('添加配置','{:url('add_config')}')">
+                    <i class="fa fa-plus"></i> 添加配置
+                </button>
+                <span class="layui-btn-dropdown" style="display:inline-block;">
+                    <button class="layui-btn layui-btn-danger" data-toggle="dropdown"><i class="fa fa-wrench"></i> 批量操作 <i class="fa fa-caret-down"></i></button>
+                    <ul class="layui-dropdown-menu layui-anim layui-anim-upbit">
+                        <li><a href="javascript:;" class="layuiBtn" data-type="getCheckData"><i class="fa fa-trash-o"></i> 批量删除 </a></li>
+                            <li><a  href="javascript:;" class="layuiBtn" data-type="usingAll" id="onAll"><i class="fa fa-check-circle"></i> 批量启用</a></li>
+                            <li><a  href="javascript:;" class="layuiBtn" data-type="forbiddenAll" id="offAll"><i class="fa fa-ban"></i> 批量禁用</a></li>
+                    </ul>
+                </span>
+            </div>
+        </div>
+
+        <div class="layui-card-body">
+            <table id="LAY-table-manage" lay-filter="LAY-table-manage"></table>
+            <!--操作模板-->
+            <script type="text/html" id="opeBar">
+                <a class="layui-btn layui-btn-xs" title="编辑" onclick="wk.layer_show('编辑配置','{:url('edit_config')}?id={{d.id}}')"><i class="fa fa-pencil"></i></a>
+                <a class="layui-btn layui-btn-danger layui-btn-xs" title="删除" onclick="wk.confirm('{{d.id}}','{:url('del_config')}')"><i class="fa fa-trash-o"></i></a>
+            </script>
+            <!--状态模板-->
+            <script type="text/html" id="staBar">
+                <input type="checkbox" value="{{d.id}}"  lay-skin="switch"  lay-text="ON|OFF" lay-filter="OnOff"{{ d.status == 1 ? 'checked' : '' }}  >
+            </script>
+        </div>
+    </div>
+</div>
+{include file="public/footer" /}
+<script>
+    layui.use(['index', 'table'], function () {
+        var $ = layui.$
+            , form = layui.form
+            , table = layui.table
+        table.render({
+            elem: '#LAY-table-manage'
+            , url: '{:url("Config/index")}'
+            ,response: {
+                statusCode: 220 //成功的状态码,默认:0
+            }
+            , page: true
+            , even: false //开启隔行背景
+            , size: 'lg' //sm小尺寸的表格 lg大尺寸
+            // ,width:100
+            , autoSort: false
+            , cellMinWidth: 150
+            , height: "full-220"
+            , limits: [10, 20, 30, 40, 50]
+            , limit: "{:config('pages')}"
+            , loading: true
+            , id: 'LAY-table'
+            , cols: [[
+                {type: 'checkbox', fixed: 'left',}
+                , {type:'numbers', width: 80, title: '序号'}
+                , {field: 'name', width: '', title: '名称', align: 'center'}
+                , {field: 'title', width: '', title: '标题', align: 'center'}
+                , {field: 'type', width: 80, title: '类型', align: 'center'}
+                , {field: 'group', width: 80, title: '分组', align: 'center'}
+                , {field: 'create_time', width: '', title: '创建时间', sort: true, align: 'center'}
+                , {field: 'update_time', width: '', title: '更新时间', sort: true, align: 'center'}
+                , {field: 'status',fixed: 'right', width: 100, title: '状态', align: 'center', templet: '#staBar'}
+                , {fixed: 'right', width: 120, title: '操作', align: 'center', toolbar: '#opeBar'}
+            ]]
+        });
+        //监听状态开关操作
+        form.on('switch(OnOff)', function (obj) {
+            var num = '';
+            obj.elem.checked == true? num = 1: num = 2;
+            //配置状态
+            wk.status(this.value,num, '{:url("status_config")}',obj);
+        });
+        //事件
+        var active = {
+            getCheckData: function(){
+                //批量删除
+                wk.batchDel(getIds(),"{:url('batchDelConfig')}");
+            }
+            ,forbiddenAll: function(){
+                //批量禁用
+                wk.batchForbidden(getIds(),2,"{:url('forbiddenConfig')}");
+            }
+            ,usingAll: function(){
+                //批量启用
+                wk.usingAll(getIds(),1,"{:url('usingConfig')}");
+            }
+        };
+
+        $('.layuiBtn').on('click', function () {
+            var type = $(this).data('type');
+            active[type] ? active[type].call(this) : '';
+        });
+        var getIds = function () {
+            var ids = [];
+            var checkStatus = table.checkStatus('LAY-table')
+                ,data = checkStatus.data;
+            $.each(data,function(index,item){
+                ids.push(item['id'])
+            });
+            return ids;
+        }
+    });
+</script>
+</body>
+</html>

+ 145 - 0
application/admin/view/data/import.html

@@ -0,0 +1,145 @@
+{include file="public/header" /}
+<body>
+<div class="layui-fluid">
+    <div class="layui-card">
+        <div class="layui-form layui-card-header layuiadmin-card-header-auto">
+            <button class="layui-btn layui-btn-danger layuiBtn" data-type="getCheckData" >
+                <i class="fa fa-trash-o"></i> 批量删除
+            </button>
+        </div>
+        <div class="layui-card-body">
+            <table id="LAY-table-manage" lay-filter="LAY-table-manage"></table>
+            <!--操作模板-->
+            <script type="text/html" id="opeBar">
+                <a class="layui-btn layui-btn-xs"   onclick="restore('{:url('revert')}','{{d.time}}')" title="还原" ><i class="fa fa-magic"></i></a>
+                <a class="layui-btn layui-btn-danger layui-btn-xs" title="删除" onclick="dataDel(this,'{{d.time}}')"><i class="fa fa-trash-o"></i></a>
+            </script>
+        </div>
+    </div>
+</div>
+{include file="public/footer" /}
+<script>
+    layui.use(['index', 'table'], function () {
+        var $ = layui.$
+            , form = layui.form
+            , table = layui.table
+        table.render({
+            elem: '#LAY-table-manage'
+            , url: '{:url("Data/import")}'
+            ,response: {
+                statusCode: 220 //成功的状态码,默认:0
+            }
+            , page: false
+            , even: false //开启隔行背景
+            , size: 'lg' //sm小尺寸的表格 lg大尺寸
+            // ,width:100
+            , cellMinWidth: 150
+            , limits: [5, 10, 15, 20, 25, 30]
+            , limit: "{:config('pages')}"
+            , loading: true
+            , id: 'LAY-table'
+            , cols: [[
+                {type: 'checkbox', fixed: 'left'}
+                , {field: 'time', width: '', title: '备份名称', align: 'center'}
+                , {field: 'part', width: '', title: '卷数', align: 'center'}
+                , {field: 'compress', width: 90, title: '压缩', align: 'center'}
+                , {field: 'size', width: '', title: '数据大小', align: 'center',}
+                , {field: 'date', width: '', title: '备份时间', align: 'center',templet:"<div>{{d.date?layui.util.toDateString(d.date,'yyyy-MM-dd HH:MM'):''}}</div>"}
+                , {width: '', title: '状态', align: 'center',templet:"<div><span id='restore_{{d.time}}'>-</span></div>"}
+                , {fixed: 'right', width: 90, title: '操作', align: 'center', toolbar: '#opeBar'}
+            ]]
+        });
+        var active = {
+            getCheckData: function(){
+                layer.confirm('确认批量删除备份文件吗?', {icon: 3, title:'提示'}, function(index){
+                    $.ajax({
+                        url: "{:url('batchDelData')}",
+                        type: "post",
+                        dataType: "json",
+                        data: "ids=" + getIds(),
+                        success: function (res) {
+                            if(res.code == 200){
+                                layer.msg(res.msg,{icon:1,time:1500,shade:0.1},function(){
+                                    if (res.data != "") {
+                                        $.each(res.data, function (index, item) {
+                                            $('#restore_' + item).parents("tr").remove();
+                                        })
+                                    }
+                                })
+                            } else if (res.code == 100){
+                                wk.error(res.msg,2,'');
+                            }
+                        }
+                    });
+                })
+            }
+        };
+
+        $('.layuiBtn').on('click', function () {
+            var type = $(this).data('type');
+            active[type] ? active[type].call(this) : '';
+        });
+        //获取选中目标
+        var getIds = function () {
+            var ids = [];
+            var checkStatus = table.checkStatus('LAY-table')
+                ,data = checkStatus.data;
+            $.each(data,function(index,item){
+                ids.push(item['time'])
+            });
+            return ids;
+        }
+    });
+    //还原数据
+    var restore = function(url,time){
+        $('.layui-btn').addClass('layui-disabled').attr('disabled','disabled');
+        $.get(url,{time:time} , success, "json");
+        window.onbeforeunload = function () { return "正在还原数据库,请不要关闭!";};
+        return false;
+        function success(data) {
+            if (data.code) {
+                if (data.data.gz) {
+                    // data.msg += status;
+                    data.msg += '<i class="fa fa-refresh fa-spin"></i>';
+                    // if (status.length === 5) {
+                    //     status = ".";
+                    // } else {
+                    //     status += ".";
+                    // }
+                }
+                var w = $('#restore_'+time)
+                w.removeClass('layui-badge layui-bg-green').addClass('layui-badge layui-bg-blue');
+                w.html(data.msg);
+                if(data.data == 'success'){
+                    // w.css('color','#1BB394');
+                    w.removeClass('layui-bg-blue').addClass('layui-bg-green');
+                    $('.layui-btn').removeClass('layui-disabled').removeAttr('disabled');
+                }
+                if (data.data.part) {
+                    $.get(url, {"part": data.data.part, "start": data.data.start}, success, "json");
+                } else {
+                    window.onbeforeunload = function () {return null;};
+                }
+            }else{
+                $('.layui-btn').removeClass('layui-disabled').removeAttr('disabled');
+            }
+        }
+    }
+    //删除备份
+    function dataDel(obj,id){
+        layer.confirm('确认删除此备份?', {icon: 3, title:'提示'}, function(index){
+            $.getJSON("{:url('delData')}", {'id' : id}, function(res){
+                if(res.code == 200){
+                    layer.msg(res.msg,{icon:1,time:1500,shade: 0.1},function(index){
+                        layer.close(index);
+                        $(obj).parents("tr").remove();
+                    });
+                }else if(res.code == 100){
+                    wk.error(res.msg,2,'');
+                }
+            });
+        })
+    }
+</script>
+</body>
+</html>

+ 165 - 0
application/admin/view/data/index.html

@@ -0,0 +1,165 @@
+{include file="public/header" /}
+<body>
+<div class="layui-fluid">
+    <div class="layui-card">
+        <div class="layui-form layui-card-header layuiadmin-card-header-auto">
+            <button class="layui-btn layuiBtn"  data-type="backups" id="export">
+                <i class="fa fa-refresh"></i> 立即备份
+            </button>
+            <button class="layui-btn layui-btn-info layuiBtn" data-type="optimize">
+                <i class="fa fa-line-chart"></i> 优化表
+            </button>
+            <button class="layui-btn layui-btn-normal layuiBtn" data-type="repair" >
+                <i class="fa fa-wrench"></i> 修复表
+            </button>
+        </div>
+
+        <div class="layui-card-body">
+            <table id="LAY-table-manage" lay-filter="LAY-table-manage"></table>
+            <!--操作模板-->
+            <script type="text/html" id="opeBar">
+                <a class="layui-btn layui-btn-info layui-btn-xs" title="优化表" onclick="together('{:url('optimize')}','{{d.name}}')" ><i class="fa fa-line-chart"></i></a>
+                <a class="layui-btn layui-btn-normal layui-btn-xs" title="修复表" onclick="together('{:url('repair')}','{{d.name}}')" ><i class="fa fa-wrench"></i></a>
+            </script>
+        </div>
+    </div>
+</div>
+{include file="public/footer" /}
+<script>
+    layui.use(['index', 'table'], function () {
+        var $ = layui.$
+            , form = layui.form
+            , table = layui.table
+        table.render({
+            elem: '#LAY-table-manage'
+            , url: '{:url("Data/index")}'
+            ,response: {
+                statusCode: 220 //成功的状态码,默认:0
+            }
+            , page: false
+            , even: false //开启隔行背景
+            , size: 'lg' //sm小尺寸的表格 lg大尺寸
+            // ,width:100
+            , cellMinWidth: 150
+            , limits: [5, 10, 15, 20, 25, 30]
+            , limit: "{:config('pages')}"
+            , loading: true
+            , id: 'LAY-table'
+            , cols: [[
+                {type: 'checkbox', fixed: 'left',LAY_CHECKED:true}
+                , {field: 'name', width: '', title: '表名',align: 'center'}
+                , {field: 'comment', width: '', title: '注释', align: 'center'}
+                , {field: 'engine', width: 90, title: '引擎', align: 'center'}
+                , {field: 'rows', width: '', title: '数据量', align: 'center',templet:'<div>【{{d.rows}}】条记录</div>'}
+                , {field: 'data_length', width: '', title: '数据大小',align: 'center'}
+                , {field: 'create_time', width: '', title: '创建时间', align: 'center',templet:"<div>{{d.create_time?layui.util.toDateString(d.create_time,'yyyy-MM-dd HH:MM'):''}}</div>"}
+                , {width: '', title: '状态', align: 'center',templet:"<div><span class='layui-badge layui-bg-orange' id='backup_{{d.name}}'>等待备份...</span></div>"}
+                , {fixed: 'right', width: 100, title: '操作', align: 'center', toolbar: '#opeBar'}
+            ]]
+        });
+        //事件
+        var active = {
+            //备份数据库
+            backups: function() {
+                var $export = $('#export');
+                $('.layui-btn').addClass('layui-disabled').attr('disabled','disabled');
+                $export.html("正在发送备份请求...");
+                $.post("{:url('export')}",{ids:getIds()},function (data) {
+                    if (data.code) {
+                        tables = data.data.tables;
+                        $export.html(data.msg + "开始备份,请不要关闭本页面!");
+                        backup(data.data.tab);
+                        window.onbeforeunload = function () {
+                            return "正在备份数据库,请不要关闭!";
+                        };
+                    } else {
+                        if (data.code == 100) {
+                            wk.error(data.msg, 2, '');
+                        }
+                        $export.html("立即备份");
+                        setTimeout(function () {
+                            $('.layui-btn').removeClass('layui-disabled').removeAttr('disabled');
+                        }, 1500);
+                    }
+                });
+            }
+            //优化表
+            ,optimize:function(){
+                together("{:url('optimize')}",getIds());
+            }
+            //修复表
+            ,repair:function(){
+                together("{:url('repair')}",getIds());
+            }
+        };
+
+        $('.layuiBtn').on('click', function () {
+            var type = $(this).data('type');
+            active[type] ? active[type].call(this) : '';
+        });
+        //获取选中目标
+        var getIds = function () {
+            var ids = [];
+            var checkStatus = table.checkStatus('LAY-table')
+                ,data = checkStatus.data;
+            $.each(data,function(index,item){
+                ids.push(item['name'])
+            });
+            return ids;
+        }
+        //开始备份
+        var backup = function(tab, status) {
+            var $export = $('#export');
+            status && showmsg(tab.id, "开始备份...(0%)");
+            $.get("{:url('export')}", tab, function (data) {
+                if (data.code) {
+                    showmsg(tab.id, data.msg);
+                    if (!$.isPlainObject(data.data.tab)) {
+                        $('.layui-btn').removeClass('layui-disabled').removeAttr('disabled');
+                        $export.html("备份完成,点击重新备份");
+                        window.onbeforeunload = function () {
+                            return null;
+                        };
+                        return;
+                    }
+                    backup(data.data.tab, tab.id != data.data.tab.id);
+                } else {
+                    if(data.code == 100){
+                        wk.error(data.msg,2,'');
+                    }
+                    $export.html("立即备份");
+                    setTimeout(function () {
+                        $('.layui-btn').removeClass('layui-disabled').removeAttr('disabled');
+                    }, 1500);
+                }
+            });
+        }
+        var  showmsg = function(id, msg) {
+            var w = $('#backup_'+tables[id]);
+            w.removeClass('layui-bg-green').addClass('layui-bg-orange');
+            if(msg == '备份完成!'){
+                w.removeClass('layui-bg-orange').addClass('layui-bg-green');
+            }
+            w.html(msg);
+            // w.css('color','#1BB394');
+        }
+    });
+    //优化表&修复表
+    var together = function(url,data){
+        $.ajax({
+            url:url,
+            data:"ids="+data,
+            type:'post',
+            dataType:'json',
+            success:function(res){
+                if(res.code == 200){
+                    wk.success(res.msg,1,'');
+                } else if (res.code == 100){
+                    wk.error(res.msg,2,'');
+                }
+            }
+        })
+    }
+</script>
+</body>
+</html>

+ 187 - 0
application/admin/view/email/index.html

@@ -0,0 +1,187 @@
+{include file="public/header" /}
+<body>
+<div class="layui-fluid">
+    <div class="layui-row layui-col-space15">
+        <div class="layui-col-md12">
+            <div class="layui-card">
+                <div class="layui-card-header">邮件服务</div>
+                <div class="layui-card-body">
+
+                    <div class="layui-form layui-form-pane">
+                        <div class="layui-form-item">
+                            <label class="layui-form-label">SMTP服务器</label>
+                            <div class="layui-input-inline">
+                                <input type="text" value="{:config('smtp.server')}" class="layui-input layui-disabled" disabled>
+                            </div>
+                            <div class="layui-form-mid layui-word-aux">如:smtp.163.com</div>
+                        </div>
+                        <div class="layui-form-item">
+                            <label class="layui-form-label">SMTP端口号</label>
+                            <div class="layui-input-inline">
+                                <input type="text" value="{:config('smtp.serverport')}" class="layui-input layui-disabled" disabled>
+                            </div>
+                            <div class="layui-form-mid layui-word-aux">一般为 25 或 465</div>
+                        </div>
+                        <div class="layui-form-item">
+                            <label class="layui-form-label">发件人邮箱</label>
+                            <div class="layui-input-inline">
+                                <input type="text" value="{:config('smtp.usermail')}" class="layui-input layui-disabled" disabled>
+                            </div>
+                        </div>
+                        <div class="layui-form-item">
+                            <label class="layui-form-label">邮箱登入密码</label>
+                            <div class="layui-input-inline">
+                                <input type="password"  value="{:config('smtp.pass')}" class="layui-input layui-disabled" disabled>
+                            </div>
+                        </div>
+                        <div class="layui-form-item">
+                            <label class="layui-form-label">收件人邮箱</label>
+                            <div class="layui-input-block">
+                                <input type="text" lay-verify="required" name="mailTo" class="layui-input" placeholder="多个邮箱请用逗号(英文)连接">
+                            </div>
+                        </div>
+                        <div class="layui-form-item">
+                            <label class="layui-form-label">邮件主题</label>
+                            <div class="layui-input-block">
+                                <input type="text" lay-verify="required" name="subject" class="layui-input" placeholder="文本">
+                            </div>
+                        </div>
+                        <div class="layui-form-item layui-form-text">
+                            <label class="layui-form-label">邮件内容</label>
+                            <div class="layui-input-block">
+                                <textarea name="body" lay-verify="required" class="layui-textarea" placeholder="文本/HTML"></textarea>
+                            </div>
+                        </div>
+                        <div class="layui-form-item">
+                            <div class="layui-input-block">
+                                <button class="layui-btn" lay-submit lay-filter="send_system_email">发送</button>
+                            </div>
+                        </div>
+                    </div>
+
+                </div>
+            </div>
+        </div>
+        <div class="layui-col-md12">
+            <div class="layui-card">
+                <div class="layui-card-header">云之讯短信</div>
+                <div class="layui-card-body">
+
+                    <div class="layui-form layui-form-pane">
+                        <div class="layui-form-item">
+                            <label class="layui-form-label">验证码</label>
+                            <div class="layui-input-inline">
+                                <input type="text" name="code" value="{:GetRandCode()}" class="layui-input layui-disabled" disabled>
+                            </div>
+                        </div>
+                        <div class="layui-form-item">
+                            <label class="layui-form-label">手机号</label>
+                            <div class="layui-input-block">
+                                <input type="text" name="phone" lay-verify="phone" class="layui-input" placeholder="中国大陆手机号" >
+                            </div>
+                        </div>
+                        <div class="layui-form-item">
+                            <div class="layui-input-block">
+                                <button class="layui-btn" lay-submit lay-filter="send_yzx_code">发送</button>
+                            </div>
+                        </div>
+                    </div>
+
+                </div>
+            </div>
+        </div>
+        <div class="layui-col-md12">
+            <div class="layui-card">
+                <div class="layui-card-header">阿里短信</div>
+                <div class="layui-card-body">
+
+                    <div class="layui-form layui-form-pane">
+                        <div class="layui-form-item">
+                            <label class="layui-form-label">验证码</label>
+                            <div class="layui-input-inline">
+                                <input type="text" name="code" value="{:GetRandCode()}" class="layui-input layui-disabled" disabled>
+                            </div>
+                        </div>
+                        <div class="layui-form-item">
+                            <label class="layui-form-label">手机号</label>
+                            <div class="layui-input-block">
+                                <input type="text" name="phone" lay-verify="phone" class="layui-input" placeholder="中国大陆手机号" >
+                            </div>
+                        </div>
+                        <div class="layui-form-item">
+                            <div class="layui-input-block">
+                                <button class="layui-btn" lay-submit lay-filter="send_ali_code">发送</button>
+                            </div>
+                        </div>
+                    </div>
+
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+{include file="public/footer" /}
+<script>
+    layui.use(['form'],function () {
+        var form = layui.form
+        form.on('submit(send_system_email)', function (data) {
+            $('.layui-btn').addClass('layui-disabled').attr('disabled','disabled');
+            var loading = layer.load(3);
+            $.ajax({
+                url:"{:url('sendEmail')}",
+                type:'post',
+                dataType:'json',
+                data:data.field,
+                success:function(res){
+                    if (res.code == 200) {
+                        layer.close(loading);
+                        wk.success(res.msg,'$(".layui-btn").removeClass(\'layui-disabled\').removeAttr(\'disabled\')');
+                    } else {
+                        layer.close(loading);
+                        wk.error(res.msg,'$(".layui-btn").removeClass(\'layui-disabled\').removeAttr(\'disabled\')');
+                    }
+                }
+            })
+        })
+        form.on('submit(send_yzx_code)', function (data) {
+            $('.layui-btn').addClass('layui-disabled').attr('disabled','disabled');
+            var loading = layer.load(3);
+            $.ajax({
+                url:"{:url('sendYzxCode')}",
+                type:'post',
+                dataType:'json',
+                data:data.field,
+                success:function(res){
+                    if (res.code == 200) {
+                        layer.close(loading);
+                        wk.success(res.msg,'$(".layui-btn").removeClass(\'layui-disabled\').removeAttr(\'disabled\')');
+                    } else {
+                        layer.close(loading);
+                        wk.error(res.msg,'$(".layui-btn").removeClass(\'layui-disabled\').removeAttr(\'disabled\')');
+                    }
+                }
+            })
+        })
+        form.on('submit(send_ali_code)', function (data) {
+            $('.layui-btn').addClass('layui-disabled').attr('disabled','disabled');
+            var loading = layer.load(3);
+            $.ajax({
+                url:"{:url('sendAliCode')}",
+                type:'post',
+                dataType:'json',
+                data:data.field,
+                success:function(res){
+                    if (res.code == 200) {
+                        layer.close(loading);
+                        wk.success(res.msg,'$(".layui-btn").removeClass(\'layui-disabled\').removeAttr(\'disabled\')');
+                    } else {
+                        layer.close(loading);
+                        wk.error(res.msg,'$(".layui-btn").removeClass(\'layui-disabled\').removeAttr(\'disabled\')');
+                    }
+                }
+            })
+        })
+    })
+</script>
+</body>
+</html>

+ 333 - 0
application/admin/view/index.html

@@ -0,0 +1,333 @@
+{include file="public/header" /}
+<body class="layui-layout-body">
+<div id="LAY_app">
+    <div class="layui-layout layui-layout-admin">
+        <div class="layui-header">
+            <!-- 头部区域 -->
+            <ul class="layui-nav layui-layout-left">
+                <li class="layui-nav-item layadmin-flexible" lay-unselect="">
+                    <a href="javascript:;" layadmin-event="flexible" title="侧边伸缩">
+                        <i class="layui-icon layui-icon-shrink-right" id="LAY_app_flexible"></i>
+                    </a>
+                </li>
+                <!-- <li class="layui-nav-item layui-hide-xs" lay-unselect="">
+                    <a href="http://www.layui.com/admin/" target="_blank" title="前台">
+                        <i class="layui-icon layui-icon-website"></i>
+                    </a>
+                </li> -->
+                <li class="layui-nav-item" lay-unselect="">
+                    <a href="javascript:;" layadmin-event="refresh" title="刷新">
+                        <i class="layui-icon layui-icon-refresh-3"></i>
+                    </a>
+                </li>
+                <!-- <li class="layui-nav-item layui-hide-xs" lay-unselect="">
+                    <input type="text" placeholder="搜索..." autocomplete="off" class="layui-input layui-input-search"
+                           layadmin-event="serach" lay-action="template/search.html?keywords=">
+                </li> -->
+            </ul>
+            <ul class="layui-nav layui-layout-right" lay-filter="layadmin-layout-right" id="view">
+
+                <!-- <li class="layui-nav-item" lay-unselect="">
+                    <a lay-href="../src/views/app/message/index.html" layadmin-event="message" lay-text="消息中心">
+                        <i class="layui-icon layui-icon-notice"></i> -->
+
+                <!-- 如果有新消息,则显示小圆点 -->
+                <!--    <span class="layui-badge-dot"></span>
+               </a>
+           </li> -->
+                <li class="layui-nav-item layui-hide-xs" lay-unselect="">
+                    <a href="javascript:;" layadmin-event="note" title="便签">
+                        <i class="layui-icon layui-icon-note"></i>
+                    </a>
+                </li>
+                <li class="layui-nav-item layui-hide-xs" lay-unselect="">
+                    <a href="javascript:;" layadmin-event="fullscreen" title="全屏">
+                        <i class="layui-icon layui-icon-screen-full"></i>
+                    </a>
+                </li>
+                <li class="layui-nav-item" lay-unselect="" >
+                    <img src="{$portrait}" data-original="{$portrait}" class="layui-circle layui-table-img" onerror="this.src='/static/admin/images/head_default.gif'" alt="{:session('rolename')}" title="{:session('rolename')}" >
+                </li>
+                <li class="layui-nav-item" lay-unselect="">
+                    <a href="javascript:;">
+                        <cite>{$username}</cite>
+                        <span class="layui-nav-more"></span></a>
+                    <dl class="layui-nav-child">
+                        <!--<dd><a href="../src/views/set/user/info.html"><i class="fa fa-user-circle"></i> 基本资料</a></dd>-->
+                        <dd><a href="javascript:;" onclick="wk.layer_show1('基本资料',$('#pInfo'),550,405)"><i class="fa fa-user-circle-o"></i> 基本资料</a></dd>
+                        <dd><a href="javascript:;" onclick="wk.layer_show1('修改头像',$('#headCrop'),700,570)"><i class="fa fa-crop"></i> 修改头像</a></dd>
+                        <dd><a href="javascript:;" onclick="wk.layer_show1('修改密码',$('#changePwd'),500,320);"><i class="fa fa-unlock-alt"></i> 修改密码</a></dd>
+                        <dd><a href="javascript:;" onclick="cache()"><i class="fa fa-history"></i> 清除缓存</a></dd>
+                        <hr>
+                        <dd  style="text-align: center;"><a  href="javascript:;" onclick="loginOut()"><i class="fa fa-sign-out"></i> 退出</a></dd>
+                    </dl>
+                </li>
+
+                <li class="layui-nav-item layui-hide-xs" lay-unselect="">
+                    <a href="javascript:;" layadmin-event="theme" title="皮肤">
+                        <i class="layui-icon layui-icon-theme"></i>
+                    </a>
+                </li>
+                <!--<li class="layui-nav-item layui-hide-xs" lay-unselect="">-->
+                    <!--<a href="javascript:;" layadmin-event="about"><i-->
+                            <!--class="layui-icon layui-icon-more-vertical"></i></a>-->
+                <!--</li>-->
+                <li class="layui-nav-item layui-show-xs-inline-block layui-hide-sm" lay-unselect="">
+                    <a href="javascript:;" layadmin-event="more"><i class="layui-icon layui-icon-more-vertical"></i></a>
+                </li>
+            </ul>
+        </div>
+
+        <!--侧边菜单-->
+        <div class="layui-side layui-side-menu">
+            <div class="layui-side-scroll">
+                <div class="layui-logo">
+                    <span>layui</span>
+                </div>
+                <ul class="layui-nav layui-nav-tree " id="LAY-system-side-menu"  lay-filter="layadmin-system-side-menu" lay-shrink="all">
+                    {if !empty($menu)}
+                        {foreach name="menu" item="vo"}
+                            <li data-name="home" class="layui-nav-item">
+                                {if condition="$vo.name eq '#'"}
+                                    <a href="javascript:;" lay-tips="{$vo.title}" lay-direction="2">
+                                        <i class="{$vo.css} layui-font"></i>
+                                        <cite>{$vo.title}</cite>
+                                        <span class="layui-nav-more"></span>
+                                    </a>
+                                {else /}
+                                    <a href="javascript:;" lay-href="{$vo.href}" lay-tips="{$vo.title}"
+                                       lay-direction="2">
+                                        <i class="{$vo.css} layui-font"></i>
+                                        <cite>{$vo.title}</cite>
+                                    </a>
+                                {/if}
+                                {if condition="$vo.name eq '#'"}
+                                    <dl class="layui-nav-child">
+                                        {if !empty($vo['child'])}
+                                            {foreach name="$vo['child']" item="v"}
+                                                {if condition="$v.name neq '##'"}
+                                                    <dd data-name="console">
+                                                        <a lay-href="{$v.href}">{$v.title}</a>
+                                                    </dd>
+                                                {else /}
+                                                    <dd data-name="grid">
+                                                        <a href="javascript:;">{$v.title}<span class="layui-nav-more"></span></a>
+                                                        <dl class="layui-nav-child">
+                                                            {if !empty($v['child'])}
+                                                                {foreach name="$v['child']" item="z"}
+                                                                    <dd data-name="list"><a lay-href="{$z.href}">{$z.title}</a></dd>
+                                                                {/foreach}
+                                                            {/if}
+                                                        </dl>
+                                                    </dd>
+                                                {/if}
+                                            {/foreach}
+                                        {/if}
+                                    </dl>
+                                {/if}
+                            </li>
+                        {/foreach}
+                    {/if}
+                </ul>
+            </div>
+        </div>
+        <!-- 页面标签 -->
+        <div class="layadmin-pagetabs" id="LAY_app_tabs">
+            <div class="layui-icon layadmin-tabs-control layui-icon-prev" layadmin-event="leftPage"></div>
+            <div class="layui-icon layadmin-tabs-control layui-icon-next" layadmin-event="rightPage"></div>
+            <div class="layui-icon layadmin-tabs-control layui-icon-down">
+                <ul class="layui-nav layadmin-tabs-select" lay-filter="layadmin-pagetabs-nav">
+                    <li class="layui-nav-item" lay-unselect="">
+                        <a href="javascript:;"><span class="layui-nav-more"></span></a>
+                        <dl class="layui-nav-child layui-anim-fadein">
+                            <dd layadmin-event="closeThisTabs"><a href="javascript:;">关闭当前标签页</a></dd>
+                            <dd layadmin-event="closeOtherTabs"><a href="javascript:;">关闭其它标签页</a></dd>
+                            <dd layadmin-event="closeAllTabs"><a href="javascript:;">关闭全部标签页</a></dd>
+                        </dl>
+                    </li>
+                </ul>
+            </div>
+            <div class="layui-tab" lay-unauto="" lay-allowclose="true" lay-filter="layadmin-layout-tabs">
+                <ul class="layui-tab-title" id="LAY_app_tabsheader">
+                    <li lay-id="../src/views/home/console.html" lay-attr="../src/views/home/console.html" class="layui-this"><i class="layui-icon layui-icon-home"></i> 首页<i class="layui-icon layui-unselect layui-tab-close">ဆ</i>
+                    </li>
+                </ul>
+            </div>
+        </div>
+
+
+        <!-- 主体内容 -->
+        <div class="layui-body" id="LAY_app_body">
+            <div class="layadmin-tabsbody-item layui-show">
+                <iframe src="{:url('Index/indexPage')}" frameborder="0" class="layadmin-iframe"></iframe>
+            </div>
+        </div>
+
+        <!-- 辅助元素,一般用于移动设备下遮罩 -->
+        <div class="layadmin-body-shade" layadmin-event="shade"></div>
+    </div>
+</div>
+{include file="public/footer" /}
+<!--修改密码-->
+<div id="changePwd" style="display:none;">
+    <div class="layui-fluid layui-col-xs12">
+        <div class="layui-card-body layui-form layui-form-pane">
+            <div class="layui-row layui-form-item ">
+                <div class="layui-form-item">
+                    <label class="layui-form-label">当前密码</label>
+                    <div class="layui-input-block">
+                        <input type="password" name="old_pwd"  placeholder="输入当前密码" lay-verify="required|oldpwd" class="layui-input" autocomplete="off"/>
+                    </div>
+                </div>
+                <div class="layui-form-item">
+                    <label class="layui-form-label">新密码</label>
+                    <div class="layui-input-block">
+                        <input type="password" name="new_pwd"  placeholder="输入新密码" lay-verify="required|newpwd" class="layui-input" autocomplete="off"/>
+                    </div>
+                </div>
+                <div class="layui-form-item">
+                    <label class="layui-form-label">确认密码</label>
+                    <div class="layui-input-block">
+                        <input type="password" name="r_pwd"  placeholder="输入确认密码" lay-verify="required|rpwd" class="layui-input" autocomplete="off"/>
+                    </div>
+                </div>
+                <div class="layui-form-item">
+                    <div class="layui-input-block">
+                        <button class="layui-btn" lay-submit="" lay-filter="component-form-element">确认修改
+                        </button>
+                        <button class="layui-btn layui-btn-primary" onclick="layer.closeAll()">关闭</button>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+<!--个人信息-->
+<div id="pInfo" style="display:none;">
+    <div class="layui-fluid layui-col-xs12">
+        <div class="layui-card-body layui-form layui-form-pane">
+            <div class="layui-row layui-form-item ">
+                <div class="layui-form-item">
+                    <label class="layui-form-label">用户名</label>
+                    <div class="layui-input-block">
+                        <input type="text" class="layui-input" style="cursor:not-allowed;" value="{:session('username')}" disabled/>
+                    </div>
+                </div>
+                <div class="layui-form-item">
+                    <label class="layui-form-label">角&nbsp;&nbsp;&nbsp;&nbsp;色</label>
+                    <div class="layui-input-block">
+                        <input type="text" class="layui-input" style="cursor:not-allowed;"  value="{:session('rolename')}" disabled/>
+                    </div>
+                </div>
+                <div class="layui-form-item">
+                    <label class="layui-form-label">手机号</label>
+                    <div class="layui-input-block">
+                        <input type="text" class="layui-input" style="cursor:not-allowed;" value="{:session('phone')}" disabled/>
+                    </div>
+                </div>
+                <div class="layui-form-item layui-form-text">
+                    <label class="layui-form-label">描&nbsp;&nbsp;&nbsp;&nbsp;述</label>
+                    <div class="layui-input-block">
+                        <textarea class="layui-textarea"style="cursor:not-allowed;resize:none" disabled>{:session('describe')}</textarea>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+<script type="text/javascript" src="__JS__/plugins/cropper/Crop.js"></script>
+<script>
+    //裁剪后的处理
+    $("#sureCut").on("click",function () {
+        if ($("#tailoringImg").attr("src") == null ){
+            layer.msg('请先选择头像',{anim:6})
+        }else{
+            var cas = $('#tailoringImg').cropper('getCroppedCanvas');//获取被裁剪后的canvas
+            var base64url = cas.toDataURL('image/png'); //转换为base64地址形式
+            //关闭裁剪框
+            layer.closeAll();
+            $.ajax({
+                url : "{:url('Upload/updateFace')}",
+                type : "post",
+                dataType : "json",
+                data:"base64url="+base64url+"&id={:session('uid')}",
+                success : function(data) {
+                    if(data.code == 200){
+                        wk.success(data.msg,'window.location.reload()')
+                    }else if(data.code == 100){
+                        wk.error(data.msg);
+                    }
+                }
+            });
+        }
+    });
+
+    layui.use(['form'], function() {
+        var form = layui.form;
+        form.verify({
+            oldpwd:function(value,item){
+                var checkResult = "";
+                $.ajax({
+                    url:"{:url('User/editPwd')}",
+                    type:'post',
+                    data:"old_pwd="+value +"&type=checkPassword",
+                    async: false,//必须同步
+                    success:function(res){
+                        if(res.code == 100){
+                            checkResult = "当前密码错误";
+                        }
+                    }
+                })
+                return checkResult;
+            },
+            newpwd: [/^[\S]{6,16}$/,'密码必须6到16位,且不能出现空格'],
+            rpwd:function(value,item){
+                if(!/^[\S]{6,16}$/.test(value)){
+                    return '密码必须6到16位,且不能出现空格';
+                }
+                var newpwd = $('input[name=new_pwd]').val();
+                if(newpwd != value){
+                    return "两次输入密码不一致";
+                }
+            }
+
+        });
+        form.on('submit(component-form-element)', function (data) {
+            $('.layui-btn').addClass('layui-disabled').attr('disabled','disabled');
+            $.ajax({
+                url:"{:url('User/editPwd')}",
+                type:'post',
+                dataType:'json',
+                data:data.field,
+                success:function(res){
+                    if (res.code == 200) {
+                        wk.success(res.msg,'',"{:url('admin/Login/loginOut')}");
+                    } else {
+                        wk.error(res.msg,'$(".layui-btn").removeClass(\'layui-disabled\').removeAttr(\'disabled\')');
+                    }
+                }
+            })
+        });
+    });
+
+    var loginOut = function(){
+        layer.confirm('你确定要退出吗?', {icon: 3,title:'提示'}, function(index){
+            layer.close(index);
+            window.location.href="{:url('admin/login/loginOut')}";
+        });
+    }
+    //清除缓存
+    var cache = function(){
+        layer.confirm('你确定要清除缓存吗?', {icon: 3, title:'提示'}, function(index){
+            $.getJSON("{:url('admin/index/clear')}",function(res){
+                if(res.code == 200){
+                    wk.success(res.msg);
+                }else if(res.code == 100){
+                    wk.error(res.msg);
+                }
+            });
+        })
+    }
+</script>
+</body>
+</html>

+ 73 - 0
application/admin/view/index/index.html

@@ -0,0 +1,73 @@
+{include file="public/header" /}
+<body>
+<div class="layui-fluid">
+    <div class="layui-row layui-col-space15">
+
+        <div class="layui-col-sm6 layui-col-md3">
+            <div class="layui-card">
+                <div class="layui-card-header">
+                    访问量
+                    <span class="layui-badge layui-bg-blue layuiadmin-badge">周</span>
+                </div>
+                <div class="layui-card-body layuiadmin-card-list">
+                    <p class="layuiadmin-big-font">9,999,666</p>
+                    <p>
+                        总计访问量
+                        <span class="layuiadmin-span-color">88万 <i class="layui-inline layui-icon layui-icon-flag"></i></span>
+                    </p>
+                </div>
+            </div>
+        </div>
+        <div class="layui-col-sm6 layui-col-md3">
+            <div class="layui-card">
+                <div class="layui-card-header">
+                    下载
+                    <span class="layui-badge layui-bg-cyan layuiadmin-badge">月</span>
+                </div>
+                <div class="layui-card-body layuiadmin-card-list">
+                    <p class="layuiadmin-big-font">33,555</p>
+                    <p>
+                        新下载
+                        <span class="layuiadmin-span-color">10% <i class="layui-inline layui-icon layui-icon-face-smile-b"></i></span>
+                    </p>
+                </div>
+            </div>
+        </div>
+        <div class="layui-col-sm6 layui-col-md3">
+            <div class="layui-card">
+                <div class="layui-card-header">
+                    收入
+                    <span class="layui-badge layui-bg-green layuiadmin-badge">年</span>
+                </div>
+                <div class="layui-card-body layuiadmin-card-list">
+
+                    <p class="layuiadmin-big-font">999,666</p>
+                    <p>
+                        总收入
+                        <span class="layuiadmin-span-color">*** <i class="layui-inline layui-icon layui-icon-dollar"></i></span>
+                    </p>
+                </div>
+            </div>
+        </div>
+        <div class="layui-col-sm6 layui-col-md3">
+            <div class="layui-card">
+                <div class="layui-card-header">
+                    活跃用户
+                    <span class="layui-badge layui-bg-orange layuiadmin-badge">月</span>
+                </div>
+                <div class="layui-card-body layuiadmin-card-list">
+
+                    <p class="layuiadmin-big-font">66,666</p>
+                    <p>
+                        最近一个月
+                        <span class="layuiadmin-span-color">15% <i class="layui-inline layui-icon layui-icon-user"></i></span>
+                    </p>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+</div>
+{include file="public/footer" /}
+</body>
+</html>

+ 119 - 0
application/admin/view/log/operate_log.html

@@ -0,0 +1,119 @@
+{include file="public/header" /}
+<body>
+<div class="layui-fluid">
+    <div class="layui-card">
+        <div class="layui-form layui-card-header layuiadmin-card-header-auto">
+            <div class="layui-form-item">
+                <div class="layui-inline">
+                    <div class="layui-input-inline">
+                        <input type="text" name="start" class="layui-input" onfocus="wk.lay_date(this);" placeholder="开始日期">
+                    </div>
+                    <div class="layui-form-mid">
+                        -
+                    </div>
+                    <div class="layui-input-inline">
+                        <input type="text" name="end" class="layui-input" onfocus="wk.lay_date(this);" placeholder="结束日期">
+                    </div>
+                </div>
+                <div class="layui-inline">
+                    <div class="layui-input-inline">
+                        <select name="key"  lay-search="">
+                            <option  value="">选择管理员</option>
+                            {volist name="search_user" id="v"}
+                                <option value="{$key}" {if condition="$val eq $key"}selected{/if}>{$v}</option>
+                            {/volist}
+                        </select>
+                    </div>
+                </div>
+                <div class="layui-inline">
+                    <div class="layui-input-inline">
+                        <button class="layui-btn" lay-submit="" lay-filter="LAY-search">立即搜索</button>
+                        <button  class="layui-btn layui-btn-normal" id="empty"  lay-submit="" lay-filter="LAY-search">重置</button>
+                    </div>
+                </div>
+            </div>
+            <div>
+                <button class="layui-btn layui-btn-danger layuiBtn" data-type="getCheckData" >
+                    <i class="fa fa-trash-o"></i> 批量删除
+                </button>
+            </div>
+        </div>
+
+        <div class="layui-card-body">
+            <table id="LAY-table-manage" lay-filter="LAY-table-manage"></table>
+            <!--操作模板-->
+            <script type="text/html" id="opeBar">
+                <a class="layui-btn layui-btn-danger layui-btn-xs" title="删除" onclick="wk.confirm('{{d.log_id}}','{:url('del_log')}')"><i class="fa fa-trash-o"></i></a>
+            </script>
+            <!--状态模板-->
+            <script type="text/html" id="staBar">
+                {{# if(d.status==200){ }}
+                    <span class="layui-badge layui-bg-green">操作成功</span>
+                {{# }else{ }}
+                    <span class="layui-badge">操作失败</span>
+                {{# } }}
+            </script>
+        </div>
+    </div>
+</div>
+{include file="public/footer" /}
+<script>
+    layui.use(['index', 'table'], function () {
+        var $ = layui.$
+            , form = layui.form
+            , table = layui.table
+        table.render({
+            elem: '#LAY-table-manage'
+            , url: '{:url("Log/operate_log")}'
+            ,response: {
+                statusCode: 220 //成功的状态码,默认:0
+            }
+            , page: true
+            , even: false //开启隔行背景
+            , size: 'lg' //sm小尺寸的表格 lg大尺寸
+            // ,width:100
+            , autoSort: false
+            , height: "full-220"
+            , cellMinWidth: 150
+            , limits: [10, 20, 30, 40, 50]
+            , limit: "{:config('pages')}"
+            , loading: true
+            , id: 'LAY-table'
+            , cols: [[
+                {type: 'checkbox', fixed: 'left',}
+                , {type:'numbers', width: 80, title: '序号'}
+                , {field: 'admin_id', width: 80, title: '用户ID', align: 'center'}
+                , {field: 'admin_name', width: '', title: '操作用户', align: 'center', templet: '#imgTpl'}
+                , {field: 'description', width: 300, title: '描述', align: 'center', templet: '#titleTpl'}
+                , {field: 'ip', width: '', title: '操作IP', align: 'center'}
+                , {field: 'ipaddr', width: '', title: '地址', align: 'center'}
+                , {field: 'add_time', width: 170, title: '操作时间', sort: true, align: 'center',templet:"<div>{{layui.util.toDateString(d.add_time*1000,'yyyy年MM月dd日')}}</div>"}
+                , {field: 'status',fixed: 'right', width: 100, title: '状态', align: 'center', templet: '#staBar'}
+                , {fixed: 'right', width: 60, title: '操作', align: 'center', toolbar: '#opeBar'}
+            ]]
+        });
+        //事件
+        var active = {
+            getCheckData: function(){
+                //批量删除
+                wk.batchDel(getIds(),"{:url('batchDelLog')}");
+            }
+        };
+
+        $('.layuiBtn').on('click', function () {
+            var type = $(this).data('type');
+            active[type] ? active[type].call(this) : '';
+        });
+        var getIds = function () {
+            var ids = [];
+            var checkStatus = table.checkStatus('LAY-table')
+                ,data = checkStatus.data;
+            $.each(data,function(index,item){
+                ids.push(item['log_id'])
+            });
+            return ids;
+        }
+    });
+</script>
+</body>
+</html>

Alguns ficheiros não foram mostrados porque muitos ficheiros mudaram neste diff