Преглед на файлове

[更新]升级V4.0版本

Anyon преди 6 години
родител
ревизия
7270556494
променени са 100 файла, в които са добавени 11228 реда и са изтрити 8248 реда
  1. 0 3
      .gitattributes
  2. 5 8
      .gitignore
  3. 0 20
      LICENSE
  4. 35 110
      README.md
  5. 0 947
      admin_v3.sql
  6. 981 0
      admin_v4.sql
  7. 0 1
      application/.htaccess
  8. 55 89
      application/admin/controller/Auth.php
  9. 69 35
      application/admin/controller/Config.php
  10. 103 79
      application/admin/controller/Index.php
  11. 12 33
      application/admin/controller/Log.php
  12. 69 56
      application/admin/controller/Login.php
  13. 46 89
      application/admin/controller/Menu.php
  14. 92 0
      application/admin/controller/Message.php
  15. 85 92
      application/admin/controller/Node.php
  16. 0 152
      application/admin/controller/Plugs.php
  17. 89 0
      application/admin/controller/Queue.php
  18. 44 76
      application/admin/controller/User.php
  19. 53 0
      application/admin/controller/api/Message.php
  20. 217 0
      application/admin/controller/api/Plugs.php
  21. 54 0
      application/admin/controller/api/Update.php
  22. 0 71
      application/admin/middleware/Auth.php
  23. 122 0
      application/admin/queue/JobsBase.php
  24. 207 0
      application/admin/service/Auth.php
  25. 55 0
      application/admin/service/Log.php
  26. 72 0
      application/admin/service/Message.php
  27. 128 0
      application/admin/service/Queue.php
  28. 111 0
      application/admin/sys.php
  29. 3659 0
      application/admin/view/api/plugs/icon.html
  30. 65 0
      application/admin/view/api/plugs/message.html
  31. 432 0
      application/admin/view/api/plugs/upfile.html
  32. 58 101
      application/admin/view/auth/apply.html
  33. 16 17
      application/admin/view/auth/form.html
  34. 54 69
      application/admin/view/auth/index.html
  35. 42 0
      application/admin/view/auth/index_search.html
  36. 24 210
      application/admin/view/config/file.html
  37. 25 0
      application/admin/view/config/file_local.html
  38. 86 0
      application/admin/view/config/file_oss.html
  39. 87 0
      application/admin/view/config/file_qiniu.html
  40. 0 82
      application/admin/view/config/index.html
  41. 61 0
      application/admin/view/config/info.html
  42. 8 0
      application/admin/view/index/command.html
  43. 128 72
      application/admin/view/index/index.html
  44. 41 42
      application/admin/view/index/main.html
  45. 54 93
      application/admin/view/log/index.html
  46. 56 0
      application/admin/view/log/index_search.html
  47. 0 76
      application/admin/view/log/sms.html
  48. 37 70
      application/admin/view/login/index.html
  49. 11 0
      application/admin/view/main.html
  50. 66 53
      application/admin/view/menu/form.html
  51. 67 74
      application/admin/view/menu/index.html
  52. 86 0
      application/admin/view/message/index.html
  53. 57 0
      application/admin/view/message/index_search.html
  54. 47 34
      application/admin/view/node/index.html
  55. 0 3660
      application/admin/view/plugs/icon.html
  56. 0 554
      application/admin/view/plugs/upfile.html
  57. 0 13
      application/admin/view/public/content.html
  58. 0 26
      application/admin/view/public/main.html
  59. 78 0
      application/admin/view/queue/index.html
  60. 68 0
      application/admin/view/queue/index_search.html
  61. 27 28
      application/admin/view/user/auth.html
  62. 45 48
      application/admin/view/user/form.html
  63. 70 128
      application/admin/view/user/index.html
  64. 57 0
      application/admin/view/user/index_search.html
  65. 38 28
      application/admin/view/user/pass.html
  66. 0 110
      application/common.php
  67. 11 7
      application/index/controller/Index.php
  68. 0 18
      application/middleware.php
  69. 50 0
      application/service/controller/Config.php
  70. 146 0
      application/service/controller/Index.php
  71. 154 0
      application/service/controller/api/Client.php
  72. 181 0
      application/service/controller/api/Push.php
  73. 67 0
      application/service/handler/Publish.php
  74. 64 0
      application/service/handler/Receive.php
  75. 169 0
      application/service/handler/Wechat.php
  76. 52 0
      application/service/logic/Build.php
  77. 150 0
      application/service/logic/Wechat.php
  78. 86 0
      application/service/view/config/index.html
  79. 79 0
      application/service/view/index/index.html
  80. 77 0
      application/service/view/index/index_search.html
  81. 70 0
      application/store/command/AutoRun.php
  82. 44 0
      application/store/controller/Config.php
  83. 35 60
      application/store/controller/Express.php
  84. 90 207
      application/store/controller/Goods.php
  85. 0 151
      application/store/controller/GoodsBrand.php
  86. 27 95
      application/store/controller/GoodsCate.php
  87. 0 157
      application/store/controller/GoodsSpec.php
  88. 57 0
      application/store/controller/Member.php
  89. 46 0
      application/store/controller/Message.php
  90. 66 104
      application/store/controller/Order.php
  91. 136 0
      application/store/controller/Page.php
  92. 37 0
      application/store/controller/api/Express.php
  93. 118 0
      application/store/controller/api/Goods.php
  94. 90 0
      application/store/controller/api/Member.php
  95. 71 0
      application/store/controller/api/Notify.php
  96. 72 0
      application/store/controller/api/Page.php
  97. 88 0
      application/store/controller/api/Wechat.php
  98. 127 0
      application/store/controller/api/member/Address.php
  99. 116 0
      application/store/controller/api/member/Center.php
  100. 298 0
      application/store/controller/api/member/Order.php

+ 0 - 3
.gitattributes

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

+ 5 - 8
.gitignore

@@ -1,11 +1,8 @@
-!.gitignore
-!.gitattributes
-*.DS_Store
-*.idea
-*.svn
-*.git
+/.git
+/.svn
+/.idea
 /runtime
+/safefile
 /nbproject
-!composer.json
 /composer.lock
-/static/upload
+/public/upload

+ 0 - 20
LICENSE

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

+ 35 - 110
README.md

@@ -1,124 +1,49 @@
-ThinkAdmin for PHP
+大道至简 · 原生框架
 --
-## 大道至简 · 悟在天成
+framework 是一个基于 ThinkPHP5.1 开发的后台管理系统,集成常用功能及封装。
 
-* ThinkAdmin 是一个基于 Thinkphp 5.1.x 开发的后台管理系统,集成后台系统常用功能。
-* 项目安装及二次开发请参考 ThinkPHP 官方文档及下面的服务环境说明,数据库 sql 文件存放于项目根目录下。
->* 注意:项目测试请另行搭建环境并创建数据库(数据库配置 config/database.php), 切勿直接使用测试环境数据!
->* 如果系统提示“测试系统禁止操作等字样”,可以删除项目演示路由配置(route/demo.php)或清空里面的路由记录。
->* 当前版本使用 ThinkPHP 5.1.x 版本,对PHP版本要求不低于php5.6,具体请查阅ThinkPHP官方文档。
+项目安装及二次开发可以参考 ThinkPHP 官方文档,数据库文件摆放在项目根目录下。
 
+#### 注意事项
+* 项目测试需要自行搭建环境导入数据库( framework.sql )并修改配置( config/database.php );
+* 若操作提示“测试系统禁止操作”等字样,需要删除演示路由配置( route/demo.php )或清空路由文件;
+* 当前版本使用 ThinkPHP5.1.x,对 PHP 版本标注不低于 PHP5.6,具体请阅读 ThinkPHP 官方文档;
+* 环境需开启 PATHINFO,不再支持 ThinkPHP 的 URL 兼容模式运行(源于如何优雅的展示);
 
-Documentation
+技术支持
 --
-认真看看文档可能会对你的开发有所帮助哦!
+开发前认真阅读 ThinkPHP 官方文档会对您有帮助哦!
 
-文档地址:[ThinkAdmin 开发文档](https://www.kancloud.cn/zoujingli/thinkadmin/content)
-
-
-PHP开发技术交流(QQ群 513350915)
+PHP 开发技术交流( QQ 群 513350915)
 
 [![PHP微信开发群 (SDK)](http://pub.idqqimg.com/wpa/images/group.png)](http://shang.qq.com/wpa/qunwpa?idkey=ae25cf789dafbef62e50a980ffc31242f150bc61a61164458216dd98c411832a) 
 
 
-Repositorie
+代码仓库
 --
- ThinkAdmin 为开源项目,允许把它用于任何地方,不受任何约束,欢迎 fork 项目。
-* Gitee  托管地址:https://gitee.com/zoujingli/Think.Admin
-* GitHub 托管地址:https://github.com/zoujingli/ThinkAdmin
-
-对于新版本的微信模块使用的是授权模式,需要用到 ThinkService 项目。
-* Gitee  托管地址:https://gitee.com/zoujingli/ThinkService
-* GitHub 托管地址:https://github.com/zoujingli/ThinkService
-
-其安装与 ThinkAdmin 相似,这里就不多说了。具体可以参见微信开放平台官网
-https://open.weixin.qq.com ,ThinkService 后台具体可以配置对应参数。
-
-ThinkAdmin 与 ThinkService 对接是通过 WebService 通信的,因此运行环境需要安装 Soap 模块支持。
-
-
-Module
+ framework 为 MIT 协议开源项目,安装使用或二次开发不受约束,欢迎 fork 项目。
+ 
+ 部分代码来自互联网,若有异议可以联系作者进行删除。
+ 
+ * 在线体验地址:https://framework.thinkadmin.top (体验账号和密码都是 admin )
+ * Gitee仓库地址:https://gitee.com/zoujingli/ThinkAdmin
+ * GitHub仓库地址:https://github.com/zoujingli/ThinkAdmin
+ 
+特别感谢
 --
-* 简易`RBAC`权限管理(用户、权限、节点、菜单控制)
-* 自建秒传文件上载组件(本地存储、七牛云存储,阿里云OSS存储)
-* 基站数据服务组件(唯一随机序号、表单更新)
-* `Http`服务组件(原生`CURL`封装,兼容PHP多版本)
-* 微信公众号服务组件(基于[WeChatDeveloper](https://github.com/zoujingli/WeChatDeveloper),微信网页授权获取用户信息、已关注粉丝管理、自定义菜单管理等等)
-* 微信商户支付服务组件(基于[WeChatDeveloper](https://github.com/zoujingli/WeChatDeveloper),支持JSAPI支付、扫码模式一支付、扫码模式二支付)
-* 更多组件开发中...
-
-
-Environment
----
->1. PHP 版本不低于 PHP5.6,推荐使用 PHP7 以达到最优效果;
->2. 需开启 PATHINFO,不再支持 ThinkPHP 的 URL 兼容模式运行(源于如何优雅的展示)。
-
-* Apache
-
-```xml
-<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>
-```
-
-* Nginx
-
-```
-server {
-	listen 80;
-	server_name wealth.demo.cuci.cc;
-	root /home/wwwroot/ThinkAdmin;
-	index index.php index.html index.htm;
-	
-	add_header X-Powered-Host $hostname;
-	fastcgi_hide_header X-Powered-By;
-	
-	if (!-e $request_filename) {
-		rewrite  ^/(.+?\.php)/?(.*)$  /$1/$2  last;
-		rewrite  ^/(.*)$  /index.php/$1  last;
-	}
-	
-	location ~ \.php($|/){
-		fastcgi_index   index.php;
-		fastcgi_pass    127.0.0.1:9000;
-		include         fastcgi_params;
-		set $real_script_name $fastcgi_script_name;
-		if ($real_script_name ~ "^(.+?\.php)(/.+)$") {
-			set $real_script_name $1;
-		}
-		fastcgi_split_path_info ^(.+?\.php)(/.*)$;
-		fastcgi_param   PATH_INFO               $fastcgi_path_info;
-		fastcgi_param   SCRIPT_NAME             $real_script_name;
-		fastcgi_param   SCRIPT_FILENAME         $document_root$real_script_name;
-		fastcgi_param   PHP_VALUE               open_basedir=$document_root:/tmp/:/proc/;
-		access_log      /home/wwwlog/domain_access.log    access;
-		error_log       /home/wwwlog/domain_error.log     error;
-	}
-	
-	location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ {
-		access_log  off;
-		error_log   off;
-		expires     30d;
-	}
-	
-	location ~ .*\.(js|css)?$ {
-		access_log   off;
-		error_log    off;
-		expires      12h;
-	}
-}
-```
-
-Copyright
+|名称|版本|描述|链接|
+|---|---|---|---|
+|Layui|2.4.5|UI组件库|https://github.com/sentsin/layui|
+|Ckeditor|4.10.1|富文件编辑器|https://github.com/ckeditor/ckeditor-dev|
+|PluPloader|3.1.2|文件上传工具1|https://github.com/fex-team/webuploader|
+|WebUploader|0.1.5|文件上传工具2|https://github.com/fex-team/webuploader|
+|Font-Awesome|4.7.0|字体图标库|https://github.com/FortAwesome/Font-Awesome|
+|ThinkPHP|5.1.35|PHP基础框架|https://github.com/top-think/framework|
+|ThinkLibrary|5.1.x-dev|ThinkPHP扩展组件|https://github.com/zoujingli/ThinkLibrary|
+|WeChatDeveloper|1.2.9|微信公众号组件|https://github.com/zoujingli/WeChatDeveloper|
+|WeOpenDeveloper|dev-master|微信开放平台组件|https://github.com/zoujingli/WeOpenDeveloper|
+
+赞助打赏
 --
-* ThinkAdmin 基于`MIT`协议发布,任何人可以用在任何地方,不受约束
-* ThinkAdmin 部分代码来自互联网,若有异议,可以联系作者进行删除
+![赞助](http://zoujingli.oschina.io/static/pay.png)
 
-
-Sponsor
---
-![赞助](http://zoujingli.oschina.io/static/pay.png)

+ 0 - 947
admin_v3.sql

@@ -1,947 +0,0 @@
-/*
-Navicat MySQL Data Transfer
-
-Source Server         : server.cuci.cc
-Source Server Version : 50558
-Source Host           : server.cuci.cc:3306
-Source Database       : admin_v3
-
-Target Server Type    : MYSQL
-Target Server Version : 50558
-File Encoding         : 65001
-
-Date: 2018-05-04 11:40:19
-*/
-
-SET FOREIGN_KEY_CHECKS=0;
-
--- ----------------------------
--- Table structure for store_express
--- ----------------------------
-DROP TABLE IF EXISTS `store_express`;
-CREATE TABLE `store_express` (
-  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
-  `express_title` varchar(50) DEFAULT '' COMMENT '快递公司名称',
-  `express_code` varchar(50) DEFAULT '' COMMENT '快递公司代码',
-  `express_desc` text COMMENT '快递公司描述',
-  `status` tinyint(1) unsigned DEFAULT '1' COMMENT '状态(0.无效,1.有效)',
-  `sort` bigint(20) unsigned DEFAULT '0' COMMENT '排序',
-  `is_deleted` tinyint(1) unsigned DEFAULT '0' COMMENT '删除状态(1删除,0未删除)',
-  `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  PRIMARY KEY (`id`)
-) ENGINE=InnoDB AUTO_INCREMENT=95 DEFAULT CHARSET=utf8 COMMENT='商城快递配置';
-
--- ----------------------------
--- Records of store_express
--- ----------------------------
-INSERT INTO `store_express` VALUES ('5', 'AAE全球专递', 'aae', '顺丰快递公司', '0', '0', '0', '2017-09-12 11:53:40');
-INSERT INTO `store_express` VALUES ('6', '安捷快递', 'anjie', '', '0', '0', '0', '2017-09-13 15:27:26');
-INSERT INTO `store_express` VALUES ('7', '安信达快递', 'anxindakuaixi', null, '0', '0', '0', '2017-09-13 16:05:19');
-INSERT INTO `store_express` VALUES ('8', '彪记快递', 'biaojikuaidi', null, '0', '0', '0', '2017-09-13 16:05:26');
-INSERT INTO `store_express` VALUES ('9', 'BHT', 'bht', '', '0', '0', '0', '2017-09-13 16:05:37');
-INSERT INTO `store_express` VALUES ('10', '百福东方国际物流', 'baifudongfang', null, '0', '0', '0', '2017-09-13 16:05:41');
-INSERT INTO `store_express` VALUES ('11', '中国东方(COE)', 'coe', null, '0', '0', '0', '2017-09-13 16:05:48');
-INSERT INTO `store_express` VALUES ('12', '长宇物流', 'changyuwuliu', null, '0', '0', '0', '2017-09-13 16:05:58');
-INSERT INTO `store_express` VALUES ('13', '大田物流', 'datianwuliu', null, '0', '0', '0', '2017-09-13 16:06:06');
-INSERT INTO `store_express` VALUES ('14', '德邦物流', 'debangwuliu', null, '1', '1', '0', '2017-09-13 16:06:14');
-INSERT INTO `store_express` VALUES ('15', 'DHL', 'dhl', null, '0', '0', '0', '2017-09-13 16:06:24');
-INSERT INTO `store_express` VALUES ('16', 'DPEX', 'dpex', null, '0', '0', '0', '2017-09-13 16:06:29');
-INSERT INTO `store_express` VALUES ('17', 'd速快递', 'dsukuaidi', null, '0', '0', '0', '2017-09-13 16:06:34');
-INSERT INTO `store_express` VALUES ('18', '递四方', 'disifang', null, '0', '0', '0', '2017-09-13 16:06:40');
-INSERT INTO `store_express` VALUES ('19', 'EMS快递', 'ems', '', '1', '0', '0', '2017-09-13 16:06:47');
-INSERT INTO `store_express` VALUES ('20', 'FEDEX(国外)', 'fedex', null, '0', '0', '0', '2017-09-13 16:06:56');
-INSERT INTO `store_express` VALUES ('21', '飞康达物流', 'feikangda', null, '0', '0', '0', '2017-09-13 16:07:03');
-INSERT INTO `store_express` VALUES ('22', '凤凰快递', 'fenghuangkuaidi', null, '0', '0', '0', '2017-09-13 16:07:10');
-INSERT INTO `store_express` VALUES ('23', '飞快达', 'feikuaida', null, '0', '0', '0', '2017-09-13 16:07:16');
-INSERT INTO `store_express` VALUES ('24', '国通快递', 'guotongkuaidi', null, '0', '0', '0', '2017-09-13 16:07:27');
-INSERT INTO `store_express` VALUES ('25', '港中能达物流', 'ganzhongnengda', null, '0', '0', '0', '2017-09-13 16:07:33');
-INSERT INTO `store_express` VALUES ('26', '广东邮政物流', 'guangdongyouzhengwuliu', null, '0', '0', '0', '2017-09-13 16:08:22');
-INSERT INTO `store_express` VALUES ('27', '共速达', 'gongsuda', null, '0', '0', '0', '2017-09-13 16:08:48');
-INSERT INTO `store_express` VALUES ('28', '汇通快运', 'huitongkuaidi', null, '0', '0', '0', '2017-09-13 16:08:56');
-INSERT INTO `store_express` VALUES ('29', '恒路物流', 'hengluwuliu', null, '0', '0', '0', '2017-09-13 16:09:02');
-INSERT INTO `store_express` VALUES ('30', '华夏龙物流', 'huaxialongwuliu', null, '0', '0', '0', '2017-09-13 16:09:12');
-INSERT INTO `store_express` VALUES ('31', '海红', 'haihongwangsong', null, '0', '0', '0', '2017-09-13 16:09:20');
-INSERT INTO `store_express` VALUES ('32', '海外环球', 'haiwaihuanqiu', null, '0', '0', '0', '2017-09-13 16:09:27');
-INSERT INTO `store_express` VALUES ('33', '佳怡物流', 'jiayiwuliu', null, '0', '0', '0', '2017-09-13 16:09:35');
-INSERT INTO `store_express` VALUES ('34', '京广速递', 'jinguangsudikuaijian', null, '0', '0', '0', '2017-09-13 16:09:42');
-INSERT INTO `store_express` VALUES ('35', '急先达', 'jixianda', null, '0', '0', '0', '2017-09-13 16:09:49');
-INSERT INTO `store_express` VALUES ('36', '佳吉物流', 'jjwl', null, '0', '0', '0', '2017-09-13 16:10:01');
-INSERT INTO `store_express` VALUES ('37', '加运美物流', 'jymwl', null, '0', '0', '0', '2017-09-13 16:10:13');
-INSERT INTO `store_express` VALUES ('38', '金大物流', 'jindawuliu', null, '0', '0', '0', '2017-09-13 16:10:22');
-INSERT INTO `store_express` VALUES ('39', '嘉里大通', 'jialidatong', null, '0', '0', '0', '2017-09-13 16:10:33');
-INSERT INTO `store_express` VALUES ('40', '晋越快递', 'jykd', null, '0', '0', '0', '2017-09-13 16:10:40');
-INSERT INTO `store_express` VALUES ('41', '快捷速递', 'kuaijiesudi', null, '0', '0', '0', '2017-09-13 16:10:49');
-INSERT INTO `store_express` VALUES ('42', '联邦快递(国内)', 'lianb', null, '0', '0', '0', '2017-09-13 16:10:58');
-INSERT INTO `store_express` VALUES ('43', '联昊通物流', 'lianhaowuliu', null, '0', '0', '0', '2017-09-13 16:11:07');
-INSERT INTO `store_express` VALUES ('44', '龙邦物流', 'longbanwuliu', null, '0', '0', '0', '2017-09-13 16:11:15');
-INSERT INTO `store_express` VALUES ('45', '立即送', 'lijisong', null, '0', '0', '0', '2017-09-13 16:11:25');
-INSERT INTO `store_express` VALUES ('46', '乐捷递', 'lejiedi', null, '0', '0', '0', '2017-09-13 16:11:36');
-INSERT INTO `store_express` VALUES ('47', '民航快递', 'minghangkuaidi', null, '0', '0', '0', '2017-09-13 16:11:45');
-INSERT INTO `store_express` VALUES ('48', '美国快递', 'meiguokuaidi', null, '0', '0', '0', '2017-09-13 16:11:53');
-INSERT INTO `store_express` VALUES ('49', '门对门', 'menduimen', null, '0', '0', '0', '2017-09-13 16:12:01');
-INSERT INTO `store_express` VALUES ('50', 'OCS', 'ocs', null, '0', '0', '0', '2017-09-13 16:12:10');
-INSERT INTO `store_express` VALUES ('51', '配思货运', 'peisihuoyunkuaidi', null, '0', '0', '0', '2017-09-13 16:12:18');
-INSERT INTO `store_express` VALUES ('52', '全晨快递', 'quanchenkuaidi', null, '0', '0', '0', '2017-09-13 16:12:26');
-INSERT INTO `store_express` VALUES ('53', '全峰快递', 'quanfengkuaidi', null, '0', '0', '0', '2017-09-13 16:12:34');
-INSERT INTO `store_express` VALUES ('54', '全际通物流', 'quanjitong', null, '0', '0', '0', '2017-09-13 16:12:41');
-INSERT INTO `store_express` VALUES ('55', '全日通快递', 'quanritongkuaidi', null, '0', '0', '0', '2017-09-13 16:12:49');
-INSERT INTO `store_express` VALUES ('56', '全一快递', 'quanyikuaidi', null, '0', '0', '0', '2017-09-13 16:12:56');
-INSERT INTO `store_express` VALUES ('57', '如风达', 'rufengda', null, '0', '0', '0', '2017-09-13 16:13:03');
-INSERT INTO `store_express` VALUES ('58', '三态速递', 'santaisudi', null, '0', '0', '0', '2017-09-13 16:13:15');
-INSERT INTO `store_express` VALUES ('59', '盛辉物流', 'shenghuiwuliu', null, '0', '0', '0', '2017-09-13 16:13:22');
-INSERT INTO `store_express` VALUES ('60', '申通', 'shentong', null, '0', '0', '0', '2017-09-13 16:13:34');
-INSERT INTO `store_express` VALUES ('61', '顺丰', 'shunfeng', '', '1', '0', '0', '2017-09-13 16:13:41');
-INSERT INTO `store_express` VALUES ('62', '速尔物流', 'sue', null, '0', '0', '0', '2017-09-13 16:13:48');
-INSERT INTO `store_express` VALUES ('63', '盛丰物流', 'shengfeng', null, '0', '0', '0', '2017-09-13 16:13:55');
-INSERT INTO `store_express` VALUES ('64', '赛澳递', 'saiaodi', null, '0', '0', '0', '2017-09-13 16:14:02');
-INSERT INTO `store_express` VALUES ('65', '天地华宇', 'tiandihuayu', null, '0', '0', '0', '2017-09-13 16:14:11');
-INSERT INTO `store_express` VALUES ('66', '天天快递', 'tiantian', null, '0', '0', '0', '2017-09-13 16:14:19');
-INSERT INTO `store_express` VALUES ('67', 'TNT', 'tnt', null, '0', '0', '0', '2017-09-13 16:14:26');
-INSERT INTO `store_express` VALUES ('68', 'UPS', 'ups', null, '0', '0', '0', '2017-09-13 16:14:29');
-INSERT INTO `store_express` VALUES ('69', '万家物流', 'wanjiawuliu', null, '0', '0', '0', '2017-09-13 16:14:37');
-INSERT INTO `store_express` VALUES ('70', '文捷航空速递', 'wenjiesudi', null, '0', '0', '0', '2017-09-13 16:14:46');
-INSERT INTO `store_express` VALUES ('71', '伍圆', 'wuyuan', null, '0', '0', '0', '2017-09-13 16:14:52');
-INSERT INTO `store_express` VALUES ('72', '万象物流', 'wxwl', null, '0', '0', '0', '2017-09-13 16:15:00');
-INSERT INTO `store_express` VALUES ('73', '新邦物流', 'xinbangwuliu', null, '0', '0', '0', '2017-09-13 16:15:06');
-INSERT INTO `store_express` VALUES ('74', '信丰物流', 'xinfengwuliu', null, '0', '0', '0', '2017-09-13 16:15:15');
-INSERT INTO `store_express` VALUES ('75', '亚风速递', 'yafengsudi', null, '0', '0', '0', '2017-09-13 16:15:23');
-INSERT INTO `store_express` VALUES ('76', '一邦速递', 'yibangwuliu', null, '0', '0', '0', '2017-09-13 16:15:30');
-INSERT INTO `store_express` VALUES ('77', '优速物流', 'youshuwuliu', null, '0', '0', '0', '2017-09-13 16:15:36');
-INSERT INTO `store_express` VALUES ('78', '邮政包裹挂号信', 'youzhengguonei', null, '0', '3', '0', '2017-09-13 16:15:44');
-INSERT INTO `store_express` VALUES ('79', '邮政国际包裹挂号信', 'youzhengguoji', null, '0', '2', '0', '2017-09-13 16:15:51');
-INSERT INTO `store_express` VALUES ('80', '远成物流', 'yuanchengwuliu', null, '0', '0', '0', '2017-09-13 16:15:57');
-INSERT INTO `store_express` VALUES ('81', '圆通速递', 'yuantong', null, '1', '1', '0', '2017-09-13 16:16:03');
-INSERT INTO `store_express` VALUES ('82', '源伟丰快递', 'yuanweifeng', null, '0', '0', '0', '2017-09-13 16:16:10');
-INSERT INTO `store_express` VALUES ('83', '元智捷诚快递', 'yuanzhijiecheng', null, '0', '0', '0', '2017-09-13 16:16:17');
-INSERT INTO `store_express` VALUES ('84', '韵达快运', 'yunda', null, '0', '0', '0', '2017-09-13 16:16:24');
-INSERT INTO `store_express` VALUES ('85', '运通快递', 'yuntongkuaidi', null, '0', '0', '0', '2017-09-13 16:16:33');
-INSERT INTO `store_express` VALUES ('86', '越丰物流', 'yuefengwuliu', null, '0', '0', '0', '2017-09-13 16:16:40');
-INSERT INTO `store_express` VALUES ('87', '源安达', 'yad', null, '0', '0', '0', '2017-09-13 16:16:47');
-INSERT INTO `store_express` VALUES ('88', '银捷速递', 'yinjiesudi', null, '0', '0', '0', '2017-09-13 16:16:56');
-INSERT INTO `store_express` VALUES ('89', '宅急送', 'zhaijisong', null, '0', '0', '0', '2017-09-13 16:17:03');
-INSERT INTO `store_express` VALUES ('90', '中铁快运', 'zhongtiekuaiyun', null, '0', '0', '0', '2017-09-13 16:17:10');
-INSERT INTO `store_express` VALUES ('91', '中通速递', 'zhongtong', '', '0', '0', '0', '2017-09-13 16:17:16');
-INSERT INTO `store_express` VALUES ('92', '中邮物流', 'zhongyouwuliu', null, '0', '0', '0', '2017-09-13 16:17:27');
-INSERT INTO `store_express` VALUES ('93', '忠信达', 'zhongxinda', null, '0', '0', '0', '2017-09-13 16:17:34');
-INSERT INTO `store_express` VALUES ('94', '芝麻开门', 'zhimakaimen', null, '0', '0', '0', '2017-09-13 16:17:41');
-
--- ----------------------------
--- Table structure for store_goods
--- ----------------------------
-DROP TABLE IF EXISTS `store_goods`;
-CREATE TABLE `store_goods` (
-  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
-  `brand_id` bigint(20) unsigned DEFAULT '0' COMMENT '品牌ID',
-  `cate_id` bigint(20) unsigned DEFAULT '0' COMMENT '商品分类id',
-  `unit_id` bigint(20) DEFAULT NULL COMMENT '商品单位ID',
-  `spec_id` bigint(20) unsigned DEFAULT '0' COMMENT '规格ID',
-  `tags_id` varchar(255) DEFAULT '' COMMENT '商品标签ID',
-  `is_code` bigint(1) DEFAULT '1' COMMENT '是否有码商品',
-  `goods_title` varchar(255) DEFAULT '' COMMENT '商品标签',
-  `goods_content` text COMMENT '商品内容',
-  `goods_logo` varchar(255) DEFAULT '' COMMENT '商品LOGO',
-  `goods_image` text COMMENT '商品图片地址',
-  `goods_video` varchar(500) DEFAULT '' COMMENT '商品视频URL',
-  `goods_desc` varchar(500) DEFAULT '' COMMENT '商品描述',
-  `package_stock` bigint(20) unsigned DEFAULT '0' COMMENT '总库存数量',
-  `package_sale` bigint(20) unsigned DEFAULT '0' COMMENT '已销售数量',
-  `favorite_num` bigint(20) unsigned DEFAULT '0' COMMENT '收藏次数',
-  `sort` bigint(20) unsigned DEFAULT '0' COMMENT '数据排序',
-  `status` bigint(1) unsigned DEFAULT '1' COMMENT '商品状态(1有效,0无效)',
-  `is_deleted` bigint(1) unsigned DEFAULT '0' COMMENT '删除状态(1删除,0未删除)',
-  `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='商城商品主表';
-
--- ----------------------------
--- Records of store_goods
--- ----------------------------
-
--- ----------------------------
--- Table structure for store_goods_brand
--- ----------------------------
-DROP TABLE IF EXISTS `store_goods_brand`;
-CREATE TABLE `store_goods_brand` (
-  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
-  `brand_logo` varchar(1024) DEFAULT '' COMMENT '品牌logo',
-  `brand_cover` varchar(1024) DEFAULT '' COMMENT '品牌封面',
-  `brand_title` varchar(255) DEFAULT '' COMMENT '商品品牌名称',
-  `brand_desc` text COMMENT '商品品牌描述',
-  `brand_detail` text COMMENT '品牌图文信息',
-  `sort` int(11) unsigned DEFAULT '0' COMMENT '商品分类排序',
-  `status` tinyint(1) unsigned DEFAULT '1' COMMENT '商品状态(1有效,0无效)',
-  `is_deleted` tinyint(1) unsigned DEFAULT '0' COMMENT '删除状态(1删除,0未删除)',
-  `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='产品品牌';
-
--- ----------------------------
--- Records of store_goods_brand
--- ----------------------------
-
--- ----------------------------
--- Table structure for store_goods_cate
--- ----------------------------
-DROP TABLE IF EXISTS `store_goods_cate`;
-CREATE TABLE `store_goods_cate` (
-  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
-  `pid` bigint(20) unsigned DEFAULT '0' COMMENT '上级分类编号',
-  `brand_id` bigint(20) DEFAULT '0' COMMENT '品牌ID',
-  `cate_title` varchar(255) DEFAULT '' COMMENT '商品分类名称',
-  `cate_desc` text COMMENT '商品分类',
-  `sort` bigint(20) unsigned DEFAULT '0' COMMENT '商品分类排序',
-  `status` bigint(1) unsigned DEFAULT '1' COMMENT '商品状态(1有效,0无效)',
-  `is_deleted` bigint(1) unsigned DEFAULT '0' COMMENT '删除状态(1删除,0未删除)',
-  `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='商城商品分类';
-
--- ----------------------------
--- Records of store_goods_cate
--- ----------------------------
-
--- ----------------------------
--- Table structure for store_goods_list
--- ----------------------------
-DROP TABLE IF EXISTS `store_goods_list`;
-CREATE TABLE `store_goods_list` (
-  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
-  `goods_id` bigint(20) unsigned DEFAULT '0' COMMENT '商品ID',
-  `goods_spec` varchar(255) DEFAULT '' COMMENT '商品规格名称',
-  `goods_number` bigint(20) unsigned DEFAULT '0' COMMENT '商品礼品-商品数量',
-  `market_price` decimal(20,2) unsigned DEFAULT '0.00' COMMENT '销售价格',
-  `selling_price` decimal(20,2) unsigned DEFAULT '0.00' COMMENT '商品价格',
-  `goods_stock` bigint(20) unsigned DEFAULT '0' COMMENT '商品库存统计',
-  `goods_sale` bigint(20) unsigned DEFAULT '0' COMMENT '已销售数量',
-  `status` bigint(1) unsigned DEFAULT '1' COMMENT '商品状态(1有效,0无效)',
-  `is_deleted` bigint(1) unsigned DEFAULT '0' COMMENT '删除状态(1删除,0未删除)',
-  `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='商城商品列表';
-
--- ----------------------------
--- Records of store_goods_list
--- ----------------------------
-
--- ----------------------------
--- Table structure for store_goods_spec
--- ----------------------------
-DROP TABLE IF EXISTS `store_goods_spec`;
-CREATE TABLE `store_goods_spec` (
-  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
-  `mch_id` bigint(20) unsigned DEFAULT '0' COMMENT '商户ID',
-  `spec_title` varchar(255) DEFAULT '' COMMENT '商品规格名称',
-  `spec_param` varchar(255) DEFAULT '' COMMENT '商品规格参数',
-  `spec_desc` varchar(255) DEFAULT '' COMMENT '商品规格描述',
-  `sort` bigint(20) unsigned DEFAULT '0' COMMENT '商品规格排序',
-  `status` bigint(1) unsigned DEFAULT '1' COMMENT '商品状态(1有效,0无效)',
-  `is_deleted` bigint(1) unsigned DEFAULT '0' COMMENT '删除状态(1删除,0未删除)',
-  `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  PRIMARY KEY (`id`),
-  KEY `index_store_goods_spec_mch_id` (`mch_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='商城商品规格';
-
--- ----------------------------
--- Records of store_goods_spec
--- ----------------------------
-
--- ----------------------------
--- Table structure for store_member
--- ----------------------------
-DROP TABLE IF EXISTS `store_member`;
-CREATE TABLE `store_member` (
-  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
-  `openid` varchar(100) DEFAULT '' COMMENT '会员微信OPENID',
-  `phone` varchar(16) DEFAULT '' COMMENT '会员手机号',
-  `password` varchar(64) NOT NULL DEFAULT '' COMMENT '登录密码',
-  `nickname` varchar(20) DEFAULT '' COMMENT '会员昵称',
-  `headimg` varchar(500) DEFAULT '' COMMENT '会员头像',
-  `sex` char(2) DEFAULT '' COMMENT '性别',
-  `level` tinyint(2) unsigned DEFAULT '1' COMMENT '会员级别',
-  `remark` varchar(500) DEFAULT '' COMMENT '会员个性签名',
-  `status` tinyint(1) unsigned DEFAULT '1' COMMENT '会员状态(1有效,0无效)',
-  `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  PRIMARY KEY (`id`),
-  UNIQUE KEY `index_store_member_openid` (`openid`) USING BTREE,
-  KEY `index_store_member_phone` (`phone`) USING BTREE
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='商城会员信息';
-
--- ----------------------------
--- Records of store_member
--- ----------------------------
-
--- ----------------------------
--- Table structure for store_member_address
--- ----------------------------
-DROP TABLE IF EXISTS `store_member_address`;
-CREATE TABLE `store_member_address` (
-  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
-  `mid` bigint(20) unsigned DEFAULT '0' COMMENT '会员ID',
-  `username` varchar(20) DEFAULT '' COMMENT '收货人姓名',
-  `phone` varchar(16) DEFAULT '' COMMENT '收货手机号',
-  `province` varchar(50) DEFAULT '' COMMENT '收货地址省份',
-  `city` varchar(50) DEFAULT '' COMMENT '收货地址城市',
-  `area` varchar(255) DEFAULT '' COMMENT '收货地址区域',
-  `address` varchar(255) DEFAULT '' COMMENT '收货详细地址',
-  `status` tinyint(1) unsigned DEFAULT '1' COMMENT '状态(0无效, 1新快递)',
-  `is_default` tinyint(1) unsigned DEFAULT '1' COMMENT '默认收货地址',
-  `is_deleted` bigint(1) unsigned DEFAULT '0' COMMENT '删除状态(1删除,0未删除)',
-  `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='商城会员收货地址';
-
--- ----------------------------
--- Records of store_member_address
--- ----------------------------
-
--- ----------------------------
--- Table structure for store_order
--- ----------------------------
-DROP TABLE IF EXISTS `store_order`;
-CREATE TABLE `store_order` (
-  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
-  `type` tinyint(1) unsigned DEFAULT '1' COMMENT '订单类型(1普通订单,2积分订单)',
-  `mid` bigint(20) unsigned DEFAULT '0' COMMENT '会员ID',
-  `order_no` char(10) DEFAULT '' COMMENT '订单号',
-  `freight_price` decimal(20,2) unsigned DEFAULT '0.00' COMMENT '快递费',
-  `goods_price` decimal(20,2) unsigned DEFAULT '0.00' COMMENT '商品总金额(不含快递费)',
-  `real_price` decimal(20,2) unsigned DEFAULT '0.00' COMMENT '真实支付金额(商品金额+快递金额)',
-  `is_pay` tinyint(1) unsigned DEFAULT '0' COMMENT '订单支付状态(0.未支付,1.已支付)',
-  `pay_type` varchar(255) DEFAULT '' COMMENT '支付方式 (wechat微信支付, alipay支付宝支付)',
-  `pay_no` varchar(100) DEFAULT '' COMMENT '商户交易号',
-  `pay_price` decimal(20,2) unsigned DEFAULT '0.00' COMMENT '实际支付金额',
-  `pay_at` datetime DEFAULT NULL COMMENT '支付时间',
-  `desc` text COMMENT '订单描述',
-  `status` bigint(1) unsigned DEFAULT '1' COMMENT '订单状态(0.无效,1.新订单,2.待发货,3.已发货,4.已收货,5.已完成,6.已退货及退款)',
-  `is_deleted` tinyint(1) unsigned DEFAULT '0' COMMENT '删除状态(1删除,0未删除)',
-  `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  PRIMARY KEY (`id`),
-  KEY `index_store_order_order_no` (`order_no`) USING BTREE,
-  KEY `index_store_order_status` (`status`) USING BTREE
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='商城订单主表';
-
--- ----------------------------
--- Records of store_order
--- ----------------------------
-
--- ----------------------------
--- Table structure for store_order_express
--- ----------------------------
-DROP TABLE IF EXISTS `store_order_express`;
-CREATE TABLE `store_order_express` (
-  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
-  `mid` bigint(20) unsigned DEFAULT '0' COMMENT '会员ID',
-  `type` tinyint(1) unsigned DEFAULT '0' COMMENT '快递类型(0.订单快递,1.退货快递)',
-  `order_no` char(10) DEFAULT '' COMMENT '订单编号',
-  `company_title` varchar(50) DEFAULT '' COMMENT '物流公司名称',
-  `company_code` varchar(50) DEFAULT '' COMMENT '物流公司编码',
-  `username` varchar(20) DEFAULT '' COMMENT '收货人姓名',
-  `phone` varchar(16) DEFAULT '' COMMENT '收货手机号',
-  `province` varchar(50) DEFAULT NULL COMMENT '收货地址省份',
-  `city` varchar(50) DEFAULT '' COMMENT '收货地址城市',
-  `area` varchar(255) DEFAULT '' COMMENT '收货地址区域',
-  `address` varchar(255) DEFAULT '' COMMENT '收货详细地址',
-  `send_no` varchar(50) DEFAULT '' COMMENT '实际物流公司单号',
-  `send_company_title` varchar(50) DEFAULT '' COMMENT '实际发货快递公司',
-  `send_company_code` varchar(50) DEFAULT '' COMMENT '实际发货快递代码',
-  `send_username` varchar(255) DEFAULT '' COMMENT '寄件人名称',
-  `send_phone` varchar(16) DEFAULT '' COMMENT '寄件人手机号',
-  `send_province` varchar(50) DEFAULT '' COMMENT '寄件人地址省份',
-  `send_city` varchar(50) DEFAULT '' COMMENT '寄件人地址城市',
-  `send_area` varchar(255) DEFAULT '' COMMENT '寄件人地址区域',
-  `send_address` varchar(255) DEFAULT '' COMMENT '寄件人详细地址',
-  `send_at` datetime DEFAULT NULL COMMENT '快递发货时间',
-  `desc` text COMMENT '发货描述',
-  `status` tinyint(1) unsigned DEFAULT '1' COMMENT '状态(0.无效,1.新快递,2.已签收,3.签收失败)',
-  `is_deleted` bigint(1) unsigned DEFAULT '0' COMMENT '删除状态(1删除,0未删除)',
-  `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='商城订单快递';
-
--- ----------------------------
--- Records of store_order_express
--- ----------------------------
-
--- ----------------------------
--- Table structure for store_order_goods
--- ----------------------------
-DROP TABLE IF EXISTS `store_order_goods`;
-CREATE TABLE `store_order_goods` (
-  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
-  `mid` bigint(20) unsigned DEFAULT '0' COMMENT '会员ID',
-  `order_no` char(10) DEFAULT '' COMMENT '订单编号',
-  `goods_id` bigint(20) DEFAULT '0' COMMENT '商品ID',
-  `goods_title` varchar(255) DEFAULT '' COMMENT '商品标签',
-  `goods_spec` varchar(255) DEFAULT '' COMMENT '商品规格',
-  `goods_logo` varchar(255) DEFAULT '' COMMENT '商品LOGO',
-  `goods_image` text COMMENT '商品图片地址',
-  `market_price` decimal(20,2) unsigned DEFAULT '0.00' COMMENT '市场价格',
-  `selling_price` decimal(20,2) unsigned DEFAULT '0.00' COMMENT '商品销售价格',
-  `price_field` varchar(20) DEFAULT 'selling_price' COMMENT '计价字段',
-  `number` bigint(20) unsigned DEFAULT '0' COMMENT '订单商品数量',
-  `status` bigint(1) unsigned DEFAULT '1' COMMENT '商品状态(1有效,0无效)',
-  `is_deleted` bigint(1) unsigned DEFAULT '0' COMMENT '删除状态(1删除,0未删除)',
-  `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  PRIMARY KEY (`id`),
-  KEY `index_store_order_list_order_no` (`order_no`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='商城订单关联商品';
-
--- ----------------------------
--- Records of store_order_goods
--- ----------------------------
-
--- ----------------------------
--- Table structure for system_auth
--- ----------------------------
-DROP TABLE IF EXISTS `system_auth`;
-CREATE TABLE `system_auth` (
-  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
-  `title` varchar(20) NOT NULL COMMENT '权限名称',
-  `status` tinyint(1) unsigned DEFAULT '1' COMMENT '状态(1:禁用,2:启用)',
-  `sort` smallint(6) unsigned DEFAULT '0' COMMENT '排序权重',
-  `desc` varchar(255) DEFAULT NULL COMMENT '备注说明',
-  `create_by` bigint(11) unsigned DEFAULT '0' COMMENT '创建人',
-  `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  PRIMARY KEY (`id`),
-  UNIQUE KEY `index_system_auth_title` (`title`) USING BTREE,
-  KEY `index_system_auth_status` (`status`) USING BTREE
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='系统权限表';
-
--- ----------------------------
--- Records of system_auth
--- ----------------------------
-
--- ----------------------------
--- Table structure for system_auth_node
--- ----------------------------
-DROP TABLE IF EXISTS `system_auth_node`;
-CREATE TABLE `system_auth_node` (
-  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
-  `auth` bigint(20) unsigned DEFAULT NULL COMMENT '角色ID',
-  `node` varchar(200) DEFAULT NULL COMMENT '节点路径',
-  PRIMARY KEY (`id`),
-  KEY `index_system_auth_auth` (`auth`) USING BTREE,
-  KEY `index_system_auth_node` (`node`) USING BTREE
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='系统角色与节点绑定';
-
--- ----------------------------
--- Records of system_auth_node
--- ----------------------------
-
--- ----------------------------
--- Table structure for system_config
--- ----------------------------
-DROP TABLE IF EXISTS `system_config`;
-CREATE TABLE `system_config` (
-  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
-  `name` varchar(100) DEFAULT NULL COMMENT '配置编码',
-  `value` varchar(500) DEFAULT NULL COMMENT '配置值',
-  PRIMARY KEY (`id`),
-  KEY `index_system_config_name` (`name`)
-) ENGINE=InnoDB AUTO_INCREMENT=43 DEFAULT CHARSET=utf8 COMMENT='系统参数配置';
-
--- ----------------------------
--- Records of system_config
--- ----------------------------
-INSERT INTO `system_config` VALUES ('1', 'app_name', 'ThinkAdmin');
-INSERT INTO `system_config` VALUES ('2', 'site_name', 'ThinkAdmin');
-INSERT INTO `system_config` VALUES ('3', 'app_version', '3.0 dev');
-INSERT INTO `system_config` VALUES ('4', 'site_copy', '©版权所有 2014-2018 楚才科技');
-INSERT INTO `system_config` VALUES ('5', 'browser_icon', 'http://localhost/ThinkAdmin/static/upload/f47b8fe06e38ae99/08e8398da45583b9.png');
-INSERT INTO `system_config` VALUES ('6', 'tongji_baidu_key', '');
-INSERT INTO `system_config` VALUES ('7', 'miitbeian', '粤ICP备16006642号-2');
-INSERT INTO `system_config` VALUES ('8', 'storage_type', 'local');
-INSERT INTO `system_config` VALUES ('9', 'storage_local_exts', 'png,jpg,rar,doc,icon,mp4');
-INSERT INTO `system_config` VALUES ('10', 'storage_qiniu_bucket', '');
-INSERT INTO `system_config` VALUES ('11', 'storage_qiniu_domain', '');
-INSERT INTO `system_config` VALUES ('12', 'storage_qiniu_access_key', '');
-INSERT INTO `system_config` VALUES ('13', 'storage_qiniu_secret_key', '');
-INSERT INTO `system_config` VALUES ('14', 'storage_oss_bucket', 'cuci');
-INSERT INTO `system_config` VALUES ('15', 'storage_oss_endpoint', 'oss-cn-beijing.aliyuncs.com');
-INSERT INTO `system_config` VALUES ('16', 'storage_oss_domain', 'cuci.oss-cn-beijing.aliyuncs.com');
-INSERT INTO `system_config` VALUES ('17', 'storage_oss_keyid', '用你自己的吧');
-INSERT INTO `system_config` VALUES ('18', 'storage_oss_secret', '用你自己的吧');
-INSERT INTO `system_config` VALUES ('34', 'wechat_appid', 'wx60a43dd8161666d4');
-INSERT INTO `system_config` VALUES ('35', 'wechat_appkey', '9890a0d7c91801a609d151099e95b61a');
-INSERT INTO `system_config` VALUES ('36', 'storage_oss_is_https', 'http');
-INSERT INTO `system_config` VALUES ('37', 'wechat_type', 'thr');
-INSERT INTO `system_config` VALUES ('38', 'wechat_token', 'test');
-INSERT INTO `system_config` VALUES ('39', 'wechat_appsecret', 'a041bec98ed015d52b99acea5c6a16ef');
-INSERT INTO `system_config` VALUES ('40', 'wechat_encodingaeskey', 'BJIUzE0gqlWy0GxfPp4J1oPTBmOrNDIGPNav1YFH5Z5');
-INSERT INTO `system_config` VALUES ('41', 'wechat_thr_appid', 'wx60a43dd8161666d4');
-INSERT INTO `system_config` VALUES ('42', 'wechat_thr_appkey', '05db2aa335382c66ab56d69b1a9ad0ee');
-
--- ----------------------------
--- Table structure for system_log
--- ----------------------------
-DROP TABLE IF EXISTS `system_log`;
-CREATE TABLE `system_log` (
-  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
-  `ip` char(15) NOT NULL DEFAULT '' COMMENT '操作者IP地址',
-  `node` char(200) NOT NULL DEFAULT '' COMMENT '当前操作节点',
-  `username` varchar(32) NOT NULL DEFAULT '' COMMENT '操作人用户名',
-  `action` varchar(200) NOT NULL DEFAULT '' COMMENT '操作行为',
-  `content` text NOT NULL COMMENT '操作内容描述',
-  `create_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='系统操作日志表';
-
--- ----------------------------
--- Records of system_log
--- ----------------------------
-
--- ----------------------------
--- Table structure for system_menu
--- ----------------------------
-DROP TABLE IF EXISTS `system_menu`;
-CREATE TABLE `system_menu` (
-  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
-  `pid` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '父id',
-  `title` varchar(100) NOT NULL DEFAULT '' COMMENT '名称',
-  `node` varchar(200) NOT NULL DEFAULT '' COMMENT '节点代码',
-  `icon` varchar(100) NOT NULL DEFAULT '' COMMENT '菜单图标',
-  `url` varchar(400) NOT NULL DEFAULT '' COMMENT '链接',
-  `params` varchar(500) DEFAULT '' COMMENT '链接参数',
-  `target` varchar(20) NOT NULL DEFAULT '_self' COMMENT '链接打开方式',
-  `sort` int(11) unsigned DEFAULT '0' COMMENT '菜单排序',
-  `status` tinyint(1) unsigned NOT NULL DEFAULT '1' COMMENT '状态(0:禁用,1:启用)',
-  `create_by` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '创建人',
-  `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  PRIMARY KEY (`id`),
-  KEY `index_system_menu_node` (`node`) USING BTREE
-) ENGINE=InnoDB AUTO_INCREMENT=43 DEFAULT CHARSET=utf8 COMMENT='系统菜单表';
-
--- ----------------------------
--- Records of system_menu
--- ----------------------------
-INSERT INTO `system_menu` VALUES ('1', '0', '系统设置', '', '', '#', '', '_self', '9000', '1', '10000', '2018-01-19 15:27:00');
-INSERT INTO `system_menu` VALUES ('2', '10', '后台菜单', '', 'fa fa-leaf', 'admin/menu/index', '', '_self', '10', '1', '10000', '2018-01-19 15:27:17');
-INSERT INTO `system_menu` VALUES ('3', '10', '系统参数', '', 'fa fa-modx', 'admin/config/index', '', '_self', '20', '1', '10000', '2018-01-19 15:27:57');
-INSERT INTO `system_menu` VALUES ('4', '11', '访问授权', '', 'fa fa-group', 'admin/auth/index', '', '_self', '20', '1', '10000', '2018-01-22 11:13:02');
-INSERT INTO `system_menu` VALUES ('5', '11', '用户管理', '', 'fa fa-user', 'admin/user/index', '', '_self', '10', '1', '0', '2018-01-23 12:15:12');
-INSERT INTO `system_menu` VALUES ('6', '11', '访问节点', '', 'fa fa-fort-awesome', 'admin/node/index', '', '_self', '30', '1', '0', '2018-01-23 12:36:54');
-INSERT INTO `system_menu` VALUES ('7', '0', '后台首页', '', '', 'admin/index/main', '', '_self', '1000', '1', '0', '2018-01-23 13:42:30');
-INSERT INTO `system_menu` VALUES ('8', '16', '系统日志', '', 'fa fa-code', 'admin/log/index', '', '_self', '10', '1', '0', '2018-01-24 13:52:58');
-INSERT INTO `system_menu` VALUES ('9', '10', '文件存储', '', 'fa fa-stop-circle', 'admin/config/file', '', '_self', '30', '1', '0', '2018-01-25 10:54:28');
-INSERT INTO `system_menu` VALUES ('10', '1', '系统管理', '', '', '#', '', '_self', '200', '1', '0', '2018-01-25 18:14:28');
-INSERT INTO `system_menu` VALUES ('11', '1', '访问权限', '', '', '#', '', '_self', '300', '1', '0', '2018-01-25 18:15:08');
-INSERT INTO `system_menu` VALUES ('16', '1', '日志管理', '', '', '#', '', '_self', '400', '1', '0', '2018-02-10 16:31:15');
-INSERT INTO `system_menu` VALUES ('17', '0', '微信管理', '', '', '#', '', '_self', '8000', '1', '0', '2018-03-06 14:42:49');
-INSERT INTO `system_menu` VALUES ('18', '17', '公众号配置', '', '', '#', '', '_self', '0', '1', '0', '2018-03-06 14:43:05');
-INSERT INTO `system_menu` VALUES ('19', '18', '微信授权绑定', '', 'fa fa-cog', 'wechat/config/index', '', '_self', '0', '1', '0', '2018-03-06 14:43:26');
-INSERT INTO `system_menu` VALUES ('20', '18', '关注默认回复', '', 'fa fa-comment-o', 'wechat/keys/subscribe', '', '_self', '0', '1', '0', '2018-03-06 14:44:45');
-INSERT INTO `system_menu` VALUES ('21', '18', '无反馈默认回复', '', 'fa fa-commenting', 'wechat/keys/defaults', '', '_self', '0', '1', '0', '2018-03-06 14:45:55');
-INSERT INTO `system_menu` VALUES ('22', '18', '微信关键字管理', '', 'fa fa-hashtag', 'wechat/keys/index', '', '_self', '0', '1', '0', '2018-03-06 14:46:23');
-INSERT INTO `system_menu` VALUES ('23', '17', '微信服务定制', '', '', '#', '', '_self', '0', '1', '0', '2018-03-06 14:47:11');
-INSERT INTO `system_menu` VALUES ('24', '23', '微信菜单管理', '', 'fa fa-gg-circle', 'wechat/menu/index', '', '_self', '0', '1', '0', '2018-03-06 14:47:39');
-INSERT INTO `system_menu` VALUES ('25', '23', '微信图文管理', '', 'fa fa-map-o', 'wechat/news/index', '', '_self', '0', '1', '0', '2018-03-06 14:48:14');
-INSERT INTO `system_menu` VALUES ('26', '17', '微信粉丝管理', '', 'fa fa-user', '#', '', '_self', '0', '1', '0', '2018-03-06 14:48:33');
-INSERT INTO `system_menu` VALUES ('27', '26', '微信粉丝列表', '', 'fa fa-users', 'wechat/fans/index', '', '_self', '20', '1', '0', '2018-03-06 14:49:04');
-INSERT INTO `system_menu` VALUES ('28', '26', '微信黑名单管理', '', 'fa fa-user-times', 'wechat/fans_block/index', '', '_self', '30', '1', '0', '2018-03-06 14:49:22');
-INSERT INTO `system_menu` VALUES ('29', '26', '微信标签管理', '', 'fa fa-tags', 'wechat/tags/index', '', '_self', '10', '1', '0', '2018-03-06 14:49:39');
-INSERT INTO `system_menu` VALUES ('32', '0', '商城管理', '', '', '#', '', '_self', '2000', '1', '0', '2018-03-20 16:46:07');
-INSERT INTO `system_menu` VALUES ('33', '32', '商品管理', '', '', '#', '', '_self', '0', '1', '0', '2018-03-20 16:46:21');
-INSERT INTO `system_menu` VALUES ('34', '33', '产品管理', '', 'fa fa-modx', 'store/goods/index', '', '_self', '0', '1', '0', '2018-03-20 16:46:45');
-INSERT INTO `system_menu` VALUES ('35', '33', '规格管理', '', 'fa fa-hashtag', 'store/goods_spec/index', '', '_self', '0', '1', '0', '2018-03-20 16:47:08');
-INSERT INTO `system_menu` VALUES ('36', '33', '分类管理', '', 'fa fa-product-hunt', 'store/goods_cate/index', '', '_self', '0', '1', '0', '2018-03-20 16:47:50');
-INSERT INTO `system_menu` VALUES ('37', '33', '品牌管理', '', 'fa fa-scribd', 'store/goods_brand/index', '', '_self', '0', '1', '0', '2018-03-20 16:48:05');
-INSERT INTO `system_menu` VALUES ('38', '32', '订单管理', '', '', '#', '', '_self', '0', '1', '0', '2018-04-21 15:07:36');
-INSERT INTO `system_menu` VALUES ('39', '38', '订单列表', '', 'fa fa-adjust', 'store/order/index', '', '_self', '0', '1', '0', '2018-04-21 15:07:54');
-INSERT INTO `system_menu` VALUES ('40', '32', '商城配置', '', '', '#', '', '_self', '0', '1', '0', '2018-04-21 15:08:17');
-INSERT INTO `system_menu` VALUES ('41', '40', '参数管理', '', '', '#', '', '_self', '0', '0', '0', '2018-04-21 15:08:25');
-INSERT INTO `system_menu` VALUES ('42', '40', '快递公司', '', 'fa fa-mixcloud', 'store/express/index', '', '_self', '0', '1', '0', '2018-04-21 15:08:50');
-
--- ----------------------------
--- Table structure for system_node
--- ----------------------------
-DROP TABLE IF EXISTS `system_node`;
-CREATE TABLE `system_node` (
-  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
-  `node` varchar(100) DEFAULT NULL COMMENT '节点代码',
-  `title` varchar(500) DEFAULT NULL COMMENT '节点标题',
-  `is_menu` tinyint(1) unsigned DEFAULT '0' COMMENT '是否可设置为菜单',
-  `is_auth` tinyint(1) unsigned DEFAULT '1' COMMENT '是否启动RBAC权限控制',
-  `is_login` tinyint(1) unsigned DEFAULT '1' COMMENT '是否启动登录控制',
-  `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  PRIMARY KEY (`id`),
-  KEY `index_system_node_node` (`node`)
-) ENGINE=InnoDB AUTO_INCREMENT=145 DEFAULT CHARSET=utf8 COMMENT='系统节点表';
-
--- ----------------------------
--- Records of system_node
--- ----------------------------
-INSERT INTO `system_node` VALUES ('13', 'admin', '系统设置', '0', '1', '1', '2018-05-04 11:02:34');
-INSERT INTO `system_node` VALUES ('14', 'admin/auth', '权限管理', '0', '1', '1', '2018-05-04 11:06:55');
-INSERT INTO `system_node` VALUES ('15', 'admin/auth/index', '权限列表', '1', '1', '1', '2018-05-04 11:06:56');
-INSERT INTO `system_node` VALUES ('16', 'admin/auth/apply', '权限配置', '0', '1', '1', '2018-05-04 11:06:56');
-INSERT INTO `system_node` VALUES ('17', 'admin/auth/add', '添加权限', '0', '1', '1', '2018-05-04 11:06:56');
-INSERT INTO `system_node` VALUES ('18', 'admin/auth/edit', '编辑权限', '0', '1', '1', '2018-05-04 11:06:56');
-INSERT INTO `system_node` VALUES ('19', 'admin/auth/forbid', '禁用权限', '0', '1', '1', '2018-05-04 11:06:56');
-INSERT INTO `system_node` VALUES ('20', 'admin/auth/resume', '启用权限', '0', '1', '1', '2018-05-04 11:06:56');
-INSERT INTO `system_node` VALUES ('21', 'admin/auth/del', '删除权限', '0', '1', '1', '2018-05-04 11:06:56');
-INSERT INTO `system_node` VALUES ('22', 'admin/config', '系统配置', '0', '1', '1', '2018-05-04 11:08:18');
-INSERT INTO `system_node` VALUES ('23', 'admin/config/index', '系统参数', '1', '1', '1', '2018-05-04 11:08:25');
-INSERT INTO `system_node` VALUES ('24', 'admin/config/file', '文件存储', '1', '1', '1', '2018-05-04 11:08:27');
-INSERT INTO `system_node` VALUES ('25', 'admin/log', '日志管理', '0', '1', '1', '2018-05-04 11:08:43');
-INSERT INTO `system_node` VALUES ('26', 'admin/log/index', '日志管理', '1', '1', '1', '2018-05-04 11:08:43');
-INSERT INTO `system_node` VALUES ('28', 'admin/log/del', '日志删除', '0', '1', '1', '2018-05-04 11:08:43');
-INSERT INTO `system_node` VALUES ('29', 'admin/menu', '系统菜单', '0', '1', '1', '2018-05-04 11:09:54');
-INSERT INTO `system_node` VALUES ('30', 'admin/menu/index', '菜单列表', '1', '1', '1', '2018-05-04 11:09:54');
-INSERT INTO `system_node` VALUES ('31', 'admin/menu/add', '添加菜单', '0', '1', '1', '2018-05-04 11:09:55');
-INSERT INTO `system_node` VALUES ('32', 'admin/menu/edit', '编辑菜单', '0', '1', '1', '2018-05-04 11:09:55');
-INSERT INTO `system_node` VALUES ('33', 'admin/menu/del', '删除菜单', '0', '1', '1', '2018-05-04 11:09:55');
-INSERT INTO `system_node` VALUES ('34', 'admin/menu/forbid', '禁用菜单', '0', '1', '1', '2018-05-04 11:09:55');
-INSERT INTO `system_node` VALUES ('35', 'admin/menu/resume', '启用菜单', '0', '1', '1', '2018-05-04 11:09:55');
-INSERT INTO `system_node` VALUES ('36', 'admin/node', '节点管理', '0', '1', '1', '2018-05-04 11:10:20');
-INSERT INTO `system_node` VALUES ('37', 'admin/node/index', '节点列表', '1', '1', '1', '2018-05-04 11:10:20');
-INSERT INTO `system_node` VALUES ('38', 'admin/node/clear', '清理节点', '0', '1', '1', '2018-05-04 11:10:21');
-INSERT INTO `system_node` VALUES ('39', 'admin/node/save', '更新节点', '0', '1', '1', '2018-05-04 11:10:21');
-INSERT INTO `system_node` VALUES ('40', 'admin/user', '系统用户', '0', '1', '1', '2018-05-04 11:10:43');
-INSERT INTO `system_node` VALUES ('41', 'admin/user/index', '用户列表', '1', '1', '1', '2018-05-04 11:10:43');
-INSERT INTO `system_node` VALUES ('42', 'admin/user/auth', '用户授权', '0', '1', '1', '2018-05-04 11:10:43');
-INSERT INTO `system_node` VALUES ('43', 'admin/user/add', '添加用户', '0', '1', '1', '2018-05-04 11:10:43');
-INSERT INTO `system_node` VALUES ('44', 'admin/user/edit', '编辑用户', '0', '1', '1', '2018-05-04 11:10:43');
-INSERT INTO `system_node` VALUES ('45', 'admin/user/pass', '修改密码', '0', '1', '1', '2018-05-04 11:10:43');
-INSERT INTO `system_node` VALUES ('46', 'admin/user/del', '删除用户', '0', '1', '1', '2018-05-04 11:10:43');
-INSERT INTO `system_node` VALUES ('47', 'admin/user/forbid', '禁用启用', '0', '1', '1', '2018-05-04 11:10:43');
-INSERT INTO `system_node` VALUES ('48', 'admin/user/resume', '启用用户', '0', '1', '1', '2018-05-04 11:10:44');
-INSERT INTO `system_node` VALUES ('49', 'store', '商城管理', '0', '1', '1', '2018-05-04 11:11:28');
-INSERT INTO `system_node` VALUES ('50', 'store/express', '快递公司管理', '0', '1', '1', '2018-05-04 11:11:39');
-INSERT INTO `system_node` VALUES ('51', 'store/express/index', '快递公司列表', '1', '1', '1', '2018-05-04 11:11:39');
-INSERT INTO `system_node` VALUES ('52', 'store/express/add', '添加快递公司', '0', '1', '1', '2018-05-04 11:11:39');
-INSERT INTO `system_node` VALUES ('53', 'store/express/edit', '编辑快递公司', '0', '1', '1', '2018-05-04 11:11:39');
-INSERT INTO `system_node` VALUES ('54', 'store/express/del', '删除快递公司', '0', '1', '1', '2018-05-04 11:11:39');
-INSERT INTO `system_node` VALUES ('55', 'store/express/forbid', '禁用快递公司', '0', '1', '1', '2018-05-04 11:11:39');
-INSERT INTO `system_node` VALUES ('56', 'store/express/resume', '启用快递公司', '0', '1', '1', '2018-05-04 11:11:40');
-INSERT INTO `system_node` VALUES ('57', 'store/order', '订单管理', '0', '1', '1', '2018-05-04 11:12:14');
-INSERT INTO `system_node` VALUES ('58', 'store/order/index', '订单列表', '1', '1', '1', '2018-05-04 11:12:17');
-INSERT INTO `system_node` VALUES ('59', 'store/order/address', '修改地址', '0', '1', '1', '2018-05-04 11:12:19');
-INSERT INTO `system_node` VALUES ('76', 'wechat', '微信管理', '0', '1', '1', '2018-05-04 11:14:59');
-INSERT INTO `system_node` VALUES ('78', 'wechat/config', '微信对接管理', '0', '1', '1', '2018-05-04 11:16:20');
-INSERT INTO `system_node` VALUES ('79', 'wechat/config/index', '微信对接配置', '1', '1', '1', '2018-05-04 11:16:23');
-INSERT INTO `system_node` VALUES ('80', 'wechat/fans', '微信粉丝管理', '0', '1', '1', '2018-05-04 11:16:31');
-INSERT INTO `system_node` VALUES ('81', 'wechat/fans/index', '微信粉丝列表', '1', '1', '1', '2018-05-04 11:16:32');
-INSERT INTO `system_node` VALUES ('82', 'wechat/fans/backadd', '微信粉丝拉黑', '0', '1', '1', '2018-05-04 11:16:32');
-INSERT INTO `system_node` VALUES ('83', 'wechat/fans/tagset', '设置粉丝标签', '0', '1', '1', '2018-05-04 11:16:32');
-INSERT INTO `system_node` VALUES ('84', 'wechat/fans/tagadd', '添加粉丝标签', '0', '1', '1', '2018-05-04 11:16:32');
-INSERT INTO `system_node` VALUES ('85', 'wechat/fans/tagdel', '删除粉丝标签', '0', '1', '1', '2018-05-04 11:16:32');
-INSERT INTO `system_node` VALUES ('86', 'wechat/fans/sync', '同步粉丝列表', '0', '1', '1', '2018-05-04 11:16:32');
-INSERT INTO `system_node` VALUES ('87', 'wechat/fans_block', '粉丝黑名单管理', '0', '1', '1', '2018-05-04 11:17:25');
-INSERT INTO `system_node` VALUES ('88', 'wechat/fans_block/index', '粉丝黑名单列表', '1', '1', '1', '2018-05-04 11:17:50');
-INSERT INTO `system_node` VALUES ('89', 'wechat/fans_block/backdel', '移除粉丝黑名单', '0', '1', '1', '2018-05-04 11:17:51');
-INSERT INTO `system_node` VALUES ('90', 'wechat/keys', '微信关键字', '0', '1', '1', '2018-05-04 11:18:09');
-INSERT INTO `system_node` VALUES ('91', 'wechat/keys/index', '关键字列表', '1', '1', '1', '2018-05-04 11:18:09');
-INSERT INTO `system_node` VALUES ('92', 'wechat/keys/add', '添加关键字', '0', '1', '1', '2018-05-04 11:18:09');
-INSERT INTO `system_node` VALUES ('93', 'wechat/keys/edit', '编辑关键字', '0', '1', '1', '2018-05-04 11:18:09');
-INSERT INTO `system_node` VALUES ('94', 'wechat/keys/del', '删除关键字', '0', '1', '1', '2018-05-04 11:18:09');
-INSERT INTO `system_node` VALUES ('95', 'wechat/keys/forbid', '禁用关键字', '0', '1', '1', '2018-05-04 11:18:09');
-INSERT INTO `system_node` VALUES ('96', 'wechat/keys/resume', '启用关键字', '0', '1', '1', '2018-05-04 11:18:09');
-INSERT INTO `system_node` VALUES ('97', 'wechat/keys/subscribe', '关注回复', '1', '1', '1', '2018-05-04 11:18:09');
-INSERT INTO `system_node` VALUES ('98', 'wechat/keys/defaults', '默认回复', '1', '1', '1', '2018-05-04 11:18:09');
-INSERT INTO `system_node` VALUES ('99', 'wechat/menu', '微信菜单管理', '0', '1', '1', '2018-05-04 11:18:57');
-INSERT INTO `system_node` VALUES ('100', 'wechat/menu/index', '微信菜单展示', '1', '1', '1', '2018-05-04 11:19:10');
-INSERT INTO `system_node` VALUES ('101', 'wechat/menu/edit', '编辑微信菜单', '0', '1', '1', '2018-05-04 11:19:22');
-INSERT INTO `system_node` VALUES ('102', 'wechat/menu/cancel', '取消微信菜单', '0', '1', '1', '2018-05-04 11:19:26');
-INSERT INTO `system_node` VALUES ('103', 'wechat/news/index', '微信图文列表', '1', '1', '1', '2018-05-04 11:19:28');
-INSERT INTO `system_node` VALUES ('104', 'wechat/news/select', '微信图文选择', '0', '1', '1', '2018-05-04 11:19:28');
-INSERT INTO `system_node` VALUES ('105', 'wechat/news/image', '微信图片选择', '0', '1', '1', '2018-05-04 11:19:28');
-INSERT INTO `system_node` VALUES ('106', 'wechat/news/add', '添加微信图文', '0', '1', '1', '2018-05-04 11:19:28');
-INSERT INTO `system_node` VALUES ('107', 'wechat/news/edit', '编辑微信图文', '0', '1', '1', '2018-05-04 11:19:28');
-INSERT INTO `system_node` VALUES ('108', 'wechat/news/del', '删除微信图文', '0', '1', '1', '2018-05-04 11:19:28');
-INSERT INTO `system_node` VALUES ('109', 'wechat/news/push', '推送微信图文', '0', '1', '1', '2018-05-04 11:19:28');
-INSERT INTO `system_node` VALUES ('110', 'wechat/news', '微信图文管理', '0', '1', '1', '2018-05-04 11:19:35');
-INSERT INTO `system_node` VALUES ('111', 'wechat/tags', '微信粉丝标签管理', '0', '1', '1', '2018-05-04 11:20:28');
-INSERT INTO `system_node` VALUES ('112', 'wechat/tags/index', '粉丝标签列表', '1', '1', '1', '2018-05-04 11:20:28');
-INSERT INTO `system_node` VALUES ('113', 'wechat/tags/add', '添加粉丝标签', '0', '1', '1', '2018-05-04 11:20:28');
-INSERT INTO `system_node` VALUES ('114', 'wechat/tags/edit', '编辑粉丝标签', '0', '1', '1', '2018-05-04 11:20:29');
-INSERT INTO `system_node` VALUES ('115', 'wechat/tags/del', '删除粉丝标签', '0', '1', '1', '2018-05-04 11:20:29');
-INSERT INTO `system_node` VALUES ('116', 'wechat/tags/sync', '同步粉丝标签', '0', '1', '1', '2018-05-04 11:20:29');
-INSERT INTO `system_node` VALUES ('117', 'store/goods', '商品管理', '0', '1', '1', '2018-05-04 11:29:55');
-INSERT INTO `system_node` VALUES ('118', 'store/goods/index', '商品列表', '1', '1', '1', '2018-05-04 11:29:56');
-INSERT INTO `system_node` VALUES ('119', 'store/goods/add', '添加商品', '0', '1', '1', '2018-05-04 11:29:56');
-INSERT INTO `system_node` VALUES ('120', 'store/goods/edit', '编辑商品', '0', '1', '1', '2018-05-04 11:29:56');
-INSERT INTO `system_node` VALUES ('121', 'store/goods/del', '删除商品', '0', '1', '1', '2018-05-04 11:29:56');
-INSERT INTO `system_node` VALUES ('122', 'store/goods/forbid', '下架商品', '0', '1', '1', '2018-05-04 11:29:56');
-INSERT INTO `system_node` VALUES ('123', 'store/goods/resume', '上架商品', '0', '1', '1', '2018-05-04 11:29:57');
-INSERT INTO `system_node` VALUES ('124', 'store/goods_brand', '商品品牌管理', '0', '1', '1', '2018-05-04 11:30:44');
-INSERT INTO `system_node` VALUES ('125', 'store/goods_brand/index', '商品品牌列表', '1', '1', '1', '2018-05-04 11:30:52');
-INSERT INTO `system_node` VALUES ('126', 'store/goods_brand/add', '添加商品品牌', '0', '1', '1', '2018-05-04 11:30:55');
-INSERT INTO `system_node` VALUES ('127', 'store/goods_brand/edit', '编辑商品品牌', '0', '1', '1', '2018-05-04 11:30:56');
-INSERT INTO `system_node` VALUES ('128', 'store/goods_brand/del', '删除商品品牌', '0', '1', '1', '2018-05-04 11:30:56');
-INSERT INTO `system_node` VALUES ('129', 'store/goods_brand/forbid', '禁用商品品牌', '0', '1', '1', '2018-05-04 11:30:56');
-INSERT INTO `system_node` VALUES ('130', 'store/goods_brand/resume', '启用商品品牌', '0', '1', '1', '2018-05-04 11:30:56');
-INSERT INTO `system_node` VALUES ('131', 'store/goods_cate', '商品分类管理', '0', '1', '1', '2018-05-04 11:31:19');
-INSERT INTO `system_node` VALUES ('132', 'store/goods_cate/index', '商品分类列表', '1', '1', '1', '2018-05-04 11:31:23');
-INSERT INTO `system_node` VALUES ('133', 'store/goods_cate/add', '添加商品分类', '0', '1', '1', '2018-05-04 11:31:23');
-INSERT INTO `system_node` VALUES ('134', 'store/goods_cate/edit', '编辑商品分类', '0', '1', '1', '2018-05-04 11:31:23');
-INSERT INTO `system_node` VALUES ('135', 'store/goods_cate/del', '删除商品分类', '0', '1', '1', '2018-05-04 11:31:24');
-INSERT INTO `system_node` VALUES ('136', 'store/goods_cate/forbid', '禁用商品分类', '0', '1', '1', '2018-05-04 11:31:24');
-INSERT INTO `system_node` VALUES ('137', 'store/goods_cate/resume', '启用商品分类', '0', '1', '1', '2018-05-04 11:31:24');
-INSERT INTO `system_node` VALUES ('138', 'store/goods_spec', '商品规格管理', '0', '1', '1', '2018-05-04 11:31:47');
-INSERT INTO `system_node` VALUES ('139', 'store/goods_spec/index', '商品规格列表', '1', '1', '1', '2018-05-04 11:31:47');
-INSERT INTO `system_node` VALUES ('140', 'store/goods_spec/add', '添加商品规格', '0', '1', '1', '2018-05-04 11:31:47');
-INSERT INTO `system_node` VALUES ('141', 'store/goods_spec/edit', '编辑商品规格', '0', '1', '1', '2018-05-04 11:31:48');
-INSERT INTO `system_node` VALUES ('142', 'store/goods_spec/del', '删除商品规格', '0', '1', '1', '2018-05-04 11:31:48');
-INSERT INTO `system_node` VALUES ('143', 'store/goods_spec/forbid', '禁用商品规格', '0', '1', '1', '2018-05-04 11:31:48');
-INSERT INTO `system_node` VALUES ('144', 'store/goods_spec/resume', '启用商品规格', '0', '1', '1', '2018-05-04 11:31:48');
-
--- ----------------------------
--- Table structure for system_sequence
--- ----------------------------
-DROP TABLE IF EXISTS `system_sequence`;
-CREATE TABLE `system_sequence` (
-  `id` bigint(20) NOT NULL AUTO_INCREMENT,
-  `type` varchar(20) DEFAULT NULL COMMENT '序号类型',
-  `sequence` char(50) NOT NULL COMMENT '序号值',
-  `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-  PRIMARY KEY (`id`),
-  UNIQUE KEY `index_system_sequence_unique` (`type`,`sequence`) USING BTREE,
-  KEY `index_system_sequence_type` (`type`),
-  KEY `index_system_sequence_number` (`sequence`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='系统序号表';
-
--- ----------------------------
--- Records of system_sequence
--- ----------------------------
-
--- ----------------------------
--- Table structure for system_user
--- ----------------------------
-DROP TABLE IF EXISTS `system_user`;
-CREATE TABLE `system_user` (
-  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
-  `username` varchar(50) NOT NULL DEFAULT '' COMMENT '用户登录名',
-  `password` char(32) NOT NULL DEFAULT '' COMMENT '用户登录密码',
-  `qq` varchar(16) DEFAULT NULL COMMENT '联系QQ',
-  `mail` varchar(32) DEFAULT NULL COMMENT '联系邮箱',
-  `phone` varchar(16) DEFAULT NULL COMMENT '联系手机号',
-  `desc` varchar(255) DEFAULT '' COMMENT '备注说明',
-  `login_num` bigint(20) unsigned DEFAULT '0' COMMENT '登录次数',
-  `login_at` datetime DEFAULT NULL,
-  `status` tinyint(1) unsigned NOT NULL DEFAULT '1' COMMENT '状态(0:禁用,1:启用)',
-  `authorize` varchar(255) DEFAULT NULL,
-  `is_deleted` tinyint(1) unsigned DEFAULT '0' COMMENT '删除状态(1:删除,0:未删)',
-  `create_by` bigint(20) unsigned DEFAULT NULL COMMENT '创建人',
-  `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  PRIMARY KEY (`id`),
-  UNIQUE KEY `index_system_user_username` (`username`) USING BTREE
-) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=utf8 COMMENT='系统用户表';
-
--- ----------------------------
--- Records of system_user
--- ----------------------------
-INSERT INTO `system_user` VALUES ('10000', 'admin', '21232f297a57a5a743894a0e4a801fc3', '22222222', '', '', '', '22973', '2018-03-26 17:06:48', '1', '2,4', '0', null, '2015-11-13 15:14:22');
-
--- ----------------------------
--- Table structure for wechat_fans
--- ----------------------------
-DROP TABLE IF EXISTS `wechat_fans`;
-CREATE TABLE `wechat_fans` (
-  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
-  `appid` char(50) DEFAULT '' COMMENT '公众号Appid',
-  `unionid` char(100) DEFAULT '' COMMENT 'unionid',
-  `openid` char(100) DEFAULT '' COMMENT '用户的标识,对当前公众号唯一',
-  `spread_openid` char(100) DEFAULT '' COMMENT '推荐人OPENID',
-  `spread_at` datetime DEFAULT NULL COMMENT '推荐时间',
-  `tagid_list` varchar(100) DEFAULT '' COMMENT '标签id',
-  `is_black` tinyint(1) unsigned DEFAULT '0' COMMENT '是否为黑名单用户',
-  `subscribe` tinyint(1) unsigned DEFAULT '0' COMMENT '用户是否关注该公众号(0:未关注, 1:已关注)',
-  `nickname` varchar(200) DEFAULT '' COMMENT '用户的昵称',
-  `sex` tinyint(1) unsigned DEFAULT NULL COMMENT '用户的性别,值为1时是男性,值为2时是女性,值为0时是未知',
-  `country` varchar(50) DEFAULT '' COMMENT '用户所在国家',
-  `province` varchar(50) DEFAULT '' COMMENT '用户所在省份',
-  `city` varchar(50) DEFAULT '' COMMENT '用户所在城市',
-  `language` varchar(50) DEFAULT '' COMMENT '用户的语言,简体中文为zh_CN',
-  `headimgurl` varchar(500) DEFAULT '' COMMENT '用户头像',
-  `subscribe_time` bigint(20) unsigned DEFAULT '0' COMMENT '用户关注时间',
-  `subscribe_at` datetime DEFAULT NULL COMMENT '关注时间',
-  `remark` varchar(50) DEFAULT '' COMMENT '备注',
-  `expires_in` bigint(20) unsigned DEFAULT '0' COMMENT '有效时间',
-  `refresh_token` varchar(200) DEFAULT '' COMMENT '刷新token',
-  `access_token` varchar(200) DEFAULT '' COMMENT '访问token',
-  `subscribe_scene` varchar(200) DEFAULT '' COMMENT '扫码关注场景',
-  `qr_scene` varchar(100) DEFAULT '' COMMENT '二维码场景值',
-  `qr_scene_str` varchar(200) DEFAULT '' COMMENT '二维码场景内容',
-  `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  PRIMARY KEY (`id`),
-  KEY `index_wechat_fans_spread_openid` (`spread_openid`) USING BTREE,
-  KEY `index_wechat_fans_openid` (`openid`) USING BTREE,
-  KEY `index_wechat_fans_unionid` (`unionid`),
-  KEY `index_wechat_fans_is_back` (`is_black`),
-  KEY `index_wechat_fans_subscribe` (`subscribe`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='微信粉丝';
-
--- ----------------------------
--- Records of wechat_fans
--- ----------------------------
-
--- ----------------------------
--- Table structure for wechat_fans_tags
--- ----------------------------
-DROP TABLE IF EXISTS `wechat_fans_tags`;
-CREATE TABLE `wechat_fans_tags` (
-  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '标签ID',
-  `appid` char(50) DEFAULT NULL COMMENT '公众号APPID',
-  `name` varchar(35) DEFAULT NULL COMMENT '标签名称',
-  `count` int(11) unsigned DEFAULT NULL COMMENT '总数',
-  `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建日期',
-  KEY `index_wechat_fans_tags_id` (`id`) USING BTREE,
-  KEY `index_wechat_fans_tags_appid` (`appid`) USING BTREE
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='微信会员标签';
-
--- ----------------------------
--- Records of wechat_fans_tags
--- ----------------------------
-
--- ----------------------------
--- Table structure for wechat_keys
--- ----------------------------
-DROP TABLE IF EXISTS `wechat_keys`;
-CREATE TABLE `wechat_keys` (
-  `id` bigint(20) NOT NULL AUTO_INCREMENT,
-  `appid` char(100) DEFAULT '' COMMENT '公众号APPID',
-  `type` varchar(20) DEFAULT '' COMMENT '类型,text 文件消息,image 图片消息,news 图文消息',
-  `keys` varchar(100) DEFAULT NULL COMMENT '关键字',
-  `content` text COMMENT '文本内容',
-  `image_url` varchar(255) DEFAULT '' COMMENT '图片链接',
-  `voice_url` varchar(255) DEFAULT '' COMMENT '语音链接',
-  `music_title` varchar(100) DEFAULT '' COMMENT '音乐标题',
-  `music_url` varchar(255) DEFAULT '' COMMENT '音乐链接',
-  `music_image` varchar(255) DEFAULT '' COMMENT '音乐缩略图链接',
-  `music_desc` varchar(255) DEFAULT '' COMMENT '音乐描述',
-  `video_title` varchar(100) DEFAULT '' COMMENT '视频标题',
-  `video_url` varchar(255) DEFAULT '' COMMENT '视频URL',
-  `video_desc` varchar(255) DEFAULT '' COMMENT '视频描述',
-  `news_id` bigint(20) unsigned DEFAULT NULL COMMENT '图文ID',
-  `sort` bigint(20) unsigned DEFAULT '0' COMMENT '排序字段',
-  `status` tinyint(1) unsigned DEFAULT '1' COMMENT '0 禁用,1 启用',
-  `create_by` bigint(20) unsigned DEFAULT NULL COMMENT '创建人',
-  `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间',
-  PRIMARY KEY (`id`),
-  KEY `index_wechat_keys_appid` (`appid`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='微信关键字';
-
--- ----------------------------
--- Records of wechat_keys
--- ----------------------------
-
--- ----------------------------
--- Table structure for wechat_menu
--- ----------------------------
-DROP TABLE IF EXISTS `wechat_menu`;
-CREATE TABLE `wechat_menu` (
-  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
-  `index` bigint(20) DEFAULT NULL,
-  `pindex` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '父id',
-  `type` varchar(24) NOT NULL DEFAULT '' COMMENT '菜单类型 null主菜单 link链接 keys关键字',
-  `name` varchar(256) NOT NULL DEFAULT '' COMMENT '菜单名称',
-  `content` text NOT NULL COMMENT '文字内容',
-  `sort` bigint(20) unsigned DEFAULT '0' COMMENT '排序',
-  `status` tinyint(1) unsigned DEFAULT '1' COMMENT '状态(0禁用1启用)',
-  `create_by` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '创建人',
-  `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  PRIMARY KEY (`id`),
-  KEY `index_wechat_menu_pindex` (`pindex`) USING BTREE
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='微信菜单配置';
-
--- ----------------------------
--- Records of wechat_menu
--- ----------------------------
-
--- ----------------------------
--- Table structure for wechat_news
--- ----------------------------
-DROP TABLE IF EXISTS `wechat_news`;
-CREATE TABLE `wechat_news` (
-  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
-  `media_id` varchar(100) DEFAULT '' COMMENT '永久素材MediaID',
-  `local_url` varchar(300) DEFAULT '' COMMENT '永久素材显示URL',
-  `article_id` varchar(60) DEFAULT '' COMMENT '关联图文ID,用,号做分割',
-  `is_deleted` tinyint(1) unsigned DEFAULT '0' COMMENT '是否删除',
-  `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `create_by` bigint(20) DEFAULT NULL COMMENT '创建人',
-  PRIMARY KEY (`id`),
-  KEY `index_wechat_news_artcle_id` (`article_id`) USING BTREE
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='微信图文表';
-
--- ----------------------------
--- Records of wechat_news
--- ----------------------------
-
--- ----------------------------
--- Table structure for wechat_news_article
--- ----------------------------
-DROP TABLE IF EXISTS `wechat_news_article`;
-CREATE TABLE `wechat_news_article` (
-  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
-  `title` varchar(50) DEFAULT '' COMMENT '素材标题',
-  `local_url` varchar(300) DEFAULT '' COMMENT '永久素材显示URL',
-  `show_cover_pic` tinyint(4) unsigned DEFAULT '0' COMMENT '是否显示封面 0不显示,1 显示',
-  `author` varchar(20) DEFAULT '' COMMENT '作者',
-  `digest` varchar(300) DEFAULT '' COMMENT '摘要内容',
-  `content` longtext COMMENT '图文内容',
-  `content_source_url` varchar(200) DEFAULT '' COMMENT '图文消息原文地址',
-  `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `create_by` bigint(20) DEFAULT NULL COMMENT '创建人',
-  PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='微信素材表';
-
--- ----------------------------
--- Records of wechat_news_article
--- ----------------------------
-
--- ----------------------------
--- Table structure for wechat_news_image
--- ----------------------------
-DROP TABLE IF EXISTS `wechat_news_image`;
-CREATE TABLE `wechat_news_image` (
-  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
-  `md5` varchar(32) DEFAULT '' COMMENT '文件md5',
-  `local_url` varchar(300) DEFAULT '' COMMENT '本地文件链接',
-  `media_url` varchar(300) DEFAULT '' COMMENT '远程图片链接',
-  `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  PRIMARY KEY (`id`),
-  KEY `index_wechat_news_image_md5` (`md5`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='微信服务器图片';
-
--- ----------------------------
--- Records of wechat_news_image
--- ----------------------------
-
--- ----------------------------
--- Table structure for wechat_news_media
--- ----------------------------
-DROP TABLE IF EXISTS `wechat_news_media`;
-CREATE TABLE `wechat_news_media` (
-  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
-  `appid` varchar(100) DEFAULT '' COMMENT '公众号ID',
-  `md5` varchar(32) DEFAULT '' COMMENT '文件md5',
-  `type` varchar(20) DEFAULT '' COMMENT '媒体类型',
-  `media_id` varchar(100) DEFAULT '' COMMENT '永久素材MediaID',
-  `local_url` varchar(300) DEFAULT '' COMMENT '本地文件链接',
-  `media_url` varchar(300) DEFAULT '' COMMENT '远程图片链接',
-  `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='微信素材表';
-
-
--- ----------------------------
--- Table structure for store_goods_stock
--- ----------------------------
-DROP TABLE IF EXISTS `store_goods_stock`;
-CREATE TABLE `store_goods_stock` (
-  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
-  `goods_id` bigint(20) unsigned DEFAULT '0' COMMENT '商品ID',
-  `goods_spec` varchar(255) DEFAULT '' COMMENT '商品属性',
-  `goods_stock` bigint(20) unsigned DEFAULT '0' COMMENT '商品库存',
-  `stock_desc` varchar(255) DEFAULT '' COMMENT '商品库存描述',
-  `sort` bigint(20) unsigned DEFAULT '0' COMMENT '数据排序',
-  `status` bigint(1) unsigned DEFAULT '1' COMMENT '商品状态(1有效,0无效)',
-  `is_deleted` bigint(1) unsigned DEFAULT '0' COMMENT '删除状态(1删除,0未删除)',
-  `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  PRIMARY KEY (`id`)
-) ENGINE=InnoDB AUTO_INCREMENT=36 DEFAULT CHARSET=utf8 COMMENT='商城商品库存';
-
--- ----------------------------
--- Records of wechat_news_media
--- ----------------------------

+ 981 - 0
admin_v4.sql

@@ -0,0 +1,981 @@
+/*
+ Navicat Premium Data Transfer
+
+ Source Server         : ctolog.com
+ Source Server Type    : MySQL
+ Source Server Version : 50562
+ Source Host           : 127.0.0.1:3306
+ Source Schema         : admin_v4
+
+ Target Server Type    : MySQL
+ Target Server Version : 50562
+ File Encoding         : 65001
+
+ Date: 02/04/2019 13:45:37
+*/
+
+SET NAMES utf8mb4;
+SET FOREIGN_KEY_CHECKS = 0;
+
+-- ----------------------------
+-- Table structure for store_express
+-- ----------------------------
+DROP TABLE IF EXISTS `store_express`;
+CREATE TABLE `store_express`  (
+  `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
+  `express_title` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '快递公司名称',
+  `express_code` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '快递公司代码',
+  `express_desc` varchar(512) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '快递公司描述',
+  `status` tinyint(1) UNSIGNED NULL DEFAULT 1 COMMENT '状态(0.无效,1.有效)',
+  `sort` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '排序权重',
+  `is_deleted` tinyint(1) UNSIGNED NULL DEFAULT 0 COMMENT '删除状态(1删除,0未删除)',
+  `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  PRIMARY KEY (`id`) USING BTREE,
+  INDEX `index_store_express_code`(`express_code`) USING BTREE,
+  INDEX `index_store_express_status`(`status`) USING BTREE,
+  INDEX `index_store_express_deleted`(`is_deleted`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 97 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '商城-快递' ROW_FORMAT = Compact;
+
+-- ----------------------------
+-- Records of store_express
+-- ----------------------------
+INSERT INTO `store_express` VALUES (5, 'AAE全球专递', 'aae', NULL, 0, 0, 0, '2017-09-12 11:53:40');
+INSERT INTO `store_express` VALUES (6, '安捷快递', 'anjie', '', 0, 0, 0, '2017-09-13 15:27:26');
+INSERT INTO `store_express` VALUES (7, '安信达快递', 'anxindakuaixi', NULL, 0, 0, 0, '2017-09-13 16:05:19');
+INSERT INTO `store_express` VALUES (8, '彪记快递', 'biaojikuaidi', NULL, 0, 0, 0, '2017-09-13 16:05:26');
+INSERT INTO `store_express` VALUES (9, 'BHT', 'bht', '', 0, 0, 0, '2017-09-13 16:05:37');
+INSERT INTO `store_express` VALUES (10, '百福东方国际物流', 'baifudongfang', NULL, 0, 0, 0, '2017-09-13 16:05:41');
+INSERT INTO `store_express` VALUES (11, '中国东方(COE)', 'coe', NULL, 0, 0, 0, '2017-09-13 16:05:48');
+INSERT INTO `store_express` VALUES (12, '长宇物流', 'changyuwuliu', NULL, 0, 0, 0, '2017-09-13 16:05:58');
+INSERT INTO `store_express` VALUES (13, '大田物流', 'datianwuliu', NULL, 0, 0, 0, '2017-09-13 16:06:06');
+INSERT INTO `store_express` VALUES (14, '德邦物流', 'debangwuliu', NULL, 1, 1, 0, '2017-09-13 16:06:14');
+INSERT INTO `store_express` VALUES (15, 'DHL', 'dhl', NULL, 0, 0, 0, '2017-09-13 16:06:24');
+INSERT INTO `store_express` VALUES (16, 'DPEX', 'dpex', NULL, 0, 0, 0, '2017-09-13 16:06:29');
+INSERT INTO `store_express` VALUES (17, 'd速快递', 'dsukuaidi', NULL, 0, 0, 0, '2017-09-13 16:06:34');
+INSERT INTO `store_express` VALUES (18, '递四方', 'disifang', NULL, 0, 0, 0, '2017-09-13 16:06:40');
+INSERT INTO `store_express` VALUES (19, 'EMS快递', 'ems', '', 1, 0, 0, '2017-09-13 16:06:47');
+INSERT INTO `store_express` VALUES (20, 'FEDEX(国外)', 'fedex', NULL, 0, 0, 0, '2017-09-13 16:06:56');
+INSERT INTO `store_express` VALUES (21, '飞康达物流', 'feikangda', NULL, 0, 0, 0, '2017-09-13 16:07:03');
+INSERT INTO `store_express` VALUES (22, '凤凰快递', 'fenghuangkuaidi', NULL, 0, 0, 0, '2017-09-13 16:07:10');
+INSERT INTO `store_express` VALUES (23, '飞快达', 'feikuaida', NULL, 0, 0, 0, '2017-09-13 16:07:16');
+INSERT INTO `store_express` VALUES (24, '国通快递', 'guotongkuaidi', NULL, 0, 0, 0, '2017-09-13 16:07:27');
+INSERT INTO `store_express` VALUES (25, '港中能达物流', 'ganzhongnengda', NULL, 0, 0, 0, '2017-09-13 16:07:33');
+INSERT INTO `store_express` VALUES (26, '广东邮政物流', 'guangdongyouzhengwuliu', NULL, 0, 0, 0, '2017-09-13 16:08:22');
+INSERT INTO `store_express` VALUES (27, '共速达', 'gongsuda', NULL, 0, 0, 0, '2017-09-13 16:08:48');
+INSERT INTO `store_express` VALUES (28, '汇通快运', 'huitongkuaidi', NULL, 1, 0, 0, '2017-09-13 16:08:56');
+INSERT INTO `store_express` VALUES (29, '恒路物流', 'hengluwuliu', NULL, 0, 0, 0, '2017-09-13 16:09:02');
+INSERT INTO `store_express` VALUES (30, '华夏龙物流', 'huaxialongwuliu', NULL, 0, 0, 0, '2017-09-13 16:09:12');
+INSERT INTO `store_express` VALUES (31, '海红', 'haihongwangsong', NULL, 0, 0, 0, '2017-09-13 16:09:20');
+INSERT INTO `store_express` VALUES (32, '海外环球', 'haiwaihuanqiu', NULL, 0, 0, 0, '2017-09-13 16:09:27');
+INSERT INTO `store_express` VALUES (33, '佳怡物流', 'jiayiwuliu', NULL, 0, 0, 0, '2017-09-13 16:09:35');
+INSERT INTO `store_express` VALUES (34, '京广速递', 'jinguangsudikuaijian', NULL, 0, 0, 0, '2017-09-13 16:09:42');
+INSERT INTO `store_express` VALUES (35, '急先达', 'jixianda', NULL, 0, 0, 0, '2017-09-13 16:09:49');
+INSERT INTO `store_express` VALUES (36, '佳吉物流', 'jjwl', NULL, 0, 0, 0, '2017-09-13 16:10:01');
+INSERT INTO `store_express` VALUES (37, '加运美物流', 'jymwl', NULL, 0, 0, 0, '2017-09-13 16:10:13');
+INSERT INTO `store_express` VALUES (38, '金大物流', 'jindawuliu', NULL, 0, 0, 0, '2017-09-13 16:10:22');
+INSERT INTO `store_express` VALUES (39, '嘉里大通', 'jialidatong', NULL, 0, 0, 0, '2017-09-13 16:10:33');
+INSERT INTO `store_express` VALUES (40, '晋越快递', 'jykd', NULL, 0, 0, 0, '2017-09-13 16:10:40');
+INSERT INTO `store_express` VALUES (41, '快捷速递', 'kuaijiesudi', NULL, 0, 0, 0, '2017-09-13 16:10:49');
+INSERT INTO `store_express` VALUES (42, '联邦快递(国内)', 'lianb', NULL, 0, 0, 0, '2017-09-13 16:10:58');
+INSERT INTO `store_express` VALUES (43, '联昊通物流', 'lianhaowuliu', NULL, 0, 0, 0, '2017-09-13 16:11:07');
+INSERT INTO `store_express` VALUES (44, '龙邦物流', 'longbanwuliu', NULL, 0, 0, 0, '2017-09-13 16:11:15');
+INSERT INTO `store_express` VALUES (45, '立即送', 'lijisong', NULL, 0, 0, 0, '2017-09-13 16:11:25');
+INSERT INTO `store_express` VALUES (46, '乐捷递', 'lejiedi', NULL, 0, 0, 0, '2017-09-13 16:11:36');
+INSERT INTO `store_express` VALUES (47, '民航快递', 'minghangkuaidi', NULL, 0, 0, 0, '2017-09-13 16:11:45');
+INSERT INTO `store_express` VALUES (48, '美国快递', 'meiguokuaidi', NULL, 0, 0, 0, '2017-09-13 16:11:53');
+INSERT INTO `store_express` VALUES (49, '门对门', 'menduimen', NULL, 0, 0, 0, '2017-09-13 16:12:01');
+INSERT INTO `store_express` VALUES (50, 'OCS', 'ocs', NULL, 0, 0, 0, '2017-09-13 16:12:10');
+INSERT INTO `store_express` VALUES (51, '配思货运', 'peisihuoyunkuaidi', NULL, 0, 0, 0, '2017-09-13 16:12:18');
+INSERT INTO `store_express` VALUES (52, '全晨快递', 'quanchenkuaidi', NULL, 0, 0, 0, '2017-09-13 16:12:26');
+INSERT INTO `store_express` VALUES (53, '全峰快递', 'quanfengkuaidi', NULL, 0, 0, 0, '2017-09-13 16:12:34');
+INSERT INTO `store_express` VALUES (54, '全际通物流', 'quanjitong', NULL, 0, 0, 0, '2017-09-13 16:12:41');
+INSERT INTO `store_express` VALUES (55, '全日通快递', 'quanritongkuaidi', NULL, 0, 0, 0, '2017-09-13 16:12:49');
+INSERT INTO `store_express` VALUES (56, '全一快递', 'quanyikuaidi', NULL, 0, 0, 0, '2017-09-13 16:12:56');
+INSERT INTO `store_express` VALUES (57, '如风达', 'rufengda', NULL, 0, 0, 0, '2017-09-13 16:13:03');
+INSERT INTO `store_express` VALUES (58, '三态速递', 'santaisudi', NULL, 0, 0, 0, '2017-09-13 16:13:15');
+INSERT INTO `store_express` VALUES (59, '盛辉物流', 'shenghuiwuliu', NULL, 0, 0, 0, '2017-09-13 16:13:22');
+INSERT INTO `store_express` VALUES (60, '申通', 'shentong', NULL, 1, 0, 0, '2017-09-13 16:13:34');
+INSERT INTO `store_express` VALUES (61, '顺丰', 'shunfeng', '', 0, 0, 0, '2017-09-13 16:13:41');
+INSERT INTO `store_express` VALUES (62, '速尔物流', 'sue', NULL, 1, 0, 0, '2017-09-13 16:13:48');
+INSERT INTO `store_express` VALUES (63, '盛丰物流', 'shengfeng', NULL, 0, 0, 0, '2017-09-13 16:13:55');
+INSERT INTO `store_express` VALUES (64, '赛澳递', 'saiaodi', NULL, 0, 0, 0, '2017-09-13 16:14:02');
+INSERT INTO `store_express` VALUES (65, '天地华宇', 'tiandihuayu', NULL, 0, 0, 0, '2017-09-13 16:14:11');
+INSERT INTO `store_express` VALUES (66, '天天快递', 'tiantian', NULL, 1, 0, 0, '2017-09-13 16:14:19');
+INSERT INTO `store_express` VALUES (67, 'TNT', 'tnt', NULL, 0, 0, 0, '2017-09-13 16:14:26');
+INSERT INTO `store_express` VALUES (68, 'UPS', 'ups', NULL, 0, 0, 0, '2017-09-13 16:14:29');
+INSERT INTO `store_express` VALUES (69, '万家物流', 'wanjiawuliu', NULL, 0, 0, 0, '2017-09-13 16:14:37');
+INSERT INTO `store_express` VALUES (70, '文捷航空速递', 'wenjiesudi', NULL, 0, 0, 0, '2017-09-13 16:14:46');
+INSERT INTO `store_express` VALUES (71, '伍圆', 'wuyuan', NULL, 0, 0, 0, '2017-09-13 16:14:52');
+INSERT INTO `store_express` VALUES (72, '万象物流', 'wxwl', NULL, 0, 0, 0, '2017-09-13 16:15:00');
+INSERT INTO `store_express` VALUES (73, '新邦物流', 'xinbangwuliu', NULL, 0, 0, 0, '2017-09-13 16:15:06');
+INSERT INTO `store_express` VALUES (74, '信丰物流', 'xinfengwuliu', NULL, 0, 0, 0, '2017-09-13 16:15:15');
+INSERT INTO `store_express` VALUES (75, '亚风速递', 'yafengsudi', NULL, 0, 0, 0, '2017-09-13 16:15:23');
+INSERT INTO `store_express` VALUES (76, '一邦速递', 'yibangwuliu', NULL, 0, 0, 0, '2017-09-13 16:15:30');
+INSERT INTO `store_express` VALUES (77, '优速物流', 'youshuwuliu', NULL, 0, 0, 0, '2017-09-13 16:15:36');
+INSERT INTO `store_express` VALUES (78, '邮政包裹挂号信', 'youzhengguonei', NULL, 0, 3, 0, '2017-09-13 16:15:44');
+INSERT INTO `store_express` VALUES (79, '邮政国际包裹挂号信', 'youzhengguoji', NULL, 1, 2, 0, '2017-09-13 16:15:51');
+INSERT INTO `store_express` VALUES (80, '远成物流', 'yuanchengwuliu', NULL, 0, 0, 0, '2017-09-13 16:15:57');
+INSERT INTO `store_express` VALUES (81, '圆通速递', 'yuantong', NULL, 1, 1, 0, '2017-09-13 16:16:03');
+INSERT INTO `store_express` VALUES (82, '源伟丰快递', 'yuanweifeng', NULL, 0, 0, 0, '2017-09-13 16:16:10');
+INSERT INTO `store_express` VALUES (83, '元智捷诚快递', 'yuanzhijiecheng', NULL, 0, 0, 0, '2017-09-13 16:16:17');
+INSERT INTO `store_express` VALUES (84, '韵达快运', 'yunda', NULL, 1, 0, 0, '2017-09-13 16:16:24');
+INSERT INTO `store_express` VALUES (85, '运通快递', 'yuntongkuaidi', NULL, 0, 0, 0, '2017-09-13 16:16:33');
+INSERT INTO `store_express` VALUES (86, '越丰物流', 'yuefengwuliu', NULL, 0, 0, 0, '2017-09-13 16:16:40');
+INSERT INTO `store_express` VALUES (87, '源安达', 'yad', NULL, 0, 0, 0, '2017-09-13 16:16:47');
+INSERT INTO `store_express` VALUES (88, '银捷速递', 'yinjiesudi', NULL, 0, 0, 0, '2017-09-13 16:16:56');
+INSERT INTO `store_express` VALUES (89, '宅急送', 'zhaijisong', NULL, 0, 0, 0, '2017-09-13 16:17:03');
+INSERT INTO `store_express` VALUES (90, '中铁快运', 'zhongtiekuaiyun', NULL, 0, 0, 0, '2017-09-13 16:17:10');
+INSERT INTO `store_express` VALUES (91, '中通速递', 'zhongtong', '', 1, 0, 0, '2017-09-13 16:17:16');
+INSERT INTO `store_express` VALUES (92, '中邮物流', 'zhongyouwuliu', NULL, 0, 0, 0, '2017-09-13 16:17:27');
+INSERT INTO `store_express` VALUES (93, '忠信达', 'zhongxinda', NULL, 0, 0, 0, '2017-09-13 16:17:34');
+INSERT INTO `store_express` VALUES (94, '芝麻开门', 'zhimakaimen', NULL, 1, 0, 1, '2017-09-13 16:17:41');
+INSERT INTO `store_express` VALUES (95, '中通快运', 'zhongtongkuaiyun', '', 1, 0, 0, '2019-03-28 15:04:41');
+INSERT INTO `store_express` VALUES (96, '德邦快递', 'debangkuaidi', '', 1, 0, 0, '2019-03-28 15:05:30');
+
+-- ----------------------------
+-- Table structure for store_goods
+-- ----------------------------
+DROP TABLE IF EXISTS `store_goods`;
+CREATE TABLE `store_goods`  (
+  `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
+  `cate_id` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '商品分类',
+  `title` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '商品标题',
+  `logo` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '商品图标',
+  `specs` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '商品规格JSON',
+  `lists` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '商品列表JSON',
+  `image` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '商品图片',
+  `content` longtext CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '商品内容',
+  `number_sales` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '销售数量',
+  `number_stock` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '库库数量',
+  `price_rate` decimal(20, 4) UNSIGNED NULL DEFAULT 0.0000 COMMENT '返利比例',
+  `price_express` decimal(20, 2) UNSIGNED NULL DEFAULT 0.00 COMMENT '统一运费',
+  `status` tinyint(1) UNSIGNED NULL DEFAULT 1 COMMENT '销售状态',
+  `sort` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '排序权重',
+  `is_deleted` tinyint(1) UNSIGNED NULL DEFAULT 0 COMMENT '删除状态',
+  `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  PRIMARY KEY (`id`) USING BTREE,
+  INDEX `index_store_goods_status`(`status`) USING BTREE,
+  INDEX `index_store_goods_cate_id`(`cate_id`) USING BTREE,
+  INDEX `index_store_goods_is_deleted`(`is_deleted`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '商品-记录' ROW_FORMAT = Compact;
+
+-- ----------------------------
+-- Table structure for store_goods_cate
+-- ----------------------------
+DROP TABLE IF EXISTS `store_goods_cate`;
+CREATE TABLE `store_goods_cate`  (
+  `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
+  `logo` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '分类图标',
+  `title` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '分类名称',
+  `desc` varchar(1024) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '分类描述',
+  `status` tinyint(1) UNSIGNED NULL DEFAULT 1 COMMENT '销售状态',
+  `sort` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '排序权重',
+  `is_deleted` tinyint(1) UNSIGNED NULL DEFAULT 0 COMMENT '删除状态',
+  `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  PRIMARY KEY (`id`) USING BTREE,
+  INDEX `index_store_goods_cate_is_deleted`(`is_deleted`) USING BTREE,
+  INDEX `index_store_goods_cate_status`(`status`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '商品-分类' ROW_FORMAT = Compact;
+
+-- ----------------------------
+-- Table structure for store_goods_list
+-- ----------------------------
+DROP TABLE IF EXISTS `store_goods_list`;
+CREATE TABLE `store_goods_list`  (
+  `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
+  `goods_id` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '商品ID',
+  `goods_spec` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '商品规格',
+  `price_market` decimal(20, 2) UNSIGNED NULL DEFAULT 0.00 COMMENT '商品标价',
+  `price_selling` decimal(20, 2) UNSIGNED NULL DEFAULT 0.00 COMMENT '商品售价',
+  `number_sales` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '销售数量',
+  `number_stock` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '商品库存',
+  `number_virtual` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '虚拟销量',
+  `status` tinyint(1) UNSIGNED NULL DEFAULT 1 COMMENT '商品状态',
+  `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  PRIMARY KEY (`id`) USING BTREE,
+  INDEX `index_store_goods_list_id`(`goods_id`) USING BTREE,
+  INDEX `index_store_goods_list_spec`(`goods_spec`) USING BTREE,
+  INDEX `index_store_goods_list_status`(`status`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '商品-详情' ROW_FORMAT = Compact;
+
+-- ----------------------------
+-- Table structure for store_goods_stock
+-- ----------------------------
+DROP TABLE IF EXISTS `store_goods_stock`;
+CREATE TABLE `store_goods_stock`  (
+  `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
+  `goods_id` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '商品ID',
+  `goods_spec` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '商品规格',
+  `number_stock` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '商品库存',
+  `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  PRIMARY KEY (`id`) USING BTREE,
+  INDEX `index_store_goods_stock_gid`(`goods_id`) USING BTREE,
+  INDEX `index_store_goods_stock_spec`(`goods_spec`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '商品-入库' ROW_FORMAT = Compact;
+
+-- ----------------------------
+-- Table structure for store_member
+-- ----------------------------
+DROP TABLE IF EXISTS `store_member`;
+CREATE TABLE `store_member`  (
+  `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
+  `openid` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '微信OPENID',
+  `headimg` varchar(512) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '头像地址',
+  `nickname` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '微信昵称',
+  `phone` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '联系手机',
+  `username` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '真实姓名',
+  `vip_level` tinyint(1) UNSIGNED NULL DEFAULT 0 COMMENT '会员级别(0游客,1为临时,2为VIP1,3为VIP2)',
+  `vip_date` date NULL DEFAULT NULL COMMENT '保级日期',
+  `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  PRIMARY KEY (`id`) USING BTREE,
+  INDEX `index_store_member_openid`(`openid`) USING BTREE,
+  INDEX `index_store_member_phone`(`phone`) USING BTREE,
+  INDEX `index_store_member_vip_level`(`vip_level`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '会员-记录' ROW_FORMAT = Compact;
+
+-- ----------------------------
+-- Table structure for store_member_address
+-- ----------------------------
+DROP TABLE IF EXISTS `store_member_address`;
+CREATE TABLE `store_member_address`  (
+  `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
+  `mid` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '会员ID',
+  `name` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '收货姓名',
+  `phone` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '收货手机',
+  `province` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '地址-省份',
+  `city` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '地址-城市',
+  `area` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '地址-区域',
+  `address` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '地址-详情',
+  `is_default` tinyint(1) UNSIGNED NULL DEFAULT 0 COMMENT '默认地址',
+  `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  PRIMARY KEY (`id`) USING BTREE,
+  INDEX `index_store_member_address_mid`(`mid`) USING BTREE,
+  INDEX `index_store_member_address_is_default`(`is_default`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '会员-收货地址' ROW_FORMAT = Compact;
+
+-- ----------------------------
+-- Table structure for store_member_sms_history
+-- ----------------------------
+DROP TABLE IF EXISTS `store_member_sms_history`;
+CREATE TABLE `store_member_sms_history`  (
+  `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
+  `mid` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '会员ID',
+  `phone` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '目标手机',
+  `content` varchar(512) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '短信内容',
+  `result` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '返回结果',
+  `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  PRIMARY KEY (`id`) USING BTREE,
+  INDEX `index_store_member_sms_history_phone`(`phone`) USING BTREE,
+  INDEX `index_store_member_sms_history_mid`(`mid`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '会员-短信' ROW_FORMAT = Compact;
+
+-- ----------------------------
+-- Table structure for store_order
+-- ----------------------------
+DROP TABLE IF EXISTS `store_order`;
+CREATE TABLE `store_order`  (
+  `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
+  `mid` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '会员ID',
+  `order_no` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '订单单号',
+  `from_mid` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '推荐会员ID',
+  `price_total` decimal(20, 2) UNSIGNED NULL DEFAULT 0.00 COMMENT '待付金额统计',
+  `price_goods` decimal(20, 2) UNSIGNED NULL DEFAULT 0.00 COMMENT '商品费用统计',
+  `price_express` decimal(20, 2) UNSIGNED NULL DEFAULT 0.00 COMMENT '快递费用统计',
+  `price_rate_amount` decimal(20, 2) UNSIGNED NULL DEFAULT 0.00 COMMENT '返利金额统计',
+  `pay_state` tinyint(1) UNSIGNED NULL DEFAULT 0 COMMENT '支付状态(0未支付,1已支付)',
+  `pay_type` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '支付方式',
+  `pay_price` decimal(20, 2) UNSIGNED NULL DEFAULT 0.00 COMMENT '支付金额',
+  `pay_no` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '支付单号',
+  `pay_at` datetime NULL DEFAULT NULL COMMENT '支付时间',
+  `cancel_state` tinyint(1) UNSIGNED NULL DEFAULT 0 COMMENT '取消状态',
+  `cancel_at` datetime NULL DEFAULT NULL COMMENT '取消时间',
+  `cancel_desc` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '取消描述',
+  `refund_state` tinyint(1) UNSIGNED NULL DEFAULT 0 COMMENT '退款状态(0未退款,1待退款,2已退款)',
+  `refund_at` datetime NULL DEFAULT NULL COMMENT '退款时间',
+  `refund_no` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '退款单号',
+  `refund_price` decimal(20, 2) NULL DEFAULT 0.00 COMMENT '退款金额',
+  `refund_desc` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '退款描述',
+  `express_state` tinyint(1) UNSIGNED NULL DEFAULT 0 COMMENT '发货状态(0未发货,1已发货,2已签收)',
+  `express_company_code` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '发货快递公司编码',
+  `express_company_title` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '发货快递公司名称',
+  `express_send_no` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '发货单号',
+  `express_send_at` datetime NULL DEFAULT NULL COMMENT '发货时间',
+  `express_address_id` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '收货地址ID',
+  `express_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '收货人姓名',
+  `express_phone` varchar(11) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '收货人手机',
+  `express_province` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '收货地址省份',
+  `express_city` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '收货地址城市',
+  `express_area` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '收货地址区域',
+  `express_address` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '收货详细地址',
+  `status` tinyint(1) UNSIGNED NULL DEFAULT 1 COMMENT '订单状态(0已取消,1预订单待补全,2新订单待支付,3已支付待发货,4已发货待签收,5已完成)',
+  `is_deleted` tinyint(1) UNSIGNED NULL DEFAULT 0 COMMENT '删除状态',
+  `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  PRIMARY KEY (`id`) USING BTREE,
+  INDEX `index_store_groups_order_mid`(`mid`) USING BTREE,
+  INDEX `index_store_groups_order_order_no`(`order_no`) USING BTREE,
+  INDEX `index_store_groups_order_pay_state`(`pay_state`) USING BTREE,
+  INDEX `index_store_groups_order_cancel_state`(`cancel_state`) USING BTREE,
+  INDEX `index_store_groups_order_refund_state`(`refund_state`) USING BTREE,
+  INDEX `index_store_groups_order_status`(`status`) USING BTREE,
+  INDEX `index_store_groups_order_pay_no`(`pay_no`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '订单-记录' ROW_FORMAT = Compact;
+
+-- ----------------------------
+-- Table structure for store_order_list
+-- ----------------------------
+DROP TABLE IF EXISTS `store_order_list`;
+CREATE TABLE `store_order_list`  (
+  `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
+  `mid` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '会员ID',
+  `from_id` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '推荐会员',
+  `order_no` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '订单单号',
+  `number` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '交易数量',
+  `goods_id` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '商品标识',
+  `goods_title` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '商品标题',
+  `goods_logo` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '商品图标',
+  `goods_spec` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '商品规格',
+  `price_real` decimal(20, 2) UNSIGNED NULL DEFAULT 0.00 COMMENT '交易金额',
+  `price_selling` decimal(20, 2) UNSIGNED NULL DEFAULT 0.00 COMMENT '销售价格',
+  `price_market` decimal(20, 2) UNSIGNED NULL DEFAULT 0.00 COMMENT '市场价格',
+  `price_express` decimal(20, 2) UNSIGNED NULL DEFAULT 0.00 COMMENT '快递费用',
+  `price_rate` decimal(20, 4) UNSIGNED NULL DEFAULT 0.0000 COMMENT '分成比例',
+  `price_rate_amount` decimal(20, 2) UNSIGNED NULL DEFAULT 0.00 COMMENT '分成金额',
+  `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  PRIMARY KEY (`id`) USING BTREE,
+  INDEX `index_store_goods_list_id`(`goods_id`) USING BTREE,
+  INDEX `index_store_goods_list_spec`(`goods_spec`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '订单-详情' ROW_FORMAT = Compact;
+
+-- ----------------------------
+-- Table structure for store_profit_record
+-- ----------------------------
+DROP TABLE IF EXISTS `store_profit_record`;
+CREATE TABLE `store_profit_record`  (
+  `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
+  `from_mid` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '来源会员ID',
+  `order_no` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '订单单号',
+  `order_mid` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '订单会员ID',
+  `order_price` decimal(20, 2) UNSIGNED NULL DEFAULT 0.00 COMMENT '订单金额',
+  `profit_price` decimal(20, 2) UNSIGNED NULL DEFAULT 0.00 COMMENT '拥金金额',
+  `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  PRIMARY KEY (`id`) USING BTREE,
+  INDEX `index_store_member_phone`(`profit_price`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '拥金-记录' ROW_FORMAT = Compact;
+
+-- ----------------------------
+-- Table structure for store_profit_used
+-- ----------------------------
+DROP TABLE IF EXISTS `store_profit_used`;
+CREATE TABLE `store_profit_used`  (
+  `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
+  `mid` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '会员ID',
+  `appid` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '公众号APPID',
+  `openid` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '微信OPENID',
+  `trs_no` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '订单号',
+  `pay_no` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '交易号',
+  `pay_desc` varchar(1024) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '提现描述',
+  `pay_price` decimal(20, 2) UNSIGNED NULL DEFAULT 0.00 COMMENT '提现金额',
+  `pay_at` datetime NULL DEFAULT NULL COMMENT '打款时间',
+  `last_at` datetime NULL DEFAULT NULL COMMENT '最后处理时间',
+  `status` tinyint(1) UNSIGNED NULL DEFAULT 1 COMMENT '提现状态(0失败,1待打款,2已完成)',
+  `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  PRIMARY KEY (`id`) USING BTREE,
+  INDEX `index_store_profit_used_openid`(`openid`) USING BTREE,
+  INDEX `index_store_profit_used_mid`(`mid`) USING BTREE,
+  INDEX `index_store_profit_used_appid`(`appid`) USING BTREE,
+  INDEX `index_store_profit_used_status`(`status`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '拥金-提现' ROW_FORMAT = Compact;
+
+-- ----------------------------
+-- Table structure for system_auth
+-- ----------------------------
+DROP TABLE IF EXISTS `system_auth`;
+CREATE TABLE `system_auth`  (
+  `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
+  `title` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '权限名称',
+  `status` tinyint(1) UNSIGNED NULL DEFAULT 1 COMMENT '权限状态',
+  `sort` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '排序权重',
+  `desc` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '备注说明',
+  `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  PRIMARY KEY (`id`) USING BTREE,
+  INDEX `index_system_auth_status`(`status`) USING BTREE,
+  INDEX `index_system_auth_title`(`title`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '系统-权限' ROW_FORMAT = Compact;
+
+-- ----------------------------
+-- Table structure for system_auth_node
+-- ----------------------------
+DROP TABLE IF EXISTS `system_auth_node`;
+CREATE TABLE `system_auth_node`  (
+  `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
+  `auth` bigint(20) UNSIGNED NULL DEFAULT NULL COMMENT '角色',
+  `node` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '节点',
+  PRIMARY KEY (`id`) USING BTREE,
+  INDEX `index_system_auth_auth`(`auth`) USING BTREE,
+  INDEX `index_system_auth_node`(`node`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '系统-权限-授权' ROW_FORMAT = Compact;
+
+-- ----------------------------
+-- Table structure for system_config
+-- ----------------------------
+DROP TABLE IF EXISTS `system_config`;
+CREATE TABLE `system_config`  (
+  `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
+  `name` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '配置名',
+  `value` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '配置值',
+  PRIMARY KEY (`id`) USING BTREE,
+  INDEX `index_system_config_name`(`name`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 70 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '系统-配置' ROW_FORMAT = Compact;
+
+-- ----------------------------
+-- Records of system_config
+-- ----------------------------
+INSERT INTO `system_config` VALUES (1, 'app_name', 'ThinkAdmin');
+INSERT INTO `system_config` VALUES (2, 'site_name', 'ThinkAdmin');
+INSERT INTO `system_config` VALUES (3, 'app_version', 'v4.0');
+INSERT INTO `system_config` VALUES (4, 'site_copy', '©版权所有 2014-2018 楚才科技');
+INSERT INTO `system_config` VALUES (5, 'site_icon', 'http://127.0.0.1:8000/upload/f47b8fe06e38ae99/08e8398da45583b9.png');
+INSERT INTO `system_config` VALUES (7, 'miitbeian', '粤ICP备16006642号-2');
+INSERT INTO `system_config` VALUES (8, 'storage_type', 'local');
+INSERT INTO `system_config` VALUES (9, 'storage_local_exts', 'doc,gif,icon,jpg,mp3,mp4,p12,pem,png,rar');
+INSERT INTO `system_config` VALUES (10, 'storage_qiniu_bucket', 'https');
+INSERT INTO `system_config` VALUES (11, 'storage_qiniu_domain', '用你自己的吧');
+INSERT INTO `system_config` VALUES (12, 'storage_qiniu_access_key', '用你自己的吧');
+INSERT INTO `system_config` VALUES (13, 'storage_qiniu_secret_key', '用你自己的吧');
+INSERT INTO `system_config` VALUES (14, 'storage_oss_bucket', 'cuci-mytest');
+INSERT INTO `system_config` VALUES (15, 'storage_oss_endpoint', 'oss-cn-hangzhou.aliyuncs.com');
+INSERT INTO `system_config` VALUES (16, 'storage_oss_domain', '用你自己的吧');
+INSERT INTO `system_config` VALUES (17, 'storage_oss_keyid', '用你自己的吧');
+INSERT INTO `system_config` VALUES (18, 'storage_oss_secret', '用你自己的吧');
+INSERT INTO `system_config` VALUES (36, 'storage_oss_is_https', 'http');
+INSERT INTO `system_config` VALUES (43, 'storage_qiniu_region', '华东');
+INSERT INTO `system_config` VALUES (44, 'storage_qiniu_is_https', 'https');
+INSERT INTO `system_config` VALUES (45, 'wechat_mch_id', '1332187001');
+INSERT INTO `system_config` VALUES (46, 'wechat_mch_key', 'A82DC5BD1F3359081049C568D8502BC5');
+INSERT INTO `system_config` VALUES (47, 'wechat_mch_ssl_type', 'p12');
+INSERT INTO `system_config` VALUES (48, 'wechat_mch_ssl_p12', '65b8e4f56718182d/1bc857ee646aa15d.p12');
+INSERT INTO `system_config` VALUES (49, 'wechat_mch_ssl_key', '');
+INSERT INTO `system_config` VALUES (50, 'wechat_mch_ssl_cer', '');
+INSERT INTO `system_config` VALUES (51, 'wechat_token', 'mytoken');
+INSERT INTO `system_config` VALUES (52, 'wechat_appid', 'wx60a43dd8161666d4');
+INSERT INTO `system_config` VALUES (53, 'wechat_appsecret', '9978422e0e431643d4b42868d183d60b');
+INSERT INTO `system_config` VALUES (54, 'wechat_encodingaeskey', '');
+INSERT INTO `system_config` VALUES (55, 'wechat_push_url', '消息推送地址:http://127.0.0.1:8000/wechat/api.push');
+INSERT INTO `system_config` VALUES (56, 'wechat_type', 'thr');
+INSERT INTO `system_config` VALUES (57, 'wechat_thr_appid', 'wx60a43dd8161666d4');
+INSERT INTO `system_config` VALUES (58, 'wechat_thr_appkey', '8007da35fd45afe88f2ccc05fe22324d');
+INSERT INTO `system_config` VALUES (60, 'wechat_thr_appurl', '消息推送地址:http://127.0.0.1:8000/wechat/api.push');
+INSERT INTO `system_config` VALUES (61, 'component_appid', 'wx1b8278fa121d8dc6');
+INSERT INTO `system_config` VALUES (62, 'component_appsecret', 'cf5af39408fb3b977584a40d399d298c');
+INSERT INTO `system_config` VALUES (63, 'component_token', 'P8QHTIxpBEq88IrxatqhgpBm2OAQROkI');
+INSERT INTO `system_config` VALUES (64, 'component_encodingaeskey', 'L5uFIa0U6KLalPyXckyqoVIJYLhsfrg8k9YzybZIHsx');
+INSERT INTO `system_config` VALUES (65, 'system_message_state', '0');
+INSERT INTO `system_config` VALUES (66, 'sms_zt_username', '可以找CUCI申请');
+INSERT INTO `system_config` VALUES (67, 'sms_zt_password', '可以找CUCI申请');
+INSERT INTO `system_config` VALUES (68, 'sms_reg_template', '您的验证码为{code},请在十分钟内完成操作!');
+INSERT INTO `system_config` VALUES (69, 'sms_secure', '可以找CUCI申请');
+
+-- ----------------------------
+-- Table structure for system_data
+-- ----------------------------
+DROP TABLE IF EXISTS `system_data`;
+CREATE TABLE `system_data`  (
+  `id` bigint(11) UNSIGNED NOT NULL AUTO_INCREMENT,
+  `name` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '配置名',
+  `value` longtext CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '配置值',
+  PRIMARY KEY (`id`) USING BTREE,
+  INDEX `index_system_data_name`(`name`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '系统-数据' ROW_FORMAT = Compact;
+
+-- ----------------------------
+-- Records of system_data
+-- ----------------------------
+INSERT INTO `system_data` VALUES (1, 'menudata', '[{\"name\":\"请输入名称\",\"type\":\"view\",\"url\":\"3252\"}]');
+
+-- ----------------------------
+-- Table structure for system_jobs
+-- ----------------------------
+DROP TABLE IF EXISTS `system_jobs`;
+CREATE TABLE `system_jobs`  (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `queue` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
+  `payload` longtext CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
+  `attempts` bigint(20) UNSIGNED NOT NULL DEFAULT 0,
+  `reserved` bigint(20) UNSIGNED NOT NULL DEFAULT 0,
+  `reserved_at` int(10) UNSIGNED NULL DEFAULT NULL,
+  `available_at` int(10) UNSIGNED NOT NULL,
+  `created_at` int(10) UNSIGNED NOT NULL,
+  PRIMARY KEY (`id`) USING BTREE,
+  INDEX `index_system_jobs_reserved`(`reserved`) USING BTREE,
+  INDEX `index_system_jobs_attempts`(`attempts`) USING BTREE,
+  INDEX `index_system_jobs_reserved_at`(`reserved_at`) USING BTREE,
+  INDEX `index_system_jobs_available_at`(`available_at`) USING BTREE,
+  INDEX `index_system_jobs_create_at`(`created_at`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '系统-任务' ROW_FORMAT = Compact;
+
+-- ----------------------------
+-- Table structure for system_jobs_log
+-- ----------------------------
+DROP TABLE IF EXISTS `system_jobs_log`;
+CREATE TABLE `system_jobs_log`  (
+  `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
+  `title` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '任务名称',
+  `uri` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '任务对象',
+  `later` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '任务延时',
+  `data` longtext CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '任务数据',
+  `desc` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '任务描述',
+  `double` tinyint(1) UNSIGNED NULL DEFAULT 1 COMMENT '任务多开',
+  `status` tinyint(1) UNSIGNED NULL DEFAULT 1 COMMENT '任务状态(1新任务,2任务进行中,3任务成功,4任务失败)',
+  `status_at` datetime NULL DEFAULT NULL COMMENT '任务状态时间',
+  `status_desc` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '任务状态描述',
+  `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  PRIMARY KEY (`id`) USING BTREE,
+  INDEX `index_system_jobs_log_status`(`status`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '系统-任务-日志' ROW_FORMAT = Compact;
+
+-- ----------------------------
+-- Table structure for system_log
+-- ----------------------------
+DROP TABLE IF EXISTS `system_log`;
+CREATE TABLE `system_log`  (
+  `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
+  `node` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '当前操作节点',
+  `geoip` varchar(15) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '操作者IP地址',
+  `action` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '操作行为名称',
+  `content` varchar(1024) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '操作内容描述',
+  `username` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '操作人用户名',
+  `create_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '系统-日志' ROW_FORMAT = Compact;
+
+-- ----------------------------
+-- Table structure for system_menu
+-- ----------------------------
+DROP TABLE IF EXISTS `system_menu`;
+CREATE TABLE `system_menu`  (
+  `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
+  `pid` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '父ID',
+  `title` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '名称',
+  `node` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '节点代码',
+  `icon` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '菜单图标',
+  `url` varchar(400) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '链接',
+  `params` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '链接参数',
+  `target` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '_self' COMMENT '打开方式',
+  `sort` int(11) UNSIGNED NULL DEFAULT 0 COMMENT '菜单排序',
+  `status` tinyint(1) UNSIGNED NULL DEFAULT 1 COMMENT '状态(0:禁用,1:启用)',
+  `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  PRIMARY KEY (`id`) USING BTREE,
+  INDEX `index_system_menu_node`(`node`) USING BTREE,
+  INDEX `index_system_menu_status`(`status`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 51 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '系统-菜单' ROW_FORMAT = Compact;
+
+-- ----------------------------
+-- Records of system_menu
+-- ----------------------------
+INSERT INTO `system_menu` VALUES (1, 0, '后台首页', '', '', 'admin/index/main', '', '_self', 100, 1, '2018-09-05 17:59:38');
+INSERT INTO `system_menu` VALUES (2, 0, '系统管理', '', '', '#', '', '_self', 300, 1, '2018-09-05 18:04:52');
+INSERT INTO `system_menu` VALUES (3, 12, '系统菜单', '', 'layui-icon layui-icon-layouts', 'admin/menu/index', '', '_self', 3, 1, '2018-09-05 18:05:26');
+INSERT INTO `system_menu` VALUES (4, 2, '系统配置', '', '', '#', '', '_self', 10, 1, '2018-09-05 18:07:17');
+INSERT INTO `system_menu` VALUES (5, 12, '用户管理', '', 'layui-icon layui-icon-username', 'admin/user/index', '', '_self', 4, 1, '2018-09-06 11:10:42');
+INSERT INTO `system_menu` VALUES (6, 12, '节点管理', '', 'layui-icon layui-icon-template', 'admin/node/index', '', '_self', 1, 1, '2018-09-06 14:16:13');
+INSERT INTO `system_menu` VALUES (7, 12, '权限管理', '', 'layui-icon layui-icon-vercode', 'admin/auth/index', '', '_self', 2, 1, '2018-09-06 15:17:14');
+INSERT INTO `system_menu` VALUES (10, 4, '文件存储', '', 'layui-icon layui-icon-template-1', 'admin/config/file', '', '_self', 2, 1, '2018-09-06 16:43:19');
+INSERT INTO `system_menu` VALUES (11, 4, '系统参数', '', 'layui-icon layui-icon-set', 'admin/config/info', '', '_self', 1, 1, '2018-09-06 16:43:47');
+INSERT INTO `system_menu` VALUES (12, 2, '权限管理', '', '', '#', '', '_self', 20, 1, '2018-09-06 18:01:31');
+INSERT INTO `system_menu` VALUES (13, 0, '商城管理', '', '', '#', '', '_self', 200, 1, '2018-10-12 13:56:29');
+INSERT INTO `system_menu` VALUES (14, 48, '商品管理', '', 'layui-icon layui-icon-component', 'store/goods/index', '', '_self', 30, 1, '2018-10-12 13:56:48');
+INSERT INTO `system_menu` VALUES (16, 0, '微信管理', '', '', '#', '', '_self', 210, 1, '2018-10-31 15:15:27');
+INSERT INTO `system_menu` VALUES (17, 16, '微信管理', '', '', '#', '', '_self', 10, 1, '2018-10-31 15:16:46');
+INSERT INTO `system_menu` VALUES (18, 17, '微信配置', '', 'layui-icon layui-icon-set', 'wechat/config/options', '', '_self', 1, 1, '2018-10-31 15:17:11');
+INSERT INTO `system_menu` VALUES (19, 17, '支付配置', '', 'layui-icon layui-icon-rmb', 'wechat/config/payment', '', '_self', 2, 1, '2018-10-31 18:28:09');
+INSERT INTO `system_menu` VALUES (20, 16, '微信定制', '', '', '#', '', '_self', 20, 1, '2018-11-13 11:46:27');
+INSERT INTO `system_menu` VALUES (21, 20, '图文管理', '', 'layui-icon layui-icon-template', 'wechat/news/index', '', '_self', 1, 1, '2018-11-13 11:46:55');
+INSERT INTO `system_menu` VALUES (22, 20, '粉丝管理', '', 'layui-icon layui-icon-user', 'wechat/fans/index', '', '_self', 2, 1, '2018-11-15 09:51:13');
+INSERT INTO `system_menu` VALUES (23, 20, '回复规则', '', 'layui-icon layui-icon-engine', 'wechat/keys/index', '', '_self', 3, 1, '2018-11-22 11:29:08');
+INSERT INTO `system_menu` VALUES (24, 20, '关注回复', '', 'layui-icon layui-icon-senior', 'wechat/keys/subscribe', '', '_self', 4, 1, '2018-11-27 11:45:28');
+INSERT INTO `system_menu` VALUES (25, 20, '默认回复', '', 'layui-icon layui-icon-survey', 'wechat/keys/defaults', '', '_self', 5, 1, '2018-11-27 11:45:58');
+INSERT INTO `system_menu` VALUES (26, 20, '微信菜单', '', 'layui-icon layui-icon-cellphone', 'wechat/menu/index', '', '_self', 6, 1, '2018-11-27 17:56:56');
+INSERT INTO `system_menu` VALUES (27, 4, '任务管理', '', 'layui-icon layui-icon-log', 'admin/queue/index', '', '_self', 3, 1, '2018-11-29 11:13:34');
+INSERT INTO `system_menu` VALUES (35, 4, '消息管理', '', 'layui-icon layui-icon-notice', 'admin/message/index', '', '_self', 4, 1, '2018-12-24 14:03:52');
+INSERT INTO `system_menu` VALUES (37, 0, '开放平台', '', '', '#', '', '_self', 220, 1, '2018-12-28 13:29:25');
+INSERT INTO `system_menu` VALUES (38, 40, '开放平台配置', '', 'layui-icon layui-icon-set', 'service/config/index', '', '_self', 0, 1, '2018-12-28 13:29:44');
+INSERT INTO `system_menu` VALUES (39, 40, '公众授权管理', '', 'layui-icon layui-icon-template-1', 'service/index/index', '', '_self', 0, 1, '2018-12-28 13:30:07');
+INSERT INTO `system_menu` VALUES (40, 37, '开放平台管理', '', '', '#', '', '_self', 0, 1, '2018-12-28 16:05:46');
+INSERT INTO `system_menu` VALUES (42, 48, '会员管理', '', 'layui-icon layui-icon-username', 'store/member/index', '', '_self', 50, 1, '2019-01-22 14:24:23');
+INSERT INTO `system_menu` VALUES (43, 48, '订单管理', '', 'layui-icon layui-icon-template-1', 'store/order/index', '', '_self', 40, 1, '2019-01-22 14:46:22');
+INSERT INTO `system_menu` VALUES (44, 48, '商品分类', '', 'layui-icon layui-icon-app', 'store/goods_cate/index', '', '_self', 20, 1, '2019-01-23 10:41:06');
+INSERT INTO `system_menu` VALUES (45, 47, '商城配置', '', 'layui-icon layui-icon-set', 'store/config/index', '', '_self', 10, 1, '2019-01-24 16:47:33');
+INSERT INTO `system_menu` VALUES (46, 47, '短信记录', '', 'layui-icon layui-icon-tabs', 'store/message/index', '', '_self', 30, 1, '2019-01-24 18:09:58');
+INSERT INTO `system_menu` VALUES (47, 13, '商城配置', '', '', '#', '', '_self', 10, 1, '2019-01-25 16:47:49');
+INSERT INTO `system_menu` VALUES (48, 13, '数据管理', '', '', '#', '', '_self', 20, 1, '2019-01-25 16:48:35');
+INSERT INTO `system_menu` VALUES (49, 4, '系统日志', '', 'layui-icon layui-icon-form', 'admin/log/index', '', '_self', 5, 1, '2019-02-18 12:56:56');
+INSERT INTO `system_menu` VALUES (50, 47, '快递管理', '', 'layui-icon layui-icon-release', 'store/express/index', '', '_self', 40, 1, '2019-04-01 17:10:59');
+
+-- ----------------------------
+-- Table structure for system_message
+-- ----------------------------
+DROP TABLE IF EXISTS `system_message`;
+CREATE TABLE `system_message`  (
+  `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
+  `code` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '消息编号',
+  `title` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '消息名称',
+  `url` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '跳转地址',
+  `desc` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '消息描述',
+  `node` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '消息授权',
+  `read_state` tinyint(1) UNSIGNED NULL DEFAULT 0 COMMENT '读取状态',
+  `read_uid` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '读取用户',
+  `read_at` datetime NULL DEFAULT NULL COMMENT '读取时间',
+  `status` tinyint(1) UNSIGNED NULL DEFAULT 1 COMMENT '消息状态',
+  `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  PRIMARY KEY (`id`) USING BTREE,
+  INDEX `index_system_message_code`(`code`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '系统-消息' ROW_FORMAT = Compact;
+
+-- ----------------------------
+-- Table structure for system_node
+-- ----------------------------
+DROP TABLE IF EXISTS `system_node`;
+CREATE TABLE `system_node`  (
+  `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
+  `node` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '节点代码',
+  `title` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '节点标题',
+  `is_menu` tinyint(1) UNSIGNED NULL DEFAULT 0 COMMENT '是否可设置为菜单',
+  `is_auth` tinyint(1) UNSIGNED NULL DEFAULT 1 COMMENT '是否启动RBAC权限控制',
+  `is_login` tinyint(1) UNSIGNED NULL DEFAULT 1 COMMENT '是否启动登录控制',
+  `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  PRIMARY KEY (`id`) USING BTREE,
+  INDEX `index_system_node_node`(`node`) USING BTREE,
+  INDEX `index_system_node_is_menu`(`is_menu`) USING BTREE,
+  INDEX `index_system_node_is_auth`(`is_auth`) USING BTREE,
+  INDEX `index_system_node_is_login`(`is_login`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 187 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '系统-节点' ROW_FORMAT = Compact;
+
+-- ----------------------------
+-- Records of system_node
+-- ----------------------------
+INSERT INTO `system_node` VALUES (1, 'admin', '系统管理', 0, 1, 1, '2018-09-06 14:20:42');
+INSERT INTO `system_node` VALUES (2, 'admin/menu', '菜单管理', 0, 1, 1, '2018-09-06 14:23:01');
+INSERT INTO `system_node` VALUES (3, 'admin/menu/index', '菜单列表', 1, 1, 1, '2018-09-06 14:23:01');
+INSERT INTO `system_node` VALUES (4, 'admin/menu/edit', '编辑菜单', 0, 1, 1, '2018-09-06 14:23:01');
+INSERT INTO `system_node` VALUES (5, 'admin/menu/add', '添加菜单', 0, 1, 1, '2018-09-06 14:23:01');
+INSERT INTO `system_node` VALUES (6, 'admin/menu/resume', '启用菜单', 0, 1, 1, '2018-09-06 14:23:01');
+INSERT INTO `system_node` VALUES (7, 'admin/menu/forbid', '禁用菜单', 0, 1, 1, '2018-09-06 14:23:02');
+INSERT INTO `system_node` VALUES (8, 'admin/menu/del', '删除菜单', 0, 1, 1, '2018-09-06 14:23:02');
+INSERT INTO `system_node` VALUES (9, 'admin/node/index', '节点列表', 1, 1, 1, '2018-09-06 14:24:20');
+INSERT INTO `system_node` VALUES (10, 'admin/node/clear', '清理节点', 0, 1, 1, '2018-09-06 14:24:20');
+INSERT INTO `system_node` VALUES (11, 'admin/node/save', '更新节点', 0, 1, 1, '2018-09-06 14:24:20');
+INSERT INTO `system_node` VALUES (12, 'admin/user/index', '用户列表', 1, 1, 1, '2018-09-06 14:24:21');
+INSERT INTO `system_node` VALUES (13, 'admin/user/auth', '用户授权', 0, 1, 1, '2018-09-06 14:24:21');
+INSERT INTO `system_node` VALUES (14, 'admin/user/add', '添加用户', 0, 1, 1, '2018-09-06 14:24:21');
+INSERT INTO `system_node` VALUES (15, 'admin/user/edit', '编辑用户', 0, 1, 1, '2018-09-06 14:24:21');
+INSERT INTO `system_node` VALUES (16, 'admin/user/pass', '修改密码', 0, 1, 1, '2018-09-06 14:24:22');
+INSERT INTO `system_node` VALUES (17, 'admin/user/del', '删除用户', 0, 1, 1, '2018-09-06 14:24:22');
+INSERT INTO `system_node` VALUES (18, 'admin/user/forbid', '禁用用户', 0, 1, 1, '2018-09-06 14:24:22');
+INSERT INTO `system_node` VALUES (19, 'admin/user/resume', '启用用户', 0, 1, 1, '2018-09-06 14:24:22');
+INSERT INTO `system_node` VALUES (20, 'admin/node', '节点管理', 0, 1, 1, '2018-09-06 14:35:36');
+INSERT INTO `system_node` VALUES (21, 'admin/user', '用户管理', 0, 1, 1, '2018-09-06 14:36:09');
+INSERT INTO `system_node` VALUES (22, 'admin/auth', '权限管理', 0, 1, 1, '2018-09-06 15:16:10');
+INSERT INTO `system_node` VALUES (23, 'admin/auth/index', '权限列表', 1, 1, 1, '2018-09-06 15:16:10');
+INSERT INTO `system_node` VALUES (24, 'admin/auth/apply', '节点授权', 0, 1, 1, '2018-09-06 15:16:10');
+INSERT INTO `system_node` VALUES (25, 'admin/auth/add', '添加授权', 0, 1, 1, '2018-09-06 15:16:10');
+INSERT INTO `system_node` VALUES (26, 'admin/auth/edit', '编辑权限', 0, 1, 1, '2018-09-06 15:16:10');
+INSERT INTO `system_node` VALUES (27, 'admin/auth/forbid', '禁用权限', 0, 1, 1, '2018-09-06 15:16:11');
+INSERT INTO `system_node` VALUES (28, 'admin/auth/resume', '启用权限', 0, 1, 1, '2018-09-06 15:16:11');
+INSERT INTO `system_node` VALUES (29, 'admin/auth/del', '删除权限', 0, 1, 1, '2018-09-06 15:16:11');
+INSERT INTO `system_node` VALUES (30, 'admin/config', '参数配置', 0, 1, 1, '2018-09-06 16:41:18');
+INSERT INTO `system_node` VALUES (32, 'admin/config/file', '文件存储', 1, 1, 1, '2018-09-06 16:41:19');
+INSERT INTO `system_node` VALUES (34, 'admin/config/info', '系统信息', 1, 1, 1, '2018-09-06 16:42:10');
+INSERT INTO `system_node` VALUES (36, 'store/goods/index', '商品列表', 1, 1, 1, '2018-10-12 13:54:45');
+INSERT INTO `system_node` VALUES (37, 'store/goods/add', '添加商品', 0, 1, 1, '2018-10-12 13:54:45');
+INSERT INTO `system_node` VALUES (38, 'store/goods/edit', '编辑商品', 0, 1, 1, '2018-10-12 13:54:46');
+INSERT INTO `system_node` VALUES (39, 'store', '商城管理', 0, 1, 1, '2018-10-12 13:54:53');
+INSERT INTO `system_node` VALUES (40, 'store/goods', '商品管理', 0, 1, 1, '2018-10-12 13:55:20');
+INSERT INTO `system_node` VALUES (41, 'store/goods/forbid', '禁用商品', 0, 1, 1, '2018-10-12 16:49:02');
+INSERT INTO `system_node` VALUES (42, 'store/goods/resume', '启用商品', 0, 1, 1, '2018-10-16 18:31:42');
+INSERT INTO `system_node` VALUES (43, 'store/goods/del', '删除商品', 0, 1, 1, '2018-10-16 18:31:50');
+INSERT INTO `system_node` VALUES (44, 'store/goods/stock', '商品入库', 0, 1, 1, '2018-10-22 17:58:37');
+INSERT INTO `system_node` VALUES (45, 'wechat', '微信模块', 0, 1, 1, '2018-10-31 15:13:55');
+INSERT INTO `system_node` VALUES (46, 'wechat/config', '微信配置', 0, 1, 1, '2018-10-31 15:14:00');
+INSERT INTO `system_node` VALUES (51, 'wechat/config/payment', '微信支付', 1, 1, 1, '2018-11-01 11:19:37');
+INSERT INTO `system_node` VALUES (53, 'wechat/config/options', '授权配置', 1, 1, 1, '2018-11-01 11:27:55');
+INSERT INTO `system_node` VALUES (54, 'wechat/news/index', '图文列表', 1, 1, 1, '2018-11-13 11:45:46');
+INSERT INTO `system_node` VALUES (56, 'wechat/news/select', '选择图文', 0, 1, 1, '2018-11-13 11:45:46');
+INSERT INTO `system_node` VALUES (57, 'wechat/news/add', '添加图文', 0, 1, 1, '2018-11-13 11:45:47');
+INSERT INTO `system_node` VALUES (58, 'wechat/news/edit', '编辑图文', 0, 1, 1, '2018-11-13 11:45:47');
+INSERT INTO `system_node` VALUES (59, 'wechat/news/del', '删除图文', 0, 1, 1, '2018-11-13 11:45:47');
+INSERT INTO `system_node` VALUES (61, 'wechat/fans/index', '粉丝列表', 1, 1, 1, '2018-11-15 09:50:28');
+INSERT INTO `system_node` VALUES (62, 'wechat/fans', '微信粉丝', 0, 1, 1, '2018-11-15 09:50:34');
+INSERT INTO `system_node` VALUES (63, 'wechat/news', '微信图文', 0, 1, 1, '2018-11-15 11:31:16');
+INSERT INTO `system_node` VALUES (64, 'wechat/fans/sync', '同步粉丝', 0, 1, 1, '2018-11-22 11:27:26');
+INSERT INTO `system_node` VALUES (65, 'wechat/keys/index', '回复规则列表', 1, 1, 1, '2018-11-22 11:27:27');
+INSERT INTO `system_node` VALUES (66, 'wechat/keys/add', '添加回复规则', 0, 1, 1, '2018-11-22 11:27:27');
+INSERT INTO `system_node` VALUES (67, 'wechat/keys/edit', '编辑回复规则', 0, 1, 1, '2018-11-22 11:27:27');
+INSERT INTO `system_node` VALUES (68, 'wechat/keys/del', '删除回复规则', 0, 1, 1, '2018-11-22 11:27:27');
+INSERT INTO `system_node` VALUES (69, 'wechat/keys/forbid', '禁用回复规则', 0, 1, 1, '2018-11-22 11:27:27');
+INSERT INTO `system_node` VALUES (70, 'wechat/keys/resume', '启用回复规则', 0, 1, 1, '2018-11-22 11:27:28');
+INSERT INTO `system_node` VALUES (71, 'wechat/keys', '回复规则管理', 0, 1, 1, '2018-11-23 10:26:06');
+INSERT INTO `system_node` VALUES (72, 'wechat/keys/subscribe', '关注回复规则', 1, 1, 1, '2018-11-27 11:43:27');
+INSERT INTO `system_node` VALUES (73, 'wechat/keys/defaults', '默认回复规则', 1, 1, 1, '2018-11-27 11:43:27');
+INSERT INTO `system_node` VALUES (74, 'wechat/fans/setblack', '拉黑粉丝', 0, 1, 1, '2018-11-27 16:23:21');
+INSERT INTO `system_node` VALUES (75, 'wechat/fans/delblack', '取消拉黑', 0, 1, 1, '2018-11-27 16:23:21');
+INSERT INTO `system_node` VALUES (76, 'wechat/menu/index', '微信菜单显示', 1, 1, 1, '2018-11-27 17:56:28');
+INSERT INTO `system_node` VALUES (77, 'wechat/menu/edit', '更新微信菜单', 0, 1, 1, '2018-11-27 17:56:28');
+INSERT INTO `system_node` VALUES (78, 'wechat/menu/cancel', '取消微信菜单', 0, 1, 1, '2018-11-27 17:56:29');
+INSERT INTO `system_node` VALUES (79, 'wechat/menu', '微信菜单管理', 0, 1, 1, '2018-11-28 16:03:03');
+INSERT INTO `system_node` VALUES (80, 'admin/queue/index', '任务列表', 1, 1, 1, '2018-11-29 11:12:54');
+INSERT INTO `system_node` VALUES (81, 'admin/queue', '任务管理', 0, 1, 1, '2018-11-29 11:13:05');
+INSERT INTO `system_node` VALUES (82, 'admin/queue/redo', '重启任务', 0, 1, 1, '2018-11-29 15:17:43');
+INSERT INTO `system_node` VALUES (83, 'admin/queue/del', '删除任务', 0, 1, 1, '2018-12-04 15:16:59');
+INSERT INTO `system_node` VALUES (114, 'admin/message/index', '消息管理', 1, 1, 1, '2018-12-24 14:03:09');
+INSERT INTO `system_node` VALUES (115, 'admin/message', '消息管理', 0, 1, 1, '2018-12-24 14:03:14');
+INSERT INTO `system_node` VALUES (116, 'admin/message/state', '消息状态', 0, 1, 1, '2018-12-24 18:41:37');
+INSERT INTO `system_node` VALUES (117, 'admin/message/del', '删除消息', 0, 1, 1, '2018-12-24 18:41:37');
+INSERT INTO `system_node` VALUES (118, 'service', '开放平台', 0, 1, 1, '2018-12-28 13:27:38');
+INSERT INTO `system_node` VALUES (119, 'service/config', '开放平台', 0, 1, 1, '2018-12-28 13:27:41');
+INSERT INTO `system_node` VALUES (120, 'service/config/index', '开放平台配置', 1, 1, 1, '2018-12-28 13:27:42');
+INSERT INTO `system_node` VALUES (121, 'service/index/index', '公众号授权列表', 1, 1, 1, '2018-12-28 13:27:42');
+INSERT INTO `system_node` VALUES (122, 'service/index/sync', '同步公众号授权', 0, 1, 1, '2018-12-28 13:27:42');
+INSERT INTO `system_node` VALUES (123, 'service/index/syncall', '公众号所有授权', 0, 1, 1, '2018-12-28 13:27:43');
+INSERT INTO `system_node` VALUES (124, 'service/index/del', '删除公众号授权', 0, 1, 1, '2018-12-28 13:27:43');
+INSERT INTO `system_node` VALUES (125, 'service/index/forbid', '禁用公众号授权', 0, 1, 1, '2018-12-28 13:27:43');
+INSERT INTO `system_node` VALUES (126, 'service/index/resume', '启用公众号授权', 0, 1, 1, '2018-12-28 13:27:43');
+INSERT INTO `system_node` VALUES (127, 'service/index', '公众号授权管理', 0, 1, 1, '2018-12-28 13:27:59');
+INSERT INTO `system_node` VALUES (147, 'admin/message/clear', '清理消息', 0, 1, 1, '2019-01-05 13:23:49');
+INSERT INTO `system_node` VALUES (148, 'admin/message/onoff', '消息开关', 0, 1, 1, '2019-01-05 13:23:49');
+INSERT INTO `system_node` VALUES (149, 'store/page/index', '页面管理', 1, 1, 1, '2019-01-18 09:58:00');
+INSERT INTO `system_node` VALUES (150, 'store/page/add', '添加页面', 0, 1, 1, '2019-01-18 09:58:00');
+INSERT INTO `system_node` VALUES (151, 'store/page/edit', '编辑页面', 0, 1, 1, '2019-01-18 09:58:00');
+INSERT INTO `system_node` VALUES (152, 'store/page/forbid', '禁用页面', 0, 1, 1, '2019-01-18 09:58:00');
+INSERT INTO `system_node` VALUES (153, 'store/page/resume', '启用页面', 0, 1, 1, '2019-01-18 09:58:01');
+INSERT INTO `system_node` VALUES (154, 'store/page/del', '删除页面', 0, 1, 1, '2019-01-18 09:58:01');
+INSERT INTO `system_node` VALUES (155, 'store/page', '页面管理', 0, 1, 1, '2019-01-18 09:58:07');
+INSERT INTO `system_node` VALUES (156, 'store/member/index', '商城会员管理', 1, 1, 1, '2019-01-22 14:23:55');
+INSERT INTO `system_node` VALUES (157, 'store/member', '商城会员管理', 0, 1, 1, '2019-01-22 14:24:02');
+INSERT INTO `system_node` VALUES (158, 'store/order/index', '商城订单管理', 1, 1, 1, '2019-01-22 14:45:52');
+INSERT INTO `system_node` VALUES (159, 'store/order', '商城订单管理', 0, 1, 1, '2019-01-22 14:45:59');
+INSERT INTO `system_node` VALUES (160, 'store/goods_cate/index', '商品分类管理', 1, 1, 1, '2019-01-23 10:39:54');
+INSERT INTO `system_node` VALUES (161, 'store/goods_cate/add', '添加商品分类', 0, 1, 1, '2019-01-23 10:39:54');
+INSERT INTO `system_node` VALUES (162, 'store/goods_cate/edit', '编辑商品分类', 0, 1, 1, '2019-01-23 10:39:54');
+INSERT INTO `system_node` VALUES (163, 'store/goods_cate/forbid', '禁用商品分类', 0, 1, 1, '2019-01-23 10:39:55');
+INSERT INTO `system_node` VALUES (164, 'store/goods_cate/resume', '启用商品分类', 0, 1, 1, '2019-01-23 10:39:55');
+INSERT INTO `system_node` VALUES (165, 'store/goods_cate/del', '删除商品分类', 0, 1, 1, '2019-01-23 10:39:55');
+INSERT INTO `system_node` VALUES (166, 'store/goods_cate', '商品分类', 0, 1, 1, '2019-01-23 10:40:01');
+INSERT INTO `system_node` VALUES (167, 'store/config/index', '商城配置', 1, 1, 1, '2019-01-24 16:47:01');
+INSERT INTO `system_node` VALUES (168, 'store/config', '商城配置', 0, 1, 1, '2019-01-24 16:47:09');
+INSERT INTO `system_node` VALUES (169, 'store/message/index', '短信消息', 1, 1, 1, '2019-01-24 18:09:05');
+INSERT INTO `system_node` VALUES (170, 'store/message', '短信消息', 0, 1, 1, '2019-01-24 18:09:12');
+INSERT INTO `system_node` VALUES (171, 'admin/log/index', '日志管理列表', 1, 1, 1, '2019-02-18 12:56:07');
+INSERT INTO `system_node` VALUES (172, 'admin/log/del', '删除日志管理', 0, 1, 1, '2019-02-18 12:56:07');
+INSERT INTO `system_node` VALUES (173, 'admin/log', '系统日志管理', 0, 1, 1, '2019-02-18 12:56:15');
+INSERT INTO `system_node` VALUES (176, 'wechat/fans/del', '删除粉丝', 0, 1, 1, '2019-03-18 10:58:10');
+INSERT INTO `system_node` VALUES (177, 'service/index/clearquota', '清空调用次数', 0, 1, 1, '2019-03-30 16:39:17');
+INSERT INTO `system_node` VALUES (178, 'store/express/index', '快递公司管理', 1, 1, 1, '2019-04-01 17:09:27');
+INSERT INTO `system_node` VALUES (179, 'store/express/add', '添加快递公司', 0, 1, 1, '2019-04-01 17:09:27');
+INSERT INTO `system_node` VALUES (180, 'store/express/edit', '编辑快递公司', 0, 1, 1, '2019-04-01 17:09:27');
+INSERT INTO `system_node` VALUES (181, 'store/express/forbid', '禁用快递公司', 0, 1, 1, '2019-04-01 17:09:27');
+INSERT INTO `system_node` VALUES (182, 'store/express/resume', '启用快递公司', 0, 1, 1, '2019-04-01 17:09:28');
+INSERT INTO `system_node` VALUES (183, 'store/express/del', '删除快递公司', 0, 1, 1, '2019-04-01 17:09:28');
+INSERT INTO `system_node` VALUES (184, 'store/order/express', '商城订单发货', 0, 1, 1, '2019-04-01 17:09:30');
+INSERT INTO `system_node` VALUES (185, 'store/order/expressquery', '商城快递查询', 0, 1, 1, '2019-04-01 17:09:30');
+INSERT INTO `system_node` VALUES (186, 'store/express', '快递公司管理', 0, 1, 1, '2019-04-01 17:09:55');
+
+-- ----------------------------
+-- Table structure for system_user
+-- ----------------------------
+DROP TABLE IF EXISTS `system_user`;
+CREATE TABLE `system_user`  (
+  `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
+  `username` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '用户账号',
+  `password` char(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '用户密码',
+  `qq` varchar(16) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '联系QQ',
+  `mail` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '联系邮箱',
+  `phone` varchar(16) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '联系手机号',
+  `login_at` datetime NULL DEFAULT NULL COMMENT '登录时间',
+  `login_ip` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '登录IP',
+  `login_num` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '登录次数',
+  `authorize` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '权限授权',
+  `desc` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '备注说明',
+  `status` tinyint(1) UNSIGNED NULL DEFAULT 1 COMMENT '状态(0:禁用,1:启用)',
+  `is_deleted` tinyint(1) UNSIGNED NULL DEFAULT 0 COMMENT '删除(1:删除,0:未删)',
+  `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  PRIMARY KEY (`id`) USING BTREE,
+  UNIQUE INDEX `index_system_user_username`(`username`) USING BTREE,
+  INDEX `index_system_user_status`(`status`) USING BTREE,
+  INDEX `index_system_user_deleted`(`is_deleted`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 10001 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '系统-用户' ROW_FORMAT = Compact;
+
+-- ----------------------------
+-- Records of system_user
+-- ----------------------------
+INSERT INTO `system_user` VALUES (10000, 'admin', '21232f297a57a5a743894a0e4a801fc3', '22222222', '', '', '2019-04-01 16:55:15', '127.0.0.1', 500, '', '', 1, 0, '2015-11-13 15:14:22');
+
+-- ----------------------------
+-- Table structure for wechat_fans
+-- ----------------------------
+DROP TABLE IF EXISTS `wechat_fans`;
+CREATE TABLE `wechat_fans`  (
+  `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
+  `appid` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '公众号APPID',
+  `unionid` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '粉丝unionid',
+  `openid` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '粉丝openid',
+  `tagid_list` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '粉丝标签id',
+  `is_black` tinyint(1) UNSIGNED NULL DEFAULT 0 COMMENT '是否为黑名单状态',
+  `subscribe` tinyint(1) UNSIGNED NULL DEFAULT 0 COMMENT '关注状态(0未关注,1已关注)',
+  `nickname` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '用户昵称',
+  `sex` tinyint(1) UNSIGNED NULL DEFAULT NULL COMMENT '用户性别(1男性,2女性,0未知)',
+  `country` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '用户所在国家',
+  `province` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '用户所在省份',
+  `city` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '用户所在城市',
+  `language` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '用户的语言(zh_CN)',
+  `headimgurl` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '用户头像',
+  `subscribe_time` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '关注时间',
+  `subscribe_at` datetime NULL DEFAULT NULL COMMENT '关注时间',
+  `remark` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '备注',
+  `subscribe_scene` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '扫码关注场景',
+  `qr_scene` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '二维码场景值',
+  `qr_scene_str` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '二维码场景内容',
+  `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  PRIMARY KEY (`id`) USING BTREE,
+  INDEX `index_wechat_fans_openid`(`openid`) USING BTREE,
+  INDEX `index_wechat_fans_unionid`(`unionid`) USING BTREE,
+  INDEX `index_wechat_fans_is_back`(`is_black`) USING BTREE,
+  INDEX `index_wechat_fans_subscribe`(`subscribe`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '微信-粉丝' ROW_FORMAT = Compact;
+
+-- ----------------------------
+-- Table structure for wechat_fans_tags
+-- ----------------------------
+DROP TABLE IF EXISTS `wechat_fans_tags`;
+CREATE TABLE `wechat_fans_tags`  (
+  `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '标签ID',
+  `appid` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '公众号APPID',
+  `name` varchar(35) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '标签名称',
+  `count` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '总数',
+  `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建日期',
+  INDEX `index_wechat_fans_tags_id`(`id`) USING BTREE,
+  INDEX `index_wechat_fans_tags_appid`(`appid`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '微信-粉丝-标签' ROW_FORMAT = Compact;
+
+-- ----------------------------
+-- Table structure for wechat_keys
+-- ----------------------------
+DROP TABLE IF EXISTS `wechat_keys`;
+CREATE TABLE `wechat_keys`  (
+  `id` bigint(20) NOT NULL AUTO_INCREMENT,
+  `appid` char(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '公众号APPID',
+  `type` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '类型,text 文件消息,image 图片消息,news 图文消息',
+  `keys` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '关键字',
+  `content` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '文本内容',
+  `image_url` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '图片链接',
+  `voice_url` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '语音链接',
+  `music_title` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '音乐标题',
+  `music_url` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '音乐链接',
+  `music_image` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '音乐缩略图链接',
+  `music_desc` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '音乐描述',
+  `video_title` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '视频标题',
+  `video_url` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '视频URL',
+  `video_desc` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '视频描述',
+  `news_id` bigint(20) UNSIGNED NULL DEFAULT NULL COMMENT '图文ID',
+  `sort` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '排序字段',
+  `status` tinyint(1) UNSIGNED NULL DEFAULT 1 COMMENT '0 禁用,1 启用',
+  `create_by` bigint(20) UNSIGNED NULL DEFAULT NULL COMMENT '创建人',
+  `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间',
+  PRIMARY KEY (`id`) USING BTREE,
+  INDEX `index_wechat_keys_appid`(`appid`) USING BTREE,
+  INDEX `index_wechat_keys_type`(`type`) USING BTREE,
+  INDEX `index_wechat_keys_keys`(`keys`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '微信-关键字' ROW_FORMAT = Compact;
+
+-- ----------------------------
+-- Table structure for wechat_media
+-- ----------------------------
+DROP TABLE IF EXISTS `wechat_media`;
+CREATE TABLE `wechat_media`  (
+  `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
+  `appid` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '公众号ID',
+  `md5` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '文件md5',
+  `type` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '媒体类型',
+  `media_id` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '永久素材MediaID',
+  `local_url` varchar(300) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '本地文件链接',
+  `media_url` varchar(300) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '远程图片链接',
+  `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  PRIMARY KEY (`id`) USING BTREE,
+  INDEX `index_wechat_media_appid`(`appid`) USING BTREE,
+  INDEX `index_wechat_media_md5`(`md5`) USING BTREE,
+  INDEX `index_wechat_media_type`(`type`) USING BTREE,
+  INDEX `index_wechat_media_media_id`(`media_id`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '微信-素材' ROW_FORMAT = Compact;
+
+-- ----------------------------
+-- Table structure for wechat_news
+-- ----------------------------
+DROP TABLE IF EXISTS `wechat_news`;
+CREATE TABLE `wechat_news`  (
+  `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
+  `media_id` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '永久素材MediaID',
+  `local_url` varchar(300) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '永久素材显示URL',
+  `article_id` varchar(60) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '关联图文ID,用,号做分割',
+  `is_deleted` tinyint(1) UNSIGNED NULL DEFAULT 0 COMMENT '是否删除',
+  `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  `create_by` bigint(20) NULL DEFAULT NULL COMMENT '创建人',
+  PRIMARY KEY (`id`) USING BTREE,
+  INDEX `index_wechat_news_artcle_id`(`article_id`) USING BTREE,
+  INDEX `index_wechat_news_media_id`(`media_id`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '微信-图文' ROW_FORMAT = Compact;
+
+-- ----------------------------
+-- Table structure for wechat_news_article
+-- ----------------------------
+DROP TABLE IF EXISTS `wechat_news_article`;
+CREATE TABLE `wechat_news_article`  (
+  `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
+  `title` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '素材标题',
+  `local_url` varchar(300) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '永久素材显示URL',
+  `show_cover_pic` tinyint(4) UNSIGNED NULL DEFAULT 0 COMMENT '显示封面(0 不显示, 1 显示)',
+  `author` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '作者',
+  `digest` varchar(300) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '摘要内容',
+  `content` longtext CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '图文内容',
+  `content_source_url` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '原文地址',
+  `read_num` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '阅读量',
+  `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '微信-图文-文章' ROW_FORMAT = Compact;
+
+-- ----------------------------
+-- Table structure for wechat_service_config
+-- ----------------------------
+DROP TABLE IF EXISTS `wechat_service_config`;
+CREATE TABLE `wechat_service_config`  (
+  `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
+  `authorizer_appid` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '公众号APPID',
+  `authorizer_access_token` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '公众号授权Token',
+  `authorizer_refresh_token` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '公众号刷新Token',
+  `func_info` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '公众号集权',
+  `nick_name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '公众号昵称',
+  `head_img` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '公众号头像',
+  `expires_in` bigint(20) NULL DEFAULT NULL COMMENT 'Token有效时间',
+  `service_type` tinyint(2) NULL DEFAULT NULL COMMENT '微信类型(0代表订阅号,2代表服务号,3代表小程序)',
+  `service_type_info` tinyint(2) NULL DEFAULT NULL COMMENT '公众号实际类型',
+  `verify_type` tinyint(2) NULL DEFAULT NULL COMMENT '公众号认证类型(-1代表未认证, 0代表微信认证)',
+  `verify_type_info` tinyint(2) NULL DEFAULT NULL COMMENT '公众号实际认证类型',
+  `user_name` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '众众号原始账号',
+  `alias` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '公众号别名',
+  `qrcode_url` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '公众号二维码',
+  `business_info` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '',
+  `principal_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '公司名称',
+  `miniprograminfo` varchar(1024) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '小程序JSON',
+  `idc` tinyint(1) UNSIGNED NULL DEFAULT NULL,
+  `signature` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '小程序的描述',
+  `total` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '统计调用次数',
+  `appkey` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '应用接口KEY',
+  `appuri` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '应用接口URI',
+  `status` tinyint(1) UNSIGNED NULL DEFAULT 1 COMMENT '状态(1正常授权,0取消授权)',
+  `is_deleted` tinyint(1) UNSIGNED NULL DEFAULT 0 COMMENT '删除状态(0未删除,1已删除)',
+  `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  PRIMARY KEY (`id`) USING BTREE,
+  UNIQUE INDEX `index_wechat_service_config_authorizer_appid`(`authorizer_appid`) USING BTREE,
+  INDEX `index_wechat_service_config_status`(`status`) USING BTREE,
+  INDEX `index_wechat_service_config_is_deleted`(`is_deleted`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '微信-授权' ROW_FORMAT = Compact;
+
+SET FOREIGN_KEY_CHECKS = 1;

+ 0 - 1
application/.htaccess

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

+ 55 - 89
application/admin/controller/Auth.php

@@ -1,11 +1,11 @@
 <?php
 
 // +----------------------------------------------------------------------
-// | ThinkAdmin
+// | framework
 // +----------------------------------------------------------------------
-// | 版权所有 2014~2017 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
 // +----------------------------------------------------------------------
-// | 官方网站: http://think.ctolog.com
+// | 官方网站: http://framework.thinkadmin.top
 // +----------------------------------------------------------------------
 // | 开源协议 ( https://mit-license.org )
 // +----------------------------------------------------------------------
@@ -14,22 +14,16 @@
 
 namespace app\admin\controller;
 
-use controller\BasicAdmin;
-use service\DataService;
-use service\NodeService;
-use service\ToolsService;
+use library\Controller;
 use think\Db;
 
 /**
- * 系统权限管理控制器
+ * 权限管理
  * Class Auth
  * @package app\admin\controller
- * @author Anyon <zoujingli@qq.com>
- * @date 2017/02/15 18:13
  */
-class Auth extends BasicAdmin
+class Auth extends Controller
 {
-
     /**
      * 默认数据模型
      * @var string
@@ -38,81 +32,56 @@ class Auth extends BasicAdmin
 
     /**
      * 权限列表
-     * @return array|string
      * @throws \think\Exception
      * @throws \think\db\exception\DataNotFoundException
      * @throws \think\db\exception\ModelNotFoundException
      * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
      */
     public function index()
     {
         $this->title = '系统权限管理';
-        return parent::_list($this->table);
+        $this->_query($this->table)->dateBetween('create_at')->like('title,desc')->equal('status')->order('sort asc,id desc')->page();
     }
 
     /**
-     * 权限授权
-     * @return string
-     * @throws \think\db\exception\DataNotFoundException
-     * @throws \think\db\exception\ModelNotFoundException
-     * @throws \think\exception\DbException
-     * @throws \think\Exception
-     */
-    public function apply()
-    {
-        $this->title = '节点授权';
-        $auth_id = $this->request->get('id', '0');
-        $method = '_apply_' . strtolower($this->request->get('action', '0'));
-        if (method_exists($this, $method)) {
-            return $this->$method($auth_id);
-        }
-        return $this->_form($this->table, 'apply');
-    }
-
-    /**
-     * 读取授权节点
-     * @param string $auth
-     */
-    protected function _apply_getnode($auth)
-    {
-        $nodes = NodeService::get();
-        $checked = Db::name('SystemAuthNode')->where(['auth' => $auth])->column('node');
-        foreach ($nodes as &$node) {
-            $node['checked'] = in_array($node['node'], $checked);
-        }
-        $all = $this->_apply_filter(ToolsService::arr2tree($nodes, 'node', 'pnode', '_sub_'));
-        $this->success('获取节点成功!', '', $all);
-    }
-
-    /**
-     * 保存授权节点
-     * @param string $auth
+     * 权限授权节点
+     * @return mixed
      * @throws \think\Exception
      * @throws \think\exception\PDOException
      */
-    protected function _apply_save($auth)
+    public function apply()
     {
-        list($data, $post) = [[], $this->request->post()];
-        foreach (isset($post['nodes']) ? $post['nodes'] : [] as $node) {
-            $data[] = ['auth' => $auth, 'node' => $node];
+        $this->title = '权限授权配置';
+        $auth = $this->request->post('id', '0');
+        switch (strtolower($this->request->post('action'))) {
+            case 'get': // 获取权限配置
+                $nodes = \app\admin\service\Auth::get();
+                $checked = Db::name('SystemAuthNode')->where(['auth' => $auth])->column('node');
+                foreach ($nodes as &$node) $node['checked'] = in_array($node['node'], $checked);
+                $data = $this->_apply_filter(\library\tools\Data::arr2tree($nodes, 'node', 'pnode', '_sub_'));
+                return $this->success('获取权限配置成功!', $data);
+            case 'save': // 保存权限配置
+                list($post, $data) = [$this->request->post(), []];
+                foreach (isset($post['nodes']) ? $post['nodes'] : [] as $node) $data[] = ['auth' => $auth, 'node' => $node];
+                Db::name('SystemAuthNode')->where(['auth' => $auth])->delete();
+                Db::name('SystemAuthNode')->insertAll($data);
+                return $this->success('权限授权配置更新成功!');
+            default:
+                return $this->_form($this->table, 'apply');
         }
-        Db::name('SystemAuthNode')->where(['auth' => $auth])->delete();
-        Db::name('SystemAuthNode')->insertAll($data);
-        $this->success('节点授权更新成功!', '');
     }
 
     /**
      * 节点数据拼装
      * @param array $nodes
-     * @param int $level
+     * @param integer $level
      * @return array
      */
-    protected function _apply_filter($nodes, $level = 1)
+    private function _apply_filter($nodes, $level = 1)
     {
-        foreach ($nodes as $key => $node) {
-            if (!empty($node['_sub_']) && is_array($node['_sub_'])) {
-                $node[$key]['_sub_'] = $this->_apply_filter($node['_sub_'], $level + 1);
-            }
+        foreach ($nodes as $key => $node) if (!empty($node['_sub_']) && is_array($node['_sub_'])) {
+            $node[$key]['_sub_'] = $this->_apply_filter($node['_sub_'], $level + 1);
         }
         return $nodes;
     }
@@ -120,68 +89,65 @@ class Auth extends BasicAdmin
     /**
      * 权限添加
      * @return array|string
-     * @throws \think\db\exception\DataNotFoundException
-     * @throws \think\db\exception\ModelNotFoundException
-     * @throws \think\exception\DbException
-     * @throws \think\Exception
      */
     public function add()
     {
-        return $this->_form($this->table, 'form');
+        $this->applyCsrfToken();
+        $this->_form($this->table, 'form');
     }
 
     /**
      * 权限编辑
      * @return array|string
-     * @throws \think\db\exception\DataNotFoundException
-     * @throws \think\db\exception\ModelNotFoundException
-     * @throws \think\exception\DbException
-     * @throws \think\Exception
      */
     public function edit()
     {
-        return $this->_form($this->table, 'form');
+        $this->applyCsrfToken();
+        $this->_form($this->table, 'form');
     }
 
     /**
      * 权限禁用
-     * @throws \think\Exception
-     * @throws \think\exception\PDOException
      */
     public function forbid()
     {
-        if (DataService::update($this->table)) {
-            $this->success("权限禁用成功!", '');
-        }
-        $this->error("权限禁用失败,请稍候再试!");
+        $this->applyCsrfToken();
+        $this->_save($this->table, ['status' => '0']);
     }
 
     /**
      * 权限恢复
-     * @throws \think\Exception
-     * @throws \think\exception\PDOException
      */
     public function resume()
     {
-        if (DataService::update($this->table)) {
-            $this->success("权限启用成功!", '');
-        }
-        $this->error("权限启用失败,请稍候再试!");
+        $this->applyCsrfToken();
+        $this->_save($this->table, ['status' => '1']);
     }
 
     /**
      * 权限删除
+     */
+    public function del()
+    {
+        $this->applyCsrfToken();
+        $this->_delete($this->table);
+    }
+
+    /**
+     * 删除结果处理
+     * @param boolean $result
      * @throws \think\Exception
      * @throws \think\exception\PDOException
      */
-    public function del()
+    protected function _del_delete_result($result)
     {
-        if (DataService::update($this->table)) {
+        if ($result) {
             $where = ['auth' => $this->request->post('id')];
             Db::name('SystemAuthNode')->where($where)->delete();
             $this->success("权限删除成功!", '');
+        } else {
+            $this->error("权限删除失败,请稍候再试!");
         }
-        $this->error("权限删除失败,请稍候再试!");
     }
 
-}
+}

+ 69 - 35
application/admin/controller/Config.php

@@ -1,11 +1,11 @@
 <?php
 
 // +----------------------------------------------------------------------
-// | ThinkAdmin
+// | framework
 // +----------------------------------------------------------------------
-// | 版权所有 2014~2017 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
 // +----------------------------------------------------------------------
-// | 官方网站: http://think.ctolog.com
+// | 官方网站: http://framework.thinkadmin.top
 // +----------------------------------------------------------------------
 // | 开源协议 ( https://mit-license.org )
 // +----------------------------------------------------------------------
@@ -14,50 +14,34 @@
 
 namespace app\admin\controller;
 
-use controller\BasicAdmin;
-use service\LogService;
-use service\WechatService;
+use library\Controller;
 
 /**
- * 后台参数配置控制器
+ * 系统配置
  * Class Config
  * @package app\admin\controller
- * @author Anyon <zoujingli@qq.com>
- * @date 2017/02/15 18:05
  */
-class Config extends BasicAdmin
+class Config extends Controller
 {
-
     /**
-     * 当前默认数据模型
+     * 默认数据模型
      * @var string
      */
-    public $table = 'SystemConfig';
+    protected $table = 'SystemConfig';
 
     /**
-     * 当前页面标题
-     * @var string
-     */
-    public $title = '系统参数配置';
-
-    /**
-     * 显示系统常规配置
-     * @return string
+     * 系统参数配置
+     * @return mixed
      * @throws \think\Exception
      * @throws \think\exception\PDOException
      */
-    public function index()
+    public function info()
     {
-        if ($this->request->isGet()) {
-            return $this->fetch('', ['title' => $this->title]);
-        }
-        if ($this->request->isPost()) {
-            foreach ($this->request->post() as $key => $vo) {
-                sysconf($key, $vo);
-            }
-            LogService::write('系统管理', '系统参数配置成功');
-            $this->success('系统参数配置成功!', '');
-        }
+        $this->applyCsrfToken();
+        $this->title = '系统参数配置';
+        if ($this->request->isGet()) return $this->fetch();
+        foreach ($this->request->post() as $k => $v) sysconf($k, $v);
+        $this->success('系统参数配置保存成功!');
     }
 
     /**
@@ -68,8 +52,58 @@ class Config extends BasicAdmin
      */
     public function file()
     {
-        $this->title = '文件存储配置';
-        return $this->index();
+        $this->applyCsrfToken();
+        if ($this->request->isGet()) {
+            $this->fetch('file', [
+                'title' => '文件存储配置',
+                'point' => [
+                    'oss-cn-hangzhou.aliyuncs.com'    => '华东 1 杭州',
+                    'oss-cn-shanghai.aliyuncs.com'    => '华东 2 上海',
+                    'oss-cn-qingdao.aliyuncs.com'     => '华北 1 青岛',
+                    'oss-cn-beijing.aliyuncs.com'     => '华北 2 北京',
+                    'oss-cn-zhangjiakou.aliyuncs.com' => '华北 3 张家口',
+                    'oss-cn-huhehaote.aliyuncs.com'   => '华北 5 呼和浩特',
+                    'oss-cn-shenzhen.aliyuncs.com'    => '华南 1 深圳',
+                    'oss-cn-hongkong.aliyuncs.com'    => '香港 1',
+                    'oss-us-west-1.aliyuncs.com'      => '美国西部 1 硅谷',
+                    'oss-us-east-1.aliyuncs.com'      => '美国东部 1 弗吉尼亚',
+                    'oss-ap-southeast-1.aliyuncs.com' => '亚太东南 1 新加坡',
+                    'oss-ap-southeast-2.aliyuncs.com' => '亚太东南 2 悉尼',
+                    'oss-ap-southeast-3.aliyuncs.com' => '亚太东南 3 吉隆坡',
+                    'oss-ap-southeast-5.aliyuncs.com' => '亚太东南 5 雅加达',
+                    'oss-ap-northeast-1.aliyuncs.com' => '亚太东北 1 日本',
+                    'oss-ap-south-1.aliyuncs.com'     => '亚太南部 1 孟买',
+                    'oss-eu-central-1.aliyuncs.com'   => '欧洲中部 1 法兰克福',
+                    'oss-eu-west-1.aliyuncs.com'      => '英国 1 伦敦',
+                    'oss-me-east-1.aliyuncs.com'      => '中东东部 1 迪拜',
+                ],
+            ]);
+        } else {
+            $post = $this->request->post();
+            if (isset($post['storage_type']) && $post['storage_type'] === 'local') {
+                $exts = array_unique(explode(',', $post['storage_local_exts']));
+                if (in_array('php', $exts)) $this->error('禁止上传可执行文件到本地服务器!');
+                $post['storage_local_exts'] = join(',', $exts);
+            }
+            foreach ($post as $key => $value) sysconf($key, $value);
+            if (isset($post['storage_type']) && $post['storage_type'] === 'oss') {
+                try {
+                    $local = sysconf('storage_oss_domain');
+                    $bucket = $this->request->post('storage_oss_bucket');
+                    $domain = \library\File::instance('oss')->setBucket($bucket);
+                    if (empty($local) || stripos($local, '.aliyuncs.com') !== false) {
+                        sysconf('storage_oss_domain', $domain);
+                    }
+                    $this->success('阿里云OSS存储动态配置成功!');
+                } catch (\think\exception\HttpResponseException $exception) {
+                    throw $exception;
+                } catch (\Exception $e) {
+                    $this->error("阿里云OSS存储配置失效,{$e->getMessage()}");
+                }
+            } else {
+                $this->success('文件存储配置保存成功!');
+            }
+        }
     }
 
-}
+}

+ 103 - 79
application/admin/controller/Index.php

@@ -1,11 +1,11 @@
 <?php
 
 // +----------------------------------------------------------------------
-// | ThinkAdmin
+// | framework
 // +----------------------------------------------------------------------
-// | 版权所有 2014~2017 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
 // +----------------------------------------------------------------------
-// | 官方网站: http://think.ctolog.com
+// | 官方网站: http://framework.thinkadmin.top
 // +----------------------------------------------------------------------
 // | 开源协议 ( https://mit-license.org )
 // +----------------------------------------------------------------------
@@ -14,130 +14,154 @@
 
 namespace app\admin\controller;
 
-use controller\BasicAdmin;
-use service\DataService;
-use service\NodeService;
-use service\ToolsService;
-use think\App;
+use library\Controller;
+use library\tools\Data;
+use think\Console;
 use think\Db;
 
 /**
- * 后台入口
+ * 后台入口管理
  * Class Index
  * @package app\admin\controller
- * @author Anyon <zoujingli@qq.com>
- * @date 2017/02/15 10:41
  */
-class Index extends BasicAdmin
+class Index extends Controller
 {
 
     /**
-     * 后台框架布局
+     * 显示后台首页
      * @throws \think\db\exception\DataNotFoundException
      * @throws \think\db\exception\ModelNotFoundException
      * @throws \think\exception\DbException
      */
     public function index()
     {
-        NodeService::applyAuthNode();
-        $list = (array)Db::name('SystemMenu')->where(['status' => '1'])->order('sort asc,id asc')->select();
-        $menus = $this->buildMenuData(ToolsService::arr2tree($list), NodeService::get(), !!session('user'));
-        if (empty($menus) && !session('user.id')) {
+        $this->title = '系统管理后台';
+        $this->menus = \app\admin\service\Auth::getAuthMenu();
+        if (empty($this->menus) && !session('user.id')) {
             $this->redirect('@admin/login');
+        } else {
+            $this->fetch();
         }
-        return $this->fetch('', ['title' => '系统管理', 'menus' => $menus]);
     }
 
     /**
-     * 后台主菜单权限过滤
-     * @param array $menus 当前菜单列表
-     * @param array $nodes 系统权限节点数据
-     * @param bool $isLogin 是否已经登录
-     * @return array
+     * 后台环境信息
+     * @return mixed
      */
-    private function buildMenuData($menus, $nodes, $isLogin)
+    public function main()
     {
-        foreach ($menus as $key => &$menu) {
-            !empty($menu['sub']) && $menu['sub'] = $this->buildMenuData($menu['sub'], $nodes, $isLogin);
-            if (!empty($menu['sub'])) {
-                $menu['url'] = '#';
-            } elseif (preg_match('/^https?\:/i', $menu['url'])) {
-                continue;
-            } elseif ($menu['url'] !== '#') {
-                $node = join('/', array_slice(explode('/', preg_replace('/[\W]/', '/', $menu['url'])), 0, 3));
-                $menu['url'] = url($menu['url']) . (empty($menu['params']) ? '' : "?{$menu['params']}");
-                if (isset($nodes[$node]) && $nodes[$node]['is_login'] && empty($isLogin)) {
-                    unset($menus[$key]);
-                } elseif (isset($nodes[$node]) && $nodes[$node]['is_auth'] && $isLogin && !auth($node)) {
-                    unset($menus[$key]);
-                }
-            } else {
-                unset($menus[$key]);
-            }
+        $this->title = '后台首页';
+        $this->think_ver = \think\App::VERSION;
+        $this->mysql_ver = Db::query('select version() as ver')[0]['ver'];
+        $this->fetch();
+    }
+
+    /**
+     * 清理系统运行缓存
+     */
+    public function clearRuntime()
+    {
+        if (!\app\admin\service\Auth::isLogin()) {
+            $this->error('需要登录才能操作哦!');
         }
-        return $menus;
+        $this->list = [
+            [
+                'title'   => 'Clean up running cached files',
+                'message' => nl2br(Console::call('clear')->fetch()),
+            ], [
+                'title'   => 'Clean up invalid session files',
+                'message' => nl2br(Console::call('xclean:session')->fetch()),
+            ],
+        ];
+        $this->fetch('admin@index/command');
     }
 
     /**
-     * 主机信息显示
-     * @return string
+     * 压缩发布系统
      */
-    public function main()
+    public function buildOptimize()
     {
-        $_version = Db::query('select version() as ver');
-        return $this->fetch('', [
-            'title'     => '后台首页',
-            'think_ver' => App::VERSION,
-            'mysql_ver' => array_pop($_version)['ver'],
-        ]);
+        if (!\app\admin\service\Auth::isLogin()) {
+            $this->error('需要登录才能操作哦!');
+        }
+        $this->list = [
+            [
+                'title'   => 'Build route cache',
+                'message' => nl2br(Console::call('optimize:route')->fetch()),
+            ], [
+                'title'   => 'Build database schema cache',
+                'message' => nl2br(Console::call('optimize:schema')->fetch()),
+            ], [
+                'title'   => 'Optimizes PSR0 and PSR4 packages',
+                'message' => nl2br(Console::call('optimize:autoload')->fetch()),
+            ], [
+                'title'   => 'Build config and common file cache',
+                'message' => nl2br(Console::call('optimize:config')->fetch()),
+            ],
+        ];
+        $this->fetch('admin@index/command');
     }
 
     /**
      * 修改密码
-     * @return array|string
+     * @param integer $id
      * @throws \think\Exception
      * @throws \think\db\exception\DataNotFoundException
      * @throws \think\db\exception\ModelNotFoundException
      * @throws \think\exception\DbException
      * @throws \think\exception\PDOException
      */
-    public function pass()
+    public function pass($id)
     {
-        if (intval($this->request->request('id')) !== intval(session('user.id'))) {
+        $this->applyCsrfToken();
+        if (intval($id) !== intval(session('user.id'))) {
             $this->error('只能修改当前用户的密码!');
         }
         if ($this->request->isGet()) {
-            $this->assign('verify', true);
-            return $this->_form('SystemUser', 'user/pass');
-        }
-        $data = $this->request->post();
-        if ($data['password'] !== $data['repassword']) {
-            $this->error('两次输入的密码不一致,请重新输入!');
-        }
-        $user = Db::name('SystemUser')->where('id', session('user.id'))->find();
-        if (md5($data['oldpassword']) !== $user['password']) {
-            $this->error('旧密码验证失败,请重新输入!');
-        }
-        if (DataService::save('SystemUser', ['id' => session('user.id'), 'password' => md5($data['password'])])) {
-            $this->success('密码修改成功,下次请使用新密码登录!', '');
+            $this->verify = true;
+            $this->_form('SystemUser', 'admin@user/pass', 'id', [], ['id' => $id]);
+        } else {
+            $data = $this->_input([
+                'password'    => $this->request->post('password'),
+                'repassword'  => $this->request->post('repassword'),
+                'oldpassword' => $this->request->post('oldpassword'),
+            ], [
+                'oldpassword' => 'require',
+                'password'    => 'require|min:4',
+                'repassword'  => 'require|confirm:password',
+            ], [
+                'oldpassword.require' => '旧密码不能为空!',
+                'password.require'    => '登录密码不能为空!',
+                'password.min'        => '登录密码长度不能少于4位有效字符!',
+                'repassword.require'  => '重复密码不能为空!',
+                'repassword.confirm'  => '重复密码与登录密码不匹配,请重新输入!',
+            ]);
+            $user = Db::name('SystemUser')->where(['id' => $id])->find();
+            if (md5($data['oldpassword']) !== $user['password']) {
+                $this->error('旧密码验证失败,请重新输入!');
+            }
+            $result = \app\admin\service\Auth::checkPassword($data['password']);
+            if (empty($result['code'])) $this->error($result['msg']);
+            if (Data::save('SystemUser', ['id' => $user['id'], 'password' => md5($data['password'])])) {
+                $this->success('密码修改成功,下次请使用新密码登录!', '');
+            } else {
+                $this->error('密码修改失败,请稍候再试!');
+            }
         }
-        $this->error('密码修改失败,请稍候再试!');
     }
 
     /**
-     * 修改资料
-     * @return array|string
-     * @throws \think\Exception
-     * @throws \think\db\exception\DataNotFoundException
-     * @throws \think\db\exception\ModelNotFoundException
-     * @throws \think\exception\DbException
+     * 修改用户资料
+     * @param integer $id 会员ID
      */
-    public function info()
+    public function info($id = 0)
     {
-        if (intval($this->request->request('id')) === intval(session('user.id'))) {
-            return $this->_form('SystemUser', 'user/form');
+        $this->applyCsrfToken();
+        if (intval($id) === intval(session('user.id'))) {
+            $this->_form('SystemUser', 'user/form', 'id', [], ['id' => $id]);
+        } else {
+            $this->error('只能修改登录用户的资料!');
         }
-        $this->error('只能修改当前用户的资料!');
     }
 
-}
+}

+ 12 - 33
application/admin/controller/Log.php

@@ -1,11 +1,11 @@
 <?php
 
 // +----------------------------------------------------------------------
-// | ThinkAdmin
+// | framework
 // +----------------------------------------------------------------------
-// | 版权所有 2014~2017 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
 // +----------------------------------------------------------------------
-// | 官方网站: http://think.ctolog.com
+// | 官方网站: http://framework.thinkadmin.top
 // +----------------------------------------------------------------------
 // | 开源协议 ( https://mit-license.org )
 // +----------------------------------------------------------------------
@@ -14,18 +14,14 @@
 
 namespace app\admin\controller;
 
-use controller\BasicAdmin;
-use service\DataService;
-use think\Db;
+use library\Controller;
 
 /**
  * 系统日志管理
  * Class Log
  * @package app\admin\controller
- * @author Anyon <zoujingli@qq.com>
- * @date 2017/02/15 18:12
  */
-class Log extends BasicAdmin
+class Log extends Controller
 {
 
     /**
@@ -36,7 +32,6 @@ class Log extends BasicAdmin
 
     /**
      * 日志列表
-     * @return array|string
      * @throws \think\Exception
      * @throws \think\db\exception\DataNotFoundException
      * @throws \think\db\exception\ModelNotFoundException
@@ -44,20 +39,8 @@ class Log extends BasicAdmin
      */
     public function index()
     {
-        // 日志行为类别
-        $actions = Db::name($this->table)->group('action')->column('action');
-        $this->assign('actions', $actions);
-        // 日志数据库对象
-        list($this->title, $get) = ['系统操作日志', $this->request->get()];
-        $db = Db::name($this->table)->order('id desc');
-        foreach (['action', 'content', 'username'] as $key) {
-            (isset($get[$key]) && $get[$key] !== '') && $db->whereLike($key, "%{$get[$key]}%");
-        }
-        if (isset($get['create_at']) && $get['create_at'] !== '') {
-            list($start, $end) = explode(' - ', $get['create_at']);
-            $db->whereBetween('create_at', ["{$start} 00:00:00", "{$end} 23:59:59"]);
-        }
-        return parent::_list($db);
+        $this->title = '系统操作日志';
+        $this->_query($this->table)->like('action,node,content,username,geoip')->dateBetween('create_at')->order('id desc')->page();
     }
 
     /**
@@ -65,11 +48,11 @@ class Log extends BasicAdmin
      * @param array $data
      * @throws \Exception
      */
-    protected function _index_data_filter(&$data)
+    protected function _index_page_filter(&$data)
     {
         $ip = new \Ip2Region();
         foreach ($data as &$vo) {
-            $result = $ip->btreeSearch($vo['ip']);
+            $result = $ip->btreeSearch($vo['geoip']);
             $vo['isp'] = isset($result['region']) ? $result['region'] : '';
             $vo['isp'] = str_replace(['内网IP', '0', '|'], '', $vo['isp']);
         }
@@ -77,15 +60,11 @@ class Log extends BasicAdmin
 
     /**
      * 日志删除操作
-     * @throws \think\Exception
-     * @throws \think\exception\PDOException
      */
     public function del()
     {
-        if (DataService::update($this->table)) {
-            $this->success("日志删除成功!", '');
-        }
-        $this->error("日志删除失败, 请稍候再试!");
+        $this->applyCsrfToken();
+        $this->_delete($this->table);
     }
 
-}
+}

+ 69 - 56
application/admin/controller/Login.php

@@ -1,11 +1,11 @@
 <?php
 
 // +----------------------------------------------------------------------
-// | ThinkAdmin
+// | framework
 // +----------------------------------------------------------------------
-// | 版权所有 2014~2017 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
 // +----------------------------------------------------------------------
-// | 官方网站: http://think.ctolog.com
+// | 官方网站: http://framework.thinkadmin.top
 // +----------------------------------------------------------------------
 // | 开源协议 ( https://mit-license.org )
 // +----------------------------------------------------------------------
@@ -14,36 +14,24 @@
 
 namespace app\admin\controller;
 
-use controller\BasicAdmin;
-use service\LogService;
-use service\NodeService;
+use library\Controller;
 use think\Db;
-use think\facade\Validate;
-
 
 /**
- * 系统登录控制器
- * class Login
+ * 用户登录管理
+ * Class Login
  * @package app\admin\controller
- * @author Anyon <zoujingli@qq.com>
- * @date 2017/02/10 13:59
  */
-class Login extends BasicAdmin
+class Login extends Controller
 {
-
     /**
-     * 控制器基础方法
+     * 设置页面标题
+     * @var string
      */
-    public function initialize()
-    {
-        if (session('user.id') && $this->request->action() !== 'out') {
-            $this->redirect('@admin');
-        }
-    }
+    public $title = '管理登录';
 
     /**
      * 用户登录
-     * @return string
      * @throws \think\Exception
      * @throws \think\db\exception\DataNotFoundException
      * @throws \think\db\exception\ModelNotFoundException
@@ -52,38 +40,64 @@ class Login extends BasicAdmin
      */
     public function index()
     {
+        $this->applyCsrfToken();
         if ($this->request->isGet()) {
-            return $this->fetch('', ['title' => '用户登录']);
+            session('loginskey', $this->skey = session('loginskey') ? session('loginskey') : uniqid());
+            $this->fetch();
+        } else {
+            $data = $this->_input([
+                'username' => $this->request->post('username'),
+                'password' => $this->request->post('password'),
+            ], [
+                'username' => 'require|min:4',
+                'password' => 'require|min:4',
+            ], [
+                'username.require' => '登录账号不能为空!',
+                'password.require' => '登录密码不能为空!',
+                'username.min'     => '登录账号长度不能少于4位有效字符!',
+                'password.min'     => '登录密码长度不能少于4位有效字符!',
+            ]);
+            // 用户信息验证
+            $map = ['is_deleted' => '0', 'username' => $data['username']];
+            $user = Db::name('SystemUser')->where($map)->find();
+            if (empty($user)) $this->error('登录账号或密码错误,请重新输入!');
+            if (empty($user['status'])) $this->error('账号已经被禁用,请联系管理!');
+            // 账号锁定消息
+            $cache = cache('user_login_' . $user['username']);
+            if (is_array($cache) && !empty($cache['number']) && !empty($cache['time'])) {
+                if ($cache['number'] >= 10 && ($diff = $cache['time'] + 3600 - time()) > 0) {
+                    list($m, $s, $info) = [floor($diff / 60), floor($diff % 60), ''];
+                    if ($m > 0) $info = "{$m} 分";
+                    $this->error("<strong class='color-red'>抱歉,该账号已经被锁定!</strong><p class='nowrap'>连续 10 次登录错误,请 {$info} {$s} 秒后再登录!</p>");
+                }
+            }
+            if (md5($user['password'] . session('loginskey')) !== $data['password']) {
+                if (empty($cache) || empty($cache['time']) || empty($cache['number']) || $cache['time'] + 3600 < time()) {
+                    $cache = ['time' => time(), 'number' => 1, 'geoip' => $this->request->ip()];
+                } elseif ($cache['number'] + 1 <= 10) {
+                    $cache = ['time' => time(), 'number' => $cache['number'] + 1, 'geoip' => $this->request->ip()];
+                }
+                cache('user_login_' . $user['username'], $cache);
+                if (($diff = 10 - $cache['number']) > 0) {
+                    $this->error("<strong class='color-red'>登录账号或密码错误!</strong><p class='nowrap'>还有 {$diff} 次尝试机会,将锁定一小时内禁止登录!</p>");
+                } else {
+                    _syslog('系统管理', "账号{$user['username']}连续10次登录密码错误,请注意账号安全!");
+                    $this->error("<strong class='color-red'>登录账号或密码错误!</strong><p class='nowrap'>尝试次数达到上限,锁定一小时内禁止登录!</p>");
+                }
+            }
+            // 登录成功并更新账号
+            cache('user_login_' . $user['username'], null);
+            Db::name('SystemUser')->where(['id' => $user['id']])->update([
+                'login_at'  => Db::raw('now()'),
+                'login_ip'  => $this->request->ip(),
+                'login_num' => Db::raw('login_num+1'),
+            ]);
+            session('user', $user);
+            session('loginskey', null);
+            empty($user['authorize']) || \app\admin\service\Auth::applyNode();
+            _syslog('系统管理', '用户登录系统成功');
+            $this->success('登录成功,正在进入系统...', url('@admin'));
         }
-        // 输入数据效验
-        $validate = Validate::make([
-            'username' => 'require|min:4',
-            'password' => 'require|min:4',
-        ], [
-            'username.require' => '登录账号不能为空!',
-            'username.min'     => '登录账号长度不能少于4位有效字符!',
-            'password.require' => '登录密码不能为空!',
-            'password.min'     => '登录密码长度不能少于4位有效字符!',
-        ]);
-        $data = [
-            'username' => $this->request->post('username', ''),
-            'password' => $this->request->post('password', ''),
-        ];
-        $validate->check($data) || $this->error($validate->getError());
-        // 用户信息验证
-        $user = Db::name('SystemUser')->where(['username' => $data['username'], 'is_deleted' => '0'])->find();
-        empty($user) && $this->error('登录账号不存在,请重新输入!');
-        empty($user['status']) && $this->error('账号已经被禁用,请联系管理员!');
-        $user['password'] !== md5($data['password']) && $this->error('登录密码错误,请重新输入!');
-        // 更新登录信息
-        Db::name('SystemUser')->where(['id' => $user['id']])->update([
-            'login_at'  => Db::raw('now()'),
-            'login_num' => Db::raw('login_num+1'),
-        ]);
-        session('user', $user);
-        !empty($user['authorize']) && NodeService::applyAuthNode();
-        LogService::write('系统管理', '用户登录系统成功');
-        $this->success('登录成功,正在进入系统...', '@admin');
     }
 
     /**
@@ -91,10 +105,9 @@ class Login extends BasicAdmin
      */
     public function out()
     {
-        session('user') && LogService::write('系统管理', '用户退出系统成功');
-        !empty($_SESSION) && $_SESSION = [];
+        if ($_SESSION) $_SESSION = [];
         [session_unset(), session_destroy()];
-        $this->success('退出登录成功!', '@admin/login');
+        $this->success('退出登录成功!', url('@admin/login'));
     }
 
-}
+}

+ 46 - 89
application/admin/controller/Menu.php

@@ -1,11 +1,11 @@
 <?php
 
 // +----------------------------------------------------------------------
-// | ThinkAdmin
+// | framework
 // +----------------------------------------------------------------------
-// | 版权所有 2014~2017 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
 // +----------------------------------------------------------------------
-// | 官方网站: http://think.ctolog.com
+// | 官方网站: http://framework.thinkadmin.top
 // +----------------------------------------------------------------------
 // | 开源协议 ( https://mit-license.org )
 // +----------------------------------------------------------------------
@@ -14,86 +14,68 @@
 
 namespace app\admin\controller;
 
-use controller\BasicAdmin;
-use service\DataService;
-use service\NodeService;
-use service\ToolsService;
+use library\Controller;
+use library\tools\Data;
 use think\Db;
 
 /**
- * 系统后台管理管理
+ * 系统菜单管理
  * Class Menu
  * @package app\admin\controller
- * @author Anyon <zoujingli@qq.com>
- * @date 2017/02/15
  */
-class Menu extends BasicAdmin
+class Menu extends Controller
 {
 
     /**
-     * 绑定操作模型
+     * 当前操作数据库
      * @var string
      */
-    public $table = 'SystemMenu';
+    protected $table = 'SystemMenu';
 
     /**
-     * 菜单列表
-     * @return array|string
-     * @throws \think\db\exception\DataNotFoundException
-     * @throws \think\db\exception\ModelNotFoundException
-     * @throws \think\exception\DbException
-     * @throws \think\Exception
+     * 系统菜单显示
      */
     public function index()
     {
-        $this->title = '后台菜单管理';
-        $db = Db::name($this->table)->order('sort asc,id asc');
-        return parent::_list($db, false);
+        $this->title = '系统菜单管理';
+        $this->_page($this->table, false);
     }
 
     /**
      * 列表数据处理
      * @param array $data
      */
-    protected function _index_data_filter(&$data)
+    protected function _index_page_filter(&$data)
     {
         foreach ($data as &$vo) {
             if ($vo['url'] !== '#') {
                 $vo['url'] = url($vo['url']) . (empty($vo['params']) ? '' : "?{$vo['params']}");
             }
-            $vo['ids'] = join(',', ToolsService::getArrSubIds($data, $vo['id']));
+            $vo['ids'] = join(',', Data::getArrSubIds($data, $vo['id']));
         }
-        $data = ToolsService::arr2table($data);
+        $data = Data::arr2table($data);
     }
 
     /**
-     * 添加菜单
-     * @return array|string
-     * @throws \think\db\exception\DataNotFoundException
-     * @throws \think\db\exception\ModelNotFoundException
-     * @throws \think\exception\DbException
-     * @throws \think\Exception
+     * 编辑菜单
      */
-    public function add()
+    public function edit()
     {
-        return $this->_form($this->table, 'form');
+        $this->applyCsrfToken();
+        $this->_form($this->table, 'form');
     }
 
     /**
-     * 编辑菜单
-     * @return array|string
-     * @throws \think\db\exception\DataNotFoundException
-     * @throws \think\db\exception\ModelNotFoundException
-     * @throws \think\exception\DbException
-     * @throws \think\Exception
+     * 添加菜单
      */
-    public function edit()
+    public function add()
     {
-        return $this->_form($this->table, 'form');
+        $this->applyCsrfToken();
+        $this->_form($this->table, 'form');
     }
 
     /**
-     * 表单数据前缀方法
+     * 表单数据
      * @param array $vo
      * @throws \think\db\exception\DataNotFoundException
      * @throws \think\db\exception\ModelNotFoundException
@@ -105,72 +87,47 @@ class Menu extends BasicAdmin
             // 上级菜单处理
             $_menus = Db::name($this->table)->where(['status' => '1'])->order('sort asc,id asc')->select();
             $_menus[] = ['title' => '顶级菜单', 'id' => '0', 'pid' => '-1'];
-            $menus = ToolsService::arr2table($_menus);
-            foreach ($menus as $key => &$menu) {
-                if (substr_count($menu['path'], '-') > 3) {
-                    unset($menus[$key]);
-                    continue;
-                }
-                if (isset($vo['pid'])) {
-                    $current_path = "-{$vo['pid']}-{$vo['id']}";
-                    if ($vo['pid'] !== '' && (stripos("{$menu['path']}-", "{$current_path}-") !== false || $menu['path'] === $current_path)) {
-                        unset($menus[$key]);
-                        continue;
-                    }
-                }
-            }
+            $menus = Data::arr2table($_menus);
+            foreach ($menus as $key => &$menu) if (substr_count($menu['path'], '-') > 3) unset($menus[$key]); # 移除三级以下的菜单
+            elseif (isset($vo['pid']) && $vo['pid'] !== '' && $cur = "-{$vo['pid']}-{$vo['id']}")
+                if (stripos("{$menu['path']}-", "{$cur}-") !== false || $menu['path'] === $cur) unset($menus[$key]); # 移除与自己相关联的菜单
+            // 选择自己的上级菜单
+            if (!isset($vo['pid']) && $this->request->get('pid', '0')) $vo['pid'] = $this->request->get('pid', '0');
             // 读取系统功能节点
-            $nodes = NodeService::get();
+            $nodes = \app\admin\service\Auth::get();
             foreach ($nodes as $key => $node) {
-                if (empty($node['is_menu'])) {
-                    unset($nodes[$key]);
-                }
+                if (empty($node['is_menu'])) unset($nodes[$key]);
+                unset($nodes[$key]['pnode'], $nodes[$key]['is_login'], $nodes[$key]['is_menu'], $nodes[$key]['is_auth']);
             }
-            // 设置上级菜单
-            if (!isset($vo['pid']) && $this->request->get('pid', '0')) {
-                $vo['pid'] = $this->request->get('pid', '0');
-            }
-            $this->assign(['nodes' => array_column($nodes, 'node'), 'menus' => $menus]);
+            list($this->menus, $this->nodes) = [$menus, array_values($nodes)];
         }
     }
 
     /**
-     * 删除菜单
-     * @throws \think\Exception
-     * @throws \think\exception\PDOException
+     * 启用菜单
      */
-    public function del()
+    public function resume()
     {
-        if (DataService::update($this->table)) {
-            $this->success("菜单删除成功!", '');
-        }
-        $this->error("菜单删除失败, 请稍候再试!");
+        $this->applyCsrfToken();
+        $this->_save($this->table, ['status' => '1']);
     }
 
     /**
-     * 菜单禁用
-     * @throws \think\Exception
-     * @throws \think\exception\PDOException
+     * 禁用菜单
      */
     public function forbid()
     {
-        if (DataService::update($this->table)) {
-            $this->success("菜单禁用成功!", '');
-        }
-        $this->error("菜单禁用失败, 请稍候再试!");
+        $this->applyCsrfToken();
+        $this->_save($this->table, ['status' => '0']);
     }
 
     /**
-     * 菜单禁用
-     * @throws \think\Exception
-     * @throws \think\exception\PDOException
+     * 删除菜单
      */
-    public function resume()
+    public function del()
     {
-        if (DataService::update($this->table)) {
-            $this->success("菜单启用成功!", '');
-        }
-        $this->error("菜单启用失败, 请稍候再试!");
+        $this->applyCsrfToken();
+        $this->_delete($this->table);
     }
 
-}
+}

+ 92 - 0
application/admin/controller/Message.php

@@ -0,0 +1,92 @@
+<?php
+
+// +----------------------------------------------------------------------
+// | framework
+// +----------------------------------------------------------------------
+// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// +----------------------------------------------------------------------
+// | 官方网站: http://framework.thinkadmin.top
+// +----------------------------------------------------------------------
+// | 开源协议 ( https://mit-license.org )
+// +----------------------------------------------------------------------
+// | github开源项目:https://github.com/zoujingli/ThinkAdmin
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller;
+
+use library\Controller;
+use think\Db;
+
+/**
+ * 系统消息管理
+ * Class Message
+ * @package app\admin\controller
+ */
+class Message extends Controller
+{
+    /**
+     * 指定数据表
+     * @var string
+     */
+    protected $table = 'SystemMessage';
+
+    /***
+     * 获取消息列表
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
+     */
+    public function index()
+    {
+        $this->title = '系统消息管理';
+        $this->_query($this->table)->like('title,desc')->equal('read_state')->dateBetween('create_at,read_at')->order('id desc')->page();
+    }
+
+    /**
+     * 消息状态
+     */
+    public function state()
+    {
+        $this->_save($this->table, ['read_state' => '1', 'read_at' => date('Y-m-d H:i:s')]);
+    }
+
+    /**
+     * 删除消息
+     */
+    public function del()
+    {
+        $this->_delete($this->table);
+    }
+
+    /**
+     * 清理所有消息
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function clear()
+    {
+        if (Db::name($this->table)->whereRaw('1=1')->delete() !== false) {
+            $this->success('系统消息清理成功!');
+        } else {
+            $this->error('系统消息清理失败,请稍候再试!');
+        }
+    }
+
+    /**
+     * 系统消息开关处理
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function onoff()
+    {
+        sysconf('system_message_state', sysconf('system_message_state') ? 0 : 1);
+        if (sysconf('system_message_state')) {
+            $this->success('系统消息提示开启成功!');
+        } else {
+            $this->success('系统消息提示关闭成功!');
+        }
+    }
+
+}

+ 85 - 92
application/admin/controller/Node.php

@@ -1,92 +1,85 @@
-<?php
-
-// +----------------------------------------------------------------------
-// | ThinkAdmin
-// +----------------------------------------------------------------------
-// | 版权所有 2014~2017 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
-// +----------------------------------------------------------------------
-// | 官方网站: http://think.ctolog.com
-// +----------------------------------------------------------------------
-// | 开源协议 ( https://mit-license.org )
-// +----------------------------------------------------------------------
-// | github开源项目:https://github.com/zoujingli/ThinkAdmin
-// +----------------------------------------------------------------------
-
-namespace app\admin\controller;
-
-use controller\BasicAdmin;
-use service\DataService;
-use service\NodeService;
-use service\ToolsService;
-use think\Db;
-
-/**
- * 系统功能节点管理
- * Class Node
- * @package app\admin\controller
- * @author Anyon <zoujingli@qq.com>
- * @date 2017/02/15 18:13
- */
-class Node extends BasicAdmin
-{
-
-    /**
-     * 指定当前默认模型
-     * @var string
-     */
-    public $table = 'SystemNode';
-
-    /**
-     * 显示节点列表
-     * @return string
-     */
-    public function index()
-    {
-        $nodes = ToolsService::arr2table(NodeService::get(), 'node', 'pnode');
-        $groups = [];
-        foreach ($nodes as $node) {
-            $pnode = explode('/', $node['node'])[0];
-            if ($node['node'] === $pnode) {
-                $groups[$pnode]['node'] = $node;
-            }
-            $groups[$pnode]['list'][] = $node;
-        }
-        return $this->fetch('', ['title' => '系统节点管理', 'nodes' => $nodes, 'groups' => $groups]);
-    }
-
-    /**
-     * 清理无效的节点记录
-     * @throws \think\Exception
-     * @throws \think\exception\PDOException
-     */
-    public function clear()
-    {
-        $nodes = array_keys(NodeService::get());
-        if (false !== Db::name($this->table)->whereNotIn('node', $nodes)->delete()) {
-            $this->success('清理无效节点记录成功!', '');
-        }
-        $this->error('清理无效记录失败,请稍候再试!');
-    }
-
-    /**
-     * 保存节点变更
-     * @throws \think\Exception
-     * @throws \think\exception\PDOException
-     */
-    public function save()
-    {
-        if ($this->request->isPost()) {
-            list($post, $data) = [$this->request->post(), []];
-            foreach ($post['list'] as $vo) {
-                if (!empty($vo['node'])) {
-                    $data['node'] = $vo['node'];
-                    $data[$vo['name']] = $vo['value'];
-                }
-            }
-            !empty($data) && DataService::save($this->table, $data, 'node');
-            $this->success('参数保存成功!', '');
-        }
-        $this->error('访问异常,请重新进入...');
-    }
-
-}
+<?php
+
+// +----------------------------------------------------------------------
+// | framework
+// +----------------------------------------------------------------------
+// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// +----------------------------------------------------------------------
+// | 官方网站: http://framework.thinkadmin.top
+// +----------------------------------------------------------------------
+// | 开源协议 ( https://mit-license.org )
+// +----------------------------------------------------------------------
+// | github开源项目:https://github.com/zoujingli/ThinkAdmin
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller;
+
+use library\Controller;
+use library\tools\Data;
+use think\Db;
+
+/**
+ * 系统节点管理
+ * Class Node
+ * @package app\admin\controller
+ */
+class Node extends Controller
+{
+    /**
+     * 指定当前数据表
+     * @var string
+     */
+    protected $table = 'SystemNode';
+
+    /**
+     * 显示节点列表
+     * @return mixed
+     */
+    public function index()
+    {
+        $this->title = '系统节点管理';
+        list($nodes, $groups) = [\app\admin\service\Auth::get(), []];
+        $this->nodes = Data::arr2table($nodes, 'node', 'pnode');
+        foreach ($this->nodes as $node) {
+            $pnode = explode('/', $node['node'])[0];
+            if ($node['node'] === $pnode) $groups[$pnode]['node'] = $node;
+            $groups[$pnode]['list'][] = $node;
+        }
+        $this->groups = $groups;
+        $this->fetch();
+    }
+
+    /**
+     * 清理无效的节点数据
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function clear()
+    {
+        $nodes = array_unique(array_column(\app\admin\service\Auth::get(), 'node'));
+        if (false !== Db::name($this->table)->whereNotIn('node', $nodes)->delete()) {
+            $this->success('清理无效的节点配置成功!', '');
+        }
+        $this->error('清理无效的节点配置,请稍候再试!');
+    }
+
+    /**
+     * 更新数据记录
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function save()
+    {
+        if ($this->request->isPost()) {
+            list($post, $data) = [$this->request->post(), []];
+            foreach ($post['list'] as $vo) if (!empty($vo['node'])) {
+                $data['node'] = $vo['node'];
+                $data[$vo['name']] = $vo['value'];
+            }
+            empty($data) || data_save($this->table, $data, 'node');
+            $this->success('节点配置保存成功!', '');
+        }
+        $this->error('访问异常,请重新进入...');
+    }
+
+}

+ 0 - 152
application/admin/controller/Plugs.php

@@ -1,152 +0,0 @@
-<?php
-
-// +----------------------------------------------------------------------
-// | ThinkAdmin
-// +----------------------------------------------------------------------
-// | 版权所有 2014~2017 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
-// +----------------------------------------------------------------------
-// | 官方网站: http://think.ctolog.com
-// +----------------------------------------------------------------------
-// | 开源协议 ( https://mit-license.org )
-// +----------------------------------------------------------------------
-// | github开源项目:https://github.com/zoujingli/ThinkAdmin
-// +----------------------------------------------------------------------
-
-namespace app\admin\controller;
-
-use controller\BasicAdmin;
-use service\FileService;
-
-/**
- * 插件助手控制器
- * Class Plugs
- * @package app\admin\controller
- * @author Anyon <zoujingli@qq.com>
- * @date 2017/02/21
- */
-class Plugs extends BasicAdmin
-{
-
-    /**
-     * 文件上传
-     * @return mixed
-     * @throws \think\Exception
-     * @throws \think\exception\PDOException
-     */
-    public function upfile()
-    {
-        $uptype = $this->request->get('uptype');
-        if (!in_array($uptype, ['local', 'qiniu', 'oss'])) {
-            $uptype = sysconf('storage_type');
-        }
-        $mode = $this->request->get('mode', 'one');
-        $types = $this->request->get('type', 'jpg,png');
-        $this->assign('mimes', FileService::getFileMine($types));
-        $this->assign('field', $this->request->get('field', 'file'));
-        return $this->fetch('', ['mode' => $mode, 'types' => $types, 'uptype' => $uptype]);
-    }
-
-    /**
-     * 通用文件上传
-     * @return \think\response\Json
-     * @throws \think\Exception
-     * @throws \think\exception\PDOException
-     * @throws \OSS\Core\OssException
-     */
-    public function upload()
-    {
-        $file = $this->request->file('file');
-        if (!$file->checkExt(strtolower(sysconf('storage_local_exts')))) {
-            return json(['code' => 'ERROR', 'msg' => '文件上传类型受限']);
-        }
-        $names = str_split($this->request->post('md5'), 16);
-        $ext = strtolower(pathinfo($file->getInfo('name'), 4));
-        $ext = $ext ? $ext : 'tmp';
-        $filename = "{$names[0]}/{$names[1]}.{$ext}";
-        // 文件上传Token验证
-        if ($this->request->post('token') !== md5($filename . session_id())) {
-            return json(['code' => 'ERROR', 'msg' => '文件上传验证失败']);
-        }
-        // 文件上传处理
-        if (($info = $file->move("static/upload/{$names[0]}", "{$names[1]}.{$ext}", true))) {
-            if (($site_url = FileService::getFileUrl($filename, 'local'))) {
-                return json(['data' => ['site_url' => $site_url], 'code' => 'SUCCESS', 'msg' => '文件上传成功']);
-            }
-        }
-        return json(['code' => 'ERROR', 'msg' => '文件上传失败']);
-    }
-
-    /**
-     * 文件状态检查
-     * @throws \OSS\Core\OssException
-     * @throws \think\Exception
-     * @throws \think\exception\PDOException
-     */
-    public function upstate()
-    {
-        $post = $this->request->post();
-        $ext = strtolower(pathinfo($post['filename'], 4));
-        $filename = join('/', str_split($post['md5'], 16)) . '.' . ($ext ? $ext : 'tmp');
-        // 检查文件是否已上传
-        if (($site_url = FileService::getFileUrl($filename))) {
-            return json(['data' => ['site_url' => $site_url], 'code' => "IS_FOUND"]);
-        }
-        // 需要上传文件,生成上传配置参数
-        $data = ['uptype' => $post['uptype'], 'file_url' => $filename];
-        switch (strtolower($post['uptype'])) {
-            case 'local':
-                $data['token'] = md5($filename . session_id());
-                $data['server'] = FileService::getUploadLocalUrl();
-                break;
-            case 'qiniu':
-                $data['token'] = $this->_getQiniuToken($filename);
-                $data['server'] = FileService::getUploadQiniuUrl(true);
-                break;
-            case 'oss':
-                $time = time() + 3600;
-                $policyText = [
-                    'expiration' => date('Y-m-d', $time) . 'T' . date('H:i:s', $time) . '.000Z',
-                    'conditions' => [['content-length-range', 0, 1048576000]],
-                ];
-                $data['server'] = FileService::getUploadOssUrl();
-                $data['policy'] = base64_encode(json_encode($policyText));
-                $data['site_url'] = FileService::getBaseUriOss() . $filename;
-                $data['signature'] = base64_encode(hash_hmac('sha1', $data['policy'], sysconf('storage_oss_secret'), true));
-                $data['OSSAccessKeyId'] = sysconf('storage_oss_keyid');
-                break;
-        }
-        return json(['data' => $data, 'code' => "NOT_FOUND"]);
-    }
-
-    /**
-     * 生成七牛文件上传Token
-     * @param string $key
-     * @return string
-     * @throws \think\Exception
-     * @throws \think\exception\PDOException
-     */
-    protected function _getQiniuToken($key)
-    {
-        $baseUrl = FileService::getBaseUriQiniu();
-        $bucket = sysconf('storage_qiniu_bucket');
-        $accessKey = sysconf('storage_qiniu_access_key');
-        $secretKey = sysconf('storage_qiniu_secret_key');
-        $params = [
-            "scope"      => "{$bucket}:{$key}", "deadline" => 3600 + time(),
-            "returnBody" => "{\"data\":{\"site_url\":\"{$baseUrl}/$(key)\",\"file_url\":\"$(key)\"}, \"code\": \"SUCCESS\"}",
-        ];
-        $data = str_replace(['+', '/'], ['-', '_'], base64_encode(json_encode($params)));
-        return $accessKey . ':' . str_replace(['+', '/'], ['-', '_'], base64_encode(hash_hmac('sha1', $data, $secretKey, true))) . ':' . $data;
-    }
-
-    /**
-     * 字体图标选择器
-     * @return \think\response\View
-     */
-    public function icon()
-    {
-        $field = $this->request->get('field', 'icon');
-        return $this->fetch('', ['field' => $field]);
-    }
-
-}

+ 89 - 0
application/admin/controller/Queue.php

@@ -0,0 +1,89 @@
+<?php
+
+// +----------------------------------------------------------------------
+// | framework
+// +----------------------------------------------------------------------
+// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// +----------------------------------------------------------------------
+// | 官方网站: http://framework.thinkadmin.top
+// +----------------------------------------------------------------------
+// | 开源协议 ( https://mit-license.org )
+// +----------------------------------------------------------------------
+// | github开源项目:https://github.com/zoujingli/ThinkAdmin
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller;
+
+use library\Controller;
+use think\Console;
+use think\Db;
+
+/**
+ * 系统消息任务管理
+ * Class Queue
+ * @package app\admin\controller
+ */
+class Queue extends Controller
+{
+    /**
+     * 绑定数据表
+     * @var string
+     */
+    protected $table = 'SystemJobsLog';
+
+    /**
+     * 任务列表
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
+     */
+    public function index()
+    {
+        $this->title = '消息任务管理';
+        $this->uris = Db::name($this->table)->distinct(true)->column('uri');
+        $this->cmd = 'php ' . env('root_path') . 'think xtask:start';
+        $this->message = Console::call('xtask:state')->fetch();
+        $this->_query($this->table)->equal('status,title,uri')->dateBetween('create_at,status_at')->order('id desc')->page();
+    }
+
+    /**
+     * 重置失败的任务
+     */
+    public function redo()
+    {
+        try {
+            $where = ['id' => $this->request->post('id')];
+            $info = Db::name($this->table)->where($where)->find();
+            if (empty($info)) $this->error('需要重置的任务获取异常!');
+            $data = isset($info['data']) ? json_decode($info['data'], true) : '[]';
+            \app\admin\service\Queue::add($info['title'], $info['uri'], $info['later'], $data, $info['double'], $info['desc']);
+            $this->success('任务重置成功!', url('@admin') . '#' . url('@admin/queue/index'));
+        } catch (\think\exception\HttpResponseException $exception) {
+            throw $exception;
+        } catch (\Exception $e) {
+            $this->error("任务重置失败,请稍候再试!<br> {$e->getMessage()}");
+        }
+    }
+
+    /**
+     * 删除消息任务
+     */
+    public function del()
+    {
+        try {
+            $isNot = false;
+            foreach (explode(',', $this->request->post('id', '0')) as $id) {
+                if (!\app\admin\service\Queue::del($id)) $isNot = true;
+            }
+            if (empty($isNot)) $this->_delete($this->table);
+            $this->success($isNot ? '部分任务删除成功!' : '任务删除成功!');
+        } catch (\think\exception\HttpResponseException $exception) {
+            throw $exception;
+        } catch (\Exception $e) {
+            $this->error("任务删除失败,请稍候再试!<br> {$e->getMessage()}");
+        }
+    }
+
+}

+ 44 - 76
application/admin/controller/User.php

@@ -1,11 +1,11 @@
 <?php
 
 // +----------------------------------------------------------------------
-// | ThinkAdmin
+// | framework
 // +----------------------------------------------------------------------
-// | 版权所有 2014~2017 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
 // +----------------------------------------------------------------------
-// | 官方网站: http://think.ctolog.com
+// | 官方网站: http://framework.thinkadmin.top
 // +----------------------------------------------------------------------
 // | 开源协议 ( https://mit-license.org )
 // +----------------------------------------------------------------------
@@ -14,8 +14,8 @@
 
 namespace app\admin\controller;
 
-use controller\BasicAdmin;
-use service\DataService;
+use library\Controller;
+use library\tools\Data;
 use think\Db;
 
 /**
@@ -25,7 +25,7 @@ use think\Db;
  * @author Anyon <zoujingli@qq.com>
  * @date 2017/02/15 18:12
  */
-class User extends BasicAdmin
+class User extends Controller
 {
 
     /**
@@ -36,89 +36,74 @@ class User extends BasicAdmin
 
     /**
      * 用户列表
-     * @return array|string
+     * @throws \think\Exception
      * @throws \think\db\exception\DataNotFoundException
      * @throws \think\db\exception\ModelNotFoundException
      * @throws \think\exception\DbException
-     * @throws \think\Exception
+     * @throws \think\exception\PDOException
      */
     public function index()
     {
         $this->title = '系统用户管理';
-        list($get, $db) = [$this->request->get(), Db::name($this->table)];
-        foreach (['username', 'phone', 'mail'] as $key) {
-            (isset($get[$key]) && $get[$key] !== '') && $db->whereLike($key, "%{$get[$key]}%");
-        }
-        if (isset($get['date']) && $get['date'] !== '') {
-            list($start, $end) = explode(' - ', $get['date']);
-            $db->whereBetween('login_at', ["{$start} 00:00:00", "{$end} 23:59:59"]);
-        }
-        return parent::_list($db->where(['is_deleted' => '0']));
+        $this->_query($this->table)->where(['is_deleted' => '0'])->like('username,phone,mail')->dateBetween('login_at')->equal('status')->page();
     }
 
     /**
      * 授权管理
-     * @return array|string
-     * @throws \think\db\exception\DataNotFoundException
-     * @throws \think\db\exception\ModelNotFoundException
-     * @throws \think\exception\DbException
-     * @throws \think\Exception
+     * @return mixed
      */
     public function auth()
     {
-        return $this->_form($this->table, 'auth');
+        $this->applyCsrfToken();
+        $this->_form($this->table, 'auth');
     }
 
     /**
      * 用户添加
-     * @return array|string
-     * @throws \think\db\exception\DataNotFoundException
-     * @throws \think\db\exception\ModelNotFoundException
-     * @throws \think\exception\DbException
-     * @throws \think\Exception
+     * @return mixed
      */
     public function add()
     {
-        return $this->_form($this->table, 'form');
+        $this->applyCsrfToken();
+        $this->_form($this->table, 'form');
     }
 
     /**
      * 用户编辑
-     * @return array|string
-     * @throws \think\db\exception\DataNotFoundException
-     * @throws \think\db\exception\ModelNotFoundException
-     * @throws \think\exception\DbException
-     * @throws \think\Exception
+     * @return mixed
      */
     public function edit()
     {
-        return $this->_form($this->table, 'form');
+        $this->applyCsrfToken();
+        $this->_form($this->table, 'form');
     }
 
     /**
      * 用户密码修改
-     * @return array|string
+     * @return mixed
      * @throws \think\Exception
-     * @throws \think\db\exception\DataNotFoundException
-     * @throws \think\db\exception\ModelNotFoundException
-     * @throws \think\exception\DbException
      * @throws \think\exception\PDOException
      */
     public function pass()
     {
+        $this->applyCsrfToken();
         if ($this->request->isGet()) {
-            $this->assign('verify', false);
-            return $this->_form($this->table, 'pass');
-        }
-        $post = $this->request->post();
-        if ($post['password'] !== $post['repassword']) {
-            $this->error('两次输入的密码不一致!');
-        }
-        $data = ['id' => $post['id'], 'password' => md5($post['password'])];
-        if (DataService::save($this->table, $data, 'id')) {
-            $this->success('密码修改成功,下次请使用新密码登录!', '');
+            $this->verify = false;
+            $this->_form($this->table, 'pass');
+        } else {
+            $post = $this->request->post();
+            if ($post['password'] !== $post['repassword']) {
+                $this->error('两次输入的密码不一致!');
+            }
+            $result = \app\admin\service\Auth::checkPassword($post['password']);
+            if (empty($result['code'])) $this->error($result['msg']);
+            $data = ['id' => $post['id'], 'password' => md5($post['password'])];
+            if (Data::save($this->table, $data, 'id')) {
+                $this->success('密码修改成功,下次请使用新密码登录!', '');
+            } else {
+                $this->error('密码修改失败,请稍候再试!');
+            }
         }
-        $this->error('密码修改失败,请稍候再试!');
     }
 
     /**
@@ -131,14 +116,9 @@ class User extends BasicAdmin
     public function _form_filter(&$data)
     {
         if ($this->request->isPost()) {
-            if (isset($data['authorize']) && is_array($data['authorize'])) {
-                $data['authorize'] = join(',', $data['authorize']);
-            } else {
-                $data['authorize'] = '';
-            }
-            if (isset($data['id'])) {
-                unset($data['username']);
-            } elseif (Db::name($this->table)->where(['username' => $data['username']])->count() > 0) {
+            $data['authorize'] = (isset($data['authorize']) && is_array($data['authorize'])) ? join(',', $data['authorize']) : '';
+            if (isset($data['id'])) unset($data['username']);
+            elseif (Db::name($this->table)->where(['username' => $data['username']])->count() > 0) {
                 $this->error('用户账号已经存在,请使用其它账号!');
             }
         } else {
@@ -149,47 +129,35 @@ class User extends BasicAdmin
 
     /**
      * 删除用户
-     * @throws \think\Exception
-     * @throws \think\exception\PDOException
      */
     public function del()
     {
         if (in_array('10000', explode(',', $this->request->post('id')))) {
             $this->error('系统超级账号禁止删除!');
         }
-        if (DataService::update($this->table)) {
-            $this->success("用户删除成功!", '');
-        }
-        $this->error("用户删除失败,请稍候再试!");
+        $this->applyCsrfToken();
+        $this->_delete($this->table);
     }
 
     /**
      * 用户禁用
-     * @throws \think\Exception
-     * @throws \think\exception\PDOException
      */
     public function forbid()
     {
         if (in_array('10000', explode(',', $this->request->post('id')))) {
             $this->error('系统超级账号禁止操作!');
         }
-        if (DataService::update($this->table)) {
-            $this->success("用户禁用成功!", '');
-        }
-        $this->error("用户禁用失败,请稍候再试!");
+        $this->applyCsrfToken();
+        $this->_save($this->table, ['status' => '0']);
     }
 
     /**
      * 用户禁用
-     * @throws \think\Exception
-     * @throws \think\exception\PDOException
      */
     public function resume()
     {
-        if (DataService::update($this->table)) {
-            $this->success("用户启用成功!", '');
-        }
-        $this->error("用户启用失败,请稍候再试!");
+        $this->applyCsrfToken();
+        $this->_save($this->table, ['status' => '1']);
     }
 
 }

+ 53 - 0
application/admin/controller/api/Message.php

@@ -0,0 +1,53 @@
+<?php
+
+// +----------------------------------------------------------------------
+// | framework
+// +----------------------------------------------------------------------
+// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// +----------------------------------------------------------------------
+// | 官方网站: http://framework.thinkadmin.top
+// +----------------------------------------------------------------------
+// | 开源协议 ( https://mit-license.org )
+// +----------------------------------------------------------------------
+// | github开源项目:https://github.com/zoujingli/ThinkAdmin
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\api;
+
+use library\Controller;
+
+/**
+ * Class Message
+ * @package app\admin\controller\api
+ */
+class Message extends Controller
+{
+
+    /**
+     * 获取系统消息列表
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function gets()
+    {
+        $list = \app\admin\service\Message::gets();
+        $this->success('获取系统消息成功!', $list);
+    }
+
+    /**
+     * 系统消息状态更新
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function set()
+    {
+        $code = $this->request->post('code');
+        if (\app\admin\service\Message::set($code)) {
+            $this->success('系统消息状态更新成功!');
+        } else {
+            $this->error('系统消息状态更新失败,请稍候再试!');
+        }
+    }
+
+}

+ 217 - 0
application/admin/controller/api/Plugs.php

@@ -0,0 +1,217 @@
+<?php
+
+// +----------------------------------------------------------------------
+// | framework
+// +----------------------------------------------------------------------
+// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// +----------------------------------------------------------------------
+// | 官方网站: http://framework.thinkadmin.top
+// +----------------------------------------------------------------------
+// | 开源协议 ( https://mit-license.org )
+// +----------------------------------------------------------------------
+// | github开源项目:https://github.com/zoujingli/ThinkAdmin
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\api;
+
+use library\Controller;
+use library\File;
+use think\Db;
+
+/**
+ * 后台插件管理
+ * Class Plugs
+ * @package app\admin\controller\api
+ */
+class Plugs extends Controller
+{
+
+    /**
+     * Plugs constructor.
+     */
+    public function __construct()
+    {
+        parent::__construct();
+        if (!\app\admin\service\Auth::isLogin()) {
+            $this->error('访问授权失败,请重新登录授权再试!');
+        }
+    }
+
+    /**
+     * 文件状态检查
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function upstate()
+    {
+        $ext = strtolower(pathinfo($this->request->post('filename', ''), PATHINFO_EXTENSION));
+        $name = File::name($this->request->post('md5'), $ext, '', 'strtolower');
+        // 检查文件是否已上传
+        $this->safe = $this->getUploadSafe();
+        if (is_string($siteUrl = File::url($name))) {
+            $this->success('检测到该文件已经存在,无需再次上传!', [
+                'site_url' => $this->safe ? $name : $siteUrl,
+            ]);
+        }
+        // 文件驱动
+        $file = File::instance($this->getUploadType());
+        // 生成上传授权参数
+        $param = [
+            'file_url' => $name, 'uptype' => $this->uptype, 'token' => md5($name . session_id()),
+            'site_url' => $file->base($name), 'server' => $file->upload(), 'safe' => $this->safe,
+        ];
+        if (strtolower($this->uptype) === 'qiniu') {
+            $auth = new \Qiniu\Auth(sysconf('storage_qiniu_access_key'), sysconf('storage_qiniu_secret_key'));
+            $param['token'] = $auth->uploadToken(sysconf('storage_qiniu_bucket'), $name, 3600, [
+                'returnBody' => json_encode(['code' => 1, 'data' => ['site_url' => $file->base($name)]], JSON_UNESCAPED_UNICODE),
+            ]);
+        } elseif (strtolower($this->uptype) === 'oss') {
+            $param['OSSAccessKeyId'] = sysconf('storage_oss_keyid');
+            $param['policy'] = base64_encode(json_encode(['conditions' => [['content-length-range', 0, 1048576000]], 'expiration' => gmdate("Y-m-d\TH:i:s\Z", time() + 3600)]));
+            $param['signature'] = base64_encode(hash_hmac('sha1', $param['policy'], sysconf('storage_oss_secret'), true));
+        }
+        $this->error('未检测到文件,需要上传完整的文件!', $param);
+    }
+
+    /**
+     * 文件上传
+     * @return mixed
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function upfile()
+    {
+        $this->safe = $this->getUploadSafe();
+        $this->uptype = $this->getUploadType();
+        $this->mode = $this->request->get('mode', 'one');
+        $this->field = $this->request->get('field', 'file');
+        $this->types = $this->request->get('type', 'jpg,png');
+        $this->mimes = File::mine($this->types);
+        $this->fetch();
+    }
+
+    /**
+     * WebUpload 文件上传
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function upload()
+    {
+        // 文件接收
+        if (!($file = $this->getUploadFile()) || empty($file)) {
+            $this->error('文件上传异常,文件可能过大或未上传!');
+        }
+        if (!$file->checkExt(strtolower(sysconf('storage_local_exts')))) {
+            $this->error('文件上传类型受限,请在后台配置!');
+        }
+        if ($file->checkExt('php')) {
+            $this->error('可执行文件禁止上传到本地服务器!');
+        }
+        // 唯一名称
+        $ext = strtolower(pathinfo($file->getInfo('name'), PATHINFO_EXTENSION));
+        $name = File::name($this->request->post('md5'), $ext, '', 'strtolower');
+        // Token 验证
+        if ($this->request->post('token') !== md5($name . session_id())) {
+            $this->error('文件上传验证失败,请刷新页面重新上传!');
+        }
+        $this->safe = $this->getUploadSafe();
+        $pathinfo = pathinfo(File::instance('local')->path($name, $this->safe));
+        if ($file->move($pathinfo['dirname'], $pathinfo['basename'], true)) {
+            if (is_array($info = File::instance('local')->info($name, $this->safe)) && isset($info['url'])) {
+                $this->success('文件上传成功!', ['site_url' => $this->safe ? $name : $info['url']]);
+            }
+        }
+        $this->error('文件上传失败,请稍候再试!');
+    }
+
+    /**
+     * Plupload 插件上传文件
+     * @return \think\response\Json
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function plupload()
+    {
+        if (!($file = $this->getUploadFile()) || empty($file)) {
+            return json(['uploaded' => false, 'error' => ['message' => '文件上传异常,文件可能过大或未上传']]);
+        }
+        if (!$file->checkExt(strtolower(sysconf('storage_local_exts')))) {
+            return json(['uploaded' => false, 'error' => ['message' => '文件上传类型受限,请在后台配置']]);
+        }
+        if ($file->checkExt('php')) {
+            return json(['uploaded' => false, 'error' => ['message' => '可执行文件禁止上传到本地服务器']]);
+        }
+        $this->safe = $this->getUploadSafe();
+        $this->uptype = $this->getUploadType();
+        $this->ext = pathinfo($file->getInfo('name'), PATHINFO_EXTENSION);
+        $name = File::name($file->getPathname(), $this->ext, '', 'md5_file');
+        $info = File::instance($this->uptype)->save($name, file_get_contents($file->getRealPath()), $this->safe);
+        if (is_array($info) && isset($info['url'])) {
+            return json(['uploaded' => true, 'filename' => $name, 'url' => $this->safe ? $name : $info['url']]);
+        }
+        return json(['uploaded' => false, 'error' => ['message' => '文件处理失败,请稍候再试!']]);
+    }
+
+    /**
+     * 获取文件上传方式
+     * @return string
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    private function getUploadType()
+    {
+        $this->uptype = input('uptype');
+        if (!in_array($this->uptype, ['local', 'oss', 'qiniu'])) {
+            $this->uptype = sysconf('storage_type');
+        }
+        return $this->uptype;
+    }
+
+    /**
+     * 获取上传安全模式
+     * @return boolean
+     */
+    private function getUploadSafe()
+    {
+        return $this->safe = boolval(input('safe'));
+    }
+
+    /**
+     * 获取本地文件对象
+     * @return \think\File
+     */
+    private function getUploadFile()
+    {
+        try {
+            return $this->request->file('file');
+        } catch (\Exception $e) {
+            $this->error(lang($e->getMessage()));
+        }
+    }
+
+    /**
+     * 系统选择器图标
+     * @return mixed
+     */
+    public function icon()
+    {
+        $this->title = '图标选择器';
+        $this->field = input('field', 'icon');
+        $this->fetch();
+    }
+
+    /**
+     * 系统消息展示
+     * @return mixed
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function message()
+    {
+        $this->title = '系统消息';
+        $this->list = Db::name('SystemMessage')->where(['read_state' => '0'])->order('id desc')->select();
+        $this->fetch();
+    }
+
+}

+ 54 - 0
application/admin/controller/api/Update.php

@@ -0,0 +1,54 @@
+<?php
+
+// +----------------------------------------------------------------------
+// | framework
+// +----------------------------------------------------------------------
+// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// +----------------------------------------------------------------------
+// | 官方网站: http://framework.thinkadmin.top
+// +----------------------------------------------------------------------
+// | 开源协议 ( https://mit-license.org )
+// +----------------------------------------------------------------------
+// | github开源项目:https://github.com/zoujingli/ThinkAdmin
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\api;
+
+use library\command\Sync as UpdateLogic;
+use library\Controller;
+
+/**
+ * 系统更新接口
+ * Class Update
+ * @package app\admin\controller\api
+ */
+class Update extends Controller
+{
+    /**
+     * 基础URL地址
+     * @var string
+     */
+    protected $baseUri = 'https://framework.thinkadmin.top';
+
+    /**
+     * 获取文件列表
+     */
+    public function tree()
+    {
+        $this->success('获取当前文件列表成功!', UpdateLogic::build());
+    }
+
+    /**
+     * 读取线上文件数据
+     * @param string $encode
+     */
+    public function read($encode)
+    {
+        $file = env('root_path') . decode($encode);
+        if (!file_exists($file)) $this->error('获取文件内容失败!');
+        $this->success('获取文件内容成功!', [
+            'format' => 'base64', 'content' => base64_encode(file_get_contents($file)),
+        ]);
+    }
+
+}

+ 0 - 71
application/admin/middleware/Auth.php

@@ -1,71 +0,0 @@
-<?php
-
-// +----------------------------------------------------------------------
-// | ThinkAdmin
-// +----------------------------------------------------------------------
-// | 版权所有 2014~2017 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
-// +----------------------------------------------------------------------
-// | 官方网站: http://think.ctolog.com
-// +----------------------------------------------------------------------
-// | 开源协议 ( https://mit-license.org )
-// +----------------------------------------------------------------------
-// | github开源项目:https://github.com/zoujingli/ThinkAdmin
-// +----------------------------------------------------------------------
-
-namespace app\admin\middleware;
-
-use service\NodeService;
-use think\Db;
-use think\Request;
-
-/**
- * 系统权限访问管理
- * Class Auth
- * @package app\admin\middleware
- */
-class Auth
-{
-    /**
-     * @param Request $request
-     * @param \Closure $next
-     * @return mixed
-     * @throws \think\db\exception\DataNotFoundException
-     * @throws \think\db\exception\ModelNotFoundException
-     * @throws \think\exception\DbException
-     */
-    public function handle($request, \Closure $next)
-    {
-        list($module, $controller, $action) = [$request->module(), $request->controller(), $request->action()];
-        $access = $this->buildAuth($node = NodeService::parseNodeStr("{$module}/{$controller}/{$action}"));
-        // 登录状态检查
-        if (!empty($access['is_login']) && !session('user')) {
-            $msg = ['code' => 0, 'msg' => '抱歉,您还没有登录获取访问权限!', 'url' => url('@admin/login')];
-            return $request->isAjax() ? json($msg) : redirect($msg['url']);
-        }
-        // 访问权限检查
-        if (!empty($access['is_auth']) && !auth($node)) {
-            return json(['code' => 0, 'msg' => '抱歉,您没有访问该模块的权限!']);
-        }
-        // 模板常量声明
-        app('view')->init(config('template.'))->assign(['classuri' => NodeService::parseNodeStr("{$module}/{$controller}")]);
-        return $next($request);
-    }
-
-    /**
-     * 根据节点获取对应权限配置
-     * @param string $node 权限节点
-     * @return array
-     * @throws \think\db\exception\DataNotFoundException
-     * @throws \think\db\exception\ModelNotFoundException
-     * @throws \think\exception\DbException
-     */
-    private function buildAuth($node)
-    {
-        $info = Db::name('SystemNode')->cache(true, 30)->where(['node' => $node])->find();
-        return [
-            'is_menu'  => intval(!empty($info['is_menu'])),
-            'is_auth'  => intval(!empty($info['is_auth'])),
-            'is_login' => empty($info['is_auth']) ? intval(!empty($info['is_login'])) : 1,
-        ];
-    }
-}

+ 122 - 0
application/admin/queue/JobsBase.php

@@ -0,0 +1,122 @@
+<?php
+
+// +----------------------------------------------------------------------
+// | framework
+// +----------------------------------------------------------------------
+// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// +----------------------------------------------------------------------
+// | 官方网站: http://framework.thinkadmin.top
+// +----------------------------------------------------------------------
+// | 开源协议 ( https://mit-license.org )
+// +----------------------------------------------------------------------
+// | github开源项目:https://github.com/zoujingli/ThinkAdmin
+// +----------------------------------------------------------------------
+
+namespace app\admin\queue;
+
+use app\admin\service\Queue;
+
+/**
+ * 基础指令公共类
+ * Class QueueBase
+ * @package app\admin
+ */
+class JobsBase
+{
+    /**
+     * 待处理
+     */
+    const STATUS_PEND = 1;
+
+    /**
+     * 处理中
+     */
+    const STATUS_PROC = 2;
+
+    /**
+     * 处理完成
+     */
+    const STATUS_COMP = 3;
+
+    /**
+     * 处理失败
+     */
+    const STATUS_FAIL = 4;
+
+    /**
+     * 任务ID
+     * @var integer
+     */
+    protected $id;
+
+    /**
+     * 任务数据
+     * @var array
+     */
+    protected $data;
+
+    /**
+     * 任务名称
+     * @var string
+     */
+    protected $title;
+
+    /**
+     * 任务状态
+     * @var integer
+     */
+    protected $status;
+
+    /**
+     * @var \think\console\Output
+     */
+    protected $output;
+
+    /**
+     * 任务状态描述
+     * @var string
+     */
+    protected $statusDesc = '';
+
+    /**
+     * 启动任务处理
+     * @param \think\queue\Job $job 当前任务对象
+     * @param array $data 任务执行对象
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function fire(\think\queue\Job $job, $data = [])
+    {
+        $this->data = $data;
+        $this->output = new \think\console\Output();
+        $this->id = isset($data['_job_id_']) ? $data['_job_id_'] : '';
+        $this->title = isset($data['_job_title_']) ? $data['_job_title_'] : '';
+        $this->output->newLine();
+        $this->output->writeln("       system task {$this->id} execution start");
+        $this->output->writeln('---------------------------------------------');
+        Queue::status($this->id, self::STATUS_PROC, $this->statusDesc);
+        if ($this->execute()) {
+            $this->output->writeln('---------------------------------------------');
+            $this->output->info("                successful");
+            $this->status = self::STATUS_COMP;
+        } else {
+            $this->output->writeln('---------------------------------------------');
+            $this->output->error("                failure");
+            $this->status = self::STATUS_FAIL;
+        }
+        $job->delete();
+        Queue::status($this->id, $this->status, $this->statusDesc);
+        $this->output->writeln('---------------------------------------------');
+        $this->output->newLine();
+    }
+
+    /**
+     * 执行任务
+     * @return boolean
+     */
+    protected function execute()
+    {
+        return true;
+    }
+
+}

+ 207 - 0
application/admin/service/Auth.php

@@ -0,0 +1,207 @@
+<?php
+
+// +----------------------------------------------------------------------
+// | framework
+// +----------------------------------------------------------------------
+// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// +----------------------------------------------------------------------
+// | 官方网站: http://framework.thinkadmin.top
+// +----------------------------------------------------------------------
+// | 开源协议 ( https://mit-license.org )
+// +----------------------------------------------------------------------
+// | github开源项目:https://github.com/zoujingli/ThinkAdmin
+// +----------------------------------------------------------------------
+
+namespace app\admin\service;
+
+use library\tools\Data;
+use library\tools\Node;
+use think\Db;
+
+/**
+ * 权限访问及菜单管理
+ * Class Auth
+ * @package app\admin\service
+ */
+class Auth
+{
+
+    /**
+     * 权限检查中间件入口
+     * @param \think\Request $request
+     * @param \Closure $next
+     * @return mixed|\think\response\Json|\think\response\Redirect
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
+     */
+    public function handle(\think\Request $request, \Closure $next)
+    {
+        // 系统消息处理
+        if (($code = $request->get('messagecode')) > 0) Message::set($code);
+        // 节点忽略跳过
+        $node = Node::current();
+        foreach (self::getIgnore() as $str) if (stripos($node, $str) === 0) return $next($request);
+        // 节点权限查询
+        $auth = Db::name('SystemNode')->cache(true, 60)->field('is_auth,is_login')->where(['node' => $node])->find();
+        $info = ['is_auth' => $auth['is_auth'], 'is_login' => $auth['is_auth'] ? 1 : $auth['is_login']];
+        // 登录状态检查
+        if (!empty($info['is_login']) && !self::isLogin()) {
+            $message = ['code' => 0, 'msg' => '抱歉,您还没有登录获取访问权限!', 'url' => url('@admin/login')];
+            return $request->isAjax() ? json($message) : redirect($message['url']);
+        }
+        // 访问权限检查
+        if (!empty($info['is_auth']) && !self::checkAuthNode($node)) {
+            return json(['code' => 0, 'msg' => '抱歉,您没有访问该模块的权限!']);
+        }
+        return $next($request);
+    }
+
+    /**
+     * 权限节点忽略规则
+     * @return array
+     */
+    public static function getIgnore()
+    {
+        return ['index', 'admin/login', 'admin/index'];
+    }
+
+    /**
+     * 获取系统代码节点
+     * @param array $nodes
+     * @return array
+     */
+    public static function get($nodes = [])
+    {
+        $ignore = self::getIgnore();
+        $alias = Db::name('SystemNode')->column('node,is_menu,is_auth,is_login,title');
+        foreach (Node::getTree(env('app_path')) as $thr) {
+            foreach ($ignore as $str) if (stripos($thr, $str) === 0) continue 2;
+            $tmp = explode('/', $thr);
+            list($one, $two) = ["{$tmp[0]}", "{$tmp[0]}/{$tmp[1]}"];
+            $nodes[$one] = array_merge(isset($alias[$one]) ? $alias[$one] : ['node' => $one, 'title' => '', 'is_menu' => 0, 'is_auth' => 0, 'is_login' => 0], ['pnode' => '']);
+            $nodes[$two] = array_merge(isset($alias[$two]) ? $alias[$two] : ['node' => $two, 'title' => '', 'is_menu' => 0, 'is_auth' => 0, 'is_login' => 0], ['pnode' => $one]);
+            $nodes[$thr] = array_merge(isset($alias[$thr]) ? $alias[$thr] : ['node' => $thr, 'title' => '', 'is_menu' => 0, 'is_auth' => 0, 'is_login' => 0], ['pnode' => $two]);
+        }
+        foreach ($nodes as &$node) list($node['is_auth'], $node['is_menu'], $node['is_login']) = [intval($node['is_auth']), intval($node['is_menu']), empty($node['is_auth']) ? intval($node['is_login']) : 1];
+        return $nodes;
+    }
+
+    /**
+     * 检查用户节点权限
+     * @param string $node 节点
+     * @return boolean
+     */
+    public static function checkAuthNode($node)
+    {
+        list($module, $controller, $action) = explode('/', str_replace(['?', '=', '&'], '/', "{$node}///"));
+        $current = Node::parseString("{$module}/{$controller}") . strtolower("/{$action}");
+        // 后台入口无需要验证权限
+        if (stripos($node, 'admin/index') === 0) return true;
+        // 超级管理员无需要验证权限
+        if (session('user.username') === 'admin') return true;
+        // 未配置权限的节点默认放行
+        if (!in_array($current, self::getAuthNode())) return true;
+        // 用户指定角色授权放行
+        return in_array($current, (array)session('user.nodes'));
+    }
+
+    /**
+     * 获取授权节点
+     * @return array
+     */
+    public static function getAuthNode()
+    {
+        $nodes = cache('need_access_node');
+        if (empty($nodes)) {
+            $nodes = Db::name('SystemNode')->where(['is_auth' => '1'])->column('node');
+            cache('need_access_node', $nodes);
+        }
+        return $nodes;
+    }
+
+    /**
+     * 应用用户权限节点
+     * @return bool
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public static function applyNode()
+    {
+        cache('need_access_node', null);
+        if (($uid = session('user.id'))) session('user', Db::name('SystemUser')->where('id', $uid)->find());
+        if (session('user.authorize') && ($ids = explode(',', session('user.authorize')))) {
+            $auths = Db::name('SystemAuth')->whereIn('id', $ids)->where('status', '1')->column('id');
+            if (empty($auths)) return session('user.nodes', []);
+            return session('user.nodes', Db::name('SystemAuthNode')->whereIn('auth', $auths)->column('node'));
+        }
+        return false;
+    }
+
+    /**
+     * 判断用户登录状态
+     * @return boolean
+     */
+    public static function isLogin()
+    {
+        return !!session('user');
+    }
+
+    /**
+     * 获取授权后的菜单
+     * @return array
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public static function getAuthMenu()
+    {
+        self::applyNode();
+        $list = Db::name('SystemMenu')->where('status', '1')->order('sort asc,id asc')->select();
+        return self::buildMenuData(Data::arr2tree($list), self::get(), self::isLogin());
+    }
+
+    /**
+     * 后台主菜单权限过滤
+     * @param array $menus 当前菜单列表
+     * @param array $nodes 系统权限节点数据
+     * @param bool $isLogin 是否已经登录
+     * @return array
+     */
+    private static function buildMenuData($menus, $nodes, $isLogin)
+    {
+        foreach ($menus as $key => &$menu) {
+            if (!empty($menu['sub'])) $menu['sub'] = self::buildMenuData($menu['sub'], $nodes, $isLogin);
+            if (!empty($menu['sub'])) $menu['url'] = '#';
+            elseif (preg_match('/^https?\:/i', $menu['url'])) continue;
+            elseif ($menu['url'] !== '#') {
+                $node = join('/', array_slice(explode('/', preg_replace('/[\W]/', '/', $menu['url'])), 0, 3));
+                $menu['url'] = url($menu['url']) . (empty($menu['params']) ? '' : "?{$menu['params']}");
+                if (isset($nodes[$node]) && $nodes[$node]['is_login'] && empty($isLogin)) unset($menus[$key]);
+                elseif (isset($nodes[$node]) && $nodes[$node]['is_auth'] && $isLogin && !self::checkAuthNode($node)) unset($menus[$key]);
+            } else unset($menus[$key]);
+        }
+        return $menus;
+    }
+
+    /**
+     * 检查密码是否合法
+     * @param string $password
+     * @return array
+     */
+    public static function checkPassword($password)
+    {
+        $password = trim($password);
+        if (!strlen($password) >= 6) {
+            return ['code' => 0, 'msg' => '密码必须大于6字符!'];
+        }
+        if (!preg_match("/^(?![\d]+$)(?![a-zA-Z]+$)(?![^\da-zA-Z]+$).{6,32}$/", $password)) {
+            return ['code' => 0, 'msg' => '密码必需包含大小写字母、数字、符号任意两者组合!'];
+        }
+        return ['code' => 1, 'msg' => '密码复杂度通过验证!'];
+    }
+
+}

+ 55 - 0
application/admin/service/Log.php

@@ -0,0 +1,55 @@
+<?php
+
+// +----------------------------------------------------------------------
+// | framework
+// +----------------------------------------------------------------------
+// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// +----------------------------------------------------------------------
+// | 官方网站: http://framework.thinkadmin.top
+// +----------------------------------------------------------------------
+// | 开源协议 ( https://mit-license.org )
+// +----------------------------------------------------------------------
+// | github开源项目:https://github.com/zoujingli/ThinkAdmin
+// +----------------------------------------------------------------------
+
+namespace app\admin\service;
+
+use library\tools\Node;
+use think\Db;
+
+/**
+ * 系统日志服务管理
+ * Class Log
+ * @package app\admin\service
+ */
+class Log
+{
+    /**
+     * 写入操作日志
+     * @param string $action
+     * @param string $content
+     * @return bool
+     */
+    public static function write($action = '行为', $content = "内容描述")
+    {
+        $data = [
+            'node'     => Node::current(),
+            'geoip'    => PHP_SAPI === 'cli' ? '127.0.0.1' : request()->ip(),
+            'action'   => $action,
+            'content'  => $content,
+            'username' => PHP_SAPI === 'cli' ? 'cli' : session('user.username'),
+        ];
+        return Db::name('SystemLog')->insert($data) !== false;
+    }
+
+    /**
+     * 清理系统日志数据
+     * @return boolean
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public static function clear()
+    {
+        return Db::name('SystemLog')->where('1=1')->delete() !== false;
+    }
+}

+ 72 - 0
application/admin/service/Message.php

@@ -0,0 +1,72 @@
+<?php
+
+// +----------------------------------------------------------------------
+// | framework
+// +----------------------------------------------------------------------
+// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// +----------------------------------------------------------------------
+// | 官方网站: http://framework.thinkadmin.top
+// +----------------------------------------------------------------------
+// | 开源协议 ( https://mit-license.org )
+// +----------------------------------------------------------------------
+// | github开源项目:https://github.com/zoujingli/ThinkAdmin
+// +----------------------------------------------------------------------
+
+namespace app\admin\service;
+
+use library\tools\Data;
+use think\Db;
+
+/**
+ * 系统消息管理
+ * Class Message
+ * @package app\admin\service
+ */
+class Message
+{
+    /**
+     * 增加系统消息
+     * @param string $title 消息标题
+     * @param string $desc 消息描述
+     * @param string $url 访问链接
+     * @param string $node 权限节点
+     * @return boolean
+     */
+    public static function add($title, $desc, $url, $node)
+    {
+        $code = Data::uniqidNumberCode(12);
+        $data = ['title' => $title, 'desc' => $desc, 'url' => $url, 'code' => $code, 'node' => $node];
+        return Db::name('SystemMessage')->insert($data) !== false;
+    }
+
+    /**
+     * 系统消息状态更新
+     * @param integer $code
+     * @return boolean
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public static function set($code)
+    {
+        $result = Db::name('SystemMessage')->where(['code' => $code, 'read_state' => '0'])->update([
+            'read_state' => '1', 'read_at' => date('Y-m-d H:i:s'), 'read_uid' => session('user.id'),
+        ]);
+        return $result !== false;
+    }
+
+    /**
+     * 获取消息列表成功
+     * @return array
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public static function gets()
+    {
+        $where = ['read_state' => '0'];
+        $list = Db::name('SystemMessage')->where($where)->order('id desc')->select();
+        foreach ($list as $key => $vo) if (!empty($vo['node']) && !auth($vo['node'])) unset($list[$key]);
+        return $list;
+    }
+
+}

+ 128 - 0
application/admin/service/Queue.php

@@ -0,0 +1,128 @@
+<?php
+
+// +----------------------------------------------------------------------
+// | framework
+// +----------------------------------------------------------------------
+// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// +----------------------------------------------------------------------
+// | 官方网站: http://framework.thinkadmin.top
+// +----------------------------------------------------------------------
+// | 开源协议 ( https://mit-license.org )
+// +----------------------------------------------------------------------
+// | github开源项目:https://github.com/zoujingli/ThinkAdmin
+// +----------------------------------------------------------------------
+
+namespace app\admin\service;
+
+use think\Db;
+
+/**
+ * 任务管理器
+ * Class Queue
+ * @package app\admin\service
+ */
+class Queue
+{
+    /**
+     * 待处理
+     */
+    const STATUS_PEND = 1;
+
+    /**
+     * 处理中
+     */
+    const STATUS_PROC = 2;
+
+    /**
+     * 处理完成
+     */
+    const STATUS_COMP = 3;
+
+    /**
+     * 处理失败
+     */
+    const STATUS_FAIL = 4;
+
+    /**
+     * 创建任务并记录日志
+     * @param string $title 任务名称
+     * @param string $uri 任务命令
+     * @param integer $later 延时时间
+     * @param array $data 任务附加数据
+     * @param integer $double 任务多开
+     * @param string $desc 任务描述
+     * @throws \think\Exception
+     */
+    public static function add($title, $uri, $later, array $data, $double = 1, $desc = '')
+    {
+        if (empty($double) && self::exists($title)) {
+            throw new \think\Exception('该任务已经创建,请耐心等待处理完成!');
+        }
+        $jobId = Db::name('SystemJobsLog')->insertGetId([
+            'title' => $title, 'later' => $later, 'uri' => $uri, 'double' => intval($double),
+            'data'  => json_encode($data, 256), 'desc' => $desc, 'status_at' => date('Y-m-d H:i:s'),
+        ]);
+        $data['_job_id_'] = $jobId;
+        $data['_job_title_'] = $title;
+        \think\Queue::later($later, $uri, $data);
+    }
+
+    /**
+     * 更新任务状态
+     * @param integer $jobId
+     * @param integer $status
+     * @param string $statusDesc
+     * @return boolean
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public static function status($jobId, $status = self::STATUS_PEND, $statusDesc = '')
+    {
+        $result = Db::name('SystemJobsLog')->where(['id' => $jobId])->update([
+            'status' => $status, 'status_desc' => $statusDesc, 'status_at' => date('Y-m-d H:i:s'),
+        ]);
+        return $result !== false;
+    }
+
+    /**
+     * 检查任务是否存在
+     * @param string $title
+     * @return boolean
+     */
+    public static function exists($title)
+    {
+        $where = [['title', 'eq', $title], ['status', 'in', [1, 2]]];
+        return Db::name('SystemJobsLog')->where($where)->count() > 0;
+    }
+
+    /**
+     * 获取任务数据
+     * @param integer $jobId
+     * @return array|null
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public static function get($jobId)
+    {
+        return Db::name('SystemJobsLog')->where(['id' => $jobId])->find();
+    }
+
+    /**
+     * 删除任务数据
+     * @param integer $jobId
+     * @return boolean
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public static function del($jobId)
+    {
+        $where = [['id', 'eq', $jobId], ['status', 'in', [1, 3, 4]]];
+        if (Db::name('SystemJobsLog')->where($where)->delete() > 0) {
+            Db::name('SystemJobs')->whereLike('payload', '%"_job_id_":"' . $jobId . '"%')->delete();
+            return true;
+        }
+        return false;
+    }
+
+}

+ 111 - 0
application/admin/sys.php

@@ -0,0 +1,111 @@
+<?php
+
+// +----------------------------------------------------------------------
+// | framework
+// +----------------------------------------------------------------------
+// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// +----------------------------------------------------------------------
+// | 官方网站: http://framework.thinkadmin.top
+// +----------------------------------------------------------------------
+// | 开源协议 ( https://mit-license.org )
+// +----------------------------------------------------------------------
+// | github开源项目:https://github.com/zoujingli/ThinkAdmin
+// +----------------------------------------------------------------------
+
+if (!function_exists('auth')) {
+    /**
+     * 节点访问权限检查
+     * @param string $node
+     * @return boolean
+     */
+    function auth($node)
+    {
+        return \app\admin\service\Auth::checkAuthNode($node);
+    }
+}
+
+if (!function_exists('sysdata')) {
+    /**
+     * JSON 数据读取与存储
+     * @param string $name 数据名称
+     * @param array|null $value 数据内容
+     * @return mixed
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    function sysdata($name, array $value = null)
+    {
+        if (is_null($value)) {
+            $data = json_decode(\think\Db::name('SystemData')->where('name', $name)->value('value'), true);
+            return empty($data) ? [] : $data;
+        }
+        return data_save('SystemData', ['name' => $name, 'value' => json_encode($value, 256)], 'name');
+    }
+}
+
+if (!function_exists('_sysmsg')) {
+    /**
+     * 增加系统消息
+     * @param string $title 消息标题
+     * @param string $desc 消息描述
+     * @param string $url 访问链接
+     * @param string $node 权限节点
+     * @return boolean
+     */
+    function _sysmsg($title, $desc, $url, $node)
+    {
+        return \app\admin\service\Message::add($title, $desc, $url, $node);
+    }
+}
+
+if (!function_exists('_syslog')) {
+    /**
+     * 写入系统日志
+     * @param string $action 日志行为
+     * @param string $content 日志内容
+     * @return boolean
+     */
+    function _syslog($action, $content)
+    {
+        return \app\admin\service\Log::write($action, $content);
+    }
+}
+
+if (!function_exists('local_image')) {
+    /**
+     * 下载远程文件到本地
+     * @param string $url 远程图片地址
+     * @return string
+     */
+    function local_image($url)
+    {
+        $result = \library\File::down($url);
+        if (isset($result['url'])) return $result['url'];
+        return $url;
+    }
+}
+
+if (!function_exists('base64_image')) {
+    /**
+     * base64 图片上传接口
+     * @param string $content
+     * @param string $predir
+     * @return string
+     */
+    function base64_image($content, $predir = 'base64/')
+    {
+        try {
+            if (preg_match('|^data:image/(.*?);base64,|i', $content)) {
+                list($ext, $base) = explode('|||', preg_replace('|^data:image/(.*?);base64,|i', '$1|||', $content));
+                $info = \library\File::save($predir . md5($base) . '.' . (empty($ext) ? 'tmp' : $ext), base64_decode($base));
+                return $info['url'];
+            }
+            return $content;
+        } catch (\Exception $e) {
+            return $content;
+        }
+    }
+}
+
+// 注册中间键
+\think\facade\Middleware::add('app\admin\service\Auth');

+ 3659 - 0
application/admin/view/api/plugs/icon.html

@@ -0,0 +1,3659 @@
+<!DOCTYPE html>
+<html lang="zh-CN">
+<head>
+    <meta charset="utf-8">
+    <title>{block name="title"}{$title|default=''}{if !empty($title)} · {/if}{:sysconf('site_name')}{/block}</title>
+    <meta name="renderer" content="webkit">
+    <meta name="format-detection" content="telephone=no">
+    <meta name="apple-mobile-web-app-capable" content="yes">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+    <meta name="apple-mobile-web-app-status-bar-style" content="black">
+    <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1">
+    <link href="__ROOT__/static/plugs/awesome/fonts.css?v={:date('ymd')}" rel="stylesheet">
+    <link href="__ROOT__/static/plugs/layui/css/layui.css?v={:date('ymd')}" rel="stylesheet">
+
+    <style>
+        ::-webkit-input-placeholder {
+            color: #aaa
+        }
+
+        ::-webkit-scrollbar {
+            width: 3px;
+            height: 3px
+        }
+
+        ::-webkit-scrollbar-track {
+            background: #ccc
+        }
+
+        ::-webkit-scrollbar-thumb {
+            background-color: #666
+        }
+
+        ::selection {
+            background-color: #ec494e;
+            color: #fff
+        }
+
+        ::-moz-selection {
+            background-color: #ec494e;
+            color: #fff
+        }
+
+        :-webkit-autofill {
+            -webkit-box-shadow: 0 0 0 1000px white inset;
+            -webkit-text-fill-color: #333
+        }
+
+        ul li {
+            width: 20%;
+            height: 65px;
+            display: block;
+            float: left;
+            margin-right: -1px;
+            margin-left: -2px;
+            margin-bottom: -2px;
+            cursor: pointer;
+            font-size: 14px;
+            overflow: hidden;
+            text-align: center;
+            padding: 15px 0 10px 0;
+            border: 1px solid #e2e2e2;
+            background-color: #efefef;
+            user-select: none;
+            -ms-user-select: none;
+            -moz-user-select: none;
+            -webkit-user-select: none;
+            transition: all .2s linear;
+            -o-transition: all .2s linear;
+            -moz-transition: all .2s linear;
+            -webkit-transition: all .2s linear
+        }
+
+        ul li:hover {
+            color: #fff;
+            background-color: #563d7c
+        }
+
+        ul li:hover i, ul li:hover div {
+            color: #fff;
+        }
+
+        ul li i {
+            color: #333;
+            display: inline-block;
+            font-size: 30px !important
+        }
+
+        ul li div {
+            color: #333;
+            height: 35px;
+            font-size: 13px;
+            line-height: 35px;
+            white-space: nowrap
+        }
+    </style>
+</head>
+<body>
+<ul class="site-doc-icon">
+    <li>
+        <i class="layui-icon layui-icon-rate-half"></i>
+        <div class="icon-title">layui-icon-rate-half</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-rate"></i>
+        <div class="icon-title">layui-icon-rate</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-rate-solid"></i>
+        <div class="icon-title">layui-icon-rate-solid</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-cellphone"></i>
+        <div class="icon-title">layui-icon-cellphone</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-vercode"></i>
+        <div class="icon-title">layui-icon-vercode</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-login-wechat"></i>
+        <div class="icon-title">layui-icon-login-wechat</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-login-qq"></i>
+        <div class="icon-title">layui-icon-login-qq</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-login-weibo"></i>
+        <div class="icon-title">layui-icon-login-weibo</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-password"></i>
+        <div class="icon-title">layui-icon-password</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-username"></i>
+        <div class="icon-title">layui-icon-username</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-refresh-3"></i>
+        <div class="icon-title">layui-icon-refresh-3</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-auz"></i>
+        <div class="icon-title">layui-icon-auz</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-spread-left"></i>
+        <div class="icon-title">layui-icon-spread-left</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-shrink-right"></i>
+        <div class="icon-title">layui-icon-shrink-right</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-snowflake"></i>
+        <div class="icon-title">layui-icon-snowflake</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-tips"></i>
+        <div class="icon-title">layui-icon-tips</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-note"></i>
+        <div class="icon-title">layui-icon-note</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-home"></i>
+        <div class="icon-title">layui-icon-home</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-senior"></i>
+        <div class="icon-title">layui-icon-senior</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-refresh"></i>
+        <div class="icon-title">layui-icon-refresh</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-refresh-1"></i>
+        <div class="icon-title">layui-icon-refresh-1</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-flag"></i>
+        <div class="icon-title">layui-icon-flag</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-theme"></i>
+        <div class="icon-title">layui-icon-theme</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-notice"></i>
+        <div class="icon-title">layui-icon-notice</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-website"></i>
+        <div class="icon-title">layui-icon-website</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-console"></i>
+        <div class="icon-title">layui-icon-console</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-face-surprised"></i>
+        <div class="icon-title">layui-icon-face-surprised</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-set"></i>
+        <div class="icon-title">layui-icon-set</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-template-1"></i>
+        <div class="icon-title">layui-icon-template-1</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-app"></i>
+        <div class="icon-title">layui-icon-app</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-template"></i>
+        <div class="icon-title">layui-icon-template</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-praise"></i>
+        <div class="icon-title">layui-icon-praise</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-tread"></i>
+        <div class="icon-title">layui-icon-tread</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-male"></i>
+        <div class="icon-title">layui-icon-male</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-female"></i>
+        <div class="icon-title">layui-icon-female</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-camera"></i>
+        <div class="icon-title">layui-icon-camera</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-camera-fill"></i>
+        <div class="icon-title">layui-icon-camera-fill</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-more"></i>
+        <div class="icon-title">layui-icon-more</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-more-vertical"></i>
+        <div class="icon-title">layui-icon-more-vertical</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-rmb"></i>
+        <div class="icon-title">layui-icon-rmb</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-dollar"></i>
+        <div class="icon-title">layui-icon-dollar</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-diamond"></i>
+        <div class="icon-title">layui-icon-diamond</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-fire"></i>
+        <div class="icon-title">layui-icon-fire</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-return"></i>
+        <div class="icon-title">layui-icon-return</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-location"></i>
+        <div class="icon-title">layui-icon-location</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-read"></i>
+        <div class="icon-title">layui-icon-read</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-survey"></i>
+        <div class="icon-title">layui-icon-survey</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-face-smile"></i>
+        <div class="icon-title">layui-icon-face-smile</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-face-cry"></i>
+        <div class="icon-title">layui-icon-face-cry</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-cart-simple"></i>
+        <div class="icon-title">layui-icon-cart-simple</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-cart"></i>
+        <div class="icon-title">layui-icon-cart</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-next"></i>
+        <div class="icon-title">layui-icon-next</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-prev"></i>
+        <div class="icon-title">layui-icon-prev</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-upload-drag"></i>
+        <div class="icon-title">layui-icon-upload-drag</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-upload"></i>
+        <div class="icon-title">layui-icon-upload</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-download-circle"></i>
+        <div class="icon-title">layui-icon-download-circle</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-component"></i>
+        <div class="icon-title">layui-icon-component</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-file-b"></i>
+        <div class="icon-title">layui-icon-file-b</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-user"></i>
+        <div class="icon-title">layui-icon-user</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-find-fill"></i>
+        <div class="icon-title">layui-icon-find-fill</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-loading layui-icon layui-anim layui-anim-rotate layui-anim-loop"></i>
+        <div class="icon-title">layui-icon-loading</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-loading-1 layui-icon layui-anim layui-anim-rotate layui-anim-loop"></i>
+        <div class="icon-title">layui-icon-loading-1</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-add-1"></i>
+        <div class="icon-title">layui-icon-add-1</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-play"></i>
+        <div class="icon-title">layui-icon-play</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-pause"></i>
+        <div class="icon-title">layui-icon-pause</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-headset"></i>
+        <div class="icon-title">layui-icon-headset</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-video"></i>
+        <div class="icon-title">layui-icon-video</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-voice"></i>
+        <div class="icon-title">layui-icon-voice</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-speaker"></i>
+        <div class="icon-title">layui-icon-speaker</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-fonts-del"></i>
+        <div class="icon-title">layui-icon-fonts-del</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-fonts-code"></i>
+        <div class="icon-title">layui-icon-fonts-code</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-fonts-html"></i>
+        <div class="icon-title">layui-icon-fonts-html</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-fonts-strong"></i>
+        <div class="icon-title">layui-icon-fonts-strong</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-unlink"></i>
+        <div class="icon-title">layui-icon-unlink</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-picture"></i>
+        <div class="icon-title">layui-icon-picture</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-link"></i>
+        <div class="icon-title">layui-icon-link</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-face-smile-b"></i>
+        <div class="icon-title">layui-icon-face-smile-b</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-align-left"></i>
+        <div class="icon-title">layui-icon-align-left</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-align-right"></i>
+        <div class="icon-title">layui-icon-align-right</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-align-center"></i>
+        <div class="icon-title">layui-icon-align-center</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-fonts-u"></i>
+        <div class="icon-title">layui-icon-fonts-u</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-fonts-i"></i>
+        <div class="icon-title">layui-icon-fonts-i</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-tabs"></i>
+        <div class="icon-title">layui-icon-tabs</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-radio"></i>
+        <div class="icon-title">layui-icon-radio</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-circle"></i>
+        <div class="icon-title">layui-icon-circle</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-edit"></i>
+        <div class="icon-title">layui-icon-edit</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-share"></i>
+        <div class="icon-title">layui-icon-share</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-delete"></i>
+        <div class="icon-title">layui-icon-delete</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-form"></i>
+        <div class="icon-title">layui-icon-form</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-cellphone-fine"></i>
+        <div class="icon-title">layui-icon-cellphone-fine</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-dialogue"></i>
+        <div class="icon-title">layui-icon-dialogue</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-fonts-clear"></i>
+        <div class="icon-title">layui-icon-fonts-clear</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-layer"></i>
+        <div class="icon-title">layui-icon-layer</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-date"></i>
+        <div class="icon-title">layui-icon-date</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-water"></i>
+        <div class="icon-title">layui-icon-water</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-code-circle"></i>
+        <div class="icon-title">layui-icon-code-circle</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-carousel"></i>
+        <div class="icon-title">layui-icon-carousel</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-prev-circle"></i>
+        <div class="icon-title">layui-icon-prev-circle</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-layouts"></i>
+        <div class="icon-title">layui-icon-layouts</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-util"></i>
+        <div class="icon-title">layui-icon-util</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-templeate-1"></i>
+        <div class="icon-title">layui-icon-templeate-1</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-upload-circle"></i>
+        <div class="icon-title">layui-icon-upload-circle</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-tree"></i>
+        <div class="icon-title">layui-icon-tree</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-table"></i>
+        <div class="icon-title">layui-icon-table</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-chart"></i>
+        <div class="icon-title">layui-icon-chart</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-chart-screen"></i>
+        <div class="icon-title">layui-icon-chart-screen</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-engine"></i>
+        <div class="icon-title">layui-icon-engine</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-triangle-d"></i>
+        <div class="icon-title">layui-icon-triangle-d</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-triangle-r"></i>
+        <div class="icon-title">layui-icon-triangle-r</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-file"></i>
+        <div class="icon-title">layui-icon-file</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-set-sm"></i>
+        <div class="icon-title">layui-icon-set-sm</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-add-circle"></i>
+        <div class="icon-title">layui-icon-add-circle</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-404"></i>
+        <div class="icon-title">layui-icon-404</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-about"></i>
+        <div class="icon-title">layui-icon-about</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-up"></i>
+        <div class="icon-title">layui-icon-up</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-down"></i>
+        <div class="icon-title">layui-icon-down</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-left"></i>
+        <div class="icon-title">layui-icon-left</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-right"></i>
+        <div class="icon-title">layui-icon-right</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-circle-dot"></i>
+        <div class="icon-title">layui-icon-circle-dot</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-search"></i>
+        <div class="icon-title">layui-icon-search</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-set-fill"></i>
+        <div class="icon-title">layui-icon-set-fill</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-group"></i>
+        <div class="icon-title">layui-icon-group</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-friends"></i>
+        <div class="icon-title">layui-icon-friends</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-reply-fill"></i>
+        <div class="icon-title">layui-icon-reply-fill</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-menu-fill"></i>
+        <div class="icon-title">layui-icon-menu-fill</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-log"></i>
+        <div class="icon-title">layui-icon-log</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-picture-fine"></i>
+        <div class="icon-title">layui-icon-picture-fine</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-face-smile-fine"></i>
+        <div class="icon-title">layui-icon-face-smile-fine</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-list"></i>
+        <div class="icon-title">layui-icon-list</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-release"></i>
+        <div class="icon-title">layui-icon-release</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-ok"></i>
+        <div class="icon-title">layui-icon-ok</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-help"></i>
+        <div class="icon-title">layui-icon-help</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-chat"></i>
+        <div class="icon-title">layui-icon-chat</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-top"></i>
+        <div class="icon-title">layui-icon-top</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-star"></i>
+        <div class="icon-title">layui-icon-star</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-star-fill"></i>
+        <div class="icon-title">layui-icon-star-fill</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-close-fill"></i>
+        <div class="icon-title">layui-icon-close-fill</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-close"></i>
+        <div class="icon-title">layui-icon-close</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-ok-circle"></i>
+        <div class="icon-title">layui-icon-ok-circle</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-add-circle-fine"></i>
+        <div class="icon-title">layui-icon-add-circle-fine</div>
+    </li>
+</ul>
+<ul>
+    <li>
+        <i class="fa fa-address-book"></i>
+        <div class="icon-title">fa-address-book</div>
+    </li>
+    <li>
+        <i class="fa fa-address-book-o"></i>
+        <div class="icon-title">fa-address-book-o</div>
+    </li>
+    <li>
+        <i class="fa fa-address-card"></i>
+        <div class="icon-title">fa-address-card</div>
+    </li>
+    <li>
+        <i class="fa fa-address-card-o"></i>
+        <div class="icon-title">fa-address-card-o</div>
+    </li>
+    <li>
+        <i class="fa fa-adjust"></i>
+        <div class="icon-title">fa-adjust</div>
+    </li>
+    <li>
+        <i class="fa fa-american-sign-language-interpreting"></i>
+        <div class="icon-title">fa-american-sign-language-interpreting</div>
+    </li>
+    <li>
+        <i class="fa fa-anchor"></i>
+        <div class="icon-title">fa-anchor</div>
+    </li>
+    <li>
+        <i class="fa fa-archive"></i>
+        <div class="icon-title">fa-archive</div>
+    </li>
+    <li>
+        <i class="fa fa-area-chart"></i>
+        <div class="icon-title">fa-area-chart</div>
+    </li>
+    <li>
+        <i class="fa fa-arrows"></i>
+        <div class="icon-title">fa-arrows</div>
+    </li>
+    <li>
+        <i class="fa fa-arrows-h"></i>
+        <div class="icon-title">fa-arrows-h</div>
+    </li>
+    <li>
+        <i class="fa fa-arrows-v"></i>
+        <div class="icon-title">fa-arrows-v</div>
+    </li>
+    <li>
+        <i class="fa fa-asl-interpreting"></i>
+        <div class="icon-title">fa-asl-interpreting</div>
+    </li>
+    <li>
+        <i class="fa fa-assistive-listening-systems"></i>
+        <div class="icon-title">fa-assistive-listening-systems</div>
+    </li>
+    <li>
+        <i class="fa fa-asterisk"></i>
+        <div class="icon-title">fa-asterisk</div>
+    </li>
+    <li>
+        <i class="fa fa-at"></i>
+        <div class="icon-title">fa-at</div>
+    </li>
+    <li>
+        <i class="fa fa-audio-description"></i>
+        <div class="icon-title">fa-audio-description</div>
+    </li>
+    <li>
+        <i class="fa fa-automobile"></i>
+        <div class="icon-title">fa-automobile</div>
+    </li>
+    <li>
+        <i class="fa fa-balance-scale"></i>
+        <div class="icon-title">fa-balance-scale</div>
+    </li>
+    <li>
+        <i class="fa fa-ban"></i>
+        <div class="icon-title">fa-ban</div>
+    </li>
+    <li>
+        <i class="fa fa-bank"></i>
+        <div class="icon-title">fa-bank</div>
+    </li>
+    <li>
+        <i class="fa fa-bar-chart"></i>
+        <div class="icon-title">fa-bar-chart</div>
+    </li>
+    <li>
+        <i class="fa fa-bar-chart-o"></i>
+        <div class="icon-title">fa-bar-chart-o</div>
+    </li>
+    <li>
+        <i class="fa fa-barcode"></i>
+        <div class="icon-title">fa-barcode</div>
+    </li>
+    <li>
+        <i class="fa fa-bars"></i>
+        <div class="icon-title">fa-bars</div>
+    </li>
+    <li>
+        <i class="fa fa-bath"></i>
+        <div class="icon-title">fa-bath</div>
+    </li>
+    <li>
+        <i class="fa fa-bathtub"></i>
+        <div class="icon-title">fa-bathtub</div>
+    </li>
+    <li>
+        <i class="fa fa-battery"></i>
+        <div class="icon-title">fa-battery</div>
+    </li>
+    <li>
+        <i class="fa fa-battery-0"></i>
+        <div class="icon-title">fa-battery-0</div>
+    </li>
+    <li>
+        <i class="fa fa-battery-1"></i>
+        <div class="icon-title">fa-battery-1</div>
+    </li>
+    <li>
+        <i class="fa fa-battery-2"></i>
+        <div class="icon-title">fa-battery-2</div>
+    </li>
+    <li>
+        <i class="fa fa-battery-3"></i>
+        <div class="icon-title">fa-battery-3</div>
+    </li>
+    <li>
+        <i class="fa fa-battery-4"></i>
+        <div class="icon-title">fa-battery-4</div>
+    </li>
+    <li>
+        <i class="fa fa-battery-empty"></i>
+        <div class="icon-title">fa-battery-empty</div>
+    </li>
+    <li>
+        <i class="fa fa-battery-full"></i>
+        <div class="icon-title">fa-battery-full</div>
+    </li>
+    <li>
+        <i class="fa fa-battery-half"></i>
+        <div class="icon-title">fa-battery-half</div>
+    </li>
+    <li>
+        <i class="fa fa-battery-quarter"></i>
+        <div class="icon-title">fa-battery-quarter</div>
+    </li>
+    <li>
+        <i class="fa fa-battery-three-quarters"></i>
+        <div class="icon-title">fa-battery-three-quarters</div>
+    </li>
+    <li>
+        <i class="fa fa-bed"></i>
+        <div class="icon-title">fa-bed</div>
+    </li>
+    <li>
+        <i class="fa fa-beer"></i>
+        <div class="icon-title">fa-beer</div>
+    </li>
+    <li>
+        <i class="fa fa-bell"></i>
+        <div class="icon-title">fa-bell</div>
+    </li>
+    <li>
+        <i class="fa fa-bell-o"></i>
+        <div class="icon-title">fa-bell-o</div>
+    </li>
+    <li>
+        <i class="fa fa-bell-slash"></i>
+        <div class="icon-title">fa-bell-slash</div>
+    </li>
+    <li>
+        <i class="fa fa-bell-slash-o"></i>
+        <div class="icon-title">fa-bell-slash-o</div>
+    </li>
+    <li>
+        <i class="fa fa-bicycle"></i>
+        <div class="icon-title">fa-bicycle</div>
+    </li>
+    <li>
+        <i class="fa fa-binoculars"></i>
+        <div class="icon-title">fa-binoculars</div>
+    </li>
+    <li>
+        <i class="fa fa-birthday-cake"></i>
+        <div class="icon-title">fa-birthday-cake</div>
+    </li>
+    <li>
+        <i class="fa fa-blind"></i>
+        <div class="icon-title">fa-blind</div>
+    </li>
+    <li>
+        <i class="fa fa-bluetooth"></i>
+        <div class="icon-title">fa-bluetooth</div>
+    </li>
+    <li>
+        <i class="fa fa-bluetooth-b"></i>
+        <div class="icon-title">fa-bluetooth-b</div>
+    </li>
+    <li>
+        <i class="fa fa-bolt"></i>
+        <div class="icon-title">fa-bolt</div>
+    </li>
+    <li>
+        <i class="fa fa-bomb"></i>
+        <div class="icon-title">fa-bomb</div>
+    </li>
+    <li>
+        <i class="fa fa-book"></i>
+        <div class="icon-title">fa-book</div>
+    </li>
+    <li>
+        <i class="fa fa-bookmark"></i>
+        <div class="icon-title">fa-bookmark</div>
+    </li>
+    <li>
+        <i class="fa fa-bookmark-o"></i>
+        <div class="icon-title">fa-bookmark-o</div>
+    </li>
+    <li>
+        <i class="fa fa-braille"></i>
+        <div class="icon-title">fa-braille</div>
+    </li>
+    <li>
+        <i class="fa fa-briefcase"></i>
+        <div class="icon-title">fa-briefcase</div>
+    </li>
+    <li>
+        <i class="fa fa-bug"></i>
+        <div class="icon-title">fa-bug</div>
+    </li>
+    <li>
+        <i class="fa fa-building"></i>
+        <div class="icon-title">fa-building</div>
+    </li>
+    <li>
+        <i class="fa fa-building-o"></i>
+        <div class="icon-title">fa-building-o</div>
+    </li>
+    <li>
+        <i class="fa fa-bullhorn"></i>
+        <div class="icon-title">fa-bullhorn</div>
+    </li>
+    <li>
+        <i class="fa fa-bullseye"></i>
+        <div class="icon-title">fa-bullseye</div>
+    </li>
+    <li>
+        <i class="fa fa-bus"></i>
+        <div class="icon-title">fa-bus</div>
+    </li>
+    <li>
+        <i class="fa fa-cab"></i>
+        <div class="icon-title">fa-cab</div>
+    </li>
+    <li>
+        <i class="fa fa-calculator"></i>
+        <div class="icon-title">fa-calculator</div>
+    </li>
+    <li>
+        <i class="fa fa-calendar"></i>
+        <div class="icon-title">fa-calendar</div>
+    </li>
+    <li>
+        <i class="fa fa-calendar-check-o"></i>
+        <div class="icon-title">fa-calendar-check-o</div>
+    </li>
+    <li>
+        <i class="fa fa-calendar-minus-o"></i>
+        <div class="icon-title">fa-calendar-minus-o</div>
+    </li>
+    <li>
+        <i class="fa fa-calendar-o"></i>
+        <div class="icon-title">fa-calendar-o</div>
+    </li>
+    <li>
+        <i class="fa fa-calendar-plus-o"></i>
+        <div class="icon-title">fa-calendar-plus-o</div>
+    </li>
+    <li>
+        <i class="fa fa-calendar-times-o"></i>
+        <div class="icon-title">fa-calendar-times-o</div>
+    </li>
+    <li>
+        <i class="fa fa-camera"></i>
+        <div class="icon-title">fa-camera</div>
+    </li>
+    <li>
+        <i class="fa fa-camera-retro"></i>
+        <div class="icon-title">fa-camera-retro</div>
+    </li>
+    <li>
+        <i class="fa fa-car"></i>
+        <div class="icon-title">fa-car</div>
+    </li>
+    <li>
+        <i class="fa fa-caret-square-o-down"></i>
+        <div class="icon-title">fa-caret-square-o-down</div>
+    </li>
+    <li>
+        <i class="fa fa-caret-square-o-left"></i>
+        <div class="icon-title">fa-caret-square-o-left</div>
+    </li>
+    <li>
+        <i class="fa fa-caret-square-o-right"></i>
+        <div class="icon-title">fa-caret-square-o-right</div>
+    </li>
+    <li>
+        <i class="fa fa-caret-square-o-up"></i>
+        <div class="icon-title">fa-caret-square-o-up</div>
+    </li>
+    <li>
+        <i class="fa fa-cart-arrow-down"></i>
+        <div class="icon-title">fa-cart-arrow-down</div>
+    </li>
+    <li>
+        <i class="fa fa-cart-plus"></i>
+        <div class="icon-title">fa-cart-plus</div>
+    </li>
+    <li>
+        <i class="fa fa-cc"></i>
+        <div class="icon-title">fa-cc</div>
+    </li>
+    <li>
+        <i class="fa fa-certificate"></i>
+        <div class="icon-title">fa-certificate</div>
+    </li>
+    <li>
+        <i class="fa fa-check"></i>
+        <div class="icon-title">fa-check</div>
+    </li>
+    <li>
+        <i class="fa fa-check-circle"></i>
+        <div class="icon-title">fa-check-circle</div>
+    </li>
+    <li>
+        <i class="fa fa-check-circle-o"></i>
+        <div class="icon-title">fa-check-circle-o</div>
+    </li>
+    <li>
+        <i class="fa fa-check-square"></i>
+        <div class="icon-title">fa-check-square</div>
+    </li>
+    <li>
+        <i class="fa fa-check-square-o"></i>
+        <div class="icon-title">fa-check-square-o</div>
+    </li>
+    <li>
+        <i class="fa fa-child"></i>
+        <div class="icon-title">fa-child</div>
+    </li>
+    <li>
+        <i class="fa fa-circle"></i>
+        <div class="icon-title">fa-circle</div>
+    </li>
+    <li>
+        <i class="fa fa-circle-o"></i>
+        <div class="icon-title">fa-circle-o</div>
+    </li>
+    <li>
+        <i class="fa fa-circle-o-notch"></i>
+        <div class="icon-title">fa-circle-o-notch</div>
+    </li>
+    <li>
+        <i class="fa fa-circle-thin"></i>
+        <div class="icon-title">fa-circle-thin</div>
+    </li>
+    <li>
+        <i class="fa fa-clock-o"></i>
+        <div class="icon-title">fa-clock-o</div>
+    </li>
+    <li>
+        <i class="fa fa-clone"></i>
+        <div class="icon-title">fa-clone</div>
+    </li>
+    <li>
+        <i class="fa fa-close"></i>
+        <div class="icon-title">fa-close</div>
+    </li>
+    <li>
+        <i class="fa fa-cloud"></i>
+        <div class="icon-title">fa-cloud</div>
+    </li>
+    <li>
+        <i class="fa fa-cloud-download"></i>
+        <div class="icon-title">fa-cloud-download</div>
+    </li>
+    <li>
+        <i class="fa fa-cloud-upload"></i>
+        <div class="icon-title">fa-cloud-upload</div>
+    </li>
+    <li>
+        <i class="fa fa-code"></i>
+        <div class="icon-title">fa-code</div>
+    </li>
+    <li>
+        <i class="fa fa-code-fork"></i>
+        <div class="icon-title">fa-code-fork</div>
+    </li>
+    <li>
+        <i class="fa fa-coffee"></i>
+        <div class="icon-title">fa-coffee</div>
+    </li>
+    <li>
+        <i class="fa fa-cog"></i>
+        <div class="icon-title">fa-cog</div>
+    </li>
+    <li>
+        <i class="fa fa-cogs"></i>
+        <div class="icon-title">fa-cogs</div>
+    </li>
+    <li>
+        <i class="fa fa-comment"></i>
+        <div class="icon-title">fa-comment</div>
+    </li>
+    <li>
+        <i class="fa fa-comment-o"></i>
+        <div class="icon-title">fa-comment-o</div>
+    </li>
+    <li>
+        <i class="fa fa-commenting"></i>
+        <div class="icon-title">fa-commenting</div>
+    </li>
+    <li>
+        <i class="fa fa-commenting-o"></i>
+        <div class="icon-title">fa-commenting-o</div>
+    </li>
+    <li>
+        <i class="fa fa-comments"></i>
+        <div class="icon-title">fa-comments</div>
+    </li>
+    <li>
+        <i class="fa fa-comments-o"></i>
+        <div class="icon-title">fa-comments-o</div>
+    </li>
+    <li>
+        <i class="fa fa-compass"></i>
+        <div class="icon-title">fa-compass</div>
+    </li>
+    <li>
+        <i class="fa fa-copyright"></i>
+        <div class="icon-title">fa-copyright</div>
+    </li>
+    <li>
+        <i class="fa fa-creative-commons"></i>
+        <div class="icon-title">fa-creative-commons</div>
+    </li>
+    <li>
+        <i class="fa fa-credit-card"></i>
+        <div class="icon-title">fa-credit-card</div>
+    </li>
+    <li><i class="fa fa-credit-card-alt"></i>
+        <div class="icon-title">fa-credit-card-alt</div>
+    </li>
+    <li><i class="fa fa-crop"></i>
+        <div class="icon-title">fa-crop</div>
+    </li>
+    <li><i class="fa fa-crosshairs"></i>
+        <div class="icon-title">fa-crosshairs</div>
+    </li>
+    <li><i class="fa fa-cube"></i>
+        <div class="icon-title">fa-cube</div>
+    </li>
+    <li><i class="fa fa-cubes"></i>
+        <div class="icon-title">fa-cubes</div>
+    </li>
+    <li><i class="fa fa-cutlery"></i>
+        <div class="icon-title">fa-cutlery</div>
+    </li>
+    <li><i class="fa fa-dashboard"></i>
+        <div class="icon-title">fa-dashboard</div>
+    </li>
+    <li><i class="fa fa-database"></i>
+        <div class="icon-title">fa-database</div>
+    </li>
+    <li><i class="fa fa-deaf"></i>
+        <div class="icon-title">fa-deaf</div>
+    </li>
+    <li><i class="fa fa-deafness"></i>
+        <div class="icon-title">fa-deafness</div>
+    </li>
+    <li><i class="fa fa-desktop"></i>
+        <div class="icon-title">fa-desktop</div>
+    </li>
+    <li><i class="fa fa-diamond"></i>
+        <div class="icon-title">fa-diamond</div>
+    </li>
+    <li><i class="fa fa-dot-circle-o"></i>
+        <div class="icon-title">fa-dot-circle-o</div>
+    </li>
+    <li><i class="fa fa-download"></i>
+        <div class="icon-title">fa-download</div>
+    </li>
+    <li><i class="fa fa-drivers-license"></i>
+        <div class="icon-title">fa-drivers-license</div>
+    </li>
+    <li><i class="fa fa-drivers-license-o"></i>
+        <div class="icon-title">fa-drivers-license-o</div>
+    </li>
+    <li><i class="fa fa-edit"></i>
+        <div class="icon-title">fa-edit</div>
+    </li>
+    <li><i class="fa fa-ellipsis-h"></i>
+        <div class="icon-title">fa-ellipsis-h</div>
+    </li>
+    <li><i class="fa fa-ellipsis-v"></i>
+        <div class="icon-title">fa-ellipsis-v</div>
+    </li>
+    <li><i class="fa fa-envelope"></i>
+        <div class="icon-title">fa-envelope</div>
+    </li>
+    <li><i class="fa fa-envelope-o"></i>
+        <div class="icon-title">fa-envelope-o</div>
+    </li>
+    <li><i class="fa fa-envelope-open"></i>
+        <div class="icon-title">fa-envelope-open</div>
+    </li>
+    <li><i class="fa fa-envelope-open-o"></i>
+        <div class="icon-title">fa-envelope-open-o</div>
+    </li>
+    <li><i class="fa fa-envelope-square"></i>
+        <div class="icon-title">fa-envelope-square</div>
+    </li>
+    <li><i class="fa fa-eraser"></i>
+        <div class="icon-title">fa-eraser</div>
+    </li>
+    <li><i class="fa fa-exchange"></i>
+        <div class="icon-title">fa-exchange</div>
+    </li>
+    <li><i class="fa fa-exclamation"></i>
+        <div class="icon-title">fa-exclamation</div>
+    </li>
+    <li><i class="fa fa-exclamation-circle"></i>
+        <div class="icon-title">fa-exclamation-circle</div>
+    </li>
+    <li><i class="fa fa-exclamation-triangle"></i>
+        <div class="icon-title">fa-exclamation-triangle</div>
+    </li>
+    <li><i class="fa fa-external-link"></i>
+        <div class="icon-title">fa-external-link</div>
+    </li>
+    <li><i class="fa fa-external-link-square"></i>
+        <div class="icon-title">fa-external-link-square</div>
+    </li>
+    <li><i class="fa fa-eye"></i>
+        <div class="icon-title">fa-eye</div>
+    </li>
+    <li><i class="fa fa-eye-slash"></i>
+        <div class="icon-title">fa-eye-slash</div>
+    </li>
+    <li><i class="fa fa-eyedropper"></i>
+        <div class="icon-title">fa-eyedropper</div>
+    </li>
+    <li><i class="fa fa-fax"></i>
+        <div class="icon-title">fa-fax</div>
+    </li>
+    <li><i class="fa fa-feed"></i>
+        <div class="icon-title">fa-feed</div>
+    </li>
+    <li><i class="fa fa-female"></i>
+        <div class="icon-title">fa-female</div>
+    </li>
+    <li><i class="fa fa-fighter-jet"></i>
+        <div class="icon-title">fa-fighter-jet</div>
+    </li>
+    <li><i class="fa fa-file-archive-o"></i>
+        <div class="icon-title">fa-file-archive-o</div>
+    </li>
+    <li><i class="fa fa-file-audio-o"></i>
+        <div class="icon-title">fa-file-audio-o</div>
+    </li>
+    <li><i class="fa fa-file-code-o"></i>
+        <div class="icon-title">fa-file-code-o</div>
+    </li>
+    <li><i class="fa fa-file-excel-o"></i>
+        <div class="icon-title">fa-file-excel-o</div>
+    </li>
+    <li><i class="fa fa-file-image-o"></i>
+        <div class="icon-title">fa-file-image-o</div>
+    </li>
+    <li><i class="fa fa-file-movie-o"></i>
+        <div class="icon-title">fa-file-movie-o</div>
+    </li>
+    <li><i class="fa fa-file-pdf-o"></i>
+        <div class="icon-title">fa-file-pdf-o</div>
+    </li>
+    <li><i class="fa fa-file-photo-o"></i>
+        <div class="icon-title">fa-file-photo-o</div>
+    </li>
+    <li><i class="fa fa-file-picture-o"></i>
+        <div class="icon-title">fa-file-picture-o</div>
+    </li>
+    <li><i class="fa fa-file-powerpoint-o"></i>
+        <div class="icon-title">fa-file-powerpoint-o</div>
+    </li>
+    <li><i class="fa fa-file-sound-o"></i>
+        <div class="icon-title">fa-file-sound-o</div>
+    </li>
+    <li><i class="fa fa-file-video-o"></i>
+        <div class="icon-title">fa-file-video-o</div>
+    </li>
+    <li><i class="fa fa-file-word-o"></i>
+        <div class="icon-title">fa-file-word-o</div>
+    </li>
+    <li><i class="fa fa-file-zip-o"></i>
+        <div class="icon-title">fa-file-zip-o</div>
+    </li>
+    <li><i class="fa fa-film"></i>
+        <div class="icon-title">fa-film</div>
+    </li>
+    <li><i class="fa fa-filter"></i>
+        <div class="icon-title">fa-filter</div>
+    </li>
+    <li><i class="fa fa-fire"></i>
+        <div class="icon-title">fa-fire</div>
+    </li>
+    <li><i class="fa fa-fire-extinguisher"></i>
+        <div class="icon-title">fa-fire-extinguisher</div>
+    </li>
+    <li><i class="fa fa-flag"></i>
+        <div class="icon-title">fa-flag</div>
+    </li>
+    <li><i class="fa fa-flag-checkered"></i>
+        <div class="icon-title">fa-flag-checkered</div>
+    </li>
+    <li><i class="fa fa-flag-o"></i>
+        <div class="icon-title">fa-flag-o</div>
+    </li>
+    <li><i class="fa fa-flash"></i>
+        <div class="icon-title">fa-flash</div>
+    </li>
+    <li><i class="fa fa-flask"></i>
+        <div class="icon-title">fa-flask</div>
+    </li>
+    <li><i class="fa fa-folder"></i>
+        <div class="icon-title">fa-folder</div>
+    </li>
+    <li><i class="fa fa-folder-o"></i>
+        <div class="icon-title">fa-folder-o</div>
+    </li>
+    <li><i class="fa fa-folder-open"></i>
+        <div class="icon-title">fa-folder-open</div>
+    </li>
+    <li><i class="fa fa-folder-open-o"></i>
+        <div class="icon-title">fa-folder-open-o</div>
+    </li>
+    <li><i class="fa fa-frown-o"></i>
+        <div class="icon-title">fa-frown-o</div>
+    </li>
+    <li><i class="fa fa-futbol-o"></i>
+        <div class="icon-title">fa-futbol-o</div>
+    </li>
+    <li><i class="fa fa-gamepad"></i>
+        <div class="icon-title">fa-gamepad</div>
+    </li>
+    <li><i class="fa fa-gavel"></i>
+        <div class="icon-title">fa-gavel</div>
+    </li>
+    <li><i class="fa fa-gear"></i>
+        <div class="icon-title">fa-gear</div>
+    </li>
+    <li><i class="fa fa-gears"></i>
+        <div class="icon-title">fa-gears</div>
+    </li>
+    <li><i class="fa fa-gift"></i>
+        <div class="icon-title">fa-gift</div>
+    </li>
+    <li><i class="fa fa-glass"></i>
+        <div class="icon-title">fa-glass</div>
+    </li>
+    <li><i class="fa fa-globe"></i>
+        <div class="icon-title">fa-globe</div>
+    </li>
+    <li><i class="fa fa-graduation-cap"></i>
+        <div class="icon-title">fa-graduation-cap</div>
+    </li>
+    <li><i class="fa fa-group"></i>
+        <div class="icon-title">fa-group</div>
+    </li>
+    <li><i class="fa fa-hand-grab-o"></i>
+        <div class="icon-title">fa-hand-grab-o</div>
+    </li>
+    <li><i class="fa fa-hand-lizard-o"></i>
+        <div class="icon-title">fa-hand-lizard-o</div>
+    </li>
+    <li><i class="fa fa-hand-paper-o"></i>
+        <div class="icon-title">fa-hand-paper-o</div>
+    </li>
+    <li><i class="fa fa-hand-peace-o"></i>
+        <div class="icon-title">fa-hand-peace-o</div>
+    </li>
+    <li><i class="fa fa-hand-pointer-o"></i>
+        <div class="icon-title">fa-hand-pointer-o</div>
+    </li>
+    <li><i class="fa fa-hand-rock-o"></i>
+        <div class="icon-title">fa-hand-rock-o</div>
+    </li>
+    <li><i class="fa fa-hand-scissors-o"></i>
+        <div class="icon-title">fa-hand-scissors-o</div>
+    </li>
+    <li><i class="fa fa-hand-spock-o"></i>
+        <div class="icon-title">fa-hand-spock-o</div>
+    </li>
+    <li><i class="fa fa-hand-stop-o"></i>
+        <div class="icon-title">fa-hand-stop-o</div>
+    </li>
+    <li><i class="fa fa-handshake-o"></i>
+        <div class="icon-title">fa-handshake-o</div>
+    </li>
+    <li><i class="fa fa-hard-of-hearing"></i>
+        <div class="icon-title">fa-hard-of-hearing</div>
+    </li>
+    <li><i class="fa fa-hashtag"></i>
+        <div class="icon-title">fa-hashtag</div>
+    </li>
+    <li><i class="fa fa-hdd-o"></i>
+        <div class="icon-title">fa-hdd-o</div>
+    </li>
+    <li><i class="fa fa-headphones"></i>
+        <div class="icon-title">fa-headphones</div>
+    </li>
+    <li><i class="fa fa-heart"></i>
+        <div class="icon-title">fa-heart</div>
+    </li>
+    <li><i class="fa fa-heart-o"></i>
+        <div class="icon-title">fa-heart-o</div>
+    </li>
+    <li><i class="fa fa-heartbeat"></i>
+        <div class="icon-title">fa-heartbeat</div>
+    </li>
+    <li><i class="fa fa-history"></i>
+        <div class="icon-title">fa-history</div>
+    </li>
+    <li><i class="fa fa-home"></i>
+        <div class="icon-title">fa-home</div>
+    </li>
+    <li><i class="fa fa-hotel"></i>
+        <div class="icon-title">fa-hotel</div>
+    </li>
+    <li><i class="fa fa-hourglass"></i>
+        <div class="icon-title">fa-hourglass</div>
+    </li>
+    <li><i class="fa fa-hourglass-1"></i>
+        <div class="icon-title">fa-hourglass-1</div>
+    </li>
+    <li><i class="fa fa-hourglass-2"></i>
+        <div class="icon-title">fa-hourglass-2</div>
+    </li>
+    <li><i class="fa fa-hourglass-3"></i>
+        <div class="icon-title">fa-hourglass-3</div>
+    </li>
+    <li><i class="fa fa-hourglass-end"></i>
+        <div class="icon-title">fa-hourglass-end</div>
+    </li>
+    <li><i class="fa fa-hourglass-half"></i>
+        <div class="icon-title">fa-hourglass-half</div>
+    </li>
+    <li><i class="fa fa-hourglass-o"></i>
+        <div class="icon-title">fa-hourglass-o</div>
+    </li>
+    <li><i class="fa fa-hourglass-start"></i>
+        <div class="icon-title">fa-hourglass-start</div>
+    </li>
+    <li><i class="fa fa-i-cursor"></i>
+        <div class="icon-title">fa-i-cursor</div>
+    </li>
+    <li><i class="fa fa-id-badge"></i>
+        <div class="icon-title">fa-id-badge</div>
+    </li>
+    <li><i class="fa fa-id-card"></i>
+        <div class="icon-title">fa-id-card</div>
+    </li>
+    <li><i class="fa fa-id-card-o"></i>
+        <div class="icon-title">fa-id-card-o</div>
+    </li>
+    <li><i class="fa fa-image"></i>
+        <div class="icon-title">fa-image</div>
+    </li>
+    <li><i class="fa fa-inbox"></i>
+        <div class="icon-title">fa-inbox</div>
+    </li>
+    <li><i class="fa fa-industry"></i>
+        <div class="icon-title">fa-industry</div>
+    </li>
+    <li><i class="fa fa-info"></i>
+        <div class="icon-title">fa-info</div>
+    </li>
+    <li><i class="fa fa-info-circle"></i>
+        <div class="icon-title">fa-info-circle</div>
+    </li>
+    <li><i class="fa fa-institution"></i>
+        <div class="icon-title">fa-institution</div>
+    </li>
+    <li><i class="fa fa-key"></i>
+        <div class="icon-title">fa-key</div>
+    </li>
+    <li><i class="fa fa-keyboard-o"></i>
+        <div class="icon-title">fa-keyboard-o</div>
+    </li>
+    <li><i class="fa fa-language"></i>
+        <div class="icon-title">fa-language</div>
+    </li>
+    <li><i class="fa fa-laptop"></i>
+        <div class="icon-title">fa-laptop</div>
+    </li>
+    <li><i class="fa fa-leaf"></i>
+        <div class="icon-title">fa-leaf</div>
+    </li>
+    <li><i class="fa fa-legal"></i>
+        <div class="icon-title">fa-legal</div>
+    </li>
+    <li><i class="fa fa-lemon-o"></i>
+        <div class="icon-title">fa-lemon-o</div>
+    </li>
+    <li><i class="fa fa-level-down"></i>
+        <div class="icon-title">fa-level-down</div>
+    </li>
+    <li><i class="fa fa-level-up"></i>
+        <div class="icon-title">fa-level-up</div>
+    </li>
+    <li><i class="fa fa-life-bouy"></i>
+        <div class="icon-title">fa-life-bouy</div>
+    </li>
+    <li><i class="fa fa-life-buoy"></i>
+        <div class="icon-title">fa-life-buoy</div>
+    </li>
+    <li><i class="fa fa-life-ring"></i>
+        <div class="icon-title">fa-life-ring</div>
+    </li>
+    <li><i class="fa fa-life-saver"></i>
+        <div class="icon-title">fa-life-saver</div>
+    </li>
+    <li><i class="fa fa-lightbulb-o"></i>
+        <div class="icon-title">fa-lightbulb-o</div>
+    </li>
+    <li><i class="fa fa-line-chart"></i>
+        <div class="icon-title">fa-line-chart</div>
+    </li>
+    <li><i class="fa fa-location-arrow"></i>
+        <div class="icon-title">fa-location-arrow</div>
+    </li>
+    <li><i class="fa fa-lock"></i>
+        <div class="icon-title">fa-lock</div>
+    </li>
+    <li><i class="fa fa-low-vision"></i>
+        <div class="icon-title">fa-low-vision</div>
+    </li>
+    <li><i class="fa fa-magic"></i>
+        <div class="icon-title">fa-magic</div>
+    </li>
+    <li><i class="fa fa-magnet"></i>
+        <div class="icon-title">fa-magnet</div>
+    </li>
+    <li><i class="fa fa-mail-forward"></i>
+        <div class="icon-title">fa-mail-forward</div>
+    </li>
+    <li><i class="fa fa-mail-reply"></i>
+        <div class="icon-title">fa-mail-reply</div>
+    </li>
+    <li><i class="fa fa-mail-reply-all"></i>
+        <div class="icon-title">fa-mail-reply-all</div>
+    </li>
+    <li><i class="fa fa-male"></i>
+        <div class="icon-title">fa-male</div>
+    </li>
+    <li><i class="fa fa-map"></i>
+        <div class="icon-title">fa-map</div>
+    </li>
+    <li><i class="fa fa-map-marker"></i>
+        <div class="icon-title">fa-map-marker</div>
+    </li>
+    <li><i class="fa fa-map-o"></i>
+        <div class="icon-title">fa-map-o</div>
+    </li>
+    <li><i class="fa fa-map-pin"></i>
+        <div class="icon-title">fa-map-pin</div>
+    </li>
+    <li><i class="fa fa-map-signs"></i>
+        <div class="icon-title">fa-map-signs</div>
+    </li>
+    <li><i class="fa fa-meh-o"></i>
+        <div class="icon-title">fa-meh-o</div>
+    </li>
+    <li><i class="fa fa-microchip"></i>
+        <div class="icon-title">fa-microchip</div>
+    </li>
+    <li><i class="fa fa-microphone"></i>
+        <div class="icon-title">fa-microphone</div>
+    </li>
+    <li><i class="fa fa-microphone-slash"></i>
+        <div class="icon-title">fa-microphone-slash</div>
+    </li>
+    <li><i class="fa fa-minus"></i>
+        <div class="icon-title">fa-minus</div>
+    </li>
+    <li><i class="fa fa-minus-circle"></i>
+        <div class="icon-title">fa-minus-circle</div>
+    </li>
+    <li><i class="fa fa-minus-square"></i>
+        <div class="icon-title">fa-minus-square</div>
+    </li>
+    <li><i class="fa fa-minus-square-o"></i>
+        <div class="icon-title">fa-minus-square-o</div>
+    </li>
+    <li><i class="fa fa-mobile"></i>
+        <div class="icon-title">fa-mobile</div>
+    </li>
+    <li><i class="fa fa-mobile-phone"></i>
+        <div class="icon-title">fa-mobile-phone</div>
+    </li>
+    <li><i class="fa fa-money"></i>
+        <div class="icon-title">fa-money</div>
+    </li>
+    <li><i class="fa fa-moon-o"></i>
+        <div class="icon-title">fa-moon-o</div>
+    </li>
+    <li><i class="fa fa-mortar-board"></i>
+        <div class="icon-title">fa-mortar-board</div>
+    </li>
+    <li><i class="fa fa-motorcycle"></i>
+        <div class="icon-title">fa-motorcycle</div>
+    </li>
+    <li><i class="fa fa-mouse-pointer"></i>
+        <div class="icon-title">fa-mouse-pointer</div>
+    </li>
+    <li><i class="fa fa-music"></i>
+        <div class="icon-title">fa-music</div>
+    </li>
+    <li><i class="fa fa-navicon"></i>
+        <div class="icon-title">fa-navicon</div>
+    </li>
+    <li><i class="fa fa-newspaper-o"></i>
+        <div class="icon-title">fa-newspaper-o</div>
+    </li>
+    <li><i class="fa fa-object-group"></i>
+        <div class="icon-title">fa-object-group</div>
+    </li>
+    <li><i class="fa fa-object-ungroup"></i>
+        <div class="icon-title">fa-object-ungroup</div>
+    </li>
+    <li><i class="fa fa-paint-brush"></i>
+        <div class="icon-title">fa-paint-brush</div>
+    </li>
+    <li><i class="fa fa-paper-plane"></i>
+        <div class="icon-title">fa-paper-plane</div>
+    </li>
+    <li><i class="fa fa-paper-plane-o"></i>
+        <div class="icon-title">fa-paper-plane-o</div>
+    </li>
+    <li><i class="fa fa-paw"></i>
+        <div class="icon-title">fa-paw</div>
+    </li>
+    <li><i class="fa fa-pencil"></i>
+        <div class="icon-title">fa-pencil</div>
+    </li>
+    <li><i class="fa fa-pencil-square"></i>
+        <div class="icon-title">fa-pencil-square</div>
+    </li>
+    <li><i class="fa fa-pencil-square-o"></i>
+        <div class="icon-title">fa-pencil-square-o</div>
+    </li>
+    <li><i class="fa fa-percent"></i>
+        <div class="icon-title">fa-percent</div>
+    </li>
+    <li><i class="fa fa-phone"></i>
+        <div class="icon-title">fa-phone</div>
+    </li>
+    <li><i class="fa fa-phone-square"></i>
+        <div class="icon-title">fa-phone-square</div>
+    </li>
+    <li><i class="fa fa-photo"></i>
+        <div class="icon-title">fa-photo</div>
+    </li>
+    <li><i class="fa fa-picture-o"></i>
+        <div class="icon-title">fa-picture-o</div>
+    </li>
+    <li><i class="fa fa-pie-chart"></i>
+        <div class="icon-title">fa-pie-chart</div>
+    </li>
+    <li><i class="fa fa-plane"></i>
+        <div class="icon-title">fa-plane</div>
+    </li>
+    <li><i class="fa fa-plug"></i>
+        <div class="icon-title">fa-plug</div>
+    </li>
+    <li><i class="fa fa-plus"></i>
+        <div class="icon-title">fa-plus</div>
+    </li>
+    <li><i class="fa fa-plus-circle"></i>
+        <div class="icon-title">fa-plus-circle</div>
+    </li>
+    <li><i class="fa fa-plus-square"></i>
+        <div class="icon-title">fa-plus-square</div>
+    </li>
+    <li><i class="fa fa-plus-square-o"></i>
+        <div class="icon-title">fa-plus-square-o</div>
+    </li>
+    <li><i class="fa fa-podcast"></i>
+        <div class="icon-title">fa-podcast</div>
+    </li>
+    <li><i class="fa fa-power-off"></i>
+        <div class="icon-title">fa-power-off</div>
+    </li>
+    <li><i class="fa fa-print"></i>
+        <div class="icon-title">fa-print</div>
+    </li>
+    <li><i class="fa fa-puzzle-piece"></i>
+        <div class="icon-title">fa-puzzle-piece</div>
+    </li>
+    <li><i class="fa fa-qrcode"></i>
+        <div class="icon-title">fa-qrcode</div>
+    </li>
+    <li><i class="fa fa-question"></i>
+        <div class="icon-title">fa-question</div>
+    </li>
+    <li><i class="fa fa-question-circle"></i>
+        <div class="icon-title">fa-question-circle</div>
+    </li>
+    <li><i class="fa fa-question-circle-o"></i>
+        <div class="icon-title">fa-question-circle-o</div>
+    </li>
+    <li><i class="fa fa-quote-left"></i>
+        <div class="icon-title">fa-quote-left</div>
+    </li>
+    <li><i class="fa fa-quote-right"></i>
+        <div class="icon-title">fa-quote-right</div>
+    </li>
+    <li><i class="fa fa-random"></i>
+        <div class="icon-title">fa-random</div>
+    </li>
+    <li><i class="fa fa-recycle"></i>
+        <div class="icon-title">fa-recycle</div>
+    </li>
+    <li><i class="fa fa-refresh"></i>
+        <div class="icon-title">fa-refresh</div>
+    </li>
+    <li><i class="fa fa-registered"></i>
+        <div class="icon-title">fa-registered</div>
+    </li>
+    <li><i class="fa fa-remove"></i>
+        <div class="icon-title">fa-remove</div>
+    </li>
+    <li><i class="fa fa-reorder"></i>
+        <div class="icon-title">fa-reorder</div>
+    </li>
+    <li><i class="fa fa-reply"></i>
+        <div class="icon-title">fa-reply</div>
+    </li>
+    <li><i class="fa fa-reply-all"></i>
+        <div class="icon-title">fa-reply-all</div>
+    </li>
+    <li><i class="fa fa-retweet"></i>
+        <div class="icon-title">fa-retweet</div>
+    </li>
+    <li><i class="fa fa-road"></i>
+        <div class="icon-title">fa-road</div>
+    </li>
+    <li><i class="fa fa-rocket"></i>
+        <div class="icon-title">fa-rocket</div>
+    </li>
+    <li><i class="fa fa-rss"></i>
+        <div class="icon-title">fa-rss</div>
+    </li>
+    <li><i class="fa fa-rss-square"></i>
+        <div class="icon-title">fa-rss-square</div>
+    </li>
+    <li><i class="fa fa-s15"></i>
+        <div class="icon-title">fa-s15</div>
+    </li>
+    <li><i class="fa fa-search"></i>
+        <div class="icon-title">fa-search</div>
+    </li>
+    <li><i class="fa fa-search-minus"></i>
+        <div class="icon-title">fa-search-minus</div>
+    </li>
+    <li><i class="fa fa-search-plus"></i>
+        <div class="icon-title">fa-search-plus</div>
+    </li>
+    <li><i class="fa fa-send"></i>
+        <div class="icon-title">fa-send</div>
+    </li>
+    <li><i class="fa fa-send-o"></i>
+        <div class="icon-title">fa-send-o</div>
+    </li>
+    <li><i class="fa fa-server"></i>
+        <div class="icon-title">fa-server</div>
+    </li>
+    <li><i class="fa fa-share"></i>
+        <div class="icon-title">fa-share</div>
+    </li>
+    <li><i class="fa fa-share-alt"></i>
+        <div class="icon-title">fa-share-alt</div>
+    </li>
+    <li><i class="fa fa-share-alt-square"></i>
+        <div class="icon-title">fa-share-alt-square</div>
+    </li>
+    <li><i class="fa fa-share-square"></i>
+        <div class="icon-title">fa-share-square</div>
+    </li>
+    <li><i class="fa fa-share-square-o"></i>
+        <div class="icon-title">fa-share-square-o</div>
+    </li>
+    <li><i class="fa fa-shield"></i>
+        <div class="icon-title">fa-shield</div>
+    </li>
+    <li><i class="fa fa-ship"></i>
+        <div class="icon-title">fa-ship</div>
+    </li>
+    <li><i class="fa fa-shopping-bag"></i>
+        <div class="icon-title">fa-shopping-bag</div>
+    </li>
+    <li><i class="fa fa-shopping-basket"></i>
+        <div class="icon-title">fa-shopping-basket</div>
+    </li>
+    <li><i class="fa fa-shopping-cart"></i>
+        <div class="icon-title">fa-shopping-cart</div>
+    </li>
+    <li><i class="fa fa-shower"></i>
+        <div class="icon-title">fa-shower</div>
+    </li>
+    <li><i class="fa fa-sign-in"></i>
+        <div class="icon-title">fa-sign-in</div>
+    </li>
+    <li><i class="fa fa-sign-language"></i>
+        <div class="icon-title">fa-sign-language</div>
+    </li>
+    <li><i class="fa fa-sign-out"></i>
+        <div class="icon-title">fa-sign-out</div>
+    </li>
+    <li><i class="fa fa-signal"></i>
+        <div class="icon-title">fa-signal</div>
+    </li>
+    <li><i class="fa fa-signing"></i>
+        <div class="icon-title">fa-signing</div>
+    </li>
+    <li><i class="fa fa-sitemap"></i>
+        <div class="icon-title">fa-sitemap</div>
+    </li>
+    <li><i class="fa fa-sliders"></i>
+        <div class="icon-title">fa-sliders</div>
+    </li>
+    <li><i class="fa fa-smile-o"></i>
+        <div class="icon-title">fa-smile-o</div>
+    </li>
+    <li><i class="fa fa-snowflake-o"></i>
+        <div class="icon-title">fa-snowflake-o</div>
+    </li>
+    <li><i class="fa fa-soccer-ball-o"></i>
+        <div class="icon-title">fa-soccer-ball-o</div>
+    </li>
+    <li><i class="fa fa-sort"></i>
+        <div class="icon-title">fa-sort</div>
+    </li>
+    <li><i class="fa fa-sort-alpha-asc"></i>
+        <div class="icon-title">fa-sort-alpha-asc</div>
+    </li>
+    <li><i class="fa fa-sort-alpha-desc"></i>
+        <div class="icon-title">fa-sort-alpha-desc</div>
+    </li>
+    <li><i class="fa fa-sort-amount-asc"></i>
+        <div class="icon-title">fa-sort-amount-asc</div>
+    </li>
+    <li><i class="fa fa-sort-amount-desc"></i>
+        <div class="icon-title">fa-sort-amount-desc</div>
+    </li>
+    <li><i class="fa fa-sort-asc"></i>
+        <div class="icon-title">fa-sort-asc</div>
+    </li>
+    <li><i class="fa fa-sort-desc"></i>
+        <div class="icon-title">fa-sort-desc</div>
+    </li>
+    <li><i class="fa fa-sort-down"></i>
+        <div class="icon-title">fa-sort-down</div>
+    </li>
+    <li><i class="fa fa-sort-numeric-asc"></i>
+        <div class="icon-title">fa-sort-numeric-asc</div>
+    </li>
+    <li><i class="fa fa-sort-numeric-desc"></i>
+        <div class="icon-title">fa-sort-numeric-desc</div>
+    </li>
+    <li><i class="fa fa-sort-up"></i>
+        <div class="icon-title">fa-sort-up</div>
+    </li>
+    <li><i class="fa fa-space-shuttle"></i>
+        <div class="icon-title">fa-space-shuttle</div>
+    </li>
+    <li><i class="fa fa-spinner"></i>
+        <div class="icon-title">fa-spinner</div>
+    </li>
+    <li><i class="fa fa-spoon"></i>
+        <div class="icon-title">fa-spoon</div>
+    </li>
+    <li><i class="fa fa-square"></i>
+        <div class="icon-title">fa-square</div>
+    </li>
+    <li><i class="fa fa-square-o"></i>
+        <div class="icon-title">fa-square-o</div>
+    </li>
+    <li><i class="fa fa-star"></i>
+        <div class="icon-title">fa-star</div>
+    </li>
+    <li><i class="fa fa-star-half"></i>
+        <div class="icon-title">fa-star-half</div>
+    </li>
+    <li><i class="fa fa-star-half-empty"></i>
+        <div class="icon-title">fa-star-half-empty</div>
+    </li>
+    <li><i class="fa fa-star-half-full"></i>
+        <div class="icon-title">fa-star-half-full</div>
+    </li>
+    <li><i class="fa fa-star-half-o"></i>
+        <div class="icon-title">fa-star-half-o</div>
+    </li>
+    <li><i class="fa fa-star-o"></i>
+        <div class="icon-title">fa-star-o</div>
+    </li>
+    <li><i class="fa fa-sticky-note"></i>
+        <div class="icon-title">fa-sticky-note</div>
+    </li>
+    <li><i class="fa fa-sticky-note-o"></i>
+        <div class="icon-title">fa-sticky-note-o</div>
+    </li>
+    <li><i class="fa fa-street-view"></i>
+        <div class="icon-title">fa-street-view</div>
+    </li>
+    <li><i class="fa fa-suitcase"></i>
+        <div class="icon-title">fa-suitcase</div>
+    </li>
+    <li><i class="fa fa-sun-o"></i>
+        <div class="icon-title">fa-sun-o</div>
+    </li>
+    <li><i class="fa fa-support"></i>
+        <div class="icon-title">fa-support</div>
+    </li>
+    <li><i class="fa fa-tablet"></i>
+        <div class="icon-title">fa-tablet</div>
+    </li>
+    <li><i class="fa fa-tachometer"></i>
+        <div class="icon-title">fa-tachometer</div>
+    </li>
+    <li><i class="fa fa-tag"></i>
+        <div class="icon-title">fa-tag</div>
+    </li>
+    <li><i class="fa fa-tags"></i>
+        <div class="icon-title">fa-tags</div>
+    </li>
+    <li><i class="fa fa-tasks"></i>
+        <div class="icon-title">fa-tasks</div>
+    </li>
+    <li><i class="fa fa-taxi"></i>
+        <div class="icon-title">fa-taxi</div>
+    </li>
+    <li><i class="fa fa-television"></i>
+        <div class="icon-title">fa-television</div>
+    </li>
+    <li><i class="fa fa-terminal"></i>
+        <div class="icon-title">fa-terminal</div>
+    </li>
+    <li><i class="fa fa-thermometer"></i>
+        <div class="icon-title">fa-thermometer</div>
+    </li>
+    <li><i class="fa fa-thermometer-0"></i>
+        <div class="icon-title">fa-thermometer-0</div>
+    </li>
+    <li><i class="fa fa-thermometer-1"></i>
+        <div class="icon-title">fa-thermometer-1</div>
+    </li>
+    <li><i class="fa fa-thermometer-2"></i>
+        <div class="icon-title">fa-thermometer-2</div>
+    </li>
+    <li><i class="fa fa-thermometer-3"></i>
+        <div class="icon-title">fa-thermometer-3</div>
+    </li>
+    <li><i class="fa fa-thermometer-4"></i>
+        <div class="icon-title">fa-thermometer-4</div>
+    </li>
+    <li><i class="fa fa-thermometer-empty"></i>
+        <div class="icon-title">fa-thermometer-empty</div>
+    </li>
+    <li><i class="fa fa-thermometer-full"></i>
+        <div class="icon-title">fa-thermometer-full</div>
+    </li>
+    <li><i class="fa fa-thermometer-half"></i>
+        <div class="icon-title">fa-thermometer-half</div>
+    </li>
+    <li><i class="fa fa-thermometer-quarter"></i>
+        <div class="icon-title">fa-thermometer-quarter</div>
+    </li>
+    <li><i class="fa fa-thermometer-three-quarters"></i>
+        <div class="icon-title">fa-thermometer-three-quarters</div>
+    </li>
+    <li><i class="fa fa-thumb-tack"></i>
+        <div class="icon-title">fa-thumb-tack</div>
+    </li>
+    <li><i class="fa fa-thumbs-down"></i>
+        <div class="icon-title">fa-thumbs-down</div>
+    </li>
+    <li><i class="fa fa-thumbs-o-down"></i>
+        <div class="icon-title">fa-thumbs-o-down</div>
+    </li>
+    <li><i class="fa fa-thumbs-o-up"></i>
+        <div class="icon-title">fa-thumbs-o-up</div>
+    </li>
+    <li><i class="fa fa-thumbs-up"></i>
+        <div class="icon-title">fa-thumbs-up</div>
+    </li>
+    <li><i class="fa fa-ticket"></i>
+        <div class="icon-title">fa-ticket</div>
+    </li>
+    <li><i class="fa fa-times"></i>
+        <div class="icon-title">fa-times</div>
+    </li>
+    <li><i class="fa fa-times-circle"></i>
+        <div class="icon-title">fa-times-circle</div>
+    </li>
+    <li><i class="fa fa-times-circle-o"></i>
+        <div class="icon-title">fa-times-circle-o</div>
+    </li>
+    <li><i class="fa fa-times-rectangle"></i>
+        <div class="icon-title">fa-times-rectangle</div>
+    </li>
+    <li><i class="fa fa-times-rectangle-o"></i>
+        <div class="icon-title">fa-times-rectangle-o</div>
+    </li>
+    <li><i class="fa fa-tint"></i>
+        <div class="icon-title">fa-tint</div>
+    </li>
+    <li><i class="fa fa-toggle-down"></i>
+        <div class="icon-title">fa-toggle-down</div>
+    </li>
+    <li><i class="fa fa-toggle-left"></i>
+        <div class="icon-title">fa-toggle-left</div>
+    </li>
+    <li><i class="fa fa-toggle-off"></i>
+        <div class="icon-title">fa-toggle-off</div>
+    </li>
+    <li><i class="fa fa-toggle-on"></i>
+        <div class="icon-title">fa-toggle-on</div>
+    </li>
+    <li><i class="fa fa-toggle-right"></i>
+        <div class="icon-title">fa-toggle-right</div>
+    </li>
+    <li><i class="fa fa-toggle-up"></i>
+        <div class="icon-title">fa-toggle-up</div>
+    </li>
+    <li><i class="fa fa-trademark"></i>
+        <div class="icon-title">fa-trademark</div>
+    </li>
+    <li><i class="fa fa-trash"></i>
+        <div class="icon-title">fa-trash</div>
+    </li>
+    <li><i class="fa fa-trash-o"></i>
+        <div class="icon-title">fa-trash-o</div>
+    </li>
+    <li><i class="fa fa-tree"></i>
+        <div class="icon-title">fa-tree</div>
+    </li>
+    <li><i class="fa fa-trophy"></i>
+        <div class="icon-title">fa-trophy</div>
+    </li>
+    <li><i class="fa fa-truck"></i>
+        <div class="icon-title">fa-truck</div>
+    </li>
+    <li><i class="fa fa-tty"></i>
+        <div class="icon-title">fa-tty</div>
+    </li>
+    <li><i class="fa fa-tv"></i>
+        <div class="icon-title">fa-tv</div>
+    </li>
+    <li><i class="fa fa-umbrella"></i>
+        <div class="icon-title">fa-umbrella</div>
+    </li>
+    <li><i class="fa fa-universal-access"></i>
+        <div class="icon-title">fa-universal-access</div>
+    </li>
+    <li><i class="fa fa-university"></i>
+        <div class="icon-title">fa-university</div>
+    </li>
+    <li><i class="fa fa-unlock"></i>
+        <div class="icon-title">fa-unlock</div>
+    </li>
+    <li><i class="fa fa-unlock-alt"></i>
+        <div class="icon-title">fa-unlock-alt</div>
+    </li>
+    <li><i class="fa fa-unsorted"></i>
+        <div class="icon-title">fa-unsorted</div>
+    </li>
+    <li><i class="fa fa-upload"></i>
+        <div class="icon-title">fa-upload</div>
+    </li>
+    <li><i class="fa fa-user"></i>
+        <div class="icon-title">fa-user</div>
+    </li>
+    <li><i class="fa fa-user-circle"></i>
+        <div class="icon-title">fa-user-circle</div>
+    </li>
+    <li><i class="fa fa-user-circle-o"></i>
+        <div class="icon-title">fa-user-circle-o</div>
+    </li>
+    <li><i class="fa fa-user-o"></i>
+        <div class="icon-title">fa-user-o</div>
+    </li>
+    <li><i class="fa fa-user-plus"></i>
+        <div class="icon-title">fa-user-plus</div>
+    </li>
+    <li><i class="fa fa-user-secret"></i>
+        <div class="icon-title">fa-user-secret</div>
+    </li>
+    <li><i class="fa fa-user-times"></i>
+        <div class="icon-title">fa-user-times</div>
+    </li>
+    <li><i class="fa fa-users"></i>
+        <div class="icon-title">fa-users</div>
+    </li>
+    <li><i class="fa fa-vcard"></i>
+        <div class="icon-title">fa-vcard</div>
+    </li>
+    <li><i class="fa fa-vcard-o"></i>
+        <div class="icon-title">fa-vcard-o</div>
+    </li>
+    <li><i class="fa fa-video-camera"></i>
+        <div class="icon-title">fa-video-camera</div>
+    </li>
+    <li><i class="fa fa-volume-control-phone"></i>
+        <div class="icon-title">fa-volume-control-phone</div>
+    </li>
+    <li><i class="fa fa-volume-down"></i>
+        <div class="icon-title">fa-volume-down</div>
+    </li>
+    <li><i class="fa fa-volume-off"></i>
+        <div class="icon-title">fa-volume-off</div>
+    </li>
+    <li><i class="fa fa-volume-up"></i>
+        <div class="icon-title">fa-volume-up</div>
+    </li>
+    <li><i class="fa fa-warning"></i>
+        <div class="icon-title">fa-warning</div>
+    </li>
+    <li><i class="fa fa-wheelchair"></i>
+        <div class="icon-title">fa-wheelchair</div>
+    </li>
+    <li><i class="fa fa-wheelchair-alt"></i>
+        <div class="icon-title">fa-wheelchair-alt</div>
+    </li>
+    <li><i class="fa fa-wifi"></i>
+        <div class="icon-title">fa-wifi</div>
+    </li>
+    <li><i class="fa fa-window-close"></i>
+        <div class="icon-title">fa-window-close</div>
+    </li>
+    <li><i class="fa fa-window-close-o"></i>
+        <div class="icon-title">fa-window-close-o</div>
+    </li>
+    <li><i class="fa fa-window-maximize"></i>
+        <div class="icon-title">fa-window-maximize</div>
+    </li>
+    <li><i class="fa fa-window-minimize"></i>
+        <div class="icon-title">fa-window-minimize</div>
+    </li>
+    <li><i class="fa fa-window-restore"></i>
+        <div class="icon-title">fa-window-restore</div>
+    </li>
+    <li><i class="fa fa-wrench"></i>
+        <div class="icon-title">fa-wrench</div>
+    </li>
+    <li><i class="fa fa-american-sign-language-interpreting"></i>
+        <div class="icon-title">fa-american-sign-language-interpreting</div>
+    </li>
+    <li><i class="fa fa-asl-interpreting"></i>
+        <div class="icon-title">fa-asl-interpreting</div>
+    </li>
+    <li><i class="fa fa-assistive-listening-systems"></i>
+        <div class="icon-title">fa-assistive-listening-systems</div>
+    </li>
+    <li><i class="fa fa-audio-description"></i>
+        <div class="icon-title">fa-audio-description</div>
+    </li>
+    <li><i class="fa fa-blind"></i>
+        <div class="icon-title">fa-blind</div>
+    </li>
+    <li><i class="fa fa-braille"></i>
+        <div class="icon-title">fa-braille</div>
+    </li>
+    <li><i class="fa fa-cc"></i>
+        <div class="icon-title">fa-cc</div>
+    </li>
+    <li><i class="fa fa-deaf"></i>
+        <div class="icon-title">fa-deaf</div>
+    </li>
+    <li><i class="fa fa-deafness"></i>
+        <div class="icon-title">fa-deafness</div>
+    </li>
+    <li><i class="fa fa-hard-of-hearing"></i>
+        <div class="icon-title">fa-hard-of-hearing</div>
+    </li>
+    <li><i class="fa fa-low-vision"></i>
+        <div class="icon-title">fa-low-vision</div>
+    </li>
+    <li><i class="fa fa-question-circle-o"></i>
+        <div class="icon-title">fa-question-circle-o</div>
+    </li>
+    <li><i class="fa fa-sign-language"></i>
+        <div class="icon-title">fa-sign-language</div>
+    </li>
+    <li><i class="fa fa-signing"></i>
+        <div class="icon-title">fa-signing</div>
+    </li>
+    <li><i class="fa fa-tty"></i>
+        <div class="icon-title">fa-tty</div>
+    </li>
+    <li><i class="fa fa-universal-access"></i>
+        <div class="icon-title">fa-universal-access</div>
+    </li>
+    <li><i class="fa fa-volume-control-phone"></i>
+        <div class="icon-title">fa-volume-control-phone</div>
+    </li>
+    <li><i class="fa fa-wheelchair"></i>
+        <div class="icon-title">fa-wheelchair</div>
+    </li>
+    <li><i class="fa fa-wheelchair-alt"></i>
+        <div class="icon-title">fa-wheelchair-alt</div>
+    </li>
+    <li><i class="fa fa-hand-grab-o"></i>
+        <div class="icon-title">fa-hand-grab-o</div>
+    </li>
+    <li><i class="fa fa-hand-lizard-o"></i>
+        <div class="icon-title">fa-hand-lizard-o</div>
+    </li>
+    <li><i class="fa fa-hand-o-down"></i>
+        <div class="icon-title">fa-hand-o-down</div>
+    </li>
+    <li><i class="fa fa-hand-o-left"></i>
+        <div class="icon-title">fa-hand-o-left</div>
+    </li>
+    <li><i class="fa fa-hand-o-right"></i>
+        <div class="icon-title">fa-hand-o-right</div>
+    </li>
+    <li><i class="fa fa-hand-o-up"></i>
+        <div class="icon-title">fa-hand-o-up</div>
+    </li>
+    <li><i class="fa fa-hand-paper-o"></i>
+        <div class="icon-title">fa-hand-paper-o</div>
+    </li>
+    <li><i class="fa fa-hand-peace-o"></i>
+        <div class="icon-title">fa-hand-peace-o</div>
+    </li>
+    <li><i class="fa fa-hand-pointer-o"></i>
+        <div class="icon-title">fa-hand-pointer-o</div>
+    </li>
+    <li><i class="fa fa-hand-rock-o"></i>
+        <div class="icon-title">fa-hand-rock-o</div>
+    </li>
+    <li><i class="fa fa-hand-scissors-o"></i>
+        <div class="icon-title">fa-hand-scissors-o</div>
+    </li>
+    <li><i class="fa fa-hand-spock-o"></i>
+        <div class="icon-title">fa-hand-spock-o</div>
+    </li>
+    <li><i class="fa fa-hand-stop-o"></i>
+        <div class="icon-title">fa-hand-stop-o</div>
+    </li>
+    <li><i class="fa fa-thumbs-down"></i>
+        <div class="icon-title">fa-thumbs-down</div>
+    </li>
+    <li><i class="fa fa-thumbs-o-down"></i>
+        <div class="icon-title">fa-thumbs-o-down</div>
+    </li>
+    <li><i class="fa fa-thumbs-o-up"></i>
+        <div class="icon-title">fa-thumbs-o-up</div>
+    </li>
+    <li><i class="fa fa-thumbs-up"></i>
+        <div class="icon-title">fa-thumbs-up</div>
+    </li>
+    <li><i class="fa fa-ambulance"></i>
+        <div class="icon-title">fa-ambulance</div>
+    </li>
+    <li><i class="fa fa-automobile"></i>
+        <div class="icon-title">fa-automobile</div>
+    </li>
+    <li><i class="fa fa-bicycle"></i>
+        <div class="icon-title">fa-bicycle</div>
+    </li>
+    <li><i class="fa fa-bus"></i>
+        <div class="icon-title">fa-bus</div>
+    </li>
+    <li><i class="fa fa-cab"></i>
+        <div class="icon-title">fa-cab</div>
+    </li>
+    <li><i class="fa fa-car"></i>
+        <div class="icon-title">fa-car</div>
+    </li>
+    <li><i class="fa fa-fighter-jet"></i>
+        <div class="icon-title">fa-fighter-jet</div>
+    </li>
+    <li><i class="fa fa-motorcycle"></i>
+        <div class="icon-title">fa-motorcycle</div>
+    </li>
+    <li><i class="fa fa-plane"></i>
+        <div class="icon-title">fa-plane</div>
+    </li>
+    <li><i class="fa fa-rocket"></i>
+        <div class="icon-title">fa-rocket</div>
+    </li>
+    <li><i class="fa fa-ship"></i>
+        <div class="icon-title">fa-ship</div>
+    </li>
+    <li><i class="fa fa-space-shuttle"></i>
+        <div class="icon-title">fa-space-shuttle</div>
+    </li>
+    <li><i class="fa fa-subway"></i>
+        <div class="icon-title">fa-subway</div>
+    </li>
+    <li><i class="fa fa-taxi"></i>
+        <div class="icon-title">fa-taxi</div>
+    </li>
+    <li><i class="fa fa-train"></i>
+        <div class="icon-title">fa-train</div>
+    </li>
+    <li><i class="fa fa-truck"></i>
+        <div class="icon-title">fa-truck</div>
+    </li>
+    <li><i class="fa fa-wheelchair"></i>
+        <div class="icon-title">fa-wheelchair</div>
+    </li>
+    <li><i class="fa fa-wheelchair-alt"></i>
+        <div class="icon-title">fa-wheelchair-alt</div>
+    </li>
+    <li><i class="fa fa-genderless"></i>
+        <div class="icon-title">fa-genderless</div>
+    </li>
+    <li><i class="fa fa-intersex"></i>
+        <div class="icon-title">fa-intersex</div>
+    </li>
+    <li><i class="fa fa-mars"></i>
+        <div class="icon-title">fa-mars</div>
+    </li>
+    <li><i class="fa fa-mars-double"></i>
+        <div class="icon-title">fa-mars-double</div>
+    </li>
+    <li><i class="fa fa-mars-stroke"></i>
+        <div class="icon-title">fa-mars-stroke</div>
+    </li>
+    <li><i class="fa fa-mars-stroke-h"></i>
+        <div class="icon-title">fa-mars-stroke-h</div>
+    </li>
+    <li><i class="fa fa-mars-stroke-v"></i>
+        <div class="icon-title">fa-mars-stroke-v</div>
+    </li>
+    <li><i class="fa fa-mercury"></i>
+        <div class="icon-title">fa-mercury</div>
+    </li>
+    <li><i class="fa fa-neuter"></i>
+        <div class="icon-title">fa-neuter</div>
+    </li>
+    <li><i class="fa fa-transgender"></i>
+        <div class="icon-title">fa-transgender</div>
+    </li>
+    <li><i class="fa fa-transgender-alt"></i>
+        <div class="icon-title">fa-transgender-alt</div>
+    </li>
+    <li><i class="fa fa-venus"></i>
+        <div class="icon-title">fa-venus</div>
+    </li>
+    <li><i class="fa fa-venus-double"></i>
+        <div class="icon-title">fa-venus-double</div>
+    </li>
+    <li><i class="fa fa-venus-mars"></i>
+        <div class="icon-title">fa-venus-mars</div>
+    </li>
+    <li><i class="fa fa-file"></i>
+        <div class="icon-title">fa-file</div>
+    </li>
+    <li><i class="fa fa-file-archive-o"></i>
+        <div class="icon-title">fa-file-archive-o</div>
+    </li>
+    <li><i class="fa fa-file-audio-o"></i>
+        <div class="icon-title">fa-file-audio-o</div>
+    </li>
+    <li><i class="fa fa-file-code-o"></i>
+        <div class="icon-title">fa-file-code-o</div>
+    </li>
+    <li><i class="fa fa-file-excel-o"></i>
+        <div class="icon-title">fa-file-excel-o</div>
+    </li>
+    <li><i class="fa fa-file-image-o"></i>
+        <div class="icon-title">fa-file-image-o</div>
+    </li>
+    <li><i class="fa fa-file-movie-o"></i>
+        <div class="icon-title">fa-file-movie-o</div>
+    </li>
+    <li><i class="fa fa-file-o"></i>
+        <div class="icon-title">fa-file-o</div>
+    </li>
+    <li><i class="fa fa-file-pdf-o"></i>
+        <div class="icon-title">fa-file-pdf-o</div>
+    </li>
+    <li><i class="fa fa-file-photo-o"></i>
+        <div class="icon-title">fa-file-photo-o</div>
+    </li>
+    <li><i class="fa fa-file-picture-o"></i>
+        <div class="icon-title">fa-file-picture-o</div>
+    </li>
+    <li><i class="fa fa-file-powerpoint-o"></i>
+        <div class="icon-title">fa-file-powerpoint-o</div>
+    </li>
+    <li><i class="fa fa-file-sound-o"></i>
+        <div class="icon-title">fa-file-sound-o</div>
+    </li>
+    <li><i class="fa fa-file-text"></i>
+        <div class="icon-title">fa-file-text</div>
+    </li>
+    <li><i class="fa fa-file-text-o"></i>
+        <div class="icon-title">fa-file-text-o</div>
+    </li>
+    <li><i class="fa fa-file-video-o"></i>
+        <div class="icon-title">fa-file-video-o</div>
+    </li>
+    <li><i class="fa fa-file-word-o"></i>
+        <div class="icon-title">fa-file-word-o</div>
+    </li>
+    <li><i class="fa fa-file-zip-o"></i>
+        <div class="icon-title">fa-file-zip-o</div>
+    </li>
+    <li><i class="fa fa-circle-o-notch"></i>
+        <div class="icon-title">fa-circle-o-notch</div>
+    </li>
+    <li><i class="fa fa-cog"></i>
+        <div class="icon-title">fa-cog</div>
+    </li>
+    <li><i class="fa fa-gear"></i>
+        <div class="icon-title">fa-gear</div>
+    </li>
+    <li><i class="fa fa-refresh"></i>
+        <div class="icon-title">fa-refresh</div>
+    </li>
+    <li><i class="fa fa-spinner"></i>
+        <div class="icon-title">fa-spinner</div>
+    </li>
+    <li><i class="fa fa-check-square"></i>
+        <div class="icon-title">fa-check-square</div>
+    </li>
+    <li><i class="fa fa-check-square-o"></i>
+        <div class="icon-title">fa-check-square-o</div>
+    </li>
+    <li><i class="fa fa-circle"></i>
+        <div class="icon-title">fa-circle</div>
+    </li>
+    <li><i class="fa fa-circle-o"></i>
+        <div class="icon-title">fa-circle-o</div>
+    </li>
+    <li><i class="fa fa-dot-circle-o"></i>
+        <div class="icon-title">fa-dot-circle-o</div>
+    </li>
+    <li><i class="fa fa-minus-square"></i>
+        <div class="icon-title">fa-minus-square</div>
+    </li>
+    <li><i class="fa fa-minus-square-o"></i>
+        <div class="icon-title">fa-minus-square-o</div>
+    </li>
+    <li><i class="fa fa-plus-square"></i>
+        <div class="icon-title">fa-plus-square</div>
+    </li>
+    <li><i class="fa fa-plus-square-o"></i>
+        <div class="icon-title">fa-plus-square-o</div>
+    </li>
+    <li><i class="fa fa-square"></i>
+        <div class="icon-title">fa-square</div>
+    </li>
+    <li><i class="fa fa-square-o"></i>
+        <div class="icon-title">fa-square-o</div>
+    </li>
+    <li><i class="fa fa-cc-amex"></i>
+        <div class="icon-title">fa-cc-amex</div>
+    </li>
+    <li><i class="fa fa-cc-diners-club"></i>
+        <div class="icon-title">fa-cc-diners-club</div>
+    </li>
+    <li><i class="fa fa-cc-discover"></i>
+        <div class="icon-title">fa-cc-discover</div>
+    </li>
+    <li><i class="fa fa-cc-jcb"></i>
+        <div class="icon-title">fa-cc-jcb</div>
+    </li>
+    <li><i class="fa fa-cc-mastercard"></i>
+        <div class="icon-title">fa-cc-mastercard</div>
+    </li>
+    <li><i class="fa fa-cc-paypal"></i>
+        <div class="icon-title">fa-cc-paypal</div>
+    </li>
+    <li><i class="fa fa-cc-stripe"></i>
+        <div class="icon-title">fa-cc-stripe</div>
+    </li>
+    <li><i class="fa fa-cc-visa"></i>
+        <div class="icon-title">fa-cc-visa</div>
+    </li>
+    <li><i class="fa fa-credit-card"></i>
+        <div class="icon-title">fa-credit-card</div>
+    </li>
+    <li><i class="fa fa-credit-card-alt"></i>
+        <div class="icon-title">fa-credit-card-alt</div>
+    </li>
+    <li><i class="fa fa-google-wallet"></i>
+        <div class="icon-title">fa-google-wallet</div>
+    </li>
+    <li><i class="fa fa-paypal"></i>
+        <div class="icon-title">fa-paypal</div>
+    </li>
+    <li><i class="fa fa-area-chart"></i>
+        <div class="icon-title">fa-area-chart</div>
+    </li>
+    <li><i class="fa fa-bar-chart"></i>
+        <div class="icon-title">fa-bar-chart</div>
+    </li>
+    <li><i class="fa fa-bar-chart-o"></i>
+        <div class="icon-title">fa-bar-chart-o</div>
+    </li>
+    <li><i class="fa fa-line-chart"></i>
+        <div class="icon-title">fa-line-chart</div>
+    </li>
+    <li><i class="fa fa-pie-chart"></i>
+        <div class="icon-title">fa-pie-chart</div>
+    </li>
+    <li><i class="fa fa-bitcoin"></i>
+        <div class="icon-title">fa-bitcoin</div>
+    </li>
+    <li><i class="fa fa-btc"></i>
+        <div class="icon-title">fa-btc</div>
+    </li>
+    <li><i class="fa fa-cny"></i>
+        <div class="icon-title">fa-cny</div>
+    </li>
+    <li><i class="fa fa-dollar"></i>
+        <div class="icon-title">fa-dollar</div>
+    </li>
+    <li><i class="fa fa-eur"></i>
+        <div class="icon-title">fa-eur</div>
+    </li>
+    <li><i class="fa fa-euro"></i>
+        <div class="icon-title">fa-euro</div>
+    </li>
+    <li><i class="fa fa-gbp"></i>
+        <div class="icon-title">fa-gbp</div>
+    </li>
+    <li><i class="fa fa-gg"></i>
+        <div class="icon-title">fa-gg</div>
+    </li>
+    <li><i class="fa fa-gg-circle"></i>
+        <div class="icon-title">fa-gg-circle</div>
+    </li>
+    <li><i class="fa fa-ils"></i>
+        <div class="icon-title">fa-ils</div>
+    </li>
+    <li><i class="fa fa-inr"></i>
+        <div class="icon-title">fa-inr</div>
+    </li>
+    <li><i class="fa fa-jpy"></i>
+        <div class="icon-title">fa-jpy</div>
+    </li>
+    <li><i class="fa fa-krw"></i>
+        <div class="icon-title">fa-krw</div>
+    </li>
+    <li><i class="fa fa-money"></i>
+        <div class="icon-title">fa-money</div>
+    </li>
+    <li><i class="fa fa-rmb"></i>
+        <div class="icon-title">fa-rmb</div>
+    </li>
+    <li><i class="fa fa-rouble"></i>
+        <div class="icon-title">fa-rouble</div>
+    </li>
+    <li><i class="fa fa-rub"></i>
+        <div class="icon-title">fa-rub</div>
+    </li>
+    <li><i class="fa fa-ruble"></i>
+        <div class="icon-title">fa-ruble</div>
+    </li>
+    <li><i class="fa fa-rupee"></i>
+        <div class="icon-title">fa-rupee</div>
+    </li>
+    <li><i class="fa fa-shekel"></i>
+        <div class="icon-title">fa-shekel</div>
+    </li>
+    <li><i class="fa fa-sheqel"></i>
+        <div class="icon-title">fa-sheqel</div>
+    </li>
+    <li><i class="fa fa-try"></i>
+        <div class="icon-title">fa-try</div>
+    </li>
+    <li><i class="fa fa-turkish-lira"></i>
+        <div class="icon-title">fa-turkish-lira</div>
+    </li>
+    <li><i class="fa fa-usd"></i>
+        <div class="icon-title">fa-usd</div>
+    </li>
+    <li><i class="fa fa-won"></i>
+        <div class="icon-title">fa-won</div>
+    </li>
+    <li><i class="fa fa-yen"></i>
+        <div class="icon-title">fa-yen</div>
+    </li>
+    <li><i class="fa fa-align-center"></i>
+        <div class="icon-title">fa-align-center</div>
+    </li>
+    <li><i class="fa fa-align-justify"></i>
+        <div class="icon-title">fa-align-justify</div>
+    </li>
+    <li><i class="fa fa-align-left"></i>
+        <div class="icon-title">fa-align-left</div>
+    </li>
+    <li><i class="fa fa-align-right"></i>
+        <div class="icon-title">fa-align-right</div>
+    </li>
+    <li><i class="fa fa-bold"></i>
+        <div class="icon-title">fa-bold</div>
+    </li>
+    <li><i class="fa fa-chain"></i>
+        <div class="icon-title">fa-chain</div>
+    </li>
+    <li><i class="fa fa-chain-broken"></i>
+        <div class="icon-title">fa-chain-broken</div>
+    </li>
+    <li><i class="fa fa-clipboard"></i>
+        <div class="icon-title">fa-clipboard</div>
+    </li>
+    <li><i class="fa fa-columns"></i>
+        <div class="icon-title">fa-columns</div>
+    </li>
+    <li><i class="fa fa-copy"></i>
+        <div class="icon-title">fa-copy</div>
+    </li>
+    <li><i class="fa fa-cut"></i>
+        <div class="icon-title">fa-cut</div>
+    </li>
+    <li><i class="fa fa-dedent"></i>
+        <div class="icon-title">fa-dedent</div>
+    </li>
+    <li><i class="fa fa-eraser"></i>
+        <div class="icon-title">fa-eraser</div>
+    </li>
+    <li><i class="fa fa-file"></i>
+        <div class="icon-title">fa-file</div>
+    </li>
+    <li><i class="fa fa-file-o"></i>
+        <div class="icon-title">fa-file-o</div>
+    </li>
+    <li><i class="fa fa-file-text"></i>
+        <div class="icon-title">fa-file-text</div>
+    </li>
+    <li><i class="fa fa-file-text-o"></i>
+        <div class="icon-title">fa-file-text-o</div>
+    </li>
+    <li><i class="fa fa-files-o"></i>
+        <div class="icon-title">fa-files-o</div>
+    </li>
+    <li><i class="fa fa-floppy-o"></i>
+        <div class="icon-title">fa-floppy-o</div>
+    </li>
+    <li><i class="fa fa-font"></i>
+        <div class="icon-title">fa-font</div>
+    </li>
+    <li><i class="fa fa-header"></i>
+        <div class="icon-title">fa-header</div>
+    </li>
+    <li><i class="fa fa-indent"></i>
+        <div class="icon-title">fa-indent</div>
+    </li>
+    <li><i class="fa fa-italic"></i>
+        <div class="icon-title">fa-italic</div>
+    </li>
+    <li><i class="fa fa-link"></i>
+        <div class="icon-title">fa-link</div>
+    </li>
+    <li><i class="fa fa-list"></i>
+        <div class="icon-title">fa-list</div>
+    </li>
+    <li><i class="fa fa-list-alt"></i>
+        <div class="icon-title">fa-list-alt</div>
+    </li>
+    <li><i class="fa fa-list-ol"></i>
+        <div class="icon-title">fa-list-ol</div>
+    </li>
+    <li><i class="fa fa-list-ul"></i>
+        <div class="icon-title">fa-list-ul</div>
+    </li>
+    <li><i class="fa fa-outdent"></i>
+        <div class="icon-title">fa-outdent</div>
+    </li>
+    <li><i class="fa fa-paperclip"></i>
+        <div class="icon-title">fa-paperclip</div>
+    </li>
+    <li><i class="fa fa-paragraph"></i>
+        <div class="icon-title">fa-paragraph</div>
+    </li>
+    <li><i class="fa fa-paste"></i>
+        <div class="icon-title">fa-paste</div>
+    </li>
+    <li><i class="fa fa-repeat"></i>
+        <div class="icon-title">fa-repeat</div>
+    </li>
+    <li><i class="fa fa-rotate-left"></i>
+        <div class="icon-title">fa-rotate-left</div>
+    </li>
+    <li><i class="fa fa-rotate-right"></i>
+        <div class="icon-title">fa-rotate-right</div>
+    </li>
+    <li><i class="fa fa-save"></i>
+        <div class="icon-title">fa-save</div>
+    </li>
+    <li><i class="fa fa-scissors"></i>
+        <div class="icon-title">fa-scissors</div>
+    </li>
+    <li><i class="fa fa-strikethrough"></i>
+        <div class="icon-title">fa-strikethrough</div>
+    </li>
+    <li><i class="fa fa-subscript"></i>
+        <div class="icon-title">fa-subscript</div>
+    </li>
+    <li><i class="fa fa-superscript"></i>
+        <div class="icon-title">fa-superscript</div>
+    </li>
+    <li><i class="fa fa-table"></i>
+        <div class="icon-title">fa-table</div>
+    </li>
+    <li><i class="fa fa-text-height"></i>
+        <div class="icon-title">fa-text-height</div>
+    </li>
+    <li><i class="fa fa-text-width"></i>
+        <div class="icon-title">fa-text-width</div>
+    </li>
+    <li><i class="fa fa-th"></i>
+        <div class="icon-title">fa-th</div>
+    </li>
+    <li><i class="fa fa-th-large"></i>
+        <div class="icon-title">fa-th-large</div>
+    </li>
+    <li><i class="fa fa-th-list"></i>
+        <div class="icon-title">fa-th-list</div>
+    </li>
+    <li><i class="fa fa-underline"></i>
+        <div class="icon-title">fa-underline</div>
+    </li>
+    <li><i class="fa fa-undo"></i>
+        <div class="icon-title">fa-undo</div>
+    </li>
+    <li><i class="fa fa-unlink"></i>
+        <div class="icon-title">fa-unlink</div>
+    </li>
+    <li><i class="fa fa-angle-double-down"></i>
+        <div class="icon-title">fa-angle-double-down</div>
+    </li>
+    <li><i class="fa fa-angle-double-left"></i>
+        <div class="icon-title">fa-angle-double-left</div>
+    </li>
+    <li><i class="fa fa-angle-double-right"></i>
+        <div class="icon-title">fa-angle-double-right</div>
+    </li>
+    <li><i class="fa fa-angle-double-up"></i>
+        <div class="icon-title">fa-angle-double-up</div>
+    </li>
+    <li><i class="fa fa-angle-down"></i>
+        <div class="icon-title">fa-angle-down</div>
+    </li>
+    <li><i class="fa fa-angle-left"></i>
+        <div class="icon-title">fa-angle-left</div>
+    </li>
+    <li><i class="fa fa-angle-right"></i>
+        <div class="icon-title">fa-angle-right</div>
+    </li>
+    <li><i class="fa fa-angle-up"></i>
+        <div class="icon-title">fa-angle-up</div>
+    </li>
+    <li><i class="fa fa-arrow-circle-down"></i>
+        <div class="icon-title">fa-arrow-circle-down</div>
+    </li>
+    <li><i class="fa fa-arrow-circle-left"></i>
+        <div class="icon-title">fa-arrow-circle-left</div>
+    </li>
+    <li><i class="fa fa-arrow-circle-o-down"></i>
+        <div class="icon-title">fa-arrow-circle-o-down</div>
+    </li>
+    <li><i class="fa fa-arrow-circle-o-left"></i>
+        <div class="icon-title">fa-arrow-circle-o-left</div>
+    </li>
+    <li><i class="fa fa-arrow-circle-o-right"></i>
+        <div class="icon-title">fa-arrow-circle-o-right</div>
+    </li>
+    <li><i class="fa fa-arrow-circle-o-up"></i>
+        <div class="icon-title">fa-arrow-circle-o-up</div>
+    </li>
+    <li><i class="fa fa-arrow-circle-right"></i>
+        <div class="icon-title">fa-arrow-circle-right</div>
+    </li>
+    <li><i class="fa fa-arrow-circle-up"></i>
+        <div class="icon-title">fa-arrow-circle-up</div>
+    </li>
+    <li><i class="fa fa-arrow-down"></i>
+        <div class="icon-title">fa-arrow-down</div>
+    </li>
+    <li><i class="fa fa-arrow-left"></i>
+        <div class="icon-title">fa-arrow-left</div>
+    </li>
+    <li><i class="fa fa-arrow-right"></i>
+        <div class="icon-title">fa-arrow-right</div>
+    </li>
+    <li><i class="fa fa-arrow-up"></i>
+        <div class="icon-title">fa-arrow-up</div>
+    </li>
+    <li><i class="fa fa-arrows"></i>
+        <div class="icon-title">fa-arrows</div>
+    </li>
+    <li><i class="fa fa-arrows-alt"></i>
+        <div class="icon-title">fa-arrows-alt</div>
+    </li>
+    <li><i class="fa fa-arrows-h"></i>
+        <div class="icon-title">fa-arrows-h</div>
+    </li>
+    <li><i class="fa fa-arrows-v"></i>
+        <div class="icon-title">fa-arrows-v</div>
+    </li>
+    <li><i class="fa fa-caret-down"></i>
+        <div class="icon-title">fa-caret-down</div>
+    </li>
+    <li><i class="fa fa-caret-left"></i>
+        <div class="icon-title">fa-caret-left</div>
+    </li>
+    <li><i class="fa fa-caret-right"></i>
+        <div class="icon-title">fa-caret-right</div>
+    </li>
+    <li><i class="fa fa-caret-square-o-down"></i>
+        <div class="icon-title">fa-caret-square-o-down</div>
+    </li>
+    <li><i class="fa fa-caret-square-o-left"></i>
+        <div class="icon-title">fa-caret-square-o-left</div>
+    </li>
+    <li><i class="fa fa-caret-square-o-right"></i>
+        <div class="icon-title">fa-caret-square-o-right</div>
+    </li>
+    <li><i class="fa fa-caret-square-o-up"></i>
+        <div class="icon-title">fa-caret-square-o-up</div>
+    </li>
+    <li><i class="fa fa-caret-up"></i>
+        <div class="icon-title">fa-caret-up</div>
+    </li>
+    <li><i class="fa fa-chevron-circle-down"></i>
+        <div class="icon-title">fa-chevron-circle-down</div>
+    </li>
+    <li><i class="fa fa-chevron-circle-left"></i>
+        <div class="icon-title">fa-chevron-circle-left</div>
+    </li>
+    <li><i class="fa fa-chevron-circle-right"></i>
+        <div class="icon-title">fa-chevron-circle-right</div>
+    </li>
+    <li><i class="fa fa-chevron-circle-up"></i>
+        <div class="icon-title">fa-chevron-circle-up</div>
+    </li>
+    <li><i class="fa fa-chevron-down"></i>
+        <div class="icon-title">fa-chevron-down</div>
+    </li>
+    <li><i class="fa fa-chevron-left"></i>
+        <div class="icon-title">fa-chevron-left</div>
+    </li>
+    <li><i class="fa fa-chevron-right"></i>
+        <div class="icon-title">fa-chevron-right</div>
+    </li>
+    <li><i class="fa fa-chevron-up"></i>
+        <div class="icon-title">fa-chevron-up</div>
+    </li>
+    <li><i class="fa fa-exchange"></i>
+        <div class="icon-title">fa-exchange</div>
+    </li>
+    <li><i class="fa fa-hand-o-down"></i>
+        <div class="icon-title">fa-hand-o-down</div>
+    </li>
+    <li><i class="fa fa-hand-o-left"></i>
+        <div class="icon-title">fa-hand-o-left</div>
+    </li>
+    <li><i class="fa fa-hand-o-right"></i>
+        <div class="icon-title">fa-hand-o-right</div>
+    </li>
+    <li><i class="fa fa-hand-o-up"></i>
+        <div class="icon-title">fa-hand-o-up</div>
+    </li>
+    <li><i class="fa fa-long-arrow-down"></i>
+        <div class="icon-title">fa-long-arrow-down</div>
+    </li>
+    <li><i class="fa fa-long-arrow-left"></i>
+        <div class="icon-title">fa-long-arrow-left</div>
+    </li>
+    <li><i class="fa fa-long-arrow-right"></i>
+        <div class="icon-title">fa-long-arrow-right</div>
+    </li>
+    <li><i class="fa fa-long-arrow-up"></i>
+        <div class="icon-title">fa-long-arrow-up</div>
+    </li>
+    <li><i class="fa fa-toggle-down"></i>
+        <div class="icon-title">fa-toggle-down</div>
+    </li>
+    <li><i class="fa fa-toggle-left"></i>
+        <div class="icon-title">fa-toggle-left</div>
+    </li>
+    <li><i class="fa fa-toggle-right"></i>
+        <div class="icon-title">fa-toggle-right</div>
+    </li>
+    <li><i class="fa fa-toggle-up"></i>
+        <div class="icon-title">fa-toggle-up</div>
+    </li>
+    <li><i class="fa fa-arrows-alt"></i>
+        <div class="icon-title">fa-arrows-alt</div>
+    </li>
+    <li><i class="fa fa-backward"></i>
+        <div class="icon-title">fa-backward</div>
+    </li>
+    <li><i class="fa fa-compress"></i>
+        <div class="icon-title">fa-compress</div>
+    </li>
+    <li><i class="fa fa-eject"></i>
+        <div class="icon-title">fa-eject</div>
+    </li>
+    <li><i class="fa fa-expand"></i>
+        <div class="icon-title">fa-expand</div>
+    </li>
+    <li><i class="fa fa-fast-backward"></i>
+        <div class="icon-title">fa-fast-backward</div>
+    </li>
+    <li><i class="fa fa-fast-forward"></i>
+        <div class="icon-title">fa-fast-forward</div>
+    </li>
+    <li><i class="fa fa-forward"></i>
+        <div class="icon-title">fa-forward</div>
+    </li>
+    <li><i class="fa fa-pause"></i>
+        <div class="icon-title">fa-pause</div>
+    </li>
+    <li><i class="fa fa-pause-circle"></i>
+        <div class="icon-title">fa-pause-circle</div>
+    </li>
+    <li><i class="fa fa-pause-circle-o"></i>
+        <div class="icon-title">fa-pause-circle-o</div>
+    </li>
+    <li><i class="fa fa-play"></i>
+        <div class="icon-title">fa-play</div>
+    </li>
+    <li><i class="fa fa-play-circle"></i>
+        <div class="icon-title">fa-play-circle</div>
+    </li>
+    <li><i class="fa fa-play-circle-o"></i>
+        <div class="icon-title">fa-play-circle-o</div>
+    </li>
+    <li><i class="fa fa-random"></i>
+        <div class="icon-title">fa-random</div>
+    </li>
+    <li><i class="fa fa-step-backward"></i>
+        <div class="icon-title">fa-step-backward</div>
+    </li>
+    <li><i class="fa fa-step-forward"></i>
+        <div class="icon-title">fa-step-forward</div>
+    </li>
+    <li><i class="fa fa-stop"></i>
+        <div class="icon-title">fa-stop</div>
+    </li>
+    <li><i class="fa fa-stop-circle"></i>
+        <div class="icon-title">fa-stop-circle</div>
+    </li>
+    <li><i class="fa fa-stop-circle-o"></i>
+        <div class="icon-title">fa-stop-circle-o</div>
+    </li>
+    <li><i class="fa fa-youtube-play"></i>
+        <div class="icon-title">fa-youtube-play</div>
+    </li>
+    <li><i class="fa fa-500px"></i>
+        <div class="icon-title">fa-500px</div>
+    </li>
+    <li><i class="fa fa-adn"></i>
+        <div class="icon-title">fa-adn</div>
+    </li>
+    <li><i class="fa fa-amazon"></i>
+        <div class="icon-title">fa-amazon</div>
+    </li>
+    <li><i class="fa fa-android"></i>
+        <div class="icon-title">fa-android</div>
+    </li>
+    <li><i class="fa fa-angellist"></i>
+        <div class="icon-title">fa-angellist</div>
+    </li>
+    <li><i class="fa fa-apple"></i>
+        <div class="icon-title">fa-apple</div>
+    </li>
+    <li><i class="fa fa-bandcamp"></i>
+        <div class="icon-title">fa-bandcamp</div>
+    </li>
+    <li><i class="fa fa-behance"></i>
+        <div class="icon-title">fa-behance</div>
+    </li>
+    <li><i class="fa fa-behance-square"></i>
+        <div class="icon-title">fa-behance-square</div>
+    </li>
+    <li><i class="fa fa-bitbucket"></i>
+        <div class="icon-title">fa-bitbucket</div>
+    </li>
+    <li><i class="fa fa-bitbucket-square"></i>
+        <div class="icon-title">fa-bitbucket-square</div>
+    </li>
+    <li><i class="fa fa-bitcoin"></i>
+        <div class="icon-title">fa-bitcoin</div>
+    </li>
+    <li><i class="fa fa-black-tie"></i>
+        <div class="icon-title">fa-black-tie</div>
+    </li>
+    <li><i class="fa fa-bluetooth"></i>
+        <div class="icon-title">fa-bluetooth</div>
+    </li>
+    <li><i class="fa fa-bluetooth-b"></i>
+        <div class="icon-title">fa-bluetooth-b</div>
+    </li>
+    <li><i class="fa fa-btc"></i>
+        <div class="icon-title">fa-btc</div>
+    </li>
+    <li><i class="fa fa-buysellads"></i>
+        <div class="icon-title">fa-buysellads</div>
+    </li>
+    <li><i class="fa fa-cc-amex"></i>
+        <div class="icon-title">fa-cc-amex</div>
+    </li>
+    <li><i class="fa fa-cc-diners-club"></i>
+        <div class="icon-title">fa-cc-diners-club</div>
+    </li>
+    <li><i class="fa fa-cc-discover"></i>
+        <div class="icon-title">fa-cc-discover</div>
+    </li>
+    <li><i class="fa fa-cc-jcb"></i>
+        <div class="icon-title">fa-cc-jcb</div>
+    </li>
+    <li><i class="fa fa-cc-mastercard"></i>
+        <div class="icon-title">fa-cc-mastercard</div>
+    </li>
+    <li><i class="fa fa-cc-paypal"></i>
+        <div class="icon-title">fa-cc-paypal</div>
+    </li>
+    <li><i class="fa fa-cc-stripe"></i>
+        <div class="icon-title">fa-cc-stripe</div>
+    </li>
+    <li><i class="fa fa-cc-visa"></i>
+        <div class="icon-title">fa-cc-visa</div>
+    </li>
+    <li><i class="fa fa-chrome"></i>
+        <div class="icon-title">fa-chrome</div>
+    </li>
+    <li><i class="fa fa-codepen"></i>
+        <div class="icon-title">fa-codepen</div>
+    </li>
+    <li><i class="fa fa-codiepie"></i>
+        <div class="icon-title">fa-codiepie</div>
+    </li>
+    <li><i class="fa fa-connectdevelop"></i>
+        <div class="icon-title">fa-connectdevelop</div>
+    </li>
+    <li><i class="fa fa-contao"></i>
+        <div class="icon-title">fa-contao</div>
+    </li>
+    <li><i class="fa fa-css3"></i>
+        <div class="icon-title">fa-css3</div>
+    </li>
+    <li><i class="fa fa-dashcube"></i>
+        <div class="icon-title">fa-dashcube</div>
+    </li>
+    <li><i class="fa fa-delicious"></i>
+        <div class="icon-title">fa-delicious</div>
+    </li>
+    <li><i class="fa fa-deviantart"></i>
+        <div class="icon-title">fa-deviantart</div>
+    </li>
+    <li><i class="fa fa-digg"></i>
+        <div class="icon-title">fa-digg</div>
+    </li>
+    <li><i class="fa fa-dribbble"></i>
+        <div class="icon-title">fa-dribbble</div>
+    </li>
+    <li><i class="fa fa-dropbox"></i>
+        <div class="icon-title">fa-dropbox</div>
+    </li>
+    <li><i class="fa fa-drupal"></i>
+        <div class="icon-title">fa-drupal</div>
+    </li>
+    <li><i class="fa fa-edge"></i>
+        <div class="icon-title">fa-edge</div>
+    </li>
+    <li><i class="fa fa-eercast"></i>
+        <div class="icon-title">fa-eercast</div>
+    </li>
+    <li><i class="fa fa-empire"></i>
+        <div class="icon-title">fa-empire</div>
+    </li>
+    <li><i class="fa fa-envira"></i>
+        <div class="icon-title">fa-envira</div>
+    </li>
+    <li><i class="fa fa-etsy"></i>
+        <div class="icon-title">fa-etsy</div>
+    </li>
+    <li><i class="fa fa-expeditedssl"></i>
+        <div class="icon-title">fa-expeditedssl</div>
+    </li>
+    <li><i class="fa fa-fa"></i>
+        <div class="icon-title">fa-fa</div>
+    </li>
+    <li><i class="fa fa-facebook"></i>
+        <div class="icon-title">fa-facebook</div>
+    </li>
+    <li><i class="fa fa-facebook-f"></i>
+        <div class="icon-title">fa-facebook-f</div>
+    </li>
+    <li><i class="fa fa-facebook-official"></i>
+        <div class="icon-title">fa-facebook-official</div>
+    </li>
+    <li><i class="fa fa-facebook-square"></i>
+        <div class="icon-title">fa-facebook-square</div>
+    </li>
+    <li><i class="fa fa-firefox"></i>
+        <div class="icon-title">fa-firefox</div>
+    </li>
+    <li><i class="fa fa-first-order"></i>
+        <div class="icon-title">fa-first-order</div>
+    </li>
+    <li><i class="fa fa-flickr"></i>
+        <div class="icon-title">fa-flickr</div>
+    </li>
+    <li><i class="fa fa-font-awesome"></i>
+        <div class="icon-title">fa-font-awesome</div>
+    </li>
+    <li><i class="fa fa-fonticons"></i>
+        <div class="icon-title">fa-fonticons</div>
+    </li>
+    <li><i class="fa fa-fort-awesome"></i>
+        <div class="icon-title">fa-fort-awesome</div>
+    </li>
+    <li><i class="fa fa-forumbee"></i>
+        <div class="icon-title">fa-forumbee</div>
+    </li>
+    <li><i class="fa fa-foursquare"></i>
+        <div class="icon-title">fa-foursquare</div>
+    </li>
+    <li><i class="fa fa-free-code-camp"></i>
+        <div class="icon-title">fa-free-code-camp</div>
+    </li>
+    <li><i class="fa fa-ge"></i>
+        <div class="icon-title">fa-ge</div>
+    </li>
+    <li><i class="fa fa-get-pocket"></i>
+        <div class="icon-title">fa-get-pocket</div>
+    </li>
+    <li><i class="fa fa-gg"></i>
+        <div class="icon-title">fa-gg</div>
+    </li>
+    <li><i class="fa fa-gg-circle"></i>
+        <div class="icon-title">fa-gg-circle</div>
+    </li>
+    <li><i class="fa fa-git"></i>
+        <div class="icon-title">fa-git</div>
+    </li>
+    <li><i class="fa fa-git-square"></i>
+        <div class="icon-title">fa-git-square</div>
+    </li>
+    <li><i class="fa fa-github"></i>
+        <div class="icon-title">fa-github</div>
+    </li>
+    <li><i class="fa fa-github-alt"></i>
+        <div class="icon-title">fa-github-alt</div>
+    </li>
+    <li><i class="fa fa-github-square"></i>
+        <div class="icon-title">fa-github-square</div>
+    </li>
+    <li><i class="fa fa-gitlab"></i>
+        <div class="icon-title">fa-gitlab</div>
+    </li>
+    <li><i class="fa fa-gittip"></i>
+        <div class="icon-title">fa-gittip</div>
+    </li>
+    <li><i class="fa fa-glide"></i>
+        <div class="icon-title">fa-glide</div>
+    </li>
+    <li><i class="fa fa-glide-g"></i>
+        <div class="icon-title">fa-glide-g</div>
+    </li>
+    <li><i class="fa fa-google"></i>
+        <div class="icon-title">fa-google</div>
+    </li>
+    <li><i class="fa fa-google-plus"></i>
+        <div class="icon-title">fa-google-plus</div>
+    </li>
+    <li><i class="fa fa-google-plus-circle"></i>
+        <div class="icon-title">fa-google-plus-circle</div>
+    </li>
+    <li><i class="fa fa-google-plus-official"></i>
+        <div class="icon-title">fa-google-plus-official</div>
+    </li>
+    <li><i class="fa fa-google-plus-square"></i>
+        <div class="icon-title">fa-google-plus-square</div>
+    </li>
+    <li><i class="fa fa-google-wallet"></i>
+        <div class="icon-title">fa-google-wallet</div>
+    </li>
+    <li><i class="fa fa-gratipay"></i>
+        <div class="icon-title">fa-gratipay</div>
+    </li>
+    <li><i class="fa fa-grav"></i>
+        <div class="icon-title">fa-grav</div>
+    </li>
+    <li><i class="fa fa-hacker-news"></i>
+        <div class="icon-title">fa-hacker-news</div>
+    </li>
+    <li><i class="fa fa-houzz"></i>
+        <div class="icon-title">fa-houzz</div>
+    </li>
+    <li><i class="fa fa-html5"></i>
+        <div class="icon-title">fa-html5</div>
+    </li>
+    <li><i class="fa fa-imdb"></i>
+        <div class="icon-title">fa-imdb</div>
+    </li>
+    <li><i class="fa fa-instagram"></i>
+        <div class="icon-title">fa-instagram</div>
+    </li>
+    <li><i class="fa fa-internet-explorer"></i>
+        <div class="icon-title">fa-internet-explorer</div>
+    </li>
+    <li><i class="fa fa-ioxhost"></i>
+        <div class="icon-title">fa-ioxhost</div>
+    </li>
+    <li><i class="fa fa-joomla"></i>
+        <div class="icon-title">fa-joomla</div>
+    </li>
+    <li><i class="fa fa-jsfiddle"></i>
+        <div class="icon-title">fa-jsfiddle</div>
+    </li>
+    <li><i class="fa fa-lastfm"></i>
+        <div class="icon-title">fa-lastfm</div>
+    </li>
+    <li><i class="fa fa-lastfm-square"></i>
+        <div class="icon-title">fa-lastfm-square</div>
+    </li>
+    <li><i class="fa fa-leanpub"></i>
+        <div class="icon-title">fa-leanpub</div>
+    </li>
+    <li><i class="fa fa-linkedin"></i>
+        <div class="icon-title">fa-linkedin</div>
+    </li>
+    <li>
+        <i class="fa fa-linkedin-square"></i>
+        <div class="icon-title">fa-linkedin-square</div>
+    </li>
+    <li>
+        <i class="fa fa-linode"></i>
+        <div class="icon-title">fa-linode</div>
+    </li>
+    <li>
+        <i class="fa fa-linux"></i>
+        <div class="icon-title">fa-linux</div>
+    </li>
+    <li>
+        <i class="fa fa-maxcdn"></i>
+        <div class="icon-title">fa-maxcdn</div>
+    </li>
+    <li>
+        <i class="fa fa-meanpath"></i>
+        <div class="icon-title">fa-meanpath</div>
+    </li>
+    <li>
+        <i class="fa fa-medium"></i>
+        <div class="icon-title">fa-medium</div>
+    </li>
+    <li>
+        <i class="fa fa-meetup"></i>
+        <div class="icon-title">fa-meetup</div>
+    </li>
+    <li>
+        <i class="fa fa-mixcloud"></i>
+        <div class="icon-title">fa-mixcloud</div>
+    </li>
+    <li>
+        <i class="fa fa-modx"></i>
+        <div class="icon-title">fa-modx</div>
+    </li>
+    <li>
+        <i class="fa fa-odnoklassniki"></i>
+        <div class="icon-title">fa-odnoklassniki</div>
+    </li>
+    <li>
+        <i class="fa fa-odnoklassniki-square"></i>
+        <div class="icon-title">fa-odnoklassniki-square</div>
+    </li>
+    <li>
+        <i class="fa fa-opencart"></i>
+        <div class="icon-title">fa-opencart</div>
+    </li>
+    <li>
+        <i class="fa fa-openid"></i>
+        <div class="icon-title">fa-openid</div>
+    </li>
+    <li>
+        <i class="fa fa-opera"></i>
+        <div class="icon-title">fa-opera</div>
+    </li>
+    <li>
+        <i class="fa fa-optin-monster"></i>
+        <div class="icon-title">fa-optin-monster</div>
+    </li>
+    <li>
+        <i class="fa fa-pagelines"></i>
+        <div class="icon-title">fa-pagelines</div>
+    </li>
+    <li>
+        <i class="fa fa-paypal"></i>
+        <div class="icon-title">fa-paypal</div>
+    </li>
+    <li>
+        <i class="fa fa-pied-piper"></i>
+        <div class="icon-title">fa-pied-piper</div>
+    </li>
+    <li>
+        <i class="fa fa-pied-piper-alt"></i>
+        <div class="icon-title">fa-pied-piper-alt</div>
+    </li>
+    <li>
+        <i class="fa fa-pied-piper-pp"></i>
+        <div class="icon-title">fa-pied-piper-pp</div>
+    </li>
+    <li>
+        <i class="fa fa-pinterest"></i>
+        <div class="icon-title">fa-pinterest</div>
+    </li>
+    <li>
+        <i class="fa fa-pinterest-p"></i>
+        <div class="icon-title">fa-pinterest-p</div>
+    </li>
+    <li>
+        <i class="fa fa-pinterest-square"></i>
+        <div class="icon-title">fa-pinterest-square</div>
+    </li>
+    <li>
+        <i class="fa fa-product-hunt"></i>
+        <div class="icon-title">fa-product-hunt</div>
+    </li>
+    <li>
+        <i class="fa fa-qq"></i>
+        <div class="icon-title">fa-qq</div>
+    </li>
+    <li>
+        <i class="fa fa-quora"></i>
+        <div class="icon-title">fa-quora</div>
+    </li>
+    <li>
+        <i class="fa fa-ra"></i>
+        <div class="icon-title">fa-ra</div>
+    </li>
+    <li>
+        <i class="fa fa-ravelry"></i>
+        <div class="icon-title">fa-ravelry</div>
+    </li>
+    <li>
+        <i class="fa fa-rebel"></i>
+        <div class="icon-title">fa-rebel</div>
+    </li>
+    <li>
+        <i class="fa fa-reddit"></i>
+        <div class="icon-title">fa-reddit</div>
+    </li>
+    <li>
+        <i class="fa fa-reddit-alien"></i>
+        <div class="icon-title">fa-reddit-alien</div>
+    </li>
+    <li>
+        <i class="fa fa-reddit-square"></i>
+        <div class="icon-title">fa-reddit-square</div>
+    </li>
+    <li>
+        <i class="fa fa-renren"></i>
+        <div class="icon-title">fa-renren</div>
+    </li>
+    <li>
+        <i class="fa fa-resistance"></i>
+        <div class="icon-title">fa-resistance</div>
+    </li>
+    <li>
+        <i class="fa fa-safari"></i>
+        <div class="icon-title">fa-safari</div>
+    </li>
+    <li>
+        <i class="fa fa-scribd"></i>
+        <div class="icon-title">fa-scribd</div>
+    </li>
+    <li>
+        <i class="fa fa-sellsy"></i>
+        <div class="icon-title">fa-sellsy</div>
+    </li>
+    <li>
+        <i class="fa fa-share-alt"></i>
+        <div class="icon-title">fa-share-alt</div>
+    </li>
+    <li>
+        <i class="fa fa-share-alt-square"></i>
+        <div class="icon-title">fa-share-alt-square</div>
+    </li>
+    <li>
+        <i class="fa fa-shirtsinbulk"></i>
+        <div class="icon-title">fa-shirtsinbulk</div>
+    </li>
+    <li>
+        <i class="fa fa-simplybuilt"></i>
+        <div class="icon-title">fa-simplybuilt</div>
+    </li>
+    <li>
+        <i class="fa fa-skyatlas"></i>
+        <div class="icon-title">fa-skyatlas</div>
+    </li>
+    <li>
+        <i class="fa fa-skype"></i>
+        <div class="icon-title">fa-skype</div>
+    </li>
+    <li>
+        <i class="fa fa-slack"></i>
+        <div class="icon-title">fa-slack</div>
+    </li>
+    <li>
+        <i class="fa fa-slideshare"></i>
+        <div class="icon-title">fa-slideshare</div>
+    </li>
+    <li>
+        <i class="fa fa-snapchat"></i>
+        <div class="icon-title">fa-snapchat</div>
+    </li>
+    <li>
+        <i class="fa fa-snapchat-ghost"></i>
+        <div class="icon-title">fa-snapchat-ghost</div>
+    </li>
+    <li>
+        <i class="fa fa-snapchat-square"></i>
+        <div class="icon-title">fa-snapchat-square</div>
+    </li>
+    <li>
+        <i class="fa fa-soundcloud"></i>
+        <div class="icon-title">fa-soundcloud</div>
+    </li>
+    <li>
+        <i class="fa fa-spotify"></i>
+        <div class="icon-title">fa-spotify</div>
+    </li>
+    <li>
+        <i class="fa fa-stack-exchange"></i>
+        <div class="icon-title">fa-stack-exchange</div>
+    </li>
+    <li>
+        <i class="fa fa-stack-overflow"></i>
+        <div class="icon-title">fa-stack-overflow</div>
+    </li>
+    <li>
+        <i class="fa fa-steam"></i>
+        <div class="icon-title">fa-steam</div>
+    </li>
+    <li>
+        <i class="fa fa-steam-square"></i>
+        <div class="icon-title">fa-steam-square</div>
+    </li>
+    <li>
+        <i class="fa fa-stumbleupon"></i>
+        <div class="icon-title">fa-stumbleupon</div>
+    </li>
+    <li>
+        <i class="fa fa-stumbleupon-circle"></i>
+        <div class="icon-title">fa-stumbleupon-circle</div>
+    </li>
+    <li>
+        <i class="fa fa-superpowers"></i>
+        <div class="icon-title">fa-superpowers</div>
+    </li>
+    <li>
+        <i class="fa fa-telegram"></i>
+        <div class="icon-title">fa-telegram</div>
+    </li>
+    <li>
+        <i class="fa fa-tencent-weibo"></i>
+        <div class="icon-title">fa-tencent-weibo</div>
+    </li>
+    <li>
+        <i class="fa fa-themeisle"></i>
+        <div class="icon-title">fa-themeisle</div>
+    </li>
+    <li>
+        <i class="fa fa-trello"></i>
+        <div class="icon-title">fa-trello</div>
+    </li>
+    <li>
+        <i class="fa fa-tripadvisor"></i>
+        <div class="icon-title">fa-tripadvisor</div>
+    </li>
+    <li>
+        <i class="fa fa-tumblr"></i>
+        <div class="icon-title">fa-tumblr</div>
+    </li>
+    <li>
+        <i class="fa fa-tumblr-square"></i>
+        <div class="icon-title">fa-tumblr-square</div>
+    </li>
+    <li>
+        <i class="fa fa-twitch"></i>
+        <div class="icon-title">fa-twitch</div>
+    </li>
+    <li>
+        <i class="fa fa-twitter"></i>
+        <div class="icon-title">fa-twitter</div>
+    </li>
+    <li>
+        <i class="fa fa-twitter-square"></i>
+        <div class="icon-title">fa-twitter-square</div>
+    </li>
+    <li>
+        <i class="fa fa-usb"></i>
+        <div class="icon-title">fa-usb</div>
+    </li>
+    <li>
+        <i class="fa fa-viacoin"></i>
+        <div class="icon-title">fa-viacoin</div>
+    </li>
+    <li>
+        <i class="fa fa-viadeo"></i>
+        <div class="icon-title">fa-viadeo</div>
+    </li>
+    <li>
+        <i class="fa fa-viadeo-square"></i>
+        <div class="icon-title">fa-viadeo-square</div>
+    </li>
+    <li>
+        <i class="fa fa-vimeo"></i>
+        <div class="icon-title">fa-vimeo</div>
+    </li>
+    <li>
+        <i class="fa fa-vimeo-square"></i>
+        <div class="icon-title">fa-vimeo-square</div>
+    </li>
+    <li>
+        <i class="fa fa-vine"></i>
+        <div class="icon-title">fa-vine</div>
+    </li>
+    <li>
+        <i class="fa fa-vk"></i>
+        <div class="icon-title">fa-vk</div>
+    </li>
+    <li>
+        <i class="fa fa-wechat"></i>
+        <div class="icon-title">fa-wechat</div>
+    </li>
+    <li>
+        <i class="fa fa-weibo"></i>
+        <div class="icon-title">fa-weibo</div>
+    </li>
+    <li>
+        <i class="fa fa-weixin"></i>
+        <div class="icon-title">fa-weixin</div>
+    </li>
+    <li>
+        <i class="fa fa-whatsapp"></i>
+        <div class="icon-title">fa-whatsapp</div>
+    </li>
+    <li>
+        <i class="fa fa-wikipedia-w"></i>
+        <div class="icon-title">fa-wikipedia-w</div>
+    </li>
+    <li>
+        <i class="fa fa-windows"></i>
+        <div class="icon-title">fa-windows</div>
+    </li>
+    <li>
+        <i class="fa fa-wordpress"></i>
+        <div class="icon-title">fa-wordpress</div>
+    </li>
+    <li>
+        <i class="fa fa-wpbeginner"></i>
+        <div class="icon-title">fa-wpbeginner</div>
+    </li>
+    <li>
+        <i class="fa fa-wpexplorer"></i>
+        <div class="icon-title">fa-wpexplorer</div>
+    </li>
+    <li>
+        <i class="fa fa-wpforms"></i>
+        <div class="icon-title">fa-wpforms</div>
+    </li>
+    <li>
+        <i class="fa fa-xing"></i>
+        <div class="icon-title">fa-xing</div>
+    </li>
+    <li>
+        <i class="fa fa-xing-square"></i>
+        <div class="icon-title">fa-xing-square</div>
+    </li>
+    <li>
+        <i class="fa fa-y-combinator"></i>
+        <div class="icon-title">fa-y-combinator</div>
+    </li>
+    <li>
+        <i class="fa fa-y-combinator-square"></i>
+        <div class="icon-title">fa-y-combinator-square</div>
+    </li>
+    <li>
+        <i class="fa fa-yahoo"></i>
+        <div class="icon-title">fa-yahoo</div>
+    </li>
+    <li>
+        <i class="fa fa-yc"></i>
+        <div class="icon-title">fa-yc</div>
+    </li>
+    <li>
+        <i class="fa fa-yc-square"></i>
+        <div class="icon-title">fa-yc-square</div>
+    </li>
+    <li>
+        <i class="fa fa-yelp"></i>
+        <div class="icon-title">fa-yelp</div>
+    </li>
+    <li>
+        <i class="fa fa-yoast"></i>
+        <div class="icon-title">fa-yoast</div>
+    </li>
+    <li>
+        <i class="fa fa-youtube"></i>
+        <div class="icon-title">fa-youtube</div>
+    </li>
+    <li>
+        <i class="fa fa-youtube-play"></i>
+        <div class="icon-title">fa-youtube-play</div>
+    </li>
+    <li>
+        <i class="fa fa-youtube-square"></i>
+        <div class="icon-title">fa-youtube-square</div>
+    </li>
+    <li>
+        <i class="fa fa-ambulance"></i>
+        <div class="icon-title">fa-ambulance</div>
+    </li>
+    <li>
+        <i class="fa fa-h-square"></i>
+        <div class="icon-title">fa-h-square</div>
+    </li>
+    <li>
+        <i class="fa fa-heart"></i>
+        <div class="icon-title">fa-heart</div>
+    </li>
+    <li>
+        <i class="fa fa-heart-o"></i>
+        <div class="icon-title">fa-heart-o</div>
+    </li>
+    <li>
+        <i class="fa fa-heartbeat"></i>
+        <div class="icon-title">fa-heartbeat</div>
+    </li>
+    <li>
+        <i class="fa fa-hospital-o"></i>
+        <div class="icon-title">fa-hospital-o</div>
+    </li>
+    <li>
+        <i class="fa fa-medkit"></i>
+        <div class="icon-title">fa-medkit</div>
+    </li>
+    <li>
+        <i class="fa fa-plus-square"></i>
+        <div class="icon-title">fa-plus-square</div>
+    </li>
+    <li>
+        <i class="fa fa-stethoscope"></i>
+        <div class="icon-title">fa-stethoscope</div>
+    </li>
+    <li>
+        <i class="fa fa-user-md"></i>
+        <div class="icon-title">fa-user-md</div>
+    </li>
+    <li>
+        <i class="fa fa-wheelchair"></i>
+        <div class="icon-title">fa-wheelchair</div>
+    </li>
+    <li>
+        <i class="fa fa-wheelchair-alt"></i>
+        <div class="icon-title">fa-wheelchair-alt</div>
+    </li>
+</ul>
+
+<script src="__ROOT__/static/plugs/jquery/jquery.min.js" type="text/javascript"></script>
+<script>
+    $(function () {
+        $('li').on('click', function () {
+            var className = $(this).find('i').get(0).className;
+            if (className) {
+                top.$('[name="{$field}"]').val(className).trigger('change');
+                top.layer.close(top.layer.getFrameIndex(window.name));
+            }
+        });
+    });
+</script>
+
+</body>
+</html>

+ 65 - 0
application/admin/view/api/plugs/message.html

@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+<html lang="zh-CN">
+<head>
+    <meta charset="utf-8">
+    <title>{block name="title"}{$title|default=''}{if !empty($title)} · {/if}{:sysconf('site_name')}{/block}</title>
+    <meta name="renderer" content="webkit">
+    <meta name="format-detection" content="telephone=no">
+    <meta name="apple-mobile-web-app-capable" content="yes">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+    <meta name="apple-mobile-web-app-status-bar-style" content="black">
+    <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1">
+    <link href="__ROOT__/static/plugs/layui/css/layui.css?v={:date('ymd')}" rel="stylesheet">
+    <style>.layui-card {
+        margin: 0
+    }
+
+    .layui-card .layui-card-body a {
+        display: block;
+        font-size: 12px;
+        color: #666
+    }</style>
+    <script src="__ROOT__/static/plugs/angular/angular.min.js"></script>
+</head>
+<body id="MessageContainer">
+<div class="layui-card" ng-repeat="x in list">
+    <div class="layui-card-header layui-bg-gray">
+        <a target="_top" href="{:url('@admin')}?messagecode={{x.code}}#{{x.url}}" ng-bind="x.title"></a>
+        <a href="javascript:void(0)" ng-click="setReadState(x.code)" style="position:absolute;right:0;top:0;width:50px;text-align:center">忽略</a>
+    </div>
+    <div class="layui-card-body">
+        <a target="_top" href="{:url('@admin')}?messagecode={{x.code}}#{{x.url}}" ng-bind="x.desc"></a>
+        <a target="_top" href="{:url('@admin')}?messagecode={{x.code}}#{{x.url}}" ng-bind="x.create_at"></a>
+    </div>
+</div>
+<script>
+    (function () {
+        var index = parent.layer.getFrameIndex(window.name);
+        var app = angular.module("MessageContainer", []).run(callback);
+        angular.bootstrap(document.getElementById(app.name), [app.name]);
+
+        function callback($rootScope, $http, $timeout, $interval) {
+            $rootScope.list = [];
+            $rootScope.setReadState = function (code) {
+                $http.post('{:url("@admin/api.message/set")}', {code: code}).then(function () {
+                    refresh(false);
+                });
+            };
+            refresh.call(this, true), $interval(function () {
+                parent.layer.iframeAuto(index);
+                // top.$body.trigger('resize');
+            }, 10);
+
+            function refresh(isCallback) {
+                $http.get('{:url("@admin/api.message/gets")}').then(function (ret) {
+                    $rootScope.list = (ret.data || {data: []}).data;
+                    if ($rootScope.list < 1) parent.layer.style(index, {height: '0'});
+                    if (isCallback !== false) $timeout(refresh, 2000);
+                });
+            }
+        }
+    })();
+</script>
+</body>
+</html>
+

+ 432 - 0
application/admin/view/api/plugs/upfile.html

@@ -0,0 +1,432 @@
+<!DOCTYPE html>
+<html lang="zh-CN">
+<head>
+    <title>{:sysconf('app_name')} {:sysconf('app_version')}</title>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <link href="{:sysconf('site_icon')}" rel="shortcut icon">
+    <meta name="viewport" content="width=device-width, initial-scale=0">
+    <link href="__ROOT__/static/plugs/uploader/webuploader.css" rel="stylesheet" type="text/css"/>
+    <link href="__ROOT__/static/plugs/uploader/theme/uploader.css" rel="stylesheet" type="text/css"/>
+    <script src="__ROOT__/static/plugs/jquery/jquery.min.js"></script>
+    <script src="__ROOT__/static/plugs/uploader/webuploader.min.js"></script>
+    <script src="__ROOT__/static/plugs/uploader/theme/upload.js"></script>
+</head>
+<body>
+<div id="uploader">
+    <div class="queueList">
+        <div id="dndArea" class="placeholder">
+            <div id="filePicker"></div>
+        </div>
+    </div>
+    <div class="statusBar" style="display:none;">
+        <div class="progress">
+            <span class="text">0%</span>
+            <span class="percentage"></span>
+        </div>
+        <div class="info"></div>
+        <div class="btns">
+            {if $mode!=='one'}
+            <div id="filePicker2"></div>
+            {/if}
+            <div class="uploadBtn">开始上传</div>
+        </div>
+    </div>
+</div>
+<script>
+    /* global WebUploader */
+
+    /**
+     * 每个文件上传成功调用
+     * @type Function
+     */
+    function uploaded(ret, file) {
+        var url = ret.url || ret.site_url;
+        $('#' + file.id).attr('data-md5', file.md5).attr('data-src', url);
+        /*{if $mode === 'one'}*/
+        top.$('[name="{$field}"]').map(function () {
+            top.$(this).attr('data-srcs', ret.url).attr('data-md5', file.md5).val(url).trigger('change');
+        });
+        top.layer.close(top.layer.getFrameIndex(window.name));
+        /*{/if}*/
+    }
+
+    var isSuccessState = false;
+
+    function completed() {
+        var btnHTML = '完成上传';
+        $('.uploadBtn').html(btnHTML).on('click', successSelected);
+
+        function successSelected() {
+            if (!isSuccessState && this.innerHTML === btnHTML) {
+                isSuccessState = true;
+                var srcs = [], md5s = [];
+                $('[data-md5] .success').map(function () {
+                    var $li = $(this).parents('[data-md5]');
+                    md5s.push($li.attr('data-md5'));
+                    srcs.push($li.attr('data-src'));
+                });
+                if (srcs.length < 1) return top.$.msg.tips('还没有选择文件,请勾选需要使用的文件!');
+                top.$('[name="{$field}"]').map(function () {
+                    top.$(this).attr('data-srcs', srcs.join('|')).attr('data-md5', md5s.join('|')).val(srcs.join('|')).trigger('change');
+                });
+                top.layer.close(top.layer.getFrameIndex(window.name));
+            }
+        }
+    }
+
+    // 当domReady的时候开始初始化
+    $(function () {
+        var uploader;
+        var $wrap = $('#uploader');
+        /* 文件容器 */
+        var $queue = $('<ul class="filelist"></ul>').appendTo($wrap.find('.queueList'));
+        /* 状态栏,包括进度和控制按钮 */
+        var $statusBar = $wrap.find('.statusBar');
+        /* 文件总体选择信息。 */
+        var $info = $statusBar.find('.info');
+        /* 上传按钮 */
+        var $upload = $wrap.find('.uploadBtn');
+        /* 没选择文件之前的内容。*/
+        var $placeHolder = $wrap.find('.placeholder');
+        var $progress = $statusBar.find('.progress').hide();
+        /* 添加的文件数量 */
+        var fileCount = 0;
+        /* 添加的文件总大小 */
+        var fileSize = 0;
+        /* 优化retina, 在retina下这个值是2 */
+        var ratio = window.devicePixelRatio || 1;
+        /* 缩略图大小 */
+        var thumbnailWidth = 110 * ratio;
+        var thumbnailHeight = 110 * ratio;
+        /* 可能有pedding, ready, uploading, confirm, done */
+        var state = "pedding";
+        /* 所有文件的进度信息,key为file id */
+        var percentages = {};
+        /* 判断浏览器是否支持文件的base64 */
+        var isSupportBase64 = (function () {
+            var data = new Image(), support = true;
+            data.onload = data.onerror = function () {
+                if (parseInt(this.width) !== 1 || parseInt(this.height) !== 1) support = false;
+            };
+            data.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
+            return support;
+        }.call(this));
+        /* 检测是否已经安装flash, 检测flash的版本 */
+        var flashVersion = (function () {
+            var version;
+            try {
+                version = navigator.plugins['Shockwave Flash'].description;
+            } catch (ex) {
+                try {
+                    version = new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version');
+                } catch (ex2) {
+                    version = '0.0';
+                }
+            }
+            version = version.match(/\d+/g);
+            return parseFloat(version[0] + '.' + version[1], 10);
+        })();
+        var supportTransition = (function () {
+            var style = document.createElement('p').style;
+            var isTransition = 'transition' in style || 'WebkitTransition' in style || 'MozTransition' in style || 'msTransition' in style || 'OTransition' in style;
+            return (style = null), isTransition;
+        })();
+
+        if (!WebUploader.Uploader.support('flash') && WebUploader.browser.ie) {
+            /*flash 安装了但是版本过低*/
+            if (flashVersion) return (function (container) {
+                window['expressinstallcallback'] = function (state) {
+                    if (state === 'Download.Cancelled') alert('您取消了更新!');
+                    else if (state === 'Download.Failed') alert('安装失败!');
+                    else alert('安装已成功,请刷新!');
+                    delete window['expressinstallcallback'];
+                };
+                var swf = '__ROOT__/static/plugs/uploader/expressInstall.swf';
+                var html = '<object type="application/' + 'x-shockwave-flash" data="' + swf + '" ';
+                if (WebUploader.browser.ie) html += 'classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" ';
+                container.html(html + 'width="100%" height="100%" style="outline:0"><param name="movie" value="' + swf + '" /><param name="wmode" value="transparent" /><param name="allowscriptaccess" value="always" /></object>');
+            })($wrap);
+            return $wrap.html('<a href="http://www.adobe.com/go/getflashplayer" target="_blank" border="0"><img alt="get flash player" src="http://www.adobe.com/macromedia/style_guide/images/160x41_Get_Flash_Player.jpg" /></a>');
+        } else if (!WebUploader.Uploader.support()) return alert('Web Uploader 不支持您的浏览器!');
+        // 文件上传前的检查
+        WebUploader.Uploader.register({'before-send-file': 'preupload'}, {
+            preupload: function (file) {
+                var me = this, owner = this.owner, deferred = WebUploader.Deferred();
+                owner.md5File(file.source).fail(function () {
+                    deferred.reject();
+                }).then(function (md5) {
+                    file.md5 = md5;
+                    var data = {id: file.id, md5: md5, uptype: '{$uptype}', filename: file.name, safe: '{$safe}' || 0};
+                    $.ajax("{:url('@')}?s=admin/api.plugs/upstate", {
+                        dataType: 'json', method: 'post', data: data, success: function (ret) {
+                            if (parseInt(ret.code) === 1) {
+                                owner.skipFile(file);
+                                uploaded.call(uploader, ret.data, file);
+                                percentages[file.id] = [file.size, 1];
+                                updateTotalProgress();
+                                console.log('文件秒传成功 --> ' + file.name);
+                            } else {
+                                file.md5 = md5;
+                                file.token = ret.data.token || '';
+                                file.key = ret.data.file_url || '';
+                                file.site_url = ret.data.site_url || '';
+                                me.options.server = ret.data.server;
+                                me.options.formData.safe = ret.data.safe || '0';
+                                me.options.formData.OSSAccessKeyId = ret.data.OSSAccessKeyId || ''; // OSS
+                                me.options.formData.signature = ret.data.signature; // OSS
+                                me.options.formData.policy = ret.data.policy; // OSS
+                                me.options.formData.success_action_status = '200'; // OSS
+                            }
+                            deferred.resolve();
+                        }
+                    });
+                });
+                return deferred.promise();
+            }
+        });
+
+        // 实例化
+        uploader = WebUploader.create({
+            pick: {
+                id: '#filePicker',
+                label: '点击选择文件',
+                /*{if $mode === 'one'}*/
+                multiple: false,
+                /*{else}*/
+                multiple: true,
+                /*{/if}*/
+            },
+            accept: {title: '选择文件', extensions: '{$types}', mimeTypes: '{$mimes}'},
+            formData: {},
+            /*{if $mode === 'one'}*/
+            auto: true,
+            fileNumLimit: 1,
+            /*{else}*/
+            auto: false,
+            fileNumLimit: 300,
+            /*{/if}*/
+            swf: '__ROOT__/static/plugs/uploader/Uploader.swf',
+            chunked: false,
+            dnd: '#dndArea',
+            paste: document.body,
+            chunkSize: 512 * 1024,
+            disableGlobalDnd: true,
+            fileSizeLimit: 200 * 1024 * 1024, // 200 M
+            fileSingleSizeLimit: 200 * 1024 * 1024, // 200 M
+            compress: {
+                width: 1600,
+                height: 16000,
+                crop: false, // 是否允许裁剪
+                quality: 90, // 图片质量(只有type为`image/jpeg`的时候才有效)
+                allowMagnify: false, // 是否允许放大(如果想要生成小图的时候不失真,此选项应该设置为false).
+                preserveHeaders: true, // 是否保留头部meta信息
+                noCompressIfLarger: false, // 如果发现压缩后文件大小比原来还大,则使用原来图片
+                compressSize: 1024 * 512, // 单位字节(如果图片大小小于此值,不会采用压缩)
+            }
+        });
+
+        /* 上传开始前的处理 */
+        uploader.on('uploadBeforeSend', function (file, data, header) {
+            header['X_Requested_With'] = 'XMLHttpRequest';
+            data['allowed_types'] = this.options.accept[0].extensions.split(',').join('|');
+            data['md5'] = file.file.md5 || '';
+            data['key'] = file.file.key || '';
+            data['safe'] = file.file.safe || 0;
+            data['token'] = file.file.token || '';
+        });
+
+        /* 处理上传后的结果 */
+        uploader.on('uploadAccept', function (fieldata, ret) {
+            // Qiniu or Local 上传
+            if (parseInt(ret.code) === 1) return uploaded.call(uploader, ret.data, fieldata.file), true;
+            // AliOSS 上传
+            if (fieldata.file.site_url) return uploaded.call(uploader, {'site_url': fieldata.file.site_url}, fieldata.file), true;
+            // 接收错误消息
+            return fieldata.file.setStatus('error', ret.msg), false;
+        });
+
+        // 拖拽时不接受 js, txt 文件。
+        uploader.on('dndAccept', function (items) {
+            var denied = false, len = items.length, unAllowed = 'text/plain;application/javascript ';
+            for (var i = 0; i < len; i++) if (~unAllowed.indexOf(items[i].type)) if (denied = true) break;
+            return !denied;
+        });
+
+        // 添加“添加文件”的按钮,
+        uploader.addButton({id: '#filePicker2', label: '继续添加'});
+        uploader.on('ready', function () {
+            window.uploader = uploader;
+        });
+
+        // 当有文件添加进来时执行,负责view的创建
+        function addFile(file) {
+            var $li = $('<li id="' + file.id + '"><p class="title">' + file.name + '</p><p class="imgWrap"></p><p class="progress"><span></span></p></li>'),
+                $btns = $('<div class="file-panel"><span class="cancel">删除</span><span class="rotateRight">向右旋转</span><span class="rotateLeft">向左旋转</span></div>').appendTo($li),
+                $prgress = $li.find('p.progress span'), $wrap = $li.find('p.imgWrap'), $info = $('<p class="error"></p>');
+            var showError = function (code) {
+                var text = '';
+                if (code === 'exceed_size') text = '文件大小超出';
+                else if (code === 'interrupt') text = '上传暂停';
+                else if (code === 'http' || code === 'server' || code === 'abort') text = '上传失败,请重试';
+                else text = code;
+                $info.text(text).appendTo($li);
+            };
+            if (file.getStatus() === 'invalid') showError(file.statusText);
+            else {
+                $wrap.text('预览中');
+                uploader.makeThumb(file, function (error, src) {
+                    if (error) return $wrap.text('不能预览');
+                    if (isSupportBase64) $wrap.empty().append($('<img src="' + src + '">'));
+                    else $.ajax('{:url("@")}?s=plugs/file/preview', {method: 'post', data: src, dataType: 'json'}).done(function (response) {
+                        if (response.result) $wrap.empty().append($('<img src="' + response.result + '">')); else $wrap.text("预览出错");
+                    });
+                }, thumbnailWidth, thumbnailHeight);
+                percentages[file.id] = [file.size, 0];
+                file.rotation = 0;
+                $upload.html('开始上传');
+            }
+            // 文件上传状态变化
+            file.on('statuschange', function (cur, prev) {
+                if (prev === 'progress') $prgress.hide().width(0);
+                else if (prev === 'queued') $li.off('mouseenter mouseleave'), $btns.remove();
+                if (cur === 'error' || cur === 'invalid') showError(file.statusText), percentages[file.id][1] = 1;
+                else if (cur === 'interrupt') showError('interrupt');
+                else if (cur === 'queued') percentages[file.id][1] = 0;
+                else if (cur === 'progress') $info.remove(), $prgress.css('display', 'block');
+                else if (cur === 'complete') $li.append('<span class="success"></span>');
+                $li.removeClass('state-' + prev).addClass('state-' + cur);
+            });
+            $li.on('mouseenter', function () {
+                $btns.stop().animate({height: 30});
+            }).on('mouseleave', function () {
+                $btns.stop().animate({height: 0});
+            });
+            $btns.on('click', 'span', function () {
+                var index = $(this).index();
+                if (index === 0) return removeFile(file), uploader.removeFile(file);
+                if (index === 1) file.rotation += 90;
+                if (index === 2) file.rotation -= 90;
+                if (supportTransition) {
+                    var deg = 'rotate(' + file.rotation + 'deg)';
+                    $wrap.css({'-webkit-transform': deg, '-mos-transform': deg, '-o-transform': deg, 'transform': deg});
+                } else $wrap.css('filter', 'progid:DXImageTransform.Microsoft.BasicImage(rotation=' + (~~((file.rotation / 90) % 4 + 4) % 4) + ')');
+            });
+            $li.appendTo($queue);
+        }
+
+        // 负责view的销毁
+        function removeFile(file) {
+            delete percentages[file.id];
+            updateTotalProgress();
+            $('#' + file.id).off().find('.file-panel').off().end().remove();
+        }
+
+        function updateTotalProgress() {
+            var loaded = 0, total = 0, spans = $progress.children(), percent;
+            $.each(percentages, function (k, v) {
+                total += v[0], loaded += v[0] * v[1];
+            });
+            percent = total ? loaded / total : 0;
+            spans.eq(0).text(Math.round(percent * 100) + '%');
+            spans.eq(1).css('width', Math.round(percent * 100) + '%');
+            updateStatus();
+        }
+
+        function updateStatus() {
+            var text = '', stats = '';
+            if (state === 'ready') text = '选中' + fileCount + '个文件,共' + WebUploader.formatSize(fileSize) + '。';
+            else if (state === 'confirm') {
+                stats = uploader.getStats();
+                if (stats.uploadFailNum) text = '已成功上传' + stats.successNum + '个文件,' + stats.uploadFailNum + '个文件上传失败,<a class="retry" href="#">重新上传</a>失败文件'
+            } else {
+                stats = uploader.getStats();
+                text = '共' + fileCount + '个(' + WebUploader.formatSize(fileSize) + '),已上传' + stats.successNum + '个';
+                if (stats.uploadFailNum) text += ',失败' + stats.uploadFailNum + '个';
+            }
+            $info.html(text);
+        }
+
+        function setState(val) {
+            if (val === state) return;
+            $upload.removeClass('state-' + state);
+            $upload.addClass('state-' + val);
+            state = val;
+            switch (state) {
+                case 'pedding':
+                    $placeHolder.removeClass('element-invisible');
+                    $queue.hide(), $statusBar.addClass('element-invisible'), uploader.refresh();
+                    break;
+                case 'ready':
+                    $placeHolder.addClass('element-invisible');
+                    $('#filePicker2').removeClass('element-invisible');
+                    $queue.show(), $statusBar.removeClass('element-invisible'), uploader.refresh();
+                    break;
+                case 'uploading':
+                    $('#filePicker2').addClass('element-invisible');
+                    $progress.show(), $upload.text('暂停上传');
+                    break;
+                case 'paused':
+                    $progress.show(), $upload.text('继续上传');
+                    break;
+                case 'confirm':
+                    $('#filePicker2').removeClass('element-invisible');
+                    $progress.hide(), $upload.text('开始上传');
+                    var stats = uploader.getStats();
+                    if (stats.successNum && !stats.uploadFailNum) return setState('finish')
+                    break;
+                case 'finish':
+                    if (uploader.getStats().successNum) completed.call(this);
+                    else (state = 'done'), location.reload();
+                    break;
+            }
+            updateStatus();
+        }
+
+        uploader.onUploadProgress = function (file, percentage) {
+            var $li = $('#' + file.id), $percent = $li.find('.progress span');
+            $percent.css('width', percentage * 100 + '%');
+            percentages[file.id][1] = percentage;
+            updateTotalProgress();
+        };
+
+        uploader.onFileQueued = function (file) {
+            fileCount++, fileSize += file.size;
+            if (fileCount === 1) $placeHolder.addClass('element-invisible'), $statusBar.show();
+            addFile(file), setState('ready'), updateTotalProgress();
+        };
+
+        uploader.onfieldequeued = function (file) {
+            fileCount--, fileSize -= file.size;
+            if (!fileCount) setState('pedding');
+            removeFile(file), updateTotalProgress();
+        };
+
+        uploader.on('all', function (type) {
+            if (type === 'uploadFinished') return setState('confirm');
+            if (type === 'startUpload') return setState('uploading');
+            if (type === 'stopUpload') return setState('paused');
+        });
+
+        uploader.onError = function () {
+            console.error(JSON.stringify(arguments));
+        };
+
+        $upload.on('click', function () {
+            if ($(this).hasClass('disabled')) return false;
+            if (state === 'ready') uploader.upload();
+            else if (state === 'paused') uploader.upload();
+            else if (state === 'uploading') uploader.stop();
+        });
+
+        $info.on('click', '.retry', function () {
+            uploader.retry();
+        });
+
+        $upload.addClass('state-' + state);
+        updateTotalProgress();
+    });
+
+</script>
+</body>
+</html>

+ 58 - 101
application/admin/view/auth/apply.html

@@ -1,9 +1,7 @@
-{extend name='admin@public/content'}
+{extend name='main'}
 
 {block name="content"}
-<ul id="zTree" class="ztree loading">
-    <li></li>
-</ul>
+<ul id="zTree" class="ztree notselect"></ul>
 <div class="hr-line-dashed"></div>
 <div class="layui-form-item text-center">
     <button class="layui-btn" data-submit-role type='button'>保存数据</button>
@@ -12,112 +10,71 @@
 {/block}
 
 {block name="script"}
-<link href="__STATIC__/plugs/ztree/zTreeStyle/zTreeStyle.css" rel="stylesheet" type="text/css">
-<script src="__STATIC__/plugs/ztree/jquery.ztree.all.min.js" type="text/javascript">;</script>
 <script>
-    $(function () {
-        window.roleForm = new function () {
-            this.data = {};
-            this.ztree = null;
-            this.setting = {
-                view: {showLine: false, showIcon: false, dblClickExpand: false},
-                check: {enable: true, nocheck: false, chkboxType: {"Y": "ps", "N": "ps"}},
-                callback: {
-                    beforeClick: function (treeId, treeNode) {
-                        if (treeNode.children.length < 1) {
-                            window.roleForm.ztree.checkNode(treeNode, !treeNode.checked, null, true);
-                        } else {
-                            window.roleForm.ztree.expandNode(treeNode);
-                        }
-                        return false;
-                    }
+    window.RoleAction = new function () {
+        this.data = {};
+        this.ztree = null;
+        this.setting = {
+            view: {showLine: false, showIcon: false, dblClickExpand: false},
+            check: {enable: true, nocheck: false, chkboxType: {"Y": "ps", "N": "ps"}},
+            callback: {
+                beforeClick: function (id, node) {
+                    node.children.length < 1 ? RoleAction.ztree.checkNode(node, !node.checked, null, true) : RoleAction.ztree.expandNode(node);
+                    return false;
                 }
-            };
-            this.getData = function (self) {
-                var index = $.msg.loading();
-                jQuery.get('{:url()}?id={$vo.id}', {action: 'getNode'}, function (ret) {
-                    $.msg.close(index);
-                    self.data = renderChildren(ret.data, 1);
-                    self.showTree();
-
-                    function renderChildren(data, level) {
-                        var childrenData = [];
-                        for (var i in data) {
-                            var children = {};
-                            children.open = true;
-                            children.node = data[i].node;
-                            children.name = data[i].title || data[i].node;
-                            children.checked = data[i].checked || false;
-                            children.children = renderChildren(data[i]._sub_, level + 1);
-                            childrenData.push(children);
-                        }
-                        return childrenData;
-                    }
-                }, 'JSON');
-            };
-            this.showTree = function () {
-                this.ztree = jQuery.fn.zTree.init(jQuery("#zTree"), this.setting, this.data);
-                while (true) {
-                    var reNodes = this.ztree.getNodesByFilter(function (node) {
-                        return (!node.node && node.children.length < 1);
-                    });
-                    if (reNodes.length < 1) {
-                        break;
-                    }
-                    for (var i in reNodes) {
-                        this.ztree.removeNode(reNodes[i]);
-                    }
-                }
-            };
-            this.submit = function () {
-                var nodes = [];
-                var data = this.ztree.getCheckedNodes(true);
-                for (var i in data) {
-                    (data[i].node) && nodes.push(data[i].node);
-                }
-                $.form.load('{:url()}?id={$vo.id}&action=save', {nodes: nodes}, 'post');
-            };
-            this.getData(this);
+            }
         };
-
+        this.renderChildren = function (list, level) {
+            var childrens = [];
+            for (var i in list) childrens.push({
+                open: true, node: list[i].node, name: list[i].title || list[i].node,
+                checked: list[i].checked || false, children: this.renderChildren(list[i]._sub_, level + 1)
+            });
+            return childrens;
+        };
+        this.getData = function (that) {
+            var index = $.msg.loading();
+            $.form.load('{:url()}', {id: '{$vo.id}', action: 'get'}, 'post', function (ret) {
+                that.data = that.renderChildren(ret.data, 1);
+                return $.msg.close(index), that.showTree(), false;
+            });
+        };
+        this.showTree = function () {
+            this.ztree = $.fn.zTree.init($("#zTree"), this.setting, this.data);
+            while (true) {
+                var nodes = this.ztree.getNodesByFilter(function (node) {
+                    return (!node.node && node.children.length < 1);
+                });
+                if (nodes.length < 1) break;
+                for (var i in nodes) this.ztree.removeNode(nodes[i]);
+            }
+        };
+        this.submit = function () {
+            var nodes = [], data = this.ztree.getCheckedNodes(true);
+            for (var i in data) if (data[i].node) nodes.push(data[i].node);
+            $.form.load('{:url()}', {id: '{$vo.id}', action: 'save', nodes: nodes}, 'post');
+        };
+        // 刷新数据
+        this.getData(this);
+        // 提交表单
         $('[data-submit-role]').on('click', function () {
-            window.roleForm.submit();
+            RoleAction.submit();
         });
-    });
+    };
 </script>
 {/block}
 
 {block name="style"}
+<link href="__ROOT__/static/plugs/ztree/zTreeStyle/zTreeStyle.css" rel="stylesheet">
+<script src="__ROOT__/static/plugs/ztree/ztree.all.min.js"></script>
 <style>
-    ul.ztree li {
-        white-space: normal !important
-    }
-
-    ul.ztree li span.button.switch {
-        margin-right: 5px
-    }
-
-    ul.ztree ul ul li {
-        display: inline-block;
-        white-space: normal
-    }
-
-    ul.ztree > li {
-        padding: 15px 25px 15px 15px;
-    }
-
-    ul.ztree > li > ul {
-        margin-top: 12px;
-        border-top: 1px solid rgba(0, 0, 0, .1);
-    }
-
-    ul.ztree > li > ul > li {
-        padding: 5px
-    }
-
-    ul.ztree > li > a > span {
-        font-size: 15px;
-        font-weight: 700
-    }
+    ul.ztree li{white-space:normal!important;}
+    ul.ztree li span.button.switch{margin-right:5px;}
+    ul.ztree ul ul li{display:inline-block;white-space:normal;}
+    ul.ztree>li{padding:15px 25px 15px 15px;}
+    ul.ztree>li>ul{margin-top:12px;border-top:1px solid rgba(0,0,0,.1);}
+    ul.ztree>li>ul>li{padding:5px;}
+    ul.ztree>li>a>span{font-weight:700;font-size:15px;}
+    ul.ztree .level2 .button.level2{background:0 0;}
 </style>
 {/block}

+ 16 - 17
application/admin/view/auth/form.html

@@ -1,25 +1,24 @@
-<form autocomplete="off" class="layui-form layui-box modal-form-box" action="{:request()->url()}" data-auto="true" method="post">
-
-    <div class="layui-form-item">
-        <label class="layui-form-label">权限名称</label>
-        <div class="layui-input-block">
-            <input type="text" name="title" value='{$vo.title|default=""}' required="required" title="请输入权限名称" placeholder="请输入权限名称" class="layui-input">
+<form class="layui-form layui-card" action="{:request()->url()}" data-auto="true" method="post" autocomplete="off">
+    <div class="layui-card-body">
+        <div class="layui-form-item">
+            <label class="layui-form-label">权限名称</label>
+            <div class="layui-input-block">
+                <input type="text" name="title" value='{$vo.title|default=""}' required placeholder="请输入权限名称" class="layui-input">
+            </div>
         </div>
-    </div>
-
-    <div class="layui-form-item">
-        <label class="layui-form-label">权限描述</label>
-        <div class="layui-input-block">
-            <textarea placeholder="请输入权限描述" required="required" title="请输入权限描述" class="layui-textarea" name="desc">{$vo.desc|default=""}</textarea>
+        <div class="layui-form-item">
+            <label class="layui-form-label">权限描述</label>
+            <div class="layui-input-block">
+                <textarea placeholder="请输入权限描述" required class="layui-textarea" name="desc">{$vo.desc|default=""}</textarea>
+            </div>
         </div>
     </div>
-
     <div class="hr-line-dashed"></div>
-
     <div class="layui-form-item text-center">
-        {if isset($vo['id'])}<input type='hidden' value='{$vo.id}' name='id'>{/if}
+        <!--{notempty name='vo.id'}-->
+        <input type='hidden' value='{$vo.id}' name='id'>
+        <!--{/notempty}-->
         <button class="layui-btn" type='submit'>保存数据</button>
         <button class="layui-btn layui-btn-danger" type='button' data-confirm="确定要取消编辑吗?" data-close>取消编辑</button>
     </div>
-
-</form>
+</form>

+ 54 - 69
application/admin/view/auth/index.html

@@ -1,83 +1,68 @@
-{extend name='admin@public/content'}
+{extend name='main'}
 
 {block name="button"}
-<!--{if auth("$classuri/add")}-->
-<button data-modal='{:url("$classuri/add")}' data-title="添加权限" class='layui-btn layui-btn-sm layui-btn-primary'>添加权限</button>
+<!--{if auth("admin/auth/add")}-->
+<button data-modal='{:url("add")}' data-title="添加权限" class='layui-btn layui-btn-sm layui-btn-primary'>添加权限</button>
 <!--{/if}-->
 
-<!--{if auth("$classuri/del")}-->
-<button data-update data-field='delete' data-action='{:url("$classuri/del")}' class='layui-btn layui-btn-sm layui-btn-primary'>删除权限</button>
+<!--{if auth("admin/auth/del")}-->
+<button data-action='{:url("del")}' data-rule="id#{key}" data-csrf="{:systoken('admin/auth/del')}" data-confirm="确定要删除这些权限吗?" class='layui-btn layui-btn-sm layui-btn-primary'>删除权限</button>
 <!--{/if}-->
 {/block}
 
 {block name="content"}
-<form autocomplete="off" onsubmit="return false;" data-auto="true" method="post">
-    <!--{if empty($list)}-->
-    <p class="help-block text-center well">没 有 记 录 哦!</p>
-    <!--{else}-->
-    <input type="hidden" value="resort" name="action">
-    <table class="layui-table" lay-skin="line">
-        <thead>
-        <tr>
-            <th class='list-table-check-td think-checkbox'>
-                <input data-auto-none="" data-check-target='.list-check-box' type='checkbox'>
-            </th>
-            <th class='list-table-sort-td'>
-                <button type="submit" class="layui-btn layui-btn-normal layui-btn-xs">排 序</button>
-            </th>
-            <th class='text-left'>名称</th>
-            <th class='text-left'>描述</th>
-            <th class='text-center'>状态</th>
-            <th class='text-left'>添加时间</th>
-            <th class='text-center'></th>
-        </tr>
-        </thead>
-        <tbody>
-        <!--{foreach $list as $key=>$vo}-->
-        <tr>
-            <td class='list-table-check-td think-checkbox'>
-                <input class="list-check-box" value='{$vo.id}' type='checkbox'>
-            </td>
-            <td class='list-table-sort-td'>
-                <input name="_{$vo.id}" value="{$vo.sort}" class="list-sort-input">
-            </td>
-            <td class='text-left'>{$vo.title}</td>
-            <td class='text-left'>{$vo.desc|default="<span class='color-desc'>没有写描述哦!</span>"}</td>
-            <td class='text-center'>
-                {if $vo.status eq 0}<span>已禁用</span>{elseif $vo.status eq 1}<span class="color-green">使用中</span>{/if}
-            </td>
-            <td class="text-left nowrap">{$vo.create_at|format_datetime}</td>
-            <td class='text-center nowrap'>
 
-                {if auth("$classuri/edit")}
-                <span class="text-explode">|</span>
-                <a data-title="编辑权限" data-modal='{:url("$classuri/edit")}?id={$vo.id}'>编辑</a>
-                {/if}
+<table class="layui-table" lay-skin="line">
+    <caption class="margin-bottom-10 text-left">{include file='auth/index_search'}</caption>
+    <!--{notempty name='list'}-->
+    <thead>
+    <tr>
+        <th class='list-table-check-td think-checkbox'>
+            <input data-auto-none data-check-target='.list-check-box' type='checkbox'>
+        </th>
+        <th class='text-left nowrap'>名称</th>
+        <th class='text-left nowrap'>描述</th>
+        <th class='text-center nowrap'>创建时间</th>
+        <th class="text-center">状态</th>
+        <th></th>
+    </tr>
+    </thead>
+    <!--{/notempty}-->
+    <tbody>
+    <!--{foreach $list as $key=>$vo}-->
+    <tr data-dbclick>
+        <td class='list-table-check-td think-checkbox'><input class="list-check-box" value='{$vo.id}' type='checkbox'></td>
+        <td class='text-left'>{$vo.title}</td>
+        <td class='text-left'>{$vo.desc|default="<span class='color-desc'>没有写描述哦!</span>"}</td>
+        <td class="text-center nowrap">{$vo.create_at|format_datetime}</td>
+        <td class='text-center nowrap'>{eq name='vo.status' value='0'}<span class="layui-badge">已禁用</span>{else}<span class="layui-badge layui-bg-green">使用中</span>{/eq}</td>
+        <td class='text-center nowrap'>
 
-                {if auth("$classuri/apply")}
-                <span class="text-explode">|</span>
-                <a data-open='{:url("$classuri/apply")}?id={$vo.id}'>授权</a>
-                {/if}
+            {if auth("admin/auth/edit")}
+            <span class="text-explode">|</span>
+            <a data-dbclick class="layui-btn layui-btn-xs" data-title="编辑权限" data-modal='{:url("admin/auth/edit")}?id={$vo.id}'>编 辑</a>
+            {/if}
 
-                {if $vo.status eq 1 and auth("$classuri/forbid")}
-                <span class="text-explode">|</span>
-                <a data-update="{$vo.id}" data-field='status' data-value='0' data-action='{:url("$classuri/forbid")}'>禁用</a>
-                {elseif auth("$classuri/resume")}
-                <span class="text-explode">|</span>
-                <a data-update="{$vo.id}" data-field='status' data-value='1' data-action='{:url("$classuri/resume")}'>启用</a>
-                {/if}
+            {if auth("admin/auth/apply")}
+            <a class="layui-btn layui-btn-normal layui-btn-xs" data-open='{:url("admin/auth/apply")}?id={$vo.id}'>授 权</a>
+            {/if}
 
-                {if auth("$classuri/del")}
-                <span class="text-explode">|</span>
-                <a data-update="{$vo.id}" data-field='delete' data-action='{:url("$classuri/del")}'>删除</a>
-                {/if}
+            {if $vo.status eq 1 and auth("admin/auth/forbid")}
+            <a class="layui-btn layui-btn-warm layui-btn-xs" data-action="{:url('forbid')}" data-value="id#{$vo.id};status#0" data-csrf="{:systoken('admin/auth/forbid')}">禁 用</a>
+            {elseif auth("admin/auth/resume")}
+            <a class="layui-btn layui-btn-warm layui-btn-xs" data-action="{:url('resume')}" data-value="id#{$vo.id};status#1" data-csrf="{:systoken('admin/auth/resume')}">启 用</a>
+            {/if}
+
+            {if auth("admin/auth/del")}
+            <a class="layui-btn layui-btn-danger layui-btn-xs" data-confirm="确定要删除数据吗?" data-action="{:url('del')}" data-value="id#{$vo.id}" data-csrf="{:systoken('admin/auth/del')}">删 除</a>
+            {/if}
+
+        </td>
+    </tr>
+    <!--{/foreach}-->
+    </tbody>
+</table>
+
+{empty name='list'}<span class="notdata">没有记录哦</span>{else}{$pagehtml|raw|default=''}{/empty}
 
-            </td>
-        </tr>
-        <!--{/foreach}-->
-        </tbody>
-    </table>
-    {if isset($page)}<p>{$page|raw}</p>{/if}
-    <!--{/if}-->
-</form>
 {/block}

+ 42 - 0
application/admin/view/auth/index_search.html

@@ -0,0 +1,42 @@
+<fieldset>
+    <legend class="layui-bg-cyan">条件搜索</legend>
+    <form class="layui-form layui-form-pane form-search" action="{:request()->url()}" onsubmit="return false" method="get" autocomplete="off">
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">权限名称</label>
+            <div class="layui-input-inline">
+                <input name="title" value="{$Think.get.title|default=''}" placeholder="请输入权限名称" class="layui-input">
+            </div>
+        </div>
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">权限描述</label>
+            <div class="layui-input-inline">
+                <input name="desc" value="{$Think.get.desc|default=''}" placeholder="请输入权限描述" class="layui-input">
+            </div>
+        </div>
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">使用状态</label>
+            <div class="layui-input-inline">
+                <select class="layui-select" name="status">
+                    {foreach [''=>'-- 全部 --','0'=>'已禁用的权限','1'=>'使用中的权限'] as $k=>$v}
+                    {eq name='Think.get.status' value='$k.""'}
+                    <option selected value="{$k}">{$v}</option>
+                    {else}
+                    <option value="{$k}">{$v}</option>
+                    {/eq}
+                    {/foreach}
+                </select>
+            </div>
+        </div>
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">创建时间</label>
+            <div class="layui-input-inline">
+                <input data-date-range name="create_at" value="{$Think.get.create_at|default=''}" placeholder="请选择创建时间" class="layui-input">
+            </div>
+        </div>
+        <div class="layui-form-item layui-inline">
+            <button class="layui-btn layui-btn-primary"><i class="layui-icon">&#xe615;</i> 搜 索</button>
+        </div>
+    </form>
+</fieldset>
+
+<script>form.render()</script>

+ 24 - 210
application/admin/view/config/file.html

@@ -1,228 +1,42 @@
-{extend name="admin@public/content"}
+{extend name="main"}
 
 {block name="content"}
-<form autocomplete="off" onsubmit="return false;" action="{:request()->url()}" data-auto="true" method="post" class='form-horizontal layui-form padding-top-20'>
 
-    <div class="form-group">
-        <label class="col-sm-2 control-label label-required">
-            Storage<br><span class="nowrap color-desc">存储引擎</span>
-        </label>
-        <div class='col-sm-8'>
-            {foreach ['local'=>'本地服务器存储','qiniu'=>'七牛云存储','oss'=>'阿里云OSS存储'] as $k=>$v}
-            <label class="think-radio">
-                <!--{if sysconf('storage_type') eq $k}-->
-                <input checked type="radio" name="storage_type" value="{$k}" title="{$v}" lay-ignore>
-                <!--{else}-->
-                <input type="radio" name="storage_type" value="{$k}" title="{$v}" lay-ignore>
-                <!--{/if}-->
-                {$v}
-            </label>
-            {/foreach}
-            <div class="help-block" data-storage-type="local">
-                文件存储在本地服务器,请确保服务器的 ./static/upload/ 目录有写入权限
-            </div>
-            <div class="help-block" data-storage-type="qiniu">
-                若还没有七牛云帐号,可<a target="_blank" href="https://portal.qiniu.com/signup?code=3lhz6nmnwbple">免费申请10G存储</a>,申请成功后添加公开bucket。
-            </div>
-            <div class="help-block" data-storage-type="oss">
-                若还没有OSS存储账号, 可<a target="_blank" href="https://oss.console.aliyun.com">创建阿里云OSS存储</a>,需要配置OSS公开访问及跨域策略。
+<form class="layui-card layui-form">
+    <div class="layui-card-body">
+        <div class="layui-form-item">
+            <label class="layui-form-label">Storage<br><span class="nowrap color-desc">存储类型</span></label>
+            <div class="layui-input-block">
+                {foreach ['local'=>'本地服务器存储','oss'=>'阿里云OSS存储','qiniu'=>'七牛云存储'] as $k=>$v}
+                <input type="radio" data-storagetype="{$k}" name="storage_type" value="{$k}" title="{$v}" lay-filter="storage_type">
+                {/foreach}
+                <p class="help-block">请选择文件存储类型,其它云储存需要配置正确的参数才可以上传文件哦!</p>
             </div>
         </div>
     </div>
+</form>
 
-    <div class="hr-line-dashed"></div>
-
-    <div class="form-group" data-storage-type="local">
-        <label class="col-sm-2 control-label">
-            AllowExts<br><span class="nowrap color-desc">允许类型</span>
-        </label>
-        <div class='col-sm-8'>
-            <input type="text" name="storage_local_exts" required="required" value="{:sysconf('storage_local_exts')}"
-                   title="请输入系统文件上传后缀" placeholder="请输入系统文件上传后缀" class="layui-input">
-            <p class="help-block">设置系统允许上传文件的后缀,多个以英文逗号隔开。如:png,jpg,rar,doc</p>
-        </div>
-    </div>
-
-    <div class="form-group" data-storage-type="qiniu">
-        <label class="col-sm-2 control-label label-required">
-            Region<br><span class="nowrap color-desc">存储区域</span>
-        </label>
-        <div class='col-sm-8'>
-            {foreach ['华东','华北','华南','北美'] as $area}
-            <label class="think-radio">
-                <!--{if sysconf('storage_qiniu_region') eq $area}-->
-                <input checked type="radio" name="storage_qiniu_region" value="{$area}" lay-ignore>
-                <!--{else}-->
-                <input type="radio" name="storage_qiniu_region" value="{$area}" lay-ignore>
-                <!--{/if}-->
-                {$area}
-            </label>
-            {/foreach}
-            <p class="help-block">七牛云存储空间所在区域,需要严格对应储存所在区域才能上传文件。</p>
-        </div>
-    </div>
-
-    <div class="form-group" data-storage-type="qiniu">
-        <label class="col-sm-2 control-label label-required">
-            Protocol<br><span class="nowrap color-desc">访问协议</span>
-        </label>
-        <div class='col-sm-8'>
-            <!--{foreach ['http','https','auto'] as $pro}-->
-            <label class="think-radio">
-                <!--{if sysconf('storage_qiniu_is_https') eq $pro}-->
-                <input checked type="radio" name="storage_qiniu_is_https" value="{$pro}" lay-ignore> {$pro}
-                <!--{else}-->
-                <input type="radio" name="storage_qiniu_is_https" value="{$pro}" lay-ignore> {$pro}
-                <!--{/if}-->
-            </label>
-            <!--{/foreach}-->
-            <p class="help-block">七牛云存储访问协议(http、https、auto),其中 https 需要配置证书才能使用,auto 为相对协议自动根据域名切换http与https。</p>
-        </div>
-    </div>
-
-    <div class="form-group" data-storage-type="qiniu">
-        <label class="col-sm-2 control-label">
-            Bucket<br><span class="nowrap color-desc">空间名称</span>
-        </label>
-        <div class='col-sm-8'>
-            <input type="text" name="storage_qiniu_bucket" required="required" value="{:sysconf('storage_qiniu_bucket')}"
-                   title="请输入七牛云存储 Bucket (空间名称)" placeholder="请输入七牛云存储 Bucket (空间名称)" class="layui-input">
-            <p class="help-block">填写七牛云存储空间名称,如:static</p>
-        </div>
-    </div>
-
-    <div class="form-group" data-storage-type="qiniu">
-        <label class="col-sm-2 control-label">
-            Domain<br><span class="nowrap color-desc">访问域名</span>
-        </label>
-        <div class='col-sm-8'>
-            <input type="text" name="storage_qiniu_domain" required="required" value="{:sysconf('storage_qiniu_domain')}"
-                   title="请输入七牛云存储 Domain (访问域名)" placeholder="请输入七牛云存储 Domain (访问域名)" class="layui-input">
-            <p class="help-block">填写七牛云存储访问域名,如:static.ctolog.cc</p>
-        </div>
-    </div>
-
-    <div class="form-group" data-storage-type="qiniu">
-        <label class="col-sm-2 control-label">
-            AccessKey<br><span class="nowrap color-desc">访问密钥</span>
-        </label>
-        <div class='col-sm-8'>
-            <input type="text" name="storage_qiniu_access_key" required="required" value="{:sysconf('storage_qiniu_access_key')}"
-                   title="请输入七牛云 AccessKey (访问密钥)" placeholder="请输入七牛云 AccessKey (访问密钥)" class="layui-input">
-            <p class="help-block">可以在 [ 七牛云 > 个人中心 ] 设置并获取到访问密钥。</p>
-        </div>
-    </div>
-
-    <div class="form-group" data-storage-type="qiniu">
-        <label class="col-sm-2 control-label">
-            SecretKey<br><span class="nowrap color-desc">安全密钥</span>
-        </label>
-        <div class='col-sm-8'>
-            <input type="text" name="storage_qiniu_secret_key" required="required" value="{:sysconf('storage_qiniu_secret_key')}" maxlength="43"
-                   title="请输入七牛云 SecretKey (安全密钥)" placeholder="请输入七牛云 SecretKey (安全密钥)" class="layui-input">
-            <p class="help-block">可以在 [ 七牛云 > 个人中心 ] 设置并获取到安全密钥。</p>
-        </div>
-    </div>
-
-    <div class="form-group" data-storage-type="oss">
-        <label class="col-sm-2 control-label label-required">
-            Protocol<br><span class="nowrap color-desc">访问协议</span>
-        </label>
-        <div class='col-sm-8'>
-            <!--{foreach ['http','https','auto'] as $pro}-->
-            <label class="think-radio">
-                <!--{if sysconf('storage_oss_is_https') eq $pro}-->
-                <input checked type="radio" name="storage_oss_is_https" value="{$pro}" lay-ignore> {$pro}
-                <!--{else}-->
-                <input type="radio" name="storage_oss_is_https" value="{$pro}" lay-ignore> {$pro}
-                <!--{/if}-->
-            </label>
-            <!--{/foreach}-->
-            <p class="help-block">阿里云对象存储访问协议(http、https、auto),其中 https 需要配置证书才能使用,auto 为相对协议自动根据域名切换http与https。</p>
-        </div>
-    </div>
-
-    <div class="form-group" data-storage-type="oss">
-        <label class="col-sm-2 control-label">
-            Bucket<br><span class="nowrap color-desc">空间名称</span>
-        </label>
-        <div class='col-sm-8'>
-            <input type="text" name="storage_oss_bucket" required="required" value="{:sysconf('storage_oss_bucket')}"
-                   title="请输入OSS Bucket (空间名称)" placeholder="请输入OSS Bucket (空间名称)" class="layui-input">
-            <p class="help-block">填写OSS存储空间名称,如:think-admin-oss</p>
-        </div>
-    </div>
-
-    <div class="form-group" data-storage-type="oss">
-        <label class="col-sm-2 control-label">
-            EndPoint<br><span class="nowrap color-desc">数据中心</span>
-        </label>
-        <div class='col-sm-8'>
-            <input type="text" name="storage_oss_endpoint" required="required" value="{:sysconf('storage_oss_endpoint')}"
-                   title="请输入OSS数据中心访问域名 (访问域名)" placeholder="请输入OSS数据中心访问域名 (访问域名)" class="layui-input">
-            <p class="help-block">填写OSS数据中心访问域名,如:oss-cn-shenzhen.aliyuncs.com</p>
-        </div>
-    </div>
-
-    <div class="form-group" data-storage-type="oss">
-        <label class="col-sm-2 control-label">
-            Domain<br><span class="nowrap color-desc">访问域名</span>
-        </label>
-        <div class='col-sm-8'>
-            <input type="text" name="storage_oss_domain" required="required" value="{:sysconf('storage_oss_domain')}"
-                   title="请输入OSS存储 Domain (访问域名)" placeholder="请输入OSS存储 Domain (访问域名)" class="layui-input">
-            <p class="help-block">填写OSS存储外部访问域名,如:think-admin-oss.oss-cn-shenzhen.aliyuncs.com</p>
-        </div>
-    </div>
-
-    <div class="form-group" data-storage-type="oss">
-        <label class="col-sm-2 control-label">
-            AccessKey<br><span class="nowrap color-desc">访问密钥</span>
-        </label>
-        <div class='col-sm-8'>
-            <input type="text" name="storage_oss_keyid" required="required" value="{:sysconf('storage_oss_keyid')}" maxlength="16"
-                   title="请输入16位OSS AccessKey (访问密钥)" placeholder="请输入OSS AccessKey (访问密钥)" class="layui-input">
-            <p class="help-block">可以在 [ 阿里云 > 个人中心 ] 设置并获取到访问密钥。</p>
-        </div>
-    </div>
-
-    <div class="form-group" data-storage-type="oss">
-        <label class="col-sm-2 control-label">
-            SecretKey<br><span class="nowrap color-desc">安全密钥</span>
-        </label>
-        <div class='col-sm-8'>
-            <input type="text" name="storage_oss_secret" required="required" value="{:sysconf('storage_oss_secret')}" maxlength="30"
-                   title="请输入30位OSS SecretKey (安全密钥)" placeholder="请输入OSS SecretKey (安全密钥)" class="layui-input">
-            <p class="help-block">可以在 [ 阿里云 > 个人中心 ] 设置并获取到安全密钥。</p>
-        </div>
-    </div>
-
-
-    <div class="hr-line-dashed"></div>
-
-    <div class="col-sm-4 col-sm-offset-2">
-        <div class="layui-form-item text-center">
-            <button class="layui-btn" type="submit">保存配置</button>
-        </div>
-    </div>
+<div data-type="oss">{include file='config/file_oss'}</div>
+<div data-type="local">{include file='config/file_local'}</div>
+<div data-type="qiniu">{include file='config/file_qiniu'}</div>
 
-</form>
 {/block}
 
 {block name="script"}
 <script>
-    (function () {
+    $(function () {
+        apply('{:sysconf("storage_type")}');
         window.form.render();
-        buildForm('{:sysconf("storage_type")}');
-        $('[name=storage_type]').on('click', function () {
-            buildForm($('[name=storage_type]:checked').val())
+
+        window.form.on('radio(storage_type)', function (data) {
+            apply(data.value);
         });
 
-        // 表单显示编译
-        function buildForm(value) {
-            var $tips = $("[data-storage-type='" + value + "']");
-            $("[data-storage-type]").not($tips.show()).hide();
+        function apply(value) {
+            var $active = $("[data-storagetype='" + value + "']").trigger('click');
+            if ($active.size() < 1) $("[data-storagetype]:first").trigger('click');
+            $('[data-type="' + value + '"]').show().siblings('[data-type]').hide();
         }
-    })();
+    });
 </script>
 {/block}

+ 25 - 0
application/admin/view/config/file_local.html

@@ -0,0 +1,25 @@
+<form onsubmit="return false;" data-auto="true" method="post" class='layui-form layui-card padding-0' autocomplete="off">
+    <div class="layui-card-body padding-0">
+        <div class="color-blue padding-left-40 padding-bottom-20">
+            文件将存储在本地服务器,需确保服务器的 public/upload 目录有写入权限,还需要有足够的存储空间。
+        </div>
+        <div class="layui-form-item">
+            <label class="layui-form-label">
+                AllowExts<br><span class="nowrap color-desc">允许上传文件</span>
+            </label>
+            <div class="layui-input-block">
+                <input type="text" name="storage_local_exts" required value="{:sysconf('storage_local_exts')}" placeholder="请输入系统文件上传后缀" class="layui-input">
+                <p class="help-block">设置系统允许上传文件的后缀,多个以英文逗号隔开。如:png,jpg,rar,doc</p>
+            </div>
+        </div>
+        <div class="hr-line-dashed margin-left-40"></div>
+        <div class="layui-form-item text-center">
+            <div class="layui-row">
+                <div class="layui-col-sm8 layui-col-md6">
+                    <input type="hidden" name="storage_type" value="local">
+                    <button class="layui-btn" type="submit">保存配置</button>
+                </div>
+            </div>
+        </div>
+    </div>
+</form>

+ 86 - 0
application/admin/view/config/file_oss.html

@@ -0,0 +1,86 @@
+<form onsubmit="return false;" data-auto="true" method="post" class='layui-form layui-card' autocomplete="off">
+    <div class="layui-card-body padding-0">
+        <div class="color-blue padding-left-40 padding-bottom-20">
+            文件将上传到阿里云OSS空间,需要配置OSS公开访问及跨域策略(目前已实现自动创建空间及配置访问策略)。
+        </div>
+        <div class="layui-form-item">
+            <label class="layui-form-label">
+                Protocol<br><span class="nowrap color-desc">访问协议</span>
+            </label>
+            <div class="layui-input-block">
+                <!--{foreach ['http','https','auto'] as $pro}-->
+                <label class="think-radio">
+                    <!--{if sysconf('storage_oss_is_https') eq $pro}-->
+                    <input checked type="radio" name="storage_oss_is_https" value="{$pro}" lay-ignore> {$pro}
+                    <!--{else}-->
+                    <input type="radio" name="storage_oss_is_https" value="{$pro}" lay-ignore> {$pro}
+                    <!--{/if}-->
+                </label>
+                <!--{/foreach}-->
+                <p class="help-block">阿里云对象存储访问协议(http、https、auto),其中 https 需要配置证书才能使用,auto 为相对协议自动根据域名切换http与https。</p>
+            </div>
+        </div>
+        <div class="layui-form-item">
+            <label class="layui-form-label">
+                Bucket<br><span class="nowrap color-desc">空间名称</span>
+            </label>
+            <div class="layui-input-block">
+                <input type="text" name="storage_oss_bucket" required value="{:sysconf('storage_oss_bucket')}" placeholder="请输入OSS Bucket (空间名称)" class="layui-input">
+                <p class="help-block">填写OSS存储空间名称,如:think-admin-oss(需要是全区唯一的值,不存在时会自动创建)</p>
+            </div>
+        </div>
+        <div class="layui-form-item">
+            <label class="layui-form-label">
+                EndPoint<br><span class="nowrap color-desc">数据中心</span>
+            </label>
+            <div class="layui-input-block">
+                <select required name="storage_oss_endpoint" class="layui-select">
+                    {foreach $point as $k=>$p}
+                    <!--{if sysconf('storage_oss_endpoint') eq $k}-->
+                    <option selected value="{$k}">{$p} <span class="font-s10 color-desc">({$k})</span></option>
+                    <!--{else}-->
+                    <option value="{$k}">{$p} <span class="font-s10 color-desc">({$k})</span></option>
+                    <!--{/if}-->
+                    {/foreach}
+                </select>
+                <p class="help-block">请选择OSS数据中心访问节点,有效值如:oss-cn-shenzhen.aliyuncs.com</p>
+            </div>
+        </div>
+        <div class="layui-form-item">
+            <label class="layui-form-label">
+                AccessKey<br><span class="nowrap color-desc">访问密钥</span>
+            </label>
+            <div class="layui-input-block">
+                <input type="text" name="storage_oss_keyid" required value="{:sysconf('storage_oss_keyid')}" maxlength="16" placeholder="请输入OSS AccessKey (访问密钥)" class="layui-input">
+                <p class="help-block">可以在 [ 阿里云 > 个人中心 ] 设置并获取到访问密钥。</p>
+            </div>
+        </div>
+        <div class="layui-form-item">
+            <label class="layui-form-label">
+                SecretKey<br><span class="nowrap color-desc">安全密钥</span>
+            </label>
+            <div class="layui-input-block">
+                <input type="text" name="storage_oss_secret" required value="{:sysconf('storage_oss_secret')}" maxlength="30" placeholder="请输入OSS SecretKey (安全密钥)" class="layui-input">
+                <p class="help-block">可以在 [ 阿里云 > 个人中心 ] 设置并获取到安全密钥。</p>
+            </div>
+        </div>
+        <div class="layui-form-item">
+            <label class="layui-form-label">
+                Domain<br><span class="nowrap color-desc">访问域名</span>
+            </label>
+            <div class="layui-input-block">
+                <input type="text" name="storage_oss_domain" value="{:sysconf('storage_oss_domain')}" placeholder="请输入OSS存储 Domain (访问域名)" class="layui-input">
+                <p class="help-block">填写OSS存储外部访问域名,如:think-admin-oss.oss-cn-shenzhen.aliyuncs.com(正常情况下是自动获取的)</p>
+            </div>
+        </div>
+        <div class="hr-line-dashed margin-left-40"></div>
+        <div class="layui-form-item text-center">
+            <div class="layui-row">
+                <div class="layui-col-sm8 layui-col-md6">
+                    <input type="hidden" name="storage_type" value="oss">
+                    <button class="layui-btn" type="submit">保存配置</button>
+                </div>
+            </div>
+        </div>
+    </div>
+</form>

+ 87 - 0
application/admin/view/config/file_qiniu.html

@@ -0,0 +1,87 @@
+<form onsubmit="return false;" data-auto="true" method="post" class='layui-form layui-card' autocomplete="off">
+    <div class="layui-card-body padding-0">
+        <div class="color-blue padding-left-40 padding-bottom-20">
+            文件将上传到七牛云空间(<a target="_blank" href="https://portal.qiniu.com/signup?code=3lhz6nmnwbple">点击这里免费申请10G存储</a>),申请成功后添加公开bucket并配置接口密钥。
+        </div>
+        <div class="layui-form-item" data-storage-type="qiniu">
+            <label class="layui-form-label">
+                Protocol<br><span class="nowrap color-desc">访问协议</span>
+            </label>
+            <div class="layui-input-block">
+                <!--{foreach ['http','https','auto'] as $pro}-->
+                <label class="think-radio">
+                    <!--{if sysconf('storage_qiniu_is_https') eq $pro}-->
+                    <input checked type="radio" name="storage_qiniu_is_https" value="{$pro}" lay-ignore> {$pro}
+                    <!--{else}-->
+                    <input type="radio" name="storage_qiniu_is_https" value="{$pro}" lay-ignore> {$pro}
+                    <!--{/if}-->
+                </label>
+                <!--{/foreach}-->
+                <p class="help-block">七牛云存储访问协议(http、https、auto),其中 https 需要配置证书才能使用,auto 为相对协议自动根据域名切换http与https。</p>
+            </div>
+        </div>
+        <div class="layui-form-item" data-storage-type="qiniu">
+            <label class="layui-form-label">
+                Region<br><span class="nowrap color-desc">存储区域</span>
+            </label>
+            <div class="layui-input-block">
+                {foreach ['华东','华北','华南','北美'] as $area}
+                <label class="think-radio">
+                    <!--{if sysconf('storage_qiniu_region') eq $area}-->
+                    <input checked type="radio" name="storage_qiniu_region" value="{$area}" lay-ignore>
+                    <!--{else}-->
+                    <input type="radio" name="storage_qiniu_region" value="{$area}" lay-ignore>
+                    <!--{/if}-->
+                    {$area}
+                </label>
+                {/foreach}
+                <p class="help-block">七牛云存储空间所在区域,需要严格对应储存所在区域才能上传文件。</p>
+            </div>
+        </div>
+        <div class="layui-form-item" data-storage-type="qiniu">
+            <label class="layui-form-label">
+                Bucket<br><span class="nowrap color-desc">空间名称</span>
+            </label>
+            <div class="layui-input-block">
+                <input type="text" name="storage_qiniu_bucket" required value="{:sysconf('storage_qiniu_bucket')}" placeholder="请输入七牛云存储 Bucket (空间名称)" class="layui-input">
+                <p class="help-block">填写七牛云存储空间名称,如:static</p>
+            </div>
+        </div>
+        <div class="layui-form-item" data-storage-type="qiniu">
+            <label class="layui-form-label">
+                Domain<br><span class="nowrap color-desc">访问域名</span>
+            </label>
+            <div class="layui-input-block">
+                <input type="text" name="storage_qiniu_domain" required value="{:sysconf('storage_qiniu_domain')}" placeholder="请输入七牛云存储 Domain (访问域名)" class="layui-input">
+                <p class="help-block">填写七牛云存储访问域名,如:static.ctolog.cc</p>
+            </div>
+        </div>
+        <div class="layui-form-item" data-storage-type="qiniu">
+            <label class="layui-form-label">
+                AccessKey<br><span class="nowrap color-desc">访问密钥</span>
+            </label>
+            <div class="layui-input-block">
+                <input type="text" name="storage_qiniu_access_key" required value="{:sysconf('storage_qiniu_access_key')}" placeholder="请输入七牛云 AccessKey (访问密钥)" class="layui-input">
+                <p class="help-block">可以在 [ 七牛云 > 个人中心 ] 设置并获取到访问密钥。</p>
+            </div>
+        </div>
+        <div class="layui-form-item" data-storage-type="qiniu">
+            <label class="layui-form-label">
+                SecretKey<br><span class="nowrap color-desc">安全密钥</span>
+            </label>
+            <div class="layui-input-block">
+                <input type="text" name="storage_qiniu_secret_key" required value="{:sysconf('storage_qiniu_secret_key')}" maxlength="43" placeholder="请输入七牛云 SecretKey (安全密钥)" class="layui-input">
+                <p class="help-block">可以在 [ 七牛云 > 个人中心 ] 设置并获取到安全密钥。</p>
+            </div>
+        </div>
+        <div class="hr-line-dashed margin-left-40"></div>
+        <div class="layui-form-item text-center">
+            <div class="layui-row">
+                <div class="layui-col-sm8 layui-col-md6">
+                    <input type="hidden" name="storage_type" value="qiniu">
+                    <button class="layui-btn" type="submit">保存配置</button>
+                </div>
+            </div>
+        </div>
+    </div>
+</form>

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

@@ -1,82 +0,0 @@
-{extend name="admin@public/content"}
-
-{block name="content"}
-<form autocomplete="off" onsubmit="return false;" action="{:request()->url()}" data-auto="true" method="post" class='form-horizontal layui-form padding-top-20'>
-
-    <div class="form-group">
-        <label class="col-sm-2 control-label">
-            AppName<br><span class="nowrap color-desc">程序名称</span>
-        </label>
-        <div class='col-sm-8'>
-            <input name="app_name" required="required" title="请输入程序名称" placeholder="请输入程序名称" value="{:sysconf('app_name')}" class="layui-input">
-            <p class="help-block">当前程序名称,在后台主标题上显示</p>
-        </div>
-    </div>
-
-    <div class="form-group">
-        <label class="col-sm-2 control-label">
-            AppVersion<br><span class="nowrap color-desc">程序版本</span>
-        </label>
-        <div class='col-sm-8'>
-            <input name="app_version" required="required" title="请输入程序版本" placeholder="请输入程序版本" value="{:sysconf('app_version')}" class="layui-input">
-            <p class="help-block">当前程序版本号,在后台主标题上标显示</p>
-        </div>
-    </div>
-
-    <div class="hr-line-dashed"></div>
-
-    <div class="form-group">
-        <label class="col-sm-2 control-label">
-            SiteName<br><span class="nowrap color-desc">网站名称</span>
-        </label>
-        <div class='col-sm-8'>
-            <input name="site_name" required="required" title="请输入网站名称" placeholder="请输入网站名称" value="{:sysconf('site_name')}" class="layui-input">
-            <p class="help-block">网站名称,显示在浏览器标签上</p>
-        </div>
-    </div>
-
-    <div class="form-group">
-        <label class="col-sm-2 control-label">
-            Copyright<br><span class="nowrap color-desc">版权信息</span>
-        </label>
-        <div class='col-sm-8'>
-            <input name="site_copy" required="required" title="请输入版权信息" placeholder="请输入版权信息" value="{:sysconf('site_copy')}" class="layui-input">
-            <p class="help-block">程序的版权信息设置,在后台登录页面显示</p>
-        </div>
-    </div>
-
-    <div class="hr-line-dashed"></div>
-
-    <div class="form-group">
-        <label class="col-sm-2 control-label">
-            Browser<br><span class="nowrap color-desc">浏览器图标</span>
-        </label>
-        <div class='col-sm-8'>
-            <img data-tips-image style="height:auto;max-height:32px;min-width:32px" src="{:sysconf('browser_icon')}"/>
-            <input type="hidden" name="browser_icon" onchange="$(this).prev('img').attr('src', this.value)" value="{:sysconf('browser_icon')}" class="layui-input">
-            <a class="btn btn-link" data-file="one" data-uptype="local" data-type="ico,png" data-field="browser_icon">上传图片</a>
-            <p class="help-block">建议上传ICO图标的尺寸为128x128px,此图标用于网站标题前,<a href="http://www.favicon-icon-generator.com/" target="_blank">ICON在线制作</a></p>
-        </div>
-    </div>
-
-    <div class="form-group">
-        <label class="col-sm-2 control-label">
-            Miitbeian<br><span class="nowrap color-desc">网站备案</span>
-        </label>
-        <div class='col-sm-8'>
-            <input name="miitbeian" title="请输入网站备案号" placeholder="请输入网站备案号" value="{:sysconf('miitbeian')}" class="layui-input">
-            <p class="help-block">网站备案号,可以在<a target="_blank" href="http://www.miitbeian.gov.cn">备案管理中心</a>查询获取</p>
-        </div>
-    </div>
-
-    <div class="hr-line-dashed"></div>
-
-    <div class="col-sm-4 col-sm-offset-2">
-        <div class="layui-form-item text-center">
-            <button class="layui-btn" type="submit">保存配置</button>
-        </div>
-    </div>
-
-</form>
-
-{/block}

+ 61 - 0
application/admin/view/config/info.html

@@ -0,0 +1,61 @@
+{extend name="main"}
+
+{block name="content"}
+
+<form onsubmit="return false;" data-auto="true" method="post" class='layui-form layui-card' autocomplete="off">
+    <div class="layui-card-body">
+        <div class="layui-form-item">
+            <label class="layui-form-label">Name<br><span class="nowrap color-desc">程序名称</span></label>
+            <div class="layui-input-block">
+                <input name="app_name" required placeholder="请输入程序名称" value="{:sysconf('app_name')}" class="layui-input">
+                <p class="help-block">当前程序名称,在后台主标题上显示</p>
+            </div>
+        </div>
+        <div class="layui-form-item">
+            <label class="layui-form-label">Version<br><span class="nowrap color-desc">程序版本</span></label>
+            <div class="layui-input-block">
+                <input name="app_version" placeholder="请输入程序版本" value="{:sysconf('app_version')}" class="layui-input">
+                <p class="help-block">当前程序版本号,在后台主标题上标显示</p>
+            </div>
+        </div>
+        <div class="layui-form-item">
+            <label class="layui-form-label">Website<br><span class="nowrap color-desc">网站名称</span></label>
+            <div class="layui-input-block">
+                <input name="site_name" required placeholder="请输入网站名称" value="{:sysconf('site_name')}" class="layui-input">
+                <p class="help-block">网站名称,显示在浏览器标签上</p>
+            </div>
+        </div>
+        <div class="layui-form-item">
+            <label class="layui-form-label">Copyright<br><span class="nowrap color-desc">版权信息</span></label>
+            <div class="layui-input-block">
+                <input name="site_copy" required placeholder="请输入版权信息" value="{:sysconf('site_copy')}" class="layui-input">
+                <p class="help-block">程序的版权信息设置,在后台登录页面显示</p>
+            </div>
+        </div>
+        <div class="layui-form-item">
+            <label class="layui-form-label">Browser<br><span class="nowrap color-desc">浏览器图标</span></label>
+            <div class="layui-input-block">
+                <img data-tips-image style="height:auto;max-height:32px;min-width:32px" src="{:sysconf('site_icon')}"/>
+                <input type="hidden" name="site_icon" onchange="$(this).prev('img').attr('src', this.value)" value="{:sysconf('site_icon')}" class="layui-input">
+                <a class="margin-left-10" data-file="btn" data-uptype="local" data-type="ico,png" data-field="site_icon">上传图片</a>
+                <p class="help-block">建议上传ICO图标的尺寸为128x128px,此图标用于网站标题前,<a href="http://www.favicon-icon-generator.com/" target="_blank">ICON在线制作</a></p>
+            </div>
+        </div>
+        <div class="layui-form-item">
+            <label class="layui-form-label">Miitbeian<br><span class="nowrap color-desc">网站备案</span></label>
+            <div class="layui-input-block">
+                <input name="miitbeian" placeholder="请输入网站备案号" value="{:sysconf('miitbeian')}" class="layui-input">
+                <p class="help-block">网站备案号,可以在<a target="_blank" href="http://www.miitbeian.gov.cn">备案管理中心</a>查询获取</p>
+            </div>
+        </div>
+        <div class="hr-line-dashed margin-left-40"></div>
+        <div class="layui-form-item text-center">
+            <div class="layui-row">
+                <div class="layui-col-sm8 layui-col-md6">
+                    <button class="layui-btn" type="submit">保存配置</button>
+                </div>
+            </div>
+        </div>
+    </div>
+</form>
+{/block}

+ 8 - 0
application/admin/view/index/command.html

@@ -0,0 +1,8 @@
+<div class="layui-code border-0 margin-0 padding-20" style="max-height:400px;overflow:auto">
+    {foreach $list as $vo}
+    <fieldset class="margin-bottom-10">
+        <legend><span class="layui-bg-gray padding-left-5 padding-right-5">{$vo.title|default='--'}</span></legend>
+        <div class="padding-bottom-10">{$vo.message|raw|default=''}</div>
+    </fieldset>
+    {/foreach}
+</div>

+ 128 - 72
application/admin/view/index/index.html

@@ -1,83 +1,139 @@
-{extend name="admin@public/main"}
+<!DOCTYPE html>
+<html lang="zh">
 
+<head>
+    <title>{block name="title"}{$title|default=''}{if !empty($title)} · {/if}{:sysconf('site_name')}{/block}</title>
+    <meta charset="utf-8">
+    <meta name="renderer" content="webkit">
+    <meta name="format-detection" content="telephone=no">
+    <meta name="apple-mobile-web-app-capable" content="yes">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+    <meta name="apple-mobile-web-app-status-bar-style" content="black">
+    <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=0.4">
+    <link rel="shortcut icon" href="{:sysconf('site_icon')}">
+    <link rel="stylesheet" href="__ROOT__/static/plugs/awesome/fonts.css?{:date('md')}">
+    <link rel="stylesheet" href="__ROOT__/static/plugs/layui/css/layui.css?{:date('md')}">
+    <link rel="stylesheet" href="__ROOT__/static/theme/css/console.css?{:date('md')}">
+    {block name="style"}{/block}
+    <script>window.ROOT_URL = '__ROOT__';</script>
+    <script src="__ROOT__/static/plugs/jquery/pace.min.js"></script>
+
+</head>
+
+<body class="layui-layout-body">
 {block name='body'}
+<div class="layui-layout layui-layout-admin layui-layout-left-hide">
 
-<!-- 顶部菜单区域 开始 -->
-<div class="framework-topbar">
-    <div class="topbar-head pull-left">
-        <a href="{:url('@')}" class="topbar-logo pull-left">{:sysconf('app_name')} <sup>{:sysconf('app_version')}</sup></a>
+    <!-- 顶部菜单 开始 -->
+    <div class="layui-header notselect">
+        <a href="{:url('@')}" class="layui-logo layui-elip">{:sysconf('app_name')} {if sysconf('app_version')}<sup class="padding-left-5">{:sysconf('app_version')}</sup>{/if}</a>
+        <ul class="layui-nav layui-layout-left">
+            {foreach $menus as $oneMenu}
+            <li class="layui-nav-item">
+                <a data-menu-node="m-{$oneMenu.id}" data-open="{$oneMenu.url}">
+                    {notempty name='oneMenu.icon'}<span class='{$oneMenu.icon} padding-right-5'></span>{/notempty}
+                    <span>{$oneMenu.title|default=''}</span>
+                </a>
+            </li>
+            {/foreach}
+        </ul>
+        <ul class="layui-nav layui-layout-right">
+            <li lay-unselect class="layui-nav-item"><a data-reload><i class="layui-icon layui-icon-refresh-3"></i></a></li>
+            {notempty name='Think.session.user'}
+            <li class="layui-nav-item">
+                <dl class="layui-nav-child">
+                    <dd lay-unselect><a data-modal="{:url('admin/index/info',['id'=>session('user.id')])}"><i class="layui-icon layui-icon-set-fill margin-right-5"></i>基本资料</a></dd>
+                    <dd lay-unselect><a data-modal="{:url('admin/index/pass',['id'=>session('user.id')])}"><i class="layui-icon layui-icon-component margin-right-5"></i>安全设置</a></dd>
+                    <dd lay-unselect><a data-modal="{:url('admin/index/buildOptimize')}"><i class="layui-icon layui-icon-template-1 margin-right-5"></i>压缩发布</a></dd>
+                    <dd lay-unselect><a data-modal="{:url('admin/index/clearRuntime')}"><i class="layui-icon layui-icon-fonts-clear margin-right-5"></i>清理缓存</a></dd>
+                    <dd lay-unselect><a data-confirm="确定要退出登录吗?" data-load="{:url('admin/login/out')}"><i class="layui-icon layui-icon-release margin-right-5"></i>退出登录</a></dd>
+                </dl>
+                <a><span><i class="layui-icon layui-icon-username margin-right-5"></i> {:session('user.username')}</span></a>
+            </li>
+            {else}
+            <li class="layui-nav-item">
+                <a data-href="{:url('@admin/login')}"><i class="layui-icon layui-icon-username"></i> 立即登录</a>
+            </li>
+            {/notempty}
+        </ul>
     </div>
-    <!--{foreach $menus as $oneMenu}-->
-    <a data-menu-node="m-{$oneMenu.id}" data-open="{$oneMenu.url}" class="topbar-btn pull-left transition">
-        {notempty name='oneMenu.icon'}<span class='font-s13 {$oneMenu.icon}'></span>&nbsp;{/notempty}
-        {$oneMenu.title|default=''}
-    </a>
-    <!--{/foreach}-->
-    <div class="pull-right">
-        <!--{if session('user.id')}-->
-        <div class="dropdown">
-            <a href="#" class="dropdown-toggle topbar-btn text-center transition" data-toggle="dropdown">
-                <span class="glyphicon glyphicon-user font-s13"></span>
-                {:session('user.username')}
-                <span class="toggle-icon glyphicon glyphicon-menu-up transition font-s13"></span>
-            </a>
-            <ul class="dropdown-menu">
-                <li class="topbar-btn"><a data-modal="{:url('admin/index/pass')}?id={:session('user.id')}" data-title="修改密码"><i class="glyphicon glyphicon-lock"></i> 修改密码</a></li>
-                <li class="topbar-btn"><a data-modal="{:url('admin/index/info')}?id={:session('user.id')}" data-title="修改资料"><i class="glyphicon glyphicon-edit"></i> 修改资料</a></li>
-                <li class="topbar-btn">
-                    <a data-load="{:url('admin/login/out')}" data-confirm="确定要退出登录吗?"><i class="glyphicon glyphicon-log-out"></i> 退出登录</a>
+    <!-- 顶部菜单 结束 -->
+
+    <!-- 左则菜单 开始 -->
+    <div class="layui-side layui-bg-black notselect">
+        <div class="layui-side-scroll">
+            <ul class="layui-nav layui-nav-tree layui-nav-tree-top">
+                <li class="layui-nav-item" lay-unselect><a class="text-center" data-target-menu-type><i class="layui-icon layui-icon-spread-left"></i></a></li>
+            </ul>
+            {foreach $menus as $oneMenu}
+            {notempty name='oneMenu.sub'}
+            <ul class="layui-nav layui-nav-tree layui-hide" data-menu-layout="m-{$oneMenu.id}">
+                {foreach $oneMenu.sub as $twoMenu}
+                {empty name='twoMenu.sub'}
+                <li class="layui-nav-item">
+                    <a data-target-tips="{$twoMenu.title}" data-menu-node="m-{$oneMenu.id}-{$twoMenu.id}" data-open="{$twoMenu.url}">
+                        <span class='{$twoMenu.icon|default="layui-icon layui-icon-link"}'></span>
+                        <span class="nav-text padding-left-5">{$twoMenu.title}</span>
+                    </a>
+                </li>
+                {else}
+                <li class="layui-nav-item" data-submenu-layout='m-{$oneMenu.id}-{$twoMenu.id}'>
+                    <a data-target-tips="{$twoMenu.title}" style="background:#393D49">
+                        <span class='nav-icon layui-hide {$twoMenu.icon|default="layui-icon layui-icon-triangle-d"}'></span>
+                        <span class="nav-text padding-left-5">{$twoMenu.title}</span>
+                    </a>
+                    <dl class="layui-nav-child">
+                        {foreach $twoMenu.sub as $thrMenu}
+                        <dd>
+                            <a data-target-tips="{$thrMenu.title}" data-open="{$thrMenu.url}" data-menu-node="m-{$oneMenu.id}-{$twoMenu.id}-{$thrMenu.id}">
+                                <span class='nav-icon padding-left-5 {$thrMenu.icon|default="layui-icon layui-icon-link"}'></span>
+                                <span class="nav-text padding-left-5">{$thrMenu.title}</span>
+                            </a>
+                        </dd>
+                        {/foreach}
+                    </dl>
                 </li>
+                {/empty}
+                {/foreach}
             </ul>
+            {/notempty}
+            {/foreach}
         </div>
-        <!--{else}-->
-        <div class="topbar-info-item">
-            <a data-href="{:url('@admin/login')}" data-toggle="dropdown" class=" topbar-btn text-center">
-                <span class='glyphicon glyphicon-user'></span> 立即登录 </span>
-            </a>
-        </div>
-        <!--{/if}-->
     </div>
-    <a class="topbar-btn pull-right transition" data-tips-text="刷新" data-reload="true" style="width:50px"><span class="glyphicon glyphicon-refresh font-s12"></span></a>
-</div>
-<!-- 顶部菜单区域 结束 -->
+    <!-- 左则菜单 结束 -->
+
+    <!-- 主体内容 开始 -->
+    <div class="layui-body">{block name='content'}{/block}</div>
+    <!-- 主体内容 结束 -->
 
-<!-- 左则菜单区域 开始 -->
-<div class="framework-leftbar">
-    {foreach $menus as $oneMenu}
-    <!--{notempty name='$oneMenu.sub'}-->
-    <div class="leftbar-container hide notselect" data-menu-layout="m-{$oneMenu.id}">
-        <div class="line-top">
-            <i class="layui-icon font-s12">&#xe65f;</i>
-        </div>
-        {foreach $oneMenu.sub as $twoMenu}
-        <!--{empty name='$twoMenu.sub'}-->
-        <a class='transition' data-menu-node="m-{$oneMenu.id}-{$twoMenu.id}" data-open="{$twoMenu.url}">
-            {notempty name='twoMenu.icon'}<span class='{$twoMenu.icon} font-icon'></span>&nbsp;{/notempty}
-            {$twoMenu.title}
-        </a>
-        <!--{else}-->
-        <div data-submenu-layout='m-{$oneMenu.id}-{$twoMenu.id}'>
-            <a class='menu-title transition'>
-                {notempty name='twoMenu.icon'}<span class='{$twoMenu.icon} font-icon'></span>&nbsp;{/notempty}
-                {$twoMenu.title} <i class='layui-icon pull-right font-s12 transition'>&#xe619;</i>
-            </a>
-            <div>
-                {foreach $twoMenu.sub as $thrMenu}
-                <a class='transition' data-open="{$thrMenu.url}" data-menu-node="m-{$oneMenu.id}-{$twoMenu.id}-{$thrMenu.id}">
-                    {notempty name='thrMenu.icon'}<span class='{$thrMenu.icon} font-icon'></span>{/notempty} {$thrMenu.title}
-                </a>
-                {/foreach}
-            </div>
-        </div>
-        <!--{/empty}-->
-        {/foreach}
-    </div>
-    <!--{/notempty}-->
-    {/foreach}
 </div>
-<!-- 左则菜单区域 结束 -->
+{/block}
+<script src="__ROOT__/static/plugs/layui/layui.all.js"></script>
+<script src="__ROOT__/static/plugs/require/require.js"></script>
+<script src="__ROOT__/static/admin.js"></script>
+{block name='script'}{/block}
+{if session('user.id') and sysconf('system_message_state')}
+<script>
+    require(['spop'], function () {
+        syncMessage();
+
+        function syncMessage() {
+            $.get('{:url("@admin/api.message/gets")}', function (ret) {
+                if (ret.code && ret.data.length > 0) for (var i in ret.data) {
+                    var item = ret.data[i];
+                    if ($('[data-message-code=' + item.code + ']').size() < 1) spop({
+                        template: '<h4 data-message-code="' + item.code + '" class="spop-title">' + item.title + '</h4>' + item.desc + '<span class="font-s10 color-desc pull-right"> ' + item.create_at + ' </span>',
+                        position: 'bottom-right', style: 'success', group: item.code, onClose: function () {
+                            $.post('{:url("@admin/api.message/set")}', {code: this.group});
+                        }
+                    });
+                }
+                setTimeout(syncMessage, 3000)
+            });
+        }
+    });
+</script>
+{/if}
+</body>
 
-<!-- 右则内容区域 开始 -->
-<div class="framework-body"></div>
-<!-- 右则内容区域 结束 -->
-{/block}
+</html>

+ 41 - 42
application/admin/view/index/main.html

@@ -1,7 +1,6 @@
-{extend name='admin@public/content'}
-
-{block name="content"}
+{extend name='main'}
 
+{block name='content'}
 <table class="layui-table" lay-even lay-skin="line">
     <colgroup>
         <col width="20%">
@@ -17,66 +16,66 @@
     </thead>
     <tbody>
     <tr>
-        <td style="max-width:200px" class="nowrap">ThinkAdmin 版本</td>
-        <td class="nowrap">{:sysconf('app_version')}</td>
-        <td style="max-width:200px" class="nowrap">产品名称</td>
-        <td class="nowrap">ThinkAdmin 管理框架</td>
-    </tr>
-    <tr>
-        <td class="nowrap">ThinkPHP 版本</td>
-        <td class="nowrap">{$think_ver}</td>
-        <td class="nowrap">产品名称</td>
-        <td class="nowrap">ThinkAdmin 管理框架</td>
+        <td style="max-width:200px">framework 版本</td>
+        <td>{:sysconf('app_version')}</td>
+        <td style="max-width:200px">产品名称</td>
+        <td>framework</td>
     </tr>
     <tr>
-        <td class="nowrap">服务器操作系统</td>
-        <td class="nowrap">{:php_uname('s')}</td>
-        <td class="nowrap">产品DEMO体验</td>
-        <td class="nowrap">
-            <a target="_blank" href="http://demo.thinkadmin.top">http://demo.thinkadmin.top</a>
+        <td>ThinkPHP 版本</td>
+        <td>{$think_ver}</td>
+        <td>在线体验</td>
+        <td>
+            <a target="_blank" href="http://framework.thinkadmin.top">http://framework.thinkadmin.top</a>
         </td>
     </tr>
     <tr>
-        <td class="nowrap">WEB运行环境</td>
-        <td class="nowrap">{:php_sapi_name()}</td>
-        <td class="nowrap">官方QQ群</td>
-        <td class="nowrap">
+        <td>服务器操作系统</td>
+        <td>{:php_uname('s')}</td>
+        <td>官方QQ群</td>
+        <td>
             <a href="http://shang.qq.com/wpa/qunwpa?idkey=ae25cf789dafbef62e50a980ffc31242f150bc61a61164458216dd98c411832a">
                 <img src="//pub.idqqimg.com/wpa/images/group.png" style="height:18px;width:auto" target="_blank">
             </a>
         </td>
     </tr>
     <tr>
-        <td class="nowrap">MySQL数据库版本</td>
-        <td class="nowrap">{$mysql_ver}</td>
-        <td class="nowrap">BUG反馈</td>
-        <td class="nowrap">
-            <a target="_blank" href="https://github.com/zoujingli/ThinkAdmin/issues">
-                https://github.com/zoujingli/ThinkAdmin/issues
+        <td>WEB运行环境</td>
+        <td>{:php_sapi_name()}</td>
+        <td>项目地址</td>
+        <td>
+            <a target="_blank" href="https://github.com/zoujingli/ThinkAdmin">
+                https://github.com/zoujingli/ThinkAdmin
             </a>
         </td>
     </tr>
     <tr>
-        <td class="nowrap">运行PHP版本</td>
-        <td class="nowrap">{$Think.PHP_VERSION}</td>
-        <td class="nowrap">项目地址</td>
-        <td class="nowrap">
-            <a target="_blank" href="https://github.com/zoujingli/ThinkAdmin">
-                https://github.com/zoujingli/ThinkAdmin
+        <td>MySQL数据库版本</td>
+        <td>{$mysql_ver}</td>
+        <td>BUG反馈</td>
+        <td>
+            <a target="_blank" href="https://github.com/zoujingli/ThinkAdmin/issues">
+                https://github.com/zoujingli/ThinkAdmin/issues
             </a>
         </td>
     </tr>
     <tr>
-        <td class="nowrap">上传大小限制</td>
-        <td class="nowrap">{:ini_get('upload_max_filesize')}</td>
-        <td class="nowrap">公司官网</td>
-        <td class="nowrap"><a target="_blank" href="http://www.cuci.cc">http://www.cuci.cc</a></td>
+        <td>运行PHP版本</td>
+        <td>{$Think.PHP_VERSION}</td>
+        <td>开发团队</td>
+        <td><a href="http://www.cuci.cc" target="_blank">广州楚才信息科技有限公司</a></td>
+    </tr>
+    <tr>
+        <td>上传大小限制</td>
+        <td>{:ini_get('upload_max_filesize')}</td>
+        <td>团队官网</td>
+        <td><a target="_blank" href="http://www.cuci.cc">http://www.cuci.cc</a></td>
     </tr>
     <tr>
-        <td class="nowrap">POST大小限制</td>
-        <td class="nowrap">{:ini_get('post_max_size')}</td>
-        <td class="nowrap">公司地址</td>
-        <td class="nowrap">广州市天河区东圃一横路东泷商贸中心C座316</td>
+        <td>POST大小限制</td>
+        <td>{:ini_get('post_max_size')}</td>
+        <td>公地址</td>
+        <td>广州市天河区东圃一横路东泷商贸中心C座316</td>
     </tr>
     </tbody>
 </table>

+ 54 - 93
application/admin/view/log/index.html

@@ -1,100 +1,61 @@
-{extend name='admin@public/content'}
+{extend name='main'}
 
 {block name="button"}
-<!--{if auth("$classuri/del")}-->
-<button data-update data-field='delete' data-action='{:url("$classuri/del")}' class='layui-btn layui-btn-sm layui-btn-primary'>删除日志</button>
-<!--{/if}-->
-{/block}
-
-{block name="content"}
-
-<!-- 表单搜索 开始 -->
-<form autocomplete="off" class="layui-form layui-form-pane form-search" action="{:request()->url()}" onsubmit="return false" method="get">
-
-    <div class="layui-form-item layui-inline">
-        <label class="layui-form-label">操作账号</label>
-        <div class="layui-input-inline">
-            <input name="username" value="{$Think.get.username|default=''}" placeholder="请输入操作者" class="layui-input">
-        </div>
-    </div>
 
-    <div class="layui-form-item layui-inline">
-        <label class="layui-form-label">操作行为</label>
-        <div class="layui-input-inline">
-            <select name='action' class='layui-select' lay-search="">
-                <option value=''> - 所有记录 -</option>
-                <!--{foreach $actions as $action}-->
-                <!--{if $action===$Think.get.action}-->
-                <option selected="selected" value='{$action}'>{$action}</option>
-                <!--{else}-->
-                <option value='{$action}'>{$action}</option>
-                <!--{/if}-->
-                <!--{/foreach}-->
-            </select>
-        </div>
-    </div>
+{if auth("admin/log/del")}
+<button data-action='{:url("del")}' data-rule="id#{key}" data-csrf="{:systoken('admin/log/del')}" data-confirm="确定要删除日志吗?" class='layui-btn layui-btn-sm layui-btn-primary'>删除日志</button>
+{/if}
 
-    <div class="layui-form-item layui-inline">
-        <label class="layui-form-label">操作内容</label>
-        <div class="layui-input-inline">
-            <input name="content" value="{$Think.get.content|default=''}" placeholder="请输入操作内容" class="layui-input">
-        </div>
-    </div>
-
-    <div class="layui-form-item layui-inline">
-        <label class="layui-form-label">操作时间</label>
-        <div class="layui-input-inline">
-            <input name="create_at" id='create_at' value="{$Think.get.create_at|default=''}" placeholder="请选择操作时间" class="layui-input">
-        </div>
-    </div>
-
-    <div class="layui-form-item layui-inline">
-        <button class="layui-btn layui-btn-primary"><i class="layui-icon">&#xe615;</i> 搜 索</button>
-    </div>
+{/block}
 
-</form>
-<script>
-    window.form.render();
-    window.laydate.render({range: true, elem: '#create_at'});
-</script>
-<!-- 表单搜索 结束 -->
+{block name="content"}
+<table class="layui-table" lay-skin="line">
+    <caption class="margin-bottom-10 text-left">{include file='log/index_search'}</caption>
+    {notempty name='list'}
+    <thead>
+    <tr>
+        <th class='list-table-check-td think-checkbox'>
+            <input data-auto-none data-check-target='.list-check-box' type='checkbox'>
+        </th>
+        <th class='text-left nowrap' width="20%">操作</th>
+        <th class='text-left nowrap' width="20%">权限</th>
+        <th class='text-left nowrap' width="20%">位置</th>
+        <th class='text-left nowrap' width="20%">操作时间</th>
+        <th></th>
+    </tr>
+    </thead>
+    <tbody>
+    <!--{foreach $list as $key=>$vo}-->
+    <tr data-dbclick>
+        <td class='list-table-check-td think-checkbox'>
+            <input class="list-check-box" value='{$vo.id}' type='checkbox'>
+        </td>
+        <td class='text-left nowrap'>
+            行为:<strong>{$vo.action|default='--'}</strong><br>
+            描述:{$vo.content|default='--'}
+        </td>
+        <td class='text-left nowrap'>
+            账号:{$vo.username|default='--'}<br>
+            节点:{$vo.node|default='--'}
+        </td>
+        <td class='text-left nowrap'>
+            地址:{$vo.geoip|default='--'}<br>
+            位置:{$vo.isp|default='--'}
+        </td>
+        <td class='text-left nowrap'>
+            日期:{$vo.create_at|format_datetime|str_replace=' ','<br>时间:',###|raw}
+        </td>
+        <td class='text-left nowrap'>
+            {if auth("admin/log/del")}
+            <a data-dbclick class="layui-btn layui-btn-sm layui-btn-danger" data-confirm="确定要删除该日志吗?" data-action="{:url('del')}" data-value="id#{$vo.id}" data-csrf="{:systoken('admin/log/del')}">删 除</a>
+            {/if}
+        </td>
+    </tr>
+    <!--{/foreach}-->
+    </tbody>
+    {/notempty}
+</table>
+
+{empty name='list'}<span class="notdata">没有记录哦</span>{else}{$pagehtml|raw|default=''}{/empty}
 
-<form onsubmit="return false;" data-auto="true" method="post">
-    <!--{empty name='list'}-->
-    <p class="help-block text-center well">没 有 记 录 哦!</p>
-    <!--{else}-->
-    <input type="hidden" value="resort" name="action">
-    <table class="layui-table" lay-skin="line">
-        <thead>
-        <tr>
-            <th class='list-table-check-td think-checkbox'>
-                <input data-auto-none="" data-check-target='.list-check-box' type='checkbox'>
-            </th>
-            <th class='text-left nowrap'>操作账号</th>
-            <th class='text-left nowrap'>权限节点</th>
-            <th class='text-left nowrap'>操作行为</th>
-            <th class='text-left nowrap'>操作内容</th>
-            <th class='text-left nowrap'>操作位置</th>
-            <th class='text-left nowrap'>操作时间</th>
-        </tr>
-        </thead>
-        <tbody>
-        <!--{foreach $list as $key=>$vo}-->
-        <tr>
-            <td class='list-table-check-td think-checkbox'>
-                <input class="list-check-box" value='{$vo.id}' type='checkbox'>
-            </td>
-            <td class='text-left nowrap'>{$vo.username}</td>
-            <td class='text-left nowrap'>{$vo.node}</td>
-            <td class='text-left nowrap'>{$vo.action}</td>
-            <td class='text-left nowrap'>{$vo.content}</td>
-            <td class='text-left nowrap'>{$vo.isp|default=$vo.ip}</td>
-            <td class='text-left nowrap'>{$vo.create_at|format_datetime}</td>
-        </tr>
-        <!--{/foreach}-->
-        </tbody>
-    </table>
-    {if isset($page)}<p>{$page|raw}</p>{/if}
-    <!--{/empty}-->
-</form>
 {/block}

+ 56 - 0
application/admin/view/log/index_search.html

@@ -0,0 +1,56 @@
+<fieldset>
+
+    <legend class="layui-bg-cyan">条件搜索</legend>
+
+    <form class="layui-form layui-form-pane form-search" action="{:request()->url()}" onsubmit="return false" method="get" autocomplete="off">
+
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">操作账号</label>
+            <div class="layui-input-inline">
+                <input name="username" value="{$Think.get.username|default=''}" placeholder="请输入操作账号" class="layui-input">
+            </div>
+        </div>
+
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">操作节点</label>
+            <div class="layui-input-inline">
+                <input name="node" value="{$Think.get.node|default=''}" placeholder="请输入操作节点" class="layui-input">
+            </div>
+        </div>
+
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">操作行为</label>
+            <div class="layui-input-inline">
+                <input name="action" value="{$Think.get.action|default=''}" placeholder="请输入操作行为" class="layui-input">
+            </div>
+        </div>
+
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">操作描述</label>
+            <div class="layui-input-inline">
+                <input name="content" value="{$Think.get.content|default=''}" placeholder="请输入操作内容" class="layui-input">
+            </div>
+        </div>
+
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">位置地址</label>
+            <div class="layui-input-inline">
+                <input name="geoip" value="{$Think.get.geoip|default=''}" placeholder="请输入位置地址" class="layui-input">
+            </div>
+        </div>
+
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">操作时间</label>
+            <div class="layui-input-inline">
+                <input data-date-range name="create_at" value="{$Think.get.create_at|default=''}" placeholder="请选择操作时间" class="layui-input">
+            </div>
+        </div>
+
+        <div class="layui-form-item layui-inline">
+            <button class="layui-btn layui-btn-primary"><i class="layui-icon">&#xe615;</i> 搜 索</button>
+        </div>
+    </form>
+
+</fieldset>
+
+<script>form.render()</script>

+ 0 - 76
application/admin/view/log/sms.html

@@ -1,76 +0,0 @@
-{extend name='admin@public/content'}
-
-{block name="content"}
-
-<!-- 表单搜索 开始 -->
-<form class="layui-form layui-form-pane form-search" action="{:request()->url()}" onsubmit="return false" method="get">
-    <div class="layui-form-item layui-inline">
-        <label class="layui-form-label">手机号码</label>
-        <div class="layui-input-inline">
-            <input name="phone" value="{$Think.get.phone|default=''}" placeholder="请输入手机号码" class="layui-input">
-        </div>
-    </div>
-
-    <div class="layui-form-item layui-inline">
-        <label class="layui-form-label">短信内容</label>
-        <div class="layui-input-inline">
-            <input name="content" value="{$Think.get.content|default=''}" placeholder="请输入短信内容" class="layui-input">
-        </div>
-    </div>
-
-    <div class="layui-form-item layui-inline">
-        <label class="layui-form-label">返回结果</label>
-        <div class="layui-input-inline">
-            <input name="result" value="{$Think.get.result|default=''}" placeholder="请输入返回结果" class="layui-input">
-        </div>
-    </div>
-
-    <div class="layui-form-item layui-inline">
-        <label class="layui-form-label">发送时间</label>
-        <div class="layui-input-inline">
-            <input name="date" id='range-date' value="{$Think.get.date|default=''}" placeholder="请选择发送时间" class="layui-input">
-        </div>
-    </div>
-
-    <div class="layui-form-item layui-inline">
-        <button class="layui-btn layui-btn-primary"><i class="layui-icon">&#xe615;</i> 搜 索</button>
-    </div>
-
-</form>
-<!-- 表单搜索 结束 -->
-
-<form onsubmit="return false;" data-auto="true" method="post">
-    <input type="hidden" value="resort" name="action"/>
-    <table class="layui-table" lay-skin="line">
-        <thead>
-        <tr>
-            <th class='list-table-check-td'>
-                <input data-auto-none="" data-check-target='.list-check-box' type='checkbox'/>
-            </th>
-            <th class='text-left nowrap'>手机号</th>
-            <th class='text-left nowrap'>短信内容</th>
-            <th class='text-left nowrap'>返回结果</th>
-            <th class='text-left nowrap'>发送时间</th>
-        </tr>
-        </thead>
-        <tbody>
-        {foreach $list as $key=>$vo}
-        <tr>
-            <td class='list-table-check-td'>
-                <input class="list-check-box" value='{$vo.id}' type='checkbox'/>
-            </td>
-            <td class='text-left nowrap'>{$vo.phone}</td>
-            <td class='text-left nowrap'>{$vo.content}</td>
-            <td class='text-left nowrap'>{$vo.result}</td>
-            <td class='text-left nowrap'>{$vo.create_at|format_datetime}</td>
-        </tr>
-        {/foreach}
-        </tbody>
-    </table>
-    {if isset($page)}<p>{$page}</p>{/if}
-    <script>
-        window.form.render();
-        window.laydate.render({range: true, elem: '#range-date'});
-    </script>
-</form>
-{/block}

+ 37 - 70
application/admin/view/login/index.html

@@ -1,82 +1,49 @@
-{extend name="admin@public/main"}
-
-{block name="style"}
-<link href="__STATIC__/theme/css/login.css" rel="stylesheet">
-{/block}
+{extend name="admin@index/index"}
 
 {block name="body"}
-<div class="login-container">
-
-    <!-- 动态云层动画 开始 -->
-    <div class="clouds-container">
-        <div class="clouds clouds-footer"></div>
-        <div class="clouds"></div>
-        <div class="clouds clouds-fast"></div>
+<div class="login-container full-height" data-supersized="__ROOT__/static/theme/img/login/bg1.jpg,__ROOT__/static/theme/img/login/bg2.jpg">
+    <div class="header notselect layui-hide-xs">
+        <a href="{:url('@')}" class="title">{:sysconf('app_name')} <span class="padding-left-5 font-s10">{:sysconf('app_version')}</span></a>
+        <ul>
+            <li class="layui-hide"><a target="_blank" href="http://document.framework.thinkadmin.top">在线帮助</a></li>
+            <li><a target="_blank" href="http://soft.ftsm-shop.com/19/3911.html">推荐使用谷歌浏览器</a></li>
+        </ul>
     </div>
-    <!-- 动态云层动画 结束 -->
-
-    <!-- 顶部导航条 开始 -->
-    <div class="header notselect">
-        <span class="title notselect">{:sysconf('app_name')} <sup>{:sysconf('app_version')}</sup></span>
+    <form data-login-form onsubmit="return false;" method="post" class="layui-anim layui-anim-upbit" autocomplete="off">
+        <h2 class="notselect">系统管理</h2>
         <ul>
-            <li><a href="javascript:void(0)" target="_blank">帮助</a></li>
-            <li>
-                <a href="http://sw.bos.baidu.com/sw-search-sp/software/9e6bc213b9d0b/ChromeStandalone_63.0.3239.132_Setup.exe">推荐使用谷歌浏览器</a>
+            <li class="username">
+                <label>
+                    <i class="layui-icon layui-icon-username"></i>
+                    <input class="layui-input" required pattern="^\S{4,}$" name="username" autofocus autocomplete="off" placeholder="请输入账号">
+                </label>
+            </li>
+            <li class="password">
+                <label>
+                    <i class="layui-icon layui-icon-password"></i>
+                    <input class="layui-input" required pattern="^\S{4,}$" name="password" maxlength="32" type="password" autocomplete="off" placeholder="请输入密码">
+                </label>
+            </li>
+            <li class="text-center padding-top-20">
+                <input type="hidden" name="skey" value="{$skey|default=''}">
+                <button type="submit" class="layui-btn layui-disabled full-width" data-form-loaded="立即登入">正在载入</button>
             </li>
         </ul>
-    </div>
-    <!-- 顶部导航条 结束 -->
-
-    <!-- 页面表单主体 开始 -->
-    <div class="container">
-        <form autocomplete="off" onsubmit="return false;" data-time="0.001" data-auto="true" method="post" class="content layui-form animated fadeInDown">
-            <div class="people">
-                <div class="tou"></div>
-                <div id="left-hander" class="initial_left_hand transition"></div>
-                <div id="right-hander" class="initial_right_hand transition"></div>
-            </div>
-            <ul>
-                <li class="username">
-                    <i></i>
-                    <input required pattern="^\S{4,}$" name="username" value="admin" type="text" autofocus="autofocus" autocomplete="off" title="请输入4位及以上的字符" placeholder="请输入用户名/手机号码">
-                </li>
-                <li class="password">
-                    <i></i>
-                    <input required pattern="^\S{4,}$" name="password" value="admin" type="password" autocomplete="off" title="请输入4位及以上的字符" placeholder="请输入密码">
-                </li>
-                <li class="text-center">
-                    <button type="submit" class="layui-btn layui-disabled" data-form-loaded="立 即 登 入">正 在 载 入</button>
-                </li>
-            </ul>
-        </form>
-    </div>
-    <!-- 页面表单主体 结束 -->
-
-    <!-- 底部版权信息 开始 -->
-    <!--{if sysconf('site_copy')}-->
+    </form>
     <div class="footer notselect">
         {:sysconf('site_copy')}
-        {if sysconf('miitbeian')} <span>|</span> <a target="_blank" href="http://www.miitbeian.gov.cn">{:sysconf('miitbeian')}</a>{/if}
+        {if sysconf('miitbeian')}<span>&nbsp;|&nbsp;</span><a target="_blank" href="http://www.miitbeian.gov.cn">{:sysconf('miitbeian')}</a>{/if}
     </div>
-    <!--{/if}-->
-    <!-- 底部版本信息 结束 -->
-
 </div>
 {/block}
 
-{block name="script"}
-<script>
-    if (window.location.href.indexOf('#') > -1) {
-        window.location.href = window.location.href.split('#')[0];
-    }
-    $(function () {
-        $('[name="password"]').on('focus', function () {
-            $('#left-hander').removeClass('initial_left_hand').addClass('left_hand');
-            $('#right-hander').removeClass('initial_right_hand').addClass('right_hand')
-        }).on('blur', function () {
-            $('#left-hander').addClass('initial_left_hand').removeClass('left_hand');
-            $('#right-hander').addClass('initial_right_hand').removeClass('right_hand')
-        });
-    });
-</script>
-{/block}
+{block name='style'}
+<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1">
+<script>if (location.href.indexOf('#') > -1) location.replace(location.href.split('#')[0])</script>
+<link rel="stylesheet" href="__ROOT__/static/theme/css/login.css">
+{/block}
+
+{block name='script'}
+<script src="__ROOT__/static/plugs/supersized/supersized.3.2.7.min.js"></script>
+{/block}
+

+ 11 - 0
application/admin/view/main.html

@@ -0,0 +1,11 @@
+<div class="layui-card">
+    {block name='style'}{/block}
+    {notempty name='title'}
+    <div class="layui-card-header layui-anim layui-anim-fadein notselect">
+        <span class="layui-icon font-s10 color-desc margin-right-5">&#xe65b;</span>{$title|default=''}
+        <div class="pull-right">{block name='button'}{/block}</div>
+    </div>
+    {/notempty}
+    <div class="layui-card-body layui-anim layui-anim-fadein">{block name='content'}{/block}</div>
+    {block name='script'}{/block}
+</div>

+ 66 - 53
application/admin/view/menu/form.html

@@ -1,74 +1,87 @@
-<form autocomplete="off" class="layui-form layui-box modal-form-box" action="{:request()->url()}" data-auto="true" method="post">
+<form class="layui-form layui-card" action="{:request()->url()}" data-auto="true" method="post" autocomplete="off">
 
-    <div class="layui-form-item">
-        <label class="layui-form-label">上级菜单</label>
-        <div class="layui-input-block">
-            <select name='pid' class='layui-select full-width' lay-ignore>
-                <!--{foreach $menus as $menu}-->
-                <!--{eq name='menu.id' value='$vo.pid|default=0'}-->
-                <option selected value='{$menu.id}'>{$menu.spl|raw}{$menu.title}</option>
-                <!--{else}-->
-                <option value='{$menu.id}'>{$menu.spl|raw}{$menu.title}</option>
-                <!--{/eq}-->
-                <!--{/foreach}-->
-            </select>
-            <p class="help-block color-desc"><b>必填</b>,请选择上级菜单或顶级菜单(目前最多支持三级菜单)</p>
+    <div class="layui-card-body">
+
+        <div class="layui-form-item">
+            <label class="layui-form-label">上级菜单</label>
+            <div class="layui-input-block">
+                <select name='pid' class='layui-select full-width' lay-ignore>
+                    <!--{foreach $menus as $menu}-->
+                    <!--{eq name='menu.id' value='$vo.pid|default=0'}-->
+                    <option selected value='{$menu.id}'>{$menu.spl|raw}{$menu.title}</option>
+                    <!--{else}-->
+                    <option value='{$menu.id}'>{$menu.spl|raw}{$menu.title}</option>
+                    <!--{/eq}-->
+                    <!--{/foreach}-->
+                </select>
+                <p class="help-block"><b>必选</b>,请选择上级菜单或顶级菜单(目前最多支持三级菜单)</p>
+            </div>
         </div>
-    </div>
 
-    <div class="layui-form-item">
-        <label class="layui-form-label">菜单名称</label>
-        <div class="layui-input-block">
-            <input type="text" name="title" value='{$vo.title|default=""}' required="required" title="请输入菜单名称" placeholder="请输入菜单名称" class="layui-input">
-            <p class="help-block color-desc"><b>必填</b>,请填写菜单名称(如:系统管理),建议字符不要太长,一般4-6个汉字</p>
+        <div class="layui-form-item">
+            <label class="layui-form-label">菜单名称</label>
+            <div class="layui-input-block">
+                <input name="title" value='{$vo.title|default=""}' required placeholder="请输入菜单名称" class="layui-input">
+                <p class="help-block"><b>必填</b>,请填写菜单名称(如:系统管理),建议字符不要太长,一般4-6个汉字</p>
+            </div>
         </div>
-    </div>
 
-    <div class="layui-form-item">
-        <label class="layui-form-label">菜单链接</label>
-        <div class="layui-input-block">
-            <input type="text" onblur="(this.value === '') && (this.value = '#')" name="url" autocomplete="off" required="required" title="请输入菜单链接" placeholder="请输入菜单链接" value="{$vo.url|default='#'}" class="layui-input typeahead">
-            <p class="help-block color-desc">
-                <b>必填</b>,请填写系统节点(如:admin/user/index),节点加入权限管理时菜单才会自动隐藏,非规则内的不会隐藏;
-                <br>正常情况下,在输入的时候会有自动提示。如果是上级菜单时,请填写"#"符号,不要填写地址或节点地址
-            </p>
+        <div class="layui-form-item">
+            <label class="layui-form-label">菜单链接</label>
+            <div class="layui-input-block">
+                <input onblur="this.value=this.value === ''?'#':this.value" name="url" required placeholder="请输入菜单链接" value="{$vo.url|default='#'}" class="layui-input">
+                <p class="help-block">
+                    <b>必填</b>,请填写系统节点(如:admin/user/index),节点加入权限管理时菜单才会自动隐藏,非规则内的不会隐藏;
+                    <br>正常情况下,在输入的时候会有自动提示。如果是上级菜单时,请填写"#"符号,不要填写地址或节点地址
+                </p>
+            </div>
         </div>
-    </div>
 
-    <div class="layui-form-item">
-        <label class="layui-form-label">链接参数</label>
-        <div class="layui-input-block">
-            <input type="text" name="params" autocomplete="off" title="请输入链接参数" placeholder="请输入链接参数" value="{$vo.params|default=''}" class="layui-input">
-            <p class="help-block color-desc"><b>可选</b>,设置菜单链接的GET访问参数(如:name=1&age=3)</p>
+        <div class="layui-form-item">
+            <label class="layui-form-label">链接参数</label>
+            <div class="layui-input-block">
+                <input name="params" placeholder="请输入链接参数" value="{$vo.params|default=''}" class="layui-input">
+                <p class="help-block"><b>可选</b>,设置菜单链接的GET访问参数(如:name=1&age=3)</p>
+            </div>
         </div>
-    </div>
 
-    <div class="layui-form-item">
-        <label class="layui-form-label">菜单图标</label>
-        <div class="layui-input-block">
-            <div class="layui-input-inline" style='width:300px'>
-                <input placeholder="请输入或选择图标" onchange="$('#icon-preview').get(0).className = this.value" type="text" name="icon" value='{$vo.icon|default=""}' class="layui-input">
+        <div class="layui-form-item">
+            <label class="layui-form-label">菜单图标</label>
+            <div class="layui-input-block">
+                <div class="layui-input-inline">
+                    <input placeholder="请输入或选择图标" onchange="$(this).parent().next().find('i').get(0).className=this.value" name="icon" value='{$vo.icon|default=""}' class="layui-input">
+                </div>
+                <span style="padding:0 12px;min-width:45px" class='layui-btn layui-btn-primary'>
+                    <i style="font-size:1.2em" class='{$vo.icon|default=""} margin-0'></i>
+                </span>
+                <button data-icon='icon' type='button' class='layui-btn layui-btn-primary'>选择图标</button>
+                <p class="help-block"><b>可选</b>,设置菜单选项前置图标,目前只支持 Font Awesome 5.2.0 字体图标</p>
             </div>
-            <span class='layui-btn layui-btn-primary' style='padding:0 12px;min-width:45px'>
-            <i id='icon-preview' style='font-size:1.2em' class='{$vo.icon|default=""}'></i>
-        </span>
-            <button data-icon='icon' type='button' class='layui-btn layui-btn-primary'>选择图标</button>
-            <p class="help-block color-desc"><b>可选</b>,设置菜单选项前置图标,目前只支持 Font Awesome 4.7.0 字体图标</p>
         </div>
+
     </div>
 
     <div class="hr-line-dashed"></div>
 
     <div class="layui-form-item text-center">
-        {if isset($vo['id'])}<input type='hidden' value='{$vo.id}' name='id'>{/if}
+        <!--{notempty name='vo.id'}-->
+        <input type='hidden' value='{$vo.id}' name='id'>
+        <!--{/notempty}-->
         <button class="layui-btn" type='submit'>保存数据</button>
         <button class="layui-btn layui-btn-danger" type='button' data-confirm="确定要取消编辑吗?" data-close>取消编辑</button>
     </div>
-    <script>
-        require(['bootstrap.typeahead'], function () {
-            var subjects = JSON.parse('{$nodes|raw|json_encode}');
-            $('.typeahead').typeahead({source: subjects, items: 5});
-        });
-    </script>
 
 </form>
+
+{block name='script'}
+<script>
+    require(['jquery.autocompleter'], function () {
+        $('input[name=url]').autocompleter({
+            limit: 6, highlightMatches: true, template: '{{ label }} <span> {{ title }} </span>', source: (function (subjects, data) {
+                for (var i in subjects) data.push({value: subjects[i].node, label: subjects[i].node, title: subjects[i].title});
+                return data;
+            })(JSON.parse('{$nodes|raw|json_encode}'), [])
+        });
+    });
+</script>
+{/block}

+ 67 - 74
application/admin/view/menu/index.html

@@ -1,87 +1,80 @@
-{extend name='admin@public/content'}
+{extend name='main'}
 
 {block name="button"}
-<!--{if auth("$classuri/add")}-->
-<button data-modal='{:url("$classuri/add")}' data-title="添加菜单" class='layui-btn layui-btn-sm layui-btn-primary'>添加菜单</button>
+
+<!--{if auth("admin/menu/add")}-->
+<button data-modal='{:url("add")}' data-title="添加菜单" class='layui-btn layui-btn-sm layui-btn-primary'>添加菜单</button>
 <!--{/if}-->
-<!--{if auth("$classuri/del")}-->
-<button data-update data-field='delete' data-action='{:url("$classuri/del")}' class='layui-btn layui-btn-sm layui-btn-primary'>删除菜单</button>
+
+<!--{if auth("admin/menu/del")}-->
+<button data-action='{:url("del")}' data-csrf="{:systoken('admin/menu/del')}" data-rule="id#{key}" class='layui-btn layui-btn-sm layui-btn-primary'>删除菜单</button>
 <!--{/if}-->
+
 {/block}
 
 {block name="content"}
-<form autocomplete="off" onsubmit="return false;" data-auto="true" method="post">
-    <!--{empty name='list'}-->
-    <p class="help-block text-center well">没 有 记 录 哦!</p>
-    <!--{else}-->
-    <input type="hidden" value="resort" name="action">
-    <table id="test" class="layui-table" lay-skin="line">
-        <thead>
-        <tr>
-            <th class='list-table-check-td think-checkbox'>
-                <input data-auto-none="" data-check-target='.list-check-box' type='checkbox'>
-            </th>
-            <th class='list-table-sort-td'>
-                <button type="submit" class="layui-btn layui-btn-normal layui-btn-xs">排 序</button>
-            </th>
-            <th class='text-center'></th>
-            <th></th>
-            <th class='visible-lg'></th>
-            <th class='text-center'></th>
-            <th class='text-center'></th>
-        </tr>
-        </thead>
-        <tbody>
-        <!--{foreach $list as $key=>$vo}-->
-        <tr>
-            <td class='list-table-check-td think-checkbox'>
-                <input class="list-check-box" value='{$vo.ids}' type='checkbox'>
-            </td>
-            <td class='list-table-sort-td'>
-                <input name="_{$vo.id}" value="{$vo.sort}" class="list-sort-input">
-            </td>
-            <td class='text-center'>
-                <i class="{$vo.icon} font-s18"></i>
-            </td>
-            <td class="nowrap"><span class="color-desc">{$vo.spl|raw}</span>{$vo.title}</td>
-            <td class='visible-lg'>{$vo.url}</td>
-            <td class='text-center nowrap'>
-                {if $vo.status eq 0}<span>已禁用</span>{elseif $vo.status eq 1}<span class="color-green">使用中</span>{/if}
-            </td>
-            <td class='text-center nowrap notselect'>
+<!--{empty name='list'}-->
+<blockquote class="layui-elem-quote">没 有 记 录 哦!</blockquote>
+<!--{else}-->
+<input type="hidden" value="resort" name="action">
+<table class="layui-table" lay-skin="line">
+    <thead>
+    <tr>
+        <th class='list-table-check-td think-checkbox'>
+            <input data-auto-none data-check-target='.list-check-box' type='checkbox'>
+        </th>
+        <th class='list-table-sort-td'>
+            <button type="button" data-reload class="layui-btn layui-btn-xs">刷 新</button>
+        </th>
+        <th class='text-center' style="width:30px"></th>
+        <th style="width:180px"></th>
+        <th class='layui-hide-xs' style="width:180px"></th>
+        <th style="width:100px"></th>
+        <th></th>
+    </tr>
+    </thead>
+    <tbody>
+    <!--{foreach $list as $key=>$vo}-->
+    <tr data-dbclick>
+        <td class='list-table-check-td think-checkbox'>
+            <input class="list-check-box" value='{$vo.ids}' type='checkbox'>
+        </td>
+        <td class='list-table-sort-td'>
+            <input data-action-blur="{:request()->url()}" data-value="id#{$vo.id};action#sort;sort#{value}" data-loading="false" value="{$vo.sort}" class="list-sort-input">
+        </td>
+        <td class='text-center'><i class="{$vo.icon} font-s18"></i></td>
+        <td class="nowrap"><span class="color-desc">{$vo.spl|raw}</span>{$vo.title}</td>
+        <td class='layui-hide-xs'>{$vo.url}</td>
+        <td class='text-center nowrap'>{eq name='vo.status' value='0'}<span class="layui-badge">已禁用</span>{else}<span class="layui-badge layui-bg-green">使用中</span>{/eq}</td>
+        <td class='text-center nowrap notselect'>
 
-                {if auth("$classuri/add")}
-                <span class="text-explode">|</span>
-                <!--{if $vo.spt<2}-->
-                <a data-title="添加菜单" data-modal='{:url("$classuri/add")}?pid={$vo.id}'>添加下级</a>
-                <!--{else}-->
-                <a class="color-desc">添加下级</a>
-                <!--{/if}-->
-                {/if}
+            {if auth("admin/menu/add")}
+            <span class="text-explode">|</span>
+            <!--{if $vo.spt<2}-->
+            <a class="layui-btn layui-btn-xs layui-btn-primary" data-tips-text="添加子菜单" data-modal='{:url("add")}?pid={$vo.id}'>添 加</a>
+            <!--{else}-->
+            <a class="layui-btn layui-btn-xs layui-btn-disabled">添 加</a>
+            <!--{/if}-->
+            {/if}
 
-                {if auth("$classuri/edit")}
-                <span class="text-explode">|</span>
-                <a data-title="编辑菜单" data-modal='{:url("$classuri/edit")}?id={$vo.id}'>编辑</a>
-                {/if}
+            {if auth("admin/menu/edit")}
+            <a data-dbclick class="layui-btn layui-btn-xs" data-title="编辑菜单" data-modal='{:url("admin/menu/edit")}?id={$vo.id}'>编 辑</a>
+            {/if}
 
-                {if $vo.status eq 1 and auth("$classuri/forbid")}
-                <span class="text-explode">|</span>
-                <a data-update="{$vo.ids}" data-field='status' data-value='0' data-action='{:url("$classuri/forbid")}'>禁用</a>
-                {elseif auth("$classuri/resume")}
-                <span class="text-explode">|</span>
-                <a data-update="{$vo.ids}" data-field='status' data-value='1' data-action='{:url("$classuri/resume")}'>启用</a>
-                {/if}
+            {if $vo.status eq 1 and auth("admin/menu/forbid")}
+            <a class="layui-btn layui-btn-warm layui-btn-xs" data-action="{:url('forbid')}" data-value="id#{$vo.ids};status#0" data-csrf="{:systoken('admin/menu/forbid')}">禁 用</a>
+            {elseif auth("admin/menu/resume")}
+            <a class="layui-btn layui-btn-warm layui-btn-xs" data-action="{:url('resume')}" data-value="id#{$vo.ids};status#1" data-csrf="{:systoken('admin/menu/resume')}">启 用</a>
+            {/if}
 
-                {if auth("$classuri/del")}
-                <span class="text-explode">|</span>
-                <a data-update="{$vo.ids}" data-field='delete' data-action='{:url("$classuri/del")}'>删除</a>
-                {/if}
+            {if auth("admin/menu/del")}
+            <a class="layui-btn layui-btn-danger layui-btn-xs" data-confirm="确定要删除数据吗?" data-action="{:url('del')}" data-value="id#{$vo.ids}" data-csrf="{:systoken('admin/menu/del')}">删 除</a>
+            {/if}
 
-            </td>
-        </tr>
-        <!--{/foreach}-->
-        </tbody>
-    </table>
-    <!--{/empty}-->
-</form>
+        </td>
+    </tr>
+    <!--{/foreach}-->
+    </tbody>
+</table>
+<!--{/empty}-->
 {/block}

+ 86 - 0
application/admin/view/message/index.html

@@ -0,0 +1,86 @@
+{extend name='main'}
+
+{block name="button"}
+
+{if auth("admin/message/onoff")}
+<form class="layui-form inline-block StatusSwitch" action="">
+    <!--{if sysconf('system_message_state')}-->
+    <input type="checkbox" checked lay-skin="switch" lay-filter="StatusSwitch" lay-text="开启|关闭">
+    <!--{else}-->
+    <input type="checkbox" lay-skin="switch" lay-filter="StatusSwitch" lay-text="开启|关闭">
+    <!--{/if}-->
+    <script>
+        form.on('switch(StatusSwitch)', function () {
+            $.form.load('{:url("onoff")}', {}, 'get', function () {
+                return false;
+            });
+        });
+    </script>
+    <style>
+        form.StatusSwitch .layui-form-switch {
+            margin: 0 10px 0 0;
+        }
+    </style>
+</form>
+{/if}
+
+{if auth("admin/message/clear")}
+<button data-load='{:url("clear")}' data-confirm="确定要清理所有消息记录吗?" class='layui-btn layui-btn-sm layui-btn-primary'>清理消息</button>
+{/if}
+
+{if auth("admin/message/del")}
+<button data-action='{:url("del")}' data-rule="id#{key}" data-confirm="确定要删除这些消息吗?" class='layui-btn layui-btn-sm layui-btn-primary'>批量删除</button>
+{/if}
+
+{/block}
+
+{block name="content"}
+<table class="layui-table" lay-skin="line">
+    <caption class="margin-bottom-10 text-left">{include file='message/index_search'}</caption>
+    {notempty name='list'}
+    <thead>
+    <tr>
+        <th class='list-table-check-td think-checkbox'>
+            <input data-auto-none data-check-target='.list-check-box' type='checkbox'>
+        </th>
+        <th class='text-left nowrap'>消息信息</th>
+        <th class='text-left nowrap'>消息状态</th>
+        <th class='text-left nowrap'>创建时间</th>
+        <th class='text-left nowrap'></th>
+    </tr>
+    </thead>
+    {/notempty}
+    <tbody>
+    {foreach $list as $key=>$vo}
+    <tr>
+        <td class='list-table-check-td think-checkbox'><input class="list-check-box" value='{$vo.id}' type='checkbox'></td>
+        <td class='text-left nowrap'>
+            <a class="color-text" href="{:url('@admin')}?messagecode={$vo.code}#{$vo.url|default=''}">{$vo.title|default=''}</a><br>
+            <span class="color-desc">{$vo.desc|default=''}</span><br>
+        </td>
+        <td class='text-left nowrap'>
+            消息状态:{if $vo.read_state}<span class="layui-badge layui-bg-green">已读取</span>{else}<span class="layui-badge layui-bg-blue">未读取</span>{/if}<br>
+            读取时间:{$vo.read_at|default='<span class="layui-badge layui-bg-blue">未读取</span>'|raw}<br>
+        </td>
+        <td class='text-left nowrap'>日期:{$vo.create_at|format_datetime|str_replace=' ','<br>时间:',###|raw}</td>
+        <td class='text-left nowrap'>
+
+            {if $vo.read_state eq 1 and auth("admin/message/state")}
+            <a class="layui-btn layui-btn-sm layui-btn-disabled">已 读</a>
+            {elseif auth("admin/message/state")}
+            <a class="layui-btn layui-btn-sm" data-action="{:url('state')}" data-value="id#{$vo.id};read_state#1">已 读</a>
+            {/if}
+
+            {if auth("admin/message/del")}
+            <a class="layui-btn layui-btn-sm layui-btn-danger" data-confirm="确定要删除该消息吗?" data-action="{:url('del')}" data-value="id#{$vo.id}">删 除</a>
+            {/if}
+
+        </td>
+    </tr>
+    {/foreach}
+    </tbody>
+</table>
+
+{empty name='list'}<span class="notdata">没有记录哦</span>{else}{$pagehtml|raw|default=''}{/empty}
+
+{/block}

+ 57 - 0
application/admin/view/message/index_search.html

@@ -0,0 +1,57 @@
+<fieldset>
+
+    <legend class="layui-bg-cyan">条件搜索</legend>
+
+    <form class="layui-form layui-form-pane form-search" action="{:request()->url()}" onsubmit="return false" method="get" autocomplete="off">
+
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">消息标题</label>
+            <div class="layui-input-inline">
+                <input name="title" value="{$Think.get.title|default=''}" placeholder="请输入消息标题" class="layui-input">
+            </div>
+        </div>
+
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">消息描述</label>
+            <div class="layui-input-inline">
+                <input name="desc" value="{$Think.get.desc|default=''}" placeholder="请输入消息描述" class="layui-input">
+            </div>
+        </div>
+
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">读取状态</label>
+            <div class="layui-input-inline">
+                <select class="layui-select" name="read_state">
+                    {foreach [''=>'-- 全部 --','0'=>'未读取消息','1'=>'已读取消息'] as $k=>$v}
+                    {eq name='Think.get.read_state' value='$k.""'}
+                    <option selected value="{$k}">{$v}</option>
+                    {else}
+                    <option value="{$k}">{$v}</option>
+                    {/eq}
+                    {/foreach}
+                </select>
+            </div>
+        </div>
+
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">读取时间</label>
+            <div class="layui-input-inline">
+                <input data-date-range name="read_at" value="{$Think.get.read_at|default=''}" placeholder="请输入读取时间" class="layui-input">
+            </div>
+        </div>
+
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">创建时间</label>
+            <div class="layui-input-inline">
+                <input data-date-range name="create_at" value="{$Think.get.create_at|default=''}" placeholder="请选择创建时间" class="layui-input">
+            </div>
+        </div>
+
+        <div class="layui-form-item layui-inline">
+            <button class="layui-btn layui-btn-primary"><i class="layui-icon">&#xe615;</i> 搜 索</button>
+        </div>
+    </form>
+
+</fieldset>
+
+<script>form.render()</script>

+ 47 - 34
application/admin/view/node/index.html

@@ -1,39 +1,43 @@
-{extend name='admin@public/content'}
+{extend name='main'}
 
 {block name='button'}
-<!--{if auth("$classuri/clear")}-->
-<button data-load='{:url("$classuri/clear")}' class='layui-btn layui-btn-sm layui-btn-primary'>清理无效记录</button>
+<!--{if auth("admin/node/clear")}-->
+<button data-load='{:url("clear")}' class='layui-btn layui-btn-sm layui-btn-primary'>清理无效记录</button>
 <!--{/if}-->
 {/block}
 
-{block name="content"}
-
+{block name='style'}
 <style>
-    .layui-table .title-input {
-        width: auto;
-        height: 28px;
-        line-height: 28px;
+    .layui-table tr:last-child td {
+        border: none
     }
 
     .layui-table label {
+        margin-top: 0;
         cursor: pointer
     }
+
+    .layui-table .title-input {
+        width: auto;
+        height: 28px;
+        line-height: 28px
+    }
 </style>
-<script>
-    $(function () {
-        $('.layui-tab ul.layui-tab-title li:first').trigger('click');
-    });
-</script>
+{/block}
+
+{block name="content"}
 <div class="layui-tab layui-tab-card layui-box">
     <ul class="layui-tab-title">
-        <!--{foreach $groups as $key=>$group}-->
-        <li>{$group.node.title|default='<span class="color-desc">未配置名称</span>'|raw}({$key})</li>
-        <!--{/foreach}-->
+        {foreach $groups as $key=>$group}
+        <li data-type='{$key}'>
+            {$group.node.title|default='<span class="color-desc">未配置名称</span>'|raw}({$key})
+        </li>
+        {/foreach}
     </ul>
     <div class="layui-tab-content">
-        {foreach $groups as $k=>$group}
+        {foreach $groups as $key=>$group}
         <div class="layui-tab-item">
-            <table class="layui-table border-none" lay-skin="line">
+            <table class="layui-table border-0 block layui-elip" lay-skin="line">
                 <!--{empty name='nodes'}-->
                 <p class="help-block text-center well">没 有 记 录 哦!</p>
                 <!--{else}-->
@@ -41,10 +45,10 @@
                 <tr>
                     <td class='text-left nowrap'>
                         <span class="color-desc">{$vo.spl|raw}</span> {$vo.node}
-                        {if auth("$classuri/save")}&nbsp;<input autocomplete="off" class='layui-input layui-input-inline title-input' name='title' data-node="{$vo.node}" value="{$vo.title}">{/if}
+                        {if auth("admin/node/save")}&nbsp;<input autocomplete="off" class='layui-input inline-block title-input' name='title' data-node="{$vo.node}" value="{$vo.title}">{/if}
                     </td>
-                    <td class='text-left nowrap'>
-                        {if auth("$classuri/save") and $vo.spt eq 1}
+                    <td class='text-left nowrap text-middle'>
+                        {if auth("admin/node/save") and $vo.spt eq 1}
                         <label class="color-desc think-checkbox">
                             <input data-login-group="{$vo.node}" type="checkbox"> 全部加入登录控制
                         </label>
@@ -57,31 +61,31 @@
                             <input data-menu-group="{$vo.node}" type="checkbox"> 全部加入菜单节点选择器
                         </label>
                         {/if}
-                        {if auth("$classuri/save") and $vo.spt eq 2}
-                        <span class="color-desc">&nbsp;&nbsp;├─&nbsp;</span>
+                        {if auth("admin/node/save") and $vo.spt eq 2}
+                        <span class="color-desc">&nbsp;├&nbsp;&nbsp;&nbsp;</span>
                         <label class="notselect margin-right-15 think-checkbox">
                             <!--{notempty name='vo.is_login'}-->
-                            <input data-login-filter="{$vo.pnode}" checked='checked' class="check-box login_{$k}_{$key}" type='checkbox' value='1' name='is_login' data-node="{$vo.node}" onclick="!this.checked && ($('.auth_{$k}_{$key}')[0].checked = !!this.checked)">
+                            <input data-login-filter="{$vo.pnode}" checked='checked' class="check-box login_{$key}" type='checkbox' value='1' name='is_login' data-node="{$vo.node}" onclick="!this.checked && ($('.auth_{$key}')[0].checked = !!this.checked)">
                             <!--{else}-->
-                            <input data-login-filter="{$vo.pnode}" class="check-box login_{$k}_{$key}" type='checkbox' value='1' name='is_login' data-node="{$vo.node}" onclick="!this.checked && ($('.auth_{$k}_{$key}')[0].checked = !!this.checked)">
+                            <input data-login-filter="{$vo.pnode}" class="check-box login_{$key}" type='checkbox' value='1' name='is_login' data-node="{$vo.node}" onclick="!this.checked && ($('.auth_{$key}')[0].checked = !!this.checked)">
                             <!--{/notempty}-->
                             加入登录控制
                         </label>
-                        <span class="color-desc">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;├─&nbsp;</span>
+                        <span class="color-desc">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;├&nbsp;&nbsp;&nbsp;</span>
                         <label class="notselect margin-right-15 think-checkbox">
                             <!--{notempty name='vo.is_auth'}-->
-                            <input data-auth-filter="{$vo.pnode}" name='is_auth' data-node="{$vo.node}" checked='checked' class="check-box auth_{$k}_{$key}" type='checkbox' onclick="this.checked && ($('.login_{$k}_{$key}')[0].checked = !!this.checked)" value='1'>
+                            <input data-auth-filter="{$vo.pnode}" name='is_auth' data-node="{$vo.node}" checked='checked' class="check-box auth_{$key}" type='checkbox' onclick="this.checked && ($('.login_{$key}')[0].checked = !!this.checked)" value='1'>
                             <!--{else}-->
-                            <input data-auth-filter="{$vo.pnode}" name='is_auth' data-node="{$vo.node}" class="check-box auth_{$k}_{$key}" type='checkbox' value='1' onclick="this.checked && ($('.login_{$k}_{$key}')[0].checked = !!this.checked)">
+                            <input data-auth-filter="{$vo.pnode}" name='is_auth' data-node="{$vo.node}" class="check-box auth_{$key}" type='checkbox' value='1' onclick="this.checked && ($('.login_{$key}')[0].checked = !!this.checked)">
                             <!--{/notempty}-->
                             加入权限控制
                         </label>
-                        <span class="color-desc">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;├─&nbsp;</span>
+                        <span class="color-desc">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;├&nbsp;&nbsp;&nbsp;</span>
                         <label class="notselect think-checkbox">
                             <!--{notempty name='vo.is_menu'}-->
-                            <input data-menu-filter="{$vo.pnode}" name='is_menu' data-node="{$vo.node}" checked='checked' class='check-box menu_{$k}_{$key}' type='checkbox' value='1'>
+                            <input data-menu-filter="{$vo.pnode}" name='is_menu' data-node="{$vo.node}" checked='checked' class='check-box menu_{$key}' type='checkbox' value='1'>
                             <!--{else}-->
-                            <input data-menu-filter="{$vo.pnode}" name='is_menu' data-node="{$vo.node}" class='check-box menu_{$k}_{$key}' type='checkbox' value='1'>
+                            <input data-menu-filter="{$vo.pnode}" name='is_menu' data-node="{$vo.node}" class='check-box menu_{$key}' type='checkbox' value='1'>
                             <!--{/notempty}-->
                             加入菜单节点选择器
                         </label>
@@ -97,10 +101,20 @@
     </div>
 </div>
 
-<!--{if auth("$classuri/save")}-->
 <script>
     $(function () {
 
+        $('.layui-tab ul.layui-tab-title li').on('click', function () {
+            layui.data('node', {key: 'type', value: this.getAttribute('data-type')});
+        });
+
+        (function () {
+            this.selectedType = layui.data('node')['type'] || '';
+            this.selectedItem = $('.layui-tab ul.layui-tab-title li[data-type="' + this.selectedType + '"]');
+            if (this.selectedItem.length < 1) this.selectedItem = $('.layui-tab ul.layui-tab-title li:first');
+            this.selectedItem.trigger('click');
+        }).call({});
+
         syncLoginGroup.call(this);
         $('[data-login-group]').on('click', function () {
             var twoNode = this.getAttribute('data-login-group');
@@ -221,5 +235,4 @@
         }
     });
 </script>
-<!--{/if}-->
 {/block}

+ 0 - 3660
application/admin/view/plugs/icon.html

@@ -1,3660 +0,0 @@
-<!DOCTYPE html>
-<html lang="zh-CN">
-<head>
-    <meta charset="utf-8">
-    <title>{block name="title"}{$title|default=''}{if !empty($title)} · {/if}{:sysconf('site_name')}{/block}</title>
-    <meta name="renderer" content="webkit">
-    <meta name="format-detection" content="telephone=no">
-    <meta name="apple-mobile-web-app-capable" content="yes">
-    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
-    <meta name="apple-mobile-web-app-status-bar-style" content="black">
-    <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1">
-    <link href="__ROOT__/static/plugs/awesome/css/font-awesome.css?v={:date('ymd')}" rel="stylesheet">
-    <link href="__ROOT__/static/plugs/layui/css/layui.css?v={:date('ymd')}" rel="stylesheet">
-
-    <style>
-        ::-webkit-input-placeholder {
-            color: #aaa
-        }
-
-        ::-webkit-scrollbar {
-            width: 3px;
-            height: 3px
-        }
-
-        ::-webkit-scrollbar-track {
-            background: #ccc
-        }
-
-        ::-webkit-scrollbar-thumb {
-            background-color: #666
-        }
-
-        ::selection {
-            background-color: #ec494e;
-            color: #fff
-        }
-
-        ::-moz-selection {
-            background-color: #ec494e;
-            color: #fff
-        }
-
-        :-webkit-autofill {
-            -webkit-box-shadow: 0 0 0 1000px white inset;
-            -webkit-text-fill-color: #333
-        }
-
-        ul li {
-            width: 20%;
-            height: 65px;
-            display: block;
-            float: left;
-            margin-right: -1px;
-            margin-left: -2px;
-            margin-bottom: -2px;
-            cursor: pointer;
-            font-size: 14px;
-            overflow: hidden;
-            text-align: center;
-            padding: 15px 0 10px 0;
-            border: 1px solid #e2e2e2;
-            background-color: #efefef;
-            user-select: none;
-            -ms-user-select: none;
-            -moz-user-select: none;
-            -webkit-user-select: none;
-            transition: all .2s linear;
-            -o-transition: all .2s linear;
-            -moz-transition: all .2s linear;
-            -webkit-transition: all .2s linear
-        }
-
-        ul li:hover {
-            color: #fff;
-            background-color: #563d7c
-        }
-
-        ul li:hover i, ul li:hover div {
-            color: #fff;
-        }
-
-        ul li i {
-            color: #333;
-            display: inline-block;
-            font-size: 30px !important
-        }
-
-        ul li div {
-            color: #333;
-            height: 35px;
-            font-size: 13px;
-            line-height: 35px;
-            white-space: nowrap
-        }
-    </style>
-
-</head>
-<body>
-<ul class="site-doc-icon">
-    <li>
-        <i class="layui-icon layui-icon-rate-half"></i>
-        <div class="icon-title">layui-icon-rate-half</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-rate"></i>
-        <div class="icon-title">layui-icon-rate</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-rate-solid"></i>
-        <div class="icon-title">layui-icon-rate-solid</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-cellphone"></i>
-        <div class="icon-title">layui-icon-cellphone</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-vercode"></i>
-        <div class="icon-title">layui-icon-vercode</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-login-wechat"></i>
-        <div class="icon-title">layui-icon-login-wechat</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-login-qq"></i>
-        <div class="icon-title">layui-icon-login-qq</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-login-weibo"></i>
-        <div class="icon-title">layui-icon-login-weibo</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-password"></i>
-        <div class="icon-title">layui-icon-password</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-username"></i>
-        <div class="icon-title">layui-icon-username</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-refresh-3"></i>
-        <div class="icon-title">layui-icon-refresh-3</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-auz"></i>
-        <div class="icon-title">layui-icon-auz</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-spread-left"></i>
-        <div class="icon-title">layui-icon-spread-left</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-shrink-right"></i>
-        <div class="icon-title">layui-icon-shrink-right</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-snowflake"></i>
-        <div class="icon-title">layui-icon-snowflake</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-tips"></i>
-        <div class="icon-title">layui-icon-tips</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-note"></i>
-        <div class="icon-title">layui-icon-note</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-home"></i>
-        <div class="icon-title">layui-icon-home</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-senior"></i>
-        <div class="icon-title">layui-icon-senior</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-refresh"></i>
-        <div class="icon-title">layui-icon-refresh</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-refresh-1"></i>
-        <div class="icon-title">layui-icon-refresh-1</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-flag"></i>
-        <div class="icon-title">layui-icon-flag</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-theme"></i>
-        <div class="icon-title">layui-icon-theme</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-notice"></i>
-        <div class="icon-title">layui-icon-notice</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-website"></i>
-        <div class="icon-title">layui-icon-website</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-console"></i>
-        <div class="icon-title">layui-icon-console</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-face-surprised"></i>
-        <div class="icon-title">layui-icon-face-surprised</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-set"></i>
-        <div class="icon-title">layui-icon-set</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-template-1"></i>
-        <div class="icon-title">layui-icon-template-1</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-app"></i>
-        <div class="icon-title">layui-icon-app</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-template"></i>
-        <div class="icon-title">layui-icon-template</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-praise"></i>
-        <div class="icon-title">layui-icon-praise</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-tread"></i>
-        <div class="icon-title">layui-icon-tread</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-male"></i>
-        <div class="icon-title">layui-icon-male</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-female"></i>
-        <div class="icon-title">layui-icon-female</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-camera"></i>
-        <div class="icon-title">layui-icon-camera</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-camera-fill"></i>
-        <div class="icon-title">layui-icon-camera-fill</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-more"></i>
-        <div class="icon-title">layui-icon-more</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-more-vertical"></i>
-        <div class="icon-title">layui-icon-more-vertical</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-rmb"></i>
-        <div class="icon-title">layui-icon-rmb</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-dollar"></i>
-        <div class="icon-title">layui-icon-dollar</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-diamond"></i>
-        <div class="icon-title">layui-icon-diamond</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-fire"></i>
-        <div class="icon-title">layui-icon-fire</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-return"></i>
-        <div class="icon-title">layui-icon-return</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-location"></i>
-        <div class="icon-title">layui-icon-location</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-read"></i>
-        <div class="icon-title">layui-icon-read</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-survey"></i>
-        <div class="icon-title">layui-icon-survey</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-face-smile"></i>
-        <div class="icon-title">layui-icon-face-smile</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-face-cry"></i>
-        <div class="icon-title">layui-icon-face-cry</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-cart-simple"></i>
-        <div class="icon-title">layui-icon-cart-simple</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-cart"></i>
-        <div class="icon-title">layui-icon-cart</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-next"></i>
-        <div class="icon-title">layui-icon-next</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-prev"></i>
-        <div class="icon-title">layui-icon-prev</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-upload-drag"></i>
-        <div class="icon-title">layui-icon-upload-drag</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-upload"></i>
-        <div class="icon-title">layui-icon-upload</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-download-circle"></i>
-        <div class="icon-title">layui-icon-download-circle</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-component"></i>
-        <div class="icon-title">layui-icon-component</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-file-b"></i>
-        <div class="icon-title">layui-icon-file-b</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-user"></i>
-        <div class="icon-title">layui-icon-user</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-find-fill"></i>
-        <div class="icon-title">layui-icon-find-fill</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-loading layui-icon layui-anim layui-anim-rotate layui-anim-loop"></i>
-        <div class="icon-title">layui-icon-loading</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-loading-1 layui-icon layui-anim layui-anim-rotate layui-anim-loop"></i>
-        <div class="icon-title">layui-icon-loading-1</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-add-1"></i>
-        <div class="icon-title">layui-icon-add-1</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-play"></i>
-        <div class="icon-title">layui-icon-play</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-pause"></i>
-        <div class="icon-title">layui-icon-pause</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-headset"></i>
-        <div class="icon-title">layui-icon-headset</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-video"></i>
-        <div class="icon-title">layui-icon-video</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-voice"></i>
-        <div class="icon-title">layui-icon-voice</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-speaker"></i>
-        <div class="icon-title">layui-icon-speaker</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-fonts-del"></i>
-        <div class="icon-title">layui-icon-fonts-del</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-fonts-code"></i>
-        <div class="icon-title">layui-icon-fonts-code</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-fonts-html"></i>
-        <div class="icon-title">layui-icon-fonts-html</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-fonts-strong"></i>
-        <div class="icon-title">layui-icon-fonts-strong</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-unlink"></i>
-        <div class="icon-title">layui-icon-unlink</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-picture"></i>
-        <div class="icon-title">layui-icon-picture</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-link"></i>
-        <div class="icon-title">layui-icon-link</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-face-smile-b"></i>
-        <div class="icon-title">layui-icon-face-smile-b</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-align-left"></i>
-        <div class="icon-title">layui-icon-align-left</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-align-right"></i>
-        <div class="icon-title">layui-icon-align-right</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-align-center"></i>
-        <div class="icon-title">layui-icon-align-center</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-fonts-u"></i>
-        <div class="icon-title">layui-icon-fonts-u</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-fonts-i"></i>
-        <div class="icon-title">layui-icon-fonts-i</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-tabs"></i>
-        <div class="icon-title">layui-icon-tabs</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-radio"></i>
-        <div class="icon-title">layui-icon-radio</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-circle"></i>
-        <div class="icon-title">layui-icon-circle</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-edit"></i>
-        <div class="icon-title">layui-icon-edit</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-share"></i>
-        <div class="icon-title">layui-icon-share</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-delete"></i>
-        <div class="icon-title">layui-icon-delete</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-form"></i>
-        <div class="icon-title">layui-icon-form</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-cellphone-fine"></i>
-        <div class="icon-title">layui-icon-cellphone-fine</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-dialogue"></i>
-        <div class="icon-title">layui-icon-dialogue</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-fonts-clear"></i>
-        <div class="icon-title">layui-icon-fonts-clear</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-layer"></i>
-        <div class="icon-title">layui-icon-layer</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-date"></i>
-        <div class="icon-title">layui-icon-date</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-water"></i>
-        <div class="icon-title">layui-icon-water</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-code-circle"></i>
-        <div class="icon-title">layui-icon-code-circle</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-carousel"></i>
-        <div class="icon-title">layui-icon-carousel</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-prev-circle"></i>
-        <div class="icon-title">layui-icon-prev-circle</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-layouts"></i>
-        <div class="icon-title">layui-icon-layouts</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-util"></i>
-        <div class="icon-title">layui-icon-util</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-templeate-1"></i>
-        <div class="icon-title">layui-icon-templeate-1</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-upload-circle"></i>
-        <div class="icon-title">layui-icon-upload-circle</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-tree"></i>
-        <div class="icon-title">layui-icon-tree</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-table"></i>
-        <div class="icon-title">layui-icon-table</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-chart"></i>
-        <div class="icon-title">layui-icon-chart</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-chart-screen"></i>
-        <div class="icon-title">layui-icon-chart-screen</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-engine"></i>
-        <div class="icon-title">layui-icon-engine</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-triangle-d"></i>
-        <div class="icon-title">layui-icon-triangle-d</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-triangle-r"></i>
-        <div class="icon-title">layui-icon-triangle-r</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-file"></i>
-        <div class="icon-title">layui-icon-file</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-set-sm"></i>
-        <div class="icon-title">layui-icon-set-sm</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-add-circle"></i>
-        <div class="icon-title">layui-icon-add-circle</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-404"></i>
-        <div class="icon-title">layui-icon-404</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-about"></i>
-        <div class="icon-title">layui-icon-about</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-up"></i>
-        <div class="icon-title">layui-icon-up</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-down"></i>
-        <div class="icon-title">layui-icon-down</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-left"></i>
-        <div class="icon-title">layui-icon-left</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-right"></i>
-        <div class="icon-title">layui-icon-right</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-circle-dot"></i>
-        <div class="icon-title">layui-icon-circle-dot</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-search"></i>
-        <div class="icon-title">layui-icon-search</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-set-fill"></i>
-        <div class="icon-title">layui-icon-set-fill</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-group"></i>
-        <div class="icon-title">layui-icon-group</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-friends"></i>
-        <div class="icon-title">layui-icon-friends</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-reply-fill"></i>
-        <div class="icon-title">layui-icon-reply-fill</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-menu-fill"></i>
-        <div class="icon-title">layui-icon-menu-fill</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-log"></i>
-        <div class="icon-title">layui-icon-log</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-picture-fine"></i>
-        <div class="icon-title">layui-icon-picture-fine</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-face-smile-fine"></i>
-        <div class="icon-title">layui-icon-face-smile-fine</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-list"></i>
-        <div class="icon-title">layui-icon-list</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-release"></i>
-        <div class="icon-title">layui-icon-release</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-ok"></i>
-        <div class="icon-title">layui-icon-ok</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-help"></i>
-        <div class="icon-title">layui-icon-help</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-chat"></i>
-        <div class="icon-title">layui-icon-chat</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-top"></i>
-        <div class="icon-title">layui-icon-top</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-star"></i>
-        <div class="icon-title">layui-icon-star</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-star-fill"></i>
-        <div class="icon-title">layui-icon-star-fill</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-close-fill"></i>
-        <div class="icon-title">layui-icon-close-fill</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-close"></i>
-        <div class="icon-title">layui-icon-close</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-ok-circle"></i>
-        <div class="icon-title">layui-icon-ok-circle</div>
-    </li>
-    <li>
-        <i class="layui-icon layui-icon-add-circle-fine"></i>
-        <div class="icon-title">layui-icon-add-circle-fine</div>
-    </li>
-</ul>
-<ul>
-    <li>
-        <i class="fa fa-address-book"></i>
-        <div class="icon-title">fa-address-book</div>
-    </li>
-    <li>
-        <i class="fa fa-address-book-o"></i>
-        <div class="icon-title">fa-address-book-o</div>
-    </li>
-    <li>
-        <i class="fa fa-address-card"></i>
-        <div class="icon-title">fa-address-card</div>
-    </li>
-    <li>
-        <i class="fa fa-address-card-o"></i>
-        <div class="icon-title">fa-address-card-o</div>
-    </li>
-    <li>
-        <i class="fa fa-adjust"></i>
-        <div class="icon-title">fa-adjust</div>
-    </li>
-    <li>
-        <i class="fa fa-american-sign-language-interpreting"></i>
-        <div class="icon-title">fa-american-sign-language-interpreting</div>
-    </li>
-    <li>
-        <i class="fa fa-anchor"></i>
-        <div class="icon-title">fa-anchor</div>
-    </li>
-    <li>
-        <i class="fa fa-archive"></i>
-        <div class="icon-title">fa-archive</div>
-    </li>
-    <li>
-        <i class="fa fa-area-chart"></i>
-        <div class="icon-title">fa-area-chart</div>
-    </li>
-    <li>
-        <i class="fa fa-arrows"></i>
-        <div class="icon-title">fa-arrows</div>
-    </li>
-    <li>
-        <i class="fa fa-arrows-h"></i>
-        <div class="icon-title">fa-arrows-h</div>
-    </li>
-    <li>
-        <i class="fa fa-arrows-v"></i>
-        <div class="icon-title">fa-arrows-v</div>
-    </li>
-    <li>
-        <i class="fa fa-asl-interpreting"></i>
-        <div class="icon-title">fa-asl-interpreting</div>
-    </li>
-    <li>
-        <i class="fa fa-assistive-listening-systems"></i>
-        <div class="icon-title">fa-assistive-listening-systems</div>
-    </li>
-    <li>
-        <i class="fa fa-asterisk"></i>
-        <div class="icon-title">fa-asterisk</div>
-    </li>
-    <li>
-        <i class="fa fa-at"></i>
-        <div class="icon-title">fa-at</div>
-    </li>
-    <li>
-        <i class="fa fa-audio-description"></i>
-        <div class="icon-title">fa-audio-description</div>
-    </li>
-    <li>
-        <i class="fa fa-automobile"></i>
-        <div class="icon-title">fa-automobile</div>
-    </li>
-    <li>
-        <i class="fa fa-balance-scale"></i>
-        <div class="icon-title">fa-balance-scale</div>
-    </li>
-    <li>
-        <i class="fa fa-ban"></i>
-        <div class="icon-title">fa-ban</div>
-    </li>
-    <li>
-        <i class="fa fa-bank"></i>
-        <div class="icon-title">fa-bank</div>
-    </li>
-    <li>
-        <i class="fa fa-bar-chart"></i>
-        <div class="icon-title">fa-bar-chart</div>
-    </li>
-    <li>
-        <i class="fa fa-bar-chart-o"></i>
-        <div class="icon-title">fa-bar-chart-o</div>
-    </li>
-    <li>
-        <i class="fa fa-barcode"></i>
-        <div class="icon-title">fa-barcode</div>
-    </li>
-    <li>
-        <i class="fa fa-bars"></i>
-        <div class="icon-title">fa-bars</div>
-    </li>
-    <li>
-        <i class="fa fa-bath"></i>
-        <div class="icon-title">fa-bath</div>
-    </li>
-    <li>
-        <i class="fa fa-bathtub"></i>
-        <div class="icon-title">fa-bathtub</div>
-    </li>
-    <li>
-        <i class="fa fa-battery"></i>
-        <div class="icon-title">fa-battery</div>
-    </li>
-    <li>
-        <i class="fa fa-battery-0"></i>
-        <div class="icon-title">fa-battery-0</div>
-    </li>
-    <li>
-        <i class="fa fa-battery-1"></i>
-        <div class="icon-title">fa-battery-1</div>
-    </li>
-    <li>
-        <i class="fa fa-battery-2"></i>
-        <div class="icon-title">fa-battery-2</div>
-    </li>
-    <li>
-        <i class="fa fa-battery-3"></i>
-        <div class="icon-title">fa-battery-3</div>
-    </li>
-    <li>
-        <i class="fa fa-battery-4"></i>
-        <div class="icon-title">fa-battery-4</div>
-    </li>
-    <li>
-        <i class="fa fa-battery-empty"></i>
-        <div class="icon-title">fa-battery-empty</div>
-    </li>
-    <li>
-        <i class="fa fa-battery-full"></i>
-        <div class="icon-title">fa-battery-full</div>
-    </li>
-    <li>
-        <i class="fa fa-battery-half"></i>
-        <div class="icon-title">fa-battery-half</div>
-    </li>
-    <li>
-        <i class="fa fa-battery-quarter"></i>
-        <div class="icon-title">fa-battery-quarter</div>
-    </li>
-    <li>
-        <i class="fa fa-battery-three-quarters"></i>
-        <div class="icon-title">fa-battery-three-quarters</div>
-    </li>
-    <li>
-        <i class="fa fa-bed"></i>
-        <div class="icon-title">fa-bed</div>
-    </li>
-    <li>
-        <i class="fa fa-beer"></i>
-        <div class="icon-title">fa-beer</div>
-    </li>
-    <li>
-        <i class="fa fa-bell"></i>
-        <div class="icon-title">fa-bell</div>
-    </li>
-    <li>
-        <i class="fa fa-bell-o"></i>
-        <div class="icon-title">fa-bell-o</div>
-    </li>
-    <li>
-        <i class="fa fa-bell-slash"></i>
-        <div class="icon-title">fa-bell-slash</div>
-    </li>
-    <li>
-        <i class="fa fa-bell-slash-o"></i>
-        <div class="icon-title">fa-bell-slash-o</div>
-    </li>
-    <li>
-        <i class="fa fa-bicycle"></i>
-        <div class="icon-title">fa-bicycle</div>
-    </li>
-    <li>
-        <i class="fa fa-binoculars"></i>
-        <div class="icon-title">fa-binoculars</div>
-    </li>
-    <li>
-        <i class="fa fa-birthday-cake"></i>
-        <div class="icon-title">fa-birthday-cake</div>
-    </li>
-    <li>
-        <i class="fa fa-blind"></i>
-        <div class="icon-title">fa-blind</div>
-    </li>
-    <li>
-        <i class="fa fa-bluetooth"></i>
-        <div class="icon-title">fa-bluetooth</div>
-    </li>
-    <li>
-        <i class="fa fa-bluetooth-b"></i>
-        <div class="icon-title">fa-bluetooth-b</div>
-    </li>
-    <li>
-        <i class="fa fa-bolt"></i>
-        <div class="icon-title">fa-bolt</div>
-    </li>
-    <li>
-        <i class="fa fa-bomb"></i>
-        <div class="icon-title">fa-bomb</div>
-    </li>
-    <li>
-        <i class="fa fa-book"></i>
-        <div class="icon-title">fa-book</div>
-    </li>
-    <li>
-        <i class="fa fa-bookmark"></i>
-        <div class="icon-title">fa-bookmark</div>
-    </li>
-    <li>
-        <i class="fa fa-bookmark-o"></i>
-        <div class="icon-title">fa-bookmark-o</div>
-    </li>
-    <li>
-        <i class="fa fa-braille"></i>
-        <div class="icon-title">fa-braille</div>
-    </li>
-    <li>
-        <i class="fa fa-briefcase"></i>
-        <div class="icon-title">fa-briefcase</div>
-    </li>
-    <li>
-        <i class="fa fa-bug"></i>
-        <div class="icon-title">fa-bug</div>
-    </li>
-    <li>
-        <i class="fa fa-building"></i>
-        <div class="icon-title">fa-building</div>
-    </li>
-    <li>
-        <i class="fa fa-building-o"></i>
-        <div class="icon-title">fa-building-o</div>
-    </li>
-    <li>
-        <i class="fa fa-bullhorn"></i>
-        <div class="icon-title">fa-bullhorn</div>
-    </li>
-    <li>
-        <i class="fa fa-bullseye"></i>
-        <div class="icon-title">fa-bullseye</div>
-    </li>
-    <li>
-        <i class="fa fa-bus"></i>
-        <div class="icon-title">fa-bus</div>
-    </li>
-    <li>
-        <i class="fa fa-cab"></i>
-        <div class="icon-title">fa-cab</div>
-    </li>
-    <li>
-        <i class="fa fa-calculator"></i>
-        <div class="icon-title">fa-calculator</div>
-    </li>
-    <li>
-        <i class="fa fa-calendar"></i>
-        <div class="icon-title">fa-calendar</div>
-    </li>
-    <li>
-        <i class="fa fa-calendar-check-o"></i>
-        <div class="icon-title">fa-calendar-check-o</div>
-    </li>
-    <li>
-        <i class="fa fa-calendar-minus-o"></i>
-        <div class="icon-title">fa-calendar-minus-o</div>
-    </li>
-    <li>
-        <i class="fa fa-calendar-o"></i>
-        <div class="icon-title">fa-calendar-o</div>
-    </li>
-    <li>
-        <i class="fa fa-calendar-plus-o"></i>
-        <div class="icon-title">fa-calendar-plus-o</div>
-    </li>
-    <li>
-        <i class="fa fa-calendar-times-o"></i>
-        <div class="icon-title">fa-calendar-times-o</div>
-    </li>
-    <li>
-        <i class="fa fa-camera"></i>
-        <div class="icon-title">fa-camera</div>
-    </li>
-    <li>
-        <i class="fa fa-camera-retro"></i>
-        <div class="icon-title">fa-camera-retro</div>
-    </li>
-    <li>
-        <i class="fa fa-car"></i>
-        <div class="icon-title">fa-car</div>
-    </li>
-    <li>
-        <i class="fa fa-caret-square-o-down"></i>
-        <div class="icon-title">fa-caret-square-o-down</div>
-    </li>
-    <li>
-        <i class="fa fa-caret-square-o-left"></i>
-        <div class="icon-title">fa-caret-square-o-left</div>
-    </li>
-    <li>
-        <i class="fa fa-caret-square-o-right"></i>
-        <div class="icon-title">fa-caret-square-o-right</div>
-    </li>
-    <li>
-        <i class="fa fa-caret-square-o-up"></i>
-        <div class="icon-title">fa-caret-square-o-up</div>
-    </li>
-    <li>
-        <i class="fa fa-cart-arrow-down"></i>
-        <div class="icon-title">fa-cart-arrow-down</div>
-    </li>
-    <li>
-        <i class="fa fa-cart-plus"></i>
-        <div class="icon-title">fa-cart-plus</div>
-    </li>
-    <li>
-        <i class="fa fa-cc"></i>
-        <div class="icon-title">fa-cc</div>
-    </li>
-    <li>
-        <i class="fa fa-certificate"></i>
-        <div class="icon-title">fa-certificate</div>
-    </li>
-    <li>
-        <i class="fa fa-check"></i>
-        <div class="icon-title">fa-check</div>
-    </li>
-    <li>
-        <i class="fa fa-check-circle"></i>
-        <div class="icon-title">fa-check-circle</div>
-    </li>
-    <li>
-        <i class="fa fa-check-circle-o"></i>
-        <div class="icon-title">fa-check-circle-o</div>
-    </li>
-    <li>
-        <i class="fa fa-check-square"></i>
-        <div class="icon-title">fa-check-square</div>
-    </li>
-    <li>
-        <i class="fa fa-check-square-o"></i>
-        <div class="icon-title">fa-check-square-o</div>
-    </li>
-    <li>
-        <i class="fa fa-child"></i>
-        <div class="icon-title">fa-child</div>
-    </li>
-    <li>
-        <i class="fa fa-circle"></i>
-        <div class="icon-title">fa-circle</div>
-    </li>
-    <li>
-        <i class="fa fa-circle-o"></i>
-        <div class="icon-title">fa-circle-o</div>
-    </li>
-    <li>
-        <i class="fa fa-circle-o-notch"></i>
-        <div class="icon-title">fa-circle-o-notch</div>
-    </li>
-    <li>
-        <i class="fa fa-circle-thin"></i>
-        <div class="icon-title">fa-circle-thin</div>
-    </li>
-    <li>
-        <i class="fa fa-clock-o"></i>
-        <div class="icon-title">fa-clock-o</div>
-    </li>
-    <li>
-        <i class="fa fa-clone"></i>
-        <div class="icon-title">fa-clone</div>
-    </li>
-    <li>
-        <i class="fa fa-close"></i>
-        <div class="icon-title">fa-close</div>
-    </li>
-    <li>
-        <i class="fa fa-cloud"></i>
-        <div class="icon-title">fa-cloud</div>
-    </li>
-    <li>
-        <i class="fa fa-cloud-download"></i>
-        <div class="icon-title">fa-cloud-download</div>
-    </li>
-    <li>
-        <i class="fa fa-cloud-upload"></i>
-        <div class="icon-title">fa-cloud-upload</div>
-    </li>
-    <li>
-        <i class="fa fa-code"></i>
-        <div class="icon-title">fa-code</div>
-    </li>
-    <li>
-        <i class="fa fa-code-fork"></i>
-        <div class="icon-title">fa-code-fork</div>
-    </li>
-    <li>
-        <i class="fa fa-coffee"></i>
-        <div class="icon-title">fa-coffee</div>
-    </li>
-    <li>
-        <i class="fa fa-cog"></i>
-        <div class="icon-title">fa-cog</div>
-    </li>
-    <li>
-        <i class="fa fa-cogs"></i>
-        <div class="icon-title">fa-cogs</div>
-    </li>
-    <li>
-        <i class="fa fa-comment"></i>
-        <div class="icon-title">fa-comment</div>
-    </li>
-    <li>
-        <i class="fa fa-comment-o"></i>
-        <div class="icon-title">fa-comment-o</div>
-    </li>
-    <li>
-        <i class="fa fa-commenting"></i>
-        <div class="icon-title">fa-commenting</div>
-    </li>
-    <li>
-        <i class="fa fa-commenting-o"></i>
-        <div class="icon-title">fa-commenting-o</div>
-    </li>
-    <li>
-        <i class="fa fa-comments"></i>
-        <div class="icon-title">fa-comments</div>
-    </li>
-    <li>
-        <i class="fa fa-comments-o"></i>
-        <div class="icon-title">fa-comments-o</div>
-    </li>
-    <li>
-        <i class="fa fa-compass"></i>
-        <div class="icon-title">fa-compass</div>
-    </li>
-    <li>
-        <i class="fa fa-copyright"></i>
-        <div class="icon-title">fa-copyright</div>
-    </li>
-    <li>
-        <i class="fa fa-creative-commons"></i>
-        <div class="icon-title">fa-creative-commons</div>
-    </li>
-    <li>
-        <i class="fa fa-credit-card"></i>
-        <div class="icon-title">fa-credit-card</div>
-    </li>
-    <li><i class="fa fa-credit-card-alt"></i>
-        <div class="icon-title">fa-credit-card-alt</div>
-    </li>
-    <li><i class="fa fa-crop"></i>
-        <div class="icon-title">fa-crop</div>
-    </li>
-    <li><i class="fa fa-crosshairs"></i>
-        <div class="icon-title">fa-crosshairs</div>
-    </li>
-    <li><i class="fa fa-cube"></i>
-        <div class="icon-title">fa-cube</div>
-    </li>
-    <li><i class="fa fa-cubes"></i>
-        <div class="icon-title">fa-cubes</div>
-    </li>
-    <li><i class="fa fa-cutlery"></i>
-        <div class="icon-title">fa-cutlery</div>
-    </li>
-    <li><i class="fa fa-dashboard"></i>
-        <div class="icon-title">fa-dashboard</div>
-    </li>
-    <li><i class="fa fa-database"></i>
-        <div class="icon-title">fa-database</div>
-    </li>
-    <li><i class="fa fa-deaf"></i>
-        <div class="icon-title">fa-deaf</div>
-    </li>
-    <li><i class="fa fa-deafness"></i>
-        <div class="icon-title">fa-deafness</div>
-    </li>
-    <li><i class="fa fa-desktop"></i>
-        <div class="icon-title">fa-desktop</div>
-    </li>
-    <li><i class="fa fa-diamond"></i>
-        <div class="icon-title">fa-diamond</div>
-    </li>
-    <li><i class="fa fa-dot-circle-o"></i>
-        <div class="icon-title">fa-dot-circle-o</div>
-    </li>
-    <li><i class="fa fa-download"></i>
-        <div class="icon-title">fa-download</div>
-    </li>
-    <li><i class="fa fa-drivers-license"></i>
-        <div class="icon-title">fa-drivers-license</div>
-    </li>
-    <li><i class="fa fa-drivers-license-o"></i>
-        <div class="icon-title">fa-drivers-license-o</div>
-    </li>
-    <li><i class="fa fa-edit"></i>
-        <div class="icon-title">fa-edit</div>
-    </li>
-    <li><i class="fa fa-ellipsis-h"></i>
-        <div class="icon-title">fa-ellipsis-h</div>
-    </li>
-    <li><i class="fa fa-ellipsis-v"></i>
-        <div class="icon-title">fa-ellipsis-v</div>
-    </li>
-    <li><i class="fa fa-envelope"></i>
-        <div class="icon-title">fa-envelope</div>
-    </li>
-    <li><i class="fa fa-envelope-o"></i>
-        <div class="icon-title">fa-envelope-o</div>
-    </li>
-    <li><i class="fa fa-envelope-open"></i>
-        <div class="icon-title">fa-envelope-open</div>
-    </li>
-    <li><i class="fa fa-envelope-open-o"></i>
-        <div class="icon-title">fa-envelope-open-o</div>
-    </li>
-    <li><i class="fa fa-envelope-square"></i>
-        <div class="icon-title">fa-envelope-square</div>
-    </li>
-    <li><i class="fa fa-eraser"></i>
-        <div class="icon-title">fa-eraser</div>
-    </li>
-    <li><i class="fa fa-exchange"></i>
-        <div class="icon-title">fa-exchange</div>
-    </li>
-    <li><i class="fa fa-exclamation"></i>
-        <div class="icon-title">fa-exclamation</div>
-    </li>
-    <li><i class="fa fa-exclamation-circle"></i>
-        <div class="icon-title">fa-exclamation-circle</div>
-    </li>
-    <li><i class="fa fa-exclamation-triangle"></i>
-        <div class="icon-title">fa-exclamation-triangle</div>
-    </li>
-    <li><i class="fa fa-external-link"></i>
-        <div class="icon-title">fa-external-link</div>
-    </li>
-    <li><i class="fa fa-external-link-square"></i>
-        <div class="icon-title">fa-external-link-square</div>
-    </li>
-    <li><i class="fa fa-eye"></i>
-        <div class="icon-title">fa-eye</div>
-    </li>
-    <li><i class="fa fa-eye-slash"></i>
-        <div class="icon-title">fa-eye-slash</div>
-    </li>
-    <li><i class="fa fa-eyedropper"></i>
-        <div class="icon-title">fa-eyedropper</div>
-    </li>
-    <li><i class="fa fa-fax"></i>
-        <div class="icon-title">fa-fax</div>
-    </li>
-    <li><i class="fa fa-feed"></i>
-        <div class="icon-title">fa-feed</div>
-    </li>
-    <li><i class="fa fa-female"></i>
-        <div class="icon-title">fa-female</div>
-    </li>
-    <li><i class="fa fa-fighter-jet"></i>
-        <div class="icon-title">fa-fighter-jet</div>
-    </li>
-    <li><i class="fa fa-file-archive-o"></i>
-        <div class="icon-title">fa-file-archive-o</div>
-    </li>
-    <li><i class="fa fa-file-audio-o"></i>
-        <div class="icon-title">fa-file-audio-o</div>
-    </li>
-    <li><i class="fa fa-file-code-o"></i>
-        <div class="icon-title">fa-file-code-o</div>
-    </li>
-    <li><i class="fa fa-file-excel-o"></i>
-        <div class="icon-title">fa-file-excel-o</div>
-    </li>
-    <li><i class="fa fa-file-image-o"></i>
-        <div class="icon-title">fa-file-image-o</div>
-    </li>
-    <li><i class="fa fa-file-movie-o"></i>
-        <div class="icon-title">fa-file-movie-o</div>
-    </li>
-    <li><i class="fa fa-file-pdf-o"></i>
-        <div class="icon-title">fa-file-pdf-o</div>
-    </li>
-    <li><i class="fa fa-file-photo-o"></i>
-        <div class="icon-title">fa-file-photo-o</div>
-    </li>
-    <li><i class="fa fa-file-picture-o"></i>
-        <div class="icon-title">fa-file-picture-o</div>
-    </li>
-    <li><i class="fa fa-file-powerpoint-o"></i>
-        <div class="icon-title">fa-file-powerpoint-o</div>
-    </li>
-    <li><i class="fa fa-file-sound-o"></i>
-        <div class="icon-title">fa-file-sound-o</div>
-    </li>
-    <li><i class="fa fa-file-video-o"></i>
-        <div class="icon-title">fa-file-video-o</div>
-    </li>
-    <li><i class="fa fa-file-word-o"></i>
-        <div class="icon-title">fa-file-word-o</div>
-    </li>
-    <li><i class="fa fa-file-zip-o"></i>
-        <div class="icon-title">fa-file-zip-o</div>
-    </li>
-    <li><i class="fa fa-film"></i>
-        <div class="icon-title">fa-film</div>
-    </li>
-    <li><i class="fa fa-filter"></i>
-        <div class="icon-title">fa-filter</div>
-    </li>
-    <li><i class="fa fa-fire"></i>
-        <div class="icon-title">fa-fire</div>
-    </li>
-    <li><i class="fa fa-fire-extinguisher"></i>
-        <div class="icon-title">fa-fire-extinguisher</div>
-    </li>
-    <li><i class="fa fa-flag"></i>
-        <div class="icon-title">fa-flag</div>
-    </li>
-    <li><i class="fa fa-flag-checkered"></i>
-        <div class="icon-title">fa-flag-checkered</div>
-    </li>
-    <li><i class="fa fa-flag-o"></i>
-        <div class="icon-title">fa-flag-o</div>
-    </li>
-    <li><i class="fa fa-flash"></i>
-        <div class="icon-title">fa-flash</div>
-    </li>
-    <li><i class="fa fa-flask"></i>
-        <div class="icon-title">fa-flask</div>
-    </li>
-    <li><i class="fa fa-folder"></i>
-        <div class="icon-title">fa-folder</div>
-    </li>
-    <li><i class="fa fa-folder-o"></i>
-        <div class="icon-title">fa-folder-o</div>
-    </li>
-    <li><i class="fa fa-folder-open"></i>
-        <div class="icon-title">fa-folder-open</div>
-    </li>
-    <li><i class="fa fa-folder-open-o"></i>
-        <div class="icon-title">fa-folder-open-o</div>
-    </li>
-    <li><i class="fa fa-frown-o"></i>
-        <div class="icon-title">fa-frown-o</div>
-    </li>
-    <li><i class="fa fa-futbol-o"></i>
-        <div class="icon-title">fa-futbol-o</div>
-    </li>
-    <li><i class="fa fa-gamepad"></i>
-        <div class="icon-title">fa-gamepad</div>
-    </li>
-    <li><i class="fa fa-gavel"></i>
-        <div class="icon-title">fa-gavel</div>
-    </li>
-    <li><i class="fa fa-gear"></i>
-        <div class="icon-title">fa-gear</div>
-    </li>
-    <li><i class="fa fa-gears"></i>
-        <div class="icon-title">fa-gears</div>
-    </li>
-    <li><i class="fa fa-gift"></i>
-        <div class="icon-title">fa-gift</div>
-    </li>
-    <li><i class="fa fa-glass"></i>
-        <div class="icon-title">fa-glass</div>
-    </li>
-    <li><i class="fa fa-globe"></i>
-        <div class="icon-title">fa-globe</div>
-    </li>
-    <li><i class="fa fa-graduation-cap"></i>
-        <div class="icon-title">fa-graduation-cap</div>
-    </li>
-    <li><i class="fa fa-group"></i>
-        <div class="icon-title">fa-group</div>
-    </li>
-    <li><i class="fa fa-hand-grab-o"></i>
-        <div class="icon-title">fa-hand-grab-o</div>
-    </li>
-    <li><i class="fa fa-hand-lizard-o"></i>
-        <div class="icon-title">fa-hand-lizard-o</div>
-    </li>
-    <li><i class="fa fa-hand-paper-o"></i>
-        <div class="icon-title">fa-hand-paper-o</div>
-    </li>
-    <li><i class="fa fa-hand-peace-o"></i>
-        <div class="icon-title">fa-hand-peace-o</div>
-    </li>
-    <li><i class="fa fa-hand-pointer-o"></i>
-        <div class="icon-title">fa-hand-pointer-o</div>
-    </li>
-    <li><i class="fa fa-hand-rock-o"></i>
-        <div class="icon-title">fa-hand-rock-o</div>
-    </li>
-    <li><i class="fa fa-hand-scissors-o"></i>
-        <div class="icon-title">fa-hand-scissors-o</div>
-    </li>
-    <li><i class="fa fa-hand-spock-o"></i>
-        <div class="icon-title">fa-hand-spock-o</div>
-    </li>
-    <li><i class="fa fa-hand-stop-o"></i>
-        <div class="icon-title">fa-hand-stop-o</div>
-    </li>
-    <li><i class="fa fa-handshake-o"></i>
-        <div class="icon-title">fa-handshake-o</div>
-    </li>
-    <li><i class="fa fa-hard-of-hearing"></i>
-        <div class="icon-title">fa-hard-of-hearing</div>
-    </li>
-    <li><i class="fa fa-hashtag"></i>
-        <div class="icon-title">fa-hashtag</div>
-    </li>
-    <li><i class="fa fa-hdd-o"></i>
-        <div class="icon-title">fa-hdd-o</div>
-    </li>
-    <li><i class="fa fa-headphones"></i>
-        <div class="icon-title">fa-headphones</div>
-    </li>
-    <li><i class="fa fa-heart"></i>
-        <div class="icon-title">fa-heart</div>
-    </li>
-    <li><i class="fa fa-heart-o"></i>
-        <div class="icon-title">fa-heart-o</div>
-    </li>
-    <li><i class="fa fa-heartbeat"></i>
-        <div class="icon-title">fa-heartbeat</div>
-    </li>
-    <li><i class="fa fa-history"></i>
-        <div class="icon-title">fa-history</div>
-    </li>
-    <li><i class="fa fa-home"></i>
-        <div class="icon-title">fa-home</div>
-    </li>
-    <li><i class="fa fa-hotel"></i>
-        <div class="icon-title">fa-hotel</div>
-    </li>
-    <li><i class="fa fa-hourglass"></i>
-        <div class="icon-title">fa-hourglass</div>
-    </li>
-    <li><i class="fa fa-hourglass-1"></i>
-        <div class="icon-title">fa-hourglass-1</div>
-    </li>
-    <li><i class="fa fa-hourglass-2"></i>
-        <div class="icon-title">fa-hourglass-2</div>
-    </li>
-    <li><i class="fa fa-hourglass-3"></i>
-        <div class="icon-title">fa-hourglass-3</div>
-    </li>
-    <li><i class="fa fa-hourglass-end"></i>
-        <div class="icon-title">fa-hourglass-end</div>
-    </li>
-    <li><i class="fa fa-hourglass-half"></i>
-        <div class="icon-title">fa-hourglass-half</div>
-    </li>
-    <li><i class="fa fa-hourglass-o"></i>
-        <div class="icon-title">fa-hourglass-o</div>
-    </li>
-    <li><i class="fa fa-hourglass-start"></i>
-        <div class="icon-title">fa-hourglass-start</div>
-    </li>
-    <li><i class="fa fa-i-cursor"></i>
-        <div class="icon-title">fa-i-cursor</div>
-    </li>
-    <li><i class="fa fa-id-badge"></i>
-        <div class="icon-title">fa-id-badge</div>
-    </li>
-    <li><i class="fa fa-id-card"></i>
-        <div class="icon-title">fa-id-card</div>
-    </li>
-    <li><i class="fa fa-id-card-o"></i>
-        <div class="icon-title">fa-id-card-o</div>
-    </li>
-    <li><i class="fa fa-image"></i>
-        <div class="icon-title">fa-image</div>
-    </li>
-    <li><i class="fa fa-inbox"></i>
-        <div class="icon-title">fa-inbox</div>
-    </li>
-    <li><i class="fa fa-industry"></i>
-        <div class="icon-title">fa-industry</div>
-    </li>
-    <li><i class="fa fa-info"></i>
-        <div class="icon-title">fa-info</div>
-    </li>
-    <li><i class="fa fa-info-circle"></i>
-        <div class="icon-title">fa-info-circle</div>
-    </li>
-    <li><i class="fa fa-institution"></i>
-        <div class="icon-title">fa-institution</div>
-    </li>
-    <li><i class="fa fa-key"></i>
-        <div class="icon-title">fa-key</div>
-    </li>
-    <li><i class="fa fa-keyboard-o"></i>
-        <div class="icon-title">fa-keyboard-o</div>
-    </li>
-    <li><i class="fa fa-language"></i>
-        <div class="icon-title">fa-language</div>
-    </li>
-    <li><i class="fa fa-laptop"></i>
-        <div class="icon-title">fa-laptop</div>
-    </li>
-    <li><i class="fa fa-leaf"></i>
-        <div class="icon-title">fa-leaf</div>
-    </li>
-    <li><i class="fa fa-legal"></i>
-        <div class="icon-title">fa-legal</div>
-    </li>
-    <li><i class="fa fa-lemon-o"></i>
-        <div class="icon-title">fa-lemon-o</div>
-    </li>
-    <li><i class="fa fa-level-down"></i>
-        <div class="icon-title">fa-level-down</div>
-    </li>
-    <li><i class="fa fa-level-up"></i>
-        <div class="icon-title">fa-level-up</div>
-    </li>
-    <li><i class="fa fa-life-bouy"></i>
-        <div class="icon-title">fa-life-bouy</div>
-    </li>
-    <li><i class="fa fa-life-buoy"></i>
-        <div class="icon-title">fa-life-buoy</div>
-    </li>
-    <li><i class="fa fa-life-ring"></i>
-        <div class="icon-title">fa-life-ring</div>
-    </li>
-    <li><i class="fa fa-life-saver"></i>
-        <div class="icon-title">fa-life-saver</div>
-    </li>
-    <li><i class="fa fa-lightbulb-o"></i>
-        <div class="icon-title">fa-lightbulb-o</div>
-    </li>
-    <li><i class="fa fa-line-chart"></i>
-        <div class="icon-title">fa-line-chart</div>
-    </li>
-    <li><i class="fa fa-location-arrow"></i>
-        <div class="icon-title">fa-location-arrow</div>
-    </li>
-    <li><i class="fa fa-lock"></i>
-        <div class="icon-title">fa-lock</div>
-    </li>
-    <li><i class="fa fa-low-vision"></i>
-        <div class="icon-title">fa-low-vision</div>
-    </li>
-    <li><i class="fa fa-magic"></i>
-        <div class="icon-title">fa-magic</div>
-    </li>
-    <li><i class="fa fa-magnet"></i>
-        <div class="icon-title">fa-magnet</div>
-    </li>
-    <li><i class="fa fa-mail-forward"></i>
-        <div class="icon-title">fa-mail-forward</div>
-    </li>
-    <li><i class="fa fa-mail-reply"></i>
-        <div class="icon-title">fa-mail-reply</div>
-    </li>
-    <li><i class="fa fa-mail-reply-all"></i>
-        <div class="icon-title">fa-mail-reply-all</div>
-    </li>
-    <li><i class="fa fa-male"></i>
-        <div class="icon-title">fa-male</div>
-    </li>
-    <li><i class="fa fa-map"></i>
-        <div class="icon-title">fa-map</div>
-    </li>
-    <li><i class="fa fa-map-marker"></i>
-        <div class="icon-title">fa-map-marker</div>
-    </li>
-    <li><i class="fa fa-map-o"></i>
-        <div class="icon-title">fa-map-o</div>
-    </li>
-    <li><i class="fa fa-map-pin"></i>
-        <div class="icon-title">fa-map-pin</div>
-    </li>
-    <li><i class="fa fa-map-signs"></i>
-        <div class="icon-title">fa-map-signs</div>
-    </li>
-    <li><i class="fa fa-meh-o"></i>
-        <div class="icon-title">fa-meh-o</div>
-    </li>
-    <li><i class="fa fa-microchip"></i>
-        <div class="icon-title">fa-microchip</div>
-    </li>
-    <li><i class="fa fa-microphone"></i>
-        <div class="icon-title">fa-microphone</div>
-    </li>
-    <li><i class="fa fa-microphone-slash"></i>
-        <div class="icon-title">fa-microphone-slash</div>
-    </li>
-    <li><i class="fa fa-minus"></i>
-        <div class="icon-title">fa-minus</div>
-    </li>
-    <li><i class="fa fa-minus-circle"></i>
-        <div class="icon-title">fa-minus-circle</div>
-    </li>
-    <li><i class="fa fa-minus-square"></i>
-        <div class="icon-title">fa-minus-square</div>
-    </li>
-    <li><i class="fa fa-minus-square-o"></i>
-        <div class="icon-title">fa-minus-square-o</div>
-    </li>
-    <li><i class="fa fa-mobile"></i>
-        <div class="icon-title">fa-mobile</div>
-    </li>
-    <li><i class="fa fa-mobile-phone"></i>
-        <div class="icon-title">fa-mobile-phone</div>
-    </li>
-    <li><i class="fa fa-money"></i>
-        <div class="icon-title">fa-money</div>
-    </li>
-    <li><i class="fa fa-moon-o"></i>
-        <div class="icon-title">fa-moon-o</div>
-    </li>
-    <li><i class="fa fa-mortar-board"></i>
-        <div class="icon-title">fa-mortar-board</div>
-    </li>
-    <li><i class="fa fa-motorcycle"></i>
-        <div class="icon-title">fa-motorcycle</div>
-    </li>
-    <li><i class="fa fa-mouse-pointer"></i>
-        <div class="icon-title">fa-mouse-pointer</div>
-    </li>
-    <li><i class="fa fa-music"></i>
-        <div class="icon-title">fa-music</div>
-    </li>
-    <li><i class="fa fa-navicon"></i>
-        <div class="icon-title">fa-navicon</div>
-    </li>
-    <li><i class="fa fa-newspaper-o"></i>
-        <div class="icon-title">fa-newspaper-o</div>
-    </li>
-    <li><i class="fa fa-object-group"></i>
-        <div class="icon-title">fa-object-group</div>
-    </li>
-    <li><i class="fa fa-object-ungroup"></i>
-        <div class="icon-title">fa-object-ungroup</div>
-    </li>
-    <li><i class="fa fa-paint-brush"></i>
-        <div class="icon-title">fa-paint-brush</div>
-    </li>
-    <li><i class="fa fa-paper-plane"></i>
-        <div class="icon-title">fa-paper-plane</div>
-    </li>
-    <li><i class="fa fa-paper-plane-o"></i>
-        <div class="icon-title">fa-paper-plane-o</div>
-    </li>
-    <li><i class="fa fa-paw"></i>
-        <div class="icon-title">fa-paw</div>
-    </li>
-    <li><i class="fa fa-pencil"></i>
-        <div class="icon-title">fa-pencil</div>
-    </li>
-    <li><i class="fa fa-pencil-square"></i>
-        <div class="icon-title">fa-pencil-square</div>
-    </li>
-    <li><i class="fa fa-pencil-square-o"></i>
-        <div class="icon-title">fa-pencil-square-o</div>
-    </li>
-    <li><i class="fa fa-percent"></i>
-        <div class="icon-title">fa-percent</div>
-    </li>
-    <li><i class="fa fa-phone"></i>
-        <div class="icon-title">fa-phone</div>
-    </li>
-    <li><i class="fa fa-phone-square"></i>
-        <div class="icon-title">fa-phone-square</div>
-    </li>
-    <li><i class="fa fa-photo"></i>
-        <div class="icon-title">fa-photo</div>
-    </li>
-    <li><i class="fa fa-picture-o"></i>
-        <div class="icon-title">fa-picture-o</div>
-    </li>
-    <li><i class="fa fa-pie-chart"></i>
-        <div class="icon-title">fa-pie-chart</div>
-    </li>
-    <li><i class="fa fa-plane"></i>
-        <div class="icon-title">fa-plane</div>
-    </li>
-    <li><i class="fa fa-plug"></i>
-        <div class="icon-title">fa-plug</div>
-    </li>
-    <li><i class="fa fa-plus"></i>
-        <div class="icon-title">fa-plus</div>
-    </li>
-    <li><i class="fa fa-plus-circle"></i>
-        <div class="icon-title">fa-plus-circle</div>
-    </li>
-    <li><i class="fa fa-plus-square"></i>
-        <div class="icon-title">fa-plus-square</div>
-    </li>
-    <li><i class="fa fa-plus-square-o"></i>
-        <div class="icon-title">fa-plus-square-o</div>
-    </li>
-    <li><i class="fa fa-podcast"></i>
-        <div class="icon-title">fa-podcast</div>
-    </li>
-    <li><i class="fa fa-power-off"></i>
-        <div class="icon-title">fa-power-off</div>
-    </li>
-    <li><i class="fa fa-print"></i>
-        <div class="icon-title">fa-print</div>
-    </li>
-    <li><i class="fa fa-puzzle-piece"></i>
-        <div class="icon-title">fa-puzzle-piece</div>
-    </li>
-    <li><i class="fa fa-qrcode"></i>
-        <div class="icon-title">fa-qrcode</div>
-    </li>
-    <li><i class="fa fa-question"></i>
-        <div class="icon-title">fa-question</div>
-    </li>
-    <li><i class="fa fa-question-circle"></i>
-        <div class="icon-title">fa-question-circle</div>
-    </li>
-    <li><i class="fa fa-question-circle-o"></i>
-        <div class="icon-title">fa-question-circle-o</div>
-    </li>
-    <li><i class="fa fa-quote-left"></i>
-        <div class="icon-title">fa-quote-left</div>
-    </li>
-    <li><i class="fa fa-quote-right"></i>
-        <div class="icon-title">fa-quote-right</div>
-    </li>
-    <li><i class="fa fa-random"></i>
-        <div class="icon-title">fa-random</div>
-    </li>
-    <li><i class="fa fa-recycle"></i>
-        <div class="icon-title">fa-recycle</div>
-    </li>
-    <li><i class="fa fa-refresh"></i>
-        <div class="icon-title">fa-refresh</div>
-    </li>
-    <li><i class="fa fa-registered"></i>
-        <div class="icon-title">fa-registered</div>
-    </li>
-    <li><i class="fa fa-remove"></i>
-        <div class="icon-title">fa-remove</div>
-    </li>
-    <li><i class="fa fa-reorder"></i>
-        <div class="icon-title">fa-reorder</div>
-    </li>
-    <li><i class="fa fa-reply"></i>
-        <div class="icon-title">fa-reply</div>
-    </li>
-    <li><i class="fa fa-reply-all"></i>
-        <div class="icon-title">fa-reply-all</div>
-    </li>
-    <li><i class="fa fa-retweet"></i>
-        <div class="icon-title">fa-retweet</div>
-    </li>
-    <li><i class="fa fa-road"></i>
-        <div class="icon-title">fa-road</div>
-    </li>
-    <li><i class="fa fa-rocket"></i>
-        <div class="icon-title">fa-rocket</div>
-    </li>
-    <li><i class="fa fa-rss"></i>
-        <div class="icon-title">fa-rss</div>
-    </li>
-    <li><i class="fa fa-rss-square"></i>
-        <div class="icon-title">fa-rss-square</div>
-    </li>
-    <li><i class="fa fa-s15"></i>
-        <div class="icon-title">fa-s15</div>
-    </li>
-    <li><i class="fa fa-search"></i>
-        <div class="icon-title">fa-search</div>
-    </li>
-    <li><i class="fa fa-search-minus"></i>
-        <div class="icon-title">fa-search-minus</div>
-    </li>
-    <li><i class="fa fa-search-plus"></i>
-        <div class="icon-title">fa-search-plus</div>
-    </li>
-    <li><i class="fa fa-send"></i>
-        <div class="icon-title">fa-send</div>
-    </li>
-    <li><i class="fa fa-send-o"></i>
-        <div class="icon-title">fa-send-o</div>
-    </li>
-    <li><i class="fa fa-server"></i>
-        <div class="icon-title">fa-server</div>
-    </li>
-    <li><i class="fa fa-share"></i>
-        <div class="icon-title">fa-share</div>
-    </li>
-    <li><i class="fa fa-share-alt"></i>
-        <div class="icon-title">fa-share-alt</div>
-    </li>
-    <li><i class="fa fa-share-alt-square"></i>
-        <div class="icon-title">fa-share-alt-square</div>
-    </li>
-    <li><i class="fa fa-share-square"></i>
-        <div class="icon-title">fa-share-square</div>
-    </li>
-    <li><i class="fa fa-share-square-o"></i>
-        <div class="icon-title">fa-share-square-o</div>
-    </li>
-    <li><i class="fa fa-shield"></i>
-        <div class="icon-title">fa-shield</div>
-    </li>
-    <li><i class="fa fa-ship"></i>
-        <div class="icon-title">fa-ship</div>
-    </li>
-    <li><i class="fa fa-shopping-bag"></i>
-        <div class="icon-title">fa-shopping-bag</div>
-    </li>
-    <li><i class="fa fa-shopping-basket"></i>
-        <div class="icon-title">fa-shopping-basket</div>
-    </li>
-    <li><i class="fa fa-shopping-cart"></i>
-        <div class="icon-title">fa-shopping-cart</div>
-    </li>
-    <li><i class="fa fa-shower"></i>
-        <div class="icon-title">fa-shower</div>
-    </li>
-    <li><i class="fa fa-sign-in"></i>
-        <div class="icon-title">fa-sign-in</div>
-    </li>
-    <li><i class="fa fa-sign-language"></i>
-        <div class="icon-title">fa-sign-language</div>
-    </li>
-    <li><i class="fa fa-sign-out"></i>
-        <div class="icon-title">fa-sign-out</div>
-    </li>
-    <li><i class="fa fa-signal"></i>
-        <div class="icon-title">fa-signal</div>
-    </li>
-    <li><i class="fa fa-signing"></i>
-        <div class="icon-title">fa-signing</div>
-    </li>
-    <li><i class="fa fa-sitemap"></i>
-        <div class="icon-title">fa-sitemap</div>
-    </li>
-    <li><i class="fa fa-sliders"></i>
-        <div class="icon-title">fa-sliders</div>
-    </li>
-    <li><i class="fa fa-smile-o"></i>
-        <div class="icon-title">fa-smile-o</div>
-    </li>
-    <li><i class="fa fa-snowflake-o"></i>
-        <div class="icon-title">fa-snowflake-o</div>
-    </li>
-    <li><i class="fa fa-soccer-ball-o"></i>
-        <div class="icon-title">fa-soccer-ball-o</div>
-    </li>
-    <li><i class="fa fa-sort"></i>
-        <div class="icon-title">fa-sort</div>
-    </li>
-    <li><i class="fa fa-sort-alpha-asc"></i>
-        <div class="icon-title">fa-sort-alpha-asc</div>
-    </li>
-    <li><i class="fa fa-sort-alpha-desc"></i>
-        <div class="icon-title">fa-sort-alpha-desc</div>
-    </li>
-    <li><i class="fa fa-sort-amount-asc"></i>
-        <div class="icon-title">fa-sort-amount-asc</div>
-    </li>
-    <li><i class="fa fa-sort-amount-desc"></i>
-        <div class="icon-title">fa-sort-amount-desc</div>
-    </li>
-    <li><i class="fa fa-sort-asc"></i>
-        <div class="icon-title">fa-sort-asc</div>
-    </li>
-    <li><i class="fa fa-sort-desc"></i>
-        <div class="icon-title">fa-sort-desc</div>
-    </li>
-    <li><i class="fa fa-sort-down"></i>
-        <div class="icon-title">fa-sort-down</div>
-    </li>
-    <li><i class="fa fa-sort-numeric-asc"></i>
-        <div class="icon-title">fa-sort-numeric-asc</div>
-    </li>
-    <li><i class="fa fa-sort-numeric-desc"></i>
-        <div class="icon-title">fa-sort-numeric-desc</div>
-    </li>
-    <li><i class="fa fa-sort-up"></i>
-        <div class="icon-title">fa-sort-up</div>
-    </li>
-    <li><i class="fa fa-space-shuttle"></i>
-        <div class="icon-title">fa-space-shuttle</div>
-    </li>
-    <li><i class="fa fa-spinner"></i>
-        <div class="icon-title">fa-spinner</div>
-    </li>
-    <li><i class="fa fa-spoon"></i>
-        <div class="icon-title">fa-spoon</div>
-    </li>
-    <li><i class="fa fa-square"></i>
-        <div class="icon-title">fa-square</div>
-    </li>
-    <li><i class="fa fa-square-o"></i>
-        <div class="icon-title">fa-square-o</div>
-    </li>
-    <li><i class="fa fa-star"></i>
-        <div class="icon-title">fa-star</div>
-    </li>
-    <li><i class="fa fa-star-half"></i>
-        <div class="icon-title">fa-star-half</div>
-    </li>
-    <li><i class="fa fa-star-half-empty"></i>
-        <div class="icon-title">fa-star-half-empty</div>
-    </li>
-    <li><i class="fa fa-star-half-full"></i>
-        <div class="icon-title">fa-star-half-full</div>
-    </li>
-    <li><i class="fa fa-star-half-o"></i>
-        <div class="icon-title">fa-star-half-o</div>
-    </li>
-    <li><i class="fa fa-star-o"></i>
-        <div class="icon-title">fa-star-o</div>
-    </li>
-    <li><i class="fa fa-sticky-note"></i>
-        <div class="icon-title">fa-sticky-note</div>
-    </li>
-    <li><i class="fa fa-sticky-note-o"></i>
-        <div class="icon-title">fa-sticky-note-o</div>
-    </li>
-    <li><i class="fa fa-street-view"></i>
-        <div class="icon-title">fa-street-view</div>
-    </li>
-    <li><i class="fa fa-suitcase"></i>
-        <div class="icon-title">fa-suitcase</div>
-    </li>
-    <li><i class="fa fa-sun-o"></i>
-        <div class="icon-title">fa-sun-o</div>
-    </li>
-    <li><i class="fa fa-support"></i>
-        <div class="icon-title">fa-support</div>
-    </li>
-    <li><i class="fa fa-tablet"></i>
-        <div class="icon-title">fa-tablet</div>
-    </li>
-    <li><i class="fa fa-tachometer"></i>
-        <div class="icon-title">fa-tachometer</div>
-    </li>
-    <li><i class="fa fa-tag"></i>
-        <div class="icon-title">fa-tag</div>
-    </li>
-    <li><i class="fa fa-tags"></i>
-        <div class="icon-title">fa-tags</div>
-    </li>
-    <li><i class="fa fa-tasks"></i>
-        <div class="icon-title">fa-tasks</div>
-    </li>
-    <li><i class="fa fa-taxi"></i>
-        <div class="icon-title">fa-taxi</div>
-    </li>
-    <li><i class="fa fa-television"></i>
-        <div class="icon-title">fa-television</div>
-    </li>
-    <li><i class="fa fa-terminal"></i>
-        <div class="icon-title">fa-terminal</div>
-    </li>
-    <li><i class="fa fa-thermometer"></i>
-        <div class="icon-title">fa-thermometer</div>
-    </li>
-    <li><i class="fa fa-thermometer-0"></i>
-        <div class="icon-title">fa-thermometer-0</div>
-    </li>
-    <li><i class="fa fa-thermometer-1"></i>
-        <div class="icon-title">fa-thermometer-1</div>
-    </li>
-    <li><i class="fa fa-thermometer-2"></i>
-        <div class="icon-title">fa-thermometer-2</div>
-    </li>
-    <li><i class="fa fa-thermometer-3"></i>
-        <div class="icon-title">fa-thermometer-3</div>
-    </li>
-    <li><i class="fa fa-thermometer-4"></i>
-        <div class="icon-title">fa-thermometer-4</div>
-    </li>
-    <li><i class="fa fa-thermometer-empty"></i>
-        <div class="icon-title">fa-thermometer-empty</div>
-    </li>
-    <li><i class="fa fa-thermometer-full"></i>
-        <div class="icon-title">fa-thermometer-full</div>
-    </li>
-    <li><i class="fa fa-thermometer-half"></i>
-        <div class="icon-title">fa-thermometer-half</div>
-    </li>
-    <li><i class="fa fa-thermometer-quarter"></i>
-        <div class="icon-title">fa-thermometer-quarter</div>
-    </li>
-    <li><i class="fa fa-thermometer-three-quarters"></i>
-        <div class="icon-title">fa-thermometer-three-quarters</div>
-    </li>
-    <li><i class="fa fa-thumb-tack"></i>
-        <div class="icon-title">fa-thumb-tack</div>
-    </li>
-    <li><i class="fa fa-thumbs-down"></i>
-        <div class="icon-title">fa-thumbs-down</div>
-    </li>
-    <li><i class="fa fa-thumbs-o-down"></i>
-        <div class="icon-title">fa-thumbs-o-down</div>
-    </li>
-    <li><i class="fa fa-thumbs-o-up"></i>
-        <div class="icon-title">fa-thumbs-o-up</div>
-    </li>
-    <li><i class="fa fa-thumbs-up"></i>
-        <div class="icon-title">fa-thumbs-up</div>
-    </li>
-    <li><i class="fa fa-ticket"></i>
-        <div class="icon-title">fa-ticket</div>
-    </li>
-    <li><i class="fa fa-times"></i>
-        <div class="icon-title">fa-times</div>
-    </li>
-    <li><i class="fa fa-times-circle"></i>
-        <div class="icon-title">fa-times-circle</div>
-    </li>
-    <li><i class="fa fa-times-circle-o"></i>
-        <div class="icon-title">fa-times-circle-o</div>
-    </li>
-    <li><i class="fa fa-times-rectangle"></i>
-        <div class="icon-title">fa-times-rectangle</div>
-    </li>
-    <li><i class="fa fa-times-rectangle-o"></i>
-        <div class="icon-title">fa-times-rectangle-o</div>
-    </li>
-    <li><i class="fa fa-tint"></i>
-        <div class="icon-title">fa-tint</div>
-    </li>
-    <li><i class="fa fa-toggle-down"></i>
-        <div class="icon-title">fa-toggle-down</div>
-    </li>
-    <li><i class="fa fa-toggle-left"></i>
-        <div class="icon-title">fa-toggle-left</div>
-    </li>
-    <li><i class="fa fa-toggle-off"></i>
-        <div class="icon-title">fa-toggle-off</div>
-    </li>
-    <li><i class="fa fa-toggle-on"></i>
-        <div class="icon-title">fa-toggle-on</div>
-    </li>
-    <li><i class="fa fa-toggle-right"></i>
-        <div class="icon-title">fa-toggle-right</div>
-    </li>
-    <li><i class="fa fa-toggle-up"></i>
-        <div class="icon-title">fa-toggle-up</div>
-    </li>
-    <li><i class="fa fa-trademark"></i>
-        <div class="icon-title">fa-trademark</div>
-    </li>
-    <li><i class="fa fa-trash"></i>
-        <div class="icon-title">fa-trash</div>
-    </li>
-    <li><i class="fa fa-trash-o"></i>
-        <div class="icon-title">fa-trash-o</div>
-    </li>
-    <li><i class="fa fa-tree"></i>
-        <div class="icon-title">fa-tree</div>
-    </li>
-    <li><i class="fa fa-trophy"></i>
-        <div class="icon-title">fa-trophy</div>
-    </li>
-    <li><i class="fa fa-truck"></i>
-        <div class="icon-title">fa-truck</div>
-    </li>
-    <li><i class="fa fa-tty"></i>
-        <div class="icon-title">fa-tty</div>
-    </li>
-    <li><i class="fa fa-tv"></i>
-        <div class="icon-title">fa-tv</div>
-    </li>
-    <li><i class="fa fa-umbrella"></i>
-        <div class="icon-title">fa-umbrella</div>
-    </li>
-    <li><i class="fa fa-universal-access"></i>
-        <div class="icon-title">fa-universal-access</div>
-    </li>
-    <li><i class="fa fa-university"></i>
-        <div class="icon-title">fa-university</div>
-    </li>
-    <li><i class="fa fa-unlock"></i>
-        <div class="icon-title">fa-unlock</div>
-    </li>
-    <li><i class="fa fa-unlock-alt"></i>
-        <div class="icon-title">fa-unlock-alt</div>
-    </li>
-    <li><i class="fa fa-unsorted"></i>
-        <div class="icon-title">fa-unsorted</div>
-    </li>
-    <li><i class="fa fa-upload"></i>
-        <div class="icon-title">fa-upload</div>
-    </li>
-    <li><i class="fa fa-user"></i>
-        <div class="icon-title">fa-user</div>
-    </li>
-    <li><i class="fa fa-user-circle"></i>
-        <div class="icon-title">fa-user-circle</div>
-    </li>
-    <li><i class="fa fa-user-circle-o"></i>
-        <div class="icon-title">fa-user-circle-o</div>
-    </li>
-    <li><i class="fa fa-user-o"></i>
-        <div class="icon-title">fa-user-o</div>
-    </li>
-    <li><i class="fa fa-user-plus"></i>
-        <div class="icon-title">fa-user-plus</div>
-    </li>
-    <li><i class="fa fa-user-secret"></i>
-        <div class="icon-title">fa-user-secret</div>
-    </li>
-    <li><i class="fa fa-user-times"></i>
-        <div class="icon-title">fa-user-times</div>
-    </li>
-    <li><i class="fa fa-users"></i>
-        <div class="icon-title">fa-users</div>
-    </li>
-    <li><i class="fa fa-vcard"></i>
-        <div class="icon-title">fa-vcard</div>
-    </li>
-    <li><i class="fa fa-vcard-o"></i>
-        <div class="icon-title">fa-vcard-o</div>
-    </li>
-    <li><i class="fa fa-video-camera"></i>
-        <div class="icon-title">fa-video-camera</div>
-    </li>
-    <li><i class="fa fa-volume-control-phone"></i>
-        <div class="icon-title">fa-volume-control-phone</div>
-    </li>
-    <li><i class="fa fa-volume-down"></i>
-        <div class="icon-title">fa-volume-down</div>
-    </li>
-    <li><i class="fa fa-volume-off"></i>
-        <div class="icon-title">fa-volume-off</div>
-    </li>
-    <li><i class="fa fa-volume-up"></i>
-        <div class="icon-title">fa-volume-up</div>
-    </li>
-    <li><i class="fa fa-warning"></i>
-        <div class="icon-title">fa-warning</div>
-    </li>
-    <li><i class="fa fa-wheelchair"></i>
-        <div class="icon-title">fa-wheelchair</div>
-    </li>
-    <li><i class="fa fa-wheelchair-alt"></i>
-        <div class="icon-title">fa-wheelchair-alt</div>
-    </li>
-    <li><i class="fa fa-wifi"></i>
-        <div class="icon-title">fa-wifi</div>
-    </li>
-    <li><i class="fa fa-window-close"></i>
-        <div class="icon-title">fa-window-close</div>
-    </li>
-    <li><i class="fa fa-window-close-o"></i>
-        <div class="icon-title">fa-window-close-o</div>
-    </li>
-    <li><i class="fa fa-window-maximize"></i>
-        <div class="icon-title">fa-window-maximize</div>
-    </li>
-    <li><i class="fa fa-window-minimize"></i>
-        <div class="icon-title">fa-window-minimize</div>
-    </li>
-    <li><i class="fa fa-window-restore"></i>
-        <div class="icon-title">fa-window-restore</div>
-    </li>
-    <li><i class="fa fa-wrench"></i>
-        <div class="icon-title">fa-wrench</div>
-    </li>
-    <li><i class="fa fa-american-sign-language-interpreting"></i>
-        <div class="icon-title">fa-american-sign-language-interpreting</div>
-    </li>
-    <li><i class="fa fa-asl-interpreting"></i>
-        <div class="icon-title">fa-asl-interpreting</div>
-    </li>
-    <li><i class="fa fa-assistive-listening-systems"></i>
-        <div class="icon-title">fa-assistive-listening-systems</div>
-    </li>
-    <li><i class="fa fa-audio-description"></i>
-        <div class="icon-title">fa-audio-description</div>
-    </li>
-    <li><i class="fa fa-blind"></i>
-        <div class="icon-title">fa-blind</div>
-    </li>
-    <li><i class="fa fa-braille"></i>
-        <div class="icon-title">fa-braille</div>
-    </li>
-    <li><i class="fa fa-cc"></i>
-        <div class="icon-title">fa-cc</div>
-    </li>
-    <li><i class="fa fa-deaf"></i>
-        <div class="icon-title">fa-deaf</div>
-    </li>
-    <li><i class="fa fa-deafness"></i>
-        <div class="icon-title">fa-deafness</div>
-    </li>
-    <li><i class="fa fa-hard-of-hearing"></i>
-        <div class="icon-title">fa-hard-of-hearing</div>
-    </li>
-    <li><i class="fa fa-low-vision"></i>
-        <div class="icon-title">fa-low-vision</div>
-    </li>
-    <li><i class="fa fa-question-circle-o"></i>
-        <div class="icon-title">fa-question-circle-o</div>
-    </li>
-    <li><i class="fa fa-sign-language"></i>
-        <div class="icon-title">fa-sign-language</div>
-    </li>
-    <li><i class="fa fa-signing"></i>
-        <div class="icon-title">fa-signing</div>
-    </li>
-    <li><i class="fa fa-tty"></i>
-        <div class="icon-title">fa-tty</div>
-    </li>
-    <li><i class="fa fa-universal-access"></i>
-        <div class="icon-title">fa-universal-access</div>
-    </li>
-    <li><i class="fa fa-volume-control-phone"></i>
-        <div class="icon-title">fa-volume-control-phone</div>
-    </li>
-    <li><i class="fa fa-wheelchair"></i>
-        <div class="icon-title">fa-wheelchair</div>
-    </li>
-    <li><i class="fa fa-wheelchair-alt"></i>
-        <div class="icon-title">fa-wheelchair-alt</div>
-    </li>
-    <li><i class="fa fa-hand-grab-o"></i>
-        <div class="icon-title">fa-hand-grab-o</div>
-    </li>
-    <li><i class="fa fa-hand-lizard-o"></i>
-        <div class="icon-title">fa-hand-lizard-o</div>
-    </li>
-    <li><i class="fa fa-hand-o-down"></i>
-        <div class="icon-title">fa-hand-o-down</div>
-    </li>
-    <li><i class="fa fa-hand-o-left"></i>
-        <div class="icon-title">fa-hand-o-left</div>
-    </li>
-    <li><i class="fa fa-hand-o-right"></i>
-        <div class="icon-title">fa-hand-o-right</div>
-    </li>
-    <li><i class="fa fa-hand-o-up"></i>
-        <div class="icon-title">fa-hand-o-up</div>
-    </li>
-    <li><i class="fa fa-hand-paper-o"></i>
-        <div class="icon-title">fa-hand-paper-o</div>
-    </li>
-    <li><i class="fa fa-hand-peace-o"></i>
-        <div class="icon-title">fa-hand-peace-o</div>
-    </li>
-    <li><i class="fa fa-hand-pointer-o"></i>
-        <div class="icon-title">fa-hand-pointer-o</div>
-    </li>
-    <li><i class="fa fa-hand-rock-o"></i>
-        <div class="icon-title">fa-hand-rock-o</div>
-    </li>
-    <li><i class="fa fa-hand-scissors-o"></i>
-        <div class="icon-title">fa-hand-scissors-o</div>
-    </li>
-    <li><i class="fa fa-hand-spock-o"></i>
-        <div class="icon-title">fa-hand-spock-o</div>
-    </li>
-    <li><i class="fa fa-hand-stop-o"></i>
-        <div class="icon-title">fa-hand-stop-o</div>
-    </li>
-    <li><i class="fa fa-thumbs-down"></i>
-        <div class="icon-title">fa-thumbs-down</div>
-    </li>
-    <li><i class="fa fa-thumbs-o-down"></i>
-        <div class="icon-title">fa-thumbs-o-down</div>
-    </li>
-    <li><i class="fa fa-thumbs-o-up"></i>
-        <div class="icon-title">fa-thumbs-o-up</div>
-    </li>
-    <li><i class="fa fa-thumbs-up"></i>
-        <div class="icon-title">fa-thumbs-up</div>
-    </li>
-    <li><i class="fa fa-ambulance"></i>
-        <div class="icon-title">fa-ambulance</div>
-    </li>
-    <li><i class="fa fa-automobile"></i>
-        <div class="icon-title">fa-automobile</div>
-    </li>
-    <li><i class="fa fa-bicycle"></i>
-        <div class="icon-title">fa-bicycle</div>
-    </li>
-    <li><i class="fa fa-bus"></i>
-        <div class="icon-title">fa-bus</div>
-    </li>
-    <li><i class="fa fa-cab"></i>
-        <div class="icon-title">fa-cab</div>
-    </li>
-    <li><i class="fa fa-car"></i>
-        <div class="icon-title">fa-car</div>
-    </li>
-    <li><i class="fa fa-fighter-jet"></i>
-        <div class="icon-title">fa-fighter-jet</div>
-    </li>
-    <li><i class="fa fa-motorcycle"></i>
-        <div class="icon-title">fa-motorcycle</div>
-    </li>
-    <li><i class="fa fa-plane"></i>
-        <div class="icon-title">fa-plane</div>
-    </li>
-    <li><i class="fa fa-rocket"></i>
-        <div class="icon-title">fa-rocket</div>
-    </li>
-    <li><i class="fa fa-ship"></i>
-        <div class="icon-title">fa-ship</div>
-    </li>
-    <li><i class="fa fa-space-shuttle"></i>
-        <div class="icon-title">fa-space-shuttle</div>
-    </li>
-    <li><i class="fa fa-subway"></i>
-        <div class="icon-title">fa-subway</div>
-    </li>
-    <li><i class="fa fa-taxi"></i>
-        <div class="icon-title">fa-taxi</div>
-    </li>
-    <li><i class="fa fa-train"></i>
-        <div class="icon-title">fa-train</div>
-    </li>
-    <li><i class="fa fa-truck"></i>
-        <div class="icon-title">fa-truck</div>
-    </li>
-    <li><i class="fa fa-wheelchair"></i>
-        <div class="icon-title">fa-wheelchair</div>
-    </li>
-    <li><i class="fa fa-wheelchair-alt"></i>
-        <div class="icon-title">fa-wheelchair-alt</div>
-    </li>
-    <li><i class="fa fa-genderless"></i>
-        <div class="icon-title">fa-genderless</div>
-    </li>
-    <li><i class="fa fa-intersex"></i>
-        <div class="icon-title">fa-intersex</div>
-    </li>
-    <li><i class="fa fa-mars"></i>
-        <div class="icon-title">fa-mars</div>
-    </li>
-    <li><i class="fa fa-mars-double"></i>
-        <div class="icon-title">fa-mars-double</div>
-    </li>
-    <li><i class="fa fa-mars-stroke"></i>
-        <div class="icon-title">fa-mars-stroke</div>
-    </li>
-    <li><i class="fa fa-mars-stroke-h"></i>
-        <div class="icon-title">fa-mars-stroke-h</div>
-    </li>
-    <li><i class="fa fa-mars-stroke-v"></i>
-        <div class="icon-title">fa-mars-stroke-v</div>
-    </li>
-    <li><i class="fa fa-mercury"></i>
-        <div class="icon-title">fa-mercury</div>
-    </li>
-    <li><i class="fa fa-neuter"></i>
-        <div class="icon-title">fa-neuter</div>
-    </li>
-    <li><i class="fa fa-transgender"></i>
-        <div class="icon-title">fa-transgender</div>
-    </li>
-    <li><i class="fa fa-transgender-alt"></i>
-        <div class="icon-title">fa-transgender-alt</div>
-    </li>
-    <li><i class="fa fa-venus"></i>
-        <div class="icon-title">fa-venus</div>
-    </li>
-    <li><i class="fa fa-venus-double"></i>
-        <div class="icon-title">fa-venus-double</div>
-    </li>
-    <li><i class="fa fa-venus-mars"></i>
-        <div class="icon-title">fa-venus-mars</div>
-    </li>
-    <li><i class="fa fa-file"></i>
-        <div class="icon-title">fa-file</div>
-    </li>
-    <li><i class="fa fa-file-archive-o"></i>
-        <div class="icon-title">fa-file-archive-o</div>
-    </li>
-    <li><i class="fa fa-file-audio-o"></i>
-        <div class="icon-title">fa-file-audio-o</div>
-    </li>
-    <li><i class="fa fa-file-code-o"></i>
-        <div class="icon-title">fa-file-code-o</div>
-    </li>
-    <li><i class="fa fa-file-excel-o"></i>
-        <div class="icon-title">fa-file-excel-o</div>
-    </li>
-    <li><i class="fa fa-file-image-o"></i>
-        <div class="icon-title">fa-file-image-o</div>
-    </li>
-    <li><i class="fa fa-file-movie-o"></i>
-        <div class="icon-title">fa-file-movie-o</div>
-    </li>
-    <li><i class="fa fa-file-o"></i>
-        <div class="icon-title">fa-file-o</div>
-    </li>
-    <li><i class="fa fa-file-pdf-o"></i>
-        <div class="icon-title">fa-file-pdf-o</div>
-    </li>
-    <li><i class="fa fa-file-photo-o"></i>
-        <div class="icon-title">fa-file-photo-o</div>
-    </li>
-    <li><i class="fa fa-file-picture-o"></i>
-        <div class="icon-title">fa-file-picture-o</div>
-    </li>
-    <li><i class="fa fa-file-powerpoint-o"></i>
-        <div class="icon-title">fa-file-powerpoint-o</div>
-    </li>
-    <li><i class="fa fa-file-sound-o"></i>
-        <div class="icon-title">fa-file-sound-o</div>
-    </li>
-    <li><i class="fa fa-file-text"></i>
-        <div class="icon-title">fa-file-text</div>
-    </li>
-    <li><i class="fa fa-file-text-o"></i>
-        <div class="icon-title">fa-file-text-o</div>
-    </li>
-    <li><i class="fa fa-file-video-o"></i>
-        <div class="icon-title">fa-file-video-o</div>
-    </li>
-    <li><i class="fa fa-file-word-o"></i>
-        <div class="icon-title">fa-file-word-o</div>
-    </li>
-    <li><i class="fa fa-file-zip-o"></i>
-        <div class="icon-title">fa-file-zip-o</div>
-    </li>
-    <li><i class="fa fa-circle-o-notch"></i>
-        <div class="icon-title">fa-circle-o-notch</div>
-    </li>
-    <li><i class="fa fa-cog"></i>
-        <div class="icon-title">fa-cog</div>
-    </li>
-    <li><i class="fa fa-gear"></i>
-        <div class="icon-title">fa-gear</div>
-    </li>
-    <li><i class="fa fa-refresh"></i>
-        <div class="icon-title">fa-refresh</div>
-    </li>
-    <li><i class="fa fa-spinner"></i>
-        <div class="icon-title">fa-spinner</div>
-    </li>
-    <li><i class="fa fa-check-square"></i>
-        <div class="icon-title">fa-check-square</div>
-    </li>
-    <li><i class="fa fa-check-square-o"></i>
-        <div class="icon-title">fa-check-square-o</div>
-    </li>
-    <li><i class="fa fa-circle"></i>
-        <div class="icon-title">fa-circle</div>
-    </li>
-    <li><i class="fa fa-circle-o"></i>
-        <div class="icon-title">fa-circle-o</div>
-    </li>
-    <li><i class="fa fa-dot-circle-o"></i>
-        <div class="icon-title">fa-dot-circle-o</div>
-    </li>
-    <li><i class="fa fa-minus-square"></i>
-        <div class="icon-title">fa-minus-square</div>
-    </li>
-    <li><i class="fa fa-minus-square-o"></i>
-        <div class="icon-title">fa-minus-square-o</div>
-    </li>
-    <li><i class="fa fa-plus-square"></i>
-        <div class="icon-title">fa-plus-square</div>
-    </li>
-    <li><i class="fa fa-plus-square-o"></i>
-        <div class="icon-title">fa-plus-square-o</div>
-    </li>
-    <li><i class="fa fa-square"></i>
-        <div class="icon-title">fa-square</div>
-    </li>
-    <li><i class="fa fa-square-o"></i>
-        <div class="icon-title">fa-square-o</div>
-    </li>
-    <li><i class="fa fa-cc-amex"></i>
-        <div class="icon-title">fa-cc-amex</div>
-    </li>
-    <li><i class="fa fa-cc-diners-club"></i>
-        <div class="icon-title">fa-cc-diners-club</div>
-    </li>
-    <li><i class="fa fa-cc-discover"></i>
-        <div class="icon-title">fa-cc-discover</div>
-    </li>
-    <li><i class="fa fa-cc-jcb"></i>
-        <div class="icon-title">fa-cc-jcb</div>
-    </li>
-    <li><i class="fa fa-cc-mastercard"></i>
-        <div class="icon-title">fa-cc-mastercard</div>
-    </li>
-    <li><i class="fa fa-cc-paypal"></i>
-        <div class="icon-title">fa-cc-paypal</div>
-    </li>
-    <li><i class="fa fa-cc-stripe"></i>
-        <div class="icon-title">fa-cc-stripe</div>
-    </li>
-    <li><i class="fa fa-cc-visa"></i>
-        <div class="icon-title">fa-cc-visa</div>
-    </li>
-    <li><i class="fa fa-credit-card"></i>
-        <div class="icon-title">fa-credit-card</div>
-    </li>
-    <li><i class="fa fa-credit-card-alt"></i>
-        <div class="icon-title">fa-credit-card-alt</div>
-    </li>
-    <li><i class="fa fa-google-wallet"></i>
-        <div class="icon-title">fa-google-wallet</div>
-    </li>
-    <li><i class="fa fa-paypal"></i>
-        <div class="icon-title">fa-paypal</div>
-    </li>
-    <li><i class="fa fa-area-chart"></i>
-        <div class="icon-title">fa-area-chart</div>
-    </li>
-    <li><i class="fa fa-bar-chart"></i>
-        <div class="icon-title">fa-bar-chart</div>
-    </li>
-    <li><i class="fa fa-bar-chart-o"></i>
-        <div class="icon-title">fa-bar-chart-o</div>
-    </li>
-    <li><i class="fa fa-line-chart"></i>
-        <div class="icon-title">fa-line-chart</div>
-    </li>
-    <li><i class="fa fa-pie-chart"></i>
-        <div class="icon-title">fa-pie-chart</div>
-    </li>
-    <li><i class="fa fa-bitcoin"></i>
-        <div class="icon-title">fa-bitcoin</div>
-    </li>
-    <li><i class="fa fa-btc"></i>
-        <div class="icon-title">fa-btc</div>
-    </li>
-    <li><i class="fa fa-cny"></i>
-        <div class="icon-title">fa-cny</div>
-    </li>
-    <li><i class="fa fa-dollar"></i>
-        <div class="icon-title">fa-dollar</div>
-    </li>
-    <li><i class="fa fa-eur"></i>
-        <div class="icon-title">fa-eur</div>
-    </li>
-    <li><i class="fa fa-euro"></i>
-        <div class="icon-title">fa-euro</div>
-    </li>
-    <li><i class="fa fa-gbp"></i>
-        <div class="icon-title">fa-gbp</div>
-    </li>
-    <li><i class="fa fa-gg"></i>
-        <div class="icon-title">fa-gg</div>
-    </li>
-    <li><i class="fa fa-gg-circle"></i>
-        <div class="icon-title">fa-gg-circle</div>
-    </li>
-    <li><i class="fa fa-ils"></i>
-        <div class="icon-title">fa-ils</div>
-    </li>
-    <li><i class="fa fa-inr"></i>
-        <div class="icon-title">fa-inr</div>
-    </li>
-    <li><i class="fa fa-jpy"></i>
-        <div class="icon-title">fa-jpy</div>
-    </li>
-    <li><i class="fa fa-krw"></i>
-        <div class="icon-title">fa-krw</div>
-    </li>
-    <li><i class="fa fa-money"></i>
-        <div class="icon-title">fa-money</div>
-    </li>
-    <li><i class="fa fa-rmb"></i>
-        <div class="icon-title">fa-rmb</div>
-    </li>
-    <li><i class="fa fa-rouble"></i>
-        <div class="icon-title">fa-rouble</div>
-    </li>
-    <li><i class="fa fa-rub"></i>
-        <div class="icon-title">fa-rub</div>
-    </li>
-    <li><i class="fa fa-ruble"></i>
-        <div class="icon-title">fa-ruble</div>
-    </li>
-    <li><i class="fa fa-rupee"></i>
-        <div class="icon-title">fa-rupee</div>
-    </li>
-    <li><i class="fa fa-shekel"></i>
-        <div class="icon-title">fa-shekel</div>
-    </li>
-    <li><i class="fa fa-sheqel"></i>
-        <div class="icon-title">fa-sheqel</div>
-    </li>
-    <li><i class="fa fa-try"></i>
-        <div class="icon-title">fa-try</div>
-    </li>
-    <li><i class="fa fa-turkish-lira"></i>
-        <div class="icon-title">fa-turkish-lira</div>
-    </li>
-    <li><i class="fa fa-usd"></i>
-        <div class="icon-title">fa-usd</div>
-    </li>
-    <li><i class="fa fa-won"></i>
-        <div class="icon-title">fa-won</div>
-    </li>
-    <li><i class="fa fa-yen"></i>
-        <div class="icon-title">fa-yen</div>
-    </li>
-    <li><i class="fa fa-align-center"></i>
-        <div class="icon-title">fa-align-center</div>
-    </li>
-    <li><i class="fa fa-align-justify"></i>
-        <div class="icon-title">fa-align-justify</div>
-    </li>
-    <li><i class="fa fa-align-left"></i>
-        <div class="icon-title">fa-align-left</div>
-    </li>
-    <li><i class="fa fa-align-right"></i>
-        <div class="icon-title">fa-align-right</div>
-    </li>
-    <li><i class="fa fa-bold"></i>
-        <div class="icon-title">fa-bold</div>
-    </li>
-    <li><i class="fa fa-chain"></i>
-        <div class="icon-title">fa-chain</div>
-    </li>
-    <li><i class="fa fa-chain-broken"></i>
-        <div class="icon-title">fa-chain-broken</div>
-    </li>
-    <li><i class="fa fa-clipboard"></i>
-        <div class="icon-title">fa-clipboard</div>
-    </li>
-    <li><i class="fa fa-columns"></i>
-        <div class="icon-title">fa-columns</div>
-    </li>
-    <li><i class="fa fa-copy"></i>
-        <div class="icon-title">fa-copy</div>
-    </li>
-    <li><i class="fa fa-cut"></i>
-        <div class="icon-title">fa-cut</div>
-    </li>
-    <li><i class="fa fa-dedent"></i>
-        <div class="icon-title">fa-dedent</div>
-    </li>
-    <li><i class="fa fa-eraser"></i>
-        <div class="icon-title">fa-eraser</div>
-    </li>
-    <li><i class="fa fa-file"></i>
-        <div class="icon-title">fa-file</div>
-    </li>
-    <li><i class="fa fa-file-o"></i>
-        <div class="icon-title">fa-file-o</div>
-    </li>
-    <li><i class="fa fa-file-text"></i>
-        <div class="icon-title">fa-file-text</div>
-    </li>
-    <li><i class="fa fa-file-text-o"></i>
-        <div class="icon-title">fa-file-text-o</div>
-    </li>
-    <li><i class="fa fa-files-o"></i>
-        <div class="icon-title">fa-files-o</div>
-    </li>
-    <li><i class="fa fa-floppy-o"></i>
-        <div class="icon-title">fa-floppy-o</div>
-    </li>
-    <li><i class="fa fa-font"></i>
-        <div class="icon-title">fa-font</div>
-    </li>
-    <li><i class="fa fa-header"></i>
-        <div class="icon-title">fa-header</div>
-    </li>
-    <li><i class="fa fa-indent"></i>
-        <div class="icon-title">fa-indent</div>
-    </li>
-    <li><i class="fa fa-italic"></i>
-        <div class="icon-title">fa-italic</div>
-    </li>
-    <li><i class="fa fa-link"></i>
-        <div class="icon-title">fa-link</div>
-    </li>
-    <li><i class="fa fa-list"></i>
-        <div class="icon-title">fa-list</div>
-    </li>
-    <li><i class="fa fa-list-alt"></i>
-        <div class="icon-title">fa-list-alt</div>
-    </li>
-    <li><i class="fa fa-list-ol"></i>
-        <div class="icon-title">fa-list-ol</div>
-    </li>
-    <li><i class="fa fa-list-ul"></i>
-        <div class="icon-title">fa-list-ul</div>
-    </li>
-    <li><i class="fa fa-outdent"></i>
-        <div class="icon-title">fa-outdent</div>
-    </li>
-    <li><i class="fa fa-paperclip"></i>
-        <div class="icon-title">fa-paperclip</div>
-    </li>
-    <li><i class="fa fa-paragraph"></i>
-        <div class="icon-title">fa-paragraph</div>
-    </li>
-    <li><i class="fa fa-paste"></i>
-        <div class="icon-title">fa-paste</div>
-    </li>
-    <li><i class="fa fa-repeat"></i>
-        <div class="icon-title">fa-repeat</div>
-    </li>
-    <li><i class="fa fa-rotate-left"></i>
-        <div class="icon-title">fa-rotate-left</div>
-    </li>
-    <li><i class="fa fa-rotate-right"></i>
-        <div class="icon-title">fa-rotate-right</div>
-    </li>
-    <li><i class="fa fa-save"></i>
-        <div class="icon-title">fa-save</div>
-    </li>
-    <li><i class="fa fa-scissors"></i>
-        <div class="icon-title">fa-scissors</div>
-    </li>
-    <li><i class="fa fa-strikethrough"></i>
-        <div class="icon-title">fa-strikethrough</div>
-    </li>
-    <li><i class="fa fa-subscript"></i>
-        <div class="icon-title">fa-subscript</div>
-    </li>
-    <li><i class="fa fa-superscript"></i>
-        <div class="icon-title">fa-superscript</div>
-    </li>
-    <li><i class="fa fa-table"></i>
-        <div class="icon-title">fa-table</div>
-    </li>
-    <li><i class="fa fa-text-height"></i>
-        <div class="icon-title">fa-text-height</div>
-    </li>
-    <li><i class="fa fa-text-width"></i>
-        <div class="icon-title">fa-text-width</div>
-    </li>
-    <li><i class="fa fa-th"></i>
-        <div class="icon-title">fa-th</div>
-    </li>
-    <li><i class="fa fa-th-large"></i>
-        <div class="icon-title">fa-th-large</div>
-    </li>
-    <li><i class="fa fa-th-list"></i>
-        <div class="icon-title">fa-th-list</div>
-    </li>
-    <li><i class="fa fa-underline"></i>
-        <div class="icon-title">fa-underline</div>
-    </li>
-    <li><i class="fa fa-undo"></i>
-        <div class="icon-title">fa-undo</div>
-    </li>
-    <li><i class="fa fa-unlink"></i>
-        <div class="icon-title">fa-unlink</div>
-    </li>
-    <li><i class="fa fa-angle-double-down"></i>
-        <div class="icon-title">fa-angle-double-down</div>
-    </li>
-    <li><i class="fa fa-angle-double-left"></i>
-        <div class="icon-title">fa-angle-double-left</div>
-    </li>
-    <li><i class="fa fa-angle-double-right"></i>
-        <div class="icon-title">fa-angle-double-right</div>
-    </li>
-    <li><i class="fa fa-angle-double-up"></i>
-        <div class="icon-title">fa-angle-double-up</div>
-    </li>
-    <li><i class="fa fa-angle-down"></i>
-        <div class="icon-title">fa-angle-down</div>
-    </li>
-    <li><i class="fa fa-angle-left"></i>
-        <div class="icon-title">fa-angle-left</div>
-    </li>
-    <li><i class="fa fa-angle-right"></i>
-        <div class="icon-title">fa-angle-right</div>
-    </li>
-    <li><i class="fa fa-angle-up"></i>
-        <div class="icon-title">fa-angle-up</div>
-    </li>
-    <li><i class="fa fa-arrow-circle-down"></i>
-        <div class="icon-title">fa-arrow-circle-down</div>
-    </li>
-    <li><i class="fa fa-arrow-circle-left"></i>
-        <div class="icon-title">fa-arrow-circle-left</div>
-    </li>
-    <li><i class="fa fa-arrow-circle-o-down"></i>
-        <div class="icon-title">fa-arrow-circle-o-down</div>
-    </li>
-    <li><i class="fa fa-arrow-circle-o-left"></i>
-        <div class="icon-title">fa-arrow-circle-o-left</div>
-    </li>
-    <li><i class="fa fa-arrow-circle-o-right"></i>
-        <div class="icon-title">fa-arrow-circle-o-right</div>
-    </li>
-    <li><i class="fa fa-arrow-circle-o-up"></i>
-        <div class="icon-title">fa-arrow-circle-o-up</div>
-    </li>
-    <li><i class="fa fa-arrow-circle-right"></i>
-        <div class="icon-title">fa-arrow-circle-right</div>
-    </li>
-    <li><i class="fa fa-arrow-circle-up"></i>
-        <div class="icon-title">fa-arrow-circle-up</div>
-    </li>
-    <li><i class="fa fa-arrow-down"></i>
-        <div class="icon-title">fa-arrow-down</div>
-    </li>
-    <li><i class="fa fa-arrow-left"></i>
-        <div class="icon-title">fa-arrow-left</div>
-    </li>
-    <li><i class="fa fa-arrow-right"></i>
-        <div class="icon-title">fa-arrow-right</div>
-    </li>
-    <li><i class="fa fa-arrow-up"></i>
-        <div class="icon-title">fa-arrow-up</div>
-    </li>
-    <li><i class="fa fa-arrows"></i>
-        <div class="icon-title">fa-arrows</div>
-    </li>
-    <li><i class="fa fa-arrows-alt"></i>
-        <div class="icon-title">fa-arrows-alt</div>
-    </li>
-    <li><i class="fa fa-arrows-h"></i>
-        <div class="icon-title">fa-arrows-h</div>
-    </li>
-    <li><i class="fa fa-arrows-v"></i>
-        <div class="icon-title">fa-arrows-v</div>
-    </li>
-    <li><i class="fa fa-caret-down"></i>
-        <div class="icon-title">fa-caret-down</div>
-    </li>
-    <li><i class="fa fa-caret-left"></i>
-        <div class="icon-title">fa-caret-left</div>
-    </li>
-    <li><i class="fa fa-caret-right"></i>
-        <div class="icon-title">fa-caret-right</div>
-    </li>
-    <li><i class="fa fa-caret-square-o-down"></i>
-        <div class="icon-title">fa-caret-square-o-down</div>
-    </li>
-    <li><i class="fa fa-caret-square-o-left"></i>
-        <div class="icon-title">fa-caret-square-o-left</div>
-    </li>
-    <li><i class="fa fa-caret-square-o-right"></i>
-        <div class="icon-title">fa-caret-square-o-right</div>
-    </li>
-    <li><i class="fa fa-caret-square-o-up"></i>
-        <div class="icon-title">fa-caret-square-o-up</div>
-    </li>
-    <li><i class="fa fa-caret-up"></i>
-        <div class="icon-title">fa-caret-up</div>
-    </li>
-    <li><i class="fa fa-chevron-circle-down"></i>
-        <div class="icon-title">fa-chevron-circle-down</div>
-    </li>
-    <li><i class="fa fa-chevron-circle-left"></i>
-        <div class="icon-title">fa-chevron-circle-left</div>
-    </li>
-    <li><i class="fa fa-chevron-circle-right"></i>
-        <div class="icon-title">fa-chevron-circle-right</div>
-    </li>
-    <li><i class="fa fa-chevron-circle-up"></i>
-        <div class="icon-title">fa-chevron-circle-up</div>
-    </li>
-    <li><i class="fa fa-chevron-down"></i>
-        <div class="icon-title">fa-chevron-down</div>
-    </li>
-    <li><i class="fa fa-chevron-left"></i>
-        <div class="icon-title">fa-chevron-left</div>
-    </li>
-    <li><i class="fa fa-chevron-right"></i>
-        <div class="icon-title">fa-chevron-right</div>
-    </li>
-    <li><i class="fa fa-chevron-up"></i>
-        <div class="icon-title">fa-chevron-up</div>
-    </li>
-    <li><i class="fa fa-exchange"></i>
-        <div class="icon-title">fa-exchange</div>
-    </li>
-    <li><i class="fa fa-hand-o-down"></i>
-        <div class="icon-title">fa-hand-o-down</div>
-    </li>
-    <li><i class="fa fa-hand-o-left"></i>
-        <div class="icon-title">fa-hand-o-left</div>
-    </li>
-    <li><i class="fa fa-hand-o-right"></i>
-        <div class="icon-title">fa-hand-o-right</div>
-    </li>
-    <li><i class="fa fa-hand-o-up"></i>
-        <div class="icon-title">fa-hand-o-up</div>
-    </li>
-    <li><i class="fa fa-long-arrow-down"></i>
-        <div class="icon-title">fa-long-arrow-down</div>
-    </li>
-    <li><i class="fa fa-long-arrow-left"></i>
-        <div class="icon-title">fa-long-arrow-left</div>
-    </li>
-    <li><i class="fa fa-long-arrow-right"></i>
-        <div class="icon-title">fa-long-arrow-right</div>
-    </li>
-    <li><i class="fa fa-long-arrow-up"></i>
-        <div class="icon-title">fa-long-arrow-up</div>
-    </li>
-    <li><i class="fa fa-toggle-down"></i>
-        <div class="icon-title">fa-toggle-down</div>
-    </li>
-    <li><i class="fa fa-toggle-left"></i>
-        <div class="icon-title">fa-toggle-left</div>
-    </li>
-    <li><i class="fa fa-toggle-right"></i>
-        <div class="icon-title">fa-toggle-right</div>
-    </li>
-    <li><i class="fa fa-toggle-up"></i>
-        <div class="icon-title">fa-toggle-up</div>
-    </li>
-    <li><i class="fa fa-arrows-alt"></i>
-        <div class="icon-title">fa-arrows-alt</div>
-    </li>
-    <li><i class="fa fa-backward"></i>
-        <div class="icon-title">fa-backward</div>
-    </li>
-    <li><i class="fa fa-compress"></i>
-        <div class="icon-title">fa-compress</div>
-    </li>
-    <li><i class="fa fa-eject"></i>
-        <div class="icon-title">fa-eject</div>
-    </li>
-    <li><i class="fa fa-expand"></i>
-        <div class="icon-title">fa-expand</div>
-    </li>
-    <li><i class="fa fa-fast-backward"></i>
-        <div class="icon-title">fa-fast-backward</div>
-    </li>
-    <li><i class="fa fa-fast-forward"></i>
-        <div class="icon-title">fa-fast-forward</div>
-    </li>
-    <li><i class="fa fa-forward"></i>
-        <div class="icon-title">fa-forward</div>
-    </li>
-    <li><i class="fa fa-pause"></i>
-        <div class="icon-title">fa-pause</div>
-    </li>
-    <li><i class="fa fa-pause-circle"></i>
-        <div class="icon-title">fa-pause-circle</div>
-    </li>
-    <li><i class="fa fa-pause-circle-o"></i>
-        <div class="icon-title">fa-pause-circle-o</div>
-    </li>
-    <li><i class="fa fa-play"></i>
-        <div class="icon-title">fa-play</div>
-    </li>
-    <li><i class="fa fa-play-circle"></i>
-        <div class="icon-title">fa-play-circle</div>
-    </li>
-    <li><i class="fa fa-play-circle-o"></i>
-        <div class="icon-title">fa-play-circle-o</div>
-    </li>
-    <li><i class="fa fa-random"></i>
-        <div class="icon-title">fa-random</div>
-    </li>
-    <li><i class="fa fa-step-backward"></i>
-        <div class="icon-title">fa-step-backward</div>
-    </li>
-    <li><i class="fa fa-step-forward"></i>
-        <div class="icon-title">fa-step-forward</div>
-    </li>
-    <li><i class="fa fa-stop"></i>
-        <div class="icon-title">fa-stop</div>
-    </li>
-    <li><i class="fa fa-stop-circle"></i>
-        <div class="icon-title">fa-stop-circle</div>
-    </li>
-    <li><i class="fa fa-stop-circle-o"></i>
-        <div class="icon-title">fa-stop-circle-o</div>
-    </li>
-    <li><i class="fa fa-youtube-play"></i>
-        <div class="icon-title">fa-youtube-play</div>
-    </li>
-    <li><i class="fa fa-500px"></i>
-        <div class="icon-title">fa-500px</div>
-    </li>
-    <li><i class="fa fa-adn"></i>
-        <div class="icon-title">fa-adn</div>
-    </li>
-    <li><i class="fa fa-amazon"></i>
-        <div class="icon-title">fa-amazon</div>
-    </li>
-    <li><i class="fa fa-android"></i>
-        <div class="icon-title">fa-android</div>
-    </li>
-    <li><i class="fa fa-angellist"></i>
-        <div class="icon-title">fa-angellist</div>
-    </li>
-    <li><i class="fa fa-apple"></i>
-        <div class="icon-title">fa-apple</div>
-    </li>
-    <li><i class="fa fa-bandcamp"></i>
-        <div class="icon-title">fa-bandcamp</div>
-    </li>
-    <li><i class="fa fa-behance"></i>
-        <div class="icon-title">fa-behance</div>
-    </li>
-    <li><i class="fa fa-behance-square"></i>
-        <div class="icon-title">fa-behance-square</div>
-    </li>
-    <li><i class="fa fa-bitbucket"></i>
-        <div class="icon-title">fa-bitbucket</div>
-    </li>
-    <li><i class="fa fa-bitbucket-square"></i>
-        <div class="icon-title">fa-bitbucket-square</div>
-    </li>
-    <li><i class="fa fa-bitcoin"></i>
-        <div class="icon-title">fa-bitcoin</div>
-    </li>
-    <li><i class="fa fa-black-tie"></i>
-        <div class="icon-title">fa-black-tie</div>
-    </li>
-    <li><i class="fa fa-bluetooth"></i>
-        <div class="icon-title">fa-bluetooth</div>
-    </li>
-    <li><i class="fa fa-bluetooth-b"></i>
-        <div class="icon-title">fa-bluetooth-b</div>
-    </li>
-    <li><i class="fa fa-btc"></i>
-        <div class="icon-title">fa-btc</div>
-    </li>
-    <li><i class="fa fa-buysellads"></i>
-        <div class="icon-title">fa-buysellads</div>
-    </li>
-    <li><i class="fa fa-cc-amex"></i>
-        <div class="icon-title">fa-cc-amex</div>
-    </li>
-    <li><i class="fa fa-cc-diners-club"></i>
-        <div class="icon-title">fa-cc-diners-club</div>
-    </li>
-    <li><i class="fa fa-cc-discover"></i>
-        <div class="icon-title">fa-cc-discover</div>
-    </li>
-    <li><i class="fa fa-cc-jcb"></i>
-        <div class="icon-title">fa-cc-jcb</div>
-    </li>
-    <li><i class="fa fa-cc-mastercard"></i>
-        <div class="icon-title">fa-cc-mastercard</div>
-    </li>
-    <li><i class="fa fa-cc-paypal"></i>
-        <div class="icon-title">fa-cc-paypal</div>
-    </li>
-    <li><i class="fa fa-cc-stripe"></i>
-        <div class="icon-title">fa-cc-stripe</div>
-    </li>
-    <li><i class="fa fa-cc-visa"></i>
-        <div class="icon-title">fa-cc-visa</div>
-    </li>
-    <li><i class="fa fa-chrome"></i>
-        <div class="icon-title">fa-chrome</div>
-    </li>
-    <li><i class="fa fa-codepen"></i>
-        <div class="icon-title">fa-codepen</div>
-    </li>
-    <li><i class="fa fa-codiepie"></i>
-        <div class="icon-title">fa-codiepie</div>
-    </li>
-    <li><i class="fa fa-connectdevelop"></i>
-        <div class="icon-title">fa-connectdevelop</div>
-    </li>
-    <li><i class="fa fa-contao"></i>
-        <div class="icon-title">fa-contao</div>
-    </li>
-    <li><i class="fa fa-css3"></i>
-        <div class="icon-title">fa-css3</div>
-    </li>
-    <li><i class="fa fa-dashcube"></i>
-        <div class="icon-title">fa-dashcube</div>
-    </li>
-    <li><i class="fa fa-delicious"></i>
-        <div class="icon-title">fa-delicious</div>
-    </li>
-    <li><i class="fa fa-deviantart"></i>
-        <div class="icon-title">fa-deviantart</div>
-    </li>
-    <li><i class="fa fa-digg"></i>
-        <div class="icon-title">fa-digg</div>
-    </li>
-    <li><i class="fa fa-dribbble"></i>
-        <div class="icon-title">fa-dribbble</div>
-    </li>
-    <li><i class="fa fa-dropbox"></i>
-        <div class="icon-title">fa-dropbox</div>
-    </li>
-    <li><i class="fa fa-drupal"></i>
-        <div class="icon-title">fa-drupal</div>
-    </li>
-    <li><i class="fa fa-edge"></i>
-        <div class="icon-title">fa-edge</div>
-    </li>
-    <li><i class="fa fa-eercast"></i>
-        <div class="icon-title">fa-eercast</div>
-    </li>
-    <li><i class="fa fa-empire"></i>
-        <div class="icon-title">fa-empire</div>
-    </li>
-    <li><i class="fa fa-envira"></i>
-        <div class="icon-title">fa-envira</div>
-    </li>
-    <li><i class="fa fa-etsy"></i>
-        <div class="icon-title">fa-etsy</div>
-    </li>
-    <li><i class="fa fa-expeditedssl"></i>
-        <div class="icon-title">fa-expeditedssl</div>
-    </li>
-    <li><i class="fa fa-fa"></i>
-        <div class="icon-title">fa-fa</div>
-    </li>
-    <li><i class="fa fa-facebook"></i>
-        <div class="icon-title">fa-facebook</div>
-    </li>
-    <li><i class="fa fa-facebook-f"></i>
-        <div class="icon-title">fa-facebook-f</div>
-    </li>
-    <li><i class="fa fa-facebook-official"></i>
-        <div class="icon-title">fa-facebook-official</div>
-    </li>
-    <li><i class="fa fa-facebook-square"></i>
-        <div class="icon-title">fa-facebook-square</div>
-    </li>
-    <li><i class="fa fa-firefox"></i>
-        <div class="icon-title">fa-firefox</div>
-    </li>
-    <li><i class="fa fa-first-order"></i>
-        <div class="icon-title">fa-first-order</div>
-    </li>
-    <li><i class="fa fa-flickr"></i>
-        <div class="icon-title">fa-flickr</div>
-    </li>
-    <li><i class="fa fa-font-awesome"></i>
-        <div class="icon-title">fa-font-awesome</div>
-    </li>
-    <li><i class="fa fa-fonticons"></i>
-        <div class="icon-title">fa-fonticons</div>
-    </li>
-    <li><i class="fa fa-fort-awesome"></i>
-        <div class="icon-title">fa-fort-awesome</div>
-    </li>
-    <li><i class="fa fa-forumbee"></i>
-        <div class="icon-title">fa-forumbee</div>
-    </li>
-    <li><i class="fa fa-foursquare"></i>
-        <div class="icon-title">fa-foursquare</div>
-    </li>
-    <li><i class="fa fa-free-code-camp"></i>
-        <div class="icon-title">fa-free-code-camp</div>
-    </li>
-    <li><i class="fa fa-ge"></i>
-        <div class="icon-title">fa-ge</div>
-    </li>
-    <li><i class="fa fa-get-pocket"></i>
-        <div class="icon-title">fa-get-pocket</div>
-    </li>
-    <li><i class="fa fa-gg"></i>
-        <div class="icon-title">fa-gg</div>
-    </li>
-    <li><i class="fa fa-gg-circle"></i>
-        <div class="icon-title">fa-gg-circle</div>
-    </li>
-    <li><i class="fa fa-git"></i>
-        <div class="icon-title">fa-git</div>
-    </li>
-    <li><i class="fa fa-git-square"></i>
-        <div class="icon-title">fa-git-square</div>
-    </li>
-    <li><i class="fa fa-github"></i>
-        <div class="icon-title">fa-github</div>
-    </li>
-    <li><i class="fa fa-github-alt"></i>
-        <div class="icon-title">fa-github-alt</div>
-    </li>
-    <li><i class="fa fa-github-square"></i>
-        <div class="icon-title">fa-github-square</div>
-    </li>
-    <li><i class="fa fa-gitlab"></i>
-        <div class="icon-title">fa-gitlab</div>
-    </li>
-    <li><i class="fa fa-gittip"></i>
-        <div class="icon-title">fa-gittip</div>
-    </li>
-    <li><i class="fa fa-glide"></i>
-        <div class="icon-title">fa-glide</div>
-    </li>
-    <li><i class="fa fa-glide-g"></i>
-        <div class="icon-title">fa-glide-g</div>
-    </li>
-    <li><i class="fa fa-google"></i>
-        <div class="icon-title">fa-google</div>
-    </li>
-    <li><i class="fa fa-google-plus"></i>
-        <div class="icon-title">fa-google-plus</div>
-    </li>
-    <li><i class="fa fa-google-plus-circle"></i>
-        <div class="icon-title">fa-google-plus-circle</div>
-    </li>
-    <li><i class="fa fa-google-plus-official"></i>
-        <div class="icon-title">fa-google-plus-official</div>
-    </li>
-    <li><i class="fa fa-google-plus-square"></i>
-        <div class="icon-title">fa-google-plus-square</div>
-    </li>
-    <li><i class="fa fa-google-wallet"></i>
-        <div class="icon-title">fa-google-wallet</div>
-    </li>
-    <li><i class="fa fa-gratipay"></i>
-        <div class="icon-title">fa-gratipay</div>
-    </li>
-    <li><i class="fa fa-grav"></i>
-        <div class="icon-title">fa-grav</div>
-    </li>
-    <li><i class="fa fa-hacker-news"></i>
-        <div class="icon-title">fa-hacker-news</div>
-    </li>
-    <li><i class="fa fa-houzz"></i>
-        <div class="icon-title">fa-houzz</div>
-    </li>
-    <li><i class="fa fa-html5"></i>
-        <div class="icon-title">fa-html5</div>
-    </li>
-    <li><i class="fa fa-imdb"></i>
-        <div class="icon-title">fa-imdb</div>
-    </li>
-    <li><i class="fa fa-instagram"></i>
-        <div class="icon-title">fa-instagram</div>
-    </li>
-    <li><i class="fa fa-internet-explorer"></i>
-        <div class="icon-title">fa-internet-explorer</div>
-    </li>
-    <li><i class="fa fa-ioxhost"></i>
-        <div class="icon-title">fa-ioxhost</div>
-    </li>
-    <li><i class="fa fa-joomla"></i>
-        <div class="icon-title">fa-joomla</div>
-    </li>
-    <li><i class="fa fa-jsfiddle"></i>
-        <div class="icon-title">fa-jsfiddle</div>
-    </li>
-    <li><i class="fa fa-lastfm"></i>
-        <div class="icon-title">fa-lastfm</div>
-    </li>
-    <li><i class="fa fa-lastfm-square"></i>
-        <div class="icon-title">fa-lastfm-square</div>
-    </li>
-    <li><i class="fa fa-leanpub"></i>
-        <div class="icon-title">fa-leanpub</div>
-    </li>
-    <li><i class="fa fa-linkedin"></i>
-        <div class="icon-title">fa-linkedin</div>
-    </li>
-    <li>
-        <i class="fa fa-linkedin-square"></i>
-        <div class="icon-title">fa-linkedin-square</div>
-    </li>
-    <li>
-        <i class="fa fa-linode"></i>
-        <div class="icon-title">fa-linode</div>
-    </li>
-    <li>
-        <i class="fa fa-linux"></i>
-        <div class="icon-title">fa-linux</div>
-    </li>
-    <li>
-        <i class="fa fa-maxcdn"></i>
-        <div class="icon-title">fa-maxcdn</div>
-    </li>
-    <li>
-        <i class="fa fa-meanpath"></i>
-        <div class="icon-title">fa-meanpath</div>
-    </li>
-    <li>
-        <i class="fa fa-medium"></i>
-        <div class="icon-title">fa-medium</div>
-    </li>
-    <li>
-        <i class="fa fa-meetup"></i>
-        <div class="icon-title">fa-meetup</div>
-    </li>
-    <li>
-        <i class="fa fa-mixcloud"></i>
-        <div class="icon-title">fa-mixcloud</div>
-    </li>
-    <li>
-        <i class="fa fa-modx"></i>
-        <div class="icon-title">fa-modx</div>
-    </li>
-    <li>
-        <i class="fa fa-odnoklassniki"></i>
-        <div class="icon-title">fa-odnoklassniki</div>
-    </li>
-    <li>
-        <i class="fa fa-odnoklassniki-square"></i>
-        <div class="icon-title">fa-odnoklassniki-square</div>
-    </li>
-    <li>
-        <i class="fa fa-opencart"></i>
-        <div class="icon-title">fa-opencart</div>
-    </li>
-    <li>
-        <i class="fa fa-openid"></i>
-        <div class="icon-title">fa-openid</div>
-    </li>
-    <li>
-        <i class="fa fa-opera"></i>
-        <div class="icon-title">fa-opera</div>
-    </li>
-    <li>
-        <i class="fa fa-optin-monster"></i>
-        <div class="icon-title">fa-optin-monster</div>
-    </li>
-    <li>
-        <i class="fa fa-pagelines"></i>
-        <div class="icon-title">fa-pagelines</div>
-    </li>
-    <li>
-        <i class="fa fa-paypal"></i>
-        <div class="icon-title">fa-paypal</div>
-    </li>
-    <li>
-        <i class="fa fa-pied-piper"></i>
-        <div class="icon-title">fa-pied-piper</div>
-    </li>
-    <li>
-        <i class="fa fa-pied-piper-alt"></i>
-        <div class="icon-title">fa-pied-piper-alt</div>
-    </li>
-    <li>
-        <i class="fa fa-pied-piper-pp"></i>
-        <div class="icon-title">fa-pied-piper-pp</div>
-    </li>
-    <li>
-        <i class="fa fa-pinterest"></i>
-        <div class="icon-title">fa-pinterest</div>
-    </li>
-    <li>
-        <i class="fa fa-pinterest-p"></i>
-        <div class="icon-title">fa-pinterest-p</div>
-    </li>
-    <li>
-        <i class="fa fa-pinterest-square"></i>
-        <div class="icon-title">fa-pinterest-square</div>
-    </li>
-    <li>
-        <i class="fa fa-product-hunt"></i>
-        <div class="icon-title">fa-product-hunt</div>
-    </li>
-    <li>
-        <i class="fa fa-qq"></i>
-        <div class="icon-title">fa-qq</div>
-    </li>
-    <li>
-        <i class="fa fa-quora"></i>
-        <div class="icon-title">fa-quora</div>
-    </li>
-    <li>
-        <i class="fa fa-ra"></i>
-        <div class="icon-title">fa-ra</div>
-    </li>
-    <li>
-        <i class="fa fa-ravelry"></i>
-        <div class="icon-title">fa-ravelry</div>
-    </li>
-    <li>
-        <i class="fa fa-rebel"></i>
-        <div class="icon-title">fa-rebel</div>
-    </li>
-    <li>
-        <i class="fa fa-reddit"></i>
-        <div class="icon-title">fa-reddit</div>
-    </li>
-    <li>
-        <i class="fa fa-reddit-alien"></i>
-        <div class="icon-title">fa-reddit-alien</div>
-    </li>
-    <li>
-        <i class="fa fa-reddit-square"></i>
-        <div class="icon-title">fa-reddit-square</div>
-    </li>
-    <li>
-        <i class="fa fa-renren"></i>
-        <div class="icon-title">fa-renren</div>
-    </li>
-    <li>
-        <i class="fa fa-resistance"></i>
-        <div class="icon-title">fa-resistance</div>
-    </li>
-    <li>
-        <i class="fa fa-safari"></i>
-        <div class="icon-title">fa-safari</div>
-    </li>
-    <li>
-        <i class="fa fa-scribd"></i>
-        <div class="icon-title">fa-scribd</div>
-    </li>
-    <li>
-        <i class="fa fa-sellsy"></i>
-        <div class="icon-title">fa-sellsy</div>
-    </li>
-    <li>
-        <i class="fa fa-share-alt"></i>
-        <div class="icon-title">fa-share-alt</div>
-    </li>
-    <li>
-        <i class="fa fa-share-alt-square"></i>
-        <div class="icon-title">fa-share-alt-square</div>
-    </li>
-    <li>
-        <i class="fa fa-shirtsinbulk"></i>
-        <div class="icon-title">fa-shirtsinbulk</div>
-    </li>
-    <li>
-        <i class="fa fa-simplybuilt"></i>
-        <div class="icon-title">fa-simplybuilt</div>
-    </li>
-    <li>
-        <i class="fa fa-skyatlas"></i>
-        <div class="icon-title">fa-skyatlas</div>
-    </li>
-    <li>
-        <i class="fa fa-skype"></i>
-        <div class="icon-title">fa-skype</div>
-    </li>
-    <li>
-        <i class="fa fa-slack"></i>
-        <div class="icon-title">fa-slack</div>
-    </li>
-    <li>
-        <i class="fa fa-slideshare"></i>
-        <div class="icon-title">fa-slideshare</div>
-    </li>
-    <li>
-        <i class="fa fa-snapchat"></i>
-        <div class="icon-title">fa-snapchat</div>
-    </li>
-    <li>
-        <i class="fa fa-snapchat-ghost"></i>
-        <div class="icon-title">fa-snapchat-ghost</div>
-    </li>
-    <li>
-        <i class="fa fa-snapchat-square"></i>
-        <div class="icon-title">fa-snapchat-square</div>
-    </li>
-    <li>
-        <i class="fa fa-soundcloud"></i>
-        <div class="icon-title">fa-soundcloud</div>
-    </li>
-    <li>
-        <i class="fa fa-spotify"></i>
-        <div class="icon-title">fa-spotify</div>
-    </li>
-    <li>
-        <i class="fa fa-stack-exchange"></i>
-        <div class="icon-title">fa-stack-exchange</div>
-    </li>
-    <li>
-        <i class="fa fa-stack-overflow"></i>
-        <div class="icon-title">fa-stack-overflow</div>
-    </li>
-    <li>
-        <i class="fa fa-steam"></i>
-        <div class="icon-title">fa-steam</div>
-    </li>
-    <li>
-        <i class="fa fa-steam-square"></i>
-        <div class="icon-title">fa-steam-square</div>
-    </li>
-    <li>
-        <i class="fa fa-stumbleupon"></i>
-        <div class="icon-title">fa-stumbleupon</div>
-    </li>
-    <li>
-        <i class="fa fa-stumbleupon-circle"></i>
-        <div class="icon-title">fa-stumbleupon-circle</div>
-    </li>
-    <li>
-        <i class="fa fa-superpowers"></i>
-        <div class="icon-title">fa-superpowers</div>
-    </li>
-    <li>
-        <i class="fa fa-telegram"></i>
-        <div class="icon-title">fa-telegram</div>
-    </li>
-    <li>
-        <i class="fa fa-tencent-weibo"></i>
-        <div class="icon-title">fa-tencent-weibo</div>
-    </li>
-    <li>
-        <i class="fa fa-themeisle"></i>
-        <div class="icon-title">fa-themeisle</div>
-    </li>
-    <li>
-        <i class="fa fa-trello"></i>
-        <div class="icon-title">fa-trello</div>
-    </li>
-    <li>
-        <i class="fa fa-tripadvisor"></i>
-        <div class="icon-title">fa-tripadvisor</div>
-    </li>
-    <li>
-        <i class="fa fa-tumblr"></i>
-        <div class="icon-title">fa-tumblr</div>
-    </li>
-    <li>
-        <i class="fa fa-tumblr-square"></i>
-        <div class="icon-title">fa-tumblr-square</div>
-    </li>
-    <li>
-        <i class="fa fa-twitch"></i>
-        <div class="icon-title">fa-twitch</div>
-    </li>
-    <li>
-        <i class="fa fa-twitter"></i>
-        <div class="icon-title">fa-twitter</div>
-    </li>
-    <li>
-        <i class="fa fa-twitter-square"></i>
-        <div class="icon-title">fa-twitter-square</div>
-    </li>
-    <li>
-        <i class="fa fa-usb"></i>
-        <div class="icon-title">fa-usb</div>
-    </li>
-    <li>
-        <i class="fa fa-viacoin"></i>
-        <div class="icon-title">fa-viacoin</div>
-    </li>
-    <li>
-        <i class="fa fa-viadeo"></i>
-        <div class="icon-title">fa-viadeo</div>
-    </li>
-    <li>
-        <i class="fa fa-viadeo-square"></i>
-        <div class="icon-title">fa-viadeo-square</div>
-    </li>
-    <li>
-        <i class="fa fa-vimeo"></i>
-        <div class="icon-title">fa-vimeo</div>
-    </li>
-    <li>
-        <i class="fa fa-vimeo-square"></i>
-        <div class="icon-title">fa-vimeo-square</div>
-    </li>
-    <li>
-        <i class="fa fa-vine"></i>
-        <div class="icon-title">fa-vine</div>
-    </li>
-    <li>
-        <i class="fa fa-vk"></i>
-        <div class="icon-title">fa-vk</div>
-    </li>
-    <li>
-        <i class="fa fa-wechat"></i>
-        <div class="icon-title">fa-wechat</div>
-    </li>
-    <li>
-        <i class="fa fa-weibo"></i>
-        <div class="icon-title">fa-weibo</div>
-    </li>
-    <li>
-        <i class="fa fa-weixin"></i>
-        <div class="icon-title">fa-weixin</div>
-    </li>
-    <li>
-        <i class="fa fa-whatsapp"></i>
-        <div class="icon-title">fa-whatsapp</div>
-    </li>
-    <li>
-        <i class="fa fa-wikipedia-w"></i>
-        <div class="icon-title">fa-wikipedia-w</div>
-    </li>
-    <li>
-        <i class="fa fa-windows"></i>
-        <div class="icon-title">fa-windows</div>
-    </li>
-    <li>
-        <i class="fa fa-wordpress"></i>
-        <div class="icon-title">fa-wordpress</div>
-    </li>
-    <li>
-        <i class="fa fa-wpbeginner"></i>
-        <div class="icon-title">fa-wpbeginner</div>
-    </li>
-    <li>
-        <i class="fa fa-wpexplorer"></i>
-        <div class="icon-title">fa-wpexplorer</div>
-    </li>
-    <li>
-        <i class="fa fa-wpforms"></i>
-        <div class="icon-title">fa-wpforms</div>
-    </li>
-    <li>
-        <i class="fa fa-xing"></i>
-        <div class="icon-title">fa-xing</div>
-    </li>
-    <li>
-        <i class="fa fa-xing-square"></i>
-        <div class="icon-title">fa-xing-square</div>
-    </li>
-    <li>
-        <i class="fa fa-y-combinator"></i>
-        <div class="icon-title">fa-y-combinator</div>
-    </li>
-    <li>
-        <i class="fa fa-y-combinator-square"></i>
-        <div class="icon-title">fa-y-combinator-square</div>
-    </li>
-    <li>
-        <i class="fa fa-yahoo"></i>
-        <div class="icon-title">fa-yahoo</div>
-    </li>
-    <li>
-        <i class="fa fa-yc"></i>
-        <div class="icon-title">fa-yc</div>
-    </li>
-    <li>
-        <i class="fa fa-yc-square"></i>
-        <div class="icon-title">fa-yc-square</div>
-    </li>
-    <li>
-        <i class="fa fa-yelp"></i>
-        <div class="icon-title">fa-yelp</div>
-    </li>
-    <li>
-        <i class="fa fa-yoast"></i>
-        <div class="icon-title">fa-yoast</div>
-    </li>
-    <li>
-        <i class="fa fa-youtube"></i>
-        <div class="icon-title">fa-youtube</div>
-    </li>
-    <li>
-        <i class="fa fa-youtube-play"></i>
-        <div class="icon-title">fa-youtube-play</div>
-    </li>
-    <li>
-        <i class="fa fa-youtube-square"></i>
-        <div class="icon-title">fa-youtube-square</div>
-    </li>
-    <li>
-        <i class="fa fa-ambulance"></i>
-        <div class="icon-title">fa-ambulance</div>
-    </li>
-    <li>
-        <i class="fa fa-h-square"></i>
-        <div class="icon-title">fa-h-square</div>
-    </li>
-    <li>
-        <i class="fa fa-heart"></i>
-        <div class="icon-title">fa-heart</div>
-    </li>
-    <li>
-        <i class="fa fa-heart-o"></i>
-        <div class="icon-title">fa-heart-o</div>
-    </li>
-    <li>
-        <i class="fa fa-heartbeat"></i>
-        <div class="icon-title">fa-heartbeat</div>
-    </li>
-    <li>
-        <i class="fa fa-hospital-o"></i>
-        <div class="icon-title">fa-hospital-o</div>
-    </li>
-    <li>
-        <i class="fa fa-medkit"></i>
-        <div class="icon-title">fa-medkit</div>
-    </li>
-    <li>
-        <i class="fa fa-plus-square"></i>
-        <div class="icon-title">fa-plus-square</div>
-    </li>
-    <li>
-        <i class="fa fa-stethoscope"></i>
-        <div class="icon-title">fa-stethoscope</div>
-    </li>
-    <li>
-        <i class="fa fa-user-md"></i>
-        <div class="icon-title">fa-user-md</div>
-    </li>
-    <li>
-        <i class="fa fa-wheelchair"></i>
-        <div class="icon-title">fa-wheelchair</div>
-    </li>
-    <li>
-        <i class="fa fa-wheelchair-alt"></i>
-        <div class="icon-title">fa-wheelchair-alt</div>
-    </li>
-</ul>
-
-<script src="__ROOT__/static/plugs/jquery/jquery.min.js" type="text/javascript"></script>
-<script>
-    $(function () {
-        $('li').on('click', function () {
-            let className = $(this).find('i').get(0).className;
-            if (className) {
-                top.$('[name="{$field}"]').val(className).trigger('change');
-                top.layer.close(top.layer.getFrameIndex(window.name));
-            }
-        });
-    });
-</script>
-
-</body>
-</html>

+ 0 - 554
application/admin/view/plugs/upfile.html

@@ -1,554 +0,0 @@
-<!DOCTYPE html>
-<html lang="zh-CN">
-    <head>
-        <title>{:sysconf('app_name')} {:sysconf('app_version')}</title>
-        <meta charset="utf-8">
-        <link rel="icon" href="../image/favicon.ico">
-        <meta http-equiv="X-UA-Compatible" content="IE=edge">
-        <meta name="viewport" content="width=device-width, initial-scale=0">
-        <link href="__STATIC__/plugs/uploader/webuploader.css" rel="stylesheet" type="text/css"/>
-        <link href="__STATIC__/plugs/uploader/theme/uploader.css" rel="stylesheet" type="text/css"/>
-        <script src="__STATIC__/plugs/jquery/jquery.min.js"></script>
-        <script src="__STATIC__/plugs/uploader/webuploader.min.js"></script>
-        <script src="__STATIC__/plugs/uploader/theme/upload.js"></script>
-    </head>
-    <body>
-        <div id="uploader">
-            <div class="queueList">
-                <div id="dndArea" class="placeholder">
-                    <div id="filePicker"></div>
-                </div>
-            </div>
-            <div class="statusBar" style="display:none;">
-                <div class="progress">
-                    <span class="text">0%</span>
-                    <span class="percentage"></span>
-                </div>
-                <div class="info"></div>
-                <div class="btns">
-                    {if $mode!=='one'}
-                    <div id="filePicker2"></div>
-                    {/if}
-                    <div class="uploadBtn">开始上传</div>
-                </div>
-            </div>
-        </div>
-        <script>
-            /* global WebUploader */
-
-            /**
-             * 每个文件上传成功调用
-             * @type Function
-             */
-            function uploaded(ret, file) {
-                var url = ret.url || ret.site_url;
-                $('#' + file.id).attr('data-md5', file.md5).attr('data-src', url);
-                /*{if $mode === 'one'}*/
-                top.$('[name="{$field}"]').map(function () {
-                    top.$(this).attr('data-srcs', ret.url).attr('data-md5', file.md5).val(url).trigger('change');
-                });
-                top.layer.close(top.layer.getFrameIndex(window.name));
-                /*{/if}*/
-            }
-
-            var isSuccessState = false;
-
-            function completed() {
-                var btnHTML = '完成上传';
-                $('.uploadBtn').html(btnHTML).on('click', successSelected);
-
-                function successSelected() {
-                    if (!isSuccessState && this.innerHTML === btnHTML) {
-                        isSuccessState = true;
-                        var srcs = [], md5s = [];
-                        $('[data-md5] .success').map(function () {
-                            var $li = $(this).parents('[data-md5]');
-                            md5s.push($li.attr('data-md5'));
-                            srcs.push($li.attr('data-src'));
-                        });
-                        if (srcs.length < 1) {
-                            return top.$.msg.tips('还没有选择文件,请勾选需要使用的文件!');
-                        }
-                        top.$('[name="{$field}"]').map(function () {
-                            top.$(this).attr('data-srcs', srcs.join('|')).attr('data-md5', md5s.join('|')).val(srcs.join('|')).trigger('change');
-                        });
-                        top.layer.close(top.layer.getFrameIndex(window.name));
-                    }
-                }
-            }
-
-            // 当domReady的时候开始初始化
-            $(function () {
-                var $wrap = $('#uploader'),
-                        /*文件容器*/
-                        $queue = $('<ul class="filelist"></ul>').appendTo($wrap.find('.queueList')),
-                        /*状态栏,包括进度和控制按钮*/
-                        $statusBar = $wrap.find('.statusBar'),
-                        /*文件总体选择信息。*/
-                        $info = $statusBar.find('.info'),
-                        /*上传按钮*/
-                        $upload = $wrap.find('.uploadBtn'),
-                        /*没选择文件之前的内容。*/
-                        $placeHolder = $wrap.find('.placeholder'),
-                        $progress = $statusBar.find('.progress').hide(),
-                        /* 添加的文件数量*/
-                        fileCount = 0,
-                        /*添加的文件总大小*/
-                        fileSize = 0,
-                        /*优化retina, 在retina下这个值是2*/
-                        ratio = window.devicePixelRatio || 1,
-                        /*缩略图大小*/
-                        thumbnailWidth = 110 * ratio, thumbnailHeight = 110 * ratio,
-                        /*可能有pedding, ready, uploading, confirm, done.*/
-                        state = 'pedding',
-                        /*所有文件的进度信息,key为file id*/
-                        percentages = {},
-                        /*判断浏览器是否支持文件的base64*/
-                        isSupportBase64 = (function () {
-                            var data = new Image();
-                            var support = true;
-                            data.onload = data.onerror = function () {
-                                if (this.width != 1 || this.height != 1) {
-                                    support = false;
-                                }
-                            };
-                            data.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
-                            return support;
-                        }.call(this)),
-                        /*检测是否已经安装flash,检测flash的版本*/
-                        flashVersion = (function () {
-                            var version;
-                            try {
-                                version = navigator.plugins['Shockwave Flash'];
-                                version = version.description;
-                            } catch (ex) {
-                                try {
-                                    version = new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version');
-                                } catch (ex2) {
-                                    version = '0.0';
-                                }
-                            }
-                            version = version.match(/\d+/g);
-                            return parseFloat(version[0] + '.' + version[1], 10);
-                        })(),
-                        supportTransition = (function () {
-                            var s = document.createElement('p').style,
-                                    r = 'transition' in s || 'WebkitTransition' in s || 'MozTransition' in s || 'msTransition' in s || 'OTransition' in s;
-                            return (s = null), r;
-                        })(),
-                        uploader;
-                if (!WebUploader.Uploader.support('flash') && WebUploader.browser.ie) {
-                    /*flash 安装了但是版本过低*/
-                    if (flashVersion) {
-                        (function (container) {
-                            window['expressinstallcallback'] = function (state) {
-                                switch (state) {
-                                    case 'Download.Cancelled':
-                                        alert('您取消了更新!');
-                                        break;
-                                    case 'Download.Failed':
-                                        alert('安装失败');
-                                        break;
-                                    default:
-                                        alert('安装已成功,请刷新!');
-                                        break;
-                                }
-                                delete window['expressinstallcallback'];
-                            };
-                            var swf = '__STATIC__/plugs/uploader/expressInstall.swf';
-                            var html = '<object type="application/' + 'x-shockwave-flash" data="' + swf + '" ';
-                            if (WebUploader.browser.ie) {
-                                html += 'classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" ';
-                            }
-                            html += 'width="100%" height="100%" style="outline:0">' +
-                                    '<param name="movie" value="' + swf + '" />' +
-                                    '<param name="wmode" value="transparent" />' +
-                                    '<param name="allowscriptaccess" value="always" />' +
-                                    '</object>';
-                            container.html(html);
-                        })($wrap);
-                    } else {
-                        $wrap.html('<a href="http://www.adobe.com/go/getflashplayer" target="_blank" border="0"><img alt="get flash player" src="http://www.adobe.com/macromedia/style_guide/images/160x41_Get_Flash_Player.jpg" /></a>');
-                    }
-                    return;
-                } else if (!WebUploader.Uploader.support()) {
-                    alert('Web Uploader 不支持您的浏览器!');
-                    return;
-                }
-                // 文件上传前的检查
-                WebUploader.Uploader.register({'before-send-file': 'preupload'}, {
-                    preupload: function (file) {
-                        var me = this, owner = this.owner, deferred = WebUploader.Deferred();
-                        owner.md5File(file.source).fail(function () {
-                            deferred.reject();
-                        }).then(function (md5) {
-                            file.md5 = md5;
-                            var data = {id: file.id, md5: md5, uptype: '{$uptype}', filename: file.name};
-                            $.ajax("{:url('admin/plugs/upstate')}", {
-                                dataType: 'json', method: 'post', data: data, success: function (ret) {
-                                    if (ret.code !== 'NOT_FOUND') {
-                                        owner.skipFile(file);
-                                        uploaded.call(uploader, ret.data, file);
-                                        percentages[file.id] = [file.size, 1];
-                                        updateTotalProgress();
-                                        console.log('文件秒传成功 --> ' + file.name);
-                                    } else {
-                                        file.md5 = md5;
-                                        file.token = ret.data.token || '';
-                                        file.key = ret.data.file_url || '';
-                                        file.site_url = ret.data.site_url || '';
-                                        me.options.formData.OSSAccessKeyId = ret.data.OSSAccessKeyId || ''; // OSS
-                                        me.options.formData.signature = ret.data.signature; // OSS
-                                        me.options.formData.policy = ret.data.policy; // OSS
-                                        me.options.formData.success_action_status = '200'; // OSS
-                                        me.options.server = ret.data.server;
-                                    }
-                                    deferred.resolve();
-                                }
-                            });
-                        });
-                        return deferred.promise();
-                    }
-                });
-
-                // 实例化
-                uploader = WebUploader.create({
-                    pick: {
-                        id: '#filePicker',
-                        label: '点击选择文件',
-                        /*{if $mode === 'one'}*/
-                        multiple: false,
-                        /*{else}*/
-                        multiple: true,
-                        /*{/if}*/
-                    },
-                    accept: {title: '选择文件', extensions: '{$types}', mimeTypes: '{$mimes}'},
-                    formData: {},
-                    /*{if $mode === 'one'}*/
-                    auto: true,
-                    fileNumLimit: 1,
-                    /*{else}*/
-                    auto: false,
-                    fileNumLimit: 300,
-                    /*{/if}*/
-                    server: '{:url("admin/plugs/upload")}',
-                    swf: '__STATIC__/plugs/uploader/Uploader.swf',
-                    chunked: false,
-                    dnd: '#dndArea',
-                    paste: document.body,
-                    chunkSize: 512 * 1024,
-                    disableGlobalDnd: true,
-                    fileSizeLimit: 200 * 1024 * 1024, // 200 M
-                    fileSingleSizeLimit: 200 * 1024 * 1024, // 200 M
-                    compress: {
-                        width: 1600,
-                        height: 16000,
-                        crop: false, // 是否允许裁剪
-                        quality: 90, // 图片质量(只有type为`image/jpeg`的时候才有效)
-                        allowMagnify: false, // 是否允许放大(如果想要生成小图的时候不失真,此选项应该设置为false).
-                        preserveHeaders: true, // 是否保留头部meta信息
-                        noCompressIfLarger: false, // 如果发现压缩后文件大小比原来还大,则使用原来图片
-                        compressSize: 1024 * 512, // 单位字节(如果图片大小小于此值,不会采用压缩)
-                    }
-                });
-
-                /* 上传开始前的处理 */
-                uploader.on('uploadBeforeSend', function (file, data, header) {
-                    header['X_Requested_With'] = 'XMLHttpRequest';
-                    data['allowed_types'] = this.options.accept[0].extensions.split(',').join('|');
-                    data['token'] = file.file.token;
-                    data['md5'] = file.file.md5;
-                    data['key'] = file.file.key;
-                });
-
-                /* 处理上传后的结果 */
-                uploader.on('uploadAccept', function (fieldata, ret) {
-                    // Qiniu or Local 上传
-                    if (ret.code === 'SUCCESS') {
-                        uploaded.call(uploader, ret.data, fieldata.file);
-                        return true;
-                    }
-                    // AliOSS 上传
-                    if (fieldata.file.site_url) {
-                        uploaded.call(uploader, {'site_url': fieldata.file.site_url}, fieldata.file);
-                        return true;
-                    }
-                    // 接收服务器返回的错误消息
-                    fieldata.file.setStatus('error', ret.msg);
-                    return false;
-                });
-
-                // 拖拽时不接受 js, txt 文件。
-                uploader.on('dndAccept', function (items) {
-                    var denied = false, len = items.length, unAllowed = 'text/plain;application/javascript ';
-                    for (var i = 0; i < len; i++) {
-                        if (~unAllowed.indexOf(items[i].type)) {
-                            denied = true;
-                            break;
-                        }
-                    }
-                    return !denied;
-                });
-
-                // 添加“添加文件”的按钮,
-                uploader.addButton({id: '#filePicker2', label: '继续添加'});
-                uploader.on('ready', function () {
-                    window.uploader = uploader;
-                });
-
-                // 当有文件添加进来时执行,负责view的创建
-                function addFile(file) {
-                    var $li = $('<li id="' + file.id + '"><p class="title">' + file.name + '</p><p class="imgWrap"></p><p class="progress"><span></span></p></li>'),
-                            $btns = $('<div class="file-panel"><span class="cancel">删除</span><span class="rotateRight">向右旋转</span><span class="rotateLeft">向左旋转</span></div>').appendTo($li),
-                            $prgress = $li.find('p.progress span'), $wrap = $li.find('p.imgWrap'), $info = $('<p class="error"></p>');
-                    var showError = function (code) {
-                        var text = '';
-                        switch (code) {
-                            case 'exceed_size':
-                                text = '文件大小超出';
-                                break;
-                            case 'interrupt':
-                                text = '上传暂停';
-                                break;
-                            case 'http':
-                            case 'server':
-                            case 'abort':
-                                text = '上传失败,请重试';
-                                break;
-                            default:
-                                text = code;
-                                break;
-                        }
-                        $info.text(text).appendTo($li);
-                    };
-                    if (file.getStatus() === 'invalid') {
-                        showError(file.statusText);
-                    } else {
-                        // @todo lazyload
-                        $wrap.text('预览中');
-                        uploader.makeThumb(file, function (error, src) {
-                            if (error) {
-                                return $wrap.text('不能预览');
-                            }
-                            var img;
-                            if (isSupportBase64) {
-                                img = $('<img src="' + src + '">');
-                                $wrap.empty().append(img);
-                            } else {
-                                $.ajax('{"plugs/file/preview"|url}', {method: 'post', data: src, dataType: 'json'}).done(function (response) {
-                                    if (response.result) {
-                                        img = $('<img src="' + response.result + '">');
-                                        $wrap.empty().append(img);
-                                    } else {
-                                        $wrap.text("预览出错");
-                                    }
-                                });
-                            }
-                        }, thumbnailWidth, thumbnailHeight);
-                        percentages[file.id] = [file.size, 0];
-                        file.rotation = 0;
-                        $upload.html('开始上传');
-                    }
-                    // 文件上传状态变化
-                    file.on('statuschange', function (cur, prev) {
-                        if (prev === 'progress') {
-                            $prgress.hide().width(0);
-                        } else if (prev === 'queued') {
-                            $li.off('mouseenter mouseleave'), $btns.remove();
-                        }
-                        if (cur === 'error' || cur === 'invalid') {
-                            showError(file.statusText);
-                            percentages[file.id][1] = 1;
-                        } else if (cur === 'interrupt') {
-                            showError('interrupt');
-                        } else if (cur === 'queued') {
-                            percentages[file.id][1] = 0;
-                        } else if (cur === 'progress') {
-                            $info.remove(), $prgress.css('display', 'block');
-                        } else if (cur === 'complete') {
-                            $li.append('<span class="success"></span>');
-                        }
-                        $li.removeClass('state-' + prev).addClass('state-' + cur);
-                    });
-                    $li.on('mouseenter', function () {
-                        $btns.stop().animate({height: 30});
-                    }).on('mouseleave', function () {
-                        $btns.stop().animate({height: 0});
-                    });
-                    $btns.on('click', 'span', function () {
-                        switch ($(this).index()) {
-                            case 0:
-                                removeFile(file);
-                                return uploader.removeFile(file);
-                            case 1:
-                                file.rotation += 90;
-                                break;
-                            case 2:
-                                file.rotation -= 90;
-                                break;
-                        }
-                        if (supportTransition) {
-                            var deg = 'rotate(' + file.rotation + 'deg)';
-                            $wrap.css({'-webkit-transform': deg, '-mos-transform': deg, '-o-transform': deg, 'transform': deg});
-                        } else {
-                            $wrap.css('filter', 'progid:DXImageTransform.Microsoft.BasicImage(rotation=' + (~~((file.rotation / 90) % 4 + 4) % 4) + ')');
-                        }
-                    });
-                    $li.appendTo($queue);
-                }
-
-                // 负责view的销毁
-                function removeFile(file) {
-                    delete percentages[file.id];
-                    updateTotalProgress();
-                    $('#' + file.id).off().find('.file-panel').off().end().remove();
-                }
-
-                function updateTotalProgress() {
-                    var loaded = 0, total = 0, spans = $progress.children(), percent;
-                    $.each(percentages, function (k, v) {
-                        total += v[0];
-                        loaded += v[0] * v[1];
-                    });
-                    percent = total ? loaded / total : 0;
-                    spans.eq(0).text(Math.round(percent * 100) + '%');
-                    spans.eq(1).css('width', Math.round(percent * 100) + '%');
-                    updateStatus();
-                }
-
-                function updateStatus() {
-                    var text = '', stats;
-                    if (state === 'ready') {
-                        text = '选中' + fileCount + '个文件,共' + WebUploader.formatSize(fileSize) + '。';
-                    } else if (state === 'confirm') {
-                        stats = uploader.getStats();
-                        if (stats.uploadFailNum) {
-                            text = '已成功上传' + stats.successNum + '个文件,' + stats.uploadFailNum + '个文件上传失败,<a class="retry" href="#">重新上传</a>失败文件'
-                        }
-                    } else {
-                        stats = uploader.getStats();
-                        text = '共' + fileCount + '个(' + WebUploader.formatSize(fileSize) + '),已上传' + stats.successNum + '个';
-                        if (stats.uploadFailNum) {
-                            text += ',失败' + stats.uploadFailNum + '个';
-                        }
-                    }
-                    $info.html(text);
-                }
-
-                function setState(val) {
-                    var stats;
-                    if (val === state) {
-                        return;
-                    }
-                    $upload.removeClass('state-' + state);
-                    $upload.addClass('state-' + val);
-                    state = val;
-                    switch (state) {
-                        case 'pedding':
-                            $placeHolder.removeClass('element-invisible');
-                            $queue.hide();
-                            $statusBar.addClass('element-invisible');
-                            uploader.refresh();
-                            break;
-                        case 'ready':
-                            $placeHolder.addClass('element-invisible');
-                            $('#filePicker2').removeClass('element-invisible');
-                            $queue.show();
-                            $statusBar.removeClass('element-invisible');
-                            uploader.refresh();
-                            break;
-                        case 'uploading':
-                            $('#filePicker2').addClass('element-invisible');
-                            $progress.show();
-                            $upload.text('暂停上传');
-                            break;
-                        case 'paused':
-                            $progress.show();
-                            $upload.text('继续上传');
-                            break;
-                        case 'confirm':
-                            $progress.hide();
-                            $('#filePicker2').removeClass('element-invisible');
-                            $upload.text('开始上传');
-                            stats = uploader.getStats();
-                            if (stats.successNum && !stats.uploadFailNum) {
-                                setState('finish');
-                                return;
-                            }
-                            break;
-                        case 'finish':
-                            stats = uploader.getStats();
-                            if (stats.successNum) {
-                                completed.call(this);
-                            } else {
-                                state = 'done';
-                                location.reload();
-                            }
-                            break;
-                    }
-                    updateStatus();
-                }
-
-                uploader.onUploadProgress = function (file, percentage) {
-                    var $li = $('#' + file.id), $percent = $li.find('.progress span');
-                    $percent.css('width', percentage * 100 + '%');
-                    percentages[file.id][1] = percentage;
-                    updateTotalProgress();
-                };
-
-                uploader.onFileQueued = function (file) {
-                    fileCount++;
-                    fileSize += file.size;
-                    if (fileCount === 1) {
-                        $placeHolder.addClass('element-invisible');
-                        $statusBar.show();
-                    }
-                    addFile(file), setState('ready'), updateTotalProgress();
-                };
-
-                uploader.onfieldequeued = function (file) {
-                    fileCount--;
-                    fileSize -= file.size;
-                    !fileCount && setState('pedding');
-                    removeFile(file), updateTotalProgress();
-                };
-
-                uploader.on('all', function (type) {
-                    switch (type) {
-                        case 'uploadFinished':
-                            return setState('confirm');
-                        case 'startUpload':
-                            return setState('uploading');
-                        case 'stopUpload':
-                            return setState('paused');
-                    }
-                });
-
-                uploader.onError = function (code) {
-                    // 000alert('Error: ' + code);
-                };
-
-                $upload.on('click', function () {
-                    if ($(this).hasClass('disabled')) {
-                        return false;
-                    }
-                    if (state === 'ready') {
-                        uploader.upload();
-                    } else if (state === 'paused') {
-                        uploader.upload();
-                    } else if (state === 'uploading') {
-                        uploader.stop();
-                    }
-                });
-
-                $info.on('click', '.retry', function () {
-                    uploader.retry();
-                });
-
-                $upload.addClass('state-' + state);
-                updateTotalProgress();
-            });
-
-        </script>
-    </body>
-</html>

+ 0 - 13
application/admin/view/public/content.html

@@ -1,13 +0,0 @@
-<!-- 右则内容区域 开始 -->
-{block name="style"}{/block}
-<div class="layui-card">
-    <!--{notempty name='title'}-->
-    <div class="layui-header notselect">
-        <div class="pull-left"><span>{$title}</span></div>
-        <div class="pull-right margin-right-15 nowrap">{block name="button"}{/block}</div>
-    </div>
-    <!--{/notempty}-->
-    <div class="layui-card-body">{block name='content'}{/block}</div>
-</div>
-{block name='script'}{/block}
-<!-- 右则内容区域 结束 -->

+ 0 - 26
application/admin/view/public/main.html

@@ -1,26 +0,0 @@
-<!DOCTYPE html>
-<html lang="zh-cn">
-    <head>
-        <meta charset="utf-8">
-        <meta name="renderer" content="webkit">
-        <title>{block name="title"}{$title|default=''}{if !empty($title)} · {/if}{:sysconf('site_name')}{/block}</title>
-        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
-        <link href="{:sysconf('browser_icon')}" rel="shortcut icon">
-        <link href="__STATIC__/plugs/awesome/css/font-awesome.min.css?v={:date('ymd')}" rel="stylesheet">
-        <link href="__STATIC__/plugs/bootstrap/css/bootstrap.min.css?v={:date('ymd')}" rel="stylesheet">
-        <link href="__STATIC__/plugs/layui/css/layui.css?v={:date('ymd')}" rel="stylesheet">
-        <link href="__STATIC__/theme/css/console.css?v={:date('ymd')}" rel="stylesheet">
-        <link href="__STATIC__/theme/css/animate.css?v={:date('ymd')}" rel="stylesheet">
-        {block name="style"}{/block}
-        <script>window.ROOT_URL = '__ROOT__';</script>
-        <script src="__STATIC__/plugs/jquery/pace.min.js"></script>
-        <script src="__STATIC__/plugs/layui/layui.all.js"></script>
-        <script src="__STATIC__/admin.js"></script>
-    </head>
-    <body class="framework mini">
-        {block name="body"}{/block}
-        <script src="__STATIC__/plugs/require/require.js"></script>
-        <script src="__STATIC__/app.js"></script>
-        {block name="script"}{/block}
-    </body>
-</html>

+ 78 - 0
application/admin/view/queue/index.html

@@ -0,0 +1,78 @@
+{extend name='main'}
+
+{block name="button"}
+
+<!--{if auth("admin/queue/del")}-->
+<button data-action='{:url("del")}' data-confirm="确定要删除这些任务吗?" data-rule="id#{key}" class='layui-btn layui-btn-sm layui-btn-primary'>批量删除任务</button>
+<!--{/if}-->
+
+{/block}
+
+{block name="content"}
+<table class="layui-table" lay-skin="line">
+    <caption class="margin-bottom-10 text-left">{include file='queue/index_search'}</caption>
+    <!--{notempty name='list'}-->
+    <thead>
+    <tr>
+        <th class='list-table-check-td think-checkbox'>
+            <input data-auto-none data-check-target='.list-check-box' type='checkbox'>
+        </th>
+        <th class='text-left nowrap'>任务信息</th>
+        <th class='text-left nowrap'>任务时间</th>
+        <th class='text-left nowrap'>任务状态</th>
+    </tr>
+    </thead>
+    <!--{/notempty}-->
+    <tbody>
+    <!--{foreach $list as $key=>$vo}-->
+    <tr>
+        <td class='list-table-check-td think-checkbox'>
+            <input class="list-check-box" value='{$vo.id}' type='checkbox'>
+        </td>
+        <td class='text-left nowrap'>
+            任务名称:{$vo.title}
+            <br>
+            任务指令:{$vo.uri}
+        </td>
+        <td class='text-left nowrap'>
+            创建时间:<span class="layui-badge layui-bg-gray">{$vo.create_at|format_datetime|raw}</span>
+            <br>
+            跟进时间:<span class="layui-badge layui-bg-gray">{$vo.status_at|format_datetime|raw}</span>
+        </td>
+        <td class='text-left nowrap'>
+            任务状态:
+            {eq name='vo.double' value='1'}
+            <span class="layui-badge layui-bg-green margin-right-5">复</span>
+            {else}
+            <span class="layui-badge layui-bg-blue margin-right-5">单</span>
+            {/eq}
+
+            {eq name='vo.status' value='1'}
+            <span class="layui-badge layui-bg-black">待处理</span>
+            {elseif $vo.status eq 2}
+            <span class="layui-badge layui-bg-green">处理中</span>
+            {elseif $vo.status eq 3}
+            <span class="layui-badge layui-bg-blue">处理完成</span>
+            {elseif $vo.status eq 4}
+            <span class="layui-badge layui-bg-red margin-right-5">处理失败</span>
+            <a class="layui-badge layui-bg-green" data-tips-text="重置该任务" data-action="{:url('redo')}" data-value="id#{$vo.id}">
+                <i class="layui-icon font-s12">&#xe669;</i>
+            </a>
+            {/eq}
+            <!--{if auth("admin/queue/del") and in_array($vo.status,[1,3,4])}-->
+            <a data-action='{:url("del")}' data-confirm="确定要删除该任务吗?" data-value="id#{$vo.id}" data-tips-text="删除该任务" class='layui-badge layui-bg-red margin-left-5'>
+                <i class="layui-icon">&#xe640;</i>
+            </a>
+            <!--{/if}-->
+            <br>
+            状态描述:
+            <span class="layui-badge layui-bg-gray">{$vo.status_desc|raw|default="<span class='color-desc'>没有获取到状态描述</span>"}</span>
+        </td>
+    </tr>
+    <!--{/foreach}-->
+    </tbody>
+</table>
+
+{empty name='list'}<span class="notdata">没有记录哦</span>{else}{$pagehtml|raw|default=''}{/empty}
+
+{/block}

+ 68 - 0
application/admin/view/queue/index_search.html

@@ -0,0 +1,68 @@
+{if session('user.username') eq 'admin'}
+<fieldset class="margin-bottom-10">
+    <legend class="layui-bg-cyan">进程守护</legend>
+    <div class="layui-code border-0 margin-top-0">
+        <p class="color-desc margin-top-10">当前消息队列守护进程运行状态</p>
+        {$message|raw|default='--'}
+        <p class="color-desc margin-top-10">配置定时任务来检查并启动进程(建议每分钟执行)</p>
+        {$cmd|default='--'}
+    </div>
+</fieldset>
+{/if}
+<fieldset>
+    <legend class="layui-bg-cyan">条件搜索</legend>
+    <form class="layui-form layui-form-pane form-search" action="{:request()->url()}" onsubmit="return false" method="get" autocomplete="off">
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">任务名称</label>
+            <div class="layui-input-inline">
+                <input name="title" value="{$Think.get.title|default=''}" placeholder="请输入任务名称" class="layui-input">
+            </div>
+        </div>
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">任务指令</label>
+            <div class="layui-input-inline">
+                <select class="layui-select" name="uri" lay-search>
+                    <option value="">-- 全部 --</option>
+                    {foreach $uris as $uri}
+                    <!--{eq name='Think.get.uri' value='$uri'}-->
+                    <option selected value="{$uri}">{$uri}</option>
+                    <!--{else}-->
+                    <option value="{$uri}">{$uri}</option>
+                    <!--{/eq}-->
+                    {/foreach}
+                </select>
+            </div>
+        </div>
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">任务状态</label>
+            <div class="layui-input-inline">
+                <select name="status" class="layui-select">
+                    {foreach [''=>'-- 全部 --','1'=>'待处理','2'=>'处理中','3'=>'处理完成','4'=>'处理失败'] as $k=>$v}
+                    <!--{if $Think.get.status eq $k}-->
+                    <option selected value="{$k}">{$v}</option>
+                    <!--{else}-->
+                    <option value="{$k}">{$v}</option>
+                    <!--{/if}-->
+                    {/foreach}
+                </select>
+            </div>
+        </div>
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">创建时间</label>
+            <div class="layui-input-inline">
+                <input data-date-range name="create_at" value="{$Think.get.create_at|default=''}" placeholder="请选择创建时间" class="layui-input">
+            </div>
+        </div>
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">跟进时间</label>
+            <div class="layui-input-inline">
+                <input data-date-range name="status_at" value="{$Think.get.status_at|default=''}" placeholder="请选择跟进时间" class="layui-input">
+            </div>
+        </div>
+        <div class="layui-form-item layui-inline">
+            <button class="layui-btn layui-btn-primary"><i class="layui-icon">&#xe615;</i> 搜 索</button>
+        </div>
+    </form>
+</fieldset>
+
+<script>form.render()</script>

+ 27 - 28
application/admin/view/user/auth.html

@@ -1,39 +1,38 @@
-<form autocomplete="off" class="layui-form layui-box modal-form-box" action="{:request()->url()}" data-auto="true" method="post">
-
-    <div class="layui-form-item">
-        <label class="layui-form-label">用户账号</label>
-        <div class="layui-input-block">
-            {if $vo and $vo.username}
-            <input type="text" readonly="" disabled="" name="username" value='{$vo.username|default=""}' required="required" title="请输入用户名称" placeholder="请输入用户名称" class="layui-input layui-bg-gray">
-            {else}
-            <input type="text" name="username" value='{$vo.username|default=""}' required="required" title="请输入用户名称" placeholder="请输入用户名称" class="layui-input">
-            {/if}
-        </div>
-    </div>
-
-    <div class="layui-form-item">
-        <label class="layui-form-label">访问授权</label>
-        <div class="layui-input-block">
-            {foreach $authorizes as $authorize}
-            <label class="think-checkbox">
-                <!--{if in_array($authorize['id'],$vo['authorize'])}-->
-                <input type="checkbox" checked name="authorize[]" value="{$authorize.id}" lay-ignore> {$authorize.title}
+<form class="layui-form layui-card" action="{:request()->url()}" data-auto="true" method="post" autocomplete="off">
+    <div class="layui-card-body">
+        <div class="layui-form-item">
+            <label class="layui-form-label">用户账号</label>
+            <div class="layui-input-block">
+                <!--{if isset($vo) and isset($vo.username)}-->
+                <input type="text" disabled value='{$vo.username|default=""}' class="layui-input layui-bg-gray">
                 <!--{else}-->
-                <input type="checkbox" name="authorize[]" value="{$authorize.id}" lay-ignore> {$authorize.title}
+                <input type="text" name="username" value='{$vo.username|default=""}' required placeholder="请输入用户名称" class="layui-input">
                 <!--{/if}-->
-            </label>
-            {/foreach}
-            {if empty($authorizes)}<span class="color-desc" style="line-height:36px">未配置权限</span>{/if}
+            </div>
+        </div>
+        <div class="layui-form-item">
+            <label class="layui-form-label">访问授权</label>
+            <div class="layui-input-block">
+                {foreach $authorizes as $authorize}
+                <label class="think-checkbox">
+                    <!--{if in_array($authorize['id'],$vo['authorize'])}-->
+                    <input type="checkbox" checked name="authorize[]" value="{$authorize.id}" lay-ignore> {$authorize.title}
+                    <!--{else}-->
+                    <input type="checkbox" name="authorize[]" value="{$authorize.id}" lay-ignore> {$authorize.title}
+                    <!--{/if}-->
+                </label>
+                {/foreach}
+                {if empty($authorizes)}<span class="color-desc" style="line-height:36px">未配置权限</span>{/if}
+            </div>
         </div>
     </div>
-
     <div class="hr-line-dashed"></div>
-
     <div class="layui-form-item text-center">
-        {if isset($vo['id'])}<input type='hidden' value='{$vo.id}' name='id'>{/if}
+        <!--{notempty name='vo.id'}-->
+        <input type='hidden' value='{$vo.id}' name='id'>
+        <!--{/notempty}-->
         <button class="layui-btn" type='submit'>保存数据</button>
         <button class="layui-btn layui-btn-danger" type='button' data-confirm="确定要取消编辑吗?" data-close>取消编辑</button>
     </div>
-
     <script>window.form.render();</script>
 </form>

+ 45 - 48
application/admin/view/user/form.html

@@ -1,59 +1,56 @@
-<form autocomplete="off" class="layui-form layui-box modal-form-box" action="{:request()->url()}" data-auto="true" method="post">
-
-    <div class="layui-form-item">
-        <label class="layui-form-label">用户账号</label>
-        <div class="layui-input-block">
-            {if $vo and isset($vo.username)}
-            <input readonly="readonly" disabled="disabled" name="username" value='{$vo.username|default=""}' required="required" title="请输入用户名称" placeholder="请输入用户名称" class="layui-input layui-bg-gray">
-            {else}
-            <input name="username" value='{$vo.username|default=""}' required="required" pattern="^.{4,}$" title="请输入用户名称" placeholder="请输入4位及以上字符用户名称" class="layui-input">
-            {/if}
+<form class="layui-form layui-card" action="{:request()->url()}" data-auto="true" method="post" autocomplete="off">
+    <div class="layui-card-body">
+        <div class="layui-form-item">
+            <label class="layui-form-label label-required">用户账号</label>
+            <div class="layui-input-block">
+                <!--{if $vo and isset($vo.username)}-->
+                <input disabled value='{$vo.username|default=""}' class="layui-input layui-bg-gray">
+                <!--{else}-->
+                <input name="username" value='{$vo.username|default=""}' required pattern="^.{4,}$" placeholder="请输入4位及以上字符用户名称" class="layui-input">
+                <!--{/if}-->
+            </div>
         </div>
-    </div>
-
-    <div class="layui-form-item">
-        <label class="layui-form-label">联系手机</label>
-        <div class="layui-input-block">
-            <input type="tel" autofocus name="phone" value='{$vo.phone|default=""}' pattern="^1[3-9][0-9]{9}$" title="请输入联系手机" placeholder="请输入联系手机" class="layui-input">
+        <div class="layui-form-item">
+            <label class="layui-form-label">联系手机</label>
+            <div class="layui-input-block">
+                <input type="tel" maxlength="11" autofocus name="phone" value='{$vo.phone|default=""}' pattern="^1[3-9][0-9]{9}$" placeholder="请输入联系手机" class="layui-input">
+            </div>
         </div>
-    </div>
-
-    <div class="layui-form-item">
-        <label class="layui-form-label">联系邮箱</label>
-        <div class="layui-input-block">
-            <input name="mail" pattern="^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$" value='{$vo.mail|default=""}' title="请输入联系邮箱" placeholder="请输入联系邮箱" class="layui-input">
+        <div class="layui-form-item">
+            <label class="layui-form-label">联系邮箱</label>
+            <div class="layui-input-block">
+                <input name="mail" pattern="^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$" value='{$vo.mail|default=""}' placeholder="请输入联系邮箱" class="layui-input">
+            </div>
         </div>
-    </div>
-
-    {if isset($authorizes)}
-    <div class="layui-form-item">
-        <label class="layui-form-label">访问授权</label>
-        <div class="layui-input-block">
-            {foreach $authorizes as $authorize}
-            <label class="think-checkbox">
-                <!--{if in_array($authorize['id'],$vo['authorize'])}-->
-                <input type="checkbox" checked name="authorize[]" value="{$authorize.id}" lay-ignore> {$authorize.title}
-                <!--{else}-->
-                <input type="checkbox" name="authorize[]" value="{$authorize.id}" lay-ignore> {$authorize.title}
-                <!--{/if}-->
-            </label>
-            {/foreach}
-            {if empty($authorizes)}<span class="color-desc" style="line-height:36px">未配置权限</span>{/if}
+        <!--{if isset($authorizes)}-->
+        <div class="layui-form-item">
+            <label class="layui-form-label">访问授权</label>
+            <div class="layui-input-block">
+                {foreach $authorizes as $authorize}
+                <label class="think-checkbox">
+                    <!--{if in_array($authorize['id'],$vo['authorize'])}-->
+                    <input type="checkbox" checked name="authorize[]" value="{$authorize.id}" lay-ignore> {$authorize.title}
+                    <!--{else}-->
+                    <input type="checkbox" name="authorize[]" value="{$authorize.id}" lay-ignore> {$authorize.title}
+                    <!--{/if}-->
+                </label>
+                {/foreach}
+                {if empty($authorizes)}<span class="color-desc" style="line-height:36px">未配置权限</span>{/if}
+            </div>
         </div>
-    </div>
-    {/if}
-
-    <div class="layui-form-item">
-        <label class="layui-form-label">用户描述</label>
-        <div class="layui-input-block">
-            <textarea placeholder="请输入用户描述" title="请输入用户描述" class="layui-textarea" name="desc">{$vo.desc|default=""}</textarea>
+        <!--{/if}-->
+        <div class="layui-form-item">
+            <label class="layui-form-label">用户描述</label>
+            <div class="layui-input-block">
+                <textarea placeholder="请输入用户描述" class="layui-textarea" name="desc">{$vo.desc|default=""}</textarea>
+            </div>
         </div>
     </div>
-
     <div class="hr-line-dashed"></div>
-
     <div class="layui-form-item text-center">
-        {if isset($vo['id'])}<input type='hidden' value='{$vo.id}' name='id'>{/if}
+        <!--{notempty name='vo.id'}-->
+        <input type='hidden' value='{$vo.id}' name='id'>
+        <!--{/notempty}-->
         <button class="layui-btn" type='submit'>保存数据</button>
         <button class="layui-btn layui-btn-danger" type='button' data-confirm="确定要取消编辑吗?" data-close>取消编辑</button>
     </div>

+ 70 - 128
application/admin/view/user/index.html

@@ -1,136 +1,78 @@
-{extend name='admin@public/content'}
+{extend name='main'}
 
 {block name="button"}
-<!--{if auth("$classuri/add")}-->
-<button data-modal='{:url("$classuri/add")}' data-title="添加用户" class='layui-btn layui-btn-sm layui-btn-primary'>添加用户</button>
-<!--{/if}-->
 
-<!--{if auth("$classuri/del")}-->
-<button data-update data-field='delete' data-action='{:url("$classuri/del")}' class='layui-btn layui-btn-sm layui-btn-primary'>删除用户</button>
-<!--{/if}-->
-{/block}
-
-{block name="content"}
-
-<!-- 表单搜索 开始 -->
-<form autocomplete="off" class="layui-form layui-form-pane form-search" action="{:request()->url()}" onsubmit="return false" method="get">
-
-    <div class="layui-form-item layui-inline">
-        <label class="layui-form-label">用户账号</label>
-        <div class="layui-input-inline">
-            <input name="username" value="{$Think.get.username|default=''}" placeholder="请输入用户名" class="layui-input">
-        </div>
-    </div>
-
-    <div class="layui-form-item layui-inline">
-        <label class="layui-form-label">联系手机</label>
-        <div class="layui-input-inline">
-            <input name="phone" value="{$Think.get.phone|default=''}" placeholder="请输入联系手机" class="layui-input">
-        </div>
-    </div>
-
-    <div class="layui-form-item layui-inline">
-        <label class="layui-form-label">电子邮箱</label>
-        <div class="layui-input-inline">
-            <input name="mail" value="{$Think.get.mail|default=''}" placeholder="请输入电子邮箱" class="layui-input">
-        </div>
-    </div>
-
-    <div class="layui-form-item layui-inline">
-        <label class="layui-form-label">登录时间</label>
-        <div class="layui-input-inline">
-            <input name="date" id='range-date' value="{$Think.get.date|default=''}" placeholder="请选择登录时间" class="layui-input">
-        </div>
-    </div>
+{if auth("admin/user/add")}
+<button data-modal='{:url("add")}' data-title="添加用户" class='layui-btn layui-btn-sm layui-btn-primary'>添加用户</button>
+{/if}
 
-    <div class="layui-form-item layui-inline">
-        <button class="layui-btn layui-btn-primary"><i class="layui-icon">&#xe615;</i> 搜 索</button>
-    </div>
+{if auth("admin/user/del")}
+<button data-action='{:url("del")}' data-rule="id#{key}" data-csrf="{:systoken('admin/user/del')}" data-confirm="确定要删除这些用户吗?" class='layui-btn layui-btn-sm layui-btn-primary'>删除用户</button>
+{/if}
 
-</form>
-<script>
-    window.laydate.render({range: true, elem: '#range-date'});
-</script>
-<!-- 表单搜索 结束 -->
-
-<form onsubmit="return false;" data-auto="true" method="post">
-    <!--{empty name='list'}-->
-    <p class="help-block text-center well">没 有 记 录 哦!</p>
-    <!--{else}-->
-    <input type="hidden" value="resort" name="action">
-    <table class="layui-table" lay-skin="line">
-        <thead>
-        <tr>
-            <th class='list-table-check-td think-checkbox'>
-                <input data-auto-none="" data-check-target='.list-check-box' type='checkbox'>
-            </th>
-            <th class='text-left nowrap'>用户名</th>
-            <th class='text-left nowrap'>手机号</th>
-            <th class='text-left nowrap'>电子邮箱</th>
-            <th class='text-left nowrap'>登录次数</th>
-            <th class='text-left nowrap'>最后登录</th>
-            <th class='text-left nowrap'>状态</th>
-            <th class='text-left nowrap'></th>
-        </tr>
-        </thead>
-        <tbody>
-        <!--{foreach $list as $key=>$vo}-->
-        <tr>
-            <td class='list-table-check-td think-checkbox'>
-                <input class="list-check-box" value='{$vo.id}' type='checkbox'>
-            </td>
-            <td class='text-left nowrap'>
-                {$vo.username}
-            </td>
-            <td class='text-left nowrap'>
-                {$vo.phone|default="<span class='color-desc'>还没有设置手机号</span>"|raw}
-            </td>
-            <td class='text-left nowrap'>
-                {$vo.mail|default="<span class='color-desc'>还没有设置邮箱</span>"|raw}
-            </td>
-            <td class='text-left nowrap'>{$vo.login_num|default=0}</td>
-            <td class='text-left nowrap'>
-                {$vo.login_at|format_datetime|default="<span class='color-desc'>从未登录</span>"|raw}
-            </td>
-            <td class='text-left nowrap'>
-                {if $vo.status eq 0}<span class="color-red">已禁用</span>{elseif $vo.status eq 1}<span class="color-green">使用中</span>{/if}
-            </td>
-            <td class='text-left nowrap'>
-
-                {if auth("$classuri/edit")}
-                <span class="text-explode">|</span>
-                <a data-title="编辑用户" data-modal='{:url("$classuri/edit")}?id={$vo.id}'>编辑</a>
-                {/if}
-
-                {if auth("$classuri/auth")}
-                <span class="text-explode">|</span>
-                <a data-title="用户授权" data-modal='{:url("$classuri/auth")}?id={$vo.id}'>授权</a>
-                {/if}
-
-                {if auth("$classuri/pass")}
-                <span class="text-explode">|</span>
-                <a data-title="设置密码" data-modal='{:url("$classuri/pass")}?id={$vo.id}'>密码</a>
-                {/if}
-
-                {if $vo.status eq 1 and auth("$classuri/forbid")}
-                <span class="text-explode">|</span>
-                <a data-update="{$vo.id}" data-field='status' data-value='0' data-action='{:url("$classuri/forbid")}'>禁用</a>
-                {elseif auth("$classuri/resume")}
-                <span class="text-explode">|</span>
-                <a data-update="{$vo.id}" data-field='status' data-value='1' data-action='{:url("$classuri/resume")}'>启用</a>
-                {/if}
+{/block}
 
-                {if auth("$classuri/del")}
-                <span class="text-explode">|</span>
-                <a data-update="{$vo.id}" data-field='delete' data-action='{:url("$classuri/del")}'>删除</a>
-                {/if}
+{block name="content"}
+<table class="layui-table" lay-skin="line">
+    <caption class="margin-bottom-10 text-left">{include file='user/index_search'}</caption>
+    {notempty name='list'}
+    <thead>
+    <tr>
+        <th class='list-table-check-td think-checkbox'>
+            <input data-auto-none data-check-target='.list-check-box' type='checkbox'>
+        </th>
+        <th class='text-left nowrap' style="width:120px">用户名</th>
+        <th class='text-left nowrap' style="width:120px">账号状态</th>
+        <th class='text-left nowrap' style="width:180px">创建时间</th>
+        <th class='text-left nowrap' style="width:150px">最后登录</th>
+        <th class='text-left nowrap'></th>
+    </tr>
+    </thead>
+    {/notempty}
+    <tbody>
+    {foreach $list as $key=>$vo}
+    <tr data-dbclick>
+        <td class='list-table-check-td think-checkbox'><input class="list-check-box" value='{$vo.id}' type='checkbox'></td>
+        <td class='text-left nowrap'>
+            用户账号:{$vo.username|default=''}<br>
+            联系手机:{$vo.phone|default='--'}
+        </td>
+        <td class='text-left nowrap'>
+            登录次数:{$vo.login_num|default=0}<br>
+            使用状态:{eq name='vo.status' value='0'}<span class="layui-badge">已禁用</span>{else}<span class="layui-badge layui-bg-green">使用中</span>{/eq}
+        </td>
+        <td class='text-left nowrap'>日期:{$vo.create_at|format_datetime|str_replace=' ','<br>时间:',###|raw}</td>
+        <td class='text-left nowrap'>{if $vo.login_num>0}日期:{$vo.login_at|format_datetime|str_replace=' ','<br>时间:',###|raw}{else} -- {/if}</td>
+        <td class='text-left nowrap'>
+
+            {if auth("admin/user/auth")}
+            <a class="layui-btn layui-btn-primary layui-btn-sm" data-title="用户授权" data-modal='{:url("auth")}?id={$vo.id}'>授 权</a>
+            {/if}
+
+            {if auth("admin/user/pass")}
+            <a class="layui-btn layui-btn-normal layui-btn-sm" data-title="设置密码" data-modal='{:url("pass")}?id={$vo.id}'>密 码</a>
+            {/if}
+
+            {if auth("admin/user/edit")}
+            <a data-dbclick class="layui-btn layui-btn-sm" data-title="编辑用户" data-modal='{:url("edit")}?id={$vo.id}'>编 辑</a>
+            {/if}
+
+            {if $vo.status eq 1 and auth("admin/user/forbid")}
+            <a class="layui-btn layui-btn-sm layui-btn-warm" data-action="{:url('forbid')}" data-value="id#{$vo.id};status#0" data-csrf="{:systoken('admin/user/forbid')}">禁 用</a>
+            {elseif auth("admin/user/resume")}
+            <a class="layui-btn layui-btn-sm layui-btn-warm" data-action="{:url('resume')}" data-value="id#{$vo.id};status#1" data-csrf="{:systoken('admin/user/resume')}">启 用</a>
+            {/if}
+
+            {if auth("admin/user/del")}
+            <a class="layui-btn layui-btn-sm layui-btn-danger" data-confirm="确定要删除该用户吗?" data-action="{:url('del')}" data-value="id#{$vo.id}" data-csrf="{:systoken('admin/user/del')}">删 除</a>
+            {/if}
+
+        </td>
+    </tr>
+    {/foreach}
+    </tbody>
+</table>
+
+{empty name='list'}<span class="notdata">没有记录哦</span>{else}{$pagehtml|raw|default=''}{/empty}
 
-            </td>
-        </tr>
-        <!--{/foreach}-->
-        </tbody>
-    </table>
-    {if isset($page)}<p>{$page|raw}</p>{/if}
-    <!--{/empty}-->
-</form>
 {/block}

+ 57 - 0
application/admin/view/user/index_search.html

@@ -0,0 +1,57 @@
+<fieldset>
+
+    <legend class="layui-bg-cyan">条件搜索</legend>
+
+    <form class="layui-form layui-form-pane form-search" action="{:request()->url()}" onsubmit="return false" method="get" autocomplete="off">
+
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">用户账号</label>
+            <div class="layui-input-inline">
+                <input name="username" value="{$Think.get.username|default=''}" placeholder="请输入用户名" class="layui-input">
+            </div>
+        </div>
+
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">联系手机</label>
+            <div class="layui-input-inline">
+                <input name="phone" value="{$Think.get.phone|default=''}" placeholder="请输入联系手机" class="layui-input">
+            </div>
+        </div>
+
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">电子邮箱</label>
+            <div class="layui-input-inline">
+                <input name="mail" value="{$Think.get.mail|default=''}" placeholder="请输入电子邮箱" class="layui-input">
+            </div>
+        </div>
+
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">使用状态</label>
+            <div class="layui-input-inline">
+                <select class="layui-select" name="status">
+                    {foreach [''=>'-- 全部 --','0'=>'已禁用的账号','1'=>'使用中的账号'] as $k=>$v}
+                    {eq name='Think.get.status' value='$k.""'}
+                    <option selected value="{$k}">{$v}</option>
+                    {else}
+                    <option value="{$k}">{$v}</option>
+                    {/eq}
+                    {/foreach}
+                </select>
+            </div>
+        </div>
+
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">登录时间</label>
+            <div class="layui-input-inline">
+                <input data-date-range name="login_at" value="{$Think.get.login_at|default=''}" placeholder="请选择登录时间" class="layui-input">
+            </div>
+        </div>
+
+        <div class="layui-form-item layui-inline">
+            <button class="layui-btn layui-btn-primary"><i class="layui-icon">&#xe615;</i> 搜 索</button>
+        </div>
+    </form>
+
+</fieldset>
+
+<script>form.render()</script>

+ 38 - 28
application/admin/view/user/pass.html

@@ -1,43 +1,53 @@
-<form autocomplete="off" class="layui-form layui-box modal-form-box" action="{:request()->url()}" data-auto="true" method="post">
-
-    <div class="layui-form-item">
-        <label class="layui-form-label">用户账号</label>
-        <div class="layui-input-block">
-            {if $vo and $vo.username}
-            <input readonly="readonly" disabled="disabled" name="username" value='{$vo.username|default=""}' required="required" title="请输入用户名称" placeholder="请输入用户名称" class="layui-input layui-bg-gray">
-            {else}
-            <input name="username" value='{$vo.username|default=""}' required="required" title="请输入用户名称" placeholder="请输入用户名称" class="layui-input">
-            {/if}
+<form class="layui-form layui-card" action="{:request()->url()}" data-auto="true" method="post" autocomplete="off">
+
+    <div class="layui-card-body">
+
+        <div class="layui-form-item">
+            <label class="layui-form-label label-required">用户账号</label>
+            <div class="layui-input-block">
+                <!--{if $vo and isset($vo.username)}-->
+                <input disabled value='{$vo.username|default=""}' class="layui-input layui-bg-gray">
+                <p class="help-block">用户账号创建后,不允许再次修改。</p>
+                <!--{else}-->
+                <input name="username" value='{$vo.username|default=""}' required pattern="^.{4,}$" placeholder="请输入4位及以上字符用户名称" class="layui-input">
+                <!--{/if}-->
+            </div>
         </div>
-    </div>
 
-    <!--{if $verify}-->
-    <div class="layui-form-item">
-        <label class="layui-form-label">旧的密码</label>
-        <div class="layui-input-block">
-            <input autofocus name="oldpassword" value='' pattern="^\S{1,}$" required="" title="请输入旧的密码" placeholder="请输入旧的密码" class="layui-input">
+        <!--{if $verify}-->
+        <div class="layui-form-item">
+            <label class="layui-form-label">旧的密码</label>
+            <div class="layui-input-block">
+                <input type="password" autofocus name="oldpassword" value='' pattern="^\S{1,}$" required placeholder="请输入旧的密码" class="layui-input">
+                <p class="help-block">请输入旧密码来验证修改权限,旧密码不限制格式。</p>
+            </div>
         </div>
-    </div>
-    <!--{/if}-->
+        <!--{/if}-->
 
-    <div class="layui-form-item">
-        <label class="layui-form-label">新的密码</label>
-        <div class="layui-input-block">
-            <input name="password" value='' pattern="^\S{1,}$" required="" title="请输入新的密码" placeholder="请输入新的密码" class="layui-input">
+        <div class="layui-form-item">
+            <label class="layui-form-label">新的密码</label>
+            <div class="layui-input-block">
+                <input type="password" name="password" maxlength="32" pattern="^(?![\d]+$)(?![a-zA-Z]+$)(?![^\da-zA-Z]+$).{6,32}$" required placeholder="请输入新的密码" class="layui-input">
+                <p class="help-block">密码必需包含大小写字母、数字、符号的任意两者组合。</p>
+            </div>
         </div>
-    </div>
 
-    <div class="layui-form-item">
-        <label class="layui-form-label">重复密码</label>
-        <div class="layui-input-block">
-            <input name="repassword" value='' pattern="^\S{1,}$" required="" title="请输入重复密码" placeholder="请输入重复密码" class="layui-input">
+        <div class="layui-form-item">
+            <label class="layui-form-label">重复密码</label>
+            <div class="layui-input-block">
+                <input type="password" name="repassword" maxlength="32" pattern="^(?![\d]+$)(?![a-zA-Z]+$)(?![^\da-zA-Z]+$).{6,32}$" required placeholder="请输入重复密码" class="layui-input">
+                <p class="help-block">密码必需包含大小写字母、数字、符号的任意两者组合。</p>
+            </div>
         </div>
+
     </div>
 
     <div class="hr-line-dashed"></div>
 
     <div class="layui-form-item text-center">
-        {if isset($vo['id'])}<input type='hidden' value='{$vo.id}' name='id'>{/if}
+        <!--{notempty name='vo.id'}-->
+        <input type='hidden' value='{$vo.id}' name='id'>
+        <!--{/notempty}-->
         <button class="layui-btn" type='submit'>保存数据</button>
         <button class="layui-btn layui-btn-danger" type='button' data-confirm="确定要取消编辑吗?" data-close>取消编辑</button>
     </div>

+ 0 - 110
application/common.php

@@ -1,110 +0,0 @@
-<?php
-
-// +----------------------------------------------------------------------
-// | ThinkAdmin
-// +----------------------------------------------------------------------
-// | 版权所有 2014~2017 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
-// +----------------------------------------------------------------------
-// | 官方网站: http://think.ctolog.com
-// +----------------------------------------------------------------------
-// | 开源协议 ( https://mit-license.org )
-// +----------------------------------------------------------------------
-// | github开源项目:https://github.com/zoujingli/ThinkAdmin
-// +----------------------------------------------------------------------
-
-use service\DataService;
-use service\NodeService;
-use think\Db;
-
-/**
- * 打印输出数据到文件
- * @param mixed $data 输出的数据
- * @param bool $force 强制替换
- * @param string|null $file
- */
-function p($data, $force = false, $file = null)
-{
-    is_null($file) && $file = env('runtime_path') . date('Ymd') . '.txt';
-    $str = (is_string($data) ? $data : (is_array($data) || is_object($data)) ? print_r($data, true) : var_export($data, true)) . PHP_EOL;
-    $force ? file_put_contents($file, $str) : file_put_contents($file, $str, FILE_APPEND);
-}
-
-/**
- * RBAC节点权限验证
- * @param string $node
- * @return bool
- */
-function auth($node)
-{
-    return NodeService::checkAuthNode($node);
-}
-
-/**
- * 设备或配置系统参数
- * @param string $name 参数名称
- * @param bool $value 默认是null为获取值,否则为更新
- * @return string|bool
- * @throws \think\Exception
- * @throws \think\exception\PDOException
- */
-function sysconf($name, $value = null)
-{
-    static $config = [];
-    if ($value !== null) {
-        list($config, $data) = [[], ['name' => $name, 'value' => $value]];
-        return DataService::save('SystemConfig', $data, 'name');
-    }
-    if (empty($config)) {
-        $config = Db::name('SystemConfig')->column('name,value');
-    }
-    return isset($config[$name]) ? $config[$name] : '';
-}
-
-/**
- * 日期格式标准输出
- * @param string $datetime 输入日期
- * @param string $format 输出格式
- * @return false|string
- */
-function format_datetime($datetime, $format = 'Y年m月d日 H:i:s')
-{
-    return date($format, strtotime($datetime));
-}
-
-/**
- * UTF8字符串加密
- * @param string $string
- * @return string
- */
-function encode($string)
-{
-    list($chars, $length) = ['', strlen($string = iconv('utf-8', 'gbk', $string))];
-    for ($i = 0; $i < $length; $i++) {
-        $chars .= str_pad(base_convert(ord($string[$i]), 10, 36), 2, 0, 0);
-    }
-    return $chars;
-}
-
-/**
- * UTF8字符串解密
- * @param string $string
- * @return string
- */
-function decode($string)
-{
-    $chars = '';
-    foreach (str_split($string, 2) as $char) {
-        $chars .= chr(intval(base_convert($char, 36, 10)));
-    }
-    return iconv('gbk', 'utf-8', $chars);
-}
-
-/**
- * 下载远程文件到本地
- * @param string $url 远程图片地址
- * @return string
- */
-function local_image($url)
-{
-    return \service\FileService::download($url)['url'];
-}

+ 11 - 7
application/index/controller/Index.php

@@ -1,11 +1,11 @@
 <?php
 
 // +----------------------------------------------------------------------
-// | ThinkAdmin
+// | framework
 // +----------------------------------------------------------------------
-// | 版权所有 2014~2017 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
 // +----------------------------------------------------------------------
-// | 官方网站: http://think.ctolog.com
+// | 官方网站: http://framework.thinkadmin.top
 // +----------------------------------------------------------------------
 // | 开源协议 ( https://mit-license.org )
 // +----------------------------------------------------------------------
@@ -14,17 +14,21 @@
 
 namespace app\index\controller;
 
-use think\Controller;
+use library\Controller;
 
 /**
- * 应用入口控制器
- * @author Anyon <zoujingli@qq.com>
+ * 应用入口
+ * Class Index
+ * @package app\index\controller
  */
 class Index extends Controller
 {
-
+    /**
+     * 入口跳转链接
+     */
     public function index()
     {
         $this->redirect('@admin/login');
     }
+
 }

+ 0 - 18
application/middleware.php

@@ -1,18 +0,0 @@
-<?php
-
-// +----------------------------------------------------------------------
-// | ThinkAdmin
-// +----------------------------------------------------------------------
-// | 版权所有 2014~2017 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
-// +----------------------------------------------------------------------
-// | 官方网站: http://think.ctolog.com
-// +----------------------------------------------------------------------
-// | 开源协议 ( https://mit-license.org )
-// +----------------------------------------------------------------------
-// | github开源项目:https://github.com/zoujingli/ThinkAdmin
-// +----------------------------------------------------------------------
-
-return [
-    // 系统权限访问管理
-    \app\admin\middleware\Auth::class,
-];

+ 50 - 0
application/service/controller/Config.php

@@ -0,0 +1,50 @@
+<?php
+
+// +----------------------------------------------------------------------
+// | framework
+// +----------------------------------------------------------------------
+// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// +----------------------------------------------------------------------
+// | 官方网站: http://framework.thinkadmin.top
+// +----------------------------------------------------------------------
+// | 开源协议 ( https://mit-license.org )
+// +----------------------------------------------------------------------
+// | github开源项目:https://github.com/zoujingli/ThinkAdmin
+// +----------------------------------------------------------------------
+
+namespace app\service\controller;
+
+use library\Controller;
+
+/**
+ * 微信配置管理
+ * Class Index
+ * @package app\wechat\controller
+ * @author Anyon <zoujingli@qq.com>
+ * @date 2017/03/27 14:43
+ */
+class Config extends Controller
+{
+
+    /**
+     * 定义当前操作表名
+     * @var string
+     */
+    public $table = 'WechatServiceConfig';
+
+    /**
+     * 微信基础参数配置
+     * @return array|string
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function index()
+    {
+        $this->applyCsrfToken();
+        $this->title = '开放平台接口配置';
+        if ($this->request->isGet()) return $this->fetch();
+        foreach ($this->request->post() as $k => $v) sysconf($k, $v);
+        $this->success('开放平台数据修改成功!', '');
+    }
+
+}

+ 146 - 0
application/service/controller/Index.php

@@ -0,0 +1,146 @@
+<?php
+
+// +----------------------------------------------------------------------
+// | framework
+// +----------------------------------------------------------------------
+// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// +----------------------------------------------------------------------
+// | 官方网站: http://framework.thinkadmin.top
+// +----------------------------------------------------------------------
+// | 开源协议 ( https://mit-license.org )
+// +----------------------------------------------------------------------
+// | github开源项目:https://github.com/zoujingli/ThinkAdmin
+// +----------------------------------------------------------------------
+
+namespace app\service\controller;
+
+use app\service\logic\Build;
+use app\service\logic\Wechat;
+use library\Controller;
+use think\Db;
+
+/**
+ * Class Index
+ * @package app\service\controller
+ */
+class Index extends Controller
+{
+
+    /**
+     * 定义当前操作表名
+     * @var string
+     */
+    public $table = 'WechatServiceConfig';
+
+    /**
+     * 微信基础参数配置
+     * @return string
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function index()
+    {
+        $this->applyCsrfToken();
+        $this->title = '微信授权管理';
+        $this->_query($this->table)
+            ->like('authorizer_appid,nick_name,principal_name')
+            ->equal('service_type,status')->dateBetween('create_at')
+            ->where(['is_deleted' => '0'])->order('id desc')->page();
+
+    }
+
+    /**
+     * 清理接口调用测试
+     * @throws \WeChat\Exceptions\InvalidResponseException
+     * @throws \WeChat\Exceptions\LocalCacheException
+     */
+    public function clearQuota()
+    {
+        $appid = input('appid');
+        $result = Wechat::WeChatLimit($appid)->clearQuota();
+        if (empty($result['errcode']) && $result['errmsg'] === 'ok') {
+            $this->success('接口调用次数清零成功!');
+        } elseif (isset($result['errmsg'])) {
+            $this->error('接口调用次数清零失败,请稍候再试!' . $result['errmsg']);
+        } else {
+            $this->error('接口调用次数清零失败,请稍候再试!');
+        }
+    }
+
+    /**
+     * 同步获取权限
+     */
+    public function sync()
+    {
+        try {
+            $appid = $this->request->get('appid');
+            $where = ['authorizer_appid' => $appid, 'is_deleted' => '0', 'status' => '1'];
+            $author = Db::name('WechatServiceConfig')->where($where)->find();
+            empty($author) && $this->error('无效的授权信息,请同步其它公众号!');
+            $info = Build::filter(Wechat::service()->getAuthorizerInfo($appid));
+            $info['authorizer_appid'] = $appid;
+            if (data_save('WechatServiceConfig', $info, 'authorizer_appid')) {
+                $this->success('更新公众号授权信息成功!', '');
+            }
+        } catch (\think\exception\HttpResponseException $exception) {
+            throw $exception;
+        } catch (\Exception $e) {
+            $this->error("获取授权信息失败,请稍候再试!<br>{$e->getMessage()}");
+        }
+    }
+
+    /**
+     * 同步获取所有授权公众号记录
+     */
+    public function syncall()
+    {
+        try {
+            $wechat = Wechat::service();
+            $result = $wechat->getAuthorizerList();
+            foreach ($result['list'] as $item) if (!empty($item['refresh_token']) && !empty($item['auth_time'])) {
+                $data = Build::filter($wechat->getAuthorizerInfo($item['authorizer_appid']));
+                $data['is_deleted'] = '0';
+                $data['authorizer_appid'] = $item['authorizer_appid'];
+                $data['authorizer_refresh_token'] = $item['refresh_token'];
+                $data['create_at'] = date('Y-m-d H:i:s', $item['auth_time']);
+                if (!data_save('WechatServiceConfig', $data, 'authorizer_appid')) {
+                    $this->error('获取授权信息失败,请稍候再试!', '');
+                }
+            }
+            $this->success('同步所有授权信息成功!', '');
+        } catch (\think\exception\HttpResponseException $exception) {
+            throw $exception;
+        } catch (\Exception $e) {
+            $this->error("同步授权失败,请稍候再试!<br>{$e->getMessage()}");
+        }
+    }
+
+    /**
+     * 删除微信
+     */
+    public function del()
+    {
+        $this->applyCsrfToken();
+        $this->_delete($this->table);
+    }
+
+    /**
+     * 微信禁用
+     */
+    public function forbid()
+    {
+        $this->applyCsrfToken();
+        $this->_save($this->table, ['status' => '0']);
+    }
+
+    /**
+     * 微信启用
+     */
+    public function resume()
+    {
+        $this->applyCsrfToken();
+        $this->_save($this->table, ['status' => '1']);
+    }
+}

+ 154 - 0
application/service/controller/api/Client.php

@@ -0,0 +1,154 @@
+<?php
+
+// +----------------------------------------------------------------------
+// | framework
+// +----------------------------------------------------------------------
+// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// +----------------------------------------------------------------------
+// | 官方网站: http://framework.thinkadmin.top
+// +----------------------------------------------------------------------
+// | 开源协议 ( https://mit-license.org )
+// +----------------------------------------------------------------------
+// | github开源项目:https://github.com/zoujingli/ThinkAdmin
+// +----------------------------------------------------------------------
+
+namespace app\service\controller\api;
+
+use app\service\logic\Wechat;
+use think\Controller;
+use think\Db;
+
+/**
+ * 获取微信SDK实例对象
+ * Class Instance
+ * @package app\wechat\controller
+ */
+class Client extends Controller
+{
+
+    /**
+     * 当前配置
+     * @var string
+     */
+    protected $config = [];
+
+    /**
+     * 当前APPID
+     * @var string
+     */
+    protected $appid = '';
+
+    /**
+     * 接口实例名称
+     * @var string
+     */
+    protected $name = '';
+
+    /**
+     * 接口类型
+     * @var string
+     */
+    protected $type = '';
+
+    /**
+     * 错误消息
+     * @var string
+     */
+    protected $message = '';
+
+    /**
+     * 启动Yar接口服务
+     * @param string $param AppName-AppId-AppKey
+     * @return string
+     */
+    public function yar($param)
+    {
+        try {
+            $instance = $this->create($param);
+            $service = new \Yar_Server(empty($instance) ? $this : $instance);
+            $service->handle();
+        } catch (\Exception $e) {
+            return $e->getMessage();
+        }
+    }
+
+    /**
+     * 启动SOAP接口服务
+     * @param string $param AppName-AppId-AppKey
+     * @return string
+     */
+    public function soap($param)
+    {
+        try {
+            $instance = $this->create($param);
+            $service = new \SoapServer(null, ['uri' => strtolower($this->name)]);
+            $service->setObject(empty($instance) ? $this : $instance);
+            $service->handle();
+        } catch (\Exception $e) {
+            return $e->getMessage();
+        }
+    }
+
+    /**
+     * 创建接口服务
+     * @param string $token
+     * @return \WeChat\Oauth|\WeChat\Pay|\WeChat\Receive|\WeChat\Script|\WeChat\User|\WeOpen\Service
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @throws \think\Exception
+     */
+    private function create($token)
+    {
+        if ($this->auth($token)) {
+            $weminiClassName = 'Account,Basic,Code,Domain,Tester,User,Crypt,Plugs,Poi,Qrcode,Template,Total';
+            $wechatClassName = 'Card,Custom,Limit,Media,Menu,Oauth,Pay,Product,Qrcode,Receive,Scan,Script,Shake,Tags,Template,User,Wifi';
+            if ($this->type === 'wechat' && stripos($wechatClassName, $this->name) !== false) {
+                $instance = Wechat::instance($this->name, $this->appid, 'WeChat');
+            } elseif ($this->type === 'wemini' && stripos($weminiClassName, $this->name) !== false) {
+                $instance = Wechat::instance($this->name, $this->appid, 'WeMini');
+            } elseif (stripos('Service,MiniApp', $this->name) !== false) {
+                $instance = Wechat::instance($this->name, $this->appid, 'WeOpen');
+            } elseif (stripos('Wechat,Config,Handler', $this->name) !== false) {
+                $className = "\\app\\service\\handler\\Wechat";
+                $instance = new $className($this->config);
+            }
+            if (!empty($instance)) return $instance;
+        }
+        throw new \think\Exception($this->message);
+    }
+
+    /**
+     * 加载微信实例对象
+     * @param string $token 数据格式 name|appid|appkey
+     * @return bool
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    private function auth($token = '')
+    {
+        list($this->name, $this->appid, $appkey, $this->type) = explode('-', $token . '---');
+        if (empty($this->name) || empty($this->appid) || empty($appkey)) {
+            $this->message = '缺少必要的参数AppId或AppKey';
+            return false;
+        }
+        $where = ['authorizer_appid' => $this->appid, 'status' => '1', 'is_deleted' => '0'];
+        $this->config = Db::name('WechatServiceConfig')->where($where)->find();
+        if (empty($this->config)) {
+            $this->message = '无效的微信绑定对象';
+            return false;
+        }
+        if (strtolower($this->config['appkey']) !== strtolower($appkey)) {
+            $this->message = '授权AppId与AppKey不匹配';
+            return false;
+        }
+        $this->message = '';
+        $this->name = ucfirst(strtolower($this->name));
+        $this->type = strtolower(empty($this->type) ? 'WeChat' : $this->type);
+        Db::name('WechatServiceConfig')->where($where)->setInc('total', 1);
+        return true;
+    }
+
+}

+ 181 - 0
application/service/controller/api/Push.php

@@ -0,0 +1,181 @@
+<?php
+
+// +----------------------------------------------------------------------
+// | framework
+// +----------------------------------------------------------------------
+// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// +----------------------------------------------------------------------
+// | 官方网站: http://framework.thinkadmin.top
+// +----------------------------------------------------------------------
+// | 开源协议 ( https://mit-license.org )
+// +----------------------------------------------------------------------
+// | github开源项目:https://github.com/zoujingli/ThinkAdmin
+// +----------------------------------------------------------------------
+
+namespace app\service\controller\api;
+
+use app\service\logic\Build;
+use app\service\logic\Wechat;
+use library\Controller;
+use think\Db;
+
+/**
+ * 微信推送事件处理
+ *
+ * @author Anyon <zoujingli@qq.com>
+ * @date 2016/10/18 12:38
+ */
+class Push extends Controller
+{
+
+    /**
+     * 微信API推送事件处理
+     * @param string $appid
+     * @return string
+     * @throws \think\Exception
+     * @throws \WeChat\Exceptions\InvalidDecryptException
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
+     */
+    public function notify($appid)
+    {
+        /* 全网发布接口测试 */
+        if ($appid === 'wx570bc396a51b8ff8') {
+            return \app\service\handler\Publish::handler($appid);
+        }
+        /* 接口类正常服务 */
+        return \app\service\handler\Receive::handler($appid);
+    }
+
+    /**
+     * 一、处理服务推送Ticket
+     * 二、处理取消公众号授权
+     * @return string
+     * @throws \think\Exception
+     * @throws \WeChat\Exceptions\InvalidResponseException
+     * @throws \WeChat\Exceptions\LocalCacheException
+     * @throws \think\exception\PDOException
+     */
+    public function ticket()
+    {
+        try {
+            $server = Wechat::service();
+            if (!($data = $server->getComonentTicket())) {
+                return "Ticket event handling failed.";
+            }
+        } catch (\Exception $e) {
+            return "Ticket event handling failed, {$e->getMessage()}";
+        }
+        if (!empty($data['AuthorizerAppid']) && isset($data['InfoType'])) {
+            # 授权成功通知
+            if ($data['InfoType'] === 'authorized') {
+                Db::name('WechatServiceConfig')->where(['authorizer_appid' => $data['AuthorizerAppid']])->update(['is_deleted' => '0']);
+            }
+            # 接收取消授权服务事件
+            if ($data['InfoType'] === 'unauthorized') {
+                Db::name('WechatServiceConfig')->where(['authorizer_appid' => $data['AuthorizerAppid']])->update(['is_deleted' => '1']);
+            }
+            # 授权更新通知
+            if ($data['InfoType'] === 'updateauthorized') {
+                $_GET['auth_code'] = $data['PreAuthCode'];
+                $this->applyAuth($server);
+            }
+        }
+        return 'success';
+    }
+
+    /**
+     * 网页授权
+     * @throws \think\Exception
+     * @throws \WeChat\Exceptions\InvalidResponseException
+     * @throws \WeChat\Exceptions\LocalCacheException
+     */
+    public function oauth()
+    {
+        list($mode, $appid, $enurl, $sessid) = [
+            $this->request->get('mode'), $this->request->get('state'),
+            $this->request->get('enurl'), $this->request->get('sessid'),
+        ];
+        $service = Wechat::service();
+        $result = $service->getOauthAccessToken($appid);
+        if (empty($result['openid'])) throw new \think\Exception('网页授权失败, 无法进一步操作!');
+        cache("{$appid}_{$sessid}_openid", $result['openid'], 3600);
+        if (!empty($mode)) {
+            $wechat = new \WeChat\Oauth($service->getConfig($appid));
+            $fans = $wechat->getUserInfo($result['access_token'], $result['openid']);
+            if (empty($fans)) throw new \think\Exception('网页授权信息获取失败, 无法进一步操作!');
+            cache("{$appid}_{$sessid}_fans", $fans, 3600);
+        }
+        redirect(decode($enurl), [], 301)->send();
+    }
+
+    /**
+     * 跳转到微信服务授权页面
+     * @param string $redirect
+     * @return string
+     * @throws \think\Exception
+     * @throws \WeChat\Exceptions\InvalidResponseException
+     * @throws \WeChat\Exceptions\LocalCacheException
+     * @throws \think\exception\PDOException
+     */
+    public function auth($redirect = '')
+    {
+        $fromRedirect = decode($redirect);
+        if (empty($redirect) || empty($fromRedirect)) {
+            return '请传入回跳Redirect参数 ( 请使用ENCODE加密 )';
+        }
+        # 预授权码不为空,则表示可以进行授权处理
+        $service = Wechat::service();
+        if (($auth_code = $this->request->get('auth_code'))) {
+            return $this->applyAuth($service, $fromRedirect);
+        }
+        # 生成微信授权链接,使用刷新跳转到授权网页
+        $url = url("@service/api.push/auth/{$redirect}", false, true, true);
+        if (($redirect = $service->getAuthRedirect($url))) {
+            ob_clean();
+            header("Refresh:0;url={$redirect}");
+            return "<script>window.location.href='{$redirect}';</script><a href='{$redirect}'>跳转中...</a>";
+        }
+        # 生成微信授权链接失败
+        return "<h2>Failed to create authorization. Please return to try again.</h2>";
+    }
+
+    /**
+     * 公众号授权绑定数据处理
+     * @param \WeOpen\Service $service
+     * @param string|null $redirect 授权成功回跳地址
+     * @return string
+     * @throws \WeChat\Exceptions\InvalidResponseException
+     * @throws \WeChat\Exceptions\LocalCacheException
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    private function applyAuth($service, $redirect = null)
+    {
+        // 通过授权code换取公众号信息
+        $result = $service->getQueryAuthorizerInfo();
+        if (empty($result['authorizer_appid'])) {
+            return "接收微信第三方平台授权失败! ";
+        }
+        // 重新通过接口查询公众号参数
+        if (!($update = array_merge($result, $service->getAuthorizerInfo($result['authorizer_appid'])))) {
+            return '获取授权数据失败, 请稍候再试!';
+        }
+        // 生成公众号授权参数
+        $update = array_merge(Build::filter($update), [
+            'status' => '1', 'is_deleted' => '0', 'expires_in' => time() + 7000, 'create_at' => date('y-m-d H:i:s'),
+        ]);
+        // 微信接口APPKEY处理与更新
+        $config = Db::name('WechatServiceConfig')->where(['authorizer_appid' => $result['authorizer_appid']])->find();
+        $update['appkey'] = empty($config['appkey']) ? md5(uniqid('', true)) : $config['appkey'];
+        data_save('WechatServiceConfig', $update, 'authorizer_appid');
+        if (!empty($redirect)) { // 带上appid与appkey跳转到应用
+            $split = stripos($redirect, '?') > 0 ? '&' : '?';
+            $realurl = preg_replace(['/appid=\w+/i', '/appkey=\w+/i', '/(\?\&)$/i'], ['', '', ''], $redirect);
+            return redirect("{$realurl}{$split}appid={$update['authorizer_appid']}&appkey={$update['appkey']}");
+        }
+    }
+
+}

+ 67 - 0
application/service/handler/Publish.php

@@ -0,0 +1,67 @@
+<?php
+
+// +----------------------------------------------------------------------
+// | framework
+// +----------------------------------------------------------------------
+// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// +----------------------------------------------------------------------
+// | 官方网站: http://framework.thinkadmin.top
+// +----------------------------------------------------------------------
+// | 开源协议 ( https://mit-license.org )
+// +----------------------------------------------------------------------
+// | github开源项目:https://github.com/zoujingli/ThinkAdmin
+// +----------------------------------------------------------------------
+
+namespace app\service\handler;
+
+use app\service\logic\Wechat;
+
+/**
+ * 第三方平台测试上线
+ *
+ * @author Anyon <zoujingli@qq.com>
+ * @date 2016/10/27 14:14
+ */
+class Publish
+{
+
+    /**
+     * 当前微信APPID
+     * @var string
+     */
+    protected static $appid;
+
+    /**
+     * 事件初始化
+     * @param string $appid
+     * @return string
+     * @throws \WeChat\Exceptions\InvalidDecryptException
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public static function handler($appid)
+    {
+        try {
+            $wechat = Wechat::WeChatReceive($appid);
+        } catch (\Exception $e) {
+            return "Wechat message handling failed, {$e->getMessage()}";
+        }
+        /* 分别执行对应类型的操作 */
+        switch (strtolower($wechat->getMsgType())) {
+            case 'text':
+                $receive = $wechat->getReceive();
+                if ($receive['Content'] === 'TESTCOMPONENT_MSG_TYPE_TEXT') {
+                    return $wechat->text('TESTCOMPONENT_MSG_TYPE_TEXT_callback')->reply([], true);
+                }
+                $key = str_replace("QUERY_AUTH_CODE:", '', $receive['Content']);
+                Wechat::instance('Service')->getQueryAuthorizerInfo($key);
+                return $wechat->text("{$key}_from_api")->reply([], true);
+            case 'event':
+                $receive = $wechat->getReceive();
+                return $wechat->text("{$receive['Event']}from_callback")->reply([], true);
+            default:
+                return 'success';
+        }
+    }
+
+}

+ 64 - 0
application/service/handler/Receive.php

@@ -0,0 +1,64 @@
+<?php
+
+// +----------------------------------------------------------------------
+// | framework
+// +----------------------------------------------------------------------
+// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// +----------------------------------------------------------------------
+// | 官方网站: http://framework.thinkadmin.top
+// +----------------------------------------------------------------------
+// | 开源协议 ( https://mit-license.org )
+// +----------------------------------------------------------------------
+// | github开源项目:https://github.com/zoujingli/ThinkAdmin
+// +----------------------------------------------------------------------
+
+namespace app\service\handler;
+
+use app\service\logic\Wechat;
+use think\Db;
+
+/**
+ * 微信推送消息处理
+ *
+ * @author Anyon <zoujingli@qq.com>
+ * @date 2016/10/27 14:14
+ */
+class Receive
+{
+
+    /**
+     * 事件初始化
+     * @param string $appid
+     * @return string
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @throws \think\Exception
+     */
+    public static function handler($appid)
+    {
+        try {
+            $service = Wechat::WeChatReceive($appid);
+        } catch (\Exception $e) {
+            return "Wechat message handling failed, {$e->getMessage()}";
+        }
+        // 验证微信配置信息
+        $config = Db::name('WechatServiceConfig')->where(['authorizer_appid' => $appid])->find();
+        if (empty($config) || empty($config['appuri'])) {
+            \think\facade\Log::error(($message = "微信{$appid}授权配置验证无效"));
+            return $message;
+        }
+        try {
+            list($data, $openid) = [$service->getReceive(), $service->getOpenid()];
+            if (isset($data['EventKey']) && is_object($data['EventKey'])) $data['EventKey'] = (array)$data['EventKey'];
+            $input = ['openid' => $openid, 'appid' => $appid, 'receive' => serialize($data), 'encrypt' => intval($service->isEncrypt())];
+            if (is_string($result = http_post($config['appuri'], $input, ['timeout' => 30]))) {
+                return $result;
+            }
+        } catch (\Exception $e) {
+            \think\facade\Log::error("微信{$appid}接口调用异常,{$e->getMessage()}");
+        }
+        return 'success';
+    }
+
+}

+ 169 - 0
application/service/handler/Wechat.php

@@ -0,0 +1,169 @@
+<?php
+
+// +----------------------------------------------------------------------
+// | framework
+// +----------------------------------------------------------------------
+// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// +----------------------------------------------------------------------
+// | 官方网站: http://framework.thinkadmin.top
+// +----------------------------------------------------------------------
+// | 开源协议 ( https://mit-license.org )
+// +----------------------------------------------------------------------
+// | github开源项目:https://github.com/zoujingli/ThinkAdmin
+// +----------------------------------------------------------------------
+
+namespace app\service\handler;
+
+use app\service\logic\Wechat as WechatLogic;
+use think\Db;
+
+/**
+ * 微信网页授权接口
+ * Class WechatHandler
+ * @package app\wechat\handler
+ * @author Anyon <zoujingli@qq.com>
+ */
+class Wechat
+{
+    /**
+     * 当前微信APPID
+     * @var string
+     */
+    protected $appid;
+
+    /**
+     * 当前微信配置
+     * @var array
+     */
+    protected $config;
+
+    /**
+     * 错误消息
+     * @var string
+     */
+    protected $message;
+
+    /**
+     * Wechat constructor.
+     * @param array $config
+     */
+    public function __construct($config = [])
+    {
+        $this->config = $config;
+        $this->appid = isset($config['authorizer_appid']) ? $config['authorizer_appid'] : '';
+    }
+
+    /**
+     * 检查微信配置服务初始化状态
+     * @return boolean
+     * @throws \think\Exception
+     */
+    private function checkInit()
+    {
+        if (!empty($this->config)) return true;
+        throw new \think\Exception('Wechat Please bind Wechat first');
+    }
+
+    /**
+     * 接口测试
+     * @return integer
+     */
+    public function test()
+    {
+        return time();
+    }
+
+    /**
+     * 获取当前公众号配置
+     * @return array|boolean
+     * @throws \think\Exception
+     */
+    public function getConfig()
+    {
+        $this->checkInit();
+        $info = Db::name('WechatServiceConfig')->where(['authorizer_appid' => $this->appid])->find();
+        if (empty($info)) return false;
+        if (isset($info['id'])) unset($info['id']);
+        return $info;
+    }
+
+    /**
+     * 设置微信接口通知URL地址
+     * @param string $notifyUri 接口通知URL地址
+     * @return boolean
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function setApiNotifyUri($notifyUri)
+    {
+        $this->checkInit();
+        if (empty($notifyUri)) throw new \think\Exception('请传入微信通知URL');
+        list($where, $data) = [['authorizer_appid' => $this->appid], ['appuri' => $notifyUri]];
+        return Db::name('WechatServiceConfig')->where($where)->update($data) !== false;
+    }
+
+    /**
+     * 更新接口Appkey(成功返回新的Appkey)
+     * @return bool|string
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function updateApiAppkey()
+    {
+        $this->checkInit();
+        $data = ['appkey' => md5(uniqid())];
+        Db::name('WechatServiceConfig')->where(['authorizer_appid' => $this->appid])->update($data);
+        return $data['appkey'];
+    }
+
+    /**
+     * 获取公众号的配置参数
+     * @param string $name 参数名称
+     * @return array|string
+     * @throws \think\Exception
+     */
+    public function config($name = null)
+    {
+        $this->checkInit();
+        return WechatLogic::WeChatScript($this->appid)->config->get($name);
+    }
+
+    /**
+     * 微信网页授权
+     * @param string $sessid 当前会话id(可用session_id()获取)
+     * @param string $selfUrl 当前会话URL地址(需包含域名的完整URL地址)
+     * @param int $fullMode 网页授权模式(0静默模式,1高级授权)
+     * @return array|bool
+     * @throws \think\Exception
+     */
+    public function oauth($sessid, $selfUrl, $fullMode = 0)
+    {
+        $this->checkInit();
+        $fans = cache("{$this->appid}_{$sessid}_fans");
+        $openid = cache("{$this->appid}_{$sessid}_openid");
+        if (!empty($openid) && (empty($fullMode) || !empty($fans))) {
+            return ['openid' => $openid, 'fans' => $fans, 'url' => ''];
+        }
+        $service = WechatLogic::service();
+        $mode = empty($fullMode) ? 'snsapi_base' : 'snsapi_userinfo';
+        $url = url('@service/api.push/oauth', '', true, true);
+        $params = ['mode' => $fullMode, 'sessid' => $sessid, 'enurl' => encode($selfUrl)];
+        $authurl = $service->getOauthRedirect($this->appid, $url . '?' . http_build_query($params), $mode);
+        return ['openid' => $openid, 'fans' => $fans, 'url' => $authurl];
+    }
+
+    /**
+     * 微信网页JS签名
+     * @param string $url 当前会话URL地址(需包含域名的完整URL地址)
+     * @return array|boolean
+     * @throws \WeChat\Exceptions\InvalidResponseException
+     * @throws \WeChat\Exceptions\LocalCacheException
+     * @throws \think\Exception
+     */
+    public function jsSign($url)
+    {
+        $this->checkInit();
+        return WechatLogic::WeChatScript($this->appid)->getJsSign($url);
+    }
+
+}

+ 52 - 0
application/service/logic/Build.php

@@ -0,0 +1,52 @@
+<?php
+
+// +----------------------------------------------------------------------
+// | framework
+// +----------------------------------------------------------------------
+// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// +----------------------------------------------------------------------
+// | 官方网站: http://framework.thinkadmin.top
+// +----------------------------------------------------------------------
+// | 开源协议 ( https://mit-license.org )
+// +----------------------------------------------------------------------
+// | github开源项目:https://github.com/zoujingli/ThinkAdmin
+// +----------------------------------------------------------------------
+
+namespace app\service\logic;
+
+/**
+ * 公众号授权数据处理
+ * Class BuildService
+ * @package app\wechat\service
+ */
+class Build
+{
+
+    /**
+     * 授权数据过滤转换处理
+     * @param array $info
+     * @return mixed
+     */
+    public static function filter(array $info)
+    {
+        if (isset($info['func_info'])) $info['func_info'] = join(',', array_map(function ($tmp) {
+            return $tmp['funcscope_category']['id'];
+        }, $info['func_info']));
+        $info['verify_type_info'] = join(',', $info['verify_type_info']);
+        $info['service_type_info'] = join(',', $info['service_type_info']);
+        $info['business_info'] = json_encode($info['business_info'], JSON_UNESCAPED_UNICODE);
+        // 微信类型:  0 代表订阅号, 2 代表服务号, 3 代表小程序
+        $info['service_type'] = intval($info['service_type_info']) === 2 ? 2 : 0;
+        if (!empty($info['MiniProgramInfo'])) {
+            // 微信类型:  0 代表订阅号, 2 代表服务号, 3 代表小程序
+            $info['service_type'] = 3;
+            // 小程序信息
+            $info['miniprograminfo'] = json_encode($info['MiniProgramInfo'], JSON_UNESCAPED_UNICODE);
+        }
+        unset($info['MiniProgramInfo']);
+        // 微信认证: -1 代表未认证, 0 代表微信认证
+        $info['verify_type'] = intval($info['verify_type_info']) !== 0 ? -1 : 0;
+        return $info;
+    }
+
+}

+ 150 - 0
application/service/logic/Wechat.php

@@ -0,0 +1,150 @@
+<?php
+
+// +----------------------------------------------------------------------
+// | framework
+// +----------------------------------------------------------------------
+// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// +----------------------------------------------------------------------
+// | 官方网站: http://framework.thinkadmin.top
+// +----------------------------------------------------------------------
+// | 开源协议 ( https://mit-license.org )
+// +----------------------------------------------------------------------
+// | github开源项目:https://github.com/zoujingli/ThinkAdmin
+// +----------------------------------------------------------------------
+
+namespace app\service\logic;
+
+use think\Db;
+
+/**
+ * 微信数据服务
+ * Class Wechat
+ * @package app\service\logic
+ * @method \WeChat\Card WeChatCard($appid) static 微信卡券管理
+ * @method \WeChat\Custom WeChatCustom($appid) static 微信客服消息
+ * @method \WeChat\Limit WeChatLimit($appid) static 接口调用频次限制
+ * @method \WeChat\Media WeChatMedia($appid) static 微信素材管理
+ * @method \WeChat\Menu WeChatMenu($appid) static 微信菜单管理
+ * @method \WeChat\Oauth WeChatOauth($appid) static 微信网页授权
+ * @method \WeChat\Pay WeChatPay($appid) static 微信支付商户
+ * @method \WeChat\Product WeChatProduct($appid) static 微信商店管理
+ * @method \WeChat\Qrcode WeChatQrcode($appid) static 微信二维码管理
+ * @method \WeChat\Receive WeChatReceive($appid) static 微信推送管理
+ * @method \WeChat\Scan WeChatScan($appid) static 微信扫一扫接入管理
+ * @method \WeChat\Script WeChatScript($appid) static 微信前端支持
+ * @method \WeChat\Shake WeChatShake($appid) static 微信揺一揺周边
+ * @method \WeChat\Tags WeChatTags($appid) static 微信用户标签管理
+ * @method \WeChat\Template WeChatTemplate($appid) static 微信模板消息
+ * @method \WeChat\User WeChatUser($appid) static 微信粉丝管理
+ * @method \WeChat\Wifi WeChatWifi($appid) static 微信门店WIFI管理
+ *
+ * ----- WeMini -----
+ * @method \WeMini\Account WeMiniAccount($appid) static 小程序账号管理
+ * @method \WeMini\Basic WeMiniBasic($appid) static 小程序基础信息设置
+ * @method \WeMini\Code WeMiniCode($appid) static 小程序代码管理
+ * @method \WeMini\Domain WeMiniDomain($appid) static 小程序域名管理
+ * @method \WeMini\Tester WeMinitester($appid) static 小程序成员管理
+ * @method \WeMini\User WeMiniUser($appid) static 小程序帐号管理
+ * --------------------
+ * @method \WeMini\Crypt WeMiniCrypt($appid) static 小程序数据加密处理
+ * @method \WeMini\Plugs WeMiniPlugs($appid) static 小程序插件管理
+ * @method \WeMini\Poi WeMiniPoi($appid) static 小程序地址管理
+ * @method \WeMini\Qrcode WeMiniQrcode($appid) static 小程序二维码管理
+ * @method \WeMini\Template WeMiniTemplate($appid) static 小程序模板消息支持
+ * @method \WeMini\Total WeMiniTotal($appid) static 小程序数据接口
+ *
+ * ----- WePay -----
+ * @method \WePay\Bill WePayBill($appid) static 微信商户账单及评论
+ * @method \WePay\Order WePayOrder($appid) static 微信商户订单
+ * @method \WePay\Refund WePayRefund($appid) static 微信商户退款
+ * @method \WePay\Coupon WePayCoupon($appid) static 微信商户代金券
+ * @method \WePay\Redpack WePayRedpack($appid) static 微信红包支持
+ * @method \WePay\Transfers WePayTransfers($appid) static 微信商户打款到零钱
+ * @method \WePay\TransfersBank WePayTransfersBank($appid) static 微信商户打款到银行卡
+ *
+ * ----- WeOpen -----
+ * @method \WeOpen\Login login() static 第三方微信登录
+ * @method \WeOpen\Service service() static 第三方服务
+ *
+ * ----- ThinkService -----
+ * @method mixed wechat() static 第三方微信工具
+ * @method mixed config() static 第三方配置工具
+ */
+class Wechat
+{
+
+    /**
+     * 接口类型模式
+     * @var string
+     */
+    private static $type = 'WeChat';
+
+    /**
+     * 实例微信对象
+     * @param string $name
+     * @param string $appid 授权公众号APPID
+     * @param string $type 将要获取SDK类型
+     * @return mixed
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public static function instance($name, $appid = '', $type = null)
+    {
+        $config = [
+            'cache_path'               => env('runtime_path') . 'wechat',
+            'component_appid'          => sysconf('component_appid'),
+            'component_token'          => sysconf('component_token'),
+            'component_appsecret'      => sysconf('component_appsecret'),
+            'component_encodingaeskey' => sysconf('component_encodingaeskey'),
+        ];
+        // 注册授权公众号 AccessToken 处理
+        $config['GetAccessTokenCallback'] = function ($authorizerAppid) use ($config) {
+            $where = ['authorizer_appid' => $authorizerAppid];
+            if (!($refreshToken = Db::name('WechatServiceConfig')->where($where)->value('authorizer_refresh_token'))) {
+                throw new \think\Exception('The WeChat information is not configured.', '404');
+            }
+            $open = new \WeOpen\MiniApp($config);
+            $result = $open->refreshAccessToken($authorizerAppid, $refreshToken);
+            if (empty($result['authorizer_access_token']) || empty($result['authorizer_refresh_token'])) {
+                throw new \think\Exception($result['errmsg'], '0');
+            }
+            Db::name('WechatServiceConfig')->where($where)->update([
+                'authorizer_access_token'  => $result['authorizer_access_token'],
+                'authorizer_refresh_token' => $result['authorizer_refresh_token'],
+            ]);
+            return $result['authorizer_access_token'];
+        };
+        $app = new \WeOpen\MiniApp($config);
+        if (in_array(strtolower($name), ['service', 'miniapp'])) {
+            return $app;
+        }
+        if (!in_array($type, ['WeChat', 'WeMini'])) {
+            $type = self::$type;
+        }
+        return $app->instance($name, $appid, $type);
+    }
+
+    /**
+     * 静态初始化对象
+     * @param string $name
+     * @param array $arguments
+     * @return mixed
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public static function __callStatic($name, $arguments)
+    {
+        if (substr($name, 0, 6) === 'WeMini') {
+            self::$type = 'WeMini';
+            $name = substr($name, 6);
+        } elseif (substr($name, 0, 6) === 'WeChat') {
+            self::$type = 'WeChat';
+            $name = substr($name, 6);
+        } elseif (substr($name, 0, 5) === 'WePay') {
+            self::$type = 'WePay';
+            $name = substr($name, 5);
+        }
+        return self::instance($name, isset($arguments[0]) ? $arguments[0] : '', self::$type);
+    }
+
+}

+ 86 - 0
application/service/view/config/index.html

@@ -0,0 +1,86 @@
+{extend name="admin@main"}
+
+{block name="content"}
+<fieldset class="margin-bottom-15">
+    <legend class="layui-bg-cyan">接口地址</legend>
+    <div class="layui-form-item">
+        <p class="color-green">授权发起页域名</p>
+        <label class="relative block">
+            <input disabled class="layui-input layui-bg-gray" value="{:request()->host()}">
+            <a data-copy="{:request()->host()}" class="fa fa-copy right-btn"></a>
+        </label>
+        <p class="help-block">必须从本域名内网页跳转到登录授权页,才可完成登录授权。无需填写 http:// 等域名协议前缀</p>
+    </div>
+    <div class="layui-form-item">
+        <p class="color-green">授权事件接收 URL</p>
+        <label class="relative block">
+            <input disabled class="layui-input layui-bg-gray" value="{:url('@service/api.push/ticket','',false,true)}">
+            <a data-copy="{:url('@service/api.push/ticket','',false,true)}" class="fa fa-copy right-btn"></a>
+        </label>
+        <p class="help-block">用于接收取消授权通知、授权成功通知、授权更新通知,也用于接收 ticket,ticket 是验证平台方的重要凭据</p>
+    </div>
+    <div class="layui-form-item">
+        <p class="color-green">微信消息与事件接收 URL</p>
+        <label class="relative block">
+            <input disabled class="layui-input layui-bg-gray" value="{:url('@service/api.push/notify/\$APPID\$','',false,true)}">
+            <a data-copy="{:url('@service/api.push/notify/\$APPID\$','',false,true)}" class="fa fa-copy right-btn"></a>
+        </label>
+        <p class="help-block">通过该 URL 接收微信消息和事件推送,该参数按规则填写,实际接收消息时 $APPID$ 将被替换为微信 AppId</p>
+    </div>
+    <div class="layui-form-item">
+        <p class="color-green">客户端系统 Yar 模块接口</p>
+        <label class="relative block"><input disabled class="layui-input layui-bg-gray" value="{:url('@service/api.client/yar/PARAM','',false,true)}"></label>
+        <p class="help-block">客户端系统 Yar 接口 URL,PARAM 由调用参数组成(AppName-AppId-AppKey-AppType)</p>
+    </div>
+    <div class="layui-form-item">
+        <p class="color-green">客户端系统 Soap 模块接口</p>
+        <label class="relative block"><input disabled class="layui-input layui-bg-gray" value="{:url('@service/api.client/soap/PARAM','',false,true)}"></label>
+        <p class="help-block">客户端系统 Soap 接口 URL,PARAM 由调用参数组成(AppName-AppId-AppKey-AppType)</p>
+    </div>
+</fieldset>
+
+<fieldset class="margin-bottom-15">
+    <legend class="layui-bg-cyan">对接参数</legend>
+    <form onsubmit="return false;" data-auto="true" method="post" class='layui-form layui-card' autocomplete="off">
+        <div class="layui-form-item">
+            <p class="color-green">开放平台服务 AppID</p>
+            <label class="relative block"><input name="component_appid" required pattern="^.{18}$" maxlength="18" placeholder="请输入18位开放平台服务AppID" value="{:sysconf('component_appid')}" class="layui-input"></label>
+            <p class="help-block">开放平台服务 AppID,需要在微信开放平台获取。</p>
+        </div>
+        <div class="layui-form-item">
+            <p class="color-green">开放平台服务 AppSecret</p>
+            <label class="relative block"><input name="component_appsecret" required pattern="^.{32}$" maxlength="32" placeholder="请输入32位开放平台服务AppSecret" value="{:sysconf('component_appsecret')}" class="layui-input"></label>
+            <p class="help-block">开放平台服务 AppSecret,需要在微信开放平台获取。</p>
+        </div>
+        <div class="layui-form-item">
+            <p class="color-green">开放平台消息校验 Token</p>
+            <label class="relative block"><input name="component_token" required placeholder="请输入微信消息校验Token" value="{:sysconf('component_token')}" class="layui-input"></label>
+            <p class="help-block">开发者在代替微信接收到消息时,用此 Token 来校验消息。</p>
+        </div>
+        <div class="layui-form-item">
+            <p class="color-green">开放平台消息加解密 AesKey</p>
+            <label class="relative block"><input name="component_encodingaeskey" required pattern="^.{43}$" maxlength="43" placeholder="请输入43位微信消息加解密Key" value="{:sysconf('component_encodingaeskey')}" class="layui-input"></label>
+            <p class="help-block">在代替微信收发消息过程中使用。必须是长度为43位的字符串,只能是字母和数字。</p>
+        </div>
+        <div class="hr-line-dashed"></div>
+        <div class="text-center padding-bottom-15">
+            <button class="layui-btn" type="submit">保存配置</button>
+        </div>
+    </form>
+</fieldset>
+{/block}
+
+{block name='style'}
+<style>
+    .right-btn {
+        top: 0;
+        right: 0;
+        width: 38px;
+        height: 38px;
+        display: inline-block;
+        position: absolute;
+        text-align: center;
+        line-height: 38px;
+    }
+</style>
+{/block}

+ 79 - 0
application/service/view/index/index.html

@@ -0,0 +1,79 @@
+{extend name="admin@main"}
+
+{block name="button"}
+<!--{if auth("service/index/syncall")}-->
+<button data-load="{:url('syncall')}" class='layui-btn layui-btn-sm layui-btn-primary'>同步授权信息</button>
+<!--{/if}-->
+{/block}
+
+{block name="content"}
+<table class="layui-table" lay-skin="line">
+    <caption class="margin-bottom-10 text-left">{include file='index/index_search'}</caption>
+    {notempty name='list'}
+    <thead>
+    <tr>
+        <th class='text-left nowrap' style="width:390px">接口信息</th>
+        <th class='text-left nowrap' style="width:120px">服务号信息</th>
+        <th class='text-left nowrap'></th>
+        <th class='text-left nowrap'></th>
+    </tr>
+    </thead>
+    {/notempty}
+    <tbody>
+    {foreach $list as $key=>$vo}
+    <tr>
+        <td class='text-left nowrap'>
+            <div class="inline-block text-top margin-right-5">
+                <img onerror="this.src='__STATIC__/theme/img/404_icon.png'" style="width:60px;height:60px" data-tips-text="微信头像" data-tips-image src="{$vo.head_img|default=''}">
+            </div>
+            <div class="inline-block">
+                公众号APPID:{$vo.authorizer_appid}&nbsp;&nbsp;&nbsp;&nbsp;调用次数:{$vo.total}<br>
+                接口授权密钥:{$vo.appkey|default='<span class="color-desc">未生成接口服务密码, 请稍候授权绑定</span>'|raw}<br>
+                消息推送接口:{$vo.appuri|default='<span class="color-desc">未配置消息推送接口</span>'|raw}
+            </div>
+        </td>
+        <td class='text-left nowrap'>
+            <div class="inline-block text-top margin-right-5">
+                <img onerror="this.src='__STATIC__/theme/img/404_icon.png'" style="width:60px;height:60px" data-tips-text="微信二维码" data-tips-image src="{$vo.qrcode_url|local_image}">
+            </div>
+            <div class="inline-block">
+                昵称:{$vo.nick_name|default='<span class="color-desc">未获取到公众号昵称</span>'|raw}<br>
+                公司:{$vo.principal_name|default='<span class="color-desc">未获取到公司名字</span>'|raw}<br>
+                状态:{if $vo.service_type eq 2}服务号{elseif $vo.service_type eq 3}小程序{else}订阅号{/if} /
+                {$vo.verify_type == -1 ? '<span class="color-red">未认证</span>' : '<span class="color-green">已认证</span>'} /
+                {if $vo.status eq 0}<span class="color-red">已禁用</span>{elseif $vo.status eq 1}<span class="color-green">使用中</span>{/if}
+            </div>
+        </td>
+        <td class="text-left nowrap">
+            账号:{$vo.user_name|default='--'}<br>
+            日期:{$vo.create_at|format_datetime|str_replace=' ','<br>时间:',###|raw}
+        </td>
+        <td class='text-left nowrap'>
+
+            {if $vo.status eq 1 and auth("servce/index/forbid")}
+            <a class="layui-btn layui-btn-sm layui-btn-warm" data-action="{:url('forbid')}" data-csrf="{:systoken('service/index/forbid')}" data-value="id#{$vo.id};status#0">禁 用</a>
+            {elseif auth("servce/index/resume")}
+            <a class="layui-btn layui-btn-sm layui-btn-warm" data-action="{:url('resume')}" data-csrf="{:systoken('service/index/resume')}" data-value="id#{$vo.id};status#1">启 用</a>
+            {/if}
+
+            {if auth("service/index/sync")}
+            <a class="layui-btn layui-btn-sm" data-load='{:url("service/index/sync")}?appid={$vo.authorizer_appid}'>同 步</a>
+            {/if}
+
+            {if auth("service/index/del")}
+            <a class="layui-btn layui-btn-sm layui-btn-danger" data-confirm="确定要删除该公众号吗?" data-action="{:url('del')}" data-csrf="{:systoken('service/index/del')}" data-value="id#{$vo.id}">删 除</a>
+            {/if}
+
+            {if auth("service/index/clearquota")}
+            <a class="layui-btn layui-btn-sm layui-btn-primary" data-confirm="每个公众号每个月有10次清零机会,请谨慎使用!" data-load='{:url("service/index/clearquota")}?appid={$vo.authorizer_appid}'>清 零</a>
+            {/if}
+
+        </td>
+    </tr>
+    {/foreach}
+    </tbody>
+</table>
+
+{empty name='list'}<span class="notdata">没有记录哦</span>{else}{$pagehtml|raw|default=''}{/empty}
+
+{/block}

+ 77 - 0
application/service/view/index/index_search.html

@@ -0,0 +1,77 @@
+<fieldset>
+
+    <legend class="layui-bg-cyan">条件搜索</legend>
+
+    <form class="layui-form layui-form-pane form-search" action="{:request()->url()}" onsubmit="return false" method="get" autocomplete="off">
+
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">微信标识</label>
+            <div class="layui-input-inline">
+                <input name="authorizer_appid" value="{$Think.get.authorizer_appid|default=''}" placeholder="请输入微信APPID" class="layui-input">
+            </div>
+        </div>
+
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">微信名称</label>
+            <div class="layui-input-inline">
+                <input name="nick_name" value="{$Think.get.nick_name|default=''}" placeholder="请输入微信名称" class="layui-input">
+            </div>
+        </div>
+
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">类型过滤</label>
+            <div class="layui-input-inline">
+                <select name="service_type" class="layui-select">
+                    <option value="">- 全部 -</option>
+                    {foreach ['0'=>'显示订阅号类型','2'=>'显示服务号类型','3'=>'显示小程序类型'] as $k=>$v}
+                    <!--{if $k.'' eq $Think.get.service_type}-->
+                    <option selected value="{$k}">{$v}</option>
+                    <!--{else}-->
+                    <option value="{$k}">{$v}</option>
+                    <!--{/if}-->
+                    {/foreach}
+                </select>
+            </div>
+        </div>
+
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">使用状态</label>
+            <div class="layui-input-inline">
+                <select class="layui-select" name="status">
+                    {foreach [''=>'- 全部 -','0'=>'已禁用的账号','1'=>'使用中的账号'] as $k=>$v}
+                    {eq name='Think.get.status' value='$k.""'}
+                    <option selected value="{$k}">{$v}</option>
+                    {else}
+                    <option value="{$k}">{$v}</option>
+                    {/eq}
+                    {/foreach}
+                </select>
+            </div>
+        </div>
+
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">注册公司</label>
+            <div class="layui-input-inline">
+                <input name="principal_name" value="{$Think.get.principal_name|default=''}" placeholder="请输入注册公司" class="layui-input">
+            </div>
+        </div>
+
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">授权时间</label>
+            <div class="layui-input-inline">
+                <input id="create_at" name="create_at" value="{$Think.get.create_at|default=''}" placeholder="请选择授权时间" class="layui-input">
+            </div>
+        </div>
+
+        <div class="layui-form-item layui-inline">
+            <button class="layui-btn layui-btn-primary"><i class="layui-icon">&#xe615;</i> 搜 索</button>
+        </div>
+
+    </form>
+
+</fieldset>
+
+<script>
+    window.form.render();
+    window.laydate.render({range: true, elem: '#create_at'});
+</script>

+ 70 - 0
application/store/command/AutoRun.php

@@ -0,0 +1,70 @@
+<?php
+
+// +----------------------------------------------------------------------
+// | framework
+// +----------------------------------------------------------------------
+// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// +----------------------------------------------------------------------
+// | 官方网站: http://framework.thinkadmin.top
+// +----------------------------------------------------------------------
+// | 开源协议 ( https://mit-license.org )
+// +----------------------------------------------------------------------
+// | github开源项目:https://github.com/zoujingli/ThinkAdmin
+// +----------------------------------------------------------------------
+
+namespace app\store\command;
+
+use think\console\Command;
+use think\Db;
+
+/**
+ * 商城数据处理指令
+ * Class AutoRun
+ * @package app\store\command
+ */
+class AutoRun extends Command
+{
+
+    protected function configure()
+    {
+        $this->setName('xclean:store')->setDescription('clean up invalid store records');
+    }
+
+    /**
+     * 执行指令
+     * @param \think\console\Input $input
+     * @param \think\console\Output $output
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
+     */
+    protected function execute(\think\console\Input $input, \think\console\Output $output)
+    {
+        # 自动取消30分钟未支付的订单
+        $where = [['create_at', '<', date('Y-m-d H:i:s', strtotime('-30 minutes'))]];
+        $count = Db::name('StoreOrder')->where(['pay_state' => '0'])->whereIn('status', ['1', '2'])->where($where)->update([
+            'status'       => '0',
+            'cancel_state' => '1',
+            'cancel_at'    => date('Y-m-d H:i:s'),
+            'cancel_desc'  => '30分钟未完成支付自动取消订单',
+        ]);
+        if ($count > 0) {
+            $this->output->info("共计自动取消了30分钟未支付的{$count}笔订单!");
+        } else {
+            $this->output->comment('没有需要自动取消30分钟未支付的订单记录!');
+        }
+        # 清理一天前未支付的订单
+        $where = [['create_at', '<', date('Y-m-d H:i:s', strtotime('-1 day'))]];
+        $list = Db::name('StoreOrder')->where(['pay_state' => '0'])->where($where)->limit(20)->select();
+        if (count($order_nos = array_unique(array_column($list, 'order_no'))) > 0) {
+            $this->output->info("自动删除前一天已经取消的订单:\n\t" . join(',' . PHP_EOL . "\t", $order_nos));
+            Db::name('StoreOrder')->whereIn('order_no', $order_nos)->delete();
+            Db::name('StoreOrderList')->whereIn('order_no', $order_nos)->delete();
+        } else {
+            $this->output->comment('没有需要自动删除前一天已经取消的订单!');
+        }
+    }
+
+}

+ 44 - 0
application/store/controller/Config.php

@@ -0,0 +1,44 @@
+<?php
+
+// +----------------------------------------------------------------------
+// | framework
+// +----------------------------------------------------------------------
+// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// +----------------------------------------------------------------------
+// | 官方网站: http://framework.thinkadmin.top
+// +----------------------------------------------------------------------
+// | 开源协议 ( https://mit-license.org )
+// +----------------------------------------------------------------------
+// | github开源项目:https://github.com/zoujingli/ThinkAdmin
+// +----------------------------------------------------------------------
+
+namespace app\store\controller;
+
+use app\store\service\Extend;
+use library\Controller;
+
+/**
+ * 微信商城配置
+ * Class Config
+ * @package app\store\controller
+ */
+class Config extends Controller
+{
+    /**
+     * 微信商城配置
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function index()
+    {
+        $this->applyCsrfToken();
+        $this->title = '商城参数配置';
+        if ($this->request->isGet()) {
+            $this->query = Extend::querySmsBalance();
+            return $this->fetch();
+        }
+        foreach ($this->request->post() as $k => $v) sysconf($k, $v);
+        $this->success('商城参数配置保存成功!');
+    }
+
+}

+ 35 - 60
application/store/controller/Express.php

@@ -1,126 +1,101 @@
 <?php
 
 // +----------------------------------------------------------------------
-// | Think.Admin
+// | framework
 // +----------------------------------------------------------------------
-// | 版权所有 2014~2017 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
 // +----------------------------------------------------------------------
-// | 官方网站: http://think.ctolog.com
+// | 官方网站: http://framework.thinkadmin.top
 // +----------------------------------------------------------------------
 // | 开源协议 ( https://mit-license.org )
 // +----------------------------------------------------------------------
-// | github开源项目:https://github.com/zoujingli/Think.Admin
+// | github开源项目:https://github.com/zoujingli/ThinkAdmin
 // +----------------------------------------------------------------------
 
 namespace app\store\controller;
 
-use controller\BasicAdmin;
-use service\DataService;
+use library\Controller;
 use think\Db;
 
 /**
- * 商城快递公司管理
+ * 快递公司管理
  * Class Express
  * @package app\store\controller
- * @author Anyon <zoujingli@qq.com>
- * @date 2017/03/27 14:43
  */
-class Express extends BasicAdmin
+class Express extends Controller
 {
-
     /**
-     * 定义当前操作表名
+     * 指定数据表
      * @var string
      */
-    public $table = 'StoreExpress';
+    protected $table = 'StoreExpress';
 
     /**
-     * 快递公司列表
-     * @return array|string
      * @throws \think\Exception
      * @throws \think\db\exception\DataNotFoundException
      * @throws \think\db\exception\ModelNotFoundException
      * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
      */
     public function index()
     {
         $this->title = '快递公司管理';
-        list($get, $db) = [$this->request->get(), Db::name($this->table)];
-        foreach (['express_title', 'express_code'] as $field) {
-            (isset($get[$field]) && $get[$field] !== '') && $db->whereLike($field, "%{$get[$field]}%");
-        }
-        if (isset($get['date']) && $get['date'] !== '') {
-            list($start, $end) = explode(' - ', $get['date']);
-            $db->whereBetween('create_at', ["{$start} 00:00:00", "{$end} 23:59:59"]);
-        }
-        return parent::_list($db->where(['is_deleted' => '0'])->order('status desc,sort asc,id desc'));
+        $this->_query($this->table)->equal('status')->like('express_title,express_code')->dateBetween('create_at')->order('status desc,sort asc,id desc')->page();
     }
 
     /**
      * 添加快递公司
-     * @return array|string
-     * @throws \think\Exception
-     * @throws \think\db\exception\DataNotFoundException
-     * @throws \think\db\exception\ModelNotFoundException
-     * @throws \think\exception\DbException
      */
     public function add()
     {
-        $this->title = '添加快递公司';
-        return $this->_form($this->table, 'form');
+        $this->_form($this->table, 'form');
     }
 
     /**
      * 编辑快递公司
-     * @return array|string
-     * @throws \think\Exception
-     * @throws \think\db\exception\DataNotFoundException
-     * @throws \think\db\exception\ModelNotFoundException
-     * @throws \think\exception\DbException
      */
     public function edit()
     {
-        $this->title = '编辑快递公司';
-        return $this->_form($this->table, 'form');
+        $this->_form($this->table, 'form');
     }
 
     /**
-     * 删除快递公司
-     * @throws \think\Exception
-     * @throws \think\exception\PDOException
+     * 表单数据处理
+     * @param array $data
      */
-    public function del()
+    protected function _form_filter(array $data)
     {
-        if (DataService::update($this->table)) {
-            $this->success("快递公司删除成功!", '');
+        if ($this->request->isPost()) {
+            $where = [['express_code', 'eq', $data['express_code']], ['is_deleted', 'eq', '0']];
+            if (!empty($data['id'])) $where[] = ['id ', 'neq', $data['id']];
+            if (Db::name($this->table)->where($where)->count() > 0) {
+                $this->error('该快递编码已经存在,请使用其它编码!');
+            }
         }
-        $this->error("快递公司删除失败,请稍候再试!");
     }
 
     /**
-     * 快递公司禁用
-     * @throws \think\Exception
-     * @throws \think\exception\PDOException
+     * 禁用快递公司
      */
     public function forbid()
     {
-        if (DataService::update($this->table)) {
-            $this->success("快递公司禁用成功!", '');
-        }
-        $this->error("快递公司禁用失败,请稍候再试!");
+        $this->_save($this->table, ['status' => '0']);
     }
 
     /**
-     * 快递公司禁用
-     * @throws \think\Exception
-     * @throws \think\exception\PDOException
+     * 启用快递公司
      */
     public function resume()
     {
-        if (DataService::update($this->table)) {
-            $this->success("快递公司启用成功!", '');
-        }
-        $this->error("快递公司启用失败,请稍候再试!");
+        $this->_save($this->table, ['status' => '1']);
+    }
+
+    /**
+     * 删除快递公司
+     */
+    public function del()
+    {
+        $this->_delete($this->table);
     }
 
-}
+}

+ 90 - 207
application/store/controller/Goods.php

@@ -1,11 +1,11 @@
 <?php
 
 // +----------------------------------------------------------------------
-// | ThinkAdmin
+// | framework
 // +----------------------------------------------------------------------
-// | 版权所有 2014~2017 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
 // +----------------------------------------------------------------------
-// | 官方网站: http://think.ctolog.com
+// | 官方网站: http://framework.thinkadmin.top
 // +----------------------------------------------------------------------
 // | 开源协议 ( https://mit-license.org )
 // +----------------------------------------------------------------------
@@ -14,291 +14,174 @@
 
 namespace app\store\controller;
 
-use app\store\service\GoodsService;
-use controller\BasicAdmin;
-use service\DataService;
-use service\ToolsService;
+use library\Controller;
+use library\tools\Data;
 use think\Db;
-use think\exception\HttpResponseException;
 
 /**
- * 商商品管理
+ * 商商品管理
  * Class Goods
  * @package app\store\controller
- * @author Anyon <zoujingli@qq.com>
- * @date 2017/03/27 14:43
  */
-class Goods extends BasicAdmin
+class Goods extends Controller
 {
-
     /**
-     * 定义当前操作表名
+     * 指定数据表
      * @var string
      */
-    public $table = 'StoreGoods';
+    protected $table = 'StoreGoods';
 
     /**
-     * 普通商品
-     * @return array|string
+     * 商品列表
+     * @return mixed
      * @throws \think\Exception
      * @throws \think\db\exception\DataNotFoundException
      * @throws \think\db\exception\ModelNotFoundException
      * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
      */
     public function index()
     {
         $this->title = '商品管理';
-        $get = $this->request->get();
-        $db = Db::name($this->table)->where(['is_deleted' => '0']);
-        if (isset($get['tags_id']) && $get['tags_id'] !== '') {
-            $db->whereLike('tags_id', "%,{$get['tags_id']},%");
-        }
-        if (isset($get['goods_title']) && $get['goods_title'] !== '') {
-            $db->whereLike('goods_title', "%{$get['goods_title']}%");
-        }
-        foreach (['cate_id', 'brand_id'] as $field) {
-            (isset($get[$field]) && $get[$field] !== '') && $db->where($field, $get[$field]);
-        }
-        if (isset($get['create_at']) && $get['create_at'] !== '') {
-            list($start, $end) = explode(' - ', $get['create_at']);
-            $db->whereBetween('create_at', ["{$start} 00:00:00", "{$end} 23:59:59"]);
-        }
-        return parent::_list($db->order('status desc,sort asc,id desc'));
+        return $this->_query($this->table)->equal('status,vip_mod,cate_id')->like('title')->where(['is_deleted' => '0'])->order('sort asc,id desc')->page();
     }
 
     /**
-     * 商城数据处理
+     * 数据列表处理
      * @param array $data
-     */
-    protected function _data_filter(&$data)
-    {
-        $result = GoodsService::buildGoodsList($data);
-        $this->assign([
-            'brands' => $result['brand'],
-            'cates'  => ToolsService::arr2table($result['cate']),
-        ]);
-    }
-
-    /**
-     * 添加商品
-     * @return array|string
      * @throws \think\db\exception\DataNotFoundException
      * @throws \think\db\exception\ModelNotFoundException
      * @throws \think\exception\DbException
-     * @throws \think\Exception
      */
-    public function add()
+    protected function _index_page_filter(&$data)
     {
-        if ($this->request->isGet()) {
-            $this->title = '添加商品';
-            $this->_form_assign();
-            return $this->_form($this->table, 'form');
-        }
-        try {
-            $data = $this->_form_build_data();
-            Db::transaction(function () use ($data) {
-                $goodsID = Db::name($this->table)->insertGetId($data['main']);
-                foreach ($data['list'] as &$vo) {
-                    $vo['goods_id'] = $goodsID;
-                }
-                Db::name('StoreGoodsList')->insertAll($data['list']);
-            });
-        } catch (HttpResponseException $exception) {
-            return $exception->getResponse();
-        } catch (\Exception $e) {
-            $this->error('商品添加失败,请稍候再试!');
+        $this->clist = Db::name('StoreGoodsCate')->where(['is_deleted' => '0', 'status' => '1'])->select();
+        $list = Db::name('StoreGoodsList')->where('status', '1')->whereIn('goods_id', array_unique(array_column($data, 'id')))->select();
+        foreach ($data as &$vo) {
+            list($vo['list'], $vo['cate']) = [[], []];
+            foreach ($list as $goods) if ($goods['goods_id'] === $vo['id']) array_push($vo['list'], $goods);
+            foreach ($this->clist as $cate) if ($cate['id'] === $vo['cate_id']) $vo['cate'] = $cate;
         }
-        list($base, $spm, $url) = [url('@admin'), $this->request->get('spm'), url('store/goods/index')];
-        $this->success('添加商品成功!', "{$base}#{$url}?spm={$spm}");
     }
 
     /**
-     * 编辑商品
-     * @return array|string
+     * 商品库存入库
+     * @return mixed
+     * @throws \think\Exception
      * @throws \think\db\exception\DataNotFoundException
      * @throws \think\db\exception\ModelNotFoundException
      * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
      */
-    public function edit()
+    public function stock()
     {
-        if (!$this->request->isPost()) {
-            $goods_id = $this->request->get('id');
-            $goods = Db::name($this->table)->where(['id' => $goods_id, 'is_deleted' => '0'])->find();
-            empty($goods) && $this->error('需要编辑的商品不存在!');
-            $goods['list'] = Db::name('StoreGoodsList')->where(['goods_id' => $goods_id, 'is_deleted' => '0'])->select();
-            $this->_form_assign();
-            return $this->fetch('form', ['vo' => $goods, 'title' => '编辑商品']);
+        if ($this->request->isGet()) {
+            $GoodsId = $this->request->get('id');
+            $goods = Db::name('StoreGoods')->where(['id' => $GoodsId])->find();
+            empty($goods) && $this->error('无效的商品信息,请稍候再试!');
+            $goods['list'] = Db::name('StoreGoodsList')->where(['goods_id' => $GoodsId])->select();
+            return $this->fetch('', ['vo' => $goods]);
         }
-        try {
-            $data = $this->_form_build_data();
-            $goods_id = $this->request->post('id');
-            $goods = Db::name($this->table)->where(['id' => $goods_id, 'is_deleted' => '0'])->find();
-            empty($goods) && $this->error('商品编辑失败,请稍候再试!');
-            foreach ($data['list'] as &$vo) {
-                $vo['goods_id'] = $goods_id;
+        list($post, $data) = [$this->request->post(), []];
+        if (isset($post['id']) && isset($post['spec']) && is_array($post['spec'])) {
+            foreach ($post['spec'] as $k => $v) if ($v > 0) array_push($data, [
+                'goods_id' => $post['id'], 'goods_spec' => $k, 'number_stock' => $v,
+            ]);
+            if (!empty($data)) {
+                Db::name('StoreGoodsStock')->insertAll($data);
+                \app\store\service\Goods::syncStock($post['id']);
+                $this->success('商品信息入库成功!');
             }
-            Db::transaction(function () use ($data, $goods_id, $goods) {
-                // 更新商品主表
-                $where = ['id' => $goods_id, 'is_deleted' => '0'];
-                Db::name('StoreGoods')->where($where)->update(array_merge($goods, $data['main']));
-                // 更新商品详细
-                Db::name('StoreGoodsList')->where(['goods_id' => $goods_id])->delete();
-                Db::name('StoreGoodsList')->insertAll($data['list']);
-            });
-        } catch (HttpResponseException $exception) {
-            return $exception->getResponse();
-        } catch (\Exception $e) {
-            $this->error('商品编辑失败,请稍候再试!' . $e->getMessage());
         }
-        list($base, $spm, $url) = [url('@admin'), $this->request->get('spm'), url('store/goods/index')];
-        $this->success('商品编辑成功!', "{$base}#{$url}?spm={$spm}");
+        $this->error('没有需要商品入库的数据!');
     }
 
     /**
-     * 表单数据处理
-     * @throws \think\db\exception\DataNotFoundException
-     * @throws \think\db\exception\ModelNotFoundException
-     * @throws \think\exception\DbException
+     * 添加商品信息
+     * @return mixed
      */
-    protected function _form_assign()
+    public function add()
     {
-        list($where, $order) = [['status' => '1', 'is_deleted' => '0'], 'sort asc,id desc'];
-        $specs = (array)Db::name('StoreGoodsSpec')->where($where)->order($order)->select();
-        $brands = (array)Db::name('StoreGoodsBrand')->where($where)->order($order)->select();
-        $cates = (array)Db::name('StoreGoodsCate')->where($where)->order($order)->select();
-        // 所有的商品信息
-        $where = ['is_deleted' => '0', 'status' => '1'];
-        $goodsListField = 'goods_id,goods_spec,goods_stock,goods_sale';
-        $goods = Db::name('StoreGoods')->field('id,goods_title')->where($where)->select();
-        $list = Db::name('StoreGoodsList')->field($goodsListField)->where($where)->select();
-        foreach ($goods as $k => $g) {
-            $goods[$k]['list'] = [];
-            foreach ($list as $v) {
-                ($g['id'] === $v['goods_id']) && $goods[$k]['list'][] = $v;
-            }
-        }
-        array_unshift($specs, ['spec_title' => ' - 不使用规格模板 -', 'spec_param' => '[]', 'id' => '0']);
-        $this->assign([
-            'specs'  => $specs,
-            'cates'  => ToolsService::arr2table($cates),
-            'brands' => $brands,
-            'all'    => $goods,
-        ]);
+        $this->title = '添加商品';
+        $this->isAddMode = '1';
+        return $this->_form($this->table, 'form');
     }
 
     /**
-     * 读取POST表单数据
-     * @return array
+     * 编辑商品信息
+     * @return mixed
      */
-    protected function _form_build_data()
+    public function edit()
     {
-        list($main, $list, $post, $verify) = [[], [], $this->request->post(), false];
-        empty($post['goods_logo']) && $this->error('商品LOGO不能为空,请上传后再提交数据!');
-        // 商品主数据组装
-        $main['cate_id'] = $this->request->post('cate_id', '0');
-        $main['spec_id'] = $this->request->post('spec_id', '0');
-        $main['brand_id'] = $this->request->post('brand_id', '0');
-        $main['goods_logo'] = $this->request->post('goods_logo', '');
-        $main['goods_title'] = $this->request->post('goods_title', '');
-        $main['goods_video'] = $this->request->post('goods_video', '');
-        $main['goods_image'] = $this->request->post('goods_image', '');
-        $main['goods_desc'] = $this->request->post('goods_desc', '', null);
-        $main['goods_content'] = $this->request->post('goods_content', '');
-        $main['tags_id'] = ',' . join(',', isset($post['tags_id']) ? $post['tags_id'] : []) . ',';
-        // 商品从数据组装
-        if (!empty($post['goods_spec'])) {
-            foreach ($post['goods_spec'] as $key => $value) {
-                $goods = [];
-                $goods['goods_spec'] = $value;
-                $goods['market_price'] = $post['market_price'][$key];
-                $goods['selling_price'] = $post['selling_price'][$key];
-                $goods['status'] = intval(!empty($post['spec_status'][$key]));
-                !empty($goods['status']) && $verify = true;
-                $list[] = $goods;
-            }
-        } else {
-            $this->error('没有商品规格或套餐信息哦!');
-        }
-        !$verify && $this->error('没有设置有效的商品规格!');
-        return ['main' => $main, 'list' => $list];
+        $this->title = '编辑商品';
+        $this->isAddMode = '0';
+        return $this->_form($this->table, 'form');
     }
 
     /**
-     * 商品库存信息更新
-     * @return string
+     * 表单数据处理
+     * @param array $data
      * @throws \think\Exception
      * @throws \think\db\exception\DataNotFoundException
      * @throws \think\db\exception\ModelNotFoundException
      * @throws \think\exception\DbException
      * @throws \think\exception\PDOException
      */
-    public function stock()
+    protected function _form_filter(&$data)
     {
-        if (!$this->request->post()) {
-            $goods_id = $this->request->get('id');
-            $goods = Db::name('StoreGoods')->where(['id' => $goods_id, 'is_deleted' => '0'])->find();
-            empty($goods) && $this->error('该商品无法操作入库操作!');
-            $where = ['goods_id' => $goods_id, 'status' => '1', 'is_deleted' => '0'];
-            $goods['list'] = Db::name('StoreGoodsList')->where($where)->select();
-            return $this->fetch('', ['vo' => $goods]);
-        }
-        // 入库保存
-        $goods_id = $this->request->post('id');
-        list($post, $data) = [$this->request->post(), []];
-        foreach ($post['spec'] as $key => $spec) {
-            if ($post['stock'][$key] > 0) {
-                $data[] = [
-                    'goods_stock' => $post['stock'][$key],
-                    'stock_desc'  => $this->request->post('desc'),
-                    'goods_spec'  => $spec, 'goods_id' => $goods_id,
-                ];
-            }
-        }
-        empty($data) && $this->error('无需入库的数据哦!');
-        if (Db::name('StoreGoodsStock')->insertAll($data) !== false) {
-            GoodsService::syncGoodsStock($goods_id);
-            $this->success('商品入库成功!', '');
+        // 生成商品ID
+        if (empty($data['id'])) $data['id'] = Data::uniqidNumberCode(10);
+        if ($this->request->isGet()) {
+            $fields = 'goods_spec,goods_id,status,price_market market,price_selling selling,number_virtual `virtual`';
+            $defaultValues = Db::name('StoreGoodsList')->where(['goods_id' => $data['id']])->column($fields);
+            $this->defaultValues = json_encode($defaultValues, JSON_UNESCAPED_UNICODE);
+            $this->cates = Db::name('StoreGoodsCate')->where(['is_deleted' => '0', 'status' => '1'])->order('sort asc,id desc')->select();
+        } elseif ($this->request->isPost()) {
+            Db::name('StoreGoodsList')->where(['goods_id' => $data['id']])->update(['status' => '0']);
+            foreach (json_decode($data['lists'], true) as $vo) Data::save('StoreGoodsList', [
+                'goods_id'       => $data['id'],
+                'goods_spec'     => $vo[0]['key'],
+                'price_market'   => $vo[0]['market'],
+                'price_selling'  => $vo[0]['selling'],
+                'number_virtual' => $vo[0]['virtual'],
+                'status'         => $vo[0]['status'] ? 1 : 0,
+            ], 'goods_spec', ['goods_id' => $data['id']]);
         }
-        $this->error('商品入库失败,请稍候再试!');
     }
 
     /**
-     * 删除商品
-     * @throws \think\Exception
-     * @throws \think\exception\PDOException
+     * 表单结果处理
+     * @param boolean $result
      */
-    public function del()
+    protected function _form_result($result)
     {
-        if (DataService::update($this->table)) {
-            $this->success("商品删除成功!", '');
+        if ($result && $this->request->isPost()) {
+            $this->success('商品编辑成功!', 'javascript:history.back()');
         }
-        $this->error("商品删除失败,请稍候再试!");
     }
 
     /**
      * 商品禁用
-     * @throws \think\Exception
-     * @throws \think\exception\PDOException
      */
     public function forbid()
     {
-        if (DataService::update($this->table)) {
-            $this->success("商品下架成功!", '');
-        }
-        $this->error("商品下架失败,请稍候再试!");
+        $this->_save($this->table, ['status' => '0']);
     }
 
     /**
      * 商品禁用
-     * @throws \think\Exception
-     * @throws \think\exception\PDOException
      */
     public function resume()
     {
-        if (DataService::update($this->table)) {
-            $this->success("商品上架成功!", '');
-        }
-        $this->error("商品上架失败,请稍候再试!");
+        $this->_save($this->table, ['status' => '1']);
+    }
+
+    /**
+     * 删除商品
+     */
+    public function del()
+    {
+        $this->_delete($this->table);
     }
 
-}
+}

+ 0 - 151
application/store/controller/GoodsBrand.php

@@ -1,151 +0,0 @@
-<?php
-
-// +----------------------------------------------------------------------
-// | Think.Admin
-// +----------------------------------------------------------------------
-// | 版权所有 2014~2017 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
-// +----------------------------------------------------------------------
-// | 官方网站: http://think.ctolog.com
-// +----------------------------------------------------------------------
-// | 开源协议 ( https://mit-license.org )
-// +----------------------------------------------------------------------
-// | github开源项目:https://github.com/zoujingli/Think.Admin
-// +----------------------------------------------------------------------
-
-namespace app\store\controller;
-
-use controller\BasicAdmin;
-use service\DataService;
-use think\Db;
-
-/**
- * 商店品牌管理
- * Class Brand
- * @package app\store\controller
- * @author Anyon <zoujingli@qq.com>
- * @date 2017/03/27 14:43
- */
-class GoodsBrand extends BasicAdmin
-{
-
-    /**
-     * 定义当前操作表名
-     * @var string
-     */
-    public $table = 'StoreGoodsBrand';
-
-    /**
-     * 品牌列表
-     * @return array|string
-     * @throws \think\Exception
-     * @throws \think\db\exception\DataNotFoundException
-     * @throws \think\db\exception\ModelNotFoundException
-     * @throws \think\exception\DbException
-     */
-    public function index()
-    {
-        $this->title = '品牌管理';
-        $get = $this->request->get();
-        $db = Db::name($this->table)->where(['is_deleted' => '0']);
-        if (isset($get['brand_title']) && $get['brand_title'] !== '') {
-            $db->whereLike('brand_title', "%{$get['brand_title']}%");
-        }
-        if (isset($get['create_at']) && $get['create_at'] !== '') {
-            list($start, $end) = explode(' - ', $get['create_at']);
-            $db->whereBetween('create_at', ["{$start} 00:00:00", "{$end} 23:59:59"]);
-        }
-        return parent::_list($db->order('sort asc,id desc'));
-    }
-
-    /**
-     * 添加品牌
-     * @return array|string
-     * @throws \think\db\exception\DataNotFoundException
-     * @throws \think\db\exception\ModelNotFoundException
-     * @throws \think\exception\DbException
-     * @throws \think\Exception
-     */
-    public function add()
-    {
-        $this->title = '添加品牌';
-        return $this->_form($this->table, 'form');
-    }
-
-    /**
-     * 编辑品牌
-     * @return array|string
-     * @throws \think\db\exception\DataNotFoundException
-     * @throws \think\db\exception\ModelNotFoundException
-     * @throws \think\exception\DbException
-     * @throws \think\Exception
-     */
-    public function edit()
-    {
-        $this->title = '编辑品牌';
-        return $this->_form($this->table, 'form');
-    }
-
-    /**
-     * 表单提交数据处理
-     * @param array $data
-     */
-    protected function _form_filter($data)
-    {
-        if ($this->request->isPost()) {
-            empty($data['brand_logo']) && $this->error('请上传品牌Logo图片');
-            empty($data['brand_cover']) && $this->error('请上传品牌封面图片');
-        }
-    }
-
-    /**
-     * 添加成功回跳处理
-     * @param bool $result
-     */
-    protected function _form_result($result)
-    {
-        if ($result !== false) {
-            list($base, $spm, $url) = [url('@admin'), $this->request->get('spm'), url('store/goods_brand/index')];
-            $this->success('数据保存成功!', "{$base}#{$url}?spm={$spm}");
-        }
-    }
-
-    /**
-     * 删除品牌
-     * @throws \think\Exception
-     * @throws \think\exception\PDOException
-     */
-    public function del()
-    {
-        if (DataService::update($this->table)) {
-            $this->success("品牌删除成功!", '');
-        }
-        $this->error("品牌删除失败,请稍候再试!");
-    }
-
-    /**
-     * 品牌禁用
-     * @throws \think\Exception
-     * @throws \think\exception\PDOException
-     */
-    public function forbid()
-    {
-        if (DataService::update($this->table)) {
-            $this->success("品牌禁用成功!", '');
-        }
-        $this->error("品牌禁用失败,请稍候再试!");
-    }
-
-    /**
-     * 品牌签禁用
-     * @throws \think\Exception
-     * @throws \think\exception\PDOException
-     */
-    public function resume()
-    {
-        if (DataService::update($this->table)) {
-            $this->success("品牌启用成功!", '');
-        }
-        $this->error("品牌启用失败,请稍候再试!");
-    }
-
-}

+ 27 - 95
application/store/controller/GoodsCate.php

@@ -1,11 +1,11 @@
 <?php
 
 // +----------------------------------------------------------------------
-// | ThinkAdmin
+// | framework
 // +----------------------------------------------------------------------
-// | 版权所有 2014~2017 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
 // +----------------------------------------------------------------------
-// | 官方网站: http://think.ctolog.com
+// | 官方网站: http://framework.thinkadmin.top
 // +----------------------------------------------------------------------
 // | 开源协议 ( https://mit-license.org )
 // +----------------------------------------------------------------------
@@ -14,144 +14,76 @@
 
 namespace app\store\controller;
 
-use controller\BasicAdmin;
-use service\DataService;
-use service\ToolsService;
-use think\Db;
+use library\Controller;
 
 /**
- * 商店商品分类管理
- * Class Cate
+ * Class GoodsCate
  * @package app\store\controller
- * @author Anyon <zoujingli@qq.com>
- * @date 2017/03/27 14:43
  */
-class GoodsCate extends BasicAdmin
+class GoodsCate extends Controller
 {
-
     /**
-     * 定义当前操作表名
+     * 绑定数据表
      * @var string
      */
-    public $table = 'StoreGoodsCate';
+    protected $table = 'StoreGoodsCate';
 
     /**
-     * 商品分类列表
-     * @return array|string
+     * @return mixed
      * @throws \think\Exception
      * @throws \think\db\exception\DataNotFoundException
      * @throws \think\db\exception\ModelNotFoundException
      * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
      */
     public function index()
     {
-        $this->title = '商品分类';
-        $db = Db::name($this->table)->where(['is_deleted' => '0']);
-        return parent::_list($db->order('sort asc,id asc'), false);
-    }
-
-    /**
-     * 列表数据处理
-     * @param array $data
-     */
-    protected function _index_data_filter(&$data)
-    {
-        foreach ($data as &$vo) {
-            $vo['ids'] = join(',', ToolsService::getArrSubIds($data, $vo['id']));
-        }
-        $data = ToolsService::arr2table($data);
+        $this->title = '商品分类管理';
+        return $this->_query($this->table)->like('title')->equal('status')->order('sort asc,id desc')->page();
     }
 
     /**
-     * 添加菜单
-     * @return array|string
-     * @throws \think\Exception
-     * @throws \think\db\exception\DataNotFoundException
-     * @throws \think\db\exception\ModelNotFoundException
-     * @throws \think\exception\DbException
+     * 添加商品分类信息
+     * @return mixed
      */
     public function add()
     {
+        $this->title = '添加商品分类';
         return $this->_form($this->table, 'form');
     }
 
     /**
-     * 编辑菜单
-     * @return array|string
-     * @throws \think\Exception
-     * @throws \think\db\exception\DataNotFoundException
-     * @throws \think\db\exception\ModelNotFoundException
-     * @throws \think\exception\DbException
+     * 编辑商品分类信息
+     * @return mixed
      */
     public function edit()
     {
+        $this->title = '编辑商品分类';
         return $this->_form($this->table, 'form');
     }
 
     /**
-     * 表单数据前缀方法
-     * @param array $vo
-     * @throws \think\db\exception\DataNotFoundException
-     * @throws \think\db\exception\ModelNotFoundException
-     * @throws \think\exception\DbException
-     */
-    protected function _form_filter(&$vo)
-    {
-        if ($this->request->isGet()) {
-            // 读取上级分类
-            $where = ['status' => '1', 'is_deleted' => '0'];
-            $_cates = (array)Db::name($this->table)->where($where)->order('sort desc,id desc')->select();
-            array_unshift($_cates, ['id' => 0, 'pid' => -1, 'cate_title' => '--- 顶级分类 ---']);
-            $cates = ToolsService::arr2table($_cates);
-            foreach ($cates as $key => &$cate) {
-                if (isset($vo['pid'])) {
-                    $path = "-{$vo['pid']}-{$vo['id']}";
-                    if ($vo['pid'] !== '' && (stripos("{$cate['path']}-", "{$path}-") !== false || $cate['path'] === $path)) {
-                        unset($cates[$key]);
-                    }
-                }
-            }
-            $this->assign('cates', $cates);
-        }
-    }
-
-    /**
-     * 删除商品分类
-     * @throws \think\Exception
-     * @throws \think\exception\PDOException
+     * 商品分类禁用
      */
-    public function del()
+    public function forbid()
     {
-        if (DataService::update($this->table)) {
-            $this->success("商品分类删除成功!", '');
-        }
-        $this->error("商品分类删除失败,请稍候再试!");
+        $this->_save($this->table, ['status' => '0']);
     }
 
     /**
      * 商品分类禁用
-     * @throws \think\Exception
-     * @throws \think\exception\PDOException
      */
-    public function forbid()
+    public function resume()
     {
-        if (DataService::update($this->table)) {
-            $this->success("商品分类禁用成功!", '');
-        }
-        $this->error("商品分类禁用失败,请稍候再试!");
+        $this->_save($this->table, ['status' => '1']);
     }
 
     /**
-     * 商品分类禁用
-     * @throws \think\Exception
-     * @throws \think\exception\PDOException
+     * 删除商品分类
      */
-    public function resume()
+    public function del()
     {
-        if (DataService::update($this->table)) {
-            $this->success("商品分类启用成功!", '');
-        }
-        $this->error("商品分类启用失败,请稍候再试!");
+        $this->_delete($this->table);
     }
 
-}
+}

+ 0 - 157
application/store/controller/GoodsSpec.php

@@ -1,157 +0,0 @@
-<?php
-
-// +----------------------------------------------------------------------
-// | ThinkAdmin
-// +----------------------------------------------------------------------
-// | 版权所有 2014~2017 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
-// +----------------------------------------------------------------------
-// | 官方网站: http://think.ctolog.com
-// +----------------------------------------------------------------------
-// | 开源协议 ( https://mit-license.org )
-// +----------------------------------------------------------------------
-// | github开源项目:https://github.com/zoujingli/ThinkAdmin
-// +----------------------------------------------------------------------
-
-namespace app\store\controller;
-
-use controller\BasicAdmin;
-use service\DataService;
-use think\Db;
-
-/**
- * 商店规格管理
- * Class Spec
- * @package app\store\controller
- * @author Anyon <zoujingli@qq.com>
- * @date 2017/03/27 14:43
- */
-class GoodsSpec extends BasicAdmin
-{
-
-    /**
-     * 定义当前操作表名
-     * @var string
-     */
-    public $table = 'StoreGoodsSpec';
-
-    /**
-     * 商品列表
-     * @return array|string
-     * @throws \think\Exception
-     * @throws \think\db\exception\DataNotFoundException
-     * @throws \think\db\exception\ModelNotFoundException
-     * @throws \think\exception\DbException
-     */
-    public function index()
-    {
-        $this->title = '规格管理(请勿随意修改或删除)';
-        $get = $this->request->get();
-        $db = Db::name($this->table)->where(['is_deleted' => '0']);
-        if (isset($get['spec_title']) && $get['spec_title'] !== '') {
-            $db->whereLike('spec_title', "%{$get['spec_title']}%");
-        }
-        if (isset($get['date']) && $get['date'] !== '') {
-            list($start, $end) = explode(' - ', $get['date']);
-            $db->whereBetween('create_at', ["{$start} 00:00:00", "{$end} 23:59:59"]);
-        }
-        return parent::_list($db->order('sort asc,id desc'));
-    }
-
-    /**
-     * 列表数据处理
-     * @param array $data
-     */
-    protected function _index_data_filter(&$data)
-    {
-        foreach ($data as &$vo) {
-            $vo['spec_param'] = json_decode($vo['spec_param'], true);
-            $vo['spec_param'] = is_array($vo['spec_param']) ? $vo['spec_param'] : [];
-        }
-    }
-
-    /**
-     * 添加商品
-     * @return array|string
-     * @throws \think\db\exception\DataNotFoundException
-     * @throws \think\db\exception\ModelNotFoundException
-     * @throws \think\exception\DbException
-     * @throws \think\Exception
-     */
-    public function add()
-    {
-        $this->title = '添加规格';
-        return $this->_form($this->table, 'form');
-    }
-
-    /**
-     * 编辑商品
-     * @return array|string
-     * @throws \think\db\exception\DataNotFoundException
-     * @throws \think\db\exception\ModelNotFoundException
-     * @throws \think\exception\DbException
-     * @throws \think\Exception
-     */
-    public function edit()
-    {
-        $this->title = '编辑规格';
-        return $this->_form($this->table, 'form');
-    }
-
-    /**
-     * 表单数据处理
-     * @param array $vo
-     */
-    protected function _form_filter(&$vo)
-    {
-        if ($this->request->isPost()) {
-            $param = json_decode($this->request->post('spec_param', '[]', null), true);
-            foreach ($param as &$v) {
-                $count = 1;
-                while ($count) {
-                    $v['value'] = trim(str_replace(['  ', '_', ',', ',', ';', ';'], ' ', $v['value'], $count));
-                }
-            }
-            $vo['spec_param'] = json_encode($param, JSON_UNESCAPED_UNICODE);
-        }
-    }
-
-    /**
-     * 删除商品规格
-     * @throws \think\Exception
-     * @throws \think\exception\PDOException
-     */
-    public function del()
-    {
-        if (DataService::update($this->table)) {
-            $this->success("商品规格删除成功!", '');
-        }
-        $this->error("商品规格删除失败,请稍候再试!");
-    }
-
-    /**
-     * 商品规格禁用
-     * @throws \think\Exception
-     * @throws \think\exception\PDOException
-     */
-    public function forbid()
-    {
-        if (DataService::update($this->table)) {
-            $this->success("商品规格禁用成功!", '');
-        }
-        $this->error("商品规格禁用失败,请稍候再试!");
-    }
-
-    /**
-     * 商品规格禁用
-     * @throws \think\Exception
-     * @throws \think\exception\PDOException
-     */
-    public function resume()
-    {
-        if (DataService::update($this->table)) {
-            $this->success("商品规格启用成功!", '');
-        }
-        $this->error("商品规格启用失败,请稍候再试!");
-    }
-
-}

+ 57 - 0
application/store/controller/Member.php

@@ -0,0 +1,57 @@
+<?php
+
+// +----------------------------------------------------------------------
+// | framework
+// +----------------------------------------------------------------------
+// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// +----------------------------------------------------------------------
+// | 官方网站: http://framework.thinkadmin.top
+// +----------------------------------------------------------------------
+// | 开源协议 ( https://mit-license.org )
+// +----------------------------------------------------------------------
+// | github开源项目:https://github.com/zoujingli/ThinkAdmin
+// +----------------------------------------------------------------------
+
+namespace app\store\controller;
+
+use library\Controller;
+
+/**
+ * 商城会员管理
+ * Class Member
+ * @package app\store\controller
+ */
+class Member extends Controller
+{
+    /**
+     * 绑定数据表
+     * @var string
+     */
+    protected $table = 'StoreMember';
+
+    /**
+     * 显示会员列表
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
+     */
+    public function index()
+    {
+        $this->title = '商城会员管理';
+        $this->_query($this->table)->like('nickname,phone')->equal('vip_level')->dateBetween('create_at')->order('id desc')->page();
+    }
+
+    /**
+     * 数据列表处理
+     * @param array $data
+     */
+    protected function _page_filter(&$data = [])
+    {
+        foreach ($data as &$vo) {
+            $vo['nickname'] = emoji_decode($vo['nickname']);
+        }
+    }
+
+}

+ 46 - 0
application/store/controller/Message.php

@@ -0,0 +1,46 @@
+<?php
+
+// +----------------------------------------------------------------------
+// | framework
+// +----------------------------------------------------------------------
+// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// +----------------------------------------------------------------------
+// | 官方网站: http://framework.thinkadmin.top
+// +----------------------------------------------------------------------
+// | 开源协议 ( https://mit-license.org )
+// +----------------------------------------------------------------------
+// | github开源项目:https://github.com/zoujingli/ThinkAdmin
+// +----------------------------------------------------------------------
+
+namespace app\store\controller;
+
+use library\Controller;
+
+/**
+ * 短信消息管理
+ * Class Message
+ * @package app\store\controller
+ */
+class Message extends Controller
+{
+    /**
+     * 绑定数据表
+     * @var string
+     */
+    protected $table = 'StoreMemberSmsHistory';
+
+    /**
+     * 短信消息列表
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
+     */
+    public function index()
+    {
+        $this->title = '手机短信记录';
+        $this->_query($this->table)->like('phone,content,result')->dateBetween('create_at')->order('id desc')->page();
+    }
+
+}

+ 66 - 104
application/store/controller/Order.php

@@ -1,157 +1,119 @@
 <?php
 
 // +----------------------------------------------------------------------
-// | Think.Admin
+// | framework
 // +----------------------------------------------------------------------
-// | 版权所有 2014~2017 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
 // +----------------------------------------------------------------------
-// | 官方网站: http://think.ctolog.com
+// | 官方网站: http://framework.thinkadmin.top
 // +----------------------------------------------------------------------
 // | 开源协议 ( https://mit-license.org )
 // +----------------------------------------------------------------------
-// | github开源项目:https://github.com/zoujingli/Think.Admin
+// | github开源项目:https://github.com/zoujingli/ThinkAdmin
 // +----------------------------------------------------------------------
 
 namespace app\store\controller;
 
-use app\store\service\OrderService;
-use controller\BasicAdmin;
-use service\DataService;
+use library\Controller;
 use think\Db;
 
 /**
- * 商订单管理
+ * 商订单管理
  * Class Order
  * @package app\store\controller
- * @author Anyon <zoujingli@qq.com>
- * @date 2017/03/27 14:43
  */
-class Order extends BasicAdmin
+class Order extends Controller
 {
-
     /**
-     * 定义当前操作表名
+     * 绑定数据表
      * @var string
      */
-    public $table = 'StoreOrder';
+    protected $table = 'StoreOrder';
 
     /**
-     * 订单列表
-     * @return array|string
+     * 商城订单列表显示
      * @throws \think\Exception
      * @throws \think\db\exception\DataNotFoundException
      * @throws \think\db\exception\ModelNotFoundException
      * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
      */
     public function index()
     {
-        $this->title = '订单管理';
-        $db = Db::name($this->table);
-        $get = $this->request->get();
-        // 会员信息查询过滤
-        $memberWhere = [];
-        foreach (['phone', 'nickname'] as $field) {
-            if (isset($get[$field]) && $get[$field] !== '') {
-                $memberWhere[] = [$field, 'like', "%{$get[$field]}%"];
-            }
-        }
-        if (!empty($memberWhere)) {
-            $memberWhere['status'] = '1';
-            $sql = Db::name('Member')->field('id')->where($memberWhere)->buildSql(true);
-            $db->where("mid in {$sql}");
-        }
-        // =============== 商品信息查询过滤 ===============
-        $goodsWhere = [];
-        foreach (['goods_title'] as $field) {
-            if (isset($get[$field]) && $get[$field] !== '') {
-                $goodsWhere[] = [$field, 'like', "%{$get[$field]}%"];
-            }
-        }
-        if (!empty($goodsWhere)) {
-            $sql = Db::name('StoreOrderList')->field('order_no')->where($goodsWhere)->buildSql(true);
-            $db->where("order_no in {$sql}");
-        }
-        // =============== 收货地址过滤 ===============
-        $expressWhere = [];
-        if (isset($get['express_title']) && $get['express_title'] !== '') {
-            $expressWhere[] = ['send_company_title|company_title', 'like', "%{$get['express_title']}%"];
-        }
-        foreach (['send_no', 'username', 'phone', 'province', 'city', 'area', 'address'] as $field) {
-            if (isset($get[$field]) && $get[$field] !== '') {
-                $expressWhere[] = [$field, 'like', "%{$get[$field]}%"];
-            }
-        }
-        if (isset($get['send_status']) && $get['send_status'] !== '') {
-            $expressWhere[] = empty($get['send_status']) ? ['send_no', 'eq', ''] : ['send_no', 'neq', ''];
-        }
-        if (!empty($expressWhere)) {
-            $sql = Db::name('StoreOrderExpress')->field('order_no')->where($expressWhere)->buildSql(true);
-            $db->where("order_no in {$sql}");
-        }
-        // =============== 主订单过滤 ===============
-        foreach (['order_no', 'desc'] as $field) {
-            (isset($get[$field]) && $get[$field] !== '') && $db->whereLike($field, "%{$get[$field]}%");
-        }
-        (isset($get['status']) && $get['status'] !== '') && $db->where('status', $get['status']);
-        // 订单是否包邮状态检索
-        if (isset($get['express_zero']) && $get['express_zero'] !== '') {
-            empty($get['express_zero']) ? $db->where('freight_price', '>', '0') : $db->where('freight_price', '0');
-        }
-        // 订单时间过滤
-        foreach (['create_at', 'pay_at'] as $field) {
-            if (isset($get[$field]) && $get[$field] !== '') {
-                list($start, $end) = explode(' - ', $get[$field]);
-                $db->whereBetween($field, ["{$start} 00:00:00", "{$end} 23:59:59"]);
-            }
-        }
-        return parent::_list($db);
+        $this->title = '商城订单管理';
+        $this->_query($this->table)->order('id desc')->page();
     }
 
     /**
-     * 订单列表数据处理
+     * 商城订单列表处理
      * @param array $data
      * @throws \think\db\exception\DataNotFoundException
      * @throws \think\db\exception\ModelNotFoundException
      * @throws \think\exception\DbException
      */
-    protected function _data_filter(&$data)
+    protected function _page_filter(array &$data)
     {
-        OrderService::buildOrderList($data);
+        $goodsList = Db::name('StoreOrderList')->whereIn('order_no', array_unique(array_column($data, 'order_no')))->select();
+        $mids = array_unique(array_merge(array_column($data, 'mid'), array_column($data, 'from_mid')));
+        $memberList = Db::name('StoreMember')->whereIn('id', $mids)->select();
+        foreach ($data as &$vo) {
+            list($vo['member'], $vo['from_member'], $vo['list']) = [[], [], []];
+            foreach ($goodsList as $goods) if ($goods['order_no'] === $vo['order_no']) {
+                $vo['list'][] = $goods;
+            }
+            foreach ($memberList as $member) if ($member['id'] === $vo['mid']) {
+                $member['nickname'] = emoji_decode($member['nickname']);
+                $vo['member'] = $member;
+            }
+        }
     }
 
     /**
-     * 订单地址修改
-     * @return string
+     * 快递管理
      * @throws \think\db\exception\DataNotFoundException
      * @throws \think\db\exception\ModelNotFoundException
      * @throws \think\exception\DbException
-     * @throws \think\Exception
      */
-    public function address()
+    public function express()
     {
-        $order_no = $this->request->get('order_no');
         if ($this->request->isGet()) {
-            $order = Db::name('StoreOrder')->where(['order_no' => $order_no])->find();
-            empty($order) && $this->error('该订单无法进行地址修改,订单数据不存在!');
-            $orderExpress = Db::name('StoreOrderExpress')->where(['order_no' => $order_no])->find();
-            empty($orderExpress) && $this->error('该订单无法进行地址修改!');
-            return $this->fetch('', $orderExpress);
-        }
-        $data = [
-            'order_no' => $order_no,
-            'username' => $this->request->post('express_username'),
-            'phone'    => $this->request->post('express_phone'),
-            'province' => $this->request->post('form_express_province'),
-            'city'     => $this->request->post('form_express_city'),
-            'area'     => $this->request->post('form_express_area'),
-            'address'  => $this->request->post('express_address'),
-            'desc'     => $this->request->post('express_desc'),
-        ];
-        if (DataService::save('StoreOrderExpress', $data, 'order_no')) {
-            $this->success('收货地址修改成功!', '');
+            $where = ['is_deleted' => '0', 'status' => '1'];
+            $this->expressList = Db::name('StoreExpress')->where($where)->order('sort asc,id desc')->select();
         }
-        $this->error('收货地址修改失败,请稍候再试!');
+        $this->_form($this->table);
+    }
+
+    /***
+     * 快递追踪查询
+     */
+    public function expressQuery()
+    {
+        list($code, $no) = [input('code', ''), input('no', '')];
+        if (empty($no)) $this->error('快递编号不能为空!');
+        if (empty($code)) $this->error('快递公司编码不能为空!');
+        $this->result = \library\tools\Express::query($code, $no);
+        $this->fetch();
     }
 
+    /**
+     * 快递表单处理
+     * @param array $vo
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    protected function _express_form_filter(&$vo)
+    {
+        if ($this->request->isPost()) {
+            $order = Db::name($this->table)->where(['id' => $vo['id']])->find();
+            if (empty($order)) $this->error('订单查询异常,请稍候再试!');
+            $express = Db::name('StoreExpress')->where(['express_code' => $vo['express_company_code']])->find();
+            if (empty($express)) $this->error('发货快递公司异常,请重新选择快递公司!');
+            $vo['express_company_title'] = $express['express_title'];
+            $vo['express_send_at'] = empty($order['express_send_at']) ? date('Y-m-d H:i:s') : $order['express_send_at'];
+            $vo['express_state'] = '1';
+            $vo['status'] = '4';
+        }
+    }
 
-}
+}

+ 136 - 0
application/store/controller/Page.php

@@ -0,0 +1,136 @@
+<?php
+
+// +----------------------------------------------------------------------
+// | framework
+// +----------------------------------------------------------------------
+// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// +----------------------------------------------------------------------
+// | 官方网站: http://framework.thinkadmin.top
+// +----------------------------------------------------------------------
+// | 开源协议 ( https://mit-license.org )
+// +----------------------------------------------------------------------
+// | github开源项目:https://github.com/zoujingli/ThinkAdmin
+// +----------------------------------------------------------------------
+
+namespace app\store\controller;
+
+use library\Controller;
+use think\Db;
+
+/**
+ * 页面管理
+ * Class Page
+ * @package app\store\controller
+ */
+class Page extends Controller
+{
+    /**
+     * 绑定数据表
+     * @var string
+     */
+    protected $table = 'StorePage';
+
+    /**
+     * 页面管理
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
+     */
+    public function index()
+    {
+        $this->title = '商城页面管理';
+        $this->_query($this->table)->order('sort asc,id desc')->page();
+    }
+
+    /**
+     * 数据列表处理
+     * @param array $data
+     */
+    protected function _page_filter(&$data)
+    {
+        foreach ($data as &$vo) {
+            $vo['one'] = json_decode($vo['one'], true);
+            $vo['mul'] = json_decode($vo['mul'], true);
+        }
+    }
+
+    /**
+     * 添加页面
+     */
+    public function add()
+    {
+        $this->title = '添加商城页面';
+        $this->_form($this->table, 'form');
+    }
+
+    /**
+     * 编辑页面
+     */
+    public function edit()
+    {
+        $this->title = '编辑商城页面';
+        $this->_form($this->table, 'form');
+    }
+
+    /**
+     * 表单数据处理
+     * @param array $post
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    protected function _form_filter(&$post = [])
+    {
+        if ($this->request->isGet()) {
+            $where = ['is_deleted' => '0', 'status' => '1'];
+            $this->goodsList = Db::name('StoreGoods')->where($where)->order('sort asc,id desc')->select();
+            $maps = ['普通商品', '临时礼包', '会员礼包'];
+            foreach ($this->goodsList as &$vo) {
+                $vo['title'] = (isset($maps[$vo['vip_mod']]) ? "【{$maps[$vo['vip_mod']]}】" : '【类型异常】') . $vo['title'];
+            }
+            if (isset($post['one'])) $post['one'] = json_decode($post['one'], true);
+            if (isset($post['mul'])) $post['mul'] = json_decode($post['mul'], true);
+        } else foreach (['one', 'mul'] as $type) {
+            if (empty($post[$type])) $post[$type] = [];
+            $post[$type] = json_encode($post[$type], JSON_UNESCAPED_UNICODE);
+        }
+    }
+
+    /**
+     * 表单数据结果处理
+     * @param boolean $result
+     */
+    protected function _form_result($result)
+    {
+        if ($result) {
+            $this->success('页面更新成功!', url('@admin') . '#' . url('@store/page/index'));
+        }
+    }
+
+    /**
+     * 禁用页面
+     */
+    public function forbid()
+    {
+        $this->_save($this->table, ['status' => '0']);
+    }
+
+    /**
+     * 启用页面
+     */
+    public function resume()
+    {
+        $this->_save($this->table, ['status' => '1']);
+    }
+
+    /**
+     * 删除页面
+     */
+    public function del()
+    {
+        $this->_delete($this->table);
+    }
+
+}

+ 37 - 0
application/store/controller/api/Express.php

@@ -0,0 +1,37 @@
+<?php
+
+// +----------------------------------------------------------------------
+// | framework
+// +----------------------------------------------------------------------
+// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// +----------------------------------------------------------------------
+// | 官方网站: http://framework.thinkadmin.top
+// +----------------------------------------------------------------------
+// | 开源协议 ( https://mit-license.org )
+// +----------------------------------------------------------------------
+// | github开源项目:https://github.com/zoujingli/ThinkAdmin
+// +----------------------------------------------------------------------
+
+namespace app\store\controller\api;
+
+use library\Controller;
+
+/**
+ * 快递查询结果
+ * Class Express
+ * @package app\store\controller\api
+ */
+class Express extends Controller
+{
+    /**
+     * 物流查询结果
+     */
+    public function query()
+    {
+        $express_no = $this->request->post('express_no', '');
+        $express_code = $this->request->post('express_code', '');
+        $result = \library\tools\Express::query($express_code, $express_no);
+        $this->success('获取物流查询结果!', $result);
+    }
+
+}

+ 118 - 0
application/store/controller/api/Goods.php

@@ -0,0 +1,118 @@
+<?php
+
+// +----------------------------------------------------------------------
+// | framework
+// +----------------------------------------------------------------------
+// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// +----------------------------------------------------------------------
+// | 官方网站: http://framework.thinkadmin.top
+// +----------------------------------------------------------------------
+// | 开源协议 ( https://mit-license.org )
+// +----------------------------------------------------------------------
+// | github开源项目:https://github.com/zoujingli/ThinkAdmin
+// +----------------------------------------------------------------------
+
+namespace app\store\controller\api;
+
+use library\Controller;
+use think\Db;
+
+/**
+ * 商品管理接口
+ * Class Goods
+ * @package app\store\controller\api
+ */
+class Goods extends Controller
+{
+
+    /**
+     * 获取商品列表
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function gets()
+    {
+        $where = [['status', 'eq', '1'], ['vip_mod', 'eq', '0'], ['is_deleted', 'eq', '0']];
+        $this->success('获取商品列表成功!', ['list' => $this->_getGoodsList($where)]);
+    }
+
+    /**
+     * 获取礼包商品列表
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function vips()
+    {
+        $where = [['status', 'eq', '1'], ['vip_mod', 'neq', '0'], ['is_deleted', 'eq', '0']];
+        $this->success('获取礼包列表成功!', ['list' => $this->_getGoodsList($where)]);
+    }
+
+    /**
+     * 获取商品列表
+     * @param array $where
+     * @return array
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    private function _getGoodsList($where = [])
+    {
+        if ($this->request->has('title', 'post', true)) {
+            $where[] = ['title', 'like', "%{$this->request->post('title')}%"];
+        }
+        if ($this->request->has('cate_id', 'post', true)) {
+            $where[] = ['cate_id', 'eq', $this->request->post('cate_id')];
+        }
+        $field = 'id,title,logo,cate_id,image,number_sales,number_stock,vip_mod,vip_month,vip_discount,content,specs,lists';
+        $list = Db::name('StoreGoods')->field($field)->where($where)->order('sort asc,id desc')->select();
+        $goodsList = Db::name('StoreGoodsList')->whereIn('goods_id', array_unique(array_column($list, 'id')))->select();
+        foreach ($list as &$vo) {
+            $vo['list'] = [];
+            $vo['image'] = explode('|', $vo['image']);
+            $vo['specs'] = json_decode($vo['specs'], true);
+            $vo['lists'] = json_decode($vo['lists'], true);
+            foreach ($goodsList as $goods) if ($goods['goods_id'] === $vo['id']) {
+                array_push($vo['list'], $goods);
+            }
+        }
+        return $list;
+    }
+
+    /**
+     * 获取单个商品信息
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function get()
+    {
+        $goods_id = input('goods_id');
+        $where = ['is_deleted' => '0', 'status' => '1', 'id' => $goods_id];
+        $field = 'id,title,logo,cate_id,image,number_sales,number_stock,vip_mod,vip_month,vip_discount,content,specs,lists';
+        $goods = Db::name('StoreGoods')->field($field)->where($where)->find();
+        if (empty($goods)) $this->error('指定商品不存在,请更换商品ID重试!');
+        $goods['image'] = explode('|', $goods['image']);
+        $goods['specs'] = json_decode($goods['specs'], true);
+        $goods['lists'] = json_decode($goods['lists'], true);
+        $goods['list'] = Db::name('StoreGoodsList')->where(['goods_id' => $goods_id])->select();
+        if (empty($goods['list'])) $this->error('指定商品规格不存在,请更换商品ID重试!');
+        $this->success('获取商品信息成功!', $goods);
+    }
+
+    /**
+     * 获取商品分类信息
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function cate()
+    {
+        $where = ['is_deleted' => '0', 'status' => '1'];
+        $field = 'id cate_id,logo cate_logo,title cate_title';
+        $list = Db::name('StoreGoodsCate')->field($field)->where($where)->order('sort asc,id desc')->select();
+        $this->success('获取商品分类成功!', ['list' => $list]);
+    }
+
+}

+ 90 - 0
application/store/controller/api/Member.php

@@ -0,0 +1,90 @@
+<?php
+
+// +----------------------------------------------------------------------
+// | framework
+// +----------------------------------------------------------------------
+// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// +----------------------------------------------------------------------
+// | 官方网站: http://framework.thinkadmin.top
+// +----------------------------------------------------------------------
+// | 开源协议 ( https://mit-license.org )
+// +----------------------------------------------------------------------
+// | github开源项目:https://github.com/zoujingli/ThinkAdmin
+// +----------------------------------------------------------------------
+
+namespace app\store\controller\api;
+
+use library\Controller;
+use think\Db;
+
+/**
+ * 会员管理基类
+ * Class Member
+ * @package app\store\controller\api
+ */
+class Member extends Controller
+{
+    /**
+     * 当前会员ID
+     * @var integer
+     */
+    protected $mid;
+
+    /**
+     * 当前会员数据
+     * @var array
+     */
+    protected $member;
+
+    /**
+     * 当前公众号OPENID
+     * @var string
+     */
+    protected $openid;
+
+    /**
+     * Member constructor.
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function __construct()
+    {
+        parent::__construct();
+        // 会员信息检查
+        $this->mid = $this->request->post('mid');
+        $this->openid = $this->request->post('openid');
+        if (empty($this->mid)) $this->error('无效的会员ID参数!');
+        if (empty($this->openid)) $this->error('无效的会员绑定OPENID!');
+        $this->getMember();
+    }
+
+    /**
+     * 获取会员信息
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    protected function getMember()
+    {
+        $where = ['id' => $this->mid, 'openid' => $this->openid];
+        $this->member = Db::name('StoreMember')->where($where)->find();
+        if (empty($this->member)) $this->error('无效的会员信息,请重新登录授权!');
+        $this->member['nickname'] = emoji_decode($this->member['nickname']);
+        // 游客会员每月没有领取机会
+        $this->member['times_count'] = 0;
+        // 临时会员及VIP1每月只有1次领取机会
+        if (in_array(intval($this->member['vip_level']), [1, 2])) {
+            $this->member['times_count'] = 1;
+        }
+        // VIP2会员每月只有2次免费领取机会
+        if (intval($this->member['vip_level']) === 3) {
+            $this->member['times_count'] = 2;
+        }
+        // 会员当前已经领取次数
+        $where = [['mid', 'eq', $this->mid], ['status', 'in', ['2', '3', '4', '5']]];
+        $this->member['times_used'] = Db::name('StoreOrder')->where($where)->count();
+        return $this->member;
+    }
+
+}

+ 71 - 0
application/store/controller/api/Notify.php

@@ -0,0 +1,71 @@
+<?php
+
+// +----------------------------------------------------------------------
+// | framework
+// +----------------------------------------------------------------------
+// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// +----------------------------------------------------------------------
+// | 官方网站: http://framework.thinkadmin.top
+// +----------------------------------------------------------------------
+// | 开源协议 ( https://mit-license.org )
+// +----------------------------------------------------------------------
+// | github开源项目:https://github.com/zoujingli/ThinkAdmin
+// +----------------------------------------------------------------------
+
+namespace app\store\controller\api;
+
+use app\store\service\Order;
+use think\Db;
+
+/**
+ * 支付通知处理
+ * Class Notify
+ * @package app\store\controller\api
+ */
+class Notify
+{
+    /**
+     * 微信支付通知处理
+     * @return string
+     * @throws \WeChat\Exceptions\InvalidResponseException
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function wxpay()
+    {
+        $wechat = \We::WePayOrder(config('wechat.miniapp'));
+        $notify = $wechat->getNotify();
+        if ($notify['result_code'] == 'SUCCESS' && $notify['return_code'] == 'SUCCESS') {
+            if ($this->update($notify['out_trade_no'], $notify['transaction_id'], $notify['cash_fee'] / 100, 'wechat')) {
+                return $wechat->getNotifySuccessReply();
+            }
+        } else return $wechat->getNotifySuccessReply();
+    }
+
+    /**
+     * 订单状态更新
+     * @param string $order_no 订单号
+     * @param string $pay_no 交易号
+     * @param string $pay_price 交易金额
+     * @param string $type 支付类型
+     * @return boolean
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    private function update($order_no, $pay_no, $pay_price, $type = 'wechat')
+    {
+        // 检查订单支付状态
+        $where = ['order_no' => $order_no, 'pay_state' => '0', 'status' => '2'];
+        $order = Db::name('StoreOrder')->where($where)->find();
+        if (empty($order)) return false;
+        // 更新订单支付状态
+        $result = Db::name('StoreOrder')->where($where)->update([
+            'pay_type'  => $type, 'pay_no' => $pay_no, 'status' => '3',
+            'pay_price' => $pay_price, 'pay_state' => '1', 'pay_at' => date('Y-m-d H:i:s'),
+        ]);
+        // 调用会员升级机制
+        Order::update($order['order_no']);
+        return $result !== false;
+    }
+
+}

+ 72 - 0
application/store/controller/api/Page.php

@@ -0,0 +1,72 @@
+<?php
+
+// +----------------------------------------------------------------------
+// | framework
+// +----------------------------------------------------------------------
+// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// +----------------------------------------------------------------------
+// | 官方网站: http://framework.thinkadmin.top
+// +----------------------------------------------------------------------
+// | 开源协议 ( https://mit-license.org )
+// +----------------------------------------------------------------------
+// | github开源项目:https://github.com/zoujingli/ThinkAdmin
+// +----------------------------------------------------------------------
+
+namespace app\store\controller\api;
+
+use library\Controller;
+use think\Db;
+
+/**
+ * 页面接口管理
+ * Class Page
+ * @package app\store\controller\api
+ */
+class Page extends Controller
+{
+
+    /**
+     * 获取微信商品首页
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function gets()
+    {
+        $list = Db::name('StorePage')->field('title,type,one,mul')->where(['status' => '1'])->order('sort asc,id desc')->select();
+        foreach ($list as &$vo) {
+            $vo['one'] = json_decode($vo['one'], true);
+            $vo['mul'] = json_decode($vo['mul'], true);
+            if ($vo['type'] === 'one') unset($vo['mul']);
+            if ($vo['type'] === 'mul') unset($vo['one']);
+        }
+        $this->success('获取页面列表成功!', ['list' => $this->build($list)]);
+    }
+
+    /**
+     * 数据列表处理
+     * @param array $data
+     * @param array $goodsId
+     * @return array
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    protected function build($data = [], $goodsId = [])
+    {
+        foreach ($data as $vo) if (isset($vo['mul'])) {
+            $goodsId = array_unique(array_merge($goodsId, $vo['mul']['goods']));
+        }
+        $goodsList = Db::name('StoreGoods')->field('id,title,logo')->whereIn('id', $goodsId)->select();
+        $field = 'goods_id,goods_spec,price_market,price_selling,number_sales,number_stock,number_virtual';
+        $goodsLists = Db::name('StoreGoodsList')->field($field)->where(['status' => '1'])->whereIn('goods_id', $goodsId)->select();
+        foreach ($goodsList as &$vo) {
+            $vo['list'] = [];
+            foreach ($goodsLists as $v) if ($vo['id'] === $v['goods_id']) $vo['list'][] = $v;
+        }
+        foreach ($data as &$vo) if (isset($vo['mul'])) {
+            foreach ($vo['mul']['goods'] as &$g) foreach ($goodsList as $v) if ($g == $v['id']) $g = $v;
+        }
+        return $data;
+    }
+}

+ 88 - 0
application/store/controller/api/Wechat.php

@@ -0,0 +1,88 @@
+<?php
+
+// +----------------------------------------------------------------------
+// | framework
+// +----------------------------------------------------------------------
+// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// +----------------------------------------------------------------------
+// | 官方网站: http://framework.thinkadmin.top
+// +----------------------------------------------------------------------
+// | 开源协议 ( https://mit-license.org )
+// +----------------------------------------------------------------------
+// | github开源项目:https://github.com/zoujingli/ThinkAdmin
+// +----------------------------------------------------------------------
+
+namespace app\store\controller\api;
+
+use library\Controller;
+use think\Db;
+
+/**
+ * Class Wechat
+ * @package app\store\controller\api
+ */
+class Wechat extends Controller
+{
+    /**
+     * 获取小程序配置
+     * @return array
+     */
+    private function config()
+    {
+        return config('wechat.miniapp');
+    }
+
+    /**
+     * Code信息换取
+     */
+    public function session()
+    {
+        try {
+            $code = $this->request->post('code');
+            $result = \We::WeMiniCrypt($this->config())->session($code);
+            if (isset($result['openid'])) {
+                data_save('StoreMember', ['openid' => $result['openid']], 'openid');
+                $result['member'] = Db::name('StoreMember')->where(['openid' => $result['openid']])->find();
+                $this->success('授权CODE信息换取成功!', $result);
+            }
+            $this->error("[{$result['errcode']}] {$result['errmsg']}");
+        } catch (\think\exception\HttpResponseException $exception) {
+            throw $exception;
+        } catch (\Exception $exception) {
+            $this->error("授权CODE信息换取失败,{$exception->getMessage()}");
+        }
+    }
+
+    /**
+     * 小程序数据解密
+     */
+    public function decode()
+    {
+        try {
+            $iv = $this->request->post('iv');
+            $session = $this->request->post('session');
+            $content = $this->request->post('encrypted');
+            if (empty($session)) {
+                $code = $this->request->post('code');
+                $result = \We::WeMiniCrypt($this->config())->session($code);
+                $session = isset($result['session_key']) ? $result['session_key'] : '';
+            }
+            $result = \We::WeMiniCrypt($this->config())->decode($iv, $session, $content);
+            if ($result !== false && isset($result['openId'])) {
+                data_save('StoreMember', [
+                    'openid'   => $result['openId'],
+                    'headimg'  => $result['avatarUrl'],
+                    'nickname' => emoji_encode($result['nickName']),
+                ], 'openid');
+                $result['member'] = Db::name('StoreMember')->where(['openid' => $result['openId']])->find();
+                $this->success('小程序加密数据解密成功!', $result);
+            }
+        } catch (\think\exception\HttpResponseException $exception) {
+            throw $exception;
+        } catch (\Exception $e) {
+            $this->error("小程序加密数据解密失败,{$e->getMessage()}");
+        }
+        $this->error('小程序加密数据解密失败,请稍候再试!');
+    }
+
+}

+ 127 - 0
application/store/controller/api/member/Address.php

@@ -0,0 +1,127 @@
+<?php
+
+// +----------------------------------------------------------------------
+// | framework
+// +----------------------------------------------------------------------
+// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// +----------------------------------------------------------------------
+// | 官方网站: http://framework.thinkadmin.top
+// +----------------------------------------------------------------------
+// | 开源协议 ( https://mit-license.org )
+// +----------------------------------------------------------------------
+// | github开源项目:https://github.com/zoujingli/ThinkAdmin
+// +----------------------------------------------------------------------
+
+namespace app\store\controller\api\member;
+
+use app\store\controller\api\Member;
+use think\Db;
+
+/**
+ * 会员收货地址管理
+ * Class Address
+ * @package app\store\controller\api\member
+ */
+class Address extends Member
+{
+
+    /**
+     * 获取会员收货地址信息
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function gets()
+    {
+        $this->success('获取会员收货地址成功!', [
+            'list' => Db::name('StoreMemberAddress')
+                ->where(['mid' => $this->member['id']])
+                ->order('is_default desc,id desc')
+                ->select(),
+        ]);
+    }
+
+    /**
+     * 更新收货地址
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function set()
+    {
+        $data = $this->_input([
+            'mid'        => $this->request->post('mid'),
+            'openid'     => $this->request->post('openid'),
+            'name'       => $this->request->post('name'),
+            'phone'      => $this->request->post('phone'),
+            'province'   => $this->request->post('province'),
+            'city'       => $this->request->post('city'),
+            'area'       => $this->request->post('area'),
+            'address'    => $this->request->post('address'),
+            'is_default' => $this->request->post('is_default'),
+        ], [
+            'name'     => 'require',
+            'phone'    => 'require|mobile',
+            'province' => 'require',
+            'city'     => 'require',
+            'area'     => 'require',
+            'address'  => 'require',
+        ], [
+            'name.require'     => '收货人姓名不能为空!',
+            'phone.require'    => '收货人联系手机不能为空!',
+            'phone.mobile'     => '收货人联系手机格式不对!',
+            'province.require' => '收货地址省份不能为空!',
+            'city.require'     => '收货地址城市不能为空!',
+            'area.require'     => '收货地址区域不能为空!',
+            'address.require'  => '收货详情地址不能为空!',
+        ]);
+        if (!empty($data['is_default'])) {
+            Db::name('StoreMemberAddress')->where(['mid' => $this->member['id']])->setField('is_default', '0');
+        }
+        if ($this->request->has('id', 'post', true)) {
+            $data['id'] = $this->request->post('id');
+        }
+        if (data_save('StoreMemberAddress', $data, 'id')) {
+            $this->success('收货地址更新成功!');
+        }
+        $this->error('收货地址更新失败,请稍候再试!');
+    }
+
+    /**
+     * 删除收货地址
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function del()
+    {
+        $id = $this->request->post('address_id');
+        if (empty($id)) $this->error('待处理的收货地址ID不能为空!');
+        $where = ['id' => $id, 'mid' => $this->member['id']];
+        if (Db::name('StoreMemberAddress')->where($where)->delete() !== false) {
+            $this->success('删除收货地址成功!');
+        }
+        $this->error('删除收货地址失败,请稍候再试!');
+    }
+
+    /**
+     * 设置默认收货地址
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
+     */
+    public function setDefault()
+    {
+        $id = $this->request->post('address_id');
+        if (empty($id)) $this->error('待处理的收货地址ID不存在!');
+        $where = ['id' => $id, 'mid' => $this->member['id']];
+        $address = Db::name('StoreMemberAddress')->where($where)->find();
+        if (empty($address)) $this->error('待处理的收货地址获取失败,请稍候再试!');
+        Db::name('StoreMemberAddress')->where(['mid' => $this->member['id']])->update(['is_default' => '0']);
+        if (Db::name('StoreMemberAddress')->where($where)->update(['is_default' => '1']) !== false) {
+            $this->success('设置默认收货地址成功!');
+        }
+        $this->error('设置默认收货地址失败!');
+    }
+
+}

+ 116 - 0
application/store/controller/api/member/Center.php

@@ -0,0 +1,116 @@
+<?php
+
+// +----------------------------------------------------------------------
+// | framework
+// +----------------------------------------------------------------------
+// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// +----------------------------------------------------------------------
+// | 官方网站: http://framework.thinkadmin.top
+// +----------------------------------------------------------------------
+// | 开源协议 ( https://mit-license.org )
+// +----------------------------------------------------------------------
+// | github开源项目:https://github.com/zoujingli/ThinkAdmin
+// +----------------------------------------------------------------------
+
+namespace app\store\controller\api\member;
+
+use app\store\controller\api\Member;
+use app\store\service\Extend;
+use think\Db;
+
+/**
+ * 商品会员中心
+ * Class Center
+ * @package app\store\controller\api\member
+ */
+class Center extends Member
+{
+    /**
+     * 修改会员资料
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function info()
+    {
+        $data = [];
+        if ($this->request->has('headimg', 'post', true)) {
+            $data['headimg'] = $this->request->post('headimg');
+        }
+        if ($this->request->has('nickname', 'post', true)) {
+            $data['nickname'] = emoji_encode($this->request->post('nickname'));
+        }
+        if ($this->request->has('username', 'post', true)) {
+            $data['username'] = emoji_encode($this->request->post('username'));
+        }
+        if (empty($data)) $this->error('没有需要修改的数据哦!');
+        if (data_save('StoreMember', array_merge($data, ['id' => $this->mid]), 'id')) {
+            $this->success('会员资料更新成功!', $this->getMember());
+        }
+        $this->error('会员资料更新失败,请稍候再试!');
+    }
+
+    /**
+     * 发送短信验证码
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
+     */
+    public function sendsms()
+    {
+        $phone = $this->request->post('phone');
+        if ($this->request->post('secure') !== sysconf('sms_secure')) {
+            $this->error('短信发送安全码不正确,请使用正确的安全码!');
+        }
+        $member = Db::name('StoreMember')->where(['phone' => $phone])->find();
+        if (!empty($member)) $this->error('该手机号已经注册了,请使用其它手机号!');
+        $cache = cache($cachekey = "send_register_sms_{$phone}");
+        if (is_array($cache) && isset($cache['time']) && $cache['time'] > time() - 120) {
+            $dtime = ($cache['time'] + 120 < time()) ? 0 : (120 - time() + $cache['time']);
+            $this->success('短信验证码已经发送!', ['time' => $dtime]);
+        }
+        list($code, $content) = [rand(1000, 9999), sysconf('sms_reg_template')];
+        if (empty($content) || stripos($content, '{code}') === false) {
+            $content = '您的验证码为{code},请在十分钟内完成操作!';
+        }
+        cache($cachekey, ['phone' => $phone, 'captcha' => $code, 'time' => time()], 600);
+        if (empty($content) || strpos($content, '{code}') === false) {
+            $this->error('获取短信模板失败,联系管理员配置!');
+        }
+        $cache = cache($cachekey);
+        if (Extend::sendSms($this->mid, $phone, str_replace('{code}', $code, $content))) {
+            $dtime = ($cache['time'] + 120 < time()) ? 0 : (120 - time() + $cache['time']);
+            $this->success('短信验证码发送成功!', ['time' => $dtime]);
+        }
+        $this->error('短信发送失败,请稍候再试!');
+    }
+
+    /**
+     * 会员登录绑定
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function bind()
+    {
+        $code = $this->request->post('code');
+        $phone = $this->request->post('phone');
+        $cache = cache($cachekey = "send_register_sms_{$phone}");
+        if (is_array($cache) && isset($cache['captcha']) && $cache['captcha'] == $code) {
+            $where = ['id' => $this->member['id']];
+            if (Db::name('StoreMember')->where($where)->update(['phone' => $phone]) !== false) {
+                $this->success('手机绑定登录成功!');
+            }
+        } else $this->error('短信验证码验证失败!');
+        $this->error('手机绑定登录失败,请稍候再试!');
+    }
+
+    /**
+     * 获取会员资源成功
+     */
+    public function member()
+    {
+        $this->success('获取会员资料成功!', $this->member);
+    }
+
+}

+ 298 - 0
application/store/controller/api/member/Order.php

@@ -0,0 +1,298 @@
+<?php
+
+// +----------------------------------------------------------------------
+// | framework
+// +----------------------------------------------------------------------
+// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// +----------------------------------------------------------------------
+// | 官方网站: http://framework.thinkadmin.top
+// +----------------------------------------------------------------------
+// | 开源协议 ( https://mit-license.org )
+// +----------------------------------------------------------------------
+// | github开源项目:https://github.com/zoujingli/ThinkAdmin
+// +----------------------------------------------------------------------
+
+namespace app\store\controller\api\member;
+
+use app\store\controller\api\Member;
+use app\store\service\Goods;
+use library\tools\Data;
+use think\Db;
+
+/**
+ * 订单接口管理
+ * Class Order
+ * @package app\store\controller\api\member
+ */
+class Order extends Member
+{
+
+    /**
+     * 创建商城订单
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * 商品ID1@商品规格1@商品数量1||商品ID2@商品规格2@商品数量2
+     */
+    public function set()
+    {
+        // 商品规则
+        $rule = $this->request->post('rule', '');
+        if (empty($rule)) $this->error('下单商品规则不能为空!');
+        // 订单处理
+        list($orderList, $order) = [[], [
+            'status'   => '1', 'mid' => $this->mid,
+            'order_no' => Data::uniqidNumberCode(12),
+            'from_mid' => $this->request->post('from_mid', '0'),
+        ]];
+        // 推荐人处理
+        if (intval($order['from_mid']) === intval($this->mid)) {
+            $order['from_mid'] = '0';
+        } elseif ($order['from_mid'] > 0) {
+            if (Db::name('StoreMember')->where(['id' => $order['from_mid']])->count() < 1) {
+                $this->error('无效的推荐会员ID,稍候再试!');
+            }
+        }
+        foreach (explode('||', $rule) as $item) {
+            list($goods_id, $goods_spec, $number) = explode('@', $item);
+            // 商品信息检查
+            $goods = Db::name('StoreGoods')->where(['id' => $goods_id, 'status' => '1', 'is_deleted' => '0'])->find();
+            if (empty($goods)) $this->error('查询商品主体信息失败,请稍候再试!');
+            $spec = Db::name('StoreGoodsList')->where(['goods_id' => $goods_id, 'goods_spec' => $goods_spec])->find();
+            if (empty($spec)) $this->error('查询商品规则信息失败,请稍候再试!');
+            // 商品库存检查
+            if ($spec['number_sales'] + $number > $spec['number_stock']) {
+                $this->error('商品库存不足,请购买其它商品!');
+            }
+            // 订单详情处理
+            array_push($orderList, [
+                'mid'               => $order['mid'],
+                'from_mid'          => $order['from_mid'],
+                'order_no'          => $order['order_no'],
+                // 商品信息字段管理
+                'number'            => $number,
+                'goods_id'          => $goods_id,
+                'goods_spec'        => $goods_spec,
+                'goods_logo'        => $goods['logo'],
+                'goods_title'       => $goods['title'],
+                // 费用字段处理
+                'price_market'      => $spec['price_market'],
+                'price_selling'     => $spec['price_selling'],
+                'price_real'        => $spec['price_selling'] * $number,
+                'price_express'     => $goods['price_express'],
+                // 返利字段处理
+                'price_rate'        => $goods['price_rate'],
+                'price_rate_amount' => $spec['price_selling'] * $number * $goods['price_rate'] / 100,
+            ]);
+        }
+        $order['price_goods'] = array_sum(array_column($orderList, 'price_real')) + 0;
+        $order['price_express'] = max(array_column($orderList, 'price_express')) + 0;
+        $order['price_total'] = $order['price_goods'] + $order['price_express'];
+        $order['price_rate_amount'] = array_sum(array_column($orderList, 'price_rate_amount')) + 0;
+        try {
+            // 订单数据写入
+            Db::name('StoreOrder')->insert($order);
+            Db::name('StoreOrderList')->insertAll($orderList);
+            // 同步商品库存及销量
+            foreach (array_unique(array_column($orderList, 'goods_id')) as $goodsId) Goods::syncStock($goodsId);
+            $this->success('订单创建成功,请补全收货信息后支付!', ['order' => $order]);
+        } catch (\think\exception\HttpResponseException $exception) {
+            throw $exception;
+        } catch (\Exception $e) {
+            $this->error("创建订单失败,请稍候再试!{$e->getMessage()}");
+        }
+    }
+
+    /**
+     * 订单信息完成
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
+     */
+    public function perfect()
+    {
+        $data = $this->_input([
+            'order_no'   => $this->request->post('order_no'),
+            'address_id' => $this->request->post('address_id'),
+        ], [
+            'order_no'   => 'require',
+            'address_id' => 'require',
+        ], [
+            'order_no.require'   => '订单号不能为空!',
+            'address_id.require' => '收货地址ID不能为空(0自提可以为空)',
+        ]);
+        $map = ['order_no' => $data['order_no'], 'mid' => $this->member['id']];
+        $order = Db::name('StoreOrder')->whereIn('status', ['1', '2'])->where($map)->find();
+        if (empty($order)) $this->error('订单异常,请返回商品重新下单!');
+        $update = ['status' => '2'];
+        $where = ['id' => $data['address_id'], 'mid' => $this->member['id']];
+        $address = Db::name('StoreMemberAddress')->where($where)->find();
+        if (empty($address)) $this->error('会员收货地址异常,请刷新页面重试!');
+        $update['express_address_id'] = $data['address_id'];
+        $update['express_name'] = $address['name'];
+        $update['express_phone'] = $address['phone'];
+        $update['express_province'] = $address['province'];
+        $update['express_city'] = $address['city'];
+        $update['express_area'] = $address['area'];
+        $update['express_address'] = $address['address'];
+        if (Db::name('StoreOrder')->where($map)->update($update) !== false) {
+            $params = $this->getPayParams($order['order_no'], $order['price_total']);
+            $this->success('更新订单会员信息成功!', $params);
+        }
+        $this->error('更新订单会员信息失败,请稍候再试!');
+    }
+
+    /**
+     * 获取订单支付状态
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function pay()
+    {
+        $order_no = $this->request->post('order_no');
+        $order = Db::name('StoreOrder')->where(['order_no' => $order_no])->find();
+        if (empty($order_no)) $this->error('获取订单信息异常,请稍候再试!');
+        if ($order['pay_state']) $this->error('订单已经完成支付,不需要再次支付!');
+        if ($order['status'] <> 2) $this->error('该订单不能发起支付哦!');
+        try {
+            $param = $this->getPayParams($order['order_no'], $order['price_total']);
+            $this->success('获取订单支付参数成功!', $param);
+        } catch (\think\exception\HttpResponseException $exception) {
+            throw  $exception;
+        } catch (\Exception $e) {
+            $this->error("获取订单支付参数失败,{$e->getMessage()}");
+        }
+    }
+
+    /**
+     * 获取订单支付参数
+     * @param string $order_no
+     * @param string $pay_price
+     * @return array
+     */
+    private function getPayParams($order_no, $pay_price)
+    {
+        $options = [
+            'body'             => '商城订单支付',
+            'openid'           => $this->openid,
+            'out_trade_no'     => $order_no,
+            // 'total_fee'        => '1',
+            'total_fee'        => $pay_price * 100,
+            'trade_type'       => 'JSAPI',
+            'notify_url'       => url('@store/api.notify/wxpay', '', false, true),
+            'spbill_create_ip' => $this->request->ip(),
+        ];
+        try {
+            $pay = \We::WePayOrder(config('wechat.miniapp'));
+            $info = $pay->create($options);
+            if ($info['return_code'] === 'SUCCESS' && $info['result_code'] === 'SUCCESS') {
+                return $pay->jsapiParams($info['prepay_id']);
+            }
+            if (isset($info['err_code_des'])) throw new \think\Exception($info['err_code_des']);
+        } catch (\Exception $e) {
+            $this->error("创建订单失败参数失败,{$e->getMessage()}");
+        }
+    }
+
+    /**
+     * 获取订单列表
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
+     */
+    public function gets()
+    {
+        $where = [['mid', 'eq', $this->mid]];
+        if ($this->request->has('order_no', 'post', true)) {
+            $where[] = ['order_no', 'eq', $this->request->post('order_no')];
+        } else {
+            $where[] = ['status', 'in', ['0', '2', '3', '4', '5']];
+        }
+        if ($this->request->has('status', 'post', true)) {
+            $where[] = ['status', 'eq', $this->request->post('status')];
+        }
+        $result = $this->_query('StoreOrder')->where($where)->order('id desc')->page(true, false, false, 20);
+        $glist = Db::name('StoreOrderList')->whereIn('order_no', array_unique(array_column($result['list'], 'order_no')))->select();
+        foreach ($result['list'] as &$vo) {
+            list($vo['goods_count'], $vo['list']) = [0, []];
+            foreach ($glist as $goods) if ($vo['order_no'] === $goods['order_no']) {
+                $vo['list'][] = $goods;
+                $vo['goods_count'] += $goods['number'];
+            }
+        }
+        $this->success('获取订单列表成功!', $result);
+    }
+
+    /**
+     * 订单取消
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
+     */
+    public function cancel()
+    {
+        $where = [
+            'mid'      => $this->member['id'],
+            'order_no' => $this->request->post('order_no'),
+        ];
+        $order = Db::name('StoreOrder')->where($where)->find();
+        if (empty($order)) $this->error('待取消的订单不存在,请稍候再试!');
+        if (in_array($order['status'], ['1', '2'])) {
+            $result = Db::name('StoreOrder')->where($where)->update([
+                'status'       => '0',
+                'cancel_state' => '1',
+                'cancel_at'    => date('Y-m-d H:i:s'),
+                'cancel_desc'  => '用户主动取消订单!',
+            ]);
+            if ($result !== false && \app\store\service\Order::syncStock($order['order_no'])) {
+                $this->success('订单取消成功!');
+            }
+            $this->error('订单取消失败,请稍候再试!');
+        }
+        $this->error('该订单状态不允许取消哦~');
+    }
+
+    /**
+     * 订单确认收货
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
+     */
+    public function confirm()
+    {
+        $where = [
+            'mid'      => $this->member['id'],
+            'order_no' => $this->request->post('order_no'),
+        ];
+        $order = Db::name('StoreOrder')->where($where)->find();
+        if (empty($order)) $this->error('待确认的订单不存在,请稍候再试!');
+        if (in_array($order['status'], ['4'])) {
+            $result = Db::name('StoreOrder')->where($where)->update(['status' => '5']);
+            if ($result !== false) $this->success('订单确认成功!');
+            $this->error('订单取确认失败,请稍候再试!');
+        }
+        $this->error('该订单状态不允许确认哦~');
+    }
+
+    /**
+     * 订单状态统计
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function total()
+    {
+        $result = Db::name('StoreOrder')->fieldRaw('mid,status,count(1) count')
+            ->where(['mid' => $this->mid])->group('status')->select();
+        $this->success('获取订单统计记录!', $result);
+    }
+}

Някои файлове не бяха показани, защото твърде много файлове са промени