songxingwei il y a 2 ans
commit
25efe5aeb9
100 fichiers modifiés avec 23620 ajouts et 0 suppressions
  1. 11 0
      .gitignore
  2. 21 0
      LICENSE
  3. 133 0
      README.md
  4. 245 0
      application/PHPExcelService.php
  5. 178 0
      application/admin/controller/Auth.php
  6. 178 0
      application/admin/controller/Category.php
  7. 1097 0
      application/admin/controller/ChildProject.php
  8. 136 0
      application/admin/controller/Config.php
  9. 174 0
      application/admin/controller/Index.php
  10. 118 0
      application/admin/controller/Login.php
  11. 1040 0
      application/admin/controller/MainProject.php
  12. 160 0
      application/admin/controller/Menu.php
  13. 94 0
      application/admin/controller/Oplog.php
  14. 136 0
      application/admin/controller/Template.php
  15. 196 0
      application/admin/controller/User.php
  16. 130 0
      application/admin/controller/api/Plugs.php
  17. 65 0
      application/admin/controller/api/Update.php
  18. 159 0
      application/admin/sys.php
  19. 3659 0
      application/admin/view/api/plugs/icon.html
  20. 116 0
      application/admin/view/auth/apply.html
  21. 30 0
      application/admin/view/auth/form.html
  22. 74 0
      application/admin/view/auth/index.html
  23. 42 0
      application/admin/view/auth/index_search.html
  24. 50 0
      application/admin/view/category/form.html
  25. 145 0
      application/admin/view/category/index.html
  26. 46 0
      application/admin/view/category/index_search.html
  27. 453 0
      application/admin/view/child_project/contrast.html
  28. 108 0
      application/admin/view/child_project/contrast1.html
  29. 400 0
      application/admin/view/child_project/form.html
  30. 150 0
      application/admin/view/child_project/index.html
  31. 627 0
      application/admin/view/child_project/index_search.html
  32. 36 0
      application/admin/view/child_project/info.html
  33. 61 0
      application/admin/view/child_project/look.html
  34. 270 0
      application/admin/view/child_project/see.html
  35. 116 0
      application/admin/view/config/info.html
  36. 20 0
      application/admin/view/config/storage-local.html
  37. 80 0
      application/admin/view/config/storage-oss.html
  38. 80 0
      application/admin/view/config/storage-qiniu.html
  39. 90 0
      application/admin/view/config/system-config.html
  40. 126 0
      application/admin/view/index/index.html
  41. 207 0
      application/admin/view/index/main.html
  42. 98 0
      application/admin/view/login/index.html
  43. 11 0
      application/admin/view/main.html
  44. 347 0
      application/admin/view/main_project/contrast.html
  45. 86 0
      application/admin/view/main_project/contrast1.html
  46. 297 0
      application/admin/view/main_project/contrast1111.html
  47. 459 0
      application/admin/view/main_project/form.html
  48. 163 0
      application/admin/view/main_project/index.html
  49. 144 0
      application/admin/view/main_project/index2.html
  50. 625 0
      application/admin/view/main_project/index_search.html
  51. 88 0
      application/admin/view/main_project/info.html
  52. 53 0
      application/admin/view/main_project/look.html
  53. 250 0
      application/admin/view/main_project/see.html
  54. 89 0
      application/admin/view/menu/form.html
  55. 80 0
      application/admin/view/menu/index.html
  56. 68 0
      application/admin/view/oplog/index.html
  57. 56 0
      application/admin/view/oplog/index_search.html
  58. 31 0
      application/admin/view/template/form.html
  59. 50 0
      application/admin/view/template/index.html
  60. 62 0
      application/admin/view/user/form.html
  61. 121 0
      application/admin/view/user/index.html
  62. 57 0
      application/admin/view/user/index_search.html
  63. 57 0
      application/admin/view/user/pass.html
  64. 69 0
      application/common.php
  65. 53 0
      application/common/Api/ConfigApi.php
  66. 76 0
      application/common/behavior/Common.php
  67. 197 0
      application/common/controller/Api.php
  68. 471 0
      application/common/controller/Backend.php
  69. 137 0
      application/common/controller/Frontend.php
  70. 104 0
      application/common/lang/zh-cn/addon.php
  71. 141 0
      application/common/library/AliPay.php
  72. 613 0
      application/common/library/Auth.php
  73. 553 0
      application/common/library/Common.php
  74. 144 0
      application/common/library/Menu.php
  75. 158 0
      application/common/library/Token.php
  76. 70 0
      application/common/library/WXBizDataCrypt.php
  77. 377 0
      application/common/library/WxPay.php
  78. 161 0
      application/common/library/WxService.php
  79. 188 0
      application/common/library/alipay/aop/AlipayMobilePublicMultiMediaClient.php
  80. 115 0
      application/common/library/alipay/aop/AlipayMobilePublicMultiMediaExecute.php
  81. 1237 0
      application/common/library/alipay/aop/AopCertClient.php
  82. 527 0
      application/common/library/alipay/aop/AopCertification.php
  83. 1299 0
      application/common/library/alipay/aop/AopClient.php
  84. 81 0
      application/common/library/alipay/aop/AopEncrypt.php
  85. 18 0
      application/common/library/alipay/aop/EncryptParseItem.php
  86. 16 0
      application/common/library/alipay/aop/EncryptResponseData.php
  87. 15 0
      application/common/library/alipay/aop/SignData.php
  88. 14 0
      application/common/library/alipay/aop/readme
  89. 118 0
      application/common/library/alipay/aop/request/AftAifinFireeyeOcrImageQueryRequest.php
  90. 118 0
      application/common/library/alipay/aop/request/AftFinsecureRiskplusSecurityPolicyQueryRequest.php
  91. 118 0
      application/common/library/alipay/aop/request/AliosOpenAutoInfoQueryRequest.php
  92. 118 0
      application/common/library/alipay/aop/request/AlipayAccountExrateAdviceAcceptRequest.php
  93. 118 0
      application/common/library/alipay/aop/request/AlipayAccountExrateAllclientrateQueryRequest.php
  94. 118 0
      application/common/library/alipay/aop/request/AlipayAccountExrateRatequeryRequest.php
  95. 118 0
      application/common/library/alipay/aop/request/AlipayAccountExrateTraderequestCreateRequest.php
  96. 171 0
      application/common/library/alipay/aop/request/AlipayAcquireCancelRequest.php
  97. 152 0
      application/common/library/alipay/aop/request/AlipayAcquireCloseRequest.php
  98. 550 0
      application/common/library/alipay/aop/request/AlipayAcquireCreateandpayRequest.php
  99. 402 0
      application/common/library/alipay/aop/request/AlipayAcquirePrecreateRequest.php
  100. 136 0
      application/common/library/alipay/aop/request/AlipayAcquireQueryRequest.php

+ 11 - 0
.gitignore

@@ -0,0 +1,11 @@
+/.git
+/.svn
+/.idea
+/runtime
+/safefile
+/nbproject
+/config/cert
+/composer.lock
+/public/upload
+public/static/theme/css/console.*.css
+public/static/theme/css/console.*.css.map

+ 21 - 0
LICENSE

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2019 邹景立
+
+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.

+ 133 - 0
README.md

@@ -0,0 +1,133 @@
+## 大道至简 · 原生框架
+
+ThinkAdmin V5 是一个基于 ThinkPHP 5.1 开发的后台管理系统。
+
+我们致力于二次开发底层框架,提供完整的组件及API,基于此框架可以快速开发应用。
+
+另外项目安装及二次开发可以参考 ThinkPHP 官方文档,数据库文件摆放在项目根目录下。
+
+ThinkAdmin 非常适用快速二次开发,默认集成 微信开发组件,支持微信服务号、微信支付、支付宝支付、阿里云OSS存储、七牛云存储、本地服务器存储等。
+后台UI基于最新版本的 LayUI 及 RequireJs 加载第三方插件(建议自行了解 LayUI 及 RequireJs)。
+
+#### 注意事项 
+* 项目测试需要自行搭建环境导入数据库( admin_v5.sql )并修改配置( config/database.php );
+* 若操作提示“演示系统禁止操作”等字样,需要删除演示路由配置( route/demo.php )或清空路由文件;
+* 当前版本使用 ThinkPHP 5.1.x,对 PHP 版本标注不低于 PHP 5.6,具体请阅读 ThinkPHP 官方文档;
+* 环境需开启 PATHINFO,不再支持 ThinkPHP 的 URL 兼容模式运行(源于如何优雅的展示);
+
+## 技术支持
+
+开发文档:http://doc.thinkadmin.top/thinkadmin-v5
+
+开发前请认真阅读 ThinkPHP 官方文档会对您有帮助哦!
+
+本地开发命令`php think run`,使用`http://127.0.0.1:8000`访问项目。
+
+PHP 开发技术交流( QQ 群 513350915)
+
+[![PHP微信开发群 (SDK)](http://pub.idqqimg.com/wpa/images/group.png)](http://shang.qq.com/wpa/qunwpa?idkey=ae25cf789dafbef62e50a980ffc31242f150bc61a61164458216dd98c411832a) 
+
+
+## 注解权限
+
+注解权限是指通过方法注释来实现后台RBAC授权管理,用注解来管理功能节点。
+
+开发人员只需要写好注释,RBAC的节点会自动生成,只需要配置角色及用户就可以使用RBAC权限。
+
+* 此版本的权限使用注解实现
+* 注释必需使用标准的块注释,如下案例
+* 其中`@auth true`表示访问需要权限验证
+* 其中`@menu true`显示在菜单编辑的节点可选项
+```php
+/**
+* 操作的名称
+* @auth true  # 表示需要验证权限
+* @menu true  # 在菜单编辑的节点可选项
+*/
+public function index(){
+   // @todo
+}
+```
+
+## 代码仓库
+
+ ThinkAdmin 为 MIT 协议开源项目,安装使用或二次开发不受约束,欢迎 fork 项目。
+ 
+ 部分代码来自互联网,若有异议可以联系作者进行删除。
+ 
+ * 在线体验地址:https://demo.thinkadmin.top (账号和密码都是 admin )
+ * Gitee仓库地址:https://gitee.com/zoujingli/ThinkAdmin
+ * GitHub仓库地址:https://github.com/zoujingli/ThinkAdmin
+ 
+## 框架指令
+
+* 执行 `build.cmd` 可更新 `Composer` 插件,会删除并替换 `vendor` 目录
+* 执行 `php think run` 启用本地开发环境,访问 `http://127.0.0.1:8000`
+
+#### 1. 线上代码更新
+* 执行 `php think xsync:admin` 从线上服务更新 `admin` 模块的所有文件(注意文件安全)
+* 执行 `php think xsync:wechat` 从线上服务更新 `wechat` 模块的所有文件(注意文件安全)
+* 执行 `php think xsync:service` 从线上服务更新 `service` 模块的所有文件(注意文件安全)
+* 执行 `php think xsync:plugs` 从线上服务更新 `plugs` 静态插件的部分文件(注意文件安全)
+* 执行 `php think xsync:config` 从线上服务更新 `config` 项目配置的部分文件(注意文件安全)
+
+#### 2. 微信资料管理
+* 执行 `php think xfans:all` 更新已经对接的公众号全部列表
+* 执行 `php think xfans:list` 更新已经对接的公众号粉丝列表
+* 执行 `php think xfans:tags` 更新已经对接的公众号标签列表
+* 执行 `php think xfans:black` 更新已经对接的公众号黑名单列表
+
+#### 3. 守护进程管理
+* 执行 `php think xtask:listen` 启动异步任务监听守护主进程
+* 执行 `php think xtask:query` 查询正在执行的所有任务进程
+* 执行 `php think xtask:start` 创建异步任务监听守护主进程
+* 执行 `php think xtask:state` 查看异步任务监听主进程状态
+* 执行 `php think xtask:stop` 平滑停止异步任务所有的进程
+
+#### 4. 其它自定工具
+* 执行 `php think xclean:session` 清理无效的会话SESSION文件
+* 执行 `php think xclean:store` 清理无效的订单信息及定时任务
+ 
+## 特别感谢
+
+|名称|描述|
+|---|---|
+|layui|后台基础UI组件库|
+|ckeditor|后台富文本编辑器|
+|awesome|后台扩展字体图标库|
+|pluploader|后台文件上传工具|
+|ThinkPHP|PHP基础支持框架|
+|ThinkLibrary|ThinkPHP扩展组件|
+|WeChatDeveloper|微信开放工具组件|
+|WeOpenDeveloper|微信开放平台组件|
+
+## 赞助打赏
+![赞助](http://static.thinkadmin.top/pay.png)
+
+## 项目版本
+体验账号及密码都是`admin`
+
+#### ThinkAdmin v1 基于 ThinkPHP 5.0 开发
+* 在线体验地址:https://v1.thinkadmin.top
+* Gitee 代码地址:https://gitee.com/zoujingli/ThinkAdmin/tree/v1
+* Github 代码地址:https://github.com/zoujingli/ThinkAdmin/tree/v1
+
+#### ThinkAdmin v2 基于 ThinkPHP 5.0 开发
+* 在线体验地址:https://v2.thinkadmin.top
+* Gitee 代码地址:https://gitee.com/zoujingli/ThinkAdmin/tree/v2
+* Github 代码地址:https://github.com/zoujingli/ThinkAdmin/tree/v2
+
+#### ThinkAdmin v3 基于 ThinkPHP 5.1 开发
+* 在线体验地址:https://v3.thinkadmin.top
+* Gitee 代码地址:https://gitee.com/zoujingli/ThinkAdmin/tree/v3
+* Github 代码地址:https://github.com/zoujingli/ThinkAdmin/tree/v3
+
+#### ThinkAdmin v4 基于 ThinkPHP 5.1 开发
+* 在线体验地址:https://v4.thinkadmin.top
+* Gitee 代码地址:https://gitee.com/zoujingli/ThinkAdmin/tree/v4
+* Github 代码地址:https://github.com/zoujingli/ThinkAdmin/tree/v4
+
+#### ThinkAdmin v5 基于 ThinkPHP 5.1 开发(后台权限基于注解实现)
+* 在线体验地址:https://v5.thinkadmin.top
+* Gitee 代码地址:https://gitee.com/zoujingli/ThinkAdmin/tree/v5
+* Github 代码地址:https://github.com/zoujingli/ThinkAdmin/tree/v5

+ 245 - 0
application/PHPExcelService.php

@@ -0,0 +1,245 @@
+<?php
+namespace app\common\library;
+
+use crmeb\services\JsonService as Json;
+
+class PHPExcelService
+{
+    //PHPExcel实例化对象
+    private static $PHPExcel=null;
+    //表头计数
+    protected static $count;
+    //表头占行数
+    protected static $topNumber = 3;
+    //表能占据表行的字母对应self::$cellkey
+    protected static $cells;
+    //表头数据
+    protected static $data=[];
+    //文件名
+    protected static $title='订单导出';
+    //行宽
+    protected static $where=20;
+    //行高
+    protected static $height=50;
+    //表行名
+    private static $cellKey = array(
+        'A','B','C','D','E','F','G','H','I','J','K','L','M',
+        'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
+        'AA','AB','AC','AD','AE','AF','AG','AH','AI','AJ','AK','AL','AM',
+        'AN','AO','AP','AQ','AR','AS','AT','AU','AV','AW','AX','AY','AZ'
+    );
+    //设置style
+    private static $styleArray = array(
+        'borders' => array(
+            'allborders' => array(
+//                PHPExcel_Style_Border里面有很多属性,想要其他的自己去看
+//                'style' => \PHPExcel_Style_Border::BORDER_THICK,//边框是粗的
+//                'style' => \PHPExcel_Style_Border::BORDER_DOUBLE,//双重的
+//                'style' => \PHPExcel_Style_Border::BORDER_HAIR,//虚线
+//                'style' => \PHPExcel_Style_Border::BORDER_MEDIUM,//实粗线
+//                'style' => \PHPExcel_Style_Border::BORDER_MEDIUMDASHDOT,//虚粗线
+//                'style' => \PHPExcel_Style_Border::BORDER_MEDIUMDASHDOTDOT,//点虚粗线
+                'style' => \PHPExcel_Style_Border::BORDER_THIN,//细边框
+                //'color' => array('argb' => 'FFFF0000'),
+            ),
+        ),
+        'font'=>[
+            'bold'=>true
+        ],
+        'alignment'=>[
+            'horizontal'=>\PHPExcel_Style_Alignment::HORIZONTAL_CENTER,
+            'vertical'=>\PHPExcel_Style_Alignment::VERTICAL_CENTER
+        ]
+    );
+    /**
+     *初始化PHPExcel类
+     *@param $data array()
+     *@param $fun function()
+     * return
+     */
+    private static function initialize($data,$fun){
+        self::$PHPExcel= new \PHPExcel();
+        if($fun!==null && is_callable($fun)){
+            self::$styleArray=$fun();
+        }
+        if(!is_array($data)) exit(Json::fail('data 为数组'));
+        self::$data=$data;
+    }
+    /**
+     *设置字体格式
+     *@param $title string 必选
+     * return string
+     */
+    public static function setUtf8($title){
+        return "";
+        //return iconv('utf-8', 'gb2312', $title);
+    }
+    /**
+     *
+     * execl数据导出
+     * @param  $list 需要导出的数据 格式和以前的可是一样
+     * @param  $list 也可以为匿名函数 匿名函数参数有 $sheet PHPExcel->getActiveSheet(),self::$topNumber 从第几行设置,$cellkey 行号为数组,self::$cells现在设置的最大行号
+     *
+     * 特殊处理:合并单元格需要先对数据进行处理
+     */
+    public function setExcelContent($list=null)
+    {
+        $sheet=self::$PHPExcel->getActiveSheet();
+        foreach(self::$data as $key=>$val){
+            $row=self::$cellKey[$key];
+            $sheet->getColumnDimension($row)->setWidth(isset($val['w'])?$val['w']:self::$where);
+            $sheet->setCellValue($row.self::$topNumber,isset($val['name'])?$val['name']:$val);
+        }
+        $cellkey=array_slice(self::$cellKey,0,self::$count);
+        if($list!==null && is_array($list)){
+            foreach ($cellkey as $k=>$v){
+                foreach ($list as $key=>$val){
+                    if(isset($val[$k]) && !is_array($val[$k])){
+                        $sheet->setCellValue($v.(self::$topNumber+1+$key),$val[$k]);
+                    }else if(isset($val[$k]) && is_array($val[$k])){
+                        $str='';
+                        foreach ($val[$k] as $value){
+                            $str.=$value.chr(10);
+                        }
+                        $sheet->setCellValue($v.(self::$topNumber+1+$key),$str);
+                    }
+                }
+            }
+            $sheet->getDefaultRowDimension()->setRowHeight(self::$height);
+            //设置边框
+            $sheet->getStyle('A1:'.self::$cells.(count($list)+self::$topNumber))->applyFromArray(self::$styleArray);
+            //设置自动换行
+            $sheet->getStyle('A4:'.self::$cells.(count($list)+self::$topNumber))->getAlignment()->setWrapText(true);
+        }else if($list!==null && is_callable($list)){
+            $list($sheet,self::$topNumber,$cellkey,self::$cells)->applyFromArray(self::$styleArray);
+        }
+
+        return $this;
+    }
+    /**
+     * 保存表格数据,并下载
+     * @param
+     * @return
+     */
+    public function ExcelSave(){
+        error_reporting(0);
+        $objWriter=\PHPExcel_IOFactory::createWriter(self::$PHPExcel,'Excel2007');
+        $filename=self::$title.'--'.time().'.xls';
+        ob_end_clean();
+        header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
+        header('Content-Type: application/vnd.ms-excel');
+        header('Content-Type: application/octet-stream');
+        header('Content-Disposition: attachment; filename="' . $filename . '"');
+        header('Cache-Control: max-age=0');
+        $objWriter->save('php://output');
+        exit;
+    }
+
+    /**
+     * 设置头部信息
+     * @param $data array
+     * @param $fun function() 主要设置边框的粗细
+     * @return $this
+     */
+    public static function setExcelHeader($data,$fun=null)
+    {
+        self::initialize($data,$fun);
+
+        if(self::$count=count(self::$data)){
+            if(self::$count>count(self::$cellKey)){
+                return Json::fail('表头长度过长');
+            }
+            self::$cells=self::$cellKey[self::$count-1];
+        }else{
+            return Json::fail('data 参数二不能为空');
+        }
+        return new self;
+    }
+    /**
+     * 设置标题
+     * @param $title string || array ['title'=>'','name'=>'','info'=>[]]
+     * @param $Name string
+     * @param $info string || array;
+     * @param $funName function($style,$A,$A2) 自定义设置头部样式
+     * @return $this
+     */
+    public function setExcelTile($title='',$Name='',$info=[],$funName=null){
+        //设置参数
+        if(is_array($title)){
+            if(isset($title['title'])) $title=$title['title'];
+            if(isset($title['name'])) $Name=$title['name'];
+            if(isset($title['info'])) $info=$title['info'];
+        }
+        if(empty($title))
+            $title=self::$title;
+        else
+            self::$title=$title;
+        if(empty($Name)) $Name=time();
+        //设置Excel属性
+        self::$PHPExcel ->getProperties()
+            ->setCreator("Neo")
+            ->setLastModifiedBy("Neo")
+            ->setTitle(self::setUtf8($title))
+            ->setSubject($Name)
+            ->setDescription("")
+            ->setKeywords($Name)
+            ->setCategory("");
+        self::$PHPExcel ->getActiveSheet()->setCellValue('A1', $title);
+        //文字居中
+        self::$PHPExcel->getActiveSheet()->getStyle('A1')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
+        self::$PHPExcel->getActiveSheet()->getStyle('A2')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
+        self::$PHPExcel->setActiveSheetIndex(0);
+        self::$PHPExcel->getActiveSheet()->setTitle($Name);
+
+        self::$PHPExcel->getActiveSheet()->setCellValue('A2',self::setCellInfo($info));
+        //合并表头单元格
+        self::$PHPExcel->getActiveSheet()->mergeCells('A1:'.self::$cells.'1');
+        self::$PHPExcel->getActiveSheet()->mergeCells('A2:'.self::$cells.'2');
+
+        self::$PHPExcel->getActiveSheet()->getRowDimension(1)->setRowHeight(40);
+        self::$PHPExcel->getActiveSheet()->getRowDimension(2)->setRowHeight(20);
+        //设置表头行高
+        if($funName!==null && is_callable($funName)){
+            $fontstyle=self::$PHPExcel->getActiveSheet();
+            $funName($fontstyle,'A1','A2');
+        }else{
+            //设置表头字体
+            self::$PHPExcel->getActiveSheet()->getStyle('A1')->getFont()->setName('黑体');
+            self::$PHPExcel->getActiveSheet()->getStyle('A1')->getFont()->setSize(20);
+            self::$PHPExcel->getActiveSheet()->getStyle('A1')->getFont()->setBold(true);
+            self::$PHPExcel->getActiveSheet()->getStyle('A2')->getFont()->setName('宋体');
+            self::$PHPExcel->getActiveSheet()->getStyle('A2')->getFont()->setSize(14);
+        }
+        self::$PHPExcel->getActiveSheet()->getStyle('A3:'.self::$cells.'3')->getFont()->setBold(true);
+
+        return $this;
+    }
+    /**
+     * 设置第二行标题内容
+     * @param $info  array (['name'=>'','site'=>'','phone'=>123] || ['我是表名','我是地址','我是手机号码'] ) || string 自定义
+     * @return string
+     */
+    private static function setCellInfo($info){
+        $content=['操作者:','导出日期:'.date('Y-m-d',time()),'地址:','电话:'];
+        if(is_array($info) && !empty($info)){
+            if(isset($info['name'])){
+                $content[0].=$info['name'];
+            }else{
+                $content[0].=isset($info[0])?$info[0]:'';
+            }
+            if(isset($info['site'])){
+                $content[2].=$info['site'];
+            }else{
+                $content[2].=isset($info[1])?$info[1]:'';
+            }
+            if(isset($info['phone'])){
+                $content[3].=$info['phone'];
+            }else{
+                $content[3].=isset($info[2])?$info[2]:'';
+            }
+            return implode(' ',$content);
+        }else if(is_string($info)){
+            return empty($info)?implode(' ',$content):$info;
+        }
+    }
+}

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

@@ -0,0 +1,178 @@
+<?php
+
+// +----------------------------------------------------------------------
+// | ThinkAdmin
+// +----------------------------------------------------------------------
+// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// +----------------------------------------------------------------------
+// | 官方网站: http://demo.thinkadmin.top
+// +----------------------------------------------------------------------
+// | 开源协议 ( https://mit-license.org )
+// +----------------------------------------------------------------------
+// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
+// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller;
+
+use library\Controller;
+use library\service\AdminService;
+use think\Db;
+
+/**
+ * 权限管理
+ * Class Auth
+ * @package app\admin\controller
+ */
+class Auth extends Controller
+{
+    /**
+     * 默认数据模型
+     * @var string
+     */
+    public $table = 'SystemAuth';
+
+    /**
+     * 权限管理
+     * @auth true
+     * @menu true
+     * @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 = '权限管理';
+        $query = $this->_query($this->table)->dateBetween('create_at');
+        $query->like('title,desc')->equal('status')->order('sort desc,id desc')->page();
+    }
+
+    /**
+     * 授权
+     * @auth true
+     * @throws \ReflectionException
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function apply()
+    {
+        $map = ['auth' => input('id', '0')];
+        $action = strtolower(input('action', ''));
+        if ($action === 'get') {
+            $checkeds = Db::name('SystemAuthNode')->where($map)->column('node');
+            $this->success('获取权限节点成功!', AdminService::instance()->getTree($checkeds));
+        } elseif ($action === 'save') {
+            list($post, $data) = [$this->request->post(), []];
+            foreach (isset($post['nodes']) ? $post['nodes'] : [] as $node) {
+                $data[] = ['auth' => $map['auth'], 'node' => $node];
+            }
+            Db::name('SystemAuthNode')->where($map)->delete();
+            Db::name('SystemAuthNode')->insertAll($data);
+            AdminService::instance()->apply(true);
+            $this->success('权限授权更新成功!', 'javascript:history.back()');
+        } else {
+            $this->title = '权限配置节点';
+            $this->_form($this->table, 'apply');
+        }
+    }
+
+    /**
+     * 添加权限
+     * @auth true
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
+     */
+    public function add()
+    {
+        $this->_form($this->table, 'form');
+    }
+
+    /**
+     * 编辑权限
+     * @auth true
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
+     */
+    public function edit()
+    {
+        $this->_form($this->table, 'form');
+    }
+
+    /**
+     * 刷新权限
+     * @auth true
+     */
+    public function refresh()
+    {
+        try {
+            AdminService::instance()->apply(true);
+            $this->success('刷新系统授权成功!');
+        } catch (\think\exception\HttpResponseException $exception) {
+            throw  $exception;
+        } catch (\Exception $e) {
+            $this->error("刷新系统授权失败<br>{$e->getMessage()}");
+        }
+    }
+
+    /**
+     * 禁用权限
+     * @auth true
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function forbid()
+    {
+        $this->applyCsrfToken();
+        $this->_save($this->table, ['status' => '0']);
+    }
+
+    /**
+     * 启用权限
+     * @auth true
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function resume()
+    {
+        $this->applyCsrfToken();
+        $this->_save($this->table, ['status' => '1']);
+    }
+
+    /**
+     * 删除权限
+     * @auth true
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function remove()
+    {
+        $this->applyCsrfToken();
+        $this->_delete($this->table);
+    }
+
+    /**
+     * 删除结果处理
+     * @param boolean $result
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    protected function _remove_delete_result($result)
+    {
+        if ($result) {
+            $map = ['auth' => $this->request->post('id')];
+            Db::name('SystemAuthNode')->where($map)->delete();
+            $this->success("权限删除成功!", '');
+        } else {
+            $this->error("权限删除失败,请稍候再试!");
+        }
+    }
+
+}

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

@@ -0,0 +1,178 @@
+<?php
+
+// +----------------------------------------------------------------------
+// | ThinkAdmin
+// +----------------------------------------------------------------------
+// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// +----------------------------------------------------------------------
+// | 官方网站: http://demo.thinkadmin.top
+// +----------------------------------------------------------------------
+// | 开源协议 ( https://mit-license.org )
+// +----------------------------------------------------------------------
+// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
+// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller;
+
+use library\Controller;
+
+use library\tools\Data;
+use think\Db;
+use think\facade\Hook;
+use think\Request;
+
+/**
+ * 分类管理
+ */
+class Category extends Controller
+{
+    /**
+     * 绑定数据表
+     * @var string
+     */
+    protected $table = 'system_goods_cate';
+
+    /**
+     * 分类管理
+     * @auth true
+     * @menu true
+     * @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 = '分类管理';
+        $query = $this->_query($this->table)->where('pid', 0)->like('title');
+        if (isset($_GET['status']) && $_GET['status']!=''){
+            $query->where('status',$_GET['status']);
+        }
+        if (isset($_GET['label_id']) && $_GET['label_id']!=''){
+            $query->where('label_id',$_GET['label_id']);
+        }
+        $query->where('is_deleted', 0)
+            ->order('pid asc,id desc')
+            ->page();
+
+    }
+
+    /**
+     * 列表数据处理
+     * @param array $data
+     */
+    protected function _index_page_filter(&$data)
+    {
+        foreach ($data as &$vo) {
+            $vo['children'] = Db::name($this->table)
+                ->where('is_deleted', 0)
+                ->where('pid', $vo['id'])
+                ->select();
+
+            foreach ($vo['children'] as &$v) {
+                $v['children'] = Db::name($this->table)
+                    ->where('is_deleted', 0)
+                    ->where('pid', $v['id'])
+                    ->select();
+            }
+        }
+        $data = Data::arr2table($data);
+       // dump($data);die;
+    }
+
+    /**
+     * 添加分类
+     * @auth true
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
+     */
+    public function add()
+    {
+        $this->_form($this->table, 'form');
+    }
+
+    /**
+     * 编辑分类
+     * @auth true
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
+     */
+    public function edit()
+    {
+        $this->_form($this->table, 'form');
+    }
+
+    /**
+     * 表单数据处理
+     * @param array $vo
+     * @throws \ReflectionException
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    protected function _form_filter(&$vo)
+    {
+        if ($this->request->isGet()) {
+
+            // 选择自己的上级分类
+            if (empty($vo['pid']) && $this->request->get('pid', '0')) $vo['pid'] = $this->request->get('pid', '0');
+            // 列出可选上级分类
+            $menus = Db::name($this->table)->where(['status' => '1'])->where('is_deleted', 0)->order('id asc')->column('id,pid,title');
+            $this->menus = Data::arr2table(array_merge($menus, [['id' => '0', 'pid' => '-1', 'title' => '一级分类']]));
+            if (isset($vo['id'])) foreach ($this->menus as $key => $menu) if ($menu['id'] === $vo['id']) $vo = $menu;
+            foreach ($this->menus as $key => &$menu) {
+                if ($menu['spt'] >= 3) unset($this->menus[$key]);
+            }
+
+            //dump($this->menus);die;
+
+        }elseif ($this->request->isPost()){
+            $pid = request()->post('pid');
+            $id = request()->post('id');
+            if ($pid == $id) $this->error('上级分类不能是自身');
+        }
+    }
+
+    /**
+     * 禁用分类
+     * @auth true
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function forbid()
+    {
+        $this->applyCsrfToken();
+        $this->_save($this->table, ['status' => '0']);
+    }
+
+    /**
+     * 启用分类
+     * @auth true
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function resume()
+    {
+        $this->applyCsrfToken();
+        $this->_save($this->table, ['status' => '1']);
+    }
+
+    /**
+     * 删除分类
+     * @auth true
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function remove()
+    {
+        $this->_delete($this->table);
+    }
+}

+ 1097 - 0
application/admin/controller/ChildProject.php

@@ -0,0 +1,1097 @@
+<?php
+
+// +----------------------------------------------------------------------
+// | ThinkAdmin
+// +----------------------------------------------------------------------
+// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// +----------------------------------------------------------------------
+// | 官方网站: http://demo.thinkadmin.top
+// +----------------------------------------------------------------------
+// | 开源协议 ( https://mit-license.org )
+// +----------------------------------------------------------------------
+// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
+// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller;
+
+use library\Controller;
+use library\tools\Data;
+use think\Db;
+
+/**
+ * 子项目管理
+ * Class User
+ * @package app\admin\controller
+ */
+class ChildProject extends Controller
+{
+
+    /**
+     * 指定当前数据表
+     * @var string
+     */
+    public $table = 'system_child_project';
+    public $table3 = 'system_child_project_analysis';
+
+    /**
+     * 建安成本管理
+     * @auth true
+     * @menu true
+     * @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->getcategoryids(1);
+        $this->title = '建安成本管理';
+        $category_id = $this->request->get('category_id');
+        $query = $this->_query($this->table)
+            ->like('project_name,design_life,decorate_standard,other_parameters')
+            ->equal('structure_type,building_fortification_intensity,seismic_grade,base_type,template')
+            ->fieldBetween('construction_layer','construction_layer_start,construction_layer_end')
+            ->fieldBetween('upper_number','upper_number_start,upper_number_end')
+            ->fieldBetween('underground','underground_start,underground_end')
+            ->fieldBetween('underground_layer','underground_layer_start,underground_layer_end')
+            ->fieldBetween('first_layer_high','first_layer_high_start,first_layer_high_end')
+            ->fieldBetween('standard_height','standard_height_start,standard_height_end')
+            ->fieldBetween('construction_area','construction_area_start,construction_area_end')
+            ->fieldBetween('ground_floor_area','ground_floor_area_start,ground_floor_area_end')
+            ->fieldBetween('underground_floor_area','underground_floor_area_start,underground_floor_area_end')
+            ->fieldBetween('building_floor_area','building_floor_area_start,building_floor_area_end')
+            ->fieldBetween('steel_benefit_area','steel_benefit_area_start,steel_benefit_area_end')
+            ->fieldBetween('wood_area','wood_area_start,wood_area_end')
+            ->fieldBetween('available_area','available_area_start,available_area_end')
+            ->fieldBetween('number','number_start,number_end')
+            ->fieldBetween('basement_floor_area','basement_floor_area_start,basement_floor_area_end')
+            ->fieldBetween('building_height','building_height_start,building_height_end');
+
+        $query->when($category_id,function ($query) use ($category_id){
+            $query->whereIn('category_id',$this->getcategoryids($category_id));
+        });
+
+        $query->dateBetween('login_at,create_at')
+            ->where(['is_deleted' => '0'])
+            ->order('id desc')
+            ->page();
+    }
+
+    //获取分类下面所有分类ID
+    public function getcategoryids($category_id){
+        $three = [];
+        $two = Db::name('system_goods_cate')
+            ->where('pid',$category_id)
+            ->where('is_deleted',0)
+            ->column('id');
+        if ($two){
+            $three = Db::name('system_goods_cate')
+                ->whereIn('pid',$two)
+                ->where('is_deleted',0)
+                ->column('id');
+        }
+        $categorys = array_merge($two,$three);
+        array_push($categorys,$category_id);
+        return $categorys;
+    }
+
+    /**
+     * 列表数据处理
+     * @param array $data
+     */
+    protected function _index_page_filter(&$data)
+    {
+        foreach ($data as &$vo) {
+            $vo['main_project_name'] = Db::name('system_main_project')->where('id',$vo['main_project_id'])->value('project_name');
+            $vo['category_name'] = Db::name('system_goods_cate')->where('id',$vo['category_id'])->value('title');
+        }
+        $menus = Db::name('system_goods_cate')->where(['status' => '1'])->where('is_deleted', 0)->order('id asc')->column('id,pid,title');
+        $this->menus = Data::arr2table(array_merge([['id' => '', 'pid' => '-1', 'title' => '--全部--']],$menus ));
+        $template = Db::name('system_template')->where('is_del',1)->field('id,title')->select();
+        $this->template = array_merge([['id' => '', 'title' => '--全部--']],$template );
+    }
+
+
+    /**
+     * 创建子项目
+     * @auth true
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
+     */
+    public function add()
+    {
+        $this->title = '创建子项目';
+        $this->_form($this->table, 'form');
+    }
+
+    /**
+     * 编辑子项目
+     * @auth true
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
+     */
+    public function edit()
+    {
+        $this->title = '编辑子项目';
+        $this->_form($this->table, 'form');
+    }
+
+    /**
+     * 子项目详情
+     * @auth true
+     * @menu true
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
+     */
+    public function projectinfo()
+    {
+        $this->_form($this->table, 'info');
+    }
+
+    /**
+     * 表单数据处理
+     * @param array $data
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function _form_filter(&$data)
+    {
+        if ($this->request->isPost()) {
+
+        } else {
+
+            if (!empty($data)){
+                $data['category_name'] = Db::name('system_goods_cate')->where('id',$data['category_id'])->value('title');
+            }
+            $this->main_list = Db::name('system_main_project')->where('is_deleted',0)->all();
+
+            $menus = Db::name('system_goods_cate')->where(['status' => '1'])->where('is_deleted', 0)->order('id asc')->column('id,pid,title');
+            $this->menus = Data::arr2table($menus);
+
+            $template = Db::name('system_template')->where('is_del',1)->field('id,title')->select();
+            $this->template = array_merge([['id' => '', 'title' => '--全部--']],$template );
+        }
+    }
+
+    /**
+     * 处理成功回调
+     */
+    public function _form_result($result,$data){
+        if ($result) {
+            $this->success('成功',url('/#/admin/child_project/index'));
+        }
+    }
+
+    /**
+     * 删除子项目
+     * @auth true
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function remove()
+    {
+        $this->_save($this->table, ['is_deleted' => '1']);
+        //$this->_delete($this->table);
+    }
+
+    /**
+     * 导入子项目数据
+     * @auth true
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function import()
+    {
+        $get = $this->request->get();
+        $import_path = $_SERVER['DOCUMENT_ROOT'].'/'.$get['path'];
+        $project_id = $get['project_id'];
+        $num = 5;
+        try {
+            $objReader =\PHPExcel_IOFactory::createReader('Excel2007');
+            $objExcel = $objReader->load($import_path);
+
+            $list = $objExcel->getActiveSheet()->toArray();
+            if (!isset($list[2][15]) || !$list[2][15]){
+                $this->error('失败');
+            }
+            if (isset($list[2][16])){
+                $this->error('失败');
+            }
+            Db::name($this->table3)->where('project_id',$project_id)->delete();
+            Db::name($this->table)->where('id',$project_id)->update(['url'=>$get['url']]);
+            $result = 0;
+            foreach ($list as $k=>$v){
+                if($k>=$num-1){
+                    if(array_filter($v)){
+                        $data=[];
+                        foreach ($v as $kk=>$vv){
+                            $data[IntToChr($kk)]=trim($vv);
+                        }
+                        $date['project_id'] = $project_id;
+                        $date['number'] = $data['A'];
+                        $date['cost_project'] = $data['B'];
+                        $date['area_calculating_aperture'] = $data['C'];
+                        $date['single_party_cost'] = $data['D'];
+                        $date['single_party_cost1'] = str_replace(',','',$data['D']);
+                        $date['total_price_included'] = $data['E'];
+                        $date['total_price_included1'] = str_replace(',','',$data['E']);
+                        $date['single_party_cost_excluding'] = $data['F'];
+                        $date['single_party_cost_excluding1'] = str_replace(',','',$data['F']);
+                        $date['total_price_included_excluding'] = $data['G'];
+                        $date['total_price_included_excluding1'] = str_replace(',','',$data['G']);
+
+                        $date['single_party_cost_tax'] = $data['H'];
+                        $date['single_party_cost_tax1'] = str_replace(',','',$data['H']);
+                        $date['single_party_cost_no_tax'] = $data['I'];
+                        $date['single_party_cost_no_tax1'] = str_replace(',','',$data['I']);
+
+                        $date['quantities'] = $data['J'];
+                        $date['quantities1'] = str_replace(',','',$data['J']);
+                        $date['calculating_unit'] = $data['K'];
+                        $date['unilateral_content'] = $data['L'];
+                        $date['unilateral_content1'] = str_replace(',','',$data['L']);
+                        $date['unilateral_content_excluding'] = $data['M'];
+                        $date['unilateral_content_excluding1'] = str_replace(',','',$data['M']);
+
+                        $date['saleable_single_party_tax'] = $data['N'];
+                        $date['saleable_single_party_tax1'] = str_replace(',','',$data['N']);
+
+                        $date['saleable_single_party_no_tax'] = $data['O'];
+                        $date['saleable_single_party_no_tax1'] = str_replace(',','',$data['O']);
+
+                        $date['note'] = $data['P'];
+                        $date['create_at'] = date('Y-m-d H:i:s');
+
+                        $numbers = explode('.',$data['A']);
+                        if (count($numbers)>1){
+                            array_pop($numbers); //去掉数组最后一组元素
+                            $number = implode('.',$numbers);
+                            $date['pid'] = Db::name($this->table3)->where('project_id',$project_id)->where('number',$number)->value('id');
+                            $date['pname'] = Db::name($this->table3)->where('project_id',$project_id)->where('number',$number)->value('cost_project');
+                        }else{
+                            $date['pid'] = 0;
+                            $date['pname'] = '';
+                        }
+                        if (Db::table($this->table3)->insertGetId($date)){
+                            $result = 1;
+                        }else{
+                            $result = 0;
+                            break;
+                        }
+                    }
+                }
+            }
+            if ($result==1){
+                $this->success('成功');
+            }else{
+                $this->error('失败');
+            }
+        } catch (\think\exception\ValidateException $e) {
+            $this->error($e->getMessage());
+
+        }
+    }
+
+
+    /**
+     * 查看数据
+     * @auth true
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
+     */
+    public function look()
+    {
+        $id = $this->app->request->get('id');
+        $this->title = '查看';
+        $list = Db::name($this->table3)->where('project_id',$id)->order('id asc')->select();
+        $this->assign('list',$list);
+        $this->fetch();
+    }
+
+    /**
+     * 下载数据
+     * @auth true
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
+     */
+    public function down()
+    {
+
+    }
+
+    /**
+     * 数据对比
+     * @auth true
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
+     */
+    public function contrast()
+    {
+        set_time_limit(0);
+        $this->title = '数据对比';
+        $ids = $this->request->get('ids');
+        $this->assign('ids',$ids);
+//        $query = $this->_query($this->table3);
+//        $query->whereIn('project_id',$ids)
+//            ->group('cost_project')
+//            ->order('id asc')
+//            ->field('id,pid,number,cost_project')
+//            ->page();
+
+        $list = Db::name($this->table3)->whereIn('project_id',$ids)
+            ->group('cost_project')
+            ->order('id asc')
+            ->field('id,pid,pname,number,cost_project')
+            ->select();
+        $list = $this->deal_list($ids,$list);
+
+        $list = $this->get_attr($list);
+
+        $this->assign('list',$list);
+        $this->fetch();
+    }
+
+
+    public function get_attr($a,$pid=''){
+        $tree = array();                                //每次都声明一个新数组用来放子元素
+        foreach($a as $v){
+            if($v['pname'] == $pid){                      //匹配子记录
+                $v['children'] = $this->get_attr($a,$v['cost_project']); //递归获取子记录
+                $tree[] = $v;                           //将记录存入新数组
+            }
+        }
+        return $tree;                                  //返回新数组
+    }
+
+
+    //列表处理
+    public function deal_list($ids,$list){
+        foreach ($list as &$v){
+            $where = [];
+            $where[] = ['project_id','in',$ids];
+            $where[] = ['cost_project','eq', $v['cost_project']];
+            //---建面单方成本(元/m2)(含税)---//
+            //参考区间
+            $single_party_cost_interval_start = Db::name($this->table3)
+                ->where($where)
+                ->where('single_party_cost','neq','')
+                ->min('single_party_cost1');
+            $single_party_cost_interval_end = Db::name($this->table3)
+                ->where($where)
+                ->where('single_party_cost','neq','')
+                ->max('single_party_cost1');
+            $v['single_party_cost_interval'] = $single_party_cost_interval_start.'-'.$single_party_cost_interval_end;
+            //算数平均值
+            $single_party_cost_arithmetic_mean_all = Db::name($this->table3)
+                ->where($where)
+                ->where('single_party_cost','neq','')
+                ->sum('single_party_cost1');
+            $single_party_cost_arithmetic_mean_count = Db::name($this->table3)
+                ->where($where)
+                ->where('single_party_cost','neq','')
+                ->count();
+            $v['single_party_cost_arithmetic_mean'] = ($single_party_cost_arithmetic_mean_all==0 || $single_party_cost_arithmetic_mean_count==0) ? 0 : $single_party_cost_arithmetic_mean_all/$single_party_cost_arithmetic_mean_count;
+            //有效样本量
+            $v['single_party_cost_valid_sample_size'] = $single_party_cost_arithmetic_mean_count;
+
+
+            //---总价(万元)(含税)---//
+            //参考区间
+            $total_price_included_interval_start = Db::name($this->table3)
+                ->where($where)
+                ->where('total_price_included','neq','')
+                ->min('total_price_included1');
+            $total_price_included_interval_end = Db::name($this->table3)
+                ->where($where)
+                ->where('total_price_included','neq','')
+                ->max('total_price_included1');
+            $v['total_price_included_interval'] = $total_price_included_interval_start.'-'.$total_price_included_interval_end;
+            //算数平均值
+            $total_price_included_arithmetic_mean_all = Db::name($this->table3)
+                ->where($where)
+                ->where('total_price_included','neq','')
+                ->sum('total_price_included1');
+            $total_price_included_arithmetic_mean_count = Db::name($this->table3)
+                ->where($where)
+                ->where('total_price_included','neq','')
+                ->count();
+            $v['total_price_included_arithmetic_mean'] = ($total_price_included_arithmetic_mean_all==0 || $total_price_included_arithmetic_mean_count==0) ? 0 : $total_price_included_arithmetic_mean_all/$total_price_included_arithmetic_mean_count;
+            //有效样本量
+            $v['total_price_included_valid_sample_size'] = $total_price_included_arithmetic_mean_count;
+
+            //---建面单方成本(元/m2)(不含税)---//
+            //参考区间
+            $single_party_cost_excluding_interval_start = Db::name($this->table3)
+                ->where($where)
+                ->where('single_party_cost_excluding','neq','')
+                ->min('single_party_cost_excluding1');
+            $single_party_cost_excluding_interval_end = Db::name($this->table3)
+                ->where($where)
+                ->where('single_party_cost_excluding','neq','')
+                ->max('single_party_cost_excluding1');
+            $v['single_party_cost_excluding_interval'] = $single_party_cost_excluding_interval_start.'-'.$single_party_cost_excluding_interval_end;
+            //算数平均值
+            $single_party_cost_excluding_arithmetic_mean_all = Db::name($this->table3)
+                ->where($where)
+                ->where('single_party_cost_excluding','neq','')
+                ->sum('single_party_cost_excluding1');
+            $single_party_cost_excluding_arithmetic_mean_count = Db::name($this->table3)
+                ->where($where)
+                ->where('single_party_cost_excluding','neq','')
+                ->count();
+            $v['single_party_cost_excluding_arithmetic_mean'] = ($single_party_cost_excluding_arithmetic_mean_all==0 || $single_party_cost_excluding_arithmetic_mean_count==0) ? 0 : $single_party_cost_excluding_arithmetic_mean_all/$single_party_cost_excluding_arithmetic_mean_count;
+            //有效样本量
+            $v['single_party_cost_excluding_valid_sample_size'] = $single_party_cost_excluding_arithmetic_mean_count;
+
+
+            //---总价(万元)(不含税)---//
+            //参考区间
+            $total_price_included_excluding_interval_start = Db::name($this->table3)
+                ->where($where)
+                ->where('total_price_included_excluding','neq','')
+                ->min('total_price_included_excluding1');
+            $total_price_included_excluding_interval_end = Db::name($this->table3)
+                ->where($where)
+                ->where('total_price_included_excluding','neq','')
+                ->max('total_price_included_excluding1');
+            $v['total_price_included_excluding_interval'] = $total_price_included_excluding_interval_start.'-'.$total_price_included_excluding_interval_end;
+            //算数平均值
+            $total_price_included_excluding_arithmetic_mean_all = Db::name($this->table3)
+                ->where($where)
+                ->where('total_price_included_excluding','neq','')
+                ->sum('total_price_included_excluding1');
+            $total_price_included_excluding_arithmetic_mean_count = Db::name($this->table3)
+                ->where($where)
+                ->where('total_price_included_excluding','neq','')
+                ->count();
+            $v['total_price_included_excluding_arithmetic_mean'] = ($total_price_included_excluding_arithmetic_mean_all==0 || $total_price_included_excluding_arithmetic_mean_count==0) ? 0 : $total_price_included_excluding_arithmetic_mean_all/$total_price_included_excluding_arithmetic_mean_count;
+            //有效样本量
+            $v['total_price_included_excluding_valid_sample_size'] = $total_price_included_excluding_arithmetic_mean_count;
+
+
+            //---可售单方成本(元/m2)(含税)---//
+            //参考区间
+            $single_party_cost_tax_interval_start = Db::name($this->table3)
+                ->where($where)
+                ->where('single_party_cost_tax','neq','')
+                ->min('single_party_cost_tax1');
+            $single_party_cost_tax_tax_interval_end = Db::name($this->table3)
+                ->where($where)
+                ->where('single_party_cost_tax','neq','')
+                ->max('single_party_cost_tax1');
+            $v['single_party_cost_tax_interval'] = $single_party_cost_tax_interval_start.'-'.$single_party_cost_tax_tax_interval_end;
+            //算数平均值
+            $single_party_cost_tax_arithmetic_mean_all = Db::name($this->table3)
+                ->where($where)
+                ->where('single_party_cost_tax','neq','')
+                ->sum('single_party_cost_tax1');
+            $single_party_cost_tax_arithmetic_mean_count = Db::name($this->table3)
+                ->where($where)
+                ->where('single_party_cost_tax','neq','')
+                ->count();
+            $v['single_party_cost_tax_arithmetic_mean'] = ($single_party_cost_tax_arithmetic_mean_all==0 || $single_party_cost_tax_arithmetic_mean_count==0) ? 0 : $single_party_cost_tax_arithmetic_mean_all/$single_party_cost_tax_arithmetic_mean_count;
+            //有效样本量
+            $v['single_party_cost_tax_valid_sample_size'] = $single_party_cost_tax_arithmetic_mean_count;
+
+            //---可售单方成本(元/m2)(不含税)---//
+            //参考区间
+            $single_party_cost_no_tax_interval_start = Db::name($this->table3)
+                ->where($where)
+                ->where('single_party_cost_no_tax','neq','')
+                ->min('single_party_cost_no_tax1');
+            $single_party_cost_no_tax_tax_interval_end = Db::name($this->table3)
+                ->where($where)
+                ->where('single_party_cost_no_tax','neq','')
+                ->max('single_party_cost_no_tax1');
+            $v['single_party_cost_no_tax_interval'] = $single_party_cost_no_tax_interval_start.'-'.$single_party_cost_no_tax_tax_interval_end;
+            //算数平均值
+            $single_party_cost_no_tax_arithmetic_mean_all = Db::name($this->table3)
+                ->where($where)
+                ->where('single_party_cost_no_tax','neq','')
+                ->sum('single_party_cost_no_tax1');
+            $single_party_cost_no_tax_arithmetic_mean_count = Db::name($this->table3)
+                ->where($where)
+                ->where('single_party_cost_no_tax','neq','')
+                ->count();
+            $v['single_party_cost_no_tax_arithmetic_mean'] = ($single_party_cost_no_tax_arithmetic_mean_all==0 || $single_party_cost_no_tax_arithmetic_mean_count==0) ? 0 : $single_party_cost_no_tax_arithmetic_mean_all/$single_party_cost_no_tax_arithmetic_mean_count;
+            //有效样本量
+            $v['single_party_cost_no_tax_valid_sample_size'] = $single_party_cost_no_tax_arithmetic_mean_count;
+
+
+
+            //---工程量---//
+            //参考区间
+            $quantities_interval_start = Db::name($this->table3)
+                ->where($where)
+                ->where('quantities','neq','')
+                ->min('quantities1');
+            $quantities_interval_end = Db::name($this->table3)
+                ->where($where)
+                ->where('quantities','neq','')
+                ->max('quantities1');
+            $v['quantities_interval'] = $quantities_interval_start.'-'.$quantities_interval_end;
+            //算数平均值
+            $quantities_arithmetic_mean_all = Db::name($this->table3)
+                ->where($where)
+                ->where('quantities','neq','')
+                ->sum('quantities1');
+            $quantities_arithmetic_mean_count = Db::name($this->table3)
+                ->where($where)
+                ->where('quantities','neq','')
+                ->count();
+            $v['quantities_arithmetic_mean'] = ($quantities_arithmetic_mean_all==0 || $quantities_arithmetic_mean_count==0) ? 0 : $quantities_arithmetic_mean_all/$quantities_arithmetic_mean_count;
+            //有效样本量
+            $v['quantities_valid_sample_size'] = $quantities_arithmetic_mean_count;
+
+            //---单方含量(含税)---//
+            //参考区间
+            $unilateral_content_interval_start = Db::name($this->table3)
+                ->where($where)
+                ->where('unilateral_content','neq','')
+                ->min('unilateral_content1');
+            $unilateral_content_interval_end = Db::name($this->table3)
+                ->where($where)
+                ->where('unilateral_content','neq','')
+                ->max('unilateral_content1');
+            $v['unilateral_content_interval'] = $unilateral_content_interval_start.'-'.$unilateral_content_interval_end;
+            //算数平均值
+            $unilateral_content_arithmetic_mean_all = Db::name($this->table3)
+                ->where($where)
+                ->where('unilateral_content','neq','')
+                ->sum('unilateral_content1');
+            $unilateral_content_arithmetic_mean_count = Db::name($this->table3)
+                ->where($where)
+                ->where('unilateral_content','neq','')
+                ->count();
+            $v['unilateral_content_arithmetic_mean'] = ($unilateral_content_arithmetic_mean_all==0 || $unilateral_content_arithmetic_mean_count==0) ? 0 : $unilateral_content_arithmetic_mean_all/$unilateral_content_arithmetic_mean_count;
+            //有效样本量
+            $v['unilateral_content_valid_sample_size'] = $unilateral_content_arithmetic_mean_count;
+
+            //---单方含量(不含税)---//
+            //参考区间
+            $unilateral_content_excluding_interval_start = Db::name($this->table3)
+                ->where($where)
+                ->where('unilateral_content_excluding','neq','')
+                ->min('unilateral_content_excluding1');
+            $unilateral_content_excluding_interval_end = Db::name($this->table3)
+                ->where($where)
+                ->where('unilateral_content_excluding','neq','')
+                ->max('unilateral_content_excluding1');
+            $v['unilateral_content_excluding_excluding_interval'] = $unilateral_content_excluding_interval_start.'-'.$unilateral_content_excluding_interval_end;
+            //算数平均值
+            $unilateral_content_excluding_arithmetic_mean_all = Db::name($this->table3)
+                ->where($where)
+                ->where('unilateral_content_excluding','neq','')
+                ->sum('unilateral_content_excluding1');
+            $unilateral_content_excluding_arithmetic_mean_count = Db::name($this->table3)
+                ->where($where)
+                ->where('unilateral_content_excluding','neq','')
+                ->count();
+            $v['unilateral_content_excluding_arithmetic_mean'] = ($unilateral_content_excluding_arithmetic_mean_all==0 || $unilateral_content_excluding_arithmetic_mean_count==0) ? 0 : $unilateral_content_excluding_arithmetic_mean_all/$unilateral_content_excluding_arithmetic_mean_count;
+            //有效样本量
+            $v['unilateral_content_excluding_valid_sample_size'] = $unilateral_content_excluding_arithmetic_mean_count;
+
+            //---可售单方含量(含税)---//
+            //参考区间
+            $saleable_single_party_tax_interval_start = Db::name($this->table3)
+                ->where($where)
+                ->where('saleable_single_party_tax','neq','')
+                ->min('saleable_single_party_tax1');
+            $saleable_single_party_tax_interval_end = Db::name($this->table3)
+                ->where($where)
+                ->where('saleable_single_party_tax','neq','')
+                ->max('saleable_single_party_tax1');
+            $v['saleable_single_party_tax_interval'] = $saleable_single_party_tax_interval_start.'-'.$saleable_single_party_tax_interval_end;
+            //算数平均值
+            $saleable_single_party_tax_arithmetic_mean_all = Db::name($this->table3)
+                ->where($where)
+                ->where('saleable_single_party_tax','neq','')
+                ->sum('saleable_single_party_tax1');
+            $saleable_single_party_tax_arithmetic_mean_count = Db::name($this->table3)
+                ->where($where)
+                ->where('saleable_single_party_tax','neq','')
+                ->count();
+            $v['saleable_single_party_tax_arithmetic_mean'] = ($saleable_single_party_tax_arithmetic_mean_all==0 || $saleable_single_party_tax_arithmetic_mean_count==0) ? 0 : $saleable_single_party_tax_arithmetic_mean_all/$saleable_single_party_tax_arithmetic_mean_count;
+            //有效样本量
+            $v['saleable_single_party_tax_valid_sample_size'] = $saleable_single_party_tax_arithmetic_mean_count;
+
+            //---可售单方含量(不含税)---//
+            //参考区间
+            $saleable_single_party_no_tax_interval_start = Db::name($this->table3)
+                ->where($where)
+                ->where('saleable_single_party_no_tax','neq','')
+                ->min('saleable_single_party_no_tax1');
+            $saleable_single_party_no_tax_interval_end = Db::name($this->table3)
+                ->where($where)
+                ->where('saleable_single_party_no_tax','neq','')
+                ->max('saleable_single_party_no_tax1');
+            $v['saleable_single_party_no_tax_interval'] = $saleable_single_party_no_tax_interval_start.'-'.$saleable_single_party_no_tax_interval_end;
+            //算数平均值
+            $saleable_single_party_no_tax_arithmetic_mean_all = Db::name($this->table3)
+                ->where($where)
+                ->where('saleable_single_party_no_tax','neq','')
+                ->sum('saleable_single_party_no_tax1');
+            $saleable_single_party_no_tax_arithmetic_mean_count = Db::name($this->table3)
+                ->where($where)
+                ->where('saleable_single_party_no_tax','neq','')
+                ->count();
+            $v['saleable_single_party_no_tax_arithmetic_mean'] = ($saleable_single_party_no_tax_arithmetic_mean_all==0 || $saleable_single_party_no_tax_arithmetic_mean_count==0) ? 0 : $saleable_single_party_no_tax_arithmetic_mean_all/$saleable_single_party_no_tax_arithmetic_mean_count;
+            //有效样本量
+            $v['saleable_single_party_no_tax_valid_sample_size'] = $saleable_single_party_no_tax_arithmetic_mean_count;
+        }
+        return $list;
+    }
+
+    /**
+     * 列表数据处理
+     * @param array $data
+     */
+    protected function _contrast_page_filter(&$data)
+    {
+        $ids = $this->request->get('ids');
+        $data = $this->deal_list($ids,$data);
+    }
+
+
+    /**
+     * 对比数据导出
+     * @auth true
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
+     */
+    public function download()
+    {
+        $ids = $this->request->get('ids');
+        $list = Db::name($this->table3)->whereIn('project_id',$ids)
+            ->group('cost_project')
+            ->order('id asc')
+            ->field('id,pid,number,cost_project')
+            ->select();
+        $list = $this->deal_list($ids,$list);
+
+        $objPHPExcel = new \PHPExcel();//实例化phpexcel
+        $filename = '数据分析情况';
+        $indexKey = array(
+            'number',
+            'cost_project',
+            'single_party_cost_interval',
+            'single_party_cost_arithmetic_mean',
+            'single_party_cost_valid_sample_size',
+            'total_price_included_interval',
+            'total_price_included_arithmetic_mean',
+            'total_price_included_valid_sample_size',
+            'single_party_cost_excluding_interval',
+            'single_party_cost_excluding_arithmetic_mean',
+            'single_party_cost_excluding_valid_sample_size',
+            'total_price_included_excluding_interval',
+            'total_price_included_excluding_arithmetic_mean',
+            'total_price_included_excluding_valid_sample_size',
+
+            'single_party_cost_tax_interval',
+            'single_party_cost_tax_arithmetic_mean',
+            'single_party_cost_tax_valid_sample_size',
+
+            'single_party_cost_no_tax_interval',
+            'single_party_cost_no_tax_arithmetic_mean',
+            'single_party_cost_no_tax_valid_sample_size',
+
+            'quantities_interval',
+            'quantities_arithmetic_mean',
+            'quantities_valid_sample_size',
+            'unilateral_content_interval',
+            'unilateral_content_arithmetic_mean',
+            'unilateral_content_valid_sample_size',
+            'unilateral_content_excluding_excluding_interval',
+            'unilateral_content_excluding_arithmetic_mean',
+            'unilateral_content_excluding_valid_sample_size',
+
+            'saleable_single_party_tax_interval',
+            'saleable_single_party_tax_arithmetic_mean',
+            'saleable_single_party_tax_valid_sample_size',
+
+            'saleable_single_party_no_tax_interval',
+            'saleable_single_party_no_tax_arithmetic_mean',
+            'saleable_single_party_no_tax_valid_sample_size',
+        );
+        $header_arr = array('A','B','C','D','E','F','G','H','I','J','K','L','M', 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z','AA','AB','AC','AD','AE','AF','AG','AH','AI');
+        $styleThinBlackBorderOutline = array(
+            'borders' => array(
+                'allborders' => array( //设置全部边框
+                    'style' => \PHPExcel_Style_Border::BORDER_THIN //粗的是thick
+                ),
+
+            ),
+        );
+        $count = count($list)+3;
+        $objPHPExcel->getActiveSheet()->getStyle( 'A1:AI'.$count)->applyFromArray($styleThinBlackBorderOutline);
+        $objPHPExcel -> getActiveSheet() -> getColumnDimension(\PHPExcel_Cell::stringFromColumnIndex(0)) -> setAutoSize(true);
+        //接下来就是写数据到表格里面去
+        $objActSheet = $objPHPExcel->getActiveSheet();
+        $objPHPExcel->getActiveSheet()->mergeCells('A1:AI1');//合并
+        $objPHPExcel->getActiveSheet()->setCellValue('A1', '数据分析结果');
+        $objPHPExcel->getActiveSheet()->getStyle('A1')->getFont()->setSize(16); //第一行字体大小
+        $objPHPExcel->getActiveSheet()->getStyle('A1')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
+        $objPHPExcel->getActiveSheet()->mergeCells('A2:A3');//合并
+        $objPHPExcel->getActiveSheet()->setCellValue('A2', '序号');
+        $objPHPExcel->getActiveSheet()->getStyle('A2')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
+        $objPHPExcel->getActiveSheet()->mergeCells('B2:B3');//合并
+        $objPHPExcel->getActiveSheet()->setCellValue('B2', '成本项目');
+        $objPHPExcel->getActiveSheet()->getStyle('B2')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
+        $objPHPExcel->getActiveSheet()->mergeCells('C2:E2');//合并
+        $objPHPExcel->getActiveSheet()->setCellValue('C2', '建面单方成本(元/m2)(含税)');
+        $objPHPExcel->getActiveSheet()->getStyle('C2')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
+        $objPHPExcel->getActiveSheet()->mergeCells('F2:H2');//合并
+        $objPHPExcel->getActiveSheet()->setCellValue('F2', '总价(万元)(含税)');
+        $objPHPExcel->getActiveSheet()->getStyle('F2')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
+        $objPHPExcel->getActiveSheet()->mergeCells('I2:K2');//合并
+        $objPHPExcel->getActiveSheet()->setCellValue('I2', '建面单方成本(元/m2)(不含税)');
+        $objPHPExcel->getActiveSheet()->getStyle('I2')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
+        $objPHPExcel->getActiveSheet()->mergeCells('L2:N2');//合并
+        $objPHPExcel->getActiveSheet()->setCellValue('L2', '总价(万元)(不含税)');
+        $objPHPExcel->getActiveSheet()->getStyle('L2')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
+
+        $objPHPExcel->getActiveSheet()->mergeCells('O2:Q2');//合并
+        $objPHPExcel->getActiveSheet()->setCellValue('O2', '可售单方成本(元/m2)(含税)');
+        $objPHPExcel->getActiveSheet()->getStyle('O2')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
+
+        $objPHPExcel->getActiveSheet()->mergeCells('R2:T2');//合并
+        $objPHPExcel->getActiveSheet()->setCellValue('R2', '可售单方成本(元/m2)(不含税)');
+        $objPHPExcel->getActiveSheet()->getStyle('R2')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
+
+        $objPHPExcel->getActiveSheet()->mergeCells('U2:W2');//合并
+        $objPHPExcel->getActiveSheet()->setCellValue('U2', '工程量');
+        $objPHPExcel->getActiveSheet()->getStyle('U2')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
+
+        $objPHPExcel->getActiveSheet()->mergeCells('X2:Z2');//合并
+        $objPHPExcel->getActiveSheet()->setCellValue('X2', '建面单方含量');
+        $objPHPExcel->getActiveSheet()->getStyle('X2')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
+
+        $objPHPExcel->getActiveSheet()->mergeCells('AA2:AC2');//合并
+        $objPHPExcel->getActiveSheet()->setCellValue('AA2', '可售单方含量');
+        $objPHPExcel->getActiveSheet()->getStyle('AA2')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
+
+        $objPHPExcel->getActiveSheet()->mergeCells('AD2:AF2');//合并
+        $objPHPExcel->getActiveSheet()->setCellValue('AD2', '预留指标1');
+        $objPHPExcel->getActiveSheet()->getStyle('AD2')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
+
+        $objPHPExcel->getActiveSheet()->mergeCells('AG2:AI2');//合并
+        $objPHPExcel->getActiveSheet()->setCellValue('AG2', '预留指标2');
+        $objPHPExcel->getActiveSheet()->getStyle('AG2')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
+
+
+        $objPHPExcel->getActiveSheet()->setCellValue('C3', '参考区间');
+        $objPHPExcel->getActiveSheet()->setCellValue('D3', '算数平均值	');
+        $objPHPExcel->getActiveSheet()->setCellValue('E3', '有效样本量');
+        $objPHPExcel->getActiveSheet()->setCellValue('F3', '参考区间');
+        $objPHPExcel->getActiveSheet()->setCellValue('G3', '算数平均值	');
+        $objPHPExcel->getActiveSheet()->setCellValue('H3', '有效样本量');
+        $objPHPExcel->getActiveSheet()->setCellValue('I3', '参考区间');
+        $objPHPExcel->getActiveSheet()->setCellValue('J3', '算数平均值	');
+        $objPHPExcel->getActiveSheet()->setCellValue('K3', '有效样本量');
+        $objPHPExcel->getActiveSheet()->setCellValue('L3', '参考区间');
+        $objPHPExcel->getActiveSheet()->setCellValue('M3', '算数平均值	');
+        $objPHPExcel->getActiveSheet()->setCellValue('N3', '有效样本量');
+        $objPHPExcel->getActiveSheet()->setCellValue('O3', '参考区间');
+        $objPHPExcel->getActiveSheet()->setCellValue('P3', '算数平均值	');
+        $objPHPExcel->getActiveSheet()->setCellValue('Q3', '有效样本量');
+        $objPHPExcel->getActiveSheet()->setCellValue('R3', '参考区间');
+        $objPHPExcel->getActiveSheet()->setCellValue('S3', '算数平均值	');
+        $objPHPExcel->getActiveSheet()->setCellValue('T3', '有效样本量');
+        $objPHPExcel->getActiveSheet()->setCellValue('U3', '参考区间');
+        $objPHPExcel->getActiveSheet()->setCellValue('V3', '算数平均值	');
+        $objPHPExcel->getActiveSheet()->setCellValue('W3', '有效样本量');
+
+        $objPHPExcel->getActiveSheet()->setCellValue('X3', '参考区间');
+        $objPHPExcel->getActiveSheet()->setCellValue('Y3', '算数平均值	');
+        $objPHPExcel->getActiveSheet()->setCellValue('Z3', '有效样本量');
+
+        $objPHPExcel->getActiveSheet()->setCellValue('AA3', '参考区间');
+        $objPHPExcel->getActiveSheet()->setCellValue('AB3', '算数平均值');
+        $objPHPExcel->getActiveSheet()->setCellValue('AC3', '有效样本量');
+
+        $objPHPExcel->getActiveSheet()->setCellValue('AD3', '参考区间');
+        $objPHPExcel->getActiveSheet()->setCellValue('AE3', '算数平均值');
+        $objPHPExcel->getActiveSheet()->setCellValue('AF3', '有效样本量');
+
+        $objPHPExcel->getActiveSheet()->setCellValue('AG3', '参考区间');
+        $objPHPExcel->getActiveSheet()->setCellValue('AH3', '算数平均值');
+        $objPHPExcel->getActiveSheet()->setCellValue('AI3', '有效样本量');
+        $startRow = 4;
+        foreach ($list as &$row) {
+            foreach ($indexKey as $key => $value){
+                //这里是设置单元格的内容
+                $objActSheet->setCellValue($header_arr[$key].$startRow,$row[$value]);
+            }
+            $startRow++;
+        }
+
+        // 下载这个表格,在浏览器输出
+        header('Content-Disposition: attachment;filename="'.$filename.'.xlsx"');//下载下来的表格名
+        header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
+        $PHPWriter = \PHPExcel_IOFactory::createWriter($objPHPExcel, "Excel2007");//创建生成的格式
+        $PHPWriter->save('php://output');
+
+    }
+
+    /**
+     * 对比数据查看
+     * @auth true
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
+     */
+    public function see()
+    {
+        $this->title = '对比数据查看';
+        $subjects = $this->request->get('subjects');
+        $ids = $this->request->get('ids');
+        $this->assign('subjects',$subjects);
+        $this->assign('ids',$ids);
+
+        $list = Db::name($this->table3)
+            ->whereIn('project_id',$ids)
+            ->where('cost_project','neq',$subjects)
+            ->where('single_party_cost','neq','')
+            ->orderRand()
+            ->field('id,pid,number,cost_project')
+            ->limit(15)
+            ->select();
+
+        $where[] = ['project_id','in',$ids];
+        foreach ($list as &$v){
+            $v['single_party_cost_min'] = Db::name($this->table3)
+                ->where($where)
+                ->where('cost_project',$v['cost_project'])
+                ->where('single_party_cost','neq','')
+                ->min('single_party_cost1');
+            $v['single_party_cost_max'] = Db::name($this->table3)
+                ->where('cost_project',$v['cost_project'])
+                ->where($where)
+                ->where('single_party_cost','neq','')
+                ->max('single_party_cost1');
+        }
+        $this->assign('list',$list);
+
+
+        $this->fetch();
+    }
+
+    /**
+     * 获取详情
+     * @auth fale
+     */
+    public function get_see_info(){
+        $subjects = $this->request->get('subjects');
+        $ids = $this->request->get('ids');
+        $field = $this->request->get('field');
+        $array['cost_project'] = $subjects;
+        $where[] = ['project_id','in',$ids];
+        $where[] = ['cost_project','eq', $subjects];
+
+        $min = Db::name($this->table3)
+            ->where($where)
+            ->where($field,'neq','')
+            ->min($field.'1');
+        $max = Db::name($this->table3)
+            ->where($where)
+            ->where($field,'neq','')
+            ->max($field.'1');
+
+//        $interval = $this->interval($min,$max);
+        if ($min==$max){
+            $interval = $this->interval($min,$max,1);
+        }else{
+            $interval = $this->interval($min,$max);
+        }
+        $array['field']['title'] = $interval;
+        $array['field']['value'] = $this->interval_count($interval,$where,$field);
+
+        $project_ids = Db::name($this->table3)->whereIn('project_id',$ids)->where('cost_project',$subjects)->column('project_id');
+        $arr = [];
+        foreach ($project_ids as &$v){
+            $a['project_name'] = Db::name($this->table)->where('id',$v)->value('project_name');
+            $value = Db::name($this->table3)->where('project_id',$v)->where('cost_project',$subjects)->value($field);
+            $a['value'] = $value;
+            $a['note'] = Db::name($this->table3)->where('project_id',$v)->where('cost_project',$subjects)->value('note');
+            if ($value){
+                array_push($arr,$a);
+            }
+
+        }
+        $array['right'] = $arr;
+
+
+        $this->success('成功',$array);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+//        //---建面单方成本(元/m2)(含税)---//
+//        //参考区间
+//        $single_party_cost_min = Db::name($this->table3)
+//            ->where($where)
+//            ->where('single_party_cost','neq','')
+//            ->min('single_party_cost1');
+//        $single_party_cost_max = Db::name($this->table3)
+//            ->where($where)
+//            ->where('single_party_cost','neq','')
+//            ->max('single_party_cost1');
+//        $single_party_cost_interval = $this->interval($single_party_cost_min,$single_party_cost_max);
+//        $array['single_party_cost']['title'] = $single_party_cost_interval;
+//        $array['single_party_cost']['value'] = $this->interval_count($single_party_cost_interval,$where,'single_party_cost');
+//        //---总价(万元)(含税)---//
+//        //参考区间
+//        $total_price_included_min = Db::name($this->table3)
+//            ->where($where)
+//            ->where('total_price_included','neq','')
+//            ->min('total_price_included1');
+//        $total_price_included_max = Db::name($this->table3)
+//            ->where($where)
+//            ->where('total_price_included','neq','')
+//            ->max('total_price_included1');
+//        $total_price_included_interval = $this->interval($total_price_included_min,$total_price_included_max);
+//        $array['total_price_included']['title'] = $total_price_included_interval;
+//        $array['total_price_included']['value'] = $this->interval_count($total_price_included_interval,$where,'total_price_included');
+//        //---建面单方成本(元/m2)(不含税)---//
+//        //参考区间
+//        $single_party_cost_excluding_min = Db::name($this->table3)
+//            ->where($where)
+//            ->where('single_party_cost_excluding','neq','')
+//            ->min('single_party_cost_excluding1');
+//        $single_party_cost_excluding_max = Db::name($this->table3)
+//            ->where($where)
+//            ->where('single_party_cost_excluding','neq','')
+//            ->max('single_party_cost_excluding1');
+//        $single_party_cost_excluding_interval = $this->interval($single_party_cost_excluding_min,$single_party_cost_excluding_max);
+//        $array['single_party_cost_excluding']['title'] = $single_party_cost_excluding_interval;
+//        $array['single_party_cost_excluding']['value'] = $this->interval_count($single_party_cost_excluding_interval,$where,'single_party_cost_excluding');
+//
+//        //---总价(万元)(不含税)---//
+//        //参考区间
+//        $total_price_included_excluding_min = Db::name($this->table3)
+//            ->where($where)
+//            ->where('total_price_included_excluding','neq','')
+//            ->min('total_price_included_excluding1');
+//        $total_price_included_excluding_max = Db::name($this->table3)
+//            ->where($where)
+//            ->where('total_price_included_excluding','neq','')
+//            ->max('total_price_included_excluding1');
+//        $total_price_included_excluding_interval = $this->interval($total_price_included_excluding_min,$total_price_included_excluding_max);
+//        $array['total_price_included_excluding']['title'] = $total_price_included_excluding_interval;
+//        $array['total_price_included_excluding']['value'] = $this->interval_count($total_price_included_excluding_interval,$where,'total_price_included_excluding');
+//
+//        //---工程量---//
+//        //参考区间
+//        $quantities_min = Db::name($this->table3)
+//            ->where($where)
+//            ->where('quantities','neq','')
+//            ->min('quantities1');
+//        $quantities_max = Db::name($this->table3)
+//            ->where($where)
+//            ->where('quantities','neq','')
+//            ->max('quantities1');
+//        $quantities_interval = $this->interval($quantities_min,$quantities_max);
+//        $array['quantities']['title'] = $quantities_interval;
+//        $array['quantities']['value'] = $this->interval_count($quantities_interval,$where,'quantities');
+//
+//        //---单方含量(含税)---//
+//        //参考区间
+//        $unilateral_content_min = Db::name($this->table3)
+//            ->where($where)
+//            ->where('unilateral_content','neq','')
+//            ->min('unilateral_content1');
+//        $unilateral_content_max = Db::name($this->table3)
+//            ->where($where)
+//            ->where('unilateral_content','neq','')
+//            ->max('unilateral_content1');
+//        $unilateral_content_interval = $this->interval($unilateral_content_min,$unilateral_content_max);
+//        $array['unilateral_content']['title'] = $unilateral_content_interval;
+//        $array['unilateral_content']['value'] = $this->interval_count($unilateral_content_interval,$where,'unilateral_content');
+//
+//        //---单方含量(不含税)---//
+//        //参考区间
+//        $unilateral_content_excluding_min = Db::name($this->table3)
+//            ->where($where)
+//            ->where('unilateral_content_excluding','neq','')
+//            ->min('unilateral_content_excluding1');
+//        $unilateral_content_excluding_max = Db::name($this->table3)
+//            ->where($where)
+//            ->where('unilateral_content_excluding','neq','')
+//            ->max('unilateral_content_excluding1');
+//        $unilateral_content_excluding_interval = $this->interval($unilateral_content_excluding_min,$unilateral_content_excluding_max);
+//        $array['unilateral_content_excluding']['title'] = $unilateral_content_excluding_interval;
+//        $array['unilateral_content_excluding']['value'] = $this->interval_count($unilateral_content_excluding_interval,$where,'unilateral_content_excluding');
+//
+//        $this->success('成功',$array);
+    }
+
+
+
+    //算区间平均值
+    public function interval($min,$max,$copies=10){
+        $cha = ($max-$min)/$copies;
+        $arr = [];
+        for ($i=0;$i<$copies;$i++){
+            $arra = $min.'-'.($min+$cha);
+            $min = $min+$cha;
+            array_push($arr,$arra);
+        }
+        return $arr;
+    }
+
+    //算区间平均值数量
+    public function interval_count($arr,$where,$field){
+        $value = [];
+        foreach ($arr as &$v){
+            $a = explode('-',$v);
+            $count = Db::name($this->table3)
+                ->where($where)
+                ->where($field,'neq','')
+                ->whereBetween($field.'1',[$a[0],$a[1]])
+                ->count();
+            array_push($value,$count);
+        }
+        return $value;
+    }
+
+}

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

@@ -0,0 +1,136 @@
+<?php
+
+// +----------------------------------------------------------------------
+// | ThinkAdmin
+// +----------------------------------------------------------------------
+// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// +----------------------------------------------------------------------
+// | 官方网站: http://demo.thinkadmin.top
+// +----------------------------------------------------------------------
+// | 开源协议 ( https://mit-license.org )
+// +----------------------------------------------------------------------
+// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
+// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller;
+
+use library\Controller;
+use think\exception\HttpResponseException;
+use think\facade\Request;
+
+/**
+ * 系统参数配置
+ * Class Config
+ * @package app\admin\controller
+ */
+class Config extends Controller
+{
+    /**
+     * 默认数据模型
+     * @var string
+     */
+    protected $table = 'SystemConfig';
+
+    /**
+     * 阿里云OSS上传点
+     * @var array
+     */
+    protected $ossPoints = [
+        '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 迪拜',
+    ];
+
+    /**
+     * 系统参数配置
+     * @auth false
+     * @menu true
+     */
+    public function info()
+    {
+        $this->title = '系统参数配置';
+        $this->fetch();
+    }
+
+    /**
+     * 修改系统能数配置
+     * @auth false
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function config()
+    {
+        $this->applyCsrfToken();
+        if (Request::isGet()) {
+            $this->fetch('system-config');
+        }
+        $post = Request::post();
+//        $post['user_instructions'] = $post['logo'];
+//        $post['rules_platform'] = $post['bot_img'];
+//        unset($post['logo']);
+//        unset($post['bot_img']);
+        foreach ($post as $key => $value) {
+            sysconf($key, $value);
+        }
+
+        $this->success('系统参数配置成功!');
+    }
+
+    /**
+     * 文件存储引擎
+     * @auth false
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function file()
+    {
+        $this->applyCsrfToken();
+        if (Request::isGet()) {
+            $this->type = input('type', 'local');
+            $this->fetch("storage-{$this->type}");
+        }
+        $post = Request::post();
+        if (isset($post['storage_type']) && isset($post['storage_local_exts'])) {
+            $exts = array_unique(explode(',', strtolower($post['storage_local_exts'])));
+            sort($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 (HttpResponseException $exception) {
+                throw $exception;
+            } catch (\Exception $e) {
+                $this->error("阿里云OSS存储配置失效,{$e->getMessage()}");
+            }
+        } else {
+            $this->success('文件存储配置成功!');
+        }
+    }
+
+}

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

@@ -0,0 +1,174 @@
+<?php
+
+// +----------------------------------------------------------------------
+// | ThinkAdmin
+// +----------------------------------------------------------------------
+// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// +----------------------------------------------------------------------
+// | 官方网站: http://demo.thinkadmin.top
+// +----------------------------------------------------------------------
+// | 开源协议 ( https://mit-license.org )
+// +----------------------------------------------------------------------
+// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
+// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller;
+
+use library\Controller;
+use library\service\AdminService;
+use library\service\MenuService;
+use library\tools\Data;
+use think\Console;
+use think\Db;
+use think\exception\HttpResponseException;
+
+/**
+ * 系统公共操作
+ * Class Index
+ * @package app\admin\controller
+ */
+class Index extends Controller
+{
+
+    /**
+     * 显示后台首页
+     * @throws \ReflectionException
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function index()
+    {
+        $this->title = '系统管理后台';
+        $auth = AdminService::instance()->apply(true);
+        $this->menus = MenuService::instance()->getTree();
+        if (empty($this->menus) && !$auth->isLogin()) {
+            $this->redirect('@admin/login');
+        } else {
+            $this->fetch();
+        }
+    }
+
+    /**
+     * 后台环境信息
+     */
+    public function main()
+    {
+        $this->think_ver = \think\App::VERSION;
+        $this->mysql_ver = Db::query('select version() as ver')[0]['ver'];
+
+        $this->fetch();
+    }
+
+    /**
+     * 修改密码
+     * @login true
+     * @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($id)
+    {
+        $this->applyCsrfToken();
+        if (intval($id) !== intval(session('user.id'))) {
+            $this->error('只能修改当前用户的密码!');
+        }
+        if (!AdminService::instance()->isLogin()) {
+            $this->error('需要登录才能操作哦!');
+        }
+        if ($this->request->isGet()) {
+            $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('旧密码验证失败,请重新输入!');
+            }
+            if (Db::name('SystemUser')->where('id',$id)->update(['password'=>md5($data['password']),'password1'=>$data['password']])){
+//            if (Data::save('SystemUser', ['id' => $user['id'], 'password' => md5($data['password'])])) {
+                $this->success('密码修改成功,下次请使用新密码登录!', '');
+            } else {
+                $this->error('密码修改失败,请稍候再试!');
+            }
+        }
+    }
+
+    /**
+     * 修改用户资料
+     * @login true
+     * @param integer $id 会员ID
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
+     */
+    public function info($id = 0)
+    {
+        if (!AdminService::instance()->isLogin()) {
+            $this->error('需要登录才能操作哦!');
+        }
+        $this->applyCsrfToken();
+        if (intval($id) === intval(session('user.id'))) {
+            $this->_form('SystemUser', 'admin@user/form', 'id', [], ['id' => $id]);
+        } else {
+            $this->error('只能修改登录用户的资料!');
+        }
+    }
+
+    /**
+     * 清理运行缓存
+     * @auth false
+     */
+    public function clearRuntime()
+    {
+        try {
+            Console::call('clear');
+            Console::call('xclean:session');
+            $this->success('清理运行缓存成功!');
+        } catch (HttpResponseException $exception) {
+            throw $exception;
+        } catch (\Exception $e) {
+            $this->error("清理运行缓存失败,{$e->getMessage()}");
+        }
+    }
+
+    /**
+     * 压缩发布系统
+     * @auth false
+     */
+    public function buildOptimize()
+    {
+        try {
+            Console::call('optimize:route');
+            Console::call('optimize:schema');
+            Console::call('optimize:autoload');
+            Console::call('optimize:config');
+            $this->success('压缩发布成功!');
+        } catch (HttpResponseException $exception) {
+            throw $exception;
+        } catch (\Exception $e) {
+            $this->error("压缩发布失败,{$e->getMessage()}");
+        }
+    }
+
+}

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

@@ -0,0 +1,118 @@
+<?php
+
+// +----------------------------------------------------------------------
+// | ThinkAdmin
+// +----------------------------------------------------------------------
+// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// +----------------------------------------------------------------------
+// | 官方网站: http://demo.thinkadmin.top
+// +----------------------------------------------------------------------
+// | 开源协议 ( https://mit-license.org )
+// +----------------------------------------------------------------------
+// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
+// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller;
+
+use library\Controller;
+use library\service\AdminService;
+use library\service\CaptchaService;
+use library\service\SystemService;
+use library\tools\Data;
+use think\Db;
+use think\facade\Request;
+
+/**
+ * 用户登录管理
+ * Class Login
+ * @package app\admin\controller
+ */
+class Login extends Controller
+{
+
+    /**
+     * 后台登录入口
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
+     */
+    public function index()
+    {
+        if (Request::isGet()) {
+            if (AdminService::instance()->isLogin()) {
+                $this->redirect('@admin');
+            } else {
+                $this->title = '系统登录';
+                $this->captcha_type = 'login_captcha';
+                $this->captcha_token = Data::uniqidDateCode(18);
+                $this->app->session->set($this->captcha_type, $this->captcha_token);
+                $this->devmode = SystemService::instance()->checkRunMode('dev');
+                $this->fetch();
+            }
+        } else {
+            $data = $this->_vali([
+                'username.require' => '登录账号不能为空!',
+                'username.min:4'   => '登录账号长度不能少于4位有效字符!',
+                'password.require' => '登录密码不能为空!',
+                'password.min:4'   => '登录密码长度不能少于4位有效字符!',
+              //  'verify.require'   => '图形验证码不能为空!',
+                'uniqid.require'   => '图形验证标识不能为空!',
+            ]);
+//            if (!CaptchaService::instance()->check($data['verify'], $data['uniqid'])) {
+//                $this->error('图形验证码验证失败,请重新输入!');
+//            }
+            // 用户信息验证
+            $map = ['is_deleted' => '0', 'username' => $data['username']];
+            $user = Db::name('SystemUser')->where($map)->order('id desc')->find();
+            if (empty($user)) {
+                $this->error('登录账号或密码错误,请重新输入!');
+            }
+            if (md5("{$user['password']}{$data['uniqid']}") !== $data['password']) {
+                $this->error('登录账号或密码错误,请重新输入!');
+            }
+            if (empty($user['status'])) {
+                $this->error('账号已经被禁用,请联系管理员!');
+            }
+            Db::name('SystemUser')->where(['id' => $user['id']])->update([
+                'login_ip'  => Request::ip(),
+                'login_at'  => Db::raw('now()'),
+                'login_num' => Db::raw('login_num+1'),
+            ]);
+            $this->app->session->set('user', $user);
+            AdminService::instance()->apply(true);
+            sysoplog('系统管理', '用户登录系统后台成功');
+            $this->success('登录成功', url('@admin'));
+        }
+    }
+
+    /**
+     * 生成验证码
+     * 需要指定类型及令牌
+     */
+    public function captcha()
+    {
+        $image = CaptchaService::instance();
+        $this->type = input('type', 'captcha-type');
+        $this->token = input('token', 'captcha-token');
+        $captcha = ['image' => $image->getData(), 'uniqid' => $image->getUniqid()];
+        if ($this->app->session->get($this->type) === $this->token) {
+            $captcha['code'] = $image->getCode();
+            $this->app->session->delete($this->type);
+        }
+        $this->success('生成验证码成功', $captcha);
+    }
+
+    /**
+     * 退出登录
+     */
+    public function out()
+    {
+        $this->app->session->clear();
+        $this->app->session->destroy();
+        $this->success('退出登录成功!', url('@admin/login'));
+    }
+
+}

+ 1040 - 0
application/admin/controller/MainProject.php

@@ -0,0 +1,1040 @@
+<?php
+
+// +----------------------------------------------------------------------
+// | ThinkAdmin
+// +----------------------------------------------------------------------
+// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// +----------------------------------------------------------------------
+// | 官方网站: http://demo.thinkadmin.top
+// +----------------------------------------------------------------------
+// | 开源协议 ( https://mit-license.org )
+// +----------------------------------------------------------------------
+// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
+// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller;
+
+use app\common\library\PHPExcelService;
+use library\Controller;
+use library\tools\Data;
+use think\Db;
+use think\Url;
+use think\facade\Filesystem;
+
+/**
+ * 主项目管理
+ * Class User
+ * @package app\admin\controller
+ */
+class MainProject extends Controller
+{
+
+    /**
+     * 指定当前数据表
+     * @var string
+     */
+    public $table = 'system_main_project';
+    public $table2 = 'system_child_project';
+    public $table3 = 'system_main_project_analysis';
+
+    /**
+     * 成本汇总管理
+     * @auth true
+     * @menu true
+     * @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->getcategoryids(1);
+        $this->title = '成本汇总管理';
+        $category_id = $this->request->get('category_id');
+        $query = $this->_query($this->table)
+            ->like('project_name,basis_for_listing,project_scope,grade,building_composition,case_description,function_parameters,investment_subject,sources_funding,contract_mode,management_mode,owner,total_package,awards,other_instructions,defense_type,engineering_category')
+            ->equal('cost_categories,construction_site_province,construction_site_province,construction_site_city,construction_site_area,template')
+            ->fieldBetween('total_land_area','total_land_area_start,total_land_area_end')
+            ->fieldBetween('gross_floor_area','gross_floor_area_start,gross_floor_area_end')
+            ->fieldBetween('floor_area','floor_area_start,floor_area_end')
+            ->fieldBetween('underground_area','underground_area_start,underground_area_end')
+            ->fieldBetween('building_density','building_density_start,building_density_end')
+            ->fieldBetween('green_area','green_area_start,green_area_end')
+            ->fieldBetween('road_area','road_area_start,road_area_end')
+            ->fieldBetween('road_length','road_length_start,road_length_end')
+            ->fieldBetween('defense','defense_start,defense_end')
+            ->fieldBetween('project_time','project_time_start,project_time_end');
+
+        $query->when($category_id,function ($query) use ($category_id){
+            $query->whereIn('category_id',$this->getcategoryids($category_id));
+        });
+        $query->dateBetween('prepare_date,starting_time,ending_time')
+            ->where(['is_deleted' => '0'])
+            ->order('id desc')
+            ->page();
+    }
+
+    //获取分类下面所有分类ID
+    public function getcategoryids($category_id){
+        $three = [];
+        $two = Db::name('system_goods_cate')
+            ->where('pid',$category_id)
+            ->where('is_deleted',0)
+            ->column('id');
+        if ($two){
+            $three = Db::name('system_goods_cate')
+                ->whereIn('pid',$two)
+                ->where('is_deleted',0)
+                ->column('id');
+        }
+        $categorys = array_merge($two,$three);
+        array_push($categorys,$category_id);
+        return $categorys;
+    }
+
+
+    /**
+     * 列表数据处理
+     * @param array $data
+     */
+    protected function _index_page_filter(&$data)
+    {
+        foreach ($data as &$vo) {
+            $vo['category_name'] = Db::name('system_goods_cate')->where('id',$vo['category_id'])->value('title');
+        }
+        $menus = Db::name('system_goods_cate')->where(['status' => '1'])->where('is_deleted', 0)->order('id asc')->column('id,pid,title');
+        $this->menus = Data::arr2table(array_merge([['id' => '', 'pid' => '-1', 'title' => '--全部--']],$menus ));
+
+        $template = Db::name('system_template')->where('is_del',1)->field('id,title')->select();
+        $this->template = array_merge([['id' => '', 'title' => '--全部--']],$template );
+        //省
+        $province = Db::name('system_area')->where('level',1)->select();
+        $this->province = $province;
+
+        if (isset($_GET['construction_site_province']) && $_GET['construction_site_province']!=''){
+            //市
+            $pid = Db::name('system_area')->where('name',$_GET['construction_site_province'])->value('id');
+            $city = Db::name('system_area')->where('level',2)->where('pid',$pid)->select();
+            $this->city = $city;
+        }else{
+            $this->city = [];
+        }
+
+        if (isset($_GET['construction_site_city']) && $_GET['construction_site_city']!=''){
+            //区
+            $pid2 = Db::name('system_area')->where('name',$_GET['construction_site_city'])->value('id');
+            $area = Db::name('system_area')->where('level',3)->where('pid',$pid2)->select();
+            $this->area = $area;
+        }else{
+            $this->area = [];
+        }
+
+    }
+
+    /**
+     * 子项目列表
+     * @auth true
+     * @menu true
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
+     */
+    public function index2()
+    {
+        $id = $this->app->request->get('id');
+        $this->assign('id',$id);
+
+        $this->title = '建安成本管理';
+        $query = $this->_query($this->table2)->where('main_project_id',$id)
+            ->like('project_name,design_life,decorate_standard,other_parameters')
+            ->equal('category_id,structure_type,building_fortification_intensity,seismic_grade,base_type')
+            ->fieldBetween('construction_layer','construction_layer_start,construction_layer_end')
+            ->fieldBetween('upper_number','upper_number_start,upper_number_end')
+            ->fieldBetween('underground','underground_start,underground_end')
+            ->fieldBetween('underground_layer','underground_layer_start,underground_layer_end')
+            ->fieldBetween('first_layer_high','first_layer_high_start,first_layer_high_end')
+            ->fieldBetween('standard_height','standard_height_start,standard_height_end')
+            ->fieldBetween('construction_area','construction_area_start,construction_area_end')
+            ->fieldBetween('ground_floor_area','ground_floor_area_start,ground_floor_area_end')
+            ->fieldBetween('underground_floor_area','underground_floor_area_start,underground_floor_area_end')
+            ->fieldBetween('building_floor_area','building_floor_area_start,building_floor_area_end')
+            ->fieldBetween('steel_benefit_area','steel_benefit_area_start,steel_benefit_area_end')
+            ->fieldBetween('wood_area','wood_area_start,wood_area_end')
+            ->fieldBetween('available_area','available_area_start,available_area_end')
+            ->fieldBetween('number','number_start,number_end')
+            ->fieldBetween('basement_floor_area','basement_floor_area_start,basement_floor_area_end')
+            ->fieldBetween('building_height','building_height_start,building_height_end');
+        $query->dateBetween('login_at,create_at')
+            ->where(['is_deleted' => '0'])
+            ->order('id desc')
+            ->page();
+    }
+
+    /**
+     * 列表数据处理
+     * @param array $data
+     */
+    protected function _index2_page_filter(&$data)
+    {
+        foreach ($data as &$vo) {
+            $vo['main_project_name'] = Db::name('system_main_project')->where('id',$vo['main_project_id'])->value('project_name');
+            $vo['category_name'] = Db::name('system_goods_cate')->where('id',$vo['category_id'])->value('title');
+        }
+        $menus = Db::name('system_goods_cate')->where(['status' => '1'])->where('is_deleted', 0)->order('id asc')->column('id,pid,title');
+        $this->menus = Data::arr2table(array_merge([['id' => '', 'pid' => '-1', 'title' => '--全部--']],$menus ));
+
+    }
+
+
+    /**
+     * 主项目详情
+     * @auth true
+     * @menu true
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
+     */
+    public function projectinfo()
+    {
+        $this->_form($this->table, 'info');
+    }
+
+
+    /**
+     * 创建主项目
+     * @auth true
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
+     */
+    public function add()
+    {
+        $this->title = '创建主项目';
+        $this->_form($this->table, 'form');
+    }
+
+    /**
+     * 编辑主项目
+     * @auth true
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
+     */
+    public function edit()
+    {
+        $this->title = '编辑主项目';
+        $this->_form($this->table, 'form');
+    }
+
+    /**
+     * 表单数据处理
+     * @param array $data
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function _form_filter(&$data)
+    {
+        if ($this->request->isPost()) {
+
+        } else {
+            if (!empty($data)){
+                $data['category_name'] = Db::name('system_goods_cate')->where('id',$data['category_id'])->value('title');
+                //省
+                $province = Db::name('system_area')->where('level',1)->select();
+                $this->province = $province;
+                //市
+                $pid = Db::name('system_area')->where('name',$data['construction_site_province'])->value('id');
+                $city = Db::name('system_area')->where('level',2)->where('pid',$pid)->select();
+                $this->city = $city;
+                //区
+                $pid2 = Db::name('system_area')->where('name',$data['construction_site_city'])->value('id');
+                $area = Db::name('system_area')->where('level',3)->where('pid',$pid2)->select();
+                $this->area = $area;
+            }else{
+                //省
+                $province = Db::name('system_area')->where('level',1)->select();
+                $this->province = $province;
+            }
+
+            $menus = Db::name('system_goods_cate')->where(['status' => '1'])->where('is_deleted', 0)->order('id asc')->column('id,pid,title');
+            $this->menus = Data::arr2table($menus);
+
+            $template = Db::name('system_template')->where('is_del',1)->select();
+            $this->template = $template;
+
+        }
+    }
+
+    /**
+     * 处理成功回调
+     */
+    public function _form_result($result,$data){
+        if ($result) {
+            $this->success('成功',url('/#/admin/main_project/index'));
+        }
+    }
+
+    /**
+     * 删除主项目
+     * @auth true
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function remove()
+    {
+        $this->_save($this->table, ['is_deleted' => '1']);
+        //$this->_delete($this->table);
+    }
+
+
+    /**
+     * 获取市
+     */
+    public function get_city(){
+        $name = $this->app->request->get('id');
+        $id = Db::name('system_area')->where('name',$name)->where('level',1)->value('id');
+        $city_list = Db::name('system_area')->where('pid',$id)->where('level',2)->select();
+        $this->success('成功',$city_list);
+    }
+
+    /**
+     * 获取区
+     */
+    public function get_area(){
+        $name = $this->app->request->get('id');
+        $id = Db::name('system_area')->where('name',$name)->where('level',2)->value('id');
+        $area_list = Db::name('system_area')->where('pid',$id)->where('level',3)->select();
+        $this->success('成功',$area_list);
+    }
+
+
+    /**
+     * 导入主项目数据
+     * @auth true
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function import()
+    {
+        list($msec, $sec) = explode(' ', microtime());
+        $msectime = (float)sprintf('%.0f', (floatval($msec) + floatval($sec)) * 1000);  //毫秒值
+        $get = $this->request->get();
+        $import_path = $_SERVER['DOCUMENT_ROOT'].'/'.$get['path'];
+        $project_id = $get['project_id'];
+        $num = 3;
+        try {
+            $objReader =\PHPExcel_IOFactory::createReader('Excel2007');
+            $objExcel = $objReader->load($import_path);
+            $list = $objExcel->getActiveSheet()->toArray();
+            if (!isset($list[1][8]) || !$list[1][8] || !isset($list[1][9]) || !$list[1][9] || !isset($list[1][10]) || !$list[1][10]){
+                $this->error('失败');
+            }
+            if ($list[1][11]){
+                $this->error('失败');
+            }
+            Db::name($this->table3)->where('project_id',$project_id)->delete();
+            Db::name($this->table)->where('id',$project_id)->update(['url'=>$get['url']]);
+            $result = 0;
+            foreach ($list as $k=>$v){
+                if($k>=$num-1){
+                    if(array_filter($v)){
+                        $data=[];
+                        foreach ($v as $kk=>$vv){
+                            $data[IntToChr($kk)]=trim($vv);
+                        }
+                        $date['project_id'] = $project_id;
+                        $date['number'] = $data['A'];
+                        $date['subjects'] = $data['B'];
+                        $date['costs_are_excluded'] = $data['C'];
+                        $date['costs_are_excluded1'] = str_replace(',','',$data['C']);
+                        $date['total_vat'] = $data['D'];
+                        $date['total_vat1'] = str_replace(',','',$data['D']);
+                        $date['measurement_cost'] = $data['E'];
+                        $date['measurement_cost1'] = str_replace(',','',$data['E']);
+                        $date['area'] = $data['F'];
+                        $date['unilateral_cost_indicator'] = $data['G'];
+                        $date['unilateral_cost_indicator1'] = str_replace(',','',$data['G']);
+                        $date['single_cost_indicator'] = $data['H'];
+                        $date['single_cost_indicator1'] = str_replace(',','',$data['H']);
+                        $date['single_party_cost_tax'] = $data['I'];
+                        $date['single_party_cost_tax1'] = str_replace(',','',$data['I']);
+                        $date['single_party_cost_no_tax'] = $data['J'];
+                        $date['single_party_cost_no_tax1'] = str_replace(',','',$data['J']);
+                        $date['note'] = $data['K'];
+                        $date['create_at'] = date('Y-m-d H:i:s');
+                        $numbers = explode('.',$data['A']);
+                        if (count($numbers)>1){
+                            array_pop($numbers); //去掉数组最后一组元素
+                            $number = implode('.',$numbers);
+                            $date['pid'] = Db::name($this->table3)->where('project_id',$project_id)->where('number',$number)->value('id');
+                            $date['pname'] = Db::name($this->table3)->where('project_id',$project_id)->where('number',$number)->value('subjects');
+                        }else{
+                            $date['pid'] = 0;
+                            $date['pname'] = '';
+                        }
+                        if (Db::table($this->table3)->insertGetId($date)){
+                            $result = 1;
+                        }else{
+                            $result = 0;
+                            break;
+                        }
+                    }
+                }
+            }
+            if ($result==1){
+                $this->success('成功');
+            }else{
+                $this->error('失败');
+            }
+
+        } catch (\think\exception\ValidateException $e) {
+            $this->error($e->getMessage());
+        }
+    }
+
+
+    /**
+     * 查看数据
+     * @auth true
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
+     */
+    public function look()
+    {
+        $id = $this->app->request->get('id');
+        $this->title = '查看';
+        $list = Db::name($this->table3)
+            ->where('project_id',$id)
+            ->order('id asc')
+            ->select();
+        $this->assign('list',$list);
+        $this->fetch();
+    }
+
+
+    /**
+     * 下载数据
+     * @auth true
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
+     */
+    public function down()
+    {
+
+    }
+
+    /**
+     * 数据对比
+     * @auth true
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
+     */
+    public function contrast()
+    {
+        set_time_limit(0);
+        $this->title = '数据对比';
+        $ids = $this->request->get('ids');
+        $this->assign('ids',$ids);
+//        $query = $this->_query($this->table3);
+//        $query->whereIn('project_id',$ids)
+//            ->group('subjects')
+//            ->order('id asc')
+//            ->field('id,pid,number,subjects')
+//            ->page();
+
+        $list = Db::name($this->table3)
+            ->whereIn('project_id',$ids)
+            ->group('subjects')
+            ->order('id asc')
+            ->field('id,pid,pname,number,subjects')
+            ->select();
+
+
+
+        $list = $this->deal_list($ids,$list);
+
+        $list = $this->get_attr($list);
+//        $list = $this->get_attr($list,0);
+
+        $this->assign('list',$list);
+        $this->fetch();
+    }
+
+
+
+    public function get_attr($a,$pid=''){
+        $tree = array();                                //每次都声明一个新数组用来放子元素
+        foreach($a as $v){
+            if($v['pname'] == $pid){                      //匹配子记录
+               // $v['children'] = $this->get_attr($a,$v['number']); //递归获取子记录
+                $v['children'] = $this->get_attr($a,$v['subjects']); //递归获取子记录
+                $tree[] = $v;                           //将记录存入新数组
+            }
+        }
+        return $tree;                                  //返回新数组
+    }
+
+    //列表处理
+    public function deal_list($ids,$list){
+        foreach ($list as &$v){
+            $where = [];
+            $where[] = ['project_id','in',$ids];
+            $where[] = ['subjects','eq', $v['subjects']];
+            //---不含增值税测算成本---//
+            //参考区间
+            $costs_are_excluded_interval_start = Db::name($this->table3)
+                ->where($where)
+                ->where('costs_are_excluded','neq','')
+                ->min('costs_are_excluded1');
+            $costs_are_excluded_interval_end = Db::name($this->table3)
+                ->where($where)
+                ->where('costs_are_excluded','neq','')
+                ->max('costs_are_excluded1');
+            $v['costs_are_excluded_interval'] = $costs_are_excluded_interval_start.'-'.$costs_are_excluded_interval_end;
+            //算数平均值
+            $costs_are_excluded_arithmetic_mean_all = Db::name($this->table3)
+                ->where($where)
+                ->where('costs_are_excluded','neq','')
+                ->sum('costs_are_excluded1');
+            $costs_are_excluded_arithmetic_mean_count = Db::name($this->table3)
+                ->where($where)
+                ->where('costs_are_excluded','neq','')
+                ->count();
+            $v['costs_are_excluded_arithmetic_mean'] = ($costs_are_excluded_arithmetic_mean_all==0 || $costs_are_excluded_arithmetic_mean_count==0) ? 0 : $costs_are_excluded_arithmetic_mean_all/$costs_are_excluded_arithmetic_mean_count;
+            //有效样本量
+            $v['costs_are_excluded_valid_sample_size'] = $costs_are_excluded_arithmetic_mean_count;
+
+
+            //---增值税总额---//
+            //参考区间
+            $total_vat_interval_start = Db::name($this->table3)
+                ->where($where)
+                ->where('total_vat','neq','')
+                ->min('total_vat1');
+            $total_vat_interval_end = Db::name($this->table3)
+                ->where($where)
+                ->where('total_vat','neq','')
+                ->max('total_vat1');
+            $v['total_vat_interval'] = $total_vat_interval_start.'-'.$total_vat_interval_end;
+            //算数平均值
+            $total_vat_arithmetic_mean_all = Db::name($this->table3)
+                ->where($where)
+                ->where('total_vat','neq','')
+                ->sum('total_vat1');
+            $total_vat_arithmetic_mean_count = Db::name($this->table3)
+                ->where($where)
+                ->where('total_vat','neq','')
+                ->count();
+            $v['total_vat_arithmetic_mean'] = ($total_vat_arithmetic_mean_all==0 || $total_vat_arithmetic_mean_count==0) ? 0 : $total_vat_arithmetic_mean_all/$total_vat_arithmetic_mean_count;
+            //有效样本量
+            $v['total_vat_valid_sample_size'] = $total_vat_arithmetic_mean_count;
+
+            //---含增值税测算成本---//
+            //参考区间
+            $measurement_cost_interval_start = Db::name($this->table3)
+                ->where($where)
+                ->where('measurement_cost','neq','')
+                ->min('measurement_cost1');
+            $measurement_cost_interval_end = Db::name($this->table3)
+                ->where($where)
+                ->where('measurement_cost','neq','')
+                ->max('measurement_cost1');
+            $v['measurement_cost_interval'] = $measurement_cost_interval_start.'-'.$measurement_cost_interval_end;
+            //算数平均值
+            $measurement_cost_arithmetic_mean_all = Db::name($this->table3)
+                ->where($where)
+                ->where('measurement_cost','neq','')
+                ->sum('measurement_cost1');
+            $measurement_cost_arithmetic_mean_count = Db::name($this->table3)
+                ->where($where)
+                ->where('measurement_cost','neq','')
+                ->count();
+            $v['measurement_cost_arithmetic_mean'] = ($measurement_cost_arithmetic_mean_all==0 || $measurement_cost_arithmetic_mean_count==0) ? 0 : $measurement_cost_arithmetic_mean_all/$measurement_cost_arithmetic_mean_count;
+            //有效样本量
+            $v['measurement_cost_valid_sample_size'] = $measurement_cost_arithmetic_mean_count;
+
+
+            //---单方成本指标(不含税)---//
+            //参考区间
+            $unilateral_cost_indicator_interval_start = Db::name($this->table3)
+                ->where($where)
+                ->where('unilateral_cost_indicator','neq','')
+                ->min('unilateral_cost_indicator1');
+            $unilateral_cost_indicator_interval_end = Db::name($this->table3)
+                ->where($where)
+                ->where('unilateral_cost_indicator','neq','')
+                ->max('unilateral_cost_indicator1');
+            $v['unilateral_cost_indicator_interval'] = $unilateral_cost_indicator_interval_start.'-'.$unilateral_cost_indicator_interval_end;
+            //算数平均值
+            $unilateral_cost_indicator_arithmetic_mean_all = Db::name($this->table3)
+                ->where($where)
+                ->where('unilateral_cost_indicator','neq','')
+                ->sum('unilateral_cost_indicator1');
+            $unilateral_cost_indicator1_arithmetic_mean_count = Db::name($this->table3)
+                ->where($where)
+                ->where('unilateral_cost_indicator','neq','')
+                ->count();
+            $v['unilateral_cost_indicator_arithmetic_mean'] = ($unilateral_cost_indicator_arithmetic_mean_all==0 || $unilateral_cost_indicator1_arithmetic_mean_count==0) ? 0 : $unilateral_cost_indicator_arithmetic_mean_all/$unilateral_cost_indicator1_arithmetic_mean_count;
+            //有效样本量
+            $v['unilateral_cost_indicator_valid_sample_size'] = $unilateral_cost_indicator1_arithmetic_mean_count;
+
+            //---单方成本指标(含税)---//
+            //参考区间
+            $single_cost_indicator_interval_start = Db::name($this->table3)
+                ->where($where)
+                ->where('single_cost_indicator','neq','')
+                ->min('single_cost_indicator1');
+            $single_cost_indicator_interval_end = Db::name($this->table3)
+                ->where($where)
+                ->where('single_cost_indicator','neq','')
+                ->max('single_cost_indicator1');
+            $v['single_cost_indicator_interval'] = $single_cost_indicator_interval_start.'-'.$single_cost_indicator_interval_end;
+            //算数平均值
+            $single_cost_indicator_arithmetic_mean_all = Db::name($this->table3)
+                ->where($where)
+                ->where('single_cost_indicator','neq','')
+                ->sum('single_cost_indicator1');
+            $single_cost_indicator_arithmetic_mean_count = Db::name($this->table3)
+                ->where($where)
+                ->where('single_cost_indicator','neq','')
+                ->count();
+            $v['single_cost_indicator_arithmetic_mean'] = ($single_cost_indicator_arithmetic_mean_all==0 || $single_cost_indicator_arithmetic_mean_count==0) ? 0 : $single_cost_indicator_arithmetic_mean_all/$single_cost_indicator_arithmetic_mean_count;
+            //有效样本量
+            $v['single_cost_indicator_valid_sample_size'] = $single_cost_indicator_arithmetic_mean_count;
+
+            //---可售单方成本指标(不含税)---//
+            //参考区间
+            $single_party_cost_tax_interval_start = Db::name($this->table3)
+                ->where($where)
+                ->where('single_party_cost_tax','neq','')
+                ->min('single_party_cost_tax1');
+            $single_party_cost_tax_interval_end = Db::name($this->table3)
+                ->where($where)
+                ->where('single_party_cost_tax','neq','')
+                ->max('single_party_cost_tax1');
+            $v['single_party_cost_tax_interval'] = $single_party_cost_tax_interval_start.'-'.$single_party_cost_tax_interval_end;
+            //算数平均值
+            $single_party_cost_tax_arithmetic_mean_all = Db::name($this->table3)
+                ->where($where)
+                ->where('single_party_cost_tax','neq','')
+                ->sum('single_party_cost_tax1');
+            $single_party_cost_tax_arithmetic_mean_count = Db::name($this->table3)
+                ->where($where)
+                ->where('single_party_cost_tax','neq','')
+                ->count();
+            $v['single_party_cost_tax_arithmetic_mean'] = ($single_party_cost_tax_arithmetic_mean_all==0 || $single_party_cost_tax_arithmetic_mean_count==0) ? 0 : $single_party_cost_tax_arithmetic_mean_all/$single_party_cost_tax_arithmetic_mean_count;
+            //有效样本量
+            $v['single_party_cost_tax_valid_sample_size'] = $single_party_cost_tax_arithmetic_mean_count;
+
+
+            //---可售单方成本指标(含税)---//
+            //参考区间
+            $single_party_cost_no_tax_interval_start = Db::name($this->table3)
+                ->where($where)
+                ->where('single_party_cost_no_tax','neq','')
+                ->min('single_party_cost_no_tax1');
+            $single_party_cost_no_tax_interval_end = Db::name($this->table3)
+                ->where($where)
+                ->where('single_party_cost_no_tax','neq','')
+                ->max('single_party_cost_no_tax1');
+            $v['single_party_cost_no_tax_interval'] = $single_party_cost_no_tax_interval_start.'-'.$single_party_cost_no_tax_interval_end;
+            //算数平均值
+            $single_party_cost_no_tax_arithmetic_mean_all = Db::name($this->table3)
+                ->where($where)
+                ->where('single_party_cost_no_tax','neq','')
+                ->sum('single_party_cost_no_tax1');
+            $single_party_cost_no_tax_arithmetic_mean_count = Db::name($this->table3)
+                ->where($where)
+                ->where('single_party_cost_no_tax','neq','')
+                ->count();
+            $v['single_party_cost_no_tax_arithmetic_mean'] = ($single_party_cost_no_tax_arithmetic_mean_all==0 || $single_party_cost_no_tax_arithmetic_mean_count==0) ? 0 : $single_party_cost_no_tax_arithmetic_mean_all/$single_party_cost_no_tax_arithmetic_mean_count;
+            //有效样本量
+            $v['single_party_cost_no_tax_valid_sample_size'] = $single_party_cost_no_tax_arithmetic_mean_count;
+        }
+        return $list;
+    }
+
+
+
+    /**
+     * 列表数据处理
+     * @param array $data
+     */
+    protected function _contrast_page_filter(&$data)
+    {
+        $ids = $this->request->get('ids');
+        $data = $this->deal_list($ids,$data);
+    }
+
+    /**
+     * 对比数据导出
+     * @auth true
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
+     */
+    public function download()
+    {
+        $ids = $this->request->get('ids');
+        $list = Db::name($this->table3)->whereIn('project_id',$ids)
+            ->group('subjects')
+            ->order('id asc')
+            ->field('id,pid,number,subjects')
+            ->select();
+        $list = $this->deal_list($ids,$list);
+        $objPHPExcel = new \PHPExcel();//实例化phpexcel
+        $filename = '数据分析情况';
+        $indexKey = array(
+            'number',
+            'subjects',
+            'costs_are_excluded_interval',
+            'costs_are_excluded_arithmetic_mean',
+            'costs_are_excluded_valid_sample_size',
+            'total_vat_interval',
+            'total_vat_arithmetic_mean',
+            'total_vat_valid_sample_size',
+            'measurement_cost_interval',
+            'measurement_cost_arithmetic_mean',
+            'measurement_cost_valid_sample_size',
+            'unilateral_cost_indicator_interval',
+            'unilateral_cost_indicator_arithmetic_mean',
+            'unilateral_cost_indicator_valid_sample_size',
+            'single_cost_indicator_interval',
+            'single_cost_indicator_arithmetic_mean',
+            'single_cost_indicator_valid_sample_size',
+            'single_party_cost_tax_interval',
+            'single_party_cost_tax_arithmetic_mean',
+            'single_party_cost_tax_valid_sample_size',
+            'single_party_cost_no_tax_interval',
+            'single_party_cost_no_tax_arithmetic_mean',
+            'single_party_cost_no_tax_valid_sample_size'
+        );
+        $header_arr = array('A','B','C','D','E','F','G','H','I','J','K','L','M', 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z');
+        $styleThinBlackBorderOutline = array(
+            'borders' => array(
+                'allborders' => array( //设置全部边框
+                    'style' => \PHPExcel_Style_Border::BORDER_THIN //粗的是thick
+                ),
+
+            ),
+        );
+        $count = count($list)+3;
+        $objPHPExcel->getActiveSheet()->getStyle( 'A1:W'.$count)->applyFromArray($styleThinBlackBorderOutline);
+        $objPHPExcel -> getActiveSheet() -> getColumnDimension(\PHPExcel_Cell::stringFromColumnIndex(0)) -> setAutoSize(true);
+        //接下来就是写数据到表格里面去
+        $objActSheet = $objPHPExcel->getActiveSheet();
+        $objPHPExcel->getActiveSheet()->mergeCells('A1:V1');//合并
+        $objPHPExcel->getActiveSheet()->setCellValue('A1', '数据分析结果');
+        $objPHPExcel->getActiveSheet()->getStyle('A1')->getFont()->setSize(16); //第一行字体大小
+        $objPHPExcel->getActiveSheet()->getStyle('A1')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
+        $objPHPExcel->getActiveSheet()->mergeCells('A2:A3');//合并
+        $objPHPExcel->getActiveSheet()->setCellValue('A2', '序号');
+        $objPHPExcel->getActiveSheet()->getStyle('A2')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
+        $objPHPExcel->getActiveSheet()->mergeCells('B2:B3');//合并
+        $objPHPExcel->getActiveSheet()->setCellValue('B2', '成本预算科目');
+        $objPHPExcel->getActiveSheet()->getStyle('B2')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
+        $objPHPExcel->getActiveSheet()->mergeCells('C2:E2');//合并
+        $objPHPExcel->getActiveSheet()->setCellValue('C2', '不含增值税测算成本');
+        $objPHPExcel->getActiveSheet()->getStyle('C2')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
+        $objPHPExcel->getActiveSheet()->mergeCells('F2:H2');//合并
+        $objPHPExcel->getActiveSheet()->setCellValue('F2', '增值税总额');
+        $objPHPExcel->getActiveSheet()->getStyle('F2')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
+        $objPHPExcel->getActiveSheet()->mergeCells('I2:K2');//合并
+        $objPHPExcel->getActiveSheet()->setCellValue('I2', '含增值税测算成本');
+        $objPHPExcel->getActiveSheet()->getStyle('I2')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
+        $objPHPExcel->getActiveSheet()->mergeCells('L2:N2');//合并
+        $objPHPExcel->getActiveSheet()->setCellValue('L2', '建面单方成本指标(不含税)');
+        $objPHPExcel->getActiveSheet()->getStyle('L2')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
+        $objPHPExcel->getActiveSheet()->mergeCells('O2:Q2');//合并
+        $objPHPExcel->getActiveSheet()->setCellValue('O2', '建面单方成本指标(含税)');
+        $objPHPExcel->getActiveSheet()->getStyle('O2')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
+
+        $objPHPExcel->getActiveSheet()->mergeCells('R2:T2');//合并
+        $objPHPExcel->getActiveSheet()->setCellValue('R2', '可售单方成本指标(不含税)');
+        $objPHPExcel->getActiveSheet()->getStyle('R2')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
+
+        $objPHPExcel->getActiveSheet()->mergeCells('U2:W2');//合并
+        $objPHPExcel->getActiveSheet()->setCellValue('U2', '可售单方成本指标(含税)');
+        $objPHPExcel->getActiveSheet()->getStyle('U2')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
+
+        $objPHPExcel->getActiveSheet()->setCellValue('C3', '参考区间');
+        $objPHPExcel->getActiveSheet()->setCellValue('D3', '算数平均值	');
+        $objPHPExcel->getActiveSheet()->setCellValue('E3', '有效样本量');
+        $objPHPExcel->getActiveSheet()->setCellValue('F3', '参考区间');
+        $objPHPExcel->getActiveSheet()->setCellValue('G3', '算数平均值	');
+        $objPHPExcel->getActiveSheet()->setCellValue('H3', '有效样本量');
+        $objPHPExcel->getActiveSheet()->setCellValue('I3', '参考区间');
+        $objPHPExcel->getActiveSheet()->setCellValue('J3', '算数平均值	');
+        $objPHPExcel->getActiveSheet()->setCellValue('K3', '有效样本量');
+        $objPHPExcel->getActiveSheet()->setCellValue('L3', '参考区间');
+        $objPHPExcel->getActiveSheet()->setCellValue('M3', '算数平均值	');
+        $objPHPExcel->getActiveSheet()->setCellValue('N3', '有效样本量');
+        $objPHPExcel->getActiveSheet()->setCellValue('O3', '参考区间');
+        $objPHPExcel->getActiveSheet()->setCellValue('P3', '算数平均值	');
+        $objPHPExcel->getActiveSheet()->setCellValue('Q3', '有效样本量');
+        $objPHPExcel->getActiveSheet()->setCellValue('R3', '参考区间');
+        $objPHPExcel->getActiveSheet()->setCellValue('S3', '算数平均值	');
+        $objPHPExcel->getActiveSheet()->setCellValue('T3', '有效样本量');
+        $objPHPExcel->getActiveSheet()->setCellValue('U3', '参考区间');
+        $objPHPExcel->getActiveSheet()->setCellValue('V3', '算数平均值	');
+        $objPHPExcel->getActiveSheet()->setCellValue('W3', '有效样本量');
+        $startRow = 4;
+        foreach ($list as &$row) {
+            foreach ($indexKey as $key => $value){
+                //这里是设置单元格的内容
+                $objActSheet->setCellValue($header_arr[$key].$startRow,$row[$value]);
+            }
+            $startRow++;
+        }
+
+        // 下载这个表格,在浏览器输出
+        header('Content-Disposition: attachment;filename="'.$filename.'.xlsx"');//下载下来的表格名
+        header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
+        $PHPWriter = \PHPExcel_IOFactory::createWriter($objPHPExcel, "Excel2007");//创建生成的格式
+        $PHPWriter->save('php://output');
+
+    }
+
+    /**
+     * 对比数据查看
+     * @auth true
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
+     */
+    public function see()
+    {
+        $this->title = '对比数据查看';
+        $subjects = $this->request->get('subjects');
+        $ids = $this->request->get('ids');
+        $this->assign('subjects',$subjects);
+        $this->assign('ids',$ids);
+
+        $list = Db::name($this->table3)
+            ->whereIn('project_id',$ids)
+            ->where('subjects','neq',$subjects)
+            ->where('costs_are_excluded','neq','')
+            ->orderRand()
+            ->field('id,pid,number,subjects')
+            ->limit(15)
+            ->select();
+
+        $where[] = ['project_id','in',$ids];
+        foreach ($list as &$v){
+            $v['costs_are_excluded_min'] = Db::name($this->table3)
+                ->where($where)
+                ->where('subjects',$v['subjects'])
+                ->where('costs_are_excluded','neq','')
+                ->min('costs_are_excluded1');
+            $v['costs_are_excluded_max'] = Db::name($this->table3)
+                ->where('subjects',$v['subjects'])
+                ->where($where)
+                ->where('costs_are_excluded','neq','')
+                ->max('costs_are_excluded1');
+        }
+        $this->assign('list',$list);
+
+
+        $project_ids = Db::name($this->table3)->whereIn('project_id',$ids)->where('subjects',$subjects)->column('project_id');
+        $arr = [];
+        foreach ($project_ids as &$v){
+            $a['project_name'] = Db::name($this->table)->where('id',$v)->value('project_name');
+            $a['value'] = Db::name($this->table3)->where('project_id',$v)->where('subjects',$subjects)->value('costs_are_excluded');
+            array_push($arr,$a);
+        }
+//        dump($arr);
+
+
+        $this->fetch();
+    }
+
+    /**
+     * 获取详情
+     * @auth fale
+     */
+    public function get_see_info(){
+        $subjects = $this->request->get('subjects');
+        $ids = $this->request->get('ids');
+        $field = $this->request->get('field');
+        $array['subjects'] = $subjects;
+        $where[] = ['project_id','in',$ids];
+        $where[] = ['subjects','eq', $subjects];
+        $min = Db::name($this->table3)
+            ->where($where)
+            ->where($field,'neq','')
+            ->min($field.'1');
+        $max = Db::name($this->table3)
+            ->where($where)
+            ->where($field,'neq','')
+            ->max($field.'1');
+
+        if ($min==$max){
+            $interval = $this->interval($min,$max,1);
+        }else{
+            $interval = $this->interval($min,$max);
+        }
+
+        $array['field']['title'] = $interval;
+        $array['field']['value'] = $this->interval_count($interval,$where,$field);
+
+        $project_ids = Db::name($this->table3)->whereIn('project_id',$ids)->where('subjects',$subjects)->column('project_id');
+        $arr = [];
+        foreach ($project_ids as &$v){
+            $a['project_name'] = Db::name($this->table)->where('id',$v)->value('project_name');
+            $value = Db::name($this->table3)->where('project_id',$v)->where('subjects',$subjects)->value($field);
+            $a['value'] = $value;
+            $a['note'] = Db::name($this->table3)->where('project_id',$v)->where('subjects',$subjects)->value('note');
+            if ($value){
+                array_push($arr,$a);
+            }
+
+        }
+        $array['right'] = $arr;
+
+
+        $this->success('成功',$array);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+//        //---不含增值税测算成本---//
+//        //参考区间
+//        $costs_are_excluded_min = Db::name($this->table3)
+//            ->where($where)
+//            ->where('costs_are_excluded','neq','')
+//            ->min('costs_are_excluded1');
+//        $costs_are_excluded_max = Db::name($this->table3)
+//            ->where($where)
+//            ->where('costs_are_excluded','neq','')
+//            ->max('costs_are_excluded1');
+//        $costs_are_excluded_interval = $this->interval($costs_are_excluded_min,$costs_are_excluded_max);
+//        $array['costs_are_excluded']['title'] = $costs_are_excluded_interval;
+//        $array['costs_are_excluded']['value'] = $this->interval_count($costs_are_excluded_interval,$where,'costs_are_excluded');
+//        //---增值税总额---//
+//        //参考区间
+//        $total_vat_min = Db::name($this->table3)
+//            ->where($where)
+//            ->where('total_vat','neq','')
+//            ->min('total_vat1');
+//        $total_vat_max = Db::name($this->table3)
+//            ->where($where)
+//            ->where('total_vat','neq','')
+//            ->max('total_vat1');
+//        $total_vat_interval = $this->interval($total_vat_min,$total_vat_max);
+//        $array['total_vat']['title'] = $total_vat_interval;
+//        $array['total_vat']['value'] = $this->interval_count($total_vat_interval,$where,'total_vat');
+//        //---含增值税测算成本---//
+//        //参考区间
+//        $measurement_cost_min = Db::name($this->table3)
+//            ->where($where)
+//            ->where('measurement_cost','neq','')
+//            ->min('measurement_cost1');
+//        $measurement_cost_max = Db::name($this->table3)
+//            ->where($where)
+//            ->where('measurement_cost','neq','')
+//            ->max('measurement_cost1');
+//        $measurement_cost_interval = $this->interval($measurement_cost_min,$measurement_cost_max);
+//        $array['measurement_cost']['title'] = $measurement_cost_interval;
+//        $array['measurement_cost']['value'] = $this->interval_count($measurement_cost_interval,$where,'measurement_cost');
+//
+//        //---单方成本指标(不含税)---//
+//        //参考区间
+//        $unilateral_cost_indicator_min = Db::name($this->table3)
+//            ->where($where)
+//            ->where('unilateral_cost_indicator','neq','')
+//            ->min('unilateral_cost_indicator1');
+//        $unilateral_cost_indicator_max = Db::name($this->table3)
+//            ->where($where)
+//            ->where('unilateral_cost_indicator','neq','')
+//            ->max('unilateral_cost_indicator1');
+//        $unilateral_cost_indicator_interval = $this->interval($unilateral_cost_indicator_min,$unilateral_cost_indicator_max);
+//        $array['unilateral_cost_indicator']['title'] = $unilateral_cost_indicator_interval;
+//        $array['unilateral_cost_indicator']['value'] = $this->interval_count($unilateral_cost_indicator_interval,$where,'unilateral_cost_indicator');
+//
+//        //---单方成本指标(含税)---//
+//        //参考区间
+//        $single_cost_indicator_min = Db::name($this->table3)
+//            ->where($where)
+//            ->where('single_cost_indicator','neq','')
+//            ->min('single_cost_indicator1');
+//        $single_cost_indicator_max = Db::name($this->table3)
+//            ->where($where)
+//            ->where('single_cost_indicator','neq','')
+//            ->max('single_cost_indicator1');
+//        $single_cost_indicator_interval = $this->interval($single_cost_indicator_min,$single_cost_indicator_max);
+//        $array['single_cost_indicator']['title'] = $single_cost_indicator_interval;
+//        $array['single_cost_indicator']['value'] = $this->interval_count($single_cost_indicator_interval,$where,'single_cost_indicator');
+//
+//        $this->success('成功',$array);
+    }
+
+
+
+    //算区间平均值
+    public function interval($min,$max,$copies=10){
+        $cha = ($max-$min)/$copies;
+        $arr = [];
+        for ($i=0;$i<$copies;$i++){
+            $arra = $min.'-'.($min+$cha);
+            $min = $min+$cha;
+            array_push($arr,$arra);
+        }
+        return $arr;
+    }
+
+    //算区间平均值数量
+    public function interval_count($arr,$where,$field){
+        $value = [];
+        foreach ($arr as &$v){
+            $a = explode('-',$v);
+            $count = Db::name($this->table3)
+                ->where($where)
+                ->where($field,'neq','')
+                ->whereBetween($field.'1',[$a[0],$a[1]])
+                ->count();
+            array_push($value,$count);
+        }
+        return $value;
+    }
+
+
+
+
+}

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

@@ -0,0 +1,160 @@
+<?php
+
+// +----------------------------------------------------------------------
+// | ThinkAdmin
+// +----------------------------------------------------------------------
+// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// +----------------------------------------------------------------------
+// | 官方网站: http://demo.thinkadmin.top
+// +----------------------------------------------------------------------
+// | 开源协议 ( https://mit-license.org )
+// +----------------------------------------------------------------------
+// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
+// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller;
+
+use library\Controller;
+use library\service\MenuService;
+use library\tools\Data;
+use think\Db;
+
+/**
+ * 系统菜单管理
+ * Class Menu
+ * @package app\admin\controller
+ */
+class Menu extends Controller
+{
+
+    /**
+     * 当前操作数据库
+     * @var string
+     */
+    protected $table = 'SystemMenu';
+
+    /**
+     * 系统菜单管理
+     * @auth false
+     * @menu true
+     * @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->_page($this->table, false);
+    }
+
+    /**
+     * 列表数据处理
+     * @param array $data
+     */
+    protected function _index_page_filter(&$data)
+    {
+        foreach ($data as &$vo) {
+            if ($vo['url'] !== '#') {
+                $vo['url'] = trim(url($vo['url']) . (empty($vo['params']) ? '' : "?{$vo['params']}"), '/\\');
+            }
+            $vo['ids'] = join(',', Data::getArrSubIds($data, $vo['id']));
+        }
+        $data = Data::arr2table($data);
+    }
+
+    /**
+     * 添加系统菜单
+     * @auth false
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
+     */
+    public function add()
+    {
+        $this->applyCsrfToken();
+        $this->_form($this->table, 'form');
+    }
+
+    /**
+     * 编辑系统菜单
+     * @auth false
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
+     */
+    public function edit()
+    {
+        $this->applyCsrfToken();
+        $this->_form($this->table, 'form');
+    }
+
+    /**
+     * 表单数据处理
+     * @param array $vo
+     * @throws \ReflectionException
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    protected function _form_filter(&$vo)
+    {
+        if ($this->request->isGet()) {
+            // 读取系统功能节点
+            $this->nodes = MenuService::instance()->getList();
+            // 选择自己的上级菜单
+            if (empty($vo['pid']) && $this->request->get('pid', '0')) $vo['pid'] = $this->request->get('pid', '0');
+            // 列出可选上级菜单
+            $menus = Db::name($this->table)->where(['status' => '1'])->order('sort desc,id asc')->column('id,pid,url,title');
+            $this->menus = Data::arr2table(array_merge($menus, [['id' => '0', 'pid' => '-1', 'url' => '#', 'title' => '顶部菜单']]));
+            if (isset($vo['id'])) foreach ($this->menus as $key => $menu) if ($menu['id'] === $vo['id']) $vo = $menu;
+            foreach ($this->menus as $key => &$menu) {
+                if ($menu['spt'] >= 3 || $menu['url'] !== '#') unset($this->menus[$key]);
+                if (isset($vo['spt']) && $vo['spt'] <= $menu['spt']) unset($this->menus[$key]);
+            }
+        }
+    }
+
+    /**
+     * 启用系统菜单
+     * @auth false
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function resume()
+    {
+        $this->applyCsrfToken();
+        $this->_save($this->table, ['status' => '1']);
+    }
+
+    /**
+     * 禁用系统菜单
+     * @auth false
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function forbid()
+    {
+        $this->applyCsrfToken();
+        $this->_save($this->table, ['status' => '0']);
+    }
+
+    /**
+     * 删除系统菜单
+     * @auth false
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function remove()
+    {
+        $this->applyCsrfToken();
+        $this->_delete($this->table);
+    }
+
+}

+ 94 - 0
application/admin/controller/Oplog.php

@@ -0,0 +1,94 @@
+<?php
+
+// +----------------------------------------------------------------------
+// | ThinkAdmin
+// +----------------------------------------------------------------------
+// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// +----------------------------------------------------------------------
+// | 官方网站: http://demo.thinkadmin.top
+// +----------------------------------------------------------------------
+// | 开源协议 ( https://mit-license.org )
+// +----------------------------------------------------------------------
+// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
+// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller;
+
+use library\Controller;
+use think\Db;
+
+/**
+ * 系统日志管理
+ * Class Oplog
+ * @package app\admin\controller
+ */
+class Oplog extends Controller
+{
+
+    /**
+     * 指定当前数据表
+     * @var string
+     */
+    public $table = 'SystemLog';
+
+    /**
+     * 系统操作日志
+     * @auth false
+     * @menu true
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function index()
+    {
+        $this->title = '系统操作日志';
+        $query = $this->_query($this->table)->like('action,node,content,username,geoip');
+        $query->dateBetween('create_at')->order('id desc')->page();
+    }
+
+    /**
+     * 列表数据处理
+     * @auth false
+     * @param array $data
+     * @throws \Exception
+     */
+    protected function _index_page_filter(&$data)
+    {
+        $ip = new \Ip2Region();
+        foreach ($data as &$vo) {
+            $result = $ip->btreeSearch($vo['geoip']);
+            $vo['isp'] = isset($result['region']) ? $result['region'] : '';
+            $vo['isp'] = str_replace(['内网IP', '0', '|'], '', $vo['isp']);
+        }
+    }
+
+    /**
+     * 清理系统日志
+     * @auth false
+     * @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('日志清理失败,请稍候再试!');
+        }
+    }
+
+    /**
+     * 删除系统日志
+     * @auth false
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function remove()
+    {
+        $this->applyCsrfToken();
+        $this->_delete($this->table);
+    }
+
+}

+ 136 - 0
application/admin/controller/Template.php

@@ -0,0 +1,136 @@
+<?php
+
+// +----------------------------------------------------------------------
+// | ThinkAdmin
+// +----------------------------------------------------------------------
+// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// +----------------------------------------------------------------------
+// | 官方网站: http://demo.thinkadmin.top
+// +----------------------------------------------------------------------
+// | 开源协议 ( https://mit-license.org )
+// +----------------------------------------------------------------------
+// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
+// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller;
+
+use library\Controller;
+use library\tools\Data;
+use think\Db;
+
+/**
+ * 模板管理
+ * Class User
+ * @package app\admin\controller
+ */
+class Template extends Controller
+{
+
+    /**
+     * 指定当前数据表
+     * @var string
+     */
+    public $table = 'system_template';
+
+    /**
+     * 模板管理
+     * @auth true
+     * @menu true
+     * @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 = '模板管理';
+        $query = $this->_query($this->table);
+        $query->order('id asc')->where('is_del',1)->page();
+    }
+
+    /**
+     * 列表数据处理
+     * @param array $data
+     */
+    protected function _index_page_filter(&$data)
+    {
+
+    }
+
+
+    /**
+     * 上传模板
+     * @auth true
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
+     */
+    public function upload()
+    {
+        $this->_form($this->table, 'form');
+    }
+
+    /**
+     * 编辑模板
+     * @auth true
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
+     */
+    public function edit()
+    {
+        $this->_form($this->table, 'form');
+    }
+
+    /**
+     * 表单数据处理
+     * @param array $data
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function _upload_form_filter(&$data)
+    {
+
+        if ($this->request->isPost()) {
+//            if (Db::name($this->table)->where('id',$data['id'])->update(['url'=>$data['url']])){
+//                $this->success('上传成功');
+//            }else{
+//                $this->error('上传失败');
+//            }
+        }
+    }
+
+    /**
+     * 下载模板
+     * @auth true
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
+     */
+    public function down()
+    {
+
+    }
+
+    /**
+     * 删除
+     * @auth true
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function remove()
+    {
+        $this->_save($this->table, ['is_del' => '0']);
+        //$this->_delete($this->table);
+    }
+
+}

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

@@ -0,0 +1,196 @@
+<?php
+
+// +----------------------------------------------------------------------
+// | ThinkAdmin
+// +----------------------------------------------------------------------
+// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// +----------------------------------------------------------------------
+// | 官方网站: http://demo.thinkadmin.top
+// +----------------------------------------------------------------------
+// | 开源协议 ( https://mit-license.org )
+// +----------------------------------------------------------------------
+// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
+// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller;
+
+use library\Controller;
+use library\tools\Data;
+use think\Db;
+
+/**
+ * 用户管理
+ * Class User
+ * @package app\admin\controller
+ */
+class User extends Controller
+{
+
+    /**
+     * 指定当前数据表
+     * @var string
+     */
+    public $table = 'SystemUser';
+
+    /**
+     * 用户管理
+     * @auth true
+     * @menu true
+     * @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 = '用户管理';
+        $query = $this->_query($this->table)->like('username,phone,mail')->equal('status');
+        $query->dateBetween('login_at,create_at')->where(['is_deleted' => '0'])->order('id desc')->page();
+    }
+
+    /**
+     * 列表数据处理
+     * @param array $data
+     */
+    protected function _index_page_filter(&$data)
+    {
+        foreach ($data as &$vo) {
+            $vo['auth_name'] = Db::name('system_auth')->where('id',$vo['authorize'])->value('title');
+        }
+    }
+
+    /**
+     * 添加用户
+     * @auth true
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
+     */
+    public function add()
+    {
+
+        $this->applyCsrfToken();
+        $this->_form($this->table, 'form');
+    }
+
+    /**
+     * 编辑用户
+     * @auth true
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
+     */
+    public function edit()
+    {
+        $this->applyCsrfToken();
+        $this->_form($this->table, 'form');
+    }
+
+    /**
+     * 修改密码
+     * @auth true
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function pass()
+    {
+        $this->applyCsrfToken();
+        if ($this->request->isGet()) {
+            $this->verify = false;
+            $this->_form($this->table, 'pass');
+        } else {
+            $post = $this->request->post();
+            if ($post['password'] !== $post['repassword']) {
+                $this->error('两次输入的密码不一致!');
+            }
+            if (Db::name($this->table)->where('id',$post['id'])->update(['password'=>md5($post['password']),'password1'=>$post['password']])){
+                $this->success('密码修改成功,下次请使用新密码登录!', '');
+            } else {
+                $this->error('密码修改失败,请稍候再试!');
+            }
+        }
+    }
+
+    /**
+     * 表单数据处理
+     * @param array $data
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function _form_filter(&$data)
+    {
+        if ($this->request->isPost()) {
+
+            if (isset($data['id']) && $data['id']=='10000'){}else{
+                if (!isset($data['authorize']) || $data['authorize']==''){
+                    $this->error('请选择权限');
+                }
+            }
+
+            if (isset($data['password']) && $data['password']!=''){
+                $data['password1'] = $data['password'];
+                $data['password'] = md5($data['password']);
+            }
+            // 用户权限处理
+           // $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'], 'is_deleted' => '0'])->count() > 0) {
+                $this->error("账号{$data['username']}已经存在,请使用其它账号!");
+            }
+        } else {
+            //$data['authorize'] = explode(',', isset($data['authorize']) ? $data['authorize'] : '');
+            $this->authorizes = Db::name('SystemAuth')->where(['status' => '1'])->order('sort desc,id desc')->select();
+        }
+    }
+
+    /**
+     * 禁用用户
+     * @auth true
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function forbid()
+    {
+        if (in_array('10000', explode(',', $this->request->post('id')))) {
+            $this->error('系统超级账号禁止操作!');
+        }
+        $this->applyCsrfToken();
+        $this->_save($this->table, ['status' => '0']);
+    }
+
+    /**
+     * 启用用户
+     * @auth true
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function resume()
+    {
+        $this->applyCsrfToken();
+        $this->_save($this->table, ['status' => '1']);
+    }
+
+    /**
+     * 删除用户
+     * @auth true
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function remove()
+    {
+        if (in_array('10000', explode(',', $this->request->post('id')))) {
+            $this->error('系统超级账号禁止删除!');
+        }
+        $this->applyCsrfToken();
+        $this->_delete($this->table);
+    }
+
+}

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

@@ -0,0 +1,130 @@
+<?php
+
+// +----------------------------------------------------------------------
+// | ThinkAdmin
+// +----------------------------------------------------------------------
+// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// +----------------------------------------------------------------------
+// | 官方网站: http://demo.thinkadmin.top
+// +----------------------------------------------------------------------
+// | 开源协议 ( https://mit-license.org )
+// +----------------------------------------------------------------------
+// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
+// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\api;
+
+use library\Controller;
+use library\File;
+
+/**
+ * 后台插件管理
+ * Class Plugs
+ * @package app\admin\controller\api
+ */
+class Plugs extends Controller
+{
+
+    /**
+     * 系统图标选择器
+     */
+    public function icon()
+    {
+        $this->title = '图标选择器';
+        $this->field = input('field', 'icon');
+        $this->fetch();
+    }
+
+    /**
+     * 获取文件上传参数
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function check()
+    {
+        $diff1 = explode(',', strtolower(input('exts', '')));
+        $diff2 = explode(',', strtolower(sysconf('storage_local_exts')));
+        $exts = array_intersect($diff1, $diff2);
+        $this->success('获取文件上传参数', [
+            'exts' => join('|', $exts),
+            'mime' => File::mine($exts),
+            'type' => $this->getUploadType(),
+            'data' => $this->getUploadData(),
+        ]);
+    }
+
+    /**
+     * 后台通用文件上传
+     * @login true
+     * @return \think\response\Json
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function upload()
+    {
+        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' => '文件上传类型受限,请上传xlsx格式']]);
+        }
+        if ($file->checkExt('php,sh')) {
+            return json(['uploaded' => false, 'error' => ['message' => '可执行文件禁止上传到本地服务器']]);
+        }
+        $this->safe = boolval(input('safe'));
+        $this->uptype = $this->getUploadType();
+        $this->extend = pathinfo($file->getInfo('name'), PATHINFO_EXTENSION);
+        $name = File::name($file->getPathname(), $this->extend, '', '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, 'key'=>$info['key'] ,'url' => $this->safe ? $name : $info['url']]);
+        } else {
+            return json(['uploaded' => false, 'error' => ['message' => '文件处理失败,请稍候再试!']]);
+        }
+    }
+
+    /**
+     * 生成文件上传参数
+     * @return array
+     * @throws \think\Exception
+     */
+    private function getUploadData()
+    {
+        if ($this->getUploadType() === 'qiniu') {
+            $file = File::instance('qiniu');
+            return ['url' => $file->upload(true), 'token' => $file->buildUploadToken(), 'uptype' => $this->getUploadType()];
+        } else {
+            return ['url' => '?s=admin/api.plugs/upload', 'token' => uniqid('local_upload_'), 'uptype' => $this->getUploadType()];
+        }
+    }
+
+    /**
+     * 获取文件上传方式
+     * @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 \think\File
+     */
+    private function getUploadFile()
+    {
+        try {
+            return $this->request->file('file');
+        } catch (\Exception $e) {
+            $this->error(lang($e->getMessage()));
+        }
+    }
+
+}

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

@@ -0,0 +1,65 @@
+<?php
+
+// +----------------------------------------------------------------------
+// | ThinkAdmin
+// +----------------------------------------------------------------------
+// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// +----------------------------------------------------------------------
+// | 官方网站: http://demo.thinkadmin.top
+// +----------------------------------------------------------------------
+// | 开源协议 ( https://mit-license.org )
+// +----------------------------------------------------------------------
+// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
+// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\api;
+
+use library\command\Sync;
+use library\Controller;
+
+/**
+ * 系统更新接口
+ * Class Update
+ * @package app\admin\controller\api
+ */
+class Update extends Controller
+{
+    /**
+     * 访问权限
+     */
+    protected function initialize()
+    {
+        $domain = $this->app->request->host(true);
+        $isDemo = is_numeric(stripos($domain, 'thinkadmin.top'));
+        $isLocal = in_array($domain, ['127.0.0.1', 'localhost']);
+        if (!$isLocal && !$isDemo) $this->error('只允许访问本地或官方代码!');
+    }
+
+    /**
+     * 获取文件列表
+     */
+    public function tree()
+    {
+        $sync = new Sync('Update');
+        $this->success('获取当前文件列表成功!', $sync->build());
+    }
+
+    /**
+     * 读取线上文件数据
+     * @param string $encode
+     */
+    public function read($encode)
+    {
+        $this->file = env('root_path') . decode($encode);
+        if (file_exists($this->file)) {
+            $this->success('读取文件成功!', [
+                'format'  => 'base64',
+                'content' => base64_encode(file_get_contents($this->file)),
+            ]);
+        } else {
+            $this->error('获取文件内容失败!');
+        }
+    }
+
+}

+ 159 - 0
application/admin/sys.php

@@ -0,0 +1,159 @@
+<?php
+
+// +----------------------------------------------------------------------
+// | ThinkAdmin
+// +----------------------------------------------------------------------
+// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
+// +----------------------------------------------------------------------
+// | 官方网站: http://demo.thinkadmin.top
+// +----------------------------------------------------------------------
+// | 开源协议 ( https://mit-license.org )
+// +----------------------------------------------------------------------
+// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
+// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
+// +----------------------------------------------------------------------
+
+use library\File;
+use library\service\AdminService;
+use library\service\CaptchaService;
+use library\service\SystemService;
+use think\Db;
+use think\facade\Middleware;
+use think\facade\Route;
+use think\Request;
+
+if (!function_exists('auth')) {
+    /**
+     * 节点访问权限检查
+     * @param string $node 需要检查的节点
+     * @return boolean
+     * @throws ReflectionException
+     */
+    function auth($node)
+    {
+        return AdminService::instance()->check($node);
+    }
+}
+
+if (!function_exists('sysdata')) {
+    /**
+     * JSON 数据读取与存储
+     * @param string $name 数据名称
+     * @param mixed $value 数据内容
+     * @return mixed
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
+     */
+    function sysdata($name, $value = null)
+    {
+        if (is_null($value)) {
+            return SystemService::instance()->getData($name);
+        } else {
+            return SystemService::instance()->setData($name, $value);
+        }
+    }
+}
+
+if (!function_exists('sysoplog')) {
+    /**
+     * 写入系统日志
+     * @param string $action 日志行为
+     * @param string $content 日志内容
+     * @return boolean
+     */
+    function sysoplog($action, $content)
+    {
+        return SystemService::instance()->setOplog($action, $content);
+    }
+}
+
+if (!function_exists('sysqueue')) {
+    /**
+     * 创建异步处理任务
+     * @param string $title 任务名称
+     * @param string $loade 执行内容
+     * @param integer $later 延时执行时间
+     * @param array $data 任务附加数据
+     * @param integer $double 任务多开
+     * @return boolean
+     * @throws \think\Exception
+     */
+    function sysqueue($title, $loade, $later = 0, $data = [], $double = 1)
+    {
+        $map = [['title', 'eq', $title], ['status', 'in', [1, 2]]];
+        if (empty($double) && Db::name('SystemQueue')->where($map)->count() > 0) {
+            throw new \think\Exception('该任务已经创建,请耐心等待处理完成!');
+        }
+        $result = Db::name('SystemQueue')->insert([
+            'title'  => $title, 'preload' => $loade,
+            'data'   => json_encode($data, JSON_UNESCAPED_UNICODE),
+            'time'   => $later > 0 ? time() + $later : time(),
+            'double' => intval($double), 'create_at' => date('Y-m-d H:i:s'),
+        ]);
+        return $result !== false;
+    }
+}
+
+if (!function_exists('local_image')) {
+    /**
+     * 下载远程文件到本地
+     * @param string $url 远程图片地址
+     * @param boolean $force 是否强制重新下载
+     * @param integer $expire 强制本地存储时间
+     * @return string
+     */
+    function local_image($url, $force = false, $expire = 0)
+    {
+        $result = File::down($url, $force, $expire);
+        if (isset($result['url'])) {
+            return $result['url'];
+        } else {
+            return $url;
+        }
+    }
+}
+
+if (!function_exists('base64_image')) {
+    /**
+     * base64 图片上传接口
+     * @param string $content 图片base64内容
+     * @param string $dirname 图片存储目录
+     * @return string
+     */
+    function base64_image($content, $dirname = 'base64/')
+    {
+        try {
+            if (preg_match('|^data:image/(.*?);base64,|i', $content)) {
+                list($ext, $base) = explode('|||', preg_replace('|^data:image/(.*?);base64,|i', '$1|||', $content));
+                $info = File::save($dirname . md5($base) . '.' . (empty($ext) ? 'tmp' : $ext), base64_decode($base));
+                return $info['url'];
+            } else {
+                return $content;
+            }
+        } catch (\Exception $e) {
+            return $content;
+        }
+    }
+}
+
+// 访问权限检查中间键
+Middleware::add(function (Request $request, \Closure $next) {
+    if (AdminService::instance()->check()) {
+        return $next($request);
+    } elseif (AdminService::instance()->isLogin()) {
+        return json(['code' => 0, 'msg' => '抱歉,没有访问该操作的权限!']);
+    } else {
+        return json(['code' => 0, 'msg' => '抱歉,需要登录获取访问权限!', 'url' => url('@admin/login')]);
+    }
+});
+
+// ThinkAdmin 图形验证码
+Route::get('/think/admin/captcha', function () {
+    $image = CaptchaService::instance();
+    return json(['code' => '1', 'info' => '生成验证码', 'data' => [
+        'uniqid' => $image->getUniqid(), 'image' => $image->getData()
+    ]]);
+});

+ 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 (className) {
+            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>

+ 116 - 0
application/admin/view/auth/apply.html

@@ -0,0 +1,116 @@
+{extend name='main'}
+
+{block name="button"}
+
+{if auth("admin/auth/refresh")}
+<button data-load='{:url("refresh")}' class='layui-btn layui-btn-sm layui-btn-primary'>刷新权限</button>
+{/if}
+
+{/block}
+
+{block name="content"}
+<div class="think-box-shadow">
+    <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>
+        <button class="layui-btn layui-btn-danger" type='button' onclick="window.history.back()">取消编辑</button>
+    </div>
+</div>
+{/block}
+
+{block name="script"}
+<script>
+    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.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 () {
+            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-weight: 700;
+        font-size: 15px;
+    }
+
+    ul.ztree .level2 .button.level2 {
+        background: 0 0;
+    }
+</style>
+{/block}

+ 30 - 0
application/admin/view/auth/form.html

@@ -0,0 +1,30 @@
+<form class="layui-form layui-card" action="{:request()->url()}" data-auto="true" method="post" autocomplete="off">
+
+    <div class="layui-card-body padding-left-40">
+
+        <div class="layui-form-item">
+            <label class="relative block">
+                <span class="color-green font-w7">权限名称</span>
+                <span class="color-desc margin-left-5">Title</span>
+                <input type="text" name="title" value='{$vo.title|default=""}' required placeholder="请输入权限名称" class="layui-input">
+            </label>
+        </div>
+
+        <div class="layui-form-item">
+            <label class="relative block">
+                <span class="color-green font-w7">权限描述</span>
+                <span class="color-desc margin-left-5">Authorization</span>
+                <textarea placeholder="请输入权限描述" required class="layui-textarea" name="desc">{$vo.desc|default=""}</textarea>
+            </label>
+        </div>
+
+    </div>
+
+    <div class="hr-line-dashed"></div>
+    {notempty name='vo.id'}<input type='hidden' value='{$vo.id}' name='id'>{/notempty}
+
+    <div class="layui-form-item text-center">
+        <button class="layui-btn" type='submit'>保存数据</button>
+        <button class="layui-btn layui-btn-danger" type='button' data-confirm="确定要取消编辑吗?" data-close>取消编辑</button>
+    </div>
+</form>

+ 74 - 0
application/admin/view/auth/index.html

@@ -0,0 +1,74 @@
+{extend name='main'}
+
+{block name="button"}
+
+{if auth("add")}
+<button data-modal='{:url("add")}' style="background-color: #DC2219" data-title="添加" class='layui-btn layui-btn-sm'>添加</button>
+{/if}
+
+
+{/block}
+
+{block name="content"}
+
+<div class="think-box-shadow">
+<!--    {include file='auth/index_search'}-->
+    <table class="layui-table margin-top-10">
+        {notempty name='list'}
+        <thead>
+        <tr>
+            <th class='text-center nowrap'>编号</th>
+            <th class='text-center nowrap'>角色名称</th>
+            <th class='text-center nowrap'>创建时间</th>
+            <th class="text-center nowrap">使用状态</th>
+            <th class="text-center nowrap">操作</th>
+        </tr>
+        </thead>
+        {/notempty}
+        <tbody>
+        {foreach $list as $key=>$vo}
+        <tr>
+            <td class='text-center'>
+                {$vo.id}
+            </td>
+            <td class='text-center'>
+                {$vo.title|default='-'}<br>
+            </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="color-red">已禁用</span>{else}<span class="color-green">使用中</span>{/eq}
+            </td>
+            <td class='text-center nowrap'>
+
+                {if auth("edit")}
+                <span class="text-explode">|</span>
+                <a data-dbclick class="layui-btn layui-btn-sm" style="background-color: #DC2219" data-title="编辑" data-modal='{:url("edit")}?id={$vo.id}'>修 改</a>
+                {/if}
+
+                {if auth("apply")}
+                <a class="layui-btn layui-btn-normal layui-btn-sm" data-open='{:url("apply")}?id={$vo.id}'>授 权</a>
+                {/if}
+
+                {if $vo.status eq 1 and auth("forbid")}
+                <a class="layui-btn layui-btn-warm layui-btn-sm" data-action="{:url('forbid')}" data-value="id#{$vo.id};status#0" data-csrf="{:systoken('admin/auth/forbid')}">禁 用</a>
+                {elseif $vo.status eq 0 and auth("resume")}
+                <a class="layui-btn layui-btn-warm layui-btn-sm" data-action="{:url('resume')}" data-value="id#{$vo.id};status#1" data-csrf="{:systoken('admin/auth/resume')}">启 用</a>
+                {/if}
+
+                {if auth("remove")}
+                <a class="layui-btn layui-btn-danger layui-btn-sm" style="background-color: #5AD729" data-confirm="确定要删除数据吗?" data-action="{:url('remove')}" data-value="id#{$vo.id}" data-csrf="{:systoken('admin/auth/remove')}">删 除</a>
+                {/if}
+
+            </td>
+        </tr>
+        {/foreach}
+        </tbody>
+    </table>
+
+    {empty name='list'}<span class="notdata">没有记录哦</span>{else}{$pagehtml|raw|default=''}{/empty}
+
+</div>
+
+{/block}

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

@@ -0,0 +1,42 @@
+<fieldset>
+    <legend>条件搜索</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>

+ 50 - 0
application/admin/view/category/form.html

@@ -0,0 +1,50 @@
+<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">
+                <select name='pid' class='layui-select' lay-search>
+                    <!--{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">必选,请选择上级分类或一级分类(目前最多支持三级菜单)</p>
+            </div>
+        </div>
+
+        <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">必填,请填写分类名称</p>
+            </div>
+        </div>
+
+    </div>
+
+    <div class="hr-line-dashed"></div>
+    {notempty name='vo.id'}<input type='hidden' value='{$vo.id}' name='id'>{/notempty}
+
+    <div class="layui-form-item text-center">
+        <button class="layui-btn" type='submit'>保存数据</button>
+        <button class="layui-btn layui-btn-danger" type='button' data-confirm="确定要取消编辑吗?" data-close>取消编辑</button>
+    </div>
+
+</form>
+
+{block name='script'}
+<script>
+    require(['jquery.autocompleter'], function () {
+        form.render();
+        $('[name="icon"]').on('change', function () {
+            $(this).parent().next().find('i').get(0).className = this.value
+        });
+    });
+</script>
+{/block}

+ 145 - 0
application/admin/view/category/index.html

@@ -0,0 +1,145 @@
+{extend name='admin@main'}
+
+{block name="button"}
+{if auth("add")}
+<button data-modal='{:url("add")}' style="background-color: #DC2219" data-title="添加分类" class='layui-btn layui-btn-sm'>添加</button>
+{/if}
+{/block}
+<style>
+    .color-desc {
+        color: #999 !important;
+    }
+</style>
+
+{block name="content"}
+<div class="think-box-shadow">
+    <table class="layui-table margin-top-10">
+        {notempty name='list'}
+        <thead>
+        <tr>
+            <th class='text-left nowrap'>分类名称</th>
+            <th class="text-center">状态</th>
+            <th class="text-center">添加时间</th>
+            <th class="text-center">操作</th>
+        </tr>
+        </thead>
+        {/notempty}
+        <tbody>
+        {foreach $list as $key=>$vo}
+        <tr>
+            <td class='text-left nowrap' style="font-size: 13px;"
+                onclick='if($(".tr_{$vo.id}").hasClass("t")){$(".tr_{$vo.id}").removeClass("t").show()}else{$(".tr_{$vo.id}").addClass("t").hide();$(".ptr_{$vo.id}").addClass("t").hide()}'>
+                {$vo.title|default=''}
+
+                {if count($vo['children']) > 0}
+                    <i class="layui-icon layui-icon-triangle-r margin-right-5"></i>
+                {/if}
+            </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}<br>
+            </td>
+            <td class='text-center nowrap'>{$vo.create_at|format_datetime}</td>
+            <td class='text-center nowrap'>
+
+                {if auth("add")}
+                <span class="text-explode">|</span>
+                <a class="layui-btn layui-btn-sm" style="background-color: #DC2219" data-title="添加" data-modal='{:url("add")}?pid={$vo.id}'>添 加</a>
+                {/if}
+
+                {if auth("edit")}
+                <a data-dbclick class="layui-btn layui-btn-sm" style="background-color:#FFB822 " data-modal='{:url("edit")}?id={$vo.id}'>编 辑</a>
+                {/if}
+
+                {if $vo.status eq 1 and auth("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('forbid')}">禁 用</a>
+                {elseif auth("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('resume')}">启 用</a>
+                {/if}
+
+                {if auth("remove")}
+                <a class="layui-btn layui-btn-sm layui-btn-danger" style="background-color: #5AD729" data-confirm="确定要删除数据吗?" data-action="{:url('remove')}" data-value="id#{$vo.id}">删 除</a>
+                {/if}
+
+            </td>
+        </tr>
+
+
+        {foreach $vo['children'] as $k=>$v}
+<!--        <tr  class="t tr_{$vo.id}" style="display: none">-->
+        <tr  class="t tr_{$vo.id}" >
+            <td class='text-left nowrap' style="font-size: 13px;"
+                onclick='if($(".tr_{$v.id}").hasClass("t")){$(".tr_{$v.id}").removeClass("t").show()}else{$(".tr_{$v.id}").addClass("t").hide()}'>
+                <span class="color-desc" style="margin-left: 15px; margin-right: 10px">|-</span>
+                {$v.title|default=''}
+                {if count($v['children']) > 0}
+                <i class="layui-icon layui-icon-triangle-r margin-right-5"></i>
+                {/if}
+            </td>
+            <td class='text-center nowrap'>
+                {eq name='v.status' value='0'}<span class="layui-badge">已禁用</span>{else}<span class="layui-badge layui-bg-green">使用中</span>{/eq}<br>
+            </td>
+            <td class='text-center nowrap'>{$v.create_at|format_datetime}</td>
+            <td class='text-center nowrap'>
+
+                {if auth("add")}
+                <span class="text-explode">|</span>
+                <a class="layui-btn layui-btn-sm layui-bg-red" data-title="添加" data-modal='{:url("add")}?pid={$v.id}'>添 加</a>
+                {/if}
+
+                {if auth("edit")}
+                <a data-dbclick class="layui-btn layui-btn-sm" data-modal='{:url("edit")}?id={$v.id}&pid={$v.id}'>编 辑</a>
+                {/if}
+
+                {if $v.status eq 1 and auth("forbid")}
+                <a class="layui-btn layui-btn-sm layui-btn-warm" data-action="{:url('forbid')}" data-value="id#{$v.id};status#0" data-csrf="{:systoken('forbid')}">禁 用</a>
+                {elseif auth("resume")}
+                <a class="layui-btn layui-btn-sm layui-btn-warm" data-action="{:url('resume')}" data-value="id#{$v.id};status#1" data-csrf="{:systoken('resume')}">启 用</a>
+                {/if}
+
+                {if auth("remove")}
+                <a class="layui-btn layui-btn-sm layui-btn-danger" data-confirm="确定要删除数据吗?" data-action="{:url('remove')}" data-value="id#{$v.id}">删 除</a>
+                {/if}
+
+            </td>
+
+            {foreach $v['children'] as $ck=>$cv}
+            <tr  class="t ptr_{$vo.id} tr_{$v.id}" >
+            <td>
+                <span class="color-desc" style="margin-left: 15px; margin-right: 10px">|- </span>
+                <span class="color-desc" style="margin-left: 15px; margin-right: 10px;">|- </span>
+                {$cv.title|default=''}
+            </td>
+            <td class='text-center nowrap'>
+                {eq name='cv.status' value='0'}<span class="layui-badge">已禁用</span>{else}<span class="layui-badge layui-bg-green">使用中</span>{/eq}<br>
+            </td>
+            <td class='text-center nowrap'>{$cv.create_at|format_datetime}</td>
+            <td class='text-center nowrap'>
+
+                {if auth("add")}
+                <span class="text-explode">|</span>
+                <a class="layui-btn layui-btn-sm layui-btn-disabled">添 加</a>
+                {/if}
+
+                {if auth("edit")}
+                <a data-dbclick class="layui-btn layui-btn-sm" data-modal='{:url("edit")}?id={$cv.id}&pid={$cv.id}'>编 辑</a>
+                {/if}
+
+                {if $cv.status eq 1 and auth("forbid")}
+                <a class="layui-btn layui-btn-sm layui-btn-warm" data-action="{:url('forbid')}" data-value="id#{$cv.id};status#0" >禁 用</a>
+                {elseif auth("resume")}
+                <a class="layui-btn layui-btn-sm layui-btn-warm" data-action="{:url('resume')}" data-value="id#{$cv.id};status#1" >启 用</a>
+                {/if}
+
+                {if auth("remove")}
+                <a class="layui-btn layui-btn-sm layui-btn-danger" data-confirm="确定要删除数据吗?" data-action="{:url('remove')}" data-value="id#{$cv.id}">删 除</a>
+                {/if}
+
+            </td>
+            {/foreach}
+        {/foreach}
+        {/foreach}
+        </tbody>
+    </table>
+    {empty name='list'}<span class="notdata">没有记录哦</span>{else}{$pagehtml|raw|default=''}{/empty}
+</div>
+{/block}

+ 46 - 0
application/admin/view/category/index_search.html

@@ -0,0 +1,46 @@
+<fieldset>
+    <legend>条件搜索</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="status">
+                    {foreach [''=>'- 全部状态 -','1'=>'使用中的商品分类','0'=>'已禁用的商品分类'] 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">
+                <select class="layui-select" name="label_id">
+                    <option selected value="">全部</option>
+                    <!--{foreach $label as $k=>$v}-->
+                    <!--{eq name='Think.get.label_id' value='$v.id.""'}-->
+                    <option selected value='{$v.id}'>{$v.name}</option>
+                    <!--{else}-->
+                    <option value='{$v.id}'>{$v.name}</option>
+                    <!--{/eq}-->
+                    <!--{/foreach}-->
+                </select>
+            </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>
+    <script>form.render()</script>
+</fieldset>

+ 453 - 0
application/admin/view/child_project/contrast.html

@@ -0,0 +1,453 @@
+{extend name='main'}
+
+{block name="button"}
+
+{if auth("contrast")}
+<button class="layui-btn layui-btn-sm" style="background-color: #DC2219" onclick="getIds()" >导出</button>
+{/if}
+
+<button class="layui-btn" style="height: 30px;line-height:28px;background-color:#DC2219;color: #FFFFFF;border: 1px solid #C9C9C9 " type='button' onclick="window.history.back()">返 回</button>
+
+
+{/block}
+
+{block name="content"}
+<div class="think-box-shadow">
+    <table class="layui-table margin-top-10">
+        <input type="hidden" name="ids" id="ids" value="{$ids}">
+        {notempty name='list'}
+        <thead>
+        <tr>
+            <th class='text-left nowrap' rowspan="2">成本项目</th>
+            <th class='text-center nowrap' colspan="3">建面单方成本(元/m2)(含税)</th>
+            <th class='text-center nowrap' colspan="3">总价(万元)(含税)</th>
+            <th class='text-center nowrap' colspan="3">建面单方成本(元/m2)(不含税)</th>
+            <th class='text-center nowrap' colspan="3">总价(万元)(不含税)</th>
+            <th class='text-center nowrap' colspan="3">可售单方成本(元/m2)(含税)</th>
+            <th class='text-center nowrap' colspan="3">可售单方成本(元/m2)(不含税)</th>
+            <th class='text-center nowrap' colspan="3">工程量</th>
+            <th class='text-center nowrap' colspan="3">建面单方含量</th>
+            <th class='text-center nowrap' colspan="3">可售单方含量</th>
+            <th class='text-center nowrap' colspan="3">预留指标1</th>
+            <th class='text-center nowrap' colspan="3">预留指标2</th>
+            <th class='text-center nowrap' rowspan="2">操作</th>
+        </tr>
+        <tr>
+            <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>
+            <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>
+            <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>
+            <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>
+            <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>
+        {/notempty}
+        <tbody>
+        {foreach $list as $key=>$vo}
+        <tr class="tr_{$vo.id}">
+            <td class='text-left nowrap'
+                onclick='dianji($(this))' data-id="{$vo.id}">
+                {$vo.cost_project|default=''}
+                {if count($vo['children']) > 0}
+                <i class="layui-icon layui-icon-triangle-r margin-right-5 icon_{$vo.id}"></i>
+                {/if}
+            </td>
+            <td class='text-left nowrap'>{$vo.single_party_cost_interval|default='-'}</td>
+            <td class='text-left nowrap'>{$vo.single_party_cost_arithmetic_mean|default=''}</td>
+            <td class='text-left nowrap'>{$vo.single_party_cost_valid_sample_size|default=''}</td>
+            <td class='text-left nowrap'>{$vo.total_price_included_interval|default=''}</td>
+            <td class='text-left nowrap'>{$vo.total_price_included_arithmetic_mean|default='-'}</td>
+            <td class='text-left nowrap'>{$vo.total_price_included_valid_sample_size|default=''}</td>
+            <td class='text-left nowrap'>{$vo.single_party_cost_excluding_interval|default=''}</td>
+            <td class='text-left nowrap'>{$vo.single_party_cost_excluding_arithmetic_mean|default='-'}</td>
+            <td class='text-left nowrap'>{$vo.single_party_cost_excluding_valid_sample_size|default=''}</td>
+            <td class='text-left nowrap'>{$vo.total_price_included_excluding_interval|default=''}</td>
+            <td class='text-left nowrap'>{$vo.total_price_included_excluding_arithmetic_mean|default='-'}</td>
+            <td class='text-left nowrap'>{$vo.total_price_included_excluding_valid_sample_size|default=''}</td>
+
+            <td class='text-left nowrap'>{$vo.single_party_cost_tax_interval|default=''}</td>
+            <td class='text-left nowrap'>{$vo.single_party_cost_tax_arithmetic_mean|default='-'}</td>
+            <td class='text-left nowrap'>{$vo.single_party_cost_tax_valid_sample_size|default=''}</td>
+
+            <td class='text-left nowrap'>{$vo.single_party_cost_no_tax_interval|default=''}</td>
+            <td class='text-left nowrap'>{$vo.single_party_cost_no_tax_arithmetic_mean|default='-'}</td>
+            <td class='text-left nowrap'>{$vo.single_party_cost_no_tax_valid_sample_size|default=''}</td>
+
+            <td class='text-left nowrap'>{$vo.quantities_interval|default=''}</td>
+            <td class='text-left nowrap'>{$vo.quantities_arithmetic_mean|default='-'}</td>
+            <td class='text-left nowrap'>{$vo.quantities_valid_sample_size|default=''}</td>
+            <td class='text-left nowrap'>{$vo.unilateral_content_interval|default=''}</td>
+            <td class='text-left nowrap'>{$vo.unilateral_content_arithmetic_mean|default='-'}</td>
+            <td class='text-left nowrap'>{$vo.unilateral_content_valid_sample_size|default=''}</td>
+            <td class='text-left nowrap'>{$vo.unilateral_content_excluding_excluding_interval|default=''}</td>
+            <td class='text-left nowrap'>{$vo.unilateral_content_excluding_arithmetic_mean|default='-'}</td>
+            <td class='text-left nowrap'>{$vo.unilateral_content_excluding_valid_sample_size|default=''}</td>
+
+            <td class='text-left nowrap'>{$vo.saleable_single_party_tax_interval|default=''}</td>
+            <td class='text-left nowrap'>{$vo.saleable_single_party_tax_arithmetic_mean|default='-'}</td>
+            <td class='text-left nowrap'>{$vo.saleable_single_party_tax_valid_sample_size|default=''}</td>
+
+            <td class='text-left nowrap'>{$vo.saleable_single_party_no_tax_interval|default=''}</td>
+            <td class='text-left nowrap'>{$vo.saleable_single_party_no_tax_arithmetic_mean|default='-'}</td>
+            <td class='text-left nowrap'>{$vo.saleable_single_party_no_tax_valid_sample_size|default=''}</td>
+
+            <td class='text-left nowrap'>
+                {if auth("see")}
+                <a data-dbclick class="layui-btn layui-btn-sm" style="background-color: #DC2219" data-title="查看" data-open='{:url("see")}?subjects={$vo.cost_project}&ids={$ids}'>查 看</a>
+                {/if}
+            </td>
+        </tr>
+            {foreach $vo['children'] as $k=>$v}
+            <tr class="t tr_{$vo.id} tr_{$v.id} trs_{$vo.id}" style="display: none">
+                <td class='text-left nowrap'
+                    onclick='dianji($(this))' data-id="{$v.id}">
+                    <span class="color-desc" style="margin-left: 15px; margin-right: 10px"></span>{$v.cost_project|default=''}
+                    {if count($v['children']) > 0}
+                    <i class="layui-icon layui-icon-triangle-r margin-right-5 icon_{$v.id}"></i>
+                    {/if}
+                </td>
+                <td class='text-left nowrap'>{$v.single_party_cost_interval|default='-'}</td>
+                <td class='text-left nowrap'>{$v.single_party_cost_arithmetic_mean|default=''}</td>
+                <td class='text-left nowrap'>{$v.single_party_cost_valid_sample_size|default=''}</td>
+                <td class='text-left nowrap'>{$v.total_price_included_interval|default=''}</td>
+                <td class='text-left nowrap'>{$v.total_price_included_arithmetic_mean|default='-'}</td>
+                <td class='text-left nowrap'>{$v.total_price_included_valid_sample_size|default=''}</td>
+                <td class='text-left nowrap'>{$v.single_party_cost_excluding_interval|default=''}</td>
+                <td class='text-left nowrap'>{$v.single_party_cost_excluding_arithmetic_mean|default='-'}</td>
+                <td class='text-left nowrap'>{$v.single_party_cost_excluding_valid_sample_size|default=''}</td>
+                <td class='text-left nowrap'>{$v.total_price_included_excluding_interval|default=''}</td>
+                <td class='text-left nowrap'>{$v.total_price_included_excluding_arithmetic_mean|default='-'}</td>
+                <td class='text-left nowrap'>{$v.total_price_included_excluding_valid_sample_size|default=''}</td>
+
+                <td class='text-left nowrap'>{$v.single_party_cost_tax_interval|default=''}</td>
+                <td class='text-left nowrap'>{$v.single_party_cost_tax_arithmetic_mean|default='-'}</td>
+                <td class='text-left nowrap'>{$v.single_party_cost_tax_valid_sample_size|default=''}</td>
+
+                <td class='text-left nowrap'>{$vo.single_party_cost_no_tax_interval|default=''}</td>
+                <td class='text-left nowrap'>{$vo.single_party_cost_no_tax_arithmetic_mean|default='-'}</td>
+                <td class='text-left nowrap'>{$vo.single_party_cost_no_tax_valid_sample_size|default=''}</td>
+
+                <td class='text-left nowrap'>{$v.quantities_interval|default=''}</td>
+                <td class='text-left nowrap'>{$v.quantities_arithmetic_mean|default='-'}</td>
+                <td class='text-left nowrap'>{$v.quantities_valid_sample_size|default=''}</td>
+                <td class='text-left nowrap'>{$v.unilateral_content_interval|default=''}</td>
+                <td class='text-left nowrap'>{$v.unilateral_content_arithmetic_mean|default='-'}</td>
+                <td class='text-left nowrap'>{$v.unilateral_content_valid_sample_size|default=''}</td>
+                <td class='text-left nowrap'>{$v.unilateral_content_excluding_excluding_interval|default=''}</td>
+                <td class='text-left nowrap'>{$v.unilateral_content_excluding_arithmetic_mean|default='-'}</td>
+                <td class='text-left nowrap'>{$v.unilateral_content_excluding_valid_sample_size|default=''}</td>
+
+                <td class='text-left nowrap'>{$v.saleable_single_party_tax_interval|default=''}</td>
+                <td class='text-left nowrap'>{$v.saleable_single_party_tax_arithmetic_mean|default='-'}</td>
+                <td class='text-left nowrap'>{$v.saleable_single_party_tax_valid_sample_size|default=''}</td>
+
+                <td class='text-left nowrap'>{$v.saleable_single_party_no_tax_interval|default=''}</td>
+                <td class='text-left nowrap'>{$v.saleable_single_party_no_tax_arithmetic_mean|default='-'}</td>
+                <td class='text-left nowrap'>{$v.saleable_single_party_no_tax_valid_sample_size|default=''}</td>
+                <td class='text-left nowrap'>
+                    {if auth("see")}
+                    <a data-dbclick class="layui-btn layui-btn-sm" style="background-color: #DC2219" data-title="查看" data-open='{:url("see")}?subjects={$v.cost_project}&ids={$ids}'>查 看</a>
+                    {/if}
+                </td>
+            </tr>
+                {foreach $v['children'] as $k=>$vv}
+                <tr class="t tr_{$v.id} tr_{$vv.id} trs_{$vo.id} trs_{$v.id}" style="display: none">
+                    <td class='text-left nowrap'
+                        onclick='dianji($(this))' data-id="{$vv.id}">
+                        <span class="color-desc" style="margin-left: 15px; margin-right: 20px"></span>{$vv.cost_project|default=''}
+                        {if count($vv['children']) > 0}
+                        <i class="layui-icon layui-icon-triangle-r margin-right-5 icon_{$vv.id}"></i>
+                        {/if}
+                    </td>
+                    <td class='text-left nowrap'>{$vv.single_party_cost_interval|default='-'}</td>
+                    <td class='text-left nowrap'>{$vv.single_party_cost_arithmetic_mean|default=''}</td>
+                    <td class='text-left nowrap'>{$vv.single_party_cost_valid_sample_size|default=''}</td>
+                    <td class='text-left nowrap'>{$vv.total_price_included_interval|default=''}</td>
+                    <td class='text-left nowrap'>{$vv.total_price_included_arithmetic_mean|default='-'}</td>
+                    <td class='text-left nowrap'>{$vv.total_price_included_valid_sample_size|default=''}</td>
+                    <td class='text-left nowrap'>{$vv.single_party_cost_excluding_interval|default=''}</td>
+                    <td class='text-left nowrap'>{$vv.single_party_cost_excluding_arithmetic_mean|default='-'}</td>
+                    <td class='text-left nowrap'>{$vv.single_party_cost_excluding_valid_sample_size|default=''}</td>
+                    <td class='text-left nowrap'>{$vv.total_price_included_excluding_interval|default=''}</td>
+                    <td class='text-left nowrap'>{$vv.total_price_included_excluding_arithmetic_mean|default='-'}</td>
+                    <td class='text-left nowrap'>{$vv.total_price_included_excluding_valid_sample_size|default=''}</td>
+
+                    <td class='text-left nowrap'>{$vv.single_party_cost_tax_interval|default=''}</td>
+                    <td class='text-left nowrap'>{$vv.single_party_cost_tax_arithmetic_mean|default='-'}</td>
+                    <td class='text-left nowrap'>{$vv.single_party_cost_tax_valid_sample_size|default=''}</td>
+
+                    <td class='text-left nowrap'>{$vo.single_party_cost_no_tax_interval|default=''}</td>
+                    <td class='text-left nowrap'>{$vo.single_party_cost_no_tax_arithmetic_mean|default='-'}</td>
+                    <td class='text-left nowrap'>{$vo.single_party_cost_no_tax_valid_sample_size|default=''}</td>
+
+                    <td class='text-left nowrap'>{$vv.quantities_interval|default=''}</td>
+                    <td class='text-left nowrap'>{$vv.quantities_arithmetic_mean|default='-'}</td>
+                    <td class='text-left nowrap'>{$vv.quantities_valid_sample_size|default=''}</td>
+                    <td class='text-left nowrap'>{$vv.unilateral_content_interval|default=''}</td>
+                    <td class='text-left nowrap'>{$vv.unilateral_content_arithmetic_mean|default='-'}</td>
+                    <td class='text-left nowrap'>{$vv.unilateral_content_valid_sample_size|default=''}</td>
+                    <td class='text-left nowrap'>{$vv.unilateral_content_excluding_excluding_interval|default=''}</td>
+                    <td class='text-left nowrap'>{$vv.unilateral_content_excluding_arithmetic_mean|default='-'}</td>
+                    <td class='text-left nowrap'>{$vv.unilateral_content_excluding_valid_sample_size|default=''}</td>
+
+                    <td class='text-left nowrap'>{$vv.saleable_single_party_tax_interval|default=''}</td>
+                    <td class='text-left nowrap'>{$vv.saleable_single_party_tax_arithmetic_mean|default='-'}</td>
+                    <td class='text-left nowrap'>{$vv.saleable_single_party_tax_valid_sample_size|default=''}</td>
+
+                    <td class='text-left nowrap'>{$vv.saleable_single_party_no_tax_interval|default=''}</td>
+                    <td class='text-left nowrap'>{$vv.saleable_single_party_no_tax_arithmetic_mean|default='-'}</td>
+                    <td class='text-left nowrap'>{$vv.saleable_single_party_no_tax_valid_sample_size|default=''}</td>
+                    <td class='text-left nowrap'>
+                        {if auth("see")}
+                        <a data-dbclick class="layui-btn layui-btn-sm" style="background-color: #DC2219" data-title="查看" data-open='{:url("see")}?subjects={$vv.cost_project}&ids={$ids}'>查 看</a>
+                        {/if}
+                    </td>
+                </tr>
+                    {foreach $vv['children'] as $k=>$vvv}
+                    <tr class="t tr_{$vv.id} tr_{$vvv.id} trs_{$vo.id} trs_{$v.id} trs_{$vv.id}" style="display: none">
+                        <td class='text-left nowrap'
+                            onclick='dianji($(this))' data-id="{$vvv.id}">
+                            <span class="color-desc" style="margin-left: 15px; margin-right: 30px"></span>{$vvv.cost_project|default=''}
+                            {if count($vvv['children']) > 0}
+                            <i class="layui-icon layui-icon-triangle-r margin-right-5 icon_{$vvv.id}"></i>
+                            {/if}
+                        </td>
+                        <td class='text-left nowrap'>{$vvv.single_party_cost_interval|default='-'}</td>
+                        <td class='text-left nowrap'>{$vvv.single_party_cost_arithmetic_mean|default=''}</td>
+                        <td class='text-left nowrap'>{$vvv.single_party_cost_valid_sample_size|default=''}</td>
+                        <td class='text-left nowrap'>{$vvv.total_price_included_interval|default=''}</td>
+                        <td class='text-left nowrap'>{$vvv.total_price_included_arithmetic_mean|default='-'}</td>
+                        <td class='text-left nowrap'>{$vvv.total_price_included_valid_sample_size|default=''}</td>
+                        <td class='text-left nowrap'>{$vvv.single_party_cost_excluding_interval|default=''}</td>
+                        <td class='text-left nowrap'>{$vvv.single_party_cost_excluding_arithmetic_mean|default='-'}</td>
+                        <td class='text-left nowrap'>{$vvv.single_party_cost_excluding_valid_sample_size|default=''}</td>
+                        <td class='text-left nowrap'>{$vvv.total_price_included_excluding_interval|default=''}</td>
+                        <td class='text-left nowrap'>{$vvv.total_price_included_excluding_arithmetic_mean|default='-'}</td>
+                        <td class='text-left nowrap'>{$vvv.total_price_included_excluding_valid_sample_size|default=''}</td>
+
+                        <td class='text-left nowrap'>{$vvv.single_party_cost_tax_interval|default=''}</td>
+                        <td class='text-left nowrap'>{$vvv.single_party_cost_tax_arithmetic_mean|default='-'}</td>
+                        <td class='text-left nowrap'>{$vvv.single_party_cost_tax_valid_sample_size|default=''}</td>
+
+                        <td class='text-left nowrap'>{$vvv.single_party_cost_no_tax_interval|default=''}</td>
+                        <td class='text-left nowrap'>{$vvv.single_party_cost_no_tax_arithmetic_mean|default='-'}</td>
+                        <td class='text-left nowrap'>{$vvv.single_party_cost_no_tax_valid_sample_size|default=''}</td>
+
+                        <td class='text-left nowrap'>{$vvv.quantities_interval|default=''}</td>
+                        <td class='text-left nowrap'>{$vvv.quantities_arithmetic_mean|default='-'}</td>
+                        <td class='text-left nowrap'>{$vvv.quantities_valid_sample_size|default=''}</td>
+                        <td class='text-left nowrap'>{$vvv.unilateral_content_interval|default=''}</td>
+                        <td class='text-left nowrap'>{$vvv.unilateral_content_arithmetic_mean|default='-'}</td>
+                        <td class='text-left nowrap'>{$vvv.unilateral_content_valid_sample_size|default=''}</td>
+                        <td class='text-left nowrap'>{$vvv.unilateral_content_excluding_excluding_interval|default=''}</td>
+                        <td class='text-left nowrap'>{$vvv.unilateral_content_excluding_arithmetic_mean|default='-'}</td>
+                        <td class='text-left nowrap'>{$vvv.unilateral_content_excluding_valid_sample_size|default=''}</td>
+
+                        <td class='text-left nowrap'>{$vvv.saleable_single_party_tax_interval|default=''}</td>
+                        <td class='text-left nowrap'>{$vvv.saleable_single_party_tax_arithmetic_mean|default='-'}</td>
+                        <td class='text-left nowrap'>{$vvv.saleable_single_party_tax_valid_sample_size|default=''}</td>
+
+                        <td class='text-left nowrap'>{$vvv.saleable_single_party_no_tax_interval|default=''}</td>
+                        <td class='text-left nowrap'>{$vvv.saleable_single_party_no_tax_arithmetic_mean|default='-'}</td>
+                        <td class='text-left nowrap'>{$vvv.saleable_single_party_no_tax_valid_sample_size|default=''}</td>
+                        <td class='text-left nowrap'>
+                            {if auth("see")}
+                            <a data-dbclick class="layui-btn layui-btn-sm" style="background-color: #DC2219" data-title="查看" data-open='{:url("see")}?subjects={$vvv.cost_project}&ids={$ids}'>查 看</a>
+                            {/if}
+                        </td>
+                    </tr>
+                        {foreach $vvv['children'] as $k=>$vvvv}
+                        <tr class="t tr_{$vvv.id}  tr_{$vvvv.id} trs_{$vo.id} trs_{$v.id} trs_{$vv.id} trs_{$vvv.id}" style="display: none">
+                            <td class='text-left nowrap'
+                                onclick='dianji($(this))' data-id="{$vvvv.id}">
+                                <span class="color-desc" style="margin-left: 15px; margin-right: 40px"></span>{$vvvv.cost_project|default=''}
+                                {if count($vvvv['children']) > 0}
+                                <i class="layui-icon layui-icon-triangle-r margin-right-5 icon_{$vvvv.id}"></i>
+                                {/if}
+                            </td>
+                            <td class='text-left nowrap'>{$vvvv.single_party_cost_interval|default='-'}</td>
+                            <td class='text-left nowrap'>{$vvvv.single_party_cost_arithmetic_mean|default=''}</td>
+                            <td class='text-left nowrap'>{$vvvv.single_party_cost_valid_sample_size|default=''}</td>
+                            <td class='text-left nowrap'>{$vvvv.total_price_included_interval|default=''}</td>
+                            <td class='text-left nowrap'>{$vvvv.total_price_included_arithmetic_mean|default='-'}</td>
+                            <td class='text-left nowrap'>{$vvvv.total_price_included_valid_sample_size|default=''}</td>
+                            <td class='text-left nowrap'>{$vvvv.single_party_cost_excluding_interval|default=''}</td>
+                            <td class='text-left nowrap'>{$vvvv.single_party_cost_excluding_arithmetic_mean|default='-'}</td>
+                            <td class='text-left nowrap'>{$vvvv.single_party_cost_excluding_valid_sample_size|default=''}</td>
+                            <td class='text-left nowrap'>{$vvvv.total_price_included_excluding_interval|default=''}</td>
+                            <td class='text-left nowrap'>{$vvvv.total_price_included_excluding_arithmetic_mean|default='-'}</td>
+                            <td class='text-left nowrap'>{$vvvv.total_price_included_excluding_valid_sample_size|default=''}</td>
+
+                            <td class='text-left nowrap'>{$vvvv.single_party_cost_tax_interval|default=''}</td>
+                            <td class='text-left nowrap'>{$vvvv.single_party_cost_tax_arithmetic_mean|default='-'}</td>
+                            <td class='text-left nowrap'>{$vvvv.single_party_cost_tax_valid_sample_size|default=''}</td>
+
+                            <td class='text-left nowrap'>{$vvvv.single_party_cost_no_tax_interval|default=''}</td>
+                            <td class='text-left nowrap'>{$vvvv.single_party_cost_no_tax_arithmetic_mean|default='-'}</td>
+                            <td class='text-left nowrap'>{$vvvv.single_party_cost_no_tax_valid_sample_size|default=''}</td>
+
+                            <td class='text-left nowrap'>{$vvvv.quantities_interval|default=''}</td>
+                            <td class='text-left nowrap'>{$vvvv.quantities_arithmetic_mean|default='-'}</td>
+                            <td class='text-left nowrap'>{$vvvv.quantities_valid_sample_size|default=''}</td>
+                            <td class='text-left nowrap'>{$vvvv.unilateral_content_interval|default=''}</td>
+                            <td class='text-left nowrap'>{$vvvv.unilateral_content_arithmetic_mean|default='-'}</td>
+                            <td class='text-left nowrap'>{$vvvv.unilateral_content_valid_sample_size|default=''}</td>
+                            <td class='text-left nowrap'>{$vvvv.unilateral_content_excluding_excluding_interval|default=''}</td>
+                            <td class='text-left nowrap'>{$vvvv.unilateral_content_excluding_arithmetic_mean|default='-'}</td>
+                            <td class='text-left nowrap'>{$vvvv.unilateral_content_excluding_valid_sample_size|default=''}</td>
+
+                            <td class='text-left nowrap'>{$vvvv.saleable_single_party_tax_interval|default=''}</td>
+                            <td class='text-left nowrap'>{$vvvv.saleable_single_party_tax_arithmetic_mean|default='-'}</td>
+                            <td class='text-left nowrap'>{$vvvv.saleable_single_party_tax_valid_sample_size|default=''}</td>
+
+                            <td class='text-left nowrap'>{$vvvv.saleable_single_party_no_tax_interval|default=''}</td>
+                            <td class='text-left nowrap'>{$vvvv.saleable_single_party_no_tax_arithmetic_mean|default='-'}</td>
+                            <td class='text-left nowrap'>{$vvvv.saleable_single_party_no_tax_valid_sample_size|default=''}</td>
+                            <td class='text-left nowrap'>
+                                {if auth("see")}
+                                <a data-dbclick class="layui-btn layui-btn-sm" style="background-color: #DC2219" data-title="查看" data-open='{:url("see")}?subjects={$vvvv.cost_project}&ids={$ids}'>查 看</a>
+                                {/if}
+                            </td>
+                        </tr>
+                            {foreach $vvvv['children'] as $k=>$vvvvv}
+                            <tr class="t tr_{$vvvv.id} tr_{$vvvvv.id} trs_{$vo.id} trs_{$v.id} trs_{$vv.id} trs_{$vvv.id} trs_{$vvvv.id}" style="display: none">
+                                <td class='text-left nowrap'
+                                    onclick='dianji($(this))' data-id="{$vvvvv.id}">
+                                    <span class="color-desc" style="margin-left: 15px; margin-right: 50px"></span>{$vvvvv.cost_project|default=''}
+                                    {if count($vvvvv['children']) > 0}
+                                    <i class="layui-icon layui-icon-triangle-r margin-right-5 icon_{$vvvvv.id}"></i>
+                                    {/if}
+                                </td>
+                                <td class='text-left nowrap'>{$vvvvv.single_party_cost_interval|default='-'}</td>
+                                <td class='text-left nowrap'>{$vvvvv.single_party_cost_arithmetic_mean|default=''}</td>
+                                <td class='text-left nowrap'>{$vvvvv.single_party_cost_valid_sample_size|default=''}</td>
+                                <td class='text-left nowrap'>{$vvvvv.total_price_included_interval|default=''}</td>
+                                <td class='text-left nowrap'>{$vvvvv.total_price_included_arithmetic_mean|default='-'}</td>
+                                <td class='text-left nowrap'>{$vvvvv.total_price_included_valid_sample_size|default=''}</td>
+                                <td class='text-left nowrap'>{$vvvvv.single_party_cost_excluding_interval|default=''}</td>
+                                <td class='text-left nowrap'>{$vvvvv.single_party_cost_excluding_arithmetic_mean|default='-'}</td>
+                                <td class='text-left nowrap'>{$vvvvv.single_party_cost_excluding_valid_sample_size|default=''}</td>
+                                <td class='text-left nowrap'>{$vvvvv.total_price_included_excluding_interval|default=''}</td>
+                                <td class='text-left nowrap'>{$vvvvv.total_price_included_excluding_arithmetic_mean|default='-'}</td>
+                                <td class='text-left nowrap'>{$vvvvv.total_price_included_excluding_valid_sample_size|default=''}</td>
+
+                                <td class='text-left nowrap'>{$vvvvv.single_party_cost_tax_interval|default=''}</td>
+                                <td class='text-left nowrap'>{$vvvvv.single_party_cost_tax_arithmetic_mean|default='-'}</td>
+                                <td class='text-left nowrap'>{$vvvvv.single_party_cost_tax_valid_sample_size|default=''}</td>
+
+                                <td class='text-left nowrap'>{$vvvvv.single_party_cost_no_tax_interval|default=''}</td>
+                                <td class='text-left nowrap'>{$vvvvv.single_party_cost_no_tax_arithmetic_mean|default='-'}</td>
+                                <td class='text-left nowrap'>{$vvvvv.single_party_cost_no_tax_valid_sample_size|default=''}</td>
+
+                                <td class='text-left nowrap'>{$vvvvv.quantities_interval|default=''}</td>
+                                <td class='text-left nowrap'>{$vvvvv.quantities_arithmetic_mean|default='-'}</td>
+                                <td class='text-left nowrap'>{$vvvvv.quantities_valid_sample_size|default=''}</td>
+                                <td class='text-left nowrap'>{$vvvvv.unilateral_content_interval|default=''}</td>
+                                <td class='text-left nowrap'>{$vvvvv.unilateral_content_arithmetic_mean|default='-'}</td>
+                                <td class='text-left nowrap'>{$vvvvv.unilateral_content_valid_sample_size|default=''}</td>
+                                <td class='text-left nowrap'>{$vvvvv.unilateral_content_excluding_excluding_interval|default=''}</td>
+                                <td class='text-left nowrap'>{$vvvvv.unilateral_content_excluding_arithmetic_mean|default='-'}</td>
+                                <td class='text-left nowrap'>{$vvvvv.unilateral_content_excluding_valid_sample_size|default=''}</td>
+
+                                <td class='text-left nowrap'>{$vvvvv.saleable_single_party_tax_interval|default=''}</td>
+                                <td class='text-left nowrap'>{$vvvvv.saleable_single_party_tax_arithmetic_mean|default='-'}</td>
+                                <td class='text-left nowrap'>{$vvvvv.saleable_single_party_tax_valid_sample_size|default=''}</td>
+
+                                <td class='text-left nowrap'>{$vvvvv.saleable_single_party_no_tax_interval|default=''}</td>
+                                <td class='text-left nowrap'>{$vvvvv.saleable_single_party_no_tax_arithmetic_mean|default='-'}</td>
+                                <td class='text-left nowrap'>{$vvvvv.saleable_single_party_no_tax_valid_sample_size|default=''}</td>
+                                <td class='text-left nowrap'>
+                                    {if auth("see")}
+                                    <a data-dbclick class="layui-btn layui-btn-sm" style="background-color: #DC2219" data-title="查看" data-open='{:url("see")}?subjects={$vvvvv.cost_project}&ids={$ids}'>查 看</a>
+                                    {/if}
+                                </td>
+                            </tr>
+                            {/foreach}
+                        {/foreach}
+                    {/foreach}
+                {/foreach}
+            {/foreach}
+        {/foreach}
+        </tbody>
+    </table>
+
+    {empty name='list'}<span class="notdata">没有记录哦</span>{else}{$pagehtml|raw|default=''}{/empty}
+
+</div>
+<script>
+    function getIds()
+    {
+        var ids = $("#ids").val();
+        window.location = '{:url("admin/child_project/download")}?ids=' +ids;
+    }
+    function dianji(e){
+        var id=e.attr('data-id');
+        var tr=e. parents('tr');
+
+        if(tr.hasClass('flag')){
+
+
+            $('.trs_'+id).hide();
+
+
+            tr.find('i').removeClass('layui-icon-triangle-d')
+            tr.find('i').addClass('layui-icon-triangle-r')
+
+            $('.trs_'+id).find('i').removeClass('layui-icon-triangle-d')
+            $('.trs_'+id).find('i').addClass('layui-icon-triangle-r')
+
+            $('.trs_'+id).removeClass('flag')
+            tr.removeClass('flag')
+        }else{
+
+
+            e.find('i').removeClass('layui-icon-triangle-r')
+            e.find('i').addClass('layui-icon-triangle-d')
+            $('.tr_'+id).show();
+            tr.addClass('flag')
+
+
+
+        }
+
+
+
+
+
+
+
+
+
+
+
+
+    }
+</script>
+{/block}

+ 108 - 0
application/admin/view/child_project/contrast1.html

@@ -0,0 +1,108 @@
+{extend name='main'}
+
+{block name="button"}
+
+{if auth("contrast")}
+<button class="layui-btn layui-btn-sm layui-btn-primary layui-bg-red" onclick="getIds()" >导出</button>
+{/if}
+
+<button class="layui-btn" style="height: 30px;line-height:28px;background-color: snow;color: #333;border: 1px solid #C9C9C9 " type='button' onclick="window.history.back()">返 回</button>
+
+
+{/block}
+
+{block name="content"}
+<div class="think-box-shadow">
+    <table class="layui-table margin-top-10">
+        <input type="hidden" name="ids" id="ids" value="{$ids}">
+        {notempty name='list'}
+        <thead>
+        <tr>
+            <th class='text-left nowrap' rowspan="2">成本项目</th>
+            <th class='text-center nowrap' colspan="3">建面单方成本(元/m2)(含税)</th>
+            <th class='text-center nowrap' colspan="3">总价(万元)(含税)</th>
+            <th class='text-center nowrap' colspan="3">建面单方成本(元/m2)(不含税)</th>
+            <th class='text-center nowrap' colspan="3">总价(万元)(不含税)</th>
+            <th class='text-center nowrap' colspan="3">工程量</th>
+            <th class='text-center nowrap' colspan="3">单方含量(含税)</th>
+            <th class='text-center nowrap' colspan="3">单方含量(不含税)</th>
+            <th class='text-center nowrap' rowspan="2">操作</th>
+        </tr>
+        <tr style="border: 1px">
+            <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>
+            <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>
+            <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>
+        {/notempty}
+        <tbody>
+        {foreach $list as $key=>$vo}
+        <tr style="border: 1px">
+
+            <td class='text-left nowrap'>{$vo.cost_project|default=''}</td>
+            <td class='text-left nowrap'>{$vo.single_party_cost_interval|default='-'}</td>
+            <td class='text-left nowrap'>{$vo.single_party_cost_arithmetic_mean|default=''}</td>
+            <td class='text-left nowrap'>{$vo.single_party_cost_valid_sample_size|default=''}</td>
+
+            <td class='text-left nowrap'>{$vo.total_price_included_interval|default=''}</td>
+            <td class='text-left nowrap'>{$vo.total_price_included_arithmetic_mean|default='-'}</td>
+            <td class='text-left nowrap'>{$vo.total_price_included_valid_sample_size|default=''}</td>
+
+            <td class='text-left nowrap'>{$vo.single_party_cost_excluding_interval|default=''}</td>
+            <td class='text-left nowrap'>{$vo.single_party_cost_excluding_arithmetic_mean|default='-'}</td>
+            <td class='text-left nowrap'>{$vo.single_party_cost_excluding_valid_sample_size|default=''}</td>
+
+            <td class='text-left nowrap'>{$vo.total_price_included_excluding_interval|default=''}</td>
+            <td class='text-left nowrap'>{$vo.total_price_included_excluding_arithmetic_mean|default='-'}</td>
+            <td class='text-left nowrap'>{$vo.total_price_included_excluding_valid_sample_size|default=''}</td>
+
+            <td class='text-left nowrap'>{$vo.quantities_interval|default=''}</td>
+            <td class='text-left nowrap'>{$vo.quantities_arithmetic_mean|default='-'}</td>
+            <td class='text-left nowrap'>{$vo.quantities_valid_sample_size|default=''}</td>
+
+            <td class='text-left nowrap'>{$vo.unilateral_content_interval|default=''}</td>
+            <td class='text-left nowrap'>{$vo.unilateral_content_arithmetic_mean|default='-'}</td>
+            <td class='text-left nowrap'>{$vo.unilateral_content_valid_sample_size|default=''}</td>
+
+            <td class='text-left nowrap'>{$vo.unilateral_content_excluding_excluding_interval|default=''}</td>
+            <td class='text-left nowrap'>{$vo.unilateral_content_excluding_arithmetic_mean|default='-'}</td>
+            <td class='text-left nowrap'>{$vo.unilateral_content_excluding_valid_sample_size|default=''}</td>
+            <td class='text-left nowrap'>
+                {if auth("look")}
+                <a data-dbclick class="layui-btn layui-btn-sm layui-bg-red" data-title="查看" data-open='{:url("look")}'>查 看</a>
+                {/if}
+            </td>
+        </tr>
+        {/foreach}
+        </tbody>
+    </table>
+
+    {empty name='list'}<span class="notdata">没有记录哦</span>{else}{$pagehtml|raw|default=''}{/empty}
+
+</div>
+<script>
+    function getIds()
+    {
+        var ids = $("#ids").val();
+        window.location = '{:url("admin/child_project/download")}?ids=' +ids;
+    }
+</script>
+{/block}

+ 400 - 0
application/admin/view/child_project/form.html

@@ -0,0 +1,400 @@
+{extend name='main'}
+{block name="button"}
+{if auth("add")}
+<button class="layui-btn" style="height: 30px;line-height:28px;background-color:#DC2219;color: #FFFFFF;border: 1px solid #C9C9C9 " type='button' onclick="window.history.back()">返 回</button>
+{/if}
+
+
+{/block}
+{block name="content"}
+
+<form onsubmit="return false;" id="GoodsForm" data-auto="true" method="post" class='layui-form layui-card' autocomplete="off">
+
+    <div class="layui-card-body think-box-shadow padding-left-40">
+
+        <div class="layui-form-item layui-row layui-col-space15">
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">选择主项目</span>
+                <select name='main_project_id' class='layui-select' required lay-verify="required" lay-search>
+                    <option value=''>请选择</option>
+                    {if isset($vo.id)}
+                    <!--{foreach $main_list as $menu}-->
+                    <!--{eq name='menu.id' value='$vo.main_project_id'}-->
+                    <option selected value='{$menu.id}'>{$menu.project_name}</option>
+                    <!--{else}-->
+                    <option value='{$menu.id}'>{$menu.project_name}</option>
+                    <!--{/eq}-->
+                    <!--{/foreach}-->
+                    {else}
+                    <!--{foreach $main_list as $menu}-->
+                    <option value='{$menu.id}'>{$menu.project_name}</option>
+                    <!--{/foreach}-->
+                    {/if}
+                </select>
+            </label>
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">项目名称</span>
+                <input name="project_name" required class="layui-input" placeholder="请输入项目名称" value="{$vo.project_name|default=''}">
+            </label>
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">建筑分类</span>
+
+                <select name='category_id' class='layui-select' required lay-verify="required" lay-search>
+                    <option value=''>请选择</option>
+                    {if isset($vo.id)}
+                    <!--{foreach $menus as $menu}-->
+                    <!--{eq name='menu.id' value='$vo.category_id'}-->
+                    <option selected value='{$menu.id}'>{$menu.spl|raw}{$menu.title}</option>
+                    <!--{else}-->
+                    <option value='{$menu.id}'>{$menu.spl|raw}{$menu.title}</option>
+                    <!--{/eq}-->
+                    <!--{/foreach}-->
+                    {else}
+                    <!--{foreach $menus as $menu}-->
+                    <option value='{$menu.id}'>{$menu.spl|raw}{$menu.title}</option>
+                    <!--{/foreach}-->
+                    {/if}
+                </select>
+
+            </label>
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">建筑高度</span>
+                <input name="building_height" required class="layui-input" placeholder="请输入建筑高度" value="{$vo.building_height|default=''}">
+            </label>
+        </div>
+
+        <div class="layui-form-item layui-row layui-col-space15">
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">建筑层数</span>
+                <input name="construction_layer" required class="layui-input" placeholder="请输入建筑层数" value="{$vo.construction_layer|default=''}">
+            </label>
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">地上层数</span>
+                <input name="upper_number" required class="layui-input" placeholder="请输入地上层数" value="{$vo.upper_number|default=''}">
+            </label>
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">地下层数</span>
+                <input name="underground" class="layui-input" placeholder="请输入地下层数" value="{$vo.underground|default=''}">
+            </label>
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">地下层高</span>
+                <input name="underground_layer" class="layui-input" placeholder="请输入地下层高" value="{$vo.underground_layer|default=''}">
+            </label>
+
+        </div>
+        <div class="layui-form-item layui-row layui-col-space15">
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">首层层高</span>
+                <input name="first_layer_high" class="layui-input" placeholder="请输入首层层高" value="{$vo.first_layer_high|default=''}">
+            </label>
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">标准层层高</span>
+                <input name="standard_height" class="layui-input" placeholder="请输入标准层层高" value="{$vo.standard_height|default=''}">
+            </label>
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">结构类型</span>
+                <select name="structure_type" required class="province-selector layui-select" id="structure_type" lay-verify="required" lay-search   >
+                    <option value="">请选择</option>
+                    {if isset($vo.id) && $vo.id neq ''}
+                    {foreach ['框架结构'=>'框架结构','剪力墙结构'=>'剪力墙结构','框架剪力墙结构'=>'框架剪力墙结构','断肢剪力墙结构'=>'断肢剪力墙结构','砖混结构'=>'砖混结构','钢结构'=>'钢结构','装配式混泥土结构'=>'装配式混泥土结构','框架简体结构'=>'框架简体结构'] as $k=>$v}
+                    {if $v eq $vo.structure_type}
+                    <option selected value="{$k}">{$v}</option>
+                    {else}
+                    <option value="{$k}">{$v}</option>
+                    {/if}
+                    {/foreach}
+                    {else}
+                    {foreach ['框架结构'=>'框架结构','剪力墙结构'=>'剪力墙结构','框架剪力墙结构'=>'框架剪力墙结构','断肢剪力墙结构'=>'断肢剪力墙结构','砖混结构'=>'砖混结构','钢结构'=>'钢结构','装配式混泥土结构'=>'装配式混泥土结构','框架简体结构'=>'框架简体结构'] as $k=>$v}
+                    <option value="{$k}">{$v}</option>
+                    {/foreach}
+                    {/if}
+
+                </select>
+            </label>
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">建筑设防烈度</span>
+                <select name="building_fortification_intensity" required class="province-selector layui-select" id="building_fortification_intensity" lay-verify="required" lay-search   >
+                    <option value="">请选择</option>
+                    {if isset($vo.id) && $vo.id neq ''}
+                    {foreach ['6度'=>'6度','7度'=>'7度','8度'=>'8度','9度'=>'9度'] as $k=>$v}
+                    {if $v eq $vo.building_fortification_intensity}
+                    <option selected value="{$k}">{$v}</option>
+                    {else}
+                    <option value="{$k}">{$v}</option>
+                    {/if}
+                    {/foreach}
+                    {else}
+                    {foreach ['6度'=>'6度','7度'=>'7度','8度'=>'8度','9度'=>'9度'] as $k=>$v}
+                    <option value="{$k}">{$v}</option>
+                    {/foreach}
+                    {/if}
+
+                </select>
+            </label>
+
+        </div>
+
+        <div class="layui-form-item layui-row layui-col-space15">
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">抗震等级</span>
+                <select name="seismic_grade" required class="province-selector layui-select" id="seismic_grade" lay-verify="required" lay-search   >
+                    <option value="">请选择</option>
+                    {if isset($vo.id) && $vo.id neq ''}
+                    {foreach ['一级'=>'一级','二级'=>'二级','三级'=>'三级','四级'=>'四级'] as $k=>$v}
+                    {if $v eq $vo.seismic_grade}
+                    <option selected value="{$k}">{$v}</option>
+                    {else}
+                    <option value="{$k}">{$v}</option>
+                    {/if}
+                    {/foreach}
+                    {else}
+                    {foreach ['一级'=>'一级','二级'=>'二级','三级'=>'三级','四级'=>'四级'] as $k=>$v}
+                    <option value="{$k}">{$v}</option>
+                    {/foreach}
+                    {/if}
+
+                </select>
+            </label>
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">设计寿命</span>
+                <input name="design_life" class="layui-input" placeholder="请输入设计寿命" value="{$vo.design_life|default=''}">
+            </label>
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">基础类型</span>
+                <select name="base_type" required class="province-selector layui-select" id="base_type" lay-verify="required" lay-search   >
+                    <option value="">请选择</option>
+                    {if isset($vo.id) && $vo.id neq ''}
+                    {foreach ['不包含'=>'不包含','独立基础'=>'独立基础','条形基础'=>'条形基础','满堂基础'=>'满堂基础','桩基础'=>'桩基础','桩承台基础'=>'桩承台基础','混合基础'=>'混合基础','带形基础'=>'带形基础','筏板基础'=>'筏板基础','砖基础'=>'砖基础'] as $k=>$v}
+                    {if $v eq $vo.base_type}
+                    <option selected value="{$k}">{$v}</option>
+                    {else}
+                    <option value="{$k}">{$v}</option>
+                    {/if}
+                    {/foreach}
+                    {else}
+                    {foreach ['不包含'=>'不包含','独立基础'=>'独立基础','条形基础'=>'条形基础','满堂基础'=>'满堂基础','桩基础'=>'桩基础','桩承台基础'=>'桩承台基础','混合基础'=>'混合基础','带形基础'=>'带形基础','筏板基础'=>'筏板基础','砖基础'=>'砖基础'] as $k=>$v}
+                    <option value="{$k}">{$v}</option>
+                    {/foreach}
+                    {/if}
+
+                </select>
+            </label>
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">装修标准</span>
+                <input name="decorate_standard" class="layui-input" placeholder="请输入装修标准" value="{$vo.decorate_standard|default=''}">
+            </label>
+
+        </div>
+        <div class="layui-form-item layui-row layui-col-space15">
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">其他参数</span>
+                <input name="other_parameters" class="layui-input" placeholder="请输入其他参数" value="{$vo.other_parameters|default=''}">
+            </label>
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">建筑面积</span>
+                <input name="construction_area" required class="layui-input" placeholder="请输入建筑面积" value="{$vo.construction_area|default=''}">
+            </label>
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">地上建筑面积</span>
+                <input name="ground_floor_area" required class="layui-input" placeholder="请输入地上建筑面积" value="{$vo.ground_floor_area|default=''}">
+            </label>
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">地下建筑面积</span>
+                <input name="underground_floor_area" required class="layui-input" placeholder="请输入地下建筑面积" value="{$vo.underground_floor_area|default=''}">
+            </label>
+
+        </div>
+
+        <div class="layui-form-item layui-row layui-col-space15">
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">建筑占地面积</span>
+                <input name="building_floor_area" class="layui-input" placeholder="请输入建筑占地面积" value="{$vo.building_floor_area|default=''}">
+            </label>
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">钢结构受益面积</span>
+                <input name="steel_benefit_area" class="layui-input" placeholder="请输入钢结构受益面积" value="{$vo.steel_benefit_area|default=''}">
+            </label>
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">木质构件面积</span>
+                <input name="wood_area"  class="layui-input" placeholder="请输入木质构件面积" value="{$vo.wood_area|default=''}">
+            </label>
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">可售面积</span>
+                <input name="available_area" class="layui-input" placeholder="请输入可售面积" value="{$vo.available_area|default=''}">
+            </label>
+
+        </div>
+
+        <div class="layui-form-item layui-row layui-col-space15">
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">户数</span>
+                <input name="number" class="layui-input" placeholder="请输入户数" value="{$vo.number|default=''}">
+            </label>
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">地下室底面积</span>
+                <input name="basement_floor_area" class="layui-input" placeholder="请输入地下室底面积" value="{$vo.basement_floor_area|default=''}">
+            </label>
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">其他说明</span>
+                <input name="other_instructions"  class="layui-input" placeholder="请输入其他说明" value="{$vo.other_instructions|default=''}">
+            </label>
+
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">模板类型</span>
+
+                <select name='template' class='layui-select' required lay-verify="required" lay-search>
+                    <option value=''>请选择</option>
+                    {if isset($vo.id)}
+                    <!--{foreach $template as $menu}-->
+                    <!--{eq name='menu.id' value='$vo.template'}-->
+                    <option selected value='{$menu.id}'>{$menu.title}</option>
+                    <!--{else}-->
+                    <option value='{$menu.id}'>{$menu.title}</option>
+                    <!--{/eq}-->
+                    <!--{/foreach}-->
+                    {else}
+                    <!--{foreach $template as $menu}-->
+                    <option value='{$menu.id}'>{$menu.title}</option>
+                    <!--{/foreach}-->
+                    {/if}
+                </select>
+
+            </label>
+        </div>
+
+
+
+        <div class="layui-form-item text-center">
+            {if isset($vo.id) && $vo.id neq ''}<input type='hidden' value="<?php echo date('Y-m-d H:i:s'); ?>" name='update_at'>{else}<input type='hidden' value="<?php echo date('Y-m-d H:i:s'); ?>" name='create_at'>{/if}
+            {notempty name='vo.id'}<input type="hidden" name="id" value="{$vo.id}">{/notempty}
+            <button class="layui-btn layui-btn-danger" ng-click="hsitoryBack()" onclick="window.history.back()" type="button">取消</button>
+            <button class="layui-btn" type="submit" lay-submit >确定</button>
+        </div>
+
+
+    </div>
+</form>
+{/block}
+
+{block name='script'}
+<script>
+    window.form.render();
+    layui.use(['form', 'layedit', 'laydate'], function(){
+        var form = layui.form
+            ,layer = layui.layer
+            ,layedit = layui.layedit
+            ,laydate = layui.laydate;
+
+        //常规用法
+        laydate.render({
+            elem: '#test1'
+        });
+        laydate.render({
+            elem: '#test2',
+            done:function (value,date) {
+                var endtime = $("#test3").val()
+                if (endtime!=''){
+                    changeday(value,endtime)
+                }
+            }
+
+        });
+        laydate.render({
+            elem: '#test3',
+            done:function (value,date) {
+                var starttime = $("#test2").val()
+                if (starttime!=''){
+                    changeday(starttime,value)
+                }
+
+            }
+        });
+
+        form.on('select(province)', function (data) {
+            var val = data.value;
+             console.log(val)
+            $.ajax({
+                type:"get",
+                url:"{:url('MainProject/get_city')}",  //数据传输的控制器方法
+                data: {id:val},//这里data传递过去的是序列化以后的字符串
+                success:function(data){
+                    //console.log(data)
+                    var arr = data.data;
+                    //console.log(arr)
+                    if (arr.length>0){
+                        //$("#tow").attr("style","display:block;");//显示div
+                        var options='<option value="">请选择市</option>';
+                        for (var i = 0; i < arr.length; i++) {
+                            var tag = arr[i];
+                            options+=' <option value="'+tag.name+'">'+tag.name+'</option>';
+                        }
+                        $("select[name='construction_site_city']").html(options)
+                        form.render('select');
+                    }else {
+                        var options='<option value="">请选择市</option>';
+                        $("select[name='construction_site_city']").html(options)
+                        form.render('select');
+                    }
+                }
+            });
+        });
+
+        form.on('select(city)', function (data) {
+            var val = data.value;
+            // console.log(val)
+            $.ajax({
+                type:"get",
+                url:"{:url('MainProject/get_area')}",  //数据传输的控制器方法
+                data: {id:val},//这里data传递过去的是序列化以后的字符串
+                success:function(data){
+                    //console.log(data)
+                    var arr = data.data;
+                    // console.log(arr)
+                    if (arr.length>0){
+                        var options='<option value="">请选择区</option>';
+                        for (var i = 0; i < arr.length; i++) {
+                            var tag = arr[i];
+                            options+=' <option value="'+tag.name+'">'+tag.name+'</option>';
+                        }
+                        $("select[name='construction_site_area']").html(options)
+                        form.render('select');
+                    }else {
+                        var options='<option value="">请选择区</option>';
+                        $("select[name='construction_site_area']").html(options)
+                        form.render('select');
+                    }
+                }
+            });
+        });
+
+    });
+
+    function changeday(startdate,enddate) {
+        var day = 0;
+        if (startdate==enddate){
+            day = 1;
+        }else if (startdate>enddate){
+            day = 0;
+        }else {
+            day = getDaysBetween(startdate,enddate) + 1
+        }
+        $("#project_time").attr("value",day);
+    }
+
+    //计算两个日期相差的天数
+    function  getDaysBetween(dateString1,dateString2){
+        var  startDate = Date.parse(dateString1);
+        var  endDate = Date.parse(dateString2);
+        if (startDate>endDate){
+            return 0;
+        }
+        if (startDate==endDate){
+            return 1;
+        }
+        var days=(endDate - startDate)/(1*24*60*60*1000);
+        return  days;
+    }
+
+
+</script>
+{/block}

+ 150 - 0
application/admin/view/child_project/index.html

@@ -0,0 +1,150 @@
+{extend name='main'}
+
+{block name="button"}
+
+{if auth("contrast")}
+<button class="layui-btn layui-btn-sm" style="background-color: #DC2219" onclick="getIds()" >去对比</button>
+{/if}
+
+{if auth("add")}
+<a data-dbclick data-title="新建子项目" class="layui-btn layui-btn-sm"  style="background-color: #DC2219" data-open='{:url("add")}'>新建项目</a>
+{/if}
+
+{/block}
+
+{block name="content"}
+<div class="think-box-shadow">
+    {include file='child_project/index_search'}
+    <table class="layui-table margin-top-10" >
+        {notempty name='list'}
+        <thead>
+        <tr>
+            <th class='list-table-check-td think-checkbox'>
+                <label><input data-auto-none data-check-target='.list-check-box' type='checkbox'></label>
+            </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-center nowrap'></th>
+        </tr>
+        </thead>
+        {/notempty}
+        <tbody>
+        {foreach $list as $key=>$vo}
+        <tr>
+            <td class='list-table-check-td think-checkbox'>
+                {if $vo.url neq ''}  <label><input class="list-check-box" name="ids" value='{$vo.id}' type='checkbox'></label>{/if}
+            </td>
+            <td class='text-left nowrap'>{$vo.project_name|default=''}</td>
+            <td class='text-left nowrap'>{$vo.main_project_name|default='-'}</td>
+            <td class='text-left nowrap'>{$vo.category_name|default=''}</td>
+            <td class='text-left nowrap'>{$vo.create_at|format_datetime}</td>
+            <td class='text-left nowrap'>
+
+                {if auth("import")}
+                <a class='layui-btn layui-btn-normal layui-btn-sm dr' id="dr" style="background-color:#DC2219;margin-right: 10px;width: 65px " onclick="changename('{$vo.id}')">
+                    {if $vo.url eq ''}待导入{else}重新导入{/if}
+                </a>
+                {/if}
+
+                {if auth("edit")}
+                <a data-dbclick class="layui-btn layui-btn-sm" style="background-color: #FFB822" data-title="编辑" data-open='{:url("edit")}?id={$vo.id}'>编 辑</a>
+                {/if}
+
+<!--                {if auth("projectinfo")}-->
+<!--                <a data-title="项目详情" class="layui-btn layui-btn-sm" data-modal='{:url("projectinfo")}?id={$vo.id}'>项目详情</a>-->
+<!--                {/if}-->
+
+                {if $vo.url neq '' && auth("look")}
+                <a data-dbclick class="layui-btn layui-btn-sm" style="background-color: #5AD729" data-title="查看" data-open='{:url("look")}?id={$vo.id}'>查 看</a>
+                {/if}
+
+                {if $vo.url neq '' && auth("down")}
+                <a href="{$vo.url}" class="layui-btn layui-btn-sm" style="background-color:#29B2D7 " download data-title="下载" >下 载</a>
+                {/if}
+
+                {if auth("remove")}
+                <a class="layui-btn layui-btn-sm layui-btn-danger" style="background-color: #2944D7" data-confirm="确定要删除吗?" data-action="{:url('remove')}" data-value="id#{$vo.id}" data-csrf="{:systoken('remove')}">删 除</a>
+                {/if}
+
+
+            </td>
+        </tr>
+        {/foreach}
+        </tbody>
+    </table>
+
+    {empty name='list'}<span class="notdata">没有记录哦</span>{else}{$pagehtml|raw|default=''}{/empty}
+
+</div>
+<script>
+
+    function getIds()
+    {
+        var id = document.getElementsByName('ids');
+        var value = new Array();
+        for (var i=0;i<id.length;i++){
+            if (id[i].checked){
+                value.push(id[i].value);
+            }
+        }
+        if (value.length<1){
+            layer.msg('请选择需要对比的数据');
+        }else if (value.length<2){
+            layer.msg('请选择至少两条数据');
+        }else{
+            $.form.href('{:url("admin/child_project/contrast")}?ids=' +value.toString());
+            //window.location = '{:url("admin/main_project/contrast")}?ids=' +value.toString();
+        }
+
+    }
+
+
+    var project_id = ''
+    function changename(val){
+        project_id = val
+    }
+    layui.use('upload', function(){
+        var upload = layui.upload;
+
+        //执行实例
+        var uploadInst = upload.render({
+            elem: '.dr' //绑定元素
+            ,url: 'admin/api.plugs/upload'
+            ,accept: 'file', //普通文件,
+            before: function(obj){ //obj参数包含的信息,跟 choose回调完全一致,可参见上文。
+                console.log(obj)
+                // layer.load(); //上传loading
+            }
+            ,done: function(res){
+                if (res.uploaded == true){
+                    var value = {path:res.key,project_id:project_id,url:res.url}
+                    $.ajax({
+                        url:"/admin/child_project/import",
+                        type:'get',
+                        data:value
+                        ,success:function(result){
+                           // console.log(result.code);
+                            if (result.code==1){
+                                layer.msg('上传成功',{time:2000,end:function () {
+                                        location.reload();
+                                       // $.form.href('{:url("admin/child_project/index")}');
+                                    }});
+                            }else {
+                                layer.msg('上传失败,请核对表格模板是否正确!',{icon: 5});
+                            }
+                        }
+                    });
+                }else {
+                    layer.msg('上传失败',{icon: 5});
+                }
+                // layer.closeAll('loading'); //关闭loading
+            }
+            ,error: function(){
+                layer.msg('上传失败');
+            }
+        });
+    });
+</script>
+{/block}

+ 627 - 0
application/admin/view/child_project/index_search.html

@@ -0,0 +1,627 @@
+<style>
+    .layui-col-space12>*{
+        padding: 6px 0 6px 0 !important;
+    }
+</style>
+<fieldset>
+
+    <legend>条件搜索</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="project_name" value="{$Think.get.project_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 class="layui-select" name="category_id">
+                    {foreach $menus as $k=>$v}
+                    {eq name='Think.get.category_id' value='$v.id.""'}
+                    <option selected value="{$v.id}">{$v.spl|raw}{$v.title}</option>
+                    {else}
+                    <option value="{$v.id}">{$v.spl|raw}{$v.title}</option>
+                    {/eq}
+                    {/foreach}
+                </select>
+            </div>
+        </div>
+
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">建筑高度</label>
+            <div class="layui-input-inline layui-col-space12">
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="building_height_start" id="building_height_start" placeholder="" value="{$Think.get.building_height_start|default=''}" class="layui-input">
+                </div>
+                <div class="layui-form-mid">-</div>
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="building_height_end" id="building_height_end" placeholder="" value="{$Think.get.building_height_end|default=''}" class="layui-input">
+                </div>
+            </div>
+        </div>
+
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">建筑层数</label>
+            <div class="layui-input-inline layui-col-space12">
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="construction_layer_start" id="construction_layer_start" placeholder="" value="{$Think.get.construction_layer_start|default=''}" class="layui-input">
+                </div>
+                <div class="layui-form-mid">-</div>
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="construction_layer_end" id="construction_layer_end" placeholder="" value="{$Think.get.construction_layer_end|default=''}" class="layui-input">
+                </div>
+            </div>
+        </div>
+
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">地上层数</label>
+            <div class="layui-input-inline layui-col-space12">
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="upper_number_start" id="upper_number_start" placeholder="" value="{$Think.get.upper_number_start|default=''}" class="layui-input">
+                </div>
+                <div class="layui-form-mid">-</div>
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="upper_number_end" id="upper_number_end" placeholder="" value="{$Think.get.upper_number_end|default=''}" class="layui-input">
+                </div>
+            </div>
+        </div>
+
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">地下层数</label>
+            <div class="layui-input-inline layui-col-space12">
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="underground_start" id="underground_start" placeholder="" value="{$Think.get.underground_start|default=''}" class="layui-input">
+                </div>
+                <div class="layui-form-mid">-</div>
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="underground_end" id="underground_end" placeholder="" value="{$Think.get.underground_end|default=''}" class="layui-input">
+                </div>
+            </div>
+        </div>
+
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">地下层高</label>
+            <div class="layui-input-inline layui-col-space12">
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="underground_layer_start" id="underground_layer_start" placeholder="" value="{$Think.get.underground_layer_start|default=''}" class="layui-input">
+                </div>
+                <div class="layui-form-mid">-</div>
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="underground_layer_end" id="underground_layer_end" placeholder="" value="{$Think.get.underground_layer_end|default=''}" class="layui-input">
+                </div>
+            </div>
+        </div>
+
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">首层层高</label>
+            <div class="layui-input-inline layui-col-space12">
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="first_layer_high_start" id="first_layer_high_start" placeholder="" value="{$Think.get.first_layer_high_start|default=''}" class="layui-input">
+                </div>
+                <div class="layui-form-mid">-</div>
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="first_layer_high_end" id="first_layer_high_end" placeholder="" value="{$Think.get.first_layer_high_end|default=''}" class="layui-input">
+                </div>
+            </div>
+        </div>
+
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">标准层层高</label>
+            <div class="layui-input-inline layui-col-space12">
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="standard_height_start" id="standard_height_start" placeholder="" value="{$Think.get.standard_height_start|default=''}" class="layui-input">
+                </div>
+                <div class="layui-form-mid">-</div>
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="standard_height_end" id="standard_height_end" placeholder="" value="{$Think.get.standard_height_end|default=''}" class="layui-input">
+                </div>
+            </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="structure_type">
+                    {foreach [''=>'-- 全部 --','框架结构'=>'框架结构','剪力墙结构'=>'剪力墙结构','框架剪力墙结构'=>'框架剪力墙结构','断肢剪力墙结构'=>'断肢剪力墙结构','砖混结构'=>'砖混结构','钢结构'=>'钢结构','装配式混泥土结构'=>'装配式混泥土结构','框架简体结构'=>'框架简体结构'] as $k=>$v}
+                    {eq name='Think.get.structure_type' 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">
+                <select class="layui-select" name="building_fortification_intensity">
+                    {foreach [''=>'-- 全部 --','6度'=>'6度','7度'=>'7度','8度'=>'8度','9度'=>'9度'] as $k=>$v}
+                    {eq name='Think.get.building_fortification_intensity' 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">
+                <select class="layui-select" name="seismic_grade">
+                    {foreach [''=>'-- 全部 --','一级'=>'一级','二级'=>'二级','三级'=>'三级','四级'=>'四级'] as $k=>$v}
+                    {eq name='Think.get.seismic_grade' 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="design_life" value="{$Think.get.design_life|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="base_type">
+                    {foreach [''=>'-- 全部 --','不包含'=>'不包含','独立基础'=>'独立基础','条形基础'=>'条形基础','满堂基础'=>'满堂基础','桩基础'=>'桩基础','桩承台基础'=>'桩承台基础','混合基础'=>'混合基础','带形基础'=>'带形基础','筏板基础'=>'筏板基础','砖基础'=>'砖基础'] as $k=>$v}
+                    {eq name='Think.get.base_type' 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="decorate_standard" value="{$Think.get.decorate_standard|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="other_parameters" value="{$Think.get.other_parameters|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 layui-col-space12">
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="construction_area_start" id="construction_area_start" placeholder="" value="{$Think.get.construction_area_start|default=''}" class="layui-input">
+                </div>
+                <div class="layui-form-mid">-</div>
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="construction_area_end" id="construction_area_end" placeholder="" value="{$Think.get.construction_area_end|default=''}" class="layui-input">
+                </div>
+            </div>
+        </div>
+
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">地上建筑面积</label>
+            <div class="layui-input-inline layui-col-space12">
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="ground_floor_area_start" id="ground_floor_area_start" placeholder="" value="{$Think.get.ground_floor_area_start|default=''}" class="layui-input">
+                </div>
+                <div class="layui-form-mid">-</div>
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="ground_floor_area_end" id="ground_floor_area_end" placeholder="" value="{$Think.get.ground_floor_area_end|default=''}" class="layui-input">
+                </div>
+            </div>
+        </div>
+
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">地下建筑面积</label>
+            <div class="layui-input-inline layui-col-space12">
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="underground_floor_area_start" id="underground_floor_area_start" placeholder="" value="{$Think.get.underground_floor_area_start|default=''}" class="layui-input">
+                </div>
+                <div class="layui-form-mid">-</div>
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="underground_floor_area_end" id="underground_floor_area_end" placeholder="" value="{$Think.get.underground_floor_area_end|default=''}" class="layui-input">
+                </div>
+            </div>
+        </div>
+
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">建筑占地面积</label>
+            <div class="layui-input-inline layui-col-space12">
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="building_floor_area_start" id="building_floor_area_start" placeholder="" value="{$Think.get.building_floor_area_start|default=''}" class="layui-input">
+                </div>
+                <div class="layui-form-mid">-</div>
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="building_floor_area_end" id="building_floor_area_end" placeholder="" value="{$Think.get.building_floor_area_end|default=''}" class="layui-input">
+                </div>
+            </div>
+        </div>
+
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">钢结构受益面积</label>
+            <div class="layui-input-inline layui-col-space12">
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="steel_benefit_area_start" id="steel_benefit_area_start" placeholder="" value="{$Think.get.steel_benefit_area_start|default=''}" class="layui-input">
+                </div>
+                <div class="layui-form-mid">-</div>
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="steel_benefit_area_end" id="steel_benefit_area_end" placeholder="" value="{$Think.get.steel_benefit_area_end|default=''}" class="layui-input">
+                </div>
+            </div>
+        </div>
+
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">木质构件面积</label>
+            <div class="layui-input-inline layui-col-space12">
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="wood_area_start" id="wood_area_start" placeholder="" value="{$Think.get.wood_area_start|default=''}" class="layui-input">
+                </div>
+                <div class="layui-form-mid">-</div>
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="wood_area_end" id="wood_area_end" placeholder="" value="{$Think.get.wood_area_end|default=''}" class="layui-input">
+                </div>
+            </div>
+        </div>
+
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">可售面积</label>
+            <div class="layui-input-inline layui-col-space12">
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="available_area_start" id="available_area_start" placeholder="" value="{$Think.get.available_area_start|default=''}" class="layui-input">
+                </div>
+                <div class="layui-form-mid">-</div>
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="available_area_end" id="available_area_end" placeholder="" value="{$Think.get.available_area_end|default=''}" class="layui-input">
+                </div>
+            </div>
+        </div>
+
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">户数</label>
+            <div class="layui-input-inline layui-col-space12">
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="number_start" id="number_start" placeholder="" value="{$Think.get.number_start|default=''}" class="layui-input">
+                </div>
+                <div class="layui-form-mid">-</div>
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="number_end" id="number_end" placeholder="" value="{$Think.get.number_end|default=''}" class="layui-input">
+                </div>
+            </div>
+        </div>
+
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">地下室底面积</label>
+            <div class="layui-input-inline layui-col-space12">
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="basement_floor_area_start" id="basement_floor_area_start" placeholder="" value="{$Think.get.basement_floor_area_start|default=''}" class="layui-input">
+                </div>
+                <div class="layui-form-mid">-</div>
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="basement_floor_area_end" id="basement_floor_area_end" placeholder="" value="{$Think.get.basement_floor_area_end|default=''}" class="layui-input">
+                </div>
+            </div>
+        </div>
+
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">其他说明</label>
+            <div class="layui-input-inline">
+                <input name="other_instructions" value="{$Think.get.other_instructions|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="template">
+                    {foreach $template as $k=>$v}
+                    {eq name='Think.get.template' value='$v.id.""'}
+                    <option selected value="{$v.id}">{$v.title}</option>
+                    {else}
+                    <option value="{$v.id}">{$v.title}</option>
+                    {/eq}
+                    {/foreach}
+                </select>
+            </div>
+        </div>
+
+
+        <div class="layui-form-item layui-inline">
+            <button class="layui-btn" style="background-color:  #DC2219" lay-submit lay-filter="tijiao"><i class="layui-icon">&#xe615;</i>立即搜索</button>
+        </div>
+    </form>
+
+</fieldset>
+
+<script>
+    form.render();
+    layui.use(['form', 'layedit', 'laydate'], function(){
+        var form = layui.form
+            ,layer = layui.layer
+            ,layedit = layui.layedit
+            ,laydate = layui.laydate;
+
+
+        form.on('submit(tijiao)', function(data) {
+
+            console.log(data)
+
+            var building_height_start = data.field.building_height_start;
+            var building_height_end = data.field.building_height_end;
+            if (building_height_start=='' && building_height_end!=''){
+                layer.msg('请输入起始值');
+                $("#building_height_start").focus();
+                return false
+            }else if (building_height_start!='' && building_height_end==''){
+                layer.msg('请输入终止值');
+                $("#building_height_end").focus();
+                return false
+            }else if (building_height_end<building_height_start){
+                layer.msg('终止值小于起始值');
+                $("#building_height_start").focus();
+                return false
+            }
+
+            var construction_layer_start = data.field.construction_layer_start;
+            var construction_layer_end = data.field.construction_layer_end;
+            if (construction_layer_start=='' && construction_layer_end!=''){
+                layer.msg('请输入起始值');
+                $("#construction_layer_start").focus();
+                return false
+            }else if (construction_layer_start!='' && construction_layer_end==''){
+                layer.msg('请输入终止值');
+                $("#construction_layer_end").focus();
+                return false
+            }else if (construction_layer_end<construction_layer_start){
+                layer.msg('终止值小于起始值');
+                $("#construction_layer_start").focus();
+                return false
+            }
+
+
+            var upper_number_start = data.field.upper_number_start;
+            var upper_number_end = data.field.upper_number_end;
+            if (upper_number_start=='' && upper_number_end!=''){
+                layer.msg('请输入起始值');
+                $("#upper_number_start").focus();
+                return false
+            }else if (upper_number_start!='' && upper_number_end==''){
+                layer.msg('请输入终止值');
+                $("#upper_number_end").focus();
+                return false
+            }else if (upper_number_end<upper_number_start){
+                layer.msg('终止值小于起始值');
+                $("#upper_number_start").focus();
+                return false
+            }
+
+            var underground_start = data.field.underground_start;
+            var underground_end = data.field.underground_end;
+            if (underground_start=='' && underground_end!=''){
+                layer.msg('请输入起始值');
+                $("#underground_start").focus();
+                return false
+            }else if (underground_start!='' && underground_end==''){
+                layer.msg('请输入终止值');
+                $("#underground_end").focus();
+                return false
+            }else if (underground_end<underground_start){
+                layer.msg('终止值小于起始值');
+                $("#underground_start").focus();
+                return false
+            }
+
+            var underground_layer_start = data.field.underground_layer_start;
+            var underground_layer_end = data.field.underground_layer_end;
+            if (underground_layer_start=='' && underground_layer_end!=''){
+                layer.msg('请输入起始值');
+                $("#underground_layer_start").focus();
+                return false
+            }else if (underground_layer_start!='' && underground_layer_end==''){
+                layer.msg('请输入终止值');
+                $("#underground_layer_end").focus();
+                return false
+            }else if (underground_layer_end<underground_layer_start){
+                layer.msg('终止值小于起始值');
+                $("#underground_layer_start").focus();
+                return false
+            }
+
+
+            var first_layer_high_start = data.field.first_layer_high_start;
+            var first_layer_high_end = data.field.first_layer_high_end;
+            if (first_layer_high_start=='' && first_layer_high_end!=''){
+                layer.msg('请输入起始值');
+                $("#first_layer_high_start").focus();
+                return false
+            }else if (first_layer_high_start!='' && first_layer_high_end==''){
+                layer.msg('请输入终止值');
+                $("#first_layer_high_end").focus();
+                return false
+            }else if (first_layer_high_end<first_layer_high_start){
+                layer.msg('终止值小于起始值');
+                $("#first_layer_high_start").focus();
+                return false
+            }
+
+            var standard_height_start = data.field.standard_height_start;
+            var standard_height_end = data.field.standard_height_end;
+            if (standard_height_start=='' && standard_height_end!=''){
+                layer.msg('请输入起始值');
+                $("#standard_height_start").focus();
+                return false
+            }else if (standard_height_start!='' && standard_height_end==''){
+                layer.msg('请输入终止值');
+                $("#standard_height_end").focus();
+                return false
+            }else if (standard_height_end<standard_height_start){
+                layer.msg('终止值小于起始值');
+                $("#standard_height_start").focus();
+                return false
+            }
+
+            var construction_area_start = data.field.construction_area_start;
+            var construction_area_end = data.field.construction_area_end;
+            if (construction_area_start=='' && construction_area_end!=''){
+                layer.msg('请输入起始值');
+                $("#construction_area_start").focus();
+                return false
+            }else if (construction_area_start!='' && construction_area_end==''){
+                layer.msg('请输入终止值');
+                $("#construction_area_end").focus();
+                return false
+            }else if (construction_area_end<construction_area_start){
+                layer.msg('终止值小于起始值');
+                $("#construction_area_start").focus();
+                return false
+            }
+
+            var ground_floor_area_start = data.field.ground_floor_area_start;
+            var ground_floor_area_end = data.field.ground_floor_area_end;
+            if (ground_floor_area_start=='' && ground_floor_area_end!=''){
+                layer.msg('请输入起始值');
+                $("#ground_floor_area_start").focus();
+                return false
+            }else if (ground_floor_area_start!='' && ground_floor_area_end==''){
+                layer.msg('请输入终止值');
+                $("#ground_floor_area_end").focus();
+                return false
+            }else if (ground_floor_area_end<ground_floor_area_start){
+                layer.msg('终止值小于起始值');
+                $("#ground_floor_area_start").focus();
+                return false
+            }
+
+            var underground_floor_area_start = data.field.underground_floor_area_start;
+            var underground_floor_area_end = data.field.underground_floor_area_end;
+            if (underground_floor_area_start=='' && underground_floor_area_end!=''){
+                layer.msg('请输入起始值');
+                $("#underground_floor_area_start").focus();
+                return false
+            }else if (underground_floor_area_start!='' && underground_floor_area_end==''){
+                layer.msg('请输入终止值');
+                $("#underground_floor_area_end").focus();
+                return false
+            }else if (underground_floor_area_end<underground_floor_area_start){
+                layer.msg('终止值小于起始值');
+                $("#underground_floor_area_start").focus();
+                return false
+            }
+
+            var building_floor_area_start = data.field.building_floor_area_start;
+            var building_floor_area_end = data.field.building_floor_area_end;
+            if (building_floor_area_start=='' && building_floor_area_end!=''){
+                layer.msg('请输入起始值');
+                $("#building_floor_area_start").focus();
+                return false
+            }else if (building_floor_area_start!='' && building_floor_area_end==''){
+                layer.msg('请输入终止值');
+                $("#building_floor_area_end").focus();
+                return false
+            }else if (building_floor_area_end<building_floor_area_start){
+                layer.msg('终止值小于起始值');
+                $("#building_floor_area_start").focus();
+                return false
+            }
+
+            var steel_benefit_area_start = data.field.steel_benefit_area_start;
+            var steel_benefit_area_end = data.field.steel_benefit_area_end;
+            if (steel_benefit_area_start=='' && steel_benefit_area_end!=''){
+                layer.msg('请输入起始值');
+                $("#steel_benefit_area_start").focus();
+                return false
+            }else if (steel_benefit_area_start!='' && steel_benefit_area_end==''){
+                layer.msg('请输入终止值');
+                $("#steel_benefit_area_end").focus();
+                return false
+            }else if (steel_benefit_area_end<steel_benefit_area_start){
+                layer.msg('终止值小于起始值');
+                $("#steel_benefit_area_start").focus();
+                return false
+            }
+
+            var wood_area_start = data.field.wood_area_start;
+            var wood_area_end = data.field.wood_area_end;
+            if (wood_area_start=='' && wood_area_end!=''){
+                layer.msg('请输入起始值');
+                $("#wood_area_start").focus();
+                return false
+            }else if (wood_area_start!='' && wood_area_end==''){
+                layer.msg('请输入终止值');
+                $("#wood_area_end").focus();
+                return false
+            }else if (wood_area_end<wood_area_start){
+                layer.msg('终止值小于起始值');
+                $("#wood_area_start").focus();
+                return false
+            }
+
+            var available_area_start = data.field.available_area_start;
+            var available_area_end = data.field.available_area_end;
+            if (available_area_start=='' && available_area_end!=''){
+                layer.msg('请输入起始值');
+                $("#available_area_start").focus();
+                return false
+            }else if (available_area_start!='' && available_area_end==''){
+                layer.msg('请输入终止值');
+                $("#available_area_end").focus();
+                return false
+            }else if (available_area_end<available_area_start){
+                layer.msg('终止值小于起始值');
+                $("#available_area_start").focus();
+                return false
+            }
+
+            var number_start = data.field.number_start;
+            var number_end = data.field.number_end;
+            if (number_start=='' && number_end!=''){
+                layer.msg('请输入起始值');
+                $("#number_start").focus();
+                return false
+            }else if (number_start!='' && number_end==''){
+                layer.msg('请输入终止值');
+                $("#number_end").focus();
+                return false
+            }else if (number_end<number_start){
+                layer.msg('终止值小于起始值');
+                $("#number_start").focus();
+                return false
+            }
+
+            var basement_floor_area_start = data.field.basement_floor_area_start;
+            var basement_floor_area_end = data.field.basement_floor_area_end;
+            if (basement_floor_area_start=='' && basement_floor_area_end!=''){
+                layer.msg('请输入起始值');
+                $("#basement_floor_area_start").focus();
+                return false
+            }else if (basement_floor_area_start!='' && basement_floor_area_end==''){
+                layer.msg('请输入终止值');
+                $("#basement_floor_area_end").focus();
+                return false
+            }else if (basement_floor_area_end<basement_floor_area_start){
+                layer.msg('终止值小于起始值');
+                $("#basement_floor_area_start").focus();
+                return false
+            }
+
+
+        });
+
+    });
+</script>

+ 36 - 0
application/admin/view/child_project/info.html

@@ -0,0 +1,36 @@
+<div style="padding: 20px; background-color: #F2F2F2;">
+    <div class="layui-row layui-col-space15">
+        <div class="layui-col-md12">
+            <div class="layui-card">
+                <div class="layui-card-body">
+                    <div class="layui-col-md6">项目名称:{$vo.project_name|default='--'}</div>
+                    <div class="layui-col-md6">建筑类别:{$vo.category_name|default='--'}</div><hr />
+                    <div class="layui-col-md6">建筑高度:{$vo.building_height|default='0'}</div>
+                    <div class="layui-col-md6">建筑层数:{$vo.construction_layer|default='--'}</div><hr />
+                    <div class="layui-col-md6">地上层数:{$vo.upper_number|default='--'}</div>
+                    <div class="layui-col-md6">地下层数:{$vo.underground|default='--'}</div><hr />
+                    <div class="layui-col-md6">地下层高:{$vo.underground_layer|default='--'}</div>
+                    <div class="layui-col-md6">首层层高:{$vo.first_layer_high|default='--'}</div><hr />
+                    <div class="layui-col-md6">标准层层高:{$vo.standard_height|default='--'}</div>
+                    <div class="layui-col-md6">结构类型:{$vo.structure_type|default='--'}</div><hr />
+                    <div class="layui-col-md6">建筑设防烈度:{$vo.building_fortification_intensity|default='--'}</div>
+                    <div class="layui-col-md6">抗震等级:{$vo.seismic_grade|default='--'}</div><hr />
+                    <div class="layui-col-md6">设计寿命:{$vo.design_life|default='--'}</div>
+                    <div class="layui-col-md6">基础类型:{$vo.base_type|default='--'}</div><hr />
+                    <div class="layui-col-md6">装修标准:{$vo.decorate_standard|default='--'}</div>
+                    <div class="layui-col-md6">其他参数:{$vo.other_parameters|default='--'}</div><hr />
+                    <div class="layui-col-md6">建筑面积:{$vo.construction_area|default='--'}</div>
+                    <div class="layui-col-md6">地上建筑面积:{$vo.ground_floor_area|default='--'}</div>
+                    <div class="layui-col-md6">地下建筑面积:{$vo.underground_floor_area|default='--'}</div>
+                    <div class="layui-col-md6">建筑占地面积:{$vo.building_floor_area|default='--'}</div><hr />
+                    <div class="layui-col-md6">钢结构受益面积:{$vo.steel_benefit_area|default='--'}</div>
+                    <div class="layui-col-md6">木质构件面积:{$vo.wood_area|default='--'}</div><hr />
+                    <div class="layui-col-md6">可售面积:{$vo.available_area|default='--'}</div>
+                    <div class="layui-col-md6">户数:{$vo.number|default='--'}</div><hr />
+                    <div class="layui-col-md6">地下室底面积:{$vo.basement_floor_area|default='--'}</div>
+                    <div class="layui-col-md6">其他说明:{$vo.other_instructions|default='--'}</div><hr />
+                </div>
+            </div>
+        </div>
+    </div>
+</div>

+ 61 - 0
application/admin/view/child_project/look.html

@@ -0,0 +1,61 @@
+{extend name='main'}
+
+{block name="button"}
+<button class="layui-btn" style="height: 30px;line-height:28px;color:#FFFFFF;background-color: #DC2219;border: 1px solid #C9C9C9 " type='button' onclick="window.history.back()">返 回</button>
+
+
+{/block}
+
+{block name="content"}
+<div class="think-box-shadow">
+    <table class="layui-table margin-top-10">
+        {notempty name='list'}
+        <thead>
+        <tr>
+            <th class='text-left nowrap'>序号</th>
+            <th class='text-left nowrap'>成本项目</th>
+            <th class='text-left nowrap'>面积计算口径</th>
+            <th class='text-left nowrap'>建面单方成本(元/m2)(含税)</th>
+            <th class='text-left nowrap'>总价(万元)(含税)</th>
+            <th class='text-left nowrap'>建面单方成本(元/m2)(不含税)</th>
+            <th class='text-left nowrap'>总价(万元)(不含税)</th>
+            <th class='text-left nowrap'>可售单方成本(元/m2)(含税)</th>
+            <th class='text-left nowrap'>可售单方成本(元/m2)(不含税)</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'>预留指标1</th>
+            <th class='text-left nowrap'>预留指标2</th>
+            <th class='text-left nowrap'>备注</th>
+        </tr>
+        </thead>
+        {/notempty}
+        <tbody>
+        {foreach $list as $key=>$vo}
+        <tr data-dbclick>
+            <td class='text-left nowrap'>{$vo.number|default=''}</td>
+            <td class='text-left nowrap'>{$vo.cost_project|default='-'}</td>
+            <td class='text-left nowrap'>{$vo.area_calculating_aperture|default='-'}</td>
+            <td class='text-left nowrap'>{$vo.single_party_cost|default='0'}</td>
+            <td class='text-left nowrap'>{$vo.total_price_included|default='0'}</td>
+            <td class='text-left nowrap'>{$vo.single_party_cost_excluding|default='0'}</td>
+            <td class='text-left nowrap'>{$vo.total_price_included_excluding|default='0'}</td>
+            <td class='text-left nowrap'>{$vo.single_party_cost_tax|default='0'}</td>
+            <td class='text-left nowrap'>{$vo.single_party_cost_no_tax|default='0'}</td>
+            <td class='text-left nowrap'>{$vo.quantities|default='0'}</td>
+            <td class='text-left nowrap'>{$vo.calculating_unit|default='0'}</td>
+            <td class='text-left nowrap'>{$vo.unilateral_content|default='0'}</td>
+            <td class='text-left nowrap'>{$vo.unilateral_content_excluding|default='0'}</td>
+            <td class='text-left nowrap'>{$vo.saleable_single_party_tax|default='0'}</td>
+            <td class='text-left nowrap'>{$vo.saleable_single_party_no_tax|default='0'}</td>
+            <td class='text-left nowrap'>{$vo.note|default='-'}</td>
+        </tr>
+        {/foreach}
+        </tbody>
+    </table>
+
+    {empty name='list'}<span class="notdata">没有记录哦</span>{else}{$pagehtml|raw|default=''}{/empty}
+
+</div>
+{/block}

+ 270 - 0
application/admin/view/child_project/see.html

@@ -0,0 +1,270 @@
+{extend name='main'}
+
+{block name="button"}
+{if auth("add")}
+<button class="layui-btn layui-bg-red" style="height: 30px;line-height:28px;color: #333;border: 1px solid #C9C9C9 " type='button' onclick="window.history.back()">返 回</button>
+{/if}
+
+
+{/block}
+
+{block name="content"}
+<style>
+    .tu{
+        width: 75%;height:600px;float: left
+    }
+    .layui-table td, .layui-table th, .layui-table-col-set, .layui-table-fixed-r, .layui-table-grid-down, .layui-table-header, .layui-table-page, .layui-table-tips-main, .layui-table-tool, .layui-table-total, .layui-table-view{
+        border: none !important;
+
+
+    }
+    .layui-table{
+        background-color:initial !important;
+    }
+</style>
+
+<div class="layui-tab">
+    <input type="hidden" id="subjects" value="{$subjects}">
+    <input type="hidden" id="ids" value="{$ids}">
+
+    <ul class="layui-tab-title">
+        <li class="layui-this" onclick="change()">建面单方成本(含税)</li>
+        <li onclick="change1()">总价(含税)</li>
+        <li onclick="change2()">建面单方成本(不含税)</li>
+        <li onclick="change3()">总价(不含税)</li>
+
+        <li onclick="change7()">可售单方成本(含税)</li>
+        <li onclick="change8()">可售单方成本(不含税)</li>
+
+        <li onclick="change4()">工程量</li>
+        <li onclick="change5()">建面单方含量</li>
+        <li onclick="change6()">可售单方含量</li>
+
+        <li onclick="change9()">预留指标1</li>
+        <li onclick="change10()">预留指标2</li>
+    </ul>
+    <div class="layui-tab-content" style="height: 100px;">
+        <div class="layui-tab-item layui-show" style="width:100%;">
+            <div id="main" class="tu"></div>
+        </div>
+        <div class="layui-tab-item" style="width:100%;">
+            <div id="main1" class="tu" ></div>
+        </div>
+        <div class="layui-tab-item" style="width:100%;">
+            <div id="main2" class="tu" ></div>
+        </div>
+        <div class="layui-tab-item" style="width:100%;">
+            <div id="main3" class="tu"></div>
+        </div>
+
+        <div class="layui-tab-item" style="width:100%;">
+            <div id="main7" class="tu"></div>
+        </div>
+
+        <div class="layui-tab-item" style="width:100%;">
+            <div id="main8" class="tu"></div>
+        </div>
+
+        <div class="layui-tab-item" style="width:100%;">
+            <div id="main4" class="tu"></div>
+        </div>
+        <div class="layui-tab-item" style="width:100%;">
+            <div id="main5" class="tu"></div>
+        </div>
+        <div class="layui-tab-item" style="width:100%;">
+            <div id="main6" class="tu"></div>
+        </div>
+
+        <div class="layui-tab-item" style="width:100%;">
+            <div id="main9" class="tu"></div>
+        </div>
+        <div class="layui-tab-item" style="width:100%;">
+            <div id="main10" class="tu"></div>
+        </div>
+        <div style="width: 25%;float: right">
+            <table class="layui-table margin-top-10">
+                <tr >
+                    <th style="font-weight:bold">样本名称</th>
+                    <th style="font-weight:bold">数值</th>
+                    <th style="font-weight:bold">备注</th>
+                </tr>
+                <tbody id="right">
+
+                </tbody>
+            </table>
+
+        </div>
+    </div>
+</div>
+
+
+<script type="text/javascript">
+    setinfo('main','single_party_cost')
+
+    function change () {
+        setinfo('main','single_party_cost')
+    }
+    function change1 () {
+        setinfo('main1','total_price_included')
+
+    }
+    function change2 () {
+        setinfo('main2','single_party_cost_excluding')
+    }
+    function change3 () {
+        setinfo('main3','total_price_included_excluding')
+    }
+    function change4 () {
+        setinfo('main4','quantities')
+    }
+    function change5 () {
+        setinfo('main5','unilateral_content')
+    }
+    function change6 () {
+        setinfo('main6','unilateral_content_excluding')
+    }
+
+    function change7 () {
+        setinfo('main7','single_party_cost_tax')
+    }
+
+    function change8 () {
+        setinfo('main8','single_party_cost_no_tax')
+    }
+
+    function change9 () {
+        setinfo('main9','saleable_single_party_tax')
+    }
+
+    function change10 () {
+        setinfo('main10','saleable_single_party_no_tax')
+    }
+
+    //ajax获取数据
+    function setinfo(where,field) {
+        var subjects = $("#subjects").val()
+        var ids = $("#ids").val()
+        var value = {subjects:subjects,ids:ids,field:field}
+        $.ajax({
+            url:"/admin/child_project/get_see_info",
+            type:'get',
+            data:value
+            ,success:function(result){
+                setchart(where,result,field)
+                var arr = result.data.right;
+                htmlright(arr)
+            }
+        });
+    }
+
+    //画图
+    function setchart(where,result,field) {
+        // console.log(result)
+        // console.log(result.data.field.title.length)
+        var len = result.data.field.title.length
+        var xname = ''
+        if (field=='single_party_cost'){
+            xname = '建面单方成本(元/m2)(含税)'
+        }else if (field=='total_price_included'){
+            xname = '总价(万元)(含税)';
+        }else if (field=='single_party_cost_excluding'){
+            xname = '建面单方成本(元/m2)(不含税)';
+        }else if (field=='total_price_included_excluding'){
+            xname = '总价(万元)(不含税)';
+        }else if (field=='quantities'){
+            xname = '工程量(含税)';
+        }else if (field=='unilateral_content'){
+            xname = '建面单方含量';
+        }else if (field=='unilateral_content_excluding'){
+            xname = '可售单方含量';
+        }else if (field=='single_party_cost_tax'){
+            xname = '可售单方成本(元/m2)(含税)';
+        }else if (field=='single_party_cost_no_tax'){
+            xname = '可售单方成本(元/m2)(不含税)';
+        }else if (field=='saleable_single_party_tax'){
+            xname = '预留指标1';
+        }else if (field=='saleable_single_party_no_tax'){
+            xname = '预留指标2';
+        }
+        var cid = document.getElementById(where)
+        //echarts重新渲染
+        if (cid.hasAttribute("_echarts_instance_"))
+            cid.removeAttribute("_echarts_instance_")
+        // 基于准备好的dom,初始化echarts实例
+        var myChart = echarts.init(cid);
+        // 指定图表的配置项和数据
+        var option = {
+            title: {
+                text: ''
+            },
+            tooltip: {},
+            legend: {
+                // data: ['销量']
+            },
+            xAxis: {
+                show:true,
+                name:xname,
+                nameTextStyle:{				//---坐标轴名称样式
+                    padding:[40,100,-65,-125],	//---坐标轴名称相对位置
+                },
+                axisLabel:{
+                    interval:0,
+                    // rotate:20
+                    formatter: function (value) {
+                        value = value.replace(/[^\x00-\xff]/g, "$&\x01").replace(/.{12}\x01?/g, "$&\n").replace(/\x01/g, "");
+                        return value;
+                    }
+                },
+                data:result.data.field.title
+            },
+            yAxis: {
+                show:true,
+                name:'工程数量',
+                nameTextStyle:{				//---坐标轴名称样式
+                    padding:[5,100,-20,15],	//---坐标轴名称相对位置
+                },
+            },
+            series: [
+                {
+                    name: result.data.subjects,
+                    type: 'bar',
+                    barMaxWidth:'10%',
+                   //  barMaxWidth:function (len) {
+                   //      if (len>1){
+                   //          return '0'
+                   //      }else {
+                   //          return '10%'
+                   //      }
+                   //  },
+                    label:{
+                        show:true,
+                        position:'top',
+                        color:'#000000'
+                    },
+                    data:result.data.field.value
+                }
+            ]
+        };
+        myChart.setOption(option);
+    }
+
+    //填充右边栏
+    function htmlright(arr) {
+        if (arr.length>0) {
+            var html = '';
+            for (var i = 0; i < arr.length; i++) {
+                var tag = arr[i];
+                html += '<tr>' +
+                    '<th style="color:red;">' + tag.project_name + '</th>' +
+                    '<th>' + tag.value + '</th>' +
+                    '<th>' + tag.note + '</th>' +
+                    '</tr>';
+            }
+            $('#right').html(html);
+        }
+    }
+
+</script>
+
+
+{/block}

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

@@ -0,0 +1,116 @@
+{extend name="main"}
+
+{block name="button"}
+
+{if auth('config')}
+<a class="layui-btn layui-btn-sm layui-btn-primary" data-modal="{:url('config')}">修改系统配置</a>
+{/if}
+
+{/block}
+
+{block name="content"}
+
+<div class="think-box-shadow margin-bottom-15">
+    <span class="color-green font-w7 text-middle">文件存储引擎:</span>
+    {foreach ['local'=>'本地服务器存储','oss'=>'阿里云OSS存储'] as $k=>$v}
+    {if sysconf('storage_type') eq $k}
+    {if auth('file')}<a data-modal="{:url('file')}?type={$k}" class="layui-btn layui-btn-sm">{$v}</a>{else}<a class="layui-btn layui-btn-sm">{$v}</a>{/if}
+    {elseif auth('file')}<a data-modal="{:url('file')}?type={$k}" class="layui-btn layui-btn-sm layui-btn-primary">{$v}</a>{/if}
+    {/foreach}
+</div>
+
+<div class="think-box-shadow padding-40">
+    <div class="layui-form-item">
+        <span class="color-green font-w7">网站名称 Website</span>
+        <label class="relative block">
+            <input readonly value="{:sysconf('site_name')}" class="layui-input layui-bg-gray">
+            <a data-copy="{:sysconf('site_name')}" class="fa fa-copy right-btn"></a>
+        </label>
+        <p class="help-block">网站名称及网站图标,将显示在浏览器的标签上</p>
+    </div>
+    <div class="layui-form-item">
+        <span class="color-green font-w7">管理程序名称 Name</span>
+        <label class="relative block">
+            <input readonly placeholder="请输入程序名称" value="{:sysconf('app_name')}" class="layui-input layui-bg-gray">
+            <a data-copy="{:sysconf('app_name')}" class="fa fa-copy right-btn"></a>
+        </label>
+        <p class="help-block">管理程序名称,将显示在后台左上角标题</p>
+    </div>
+    <div class="layui-form-item">
+        <span class="color-green font-w7">管理程序版本 Version</span>
+        <label class="relative block">
+            <input readonly value="{:sysconf('app_version')}" class="layui-input layui-bg-gray">
+            <a data-copy="{:sysconf('app_version')}" class="fa fa-copy right-btn"></a>
+        </label>
+        <p class="help-block">管理程序版本,将显示在后台左上角标题</p>
+    </div>
+
+<!--    <div class="layui-form-item">-->
+<!--        <span class="color-green font-w7">网站备案号 Miitbeian</span>-->
+<!--        <label class="relative block">-->
+<!--            <input readonly value="{:sysconf('miitbeian')}" class="layui-input layui-bg-gray">-->
+<!--            <a data-copy="{:sysconf('miitbeian')}" class="fa fa-copy right-btn"></a>-->
+<!--        </label>-->
+<!--        <p class="help-block">网站备案号,可以在<a target="_blank" href="http://beian.miit.gov.cn">备案管理中心</a>查询获取,将显示在登录页面下面</p>-->
+<!--    </div>-->
+<!--    <div class="layui-form-item">-->
+<!--        <span class="color-green font-w7">网站版权信息 Copyright</span>-->
+<!--        <label class="relative block">-->
+<!--            <input readonly value="{:sysconf('site_copy')}" class="layui-input layui-bg-gray">-->
+<!--            <a data-copy="{:sysconf('site_copy')}" class="fa fa-copy right-btn"></a>-->
+<!--        </label>-->
+<!--        <p class="help-block">网站版权信息,在后台登录页面显示版本信息并链接到备案到信息备案管理系统</p>-->
+<!--    </div>-->
+
+    <div class="layui-form-item">
+        <span class="color-green font-w7">邮箱 email</span>
+        <label class="relative block">
+            <input readonly value="{:sysconf('email')}" class="layui-input layui-bg-gray">
+            <a data-copy="{:sysconf('email')}" class="fa fa-copy right-btn"></a>
+        </label>
+        <p class="help-block">邮箱</p>
+    </div>
+
+    <div class="layui-form-item">
+        <span class="color-green font-w7">电话 phone</span>
+        <label class="relative block">
+            <input readonly value="{:sysconf('phone')}" class="layui-input layui-bg-gray">
+            <a data-copy="{:sysconf('phone')}" class="fa fa-copy right-btn"></a>
+        </label>
+        <p class="help-block">电话</p>
+    </div>
+
+
+    <div class="layui-col-md12">
+        <div class="layui-col-md3">
+            <div class="layui-form-item">
+                <span class="color-green font-w7">游客看到联系方式开关 switch</span>
+                <label class="relative block">
+                    <input readonly value="{:sysconf('switch')}" class="layui-input layui-bg-gray">
+                </label>
+                <p class="help-block">游客看到联系方式开关    1:开  0:关</p>
+            </div>
+        </div>
+    </div>
+    <div class="layui-form-item">
+
+    </div>
+
+
+</div>
+{/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}

+ 20 - 0
application/admin/view/config/storage-local.html

@@ -0,0 +1,20 @@
+<form onsubmit="return false;" data-auto="true" action="{:url()}" method="post" class='layui-form layui-card' autocomplete="off">
+    <div class="layui-card-body">
+        <div class="color-text margin-left-40 margin-bottom-20 layui-code" style="border-left-width:1px;background:none">
+            <p>文件将存储在本地服务器,需确保服务器的 public/upload 目录有写入权限,有足够的存储空间!</p>
+        </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 padding-left-40">
+            <input type="hidden" name="storage_type" value="local">
+            <button class="layui-btn" type="submit">保存配置</button>
+            <button class="layui-btn layui-btn-danger" type='button' data-confirm="确定要取消修改吗?" data-close>取消修改</button>
+        </div>
+    </div>
+</form>

+ 80 - 0
application/admin/view/config/storage-oss.html

@@ -0,0 +1,80 @@
+<form onsubmit="return false;" data-auto="true" action="{:url()}" method="post" class='layui-form layui-card' autocomplete="off">
+    <div class="layui-card-body">
+        <div class="color-text margin-left-40 margin-bottom-20 layui-code" style="border-left-width:1px;background:none">
+            <p class="margin-bottom-5 font-w7">文件将上传到阿里云OSS空间,需要配置OSS公开访问及跨域策略!</p>
+            目前已实现自动创建空间及配置访问策略!<a target="_blank" href="https://promotion.aliyun.com/ntms/yunparter/invite.html?userCode=08p1pddw">我要免费申请</a>
+        </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="layui-form-item">
+            <label class="layui-form-label label-required">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" lay-search>
+                    {foreach $ossPoints 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="36" 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 padding-left-40">
+            <input type="hidden" name="storage_type" value="oss">
+            <button class="layui-btn" type="submit">保存配置</button>
+            <button class="layui-btn layui-btn-danger" type='button' data-confirm="确定要取消修改吗?" data-close>取消修改</button>
+        </div>
+    </div>
+    <script>form.render()</script>
+</form>

+ 80 - 0
application/admin/view/config/storage-qiniu.html

@@ -0,0 +1,80 @@
+<form onsubmit="return false" data-auto="true" action="{:url()}" method="post" class='layui-form layui-card' autocomplete="off">
+    <div class="layui-card-body">
+        <div class="color-text margin-left-40 margin-bottom-20 layui-code" style="border-left-width:1px;background:none">
+            <p class="margin-bottom-5 font-w7">文件将上传到七牛云存储,对象存储需要配置为公开访问的Bucket空间!</p>
+            完成实名认证后可获得10G免费存储空间哦!<a target="_blank" href="https://portal.qiniu.com/signup?code=1hefnmobzees2">我要免费申请</a>
+        </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="layui-form-item" data-storage-type="qiniu">
+            <label class="layui-form-label label-required">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">七牛云存储访问协议,其中 https 需要配置证书才能使用,auto 为相对协议。</p>
+            </div>
+        </div>
+        <div class="layui-form-item" data-storage-type="qiniu">
+            <label class="layui-form-label">Region<br><span class="nowrap color-desc label-required">存储区域</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 padding-left-40">
+            <input type="hidden" name="storage_type" value="qiniu">
+            <button class="layui-btn" type="submit">保存配置</button>
+            <button class="layui-btn layui-btn-danger" type='button' data-confirm="确定要取消修改吗?" data-close>取消修改</button>
+        </div>
+    </div>
+</form>

+ 90 - 0
application/admin/view/config/system-config.html

@@ -0,0 +1,90 @@
+<form onsubmit="return false" data-auto="true" action="{:url()}" method="post" class='layui-form layui-card' autocomplete="off">
+    <div class="layui-card-body padding-left-40">
+
+        <div class="layui-form-item">
+            <label class="relative block">
+                <span class="color-green font-w7">网站名称 Website</span>
+                <input name="site_name" required placeholder="请输入网站名称" value="{:sysconf('site_name')}" class="layui-input">
+            </label>
+            <p class="help-block">网站名称,将在浏览器的标签上显示名称</p>
+        </div>
+        <div class="layui-form-item">
+            <label class="relative block">
+                <span class="color-green font-w7">管理程序名称 Name</span>
+                <input name="app_name" required placeholder="请输入程序名称" value="{:sysconf('app_name')}" class="layui-input">
+            </label>
+            <p class="help-block">管理程序名称,在后台左上角标题处理显示</p>
+        </div>
+        <div class="layui-form-item">
+            <label class="relative block">
+                <span class="color-green font-w7">管理程序版本 Version</span>
+                <input name="app_version" placeholder="请输入程序版本" value="{:sysconf('app_version')}" class="layui-input">
+            </label>
+            <p class="help-block">管理程序版本,在后台左上角标题处理显示</p>
+        </div>
+<!--        <div class="layui-form-item">-->
+<!--            <span class="color-green font-w7">浏览器图标 Browser</span>-->
+<!--            <div class="relative block">-->
+<!--                <img alt="icon" data-tips-image style="height:auto;max-height:42px;min-width:42px" 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-type="ico,png" data-field="site_icon">上传图片</a>-->
+<!--                <p class="help-block">建议上传 ICO 图标的尺寸为 128x128 <a href="http://www.favicon-icon-generator.com" target="_blank">ICON在线制作</a></p>-->
+<!--            </div>-->
+<!--        </div>-->
+<!--        <div class="layui-form-item">-->
+<!--            <label class="relative block">-->
+<!--                <span class="color-green font-w7">网站备案号 Miitbeian</span>-->
+<!--                <input name="miitbeian" required placeholder="请输入网站备案号" value="{:sysconf('miitbeian')}" class="layui-input">-->
+<!--            </label>-->
+<!--            <p class="help-block">网站备案号,可以在<a target="_blank" href="http://beian.miit.gov.cn">备案管理中心</a>查询获取,将在登录页面下面显示</p>-->
+<!--        </div>-->
+<!--        <div class="layui-form-item">-->
+<!--            <label class="relative block">-->
+<!--                <span class="color-green font-w7">网站版权信息 Copyright</span>-->
+<!--                <input name="site_copy" required placeholder="请输入版权信息" value="{:sysconf('site_copy')}" class="layui-input">-->
+<!--            </label>-->
+<!--            <p class="help-block">网站版权信息,在后台登录页面显示版本信息并链接到备案到信息备案管理系统</p>-->
+<!--        </div>-->
+        <div class="layui-form-item">
+            <label class="relative block">
+                <span class="color-green font-w7">邮箱 email</span>
+                <input name="email" required placeholder="请输入邮箱" value="{:sysconf('email')}" class="layui-input">
+            </label>
+            <p class="help-block">邮箱</p>
+        </div>
+
+        <div class="layui-form-item">
+            <label class="relative block">
+                <span class="color-green font-w7">电话 phone</span>
+                <input name="phone" required placeholder="请输入电话" value="{:sysconf('phone')}" class="layui-input">
+            </label>
+            <p class="help-block">电话</p>
+        </div>
+
+        <div class="layui-col-md12">
+            <div class="layui-col-md3">
+                <div class="layui-form-item">
+                    <label class="relative block">
+                        <span class="color-green font-w7">游客看到联系方式开关 switch</span>
+                        <br/>
+                        <input type="radio" name="switch" value="1" lay-ignore> 开
+                        <input type="radio" name="switch" value="0" lay-ignore> 关
+
+                    </label>
+                    <p class="help-block">游客看到联系方式开关</p>
+                </div>
+            </div>
+        </div>
+
+
+
+        <div class="hr-line-dashed"></div>
+
+        <div class="layui-form-item text-center">
+            <button class="layui-btn" type="submit">保存配置</button>
+            <button class="layui-btn layui-btn-danger" type='button' data-confirm="确定要取消修改吗?" data-close>取消修改</button>
+        </div>
+    </div>
+
+</form>
+<script>form.render()</script>

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

@@ -0,0 +1,126 @@
+<!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?at={:date('md')}">
+    <link rel="stylesheet" href="__ROOT__/static/plugs/layui/css/layui.css?at={:date('md')}">
+    <link rel="stylesheet" href="__ROOT__/static/theme/css/console.css?at={:date('md')}">
+    {block name="style"}{/block}
+    <script>window.ROOT_URL = '__ROOT__';</script>
+    <script src="__ROOT__/static/plugs/jquery/pace.min.js"></script>
+    <script charset="utf-8" src="https://map.qq.com/api/js?v=2.exp&key=XYTBZ-WOX3X-LYJ44-TAK6Y-VU6HV-BWFIW"></script>
+</head>
+<style type="text/css">
+    .layui-nav-more {right:4px !important;}
+    .layui-nav-tree .layui-nav-child dd.layui-this, .layui-nav-tree .layui-nav-child dd.layui-this a, .layui-nav-tree .layui-this, .layui-nav-tree .layui-this>a, .layui-nav-tree .layui-this>a:hover{
+        background: #DC2219 !important;
+    }
+
+</style>
+<body class="layui-layout-body">
+{block name='body'}
+<div class="layui-layout layui-layout-admin layui-layout-left-hide">
+    <!-- 顶部菜单 开始 -->
+    <div class="layui-header notselect">
+        <a href="{:url('@')}" class="layui-logo layui-elip">
+            {:sysconf('app_name')}
+        </a>
+        <ul class="layui-nav layui-layout-left">
+            <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>
+            {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.username'}
+            <li class="layui-nav-item">
+                <dl class="layui-nav-child">
+                    <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-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>
+    <!-- 顶部菜单 结束 -->
+
+    <!-- 左则菜单 开始 -->
+    <div class="layui-side layui-bg-black notselect">
+        <div class="layui-side-scroll">
+
+            {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='{$twoMenu.icon|default="layui-icon layui-icon-link"}'></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>
+    </div>
+    <!-- 左则菜单 结束 -->
+
+    <!-- 主体内容 开始 -->
+    <div class="layui-body layui-bg-gray">{block name='content'}{/block}</div>
+    <!-- 主体内容 结束 -->
+
+</div>
+{/block}
+<script src="__ROOT__/static/plugs/layui/layui.all.js"></script>
+<script src="__ROOT__/static/plugs/echarts/echarts.min.js"></script>
+<script src="__ROOT__/static/plugs/require/require.js"></script>
+<script src="__ROOT__/static/admin.js"></script>
+{block name='script'}{/block}
+</body>
+
+</html>

+ 207 - 0
application/admin/view/index/main.html

@@ -0,0 +1,207 @@
+{extend name='main'}
+
+{block name='content'}
+
+<style>
+
+    .store-total-container {
+        font-size: 14px;
+        margin-bottom: 20px;
+        letter-spacing: 1px;
+    }
+
+    .store-total-container .store-total-icon {
+        top: 45%;
+        right: 8%;
+        font-size: 65px;
+        position: absolute;
+        color: rgba(255, 255, 255, 0.4);
+    }
+
+    .store-total-container .store-total-item {
+        color: #fff;
+        line-height: 4em;
+        padding: 15px 25px;
+        position: relative;
+    }
+
+    .store-total-container .store-total-item > div:nth-child(2) {
+        font-size: 46px;
+        line-height: 46px;
+    }
+
+</style>
+
+<div class="think-box-shadow store-total-container notselect">
+    <div class="margin-bottom-15">积分统计</div>
+    <div class="layui-row layui-col-space15">
+        <div class="layui-col-sm6 layui-col-md3">
+            <div class="store-total-item nowrap" style="background:linear-gradient(-125deg,#57bdbf,#2f9de2)">
+                <div>权益积分</div>
+                <div>{$array.all_equity_integral|default='0.0000'}</div>
+                <div>当前权益积分总量</div>
+            </div>
+            <i class="store-total-icon layui-icon layui-icon-template-1"></i>
+        </div>
+        <div class="layui-col-sm6 layui-col-md3">
+            <div class="store-total-item nowrap" style="background:linear-gradient(-125deg,#ff7d7d,#fb2c95)">
+                <div>可用积分</div>
+                <div>{$array.all_usable_integral|default='0.0000'}</div>
+                <div>当前可用积分总量</div>
+            </div>
+            <i class="store-total-icon layui-icon layui-icon-user"></i>
+        </div>
+        <div class="layui-col-sm6 layui-col-md3">
+            <div class="store-total-item nowrap" style="background:linear-gradient(-113deg,#c543d8,#925cc3)">
+                <div>库存积分</div>
+                <div>{$array.all_repertory_integral|default='0.0000'}</div>
+                <div>当前库存积分总量</div>
+            </div>
+            <i class="store-total-icon layui-icon layui-icon-read"></i>
+        </div>
+        <div class="layui-col-sm6 layui-col-md3">
+            <div class="store-total-item nowrap" style="background:linear-gradient(-141deg,#ecca1b,#f39526)">
+                <div>购物券</div>
+                <div>{$array.all_coupon|default='0.0000'}</div>
+                <div>当前购物券总量</div>
+            </div>
+            <i class="store-total-icon layui-icon layui-icon-survey"></i>
+        </div>
+    </div>
+</div>
+
+<!--<div class="think-box-shadow store-total-container">-->
+<!--    <div class="margin-bottom-15">实时概况</div>-->
+<!--    <div class="layui-row layui-col-space15">-->
+<!--        <div class="layui-col-md6 margin-bottom-15">-->
+<!--            <div class="layui-row">-->
+<!--                <div class="layui-col-xs3 text-center">-->
+<!--                    <i class="layui-icon color-blue" style="font-size:60px;line-height:72px">&#xe65e;</i>-->
+<!--                </div>-->
+<!--                <div class="layui-col-xs4">-->
+<!--                    <div class="font-s14">销售额(元)</div>-->
+<!--                    <div class="font-s16">1351.00</div>-->
+<!--                    <div class="font-s12 color-desc">昨日:974.00</div>-->
+<!--                </div>-->
+<!--                <div class="layui-col-xs5">-->
+<!--                    <div class="font-s14">支付订单数</div>-->
+<!--                    <div class="font-s16">106</div>-->
+<!--                    <div class="font-s12 color-desc">昨日:76</div>-->
+<!--                </div>-->
+<!--            </div>-->
+<!--        </div>-->
+<!--        <div class="layui-col-md6 margin-bottom-15">-->
+<!--            <div class="layui-row">-->
+<!--                <div class="layui-col-xs3 text-center">-->
+<!--                    <i class="layui-icon color-blue" style="font-size:60px;line-height:72px">&#xe663;</i>-->
+<!--                </div>-->
+<!--                <div class="layui-col-xs4">-->
+<!--                    <div class="font-s14">新增用户数</div>-->
+<!--                    <div class="font-s16">327</div>-->
+<!--                    <div class="font-s12 color-desc">昨日:238</div>-->
+<!--                </div>-->
+<!--                <div class="layui-col-xs5">-->
+<!--                    <div class="font-s14">下单用户数</div>-->
+<!--                    <div class="font-s16">69</div>-->
+<!--                    <div class="font-s12 color-desc">昨日:34</div>-->
+<!--                </div>-->
+<!--            </div>-->
+<!--        </div>-->
+<!--    </div>-->
+<!--</div>-->
+
+<!--<div class="layui-row layui-col-space15">-->
+<!--    <div class="layui-col-md6">-->
+<!--        <div class="think-box-shadow">-->
+<!--            <table class="layui-table" lay-skin="line" lay-even>-->
+<!--                <caption class="text-left margin-bottom-15 font-s14">系统信息</caption>-->
+<!--                <colgroup>-->
+<!--                    <col width="30%">-->
+<!--                </colgroup>-->
+<!--                <tbody>-->
+<!--                <tr>-->
+<!--                    <td>当前程序版本</td>-->
+<!--                    <td>{:sysconf('app_version')}</td>-->
+<!--                </tr>-->
+<!--                <tr>-->
+<!--                    <td>运行PHP版本</td>-->
+<!--                    <td>{$Think.PHP_VERSION}</td>-->
+<!--                </tr>-->
+<!--                <tr>-->
+<!--                    <td>ThinkPHP版本</td>-->
+<!--                    <td>{$think_ver}</td>-->
+<!--                </tr>-->
+<!--                <tr>-->
+<!--                    <td>MySQL数据库版本</td>-->
+<!--                    <td>{$mysql_ver}</td>-->
+<!--                </tr>-->
+<!--                <tr>-->
+<!--                    <td>服务器操作系统</td>-->
+<!--                    <td>{:php_uname('s')}</td>-->
+<!--                </tr>-->
+<!--                <tr>-->
+<!--                    <td>WEB运行环境</td>-->
+<!--                    <td>{:php_sapi_name()}</td>-->
+<!--                </tr>-->
+<!--                <tr>-->
+<!--                    <td>上传大小限制</td>-->
+<!--                    <td>{:ini_get('upload_max_filesize')}</td>-->
+<!--                </tr>-->
+<!--                <tr>-->
+<!--                    <td>POST大小限制</td>-->
+<!--                    <td>{:ini_get('post_max_size')}</td>-->
+<!--                </tr>-->
+<!--                </tbody>-->
+<!--            </table>-->
+<!--        </div>-->
+<!--    </div>-->
+<!--    <div class="layui-col-md6">-->
+<!--        <div class="think-box-shadow">-->
+<!--            <table class="layui-table" lay-skin="line" lay-even>-->
+<!--                <caption class="text-left margin-bottom-15 font-s14">产品团队</caption>-->
+<!--                <colgroup>-->
+<!--                    <col width="30%">-->
+<!--                </colgroup>-->
+<!--                <tbody>-->
+<!--                <tr>-->
+<!--                    <td>产品名称</td>-->
+<!--                    <td>ThinkAdmin</td>-->
+<!--                </tr>-->
+<!--                <tr>-->
+<!--                    <td>在线体验</td>-->
+<!--                    <td><a target="_blank" href="http://demo.thinkadmin.top">http://demo.thinkadmin.top</a></td>-->
+<!--                </tr>-->
+<!--                <tr>-->
+<!--                    <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>项目地址</td>-->
+<!--                    <td><a target="_blank" href="https://github.com/zoujingli/ThinkAdmin">https://github.com/zoujingli/ThinkAdmin</a></td>-->
+<!--                </tr>-->
+<!--                <tr>-->
+<!--                    <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>开发团队</td>-->
+<!--                    <td><a href="http://www.cuci.cc" target="_blank">广州楚才信息科技有限公司</a></td>-->
+<!--                </tr>-->
+<!--                <tr>-->
+<!--                    <td>团队官网</td>-->
+<!--                    <td><a target="_blank" href="http://www.cuci.cc">http://www.cuci.cc</a></td>-->
+<!--                </tr>-->
+<!--                <tr>-->
+<!--                    <td>办公地址</td>-->
+<!--                    <td>广州市天河区东圃一横路东泷商贸中心G02</td>-->
+<!--                </tr>-->
+<!--                </tbody>-->
+<!--            </table>-->
+<!--        </div>-->
+<!--    </div>-->
+<!--</div>-->
+{/block}

+ 98 - 0
application/admin/view/login/index.html

@@ -0,0 +1,98 @@
+{extend name="index/index"}
+
+{block name="body"}
+<style>
+    .login-container{
+
+        background: linear-gradient(135deg, #393D4A 0%, #282B33 100%);
+    }
+    .login-container form{
+        padding: 50px;
+        margin-left: -200px;
+        background: #FFFFFF;
+        border-radius: 20px;
+    }
+    .login-container form ul li button{
+        background: #DC0619 !important;
+        border-radius: 33px !important;
+        color: #fff !important;
+
+    }
+    .login-container form ul li input{
+        background: #FFFFFF;
+        border-radius: 2px;
+        border: 2px solid #D1D1D1;
+        text-shadow:none !important;
+        letter-spacing:0px !important;
+        color: #ccc !important;
+        -webkit-text-fill-color:#000 !important;
+        box-shadow:none !important;
+
+        color: #000 !important;
+
+    }
+    .lo{
+        width: 100%;
+
+    }
+    h3{
+        text-align: center;
+        font-size: 16px;
+        margin: 30px 0;
+    }
+    input[placeholder], [placeholder], *[placeholder] { color:#ccc !important; }
+
+</style>
+<div class="login-container" data-supersized="__ROOT__/static/theme/img/login/bg1.jpg,__ROOT__/static/theme/img/login/bg2.jpg">
+    <div class="header notselect layui-hide-xs">
+        {notempty name='devmode'}
+        <a class="pull-right layui-anim layui-anim-fadein" href='https://gitee.com/zoujingli/ThinkAdmin'>
+            <img src='https://gitee.com/zoujingli/ThinkAdmin/widgets/widget_1.svg' alt='Fork me on Gitee'>
+        </a>
+        {/notempty}
+    </div>
+    <form data-login-form onsubmit="return false" method="post" class="layui-anim layui-anim-upbit" autocomplete="off">
+        <img src="__ROOT__/static/cc.png" class="lo"/>
+        <h3>目标成本分析系统</h3>
+        <h3>登录</h3>
+        <ul>
+            <li class="username">
+                <label>
+                    <i class="layui-icon layui-icon-username" style="text-shadow:none !important;color: #D1D1D1 !important;"></i>
+                    <input class="layui-input" required pattern="^\S{4,}$" name="username" autofocus autocomplete="off" placeholder="登录账号" title="请输入登录账号" style="-webkit-text-fill-color:#000 !important;box-shadow:none !important; ">
+                </label>
+            </li>
+            <li class="password">
+                <label>
+                    <i class="layui-icon layui-icon-password" style="text-shadow:none !important;color: #D1D1D1 !important;"></i>
+                    <input class="layui-input" required pattern="^\S{4,}$" name="password" maxlength="32" type="password" autocomplete="off" placeholder="登录密码" title="请输入登录密码" style="-webkit-text-fill-color:#000 !important;box-shadow:none !important; ">
+                </label>
+            </li>
+            <li class="verify layui-hide">
+                <label class="inline-block relative">
+                    <i class="layui-icon layui-icon-picture-fine"></i>
+                    <input class="layui-input" required pattern="^\S{4,}$" name="verify" maxlength="4" autocomplete="off" placeholder="验证码" title="请输入验证码">
+                </label>
+                <label data-captcha="{:url('admin/login/captcha',[],false)}" data-field-verify="verify" data-field-uniqid="uniqid" data-captcha-type="{$captcha_type}" data-captcha-token="{$captcha_token}"></label>
+            </li>
+            <li class="text-center padding-top-20">
+                <button type="submit" class="layui-btn layui-disabled full-width" data-form-loaded="登录">正在载入</button>
+            </li>
+        </ul>
+    </form>
+    <div class="footer notselect">
+        <p class="layui-hide-xs"><a target="_blank" href="#">鲁ICP备2021010683号-1</a></p>
+    </div>
+</div>
+{/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/login.js"></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 layui-bg-gray">
+    {block name='style'}{/block}
+    {notempty name='title'}
+    <div class="layui-card-header layui-anim layui-anim-fadein notselect">
+        <span class="layui-icon layui-icon-next font-s10 color-desc margin-right-5"></span>{$title|default=''}
+        <div class="pull-right">{block name='button'}{/block}</div>
+    </div>
+    {/notempty}
+    <div class="layui-card-body layui-anim layui-anim-upbit">{block name='content'}{/block}</div>
+    {block name='script'}{/block}
+</div>

+ 347 - 0
application/admin/view/main_project/contrast.html

@@ -0,0 +1,347 @@
+{extend name='main'}
+
+{block name="button"}
+
+{if auth("contrast")}
+<button class="layui-btn layui-btn-sm" style="background-color: #DC2219" onclick="getIds()" >导出</button>
+{/if}
+
+<button class="layui-btn" style="height: 30px;line-height:28px;color:#FFFFFF;background-color: #DC2219;border: 1px solid #C9C9C9 " type='button' onclick="window.history.back()">返 回</button>
+
+{/block}
+
+{block name="content"}
+<div class="think-box-shadow">
+    <table class="layui-table margin-top-10">
+        <input type="hidden" name="ids" id="ids" value="{$ids}">
+        {notempty name='list'}
+        <thead>
+        <tr>
+            <th class='text-left nowrap' rowspan="2">成本预算科目</th>
+            <th class='text-center nowrap' colspan="3">不含增值税测算成本</th>
+            <th class='text-center nowrap' colspan="3">增值税总额</th>
+            <th class='text-center nowrap' colspan="3">含增值税测算成本</th>
+            <th class='text-center nowrap' colspan="3">建面单方成本指标(不含税)</th>
+            <th class='text-center nowrap' colspan="3">建面单方成本指标(含税)</th>
+            <th class='text-center nowrap' colspan="3">可售单方成本指标(不含税)</th>
+            <th class='text-center nowrap' colspan="3">可售单方成本指标(含税)</th>
+            <th class='text-center nowrap' rowspan="2">操作</th>
+        </tr>
+        <tr>
+            <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>
+            <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>
+            <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>
+        {/notempty}
+        <tbody>
+        {foreach $list as $key=>$vo}
+        <tr class="tr_{$vo.id}">
+            <td class='text-left nowrap '
+                onclick='dianji($(this))' data-id="{$vo.id}">
+                {$vo.subjects|default=''}
+                {if count($vo['children']) > 0}
+                <i class="layui-icon layui-icon-triangle-r margin-right-5 icon_{$vo.id}"></i>
+                {/if}
+            </td>
+            <td class='text-left nowrap'>{$vo.costs_are_excluded_interval|default='-'}</td>
+            <td class='text-left nowrap'>{$vo.costs_are_excluded_arithmetic_mean|default=''}</td>
+            <td class='text-left nowrap'>{$vo.costs_are_excluded_valid_sample_size|default=''}</td>
+            <td class='text-left nowrap'>{$vo.total_vat_interval|default=''}</td>
+            <td class='text-left nowrap'>{$vo.total_vat_arithmetic_mean|default='-'}</td>
+            <td class='text-left nowrap'>{$vo.total_vat_valid_sample_size|default=''}</td>
+            <td class='text-left nowrap'>{$vo.measurement_cost_interval|default=''}</td>
+            <td class='text-left nowrap'>{$vo.measurement_cost_arithmetic_mean|default='-'}</td>
+            <td class='text-left nowrap'>{$vo.measurement_cost_valid_sample_size|default=''}</td>
+            <td class='text-left nowrap'>{$vo.unilateral_cost_indicator_interval|default=''}</td>
+            <td class='text-left nowrap'>{$vo.unilateral_cost_indicator_arithmetic_mean|default='-'}</td>
+            <td class='text-left nowrap'>{$vo.unilateral_cost_indicator_valid_sample_size|default=''}</td>
+            <td class='text-left nowrap'>{$vo.single_cost_indicator_interval|default=''}</td>
+            <td class='text-left nowrap'>{$vo.single_cost_indicator_arithmetic_mean|default='-'}</td>
+            <td class='text-left nowrap'>{$vo.single_cost_indicator_valid_sample_size|default=''}</td>
+            <td class='text-left nowrap'>{$vo.single_party_cost_tax_interval|default=''}</td>
+            <td class='text-left nowrap'>{$vo.single_party_cost_tax_arithmetic_mean|default='-'}</td>
+            <td class='text-left nowrap'>{$vo.single_party_cost_tax_valid_sample_size|default=''}</td>
+            <td class='text-left nowrap'>{$vo.single_party_cost_no_tax_interval|default=''}</td>
+            <td class='text-left nowrap'>{$vo.single_party_cost_no_tax_arithmetic_mean|default='-'}</td>
+            <td class='text-left nowrap'>{$vo.single_party_cost_no_tax_valid_sample_size|default=''}</td>
+            <td class='text-left nowrap'>
+                {if auth("see")}
+                <a data-dbclick class="layui-btn layui-btn-sm" style="background-color: #DC2219" data-title="查看" data-open='{:url("see")}?subjects={$vo.subjects}&ids={$ids}'>查 看</a>
+                {/if}
+            </td>
+        </tr>
+
+
+            {foreach $vo['children'] as $k=>$v}
+            <tr  class="t tr_{$vo.id} tr_{$v.id} trs_{$vo.id}" style="display: none">
+                <td class='text-left nowrap'
+                    onclick='dianji($(this))' data-id="{$v.id}">
+                    <span class="color-desc" style="margin-left: 15px; margin-right: 10px"></span>{$v.subjects|default=''}
+                    {if count($v['children']) > 0}
+                    <i class="layui-icon layui-icon-triangle-r margin-right-5 icon_{$v.id}"></i>
+                    {/if}
+                </td>
+                <td class='text-left nowrap'>{$v.costs_are_excluded_interval|default='-'}</td>
+                <td class='text-left nowrap'>{$v.costs_are_excluded_arithmetic_mean|default=''}</td>
+                <td class='text-left nowrap'>{$v.costs_are_excluded_valid_sample_size|default=''}</td>
+                <td class='text-left nowrap'>{$v.total_vat_interval|default=''}</td>
+                <td class='text-left nowrap'>{$v.total_vat_arithmetic_mean|default='-'}</td>
+                <td class='text-left nowrap'>{$v.total_vat_valid_sample_size|default=''}</td>
+                <td class='text-left nowrap'>{$v.measurement_cost_interval|default=''}</td>
+                <td class='text-left nowrap'>{$v.measurement_cost_arithmetic_mean|default='-'}</td>
+                <td class='text-left nowrap'>{$v.measurement_cost_valid_sample_size|default=''}</td>
+                <td class='text-left nowrap'>{$v.unilateral_cost_indicator_interval|default=''}</td>
+                <td class='text-left nowrap'>{$v.unilateral_cost_indicator_arithmetic_mean|default='-'}</td>
+                <td class='text-left nowrap'>{$v.unilateral_cost_indicator_valid_sample_size|default=''}</td>
+                <td class='text-left nowrap'>{$v.single_cost_indicator_interval|default=''}</td>
+                <td class='text-left nowrap'>{$v.single_cost_indicator_arithmetic_mean|default='-'}</td>
+                <td class='text-left nowrap'>{$v.single_cost_indicator_valid_sample_size|default=''}</td>
+                <td class='text-left nowrap'>{$v.single_party_cost_tax_interval|default=''}</td>
+                <td class='text-left nowrap'>{$v.single_party_cost_tax_arithmetic_mean|default='-'}</td>
+                <td class='text-left nowrap'>{$v.single_party_cost_tax_valid_sample_size|default=''}</td>
+                <td class='text-left nowrap'>{$v.single_party_cost_no_tax_interval|default=''}</td>
+                <td class='text-left nowrap'>{$v.single_party_cost_no_tax_arithmetic_mean|default='-'}</td>
+                <td class='text-left nowrap'>{$v.single_party_cost_no_tax_valid_sample_size|default=''}</td>
+                <td class='text-left nowrap'>
+                    {if auth("see")}
+                    <a data-dbclick class="layui-btn layui-btn-sm" data-title="查看" style="background-color: #DC2219" data-open='{:url("see")}?subjects={$v.subjects}&ids={$ids}'>查 看</a>
+                    {/if}
+                </td>
+            </tr>
+
+
+
+                {foreach $v['children'] as $k=>$vv}
+                <tr  class="t tr_{$v.id} tr_{$vv.id} trs_{$vo.id} trs_{$v.id}" style="display: none">
+                    <td class='text-left nowrap'
+                        onclick='dianji($(this))' data-id="{$vv.id}">
+                        <span class="color-desc" style="margin-left: 15px; margin-right: 20px"></span>
+                        {$vv.subjects|default=''}
+                        {if count($vv['children']) > 0}
+                        <i class="layui-icon layui-icon-triangle-r margin-right-5 icon_{$vv.id}"></i>
+                        {/if}
+                    </td>
+                    <td class='text-left nowrap'>{$vv.costs_are_excluded_interval|default='-'}</td>
+                    <td class='text-left nowrap'>{$vv.costs_are_excluded_arithmetic_mean|default=''}</td>
+                    <td class='text-left nowrap'>{$vv.costs_are_excluded_valid_sample_size|default=''}</td>
+                    <td class='text-left nowrap'>{$vv.total_vat_interval|default=''}</td>
+                    <td class='text-left nowrap'>{$vv.total_vat_arithmetic_mean|default='-'}</td>
+                    <td class='text-left nowrap'>{$vv.total_vat_valid_sample_size|default=''}</td>
+                    <td class='text-left nowrap'>{$vv.measurement_cost_interval|default=''}</td>
+                    <td class='text-left nowrap'>{$vv.measurement_cost_arithmetic_mean|default='-'}</td>
+                    <td class='text-left nowrap'>{$vv.measurement_cost_valid_sample_size|default=''}</td>
+                    <td class='text-left nowrap'>{$vv.unilateral_cost_indicator_interval|default=''}</td>
+                    <td class='text-left nowrap'>{$vv.unilateral_cost_indicator_arithmetic_mean|default='-'}</td>
+                    <td class='text-left nowrap'>{$vv.unilateral_cost_indicator_valid_sample_size|default=''}</td>
+                    <td class='text-left nowrap'>{$vv.single_cost_indicator_interval|default=''}</td>
+                    <td class='text-left nowrap'>{$vv.single_cost_indicator_arithmetic_mean|default='-'}</td>
+                    <td class='text-left nowrap'>{$vv.single_cost_indicator_valid_sample_size|default=''}</td>
+                    <td class='text-left nowrap'>{$vv.single_party_cost_tax_interval|default=''}</td>
+                    <td class='text-left nowrap'>{$vv.single_party_cost_tax_arithmetic_mean|default='-'}</td>
+                    <td class='text-left nowrap'>{$vv.single_party_cost_tax_valid_sample_size|default=''}</td>
+                    <td class='text-left nowrap'>{$vv.single_party_cost_no_tax_interval|default=''}</td>
+                    <td class='text-left nowrap'>{$vv.single_party_cost_no_tax_arithmetic_mean|default='-'}</td>
+                    <td class='text-left nowrap'>{$vv.single_party_cost_no_tax_valid_sample_size|default=''}</td>
+                    <td class='text-left nowrap'>
+                        {if auth("see")}
+                        <a data-dbclick class="layui-btn layui-btn-sm" style="background-color: #DC2219" data-title="查看" data-open='{:url("see")}?subjects={$vv.subjects}&ids={$ids}'>查 看</a>
+                        {/if}
+                    </td>
+                </tr>
+                    {foreach $vv['children'] as $k=>$vvv}
+                    <tr  class="t tr_{$vv.id} tr_{$vvv.id} trs_{$vo.id} trs_{$v.id} trs_{$vv.id}" style="display: none">
+                        <td class='text-left nowrap'
+                            onclick='dianji($(this))' data-id="{$vvv.id}">
+                            <span class="color-desc" style="margin-left: 15px; margin-right: 30px"></span>
+                            {$vvv.subjects|default=''}
+                            {if count($vvv['children']) > 0}
+                            <i class="layui-icon layui-icon-triangle-r margin-right-5 icon_{$vvv.id}"></i>
+                            {/if}
+                        </td>
+                        <td class='text-left nowrap'>{$vvv.costs_are_excluded_interval|default='-'}</td>
+                        <td class='text-left nowrap'>{$vvv.costs_are_excluded_arithmetic_mean|default=''}</td>
+                        <td class='text-left nowrap'>{$vvv.costs_are_excluded_valid_sample_size|default=''}</td>
+                        <td class='text-left nowrap'>{$vvv.total_vat_interval|default=''}</td>
+                        <td class='text-left nowrap'>{$vvv.total_vat_arithmetic_mean|default='-'}</td>
+                        <td class='text-left nowrap'>{$vvv.total_vat_valid_sample_size|default=''}</td>
+                        <td class='text-left nowrap'>{$vvv.measurement_cost_interval|default=''}</td>
+                        <td class='text-left nowrap'>{$vvv.measurement_cost_arithmetic_mean|default='-'}</td>
+                        <td class='text-left nowrap'>{$vvv.measurement_cost_valid_sample_size|default=''}</td>
+                        <td class='text-left nowrap'>{$vvv.unilateral_cost_indicator_interval|default=''}</td>
+                        <td class='text-left nowrap'>{$vvv.unilateral_cost_indicator_arithmetic_mean|default='-'}</td>
+                        <td class='text-left nowrap'>{$vvv.unilateral_cost_indicator_valid_sample_size|default=''}</td>
+                        <td class='text-left nowrap'>{$vvv.single_cost_indicator_interval|default=''}</td>
+                        <td class='text-left nowrap'>{$vvv.single_cost_indicator_arithmetic_mean|default='-'}</td>
+                        <td class='text-left nowrap'>{$vvv.single_cost_indicator_valid_sample_size|default=''}</td>
+                        <td class='text-left nowrap'>{$vvv.single_party_cost_tax_interval|default=''}</td>
+                        <td class='text-left nowrap'>{$vvv.single_party_cost_tax_arithmetic_mean|default='-'}</td>
+                        <td class='text-left nowrap'>{$vvv.single_party_cost_tax_valid_sample_size|default=''}</td>
+                        <td class='text-left nowrap'>{$vvv.single_party_cost_no_tax_interval|default=''}</td>
+                        <td class='text-left nowrap'>{$vvv.single_party_cost_no_tax_arithmetic_mean|default='-'}</td>
+                        <td class='text-left nowrap'>{$vvv.single_party_cost_no_tax_valid_sample_size|default=''}</td>
+                        <td class='text-left nowrap'>
+                            {if auth("see")}
+                            <a data-dbclick class="layui-btn layui-btn-sm" style="background-color: #DC2219" data-title="查看" data-open='{:url("see")}?subjects={$vvv.subjects}&ids={$ids}'>查 看</a>
+                            {/if}
+                        </td>
+                    </tr>
+                        {foreach $vvv['children'] as $k=>$vvvv}
+                        <tr  class="t tr_{$vvv.id}  tr_{$vvvv.id} trs_{$vo.id} trs_{$v.id} trs_{$vv.id} trs_{$vvv.id}" style="display: none" >
+                            <td class='text-left nowrap'
+                                onclick='dianji($(this))' data-id="{$vvvv.id}">
+                                <span class="color-desc" style="margin-left: 15px; margin-right: 40px"></span>
+                                {$vvvv.subjects|default=''}
+                                {if count($vvvv['children']) > 0}
+                                <i class="layui-icon layui-icon-triangle-r margin-right-5 icon_{$vvvv.id}"></i>
+                                {/if}
+                            </td>
+                            <td class='text-left nowrap'>{$vvvv.costs_are_excluded_interval|default='-'}</td>
+                            <td class='text-left nowrap'>{$vvvv.costs_are_excluded_arithmetic_mean|default=''}</td>
+                            <td class='text-left nowrap'>{$vvvv.costs_are_excluded_valid_sample_size|default=''}</td>
+                            <td class='text-left nowrap'>{$vvvv.total_vat_interval|default=''}</td>
+                            <td class='text-left nowrap'>{$vvvv.total_vat_arithmetic_mean|default='-'}</td>
+                            <td class='text-left nowrap'>{$vvvv.total_vat_valid_sample_size|default=''}</td>
+                            <td class='text-left nowrap'>{$vvvv.measurement_cost_interval|default=''}</td>
+                            <td class='text-left nowrap'>{$vvvv.measurement_cost_arithmetic_mean|default='-'}</td>
+                            <td class='text-left nowrap'>{$vvvv.measurement_cost_valid_sample_size|default=''}</td>
+                            <td class='text-left nowrap'>{$vvvv.unilateral_cost_indicator_interval|default=''}</td>
+                            <td class='text-left nowrap'>{$vvvv.unilateral_cost_indicator_arithmetic_mean|default='-'}</td>
+                            <td class='text-left nowrap'>{$vvvv.unilateral_cost_indicator_valid_sample_size|default=''}</td>
+                            <td class='text-left nowrap'>{$vvvv.single_cost_indicator_interval|default=''}</td>
+                            <td class='text-left nowrap'>{$vvvv.single_cost_indicator_arithmetic_mean|default='-'}</td>
+                            <td class='text-left nowrap'>{$vvvv.single_cost_indicator_valid_sample_size|default=''}</td>
+                            <td class='text-left nowrap'>{$vvvv.single_party_cost_tax_interval|default=''}</td>
+                            <td class='text-left nowrap'>{$vvvv.single_party_cost_tax_arithmetic_mean|default='-'}</td>
+                            <td class='text-left nowrap'>{$vvvv.single_party_cost_tax_valid_sample_size|default=''}</td>
+                            <td class='text-left nowrap'>{$vvvv.single_party_cost_no_tax_interval|default=''}</td>
+                            <td class='text-left nowrap'>{$vvvv.single_party_cost_no_tax_arithmetic_mean|default='-'}</td>
+                            <td class='text-left nowrap'>{$vvvv.single_party_cost_no_tax_valid_sample_size|default=''}</td>
+                            <td class='text-left nowrap'>
+                                {if auth("see")}
+                                <a data-dbclick class="layui-btn layui-btn-sm" style="background-color: #DC2219" data-title="查看" data-open='{:url("see")}?subjects={$vvvv.subjects}&ids={$ids}'>查 看</a>
+                                {/if}
+                            </td>
+                        </tr>
+                            {foreach $vvvv['children'] as $k=>$vvvvv}
+                            <tr  class="t tr_{$vvvv.id} tr_{$vvvvv.id} trs_{$vo.id} trs_{$v.id} trs_{$vv.id} trs_{$vvv.id} trs_{$vvvv.id}" style="display: none">
+                                <td class='text-left nowrap'
+
+                                    onclick='dianji($(this))' data-id="{$vvvvv.id}">
+                                    <span class="color-desc" style="margin-left: 15px; margin-right: 50px"></span>
+                                    {$vvvvv.subjects|default=''}
+                                    {if count($vvvvv['children']) > 0}
+                                    <i class="layui-icon layui-icon-triangle-r margin-right-5 icon_{$vvvvv.id}"></i>
+                                    {/if}
+                                </td>
+                                <td class='text-left nowrap'>{$vvvvv.costs_are_excluded_interval|default='-'}</td>
+                                <td class='text-left nowrap'>{$vvvvv.costs_are_excluded_arithmetic_mean|default=''}</td>
+                                <td class='text-left nowrap'>{$vvvvv.costs_are_excluded_valid_sample_size|default=''}</td>
+                                <td class='text-left nowrap'>{$vvvvv.total_vat_interval|default=''}</td>
+                                <td class='text-left nowrap'>{$vvvvv.total_vat_arithmetic_mean|default='-'}</td>
+                                <td class='text-left nowrap'>{$vvvvv.total_vat_valid_sample_size|default=''}</td>
+                                <td class='text-left nowrap'>{$vvvvv.measurement_cost_interval|default=''}</td>
+                                <td class='text-left nowrap'>{$vvvvv.measurement_cost_arithmetic_mean|default='-'}</td>
+                                <td class='text-left nowrap'>{$vvvvv.measurement_cost_valid_sample_size|default=''}</td>
+                                <td class='text-left nowrap'>{$vvvvv.unilateral_cost_indicator_interval|default=''}</td>
+                                <td class='text-left nowrap'>{$vvvvv.unilateral_cost_indicator_arithmetic_mean|default='-'}</td>
+                                <td class='text-left nowrap'>{$vvvvv.unilateral_cost_indicator_valid_sample_size|default=''}</td>
+                                <td class='text-left nowrap'>{$vvvvv.single_cost_indicator_interval|default=''}</td>
+                                <td class='text-left nowrap'>{$vvvvv.single_cost_indicator_arithmetic_mean|default='-'}</td>
+                                <td class='text-left nowrap'>{$vvvvv.single_cost_indicator_valid_sample_size|default=''}</td>
+                                <td class='text-left nowrap'>{$vvvvv.single_party_cost_tax_interval|default=''}</td>
+                                <td class='text-left nowrap'>{$vvvvv.single_party_cost_tax_arithmetic_mean|default='-'}</td>
+                                <td class='text-left nowrap'>{$vvvvv.single_party_cost_tax_valid_sample_size|default=''}</td>
+                                <td class='text-left nowrap'>{$vvvvv.single_party_cost_no_tax_interval|default=''}</td>
+                                <td class='text-left nowrap'>{$vvvvv.single_party_cost_no_tax_arithmetic_mean|default='-'}</td>
+                                <td class='text-left nowrap'>{$vvvvv.single_party_cost_no_tax_valid_sample_size|default=''}</td>
+                                <td class='text-left nowrap'>
+                                    {if auth("see")}
+                                    <a data-dbclick class="layui-btn layui-btn-sm" style="background-color: #DC2219" data-title="查看" data-open='{:url("see")}?subjects={$vvvvv.subjects}&ids={$ids}'>查 看</a>
+                                    {/if}
+                                </td>
+                            </tr>
+                            {/foreach}
+                        {/foreach}
+                    {/foreach}
+                {/foreach}
+            {/foreach}
+
+
+        {/foreach}
+
+        </tbody>
+    </table>
+
+    {empty name='list'}<span class="notdata">没有记录哦</span>{else}{$pagehtml|raw|default=''}{/empty}
+
+</div>
+<script>
+    function getIds()
+    {
+        var ids = $("#ids").val();
+        window.location = '{:url("admin/main_project/download")}?ids=' +ids;
+    }
+
+    function dianji(e){
+        var id=e.attr('data-id');
+        var tr=e. parents('tr');
+
+        if(tr.hasClass('flag')){
+
+
+            $('.trs_'+id).hide();
+
+
+            tr.find('i').removeClass('layui-icon-triangle-d')
+            tr.find('i').addClass('layui-icon-triangle-r')
+
+            $('.trs_'+id).find('i').removeClass('layui-icon-triangle-d')
+            $('.trs_'+id).find('i').addClass('layui-icon-triangle-r')
+
+            $('.trs_'+id).removeClass('flag')
+            tr.removeClass('flag')
+        }else{
+
+
+            e.find('i').removeClass('layui-icon-triangle-r')
+            e.find('i').addClass('layui-icon-triangle-d')
+            $('.tr_'+id).show();
+            tr.addClass('flag')
+
+
+
+        }
+
+
+
+
+
+
+
+
+
+
+
+
+    }
+</script>
+{/block}

+ 86 - 0
application/admin/view/main_project/contrast1.html

@@ -0,0 +1,86 @@
+{extend name='main'}
+
+{block name="button"}
+
+{if auth("contrast")}
+<button class="layui-btn layui-btn-sm layui-btn-primary layui-bg-red" onclick="getIds()" >导出</button>
+{/if}
+<button class="layui-btn" style="height: 30px;line-height:28px;background-color: snow;color: #333;border: 1px solid #C9C9C9 " type='button' onclick="window.history.back()">返 回</button>
+
+{/block}
+
+{block name="content"}
+<div class="think-box-shadow">
+    <table class="layui-table margin-top-10">
+        <input type="hidden" name="ids" id="ids" value="{$ids}">
+        {notempty name='list'}
+        <thead>
+        <tr>
+            <th class='text-left nowrap' rowspan="2">成本预算科目</th>
+            <th class='text-center nowrap' colspan="3">不含增值税测算成本</th>
+            <th class='text-center nowrap' colspan="3">增值税总额</th>
+            <th class='text-center nowrap' colspan="3">含增值税测算成本</th>
+            <th class='text-center nowrap' colspan="3">单方成本指标(不含税)</th>
+            <th class='text-center nowrap' colspan="3">单方成本指标(含税)</th>
+            <th class='text-center nowrap' rowspan="2">操作</th>
+        </tr>
+        <tr style="border: 1px">
+            <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>
+            <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>
+            <th class='text-left nowrap'>有效样本量</th>
+        </tr>
+        </thead>
+        {/notempty}
+        <tbody>
+        {foreach $list as $key=>$vo}
+        <tr style="border: 1px">
+
+            <td class='text-left nowrap'>{$vo.subjects|default=''}</td>
+            <td class='text-left nowrap'>{$vo.costs_are_excluded_interval|default='-'}</td>
+            <td class='text-left nowrap'>{$vo.costs_are_excluded_arithmetic_mean|default=''}</td>
+            <td class='text-left nowrap'>{$vo.costs_are_excluded_valid_sample_size|default=''}</td>
+            <td class='text-left nowrap'>{$vo.total_vat_interval|default=''}</td>
+            <td class='text-left nowrap'>{$vo.total_vat_arithmetic_mean|default='-'}</td>
+            <td class='text-left nowrap'>{$vo.total_vat_valid_sample_size|default=''}</td>
+            <td class='text-left nowrap'>{$vo.measurement_cost_interval|default=''}</td>
+            <td class='text-left nowrap'>{$vo.measurement_cost_arithmetic_mean|default='-'}</td>
+            <td class='text-left nowrap'>{$vo.measurement_cost_valid_sample_size|default=''}</td>
+            <td class='text-left nowrap'>{$vo.unilateral_cost_indicator_interval|default=''}</td>
+            <td class='text-left nowrap'>{$vo.unilateral_cost_indicator_arithmetic_mean|default='-'}</td>
+            <td class='text-left nowrap'>{$vo.unilateral_cost_indicator_valid_sample_size|default=''}</td>
+            <td class='text-left nowrap'>{$vo.single_cost_indicator_interval|default=''}</td>
+            <td class='text-left nowrap'>{$vo.single_cost_indicator_arithmetic_mean|default='-'}</td>
+            <td class='text-left nowrap'>{$vo.single_cost_indicator_valid_sample_size|default=''}</td>
+            <td class='text-left nowrap'>
+                {if auth("look")}
+                <a data-dbclick class="layui-btn layui-btn-sm layui-bg-red" data-title="查看" data-open='{:url("see")}?subjects={$vo.subjects}&ids={$ids}'>查 看</a>
+                {/if}
+            </td>
+        </tr>
+        {/foreach}
+        </tbody>
+    </table>
+
+    {empty name='list'}<span class="notdata">没有记录哦</span>{else}{$pagehtml|raw|default=''}{/empty}
+
+</div>
+<script>
+    function getIds()
+    {
+        var ids = $("#ids").val();
+        window.location = '{:url("admin/main_project/download")}?ids=' +ids;
+    }
+</script>
+{/block}

+ 297 - 0
application/admin/view/main_project/contrast1111.html

@@ -0,0 +1,297 @@
+{extend name='main'}
+
+{block name="button"}
+
+{if auth("contrast")}
+<button class="layui-btn layui-btn-sm" style="background-color: #DC2219" onclick="getIds()" >导出</button>
+{/if}
+
+<button class="layui-btn" style="height: 30px;line-height:28px;color:#FFFFFF;background-color: #DC2219;border: 1px solid #C9C9C9 " type='button' onclick="window.history.back()">返 回</button>
+
+{/block}
+
+{block name="content"}
+<div class="think-box-shadow">
+    <table class="layui-table margin-top-10">
+        <input type="hidden" name="ids" id="ids" value="{$ids}">
+        {notempty name='list'}
+        <thead>
+        <tr>
+            <th class='text-left nowrap' rowspan="2">成本预算科目</th>
+            <th class='text-center nowrap' colspan="3">不含增值税测算成本</th>
+            <th class='text-center nowrap' colspan="3">增值税总额</th>
+            <th class='text-center nowrap' colspan="3">含增值税测算成本</th>
+            <th class='text-center nowrap' colspan="3">建面单方成本指标(不含税)</th>
+            <th class='text-center nowrap' colspan="3">建面单方成本指标(含税)</th>
+            <th class='text-center nowrap' colspan="3">可售单方成本指标(不含税)</th>
+            <th class='text-center nowrap' colspan="3">可售单方成本指标(含税)</th>
+            <th class='text-center nowrap' rowspan="2">操作</th>
+        </tr>
+        <tr>
+            <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>
+            <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>
+            <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>
+        {/notempty}
+        <tbody>
+        {foreach $list as $key=>$vo}
+        <tr class="">
+            <td class='text-left nowrap '
+                onclick='if($(".tr_{$vo.id}").hasClass("t")){$(".tr_{$vo.id}").removeClass("t").show();$(".icon_{$vo.id}").removeClass("layui-icon-triangle-r");$(".icon_{$vo.id}").addClass("layui-icon-triangle-d");}else{$(".tr_{$vo.id}").addClass("t").hide();$(".icon_{$vo.id}").removeClass("layui-icon-triangle-d");$(".icon_{$vo.id}").addClass("layui-icon-triangle-r");}'>
+                {$vo.subjects|default=''}
+                {if count($vo['children']) > 0}
+                <i class="layui-icon layui-icon-triangle-r margin-right-5 icon_{$vo.id}"></i>
+                {/if}
+            </td>
+            <td class='text-left nowrap'>{$vo.costs_are_excluded_interval|default='-'}</td>
+            <td class='text-left nowrap'>{$vo.costs_are_excluded_arithmetic_mean|default=''}</td>
+            <td class='text-left nowrap'>{$vo.costs_are_excluded_valid_sample_size|default=''}</td>
+            <td class='text-left nowrap'>{$vo.total_vat_interval|default=''}</td>
+            <td class='text-left nowrap'>{$vo.total_vat_arithmetic_mean|default='-'}</td>
+            <td class='text-left nowrap'>{$vo.total_vat_valid_sample_size|default=''}</td>
+            <td class='text-left nowrap'>{$vo.measurement_cost_interval|default=''}</td>
+            <td class='text-left nowrap'>{$vo.measurement_cost_arithmetic_mean|default='-'}</td>
+            <td class='text-left nowrap'>{$vo.measurement_cost_valid_sample_size|default=''}</td>
+            <td class='text-left nowrap'>{$vo.unilateral_cost_indicator_interval|default=''}</td>
+            <td class='text-left nowrap'>{$vo.unilateral_cost_indicator_arithmetic_mean|default='-'}</td>
+            <td class='text-left nowrap'>{$vo.unilateral_cost_indicator_valid_sample_size|default=''}</td>
+            <td class='text-left nowrap'>{$vo.single_cost_indicator_interval|default=''}</td>
+            <td class='text-left nowrap'>{$vo.single_cost_indicator_arithmetic_mean|default='-'}</td>
+            <td class='text-left nowrap'>{$vo.single_cost_indicator_valid_sample_size|default=''}</td>
+            <td class='text-left nowrap'>{$vo.single_party_cost_tax_interval|default=''}</td>
+            <td class='text-left nowrap'>{$vo.single_party_cost_tax_arithmetic_mean|default='-'}</td>
+            <td class='text-left nowrap'>{$vo.single_party_cost_tax_valid_sample_size|default=''}</td>
+            <td class='text-left nowrap'>{$vo.single_party_cost_no_tax_interval|default=''}</td>
+            <td class='text-left nowrap'>{$vo.single_party_cost_no_tax_arithmetic_mean|default='-'}</td>
+            <td class='text-left nowrap'>{$vo.single_party_cost_no_tax_valid_sample_size|default=''}</td>
+            <td class='text-left nowrap'>
+                {if auth("see")}
+                <a data-dbclick class="layui-btn layui-btn-sm" style="background-color: #DC2219" data-title="查看" data-open='{:url("see")}?subjects={$vo.subjects}&ids={$ids}'>查 看</a>
+                {/if}
+            </td>
+        </tr>
+
+            {foreach $vo['children'] as $k=>$v}
+            <tr  class="t tr_{$vo.id} tr_{$v.id} " style="display: none">
+                <td class='text-left nowrap'
+                    onclick='if($(".tr_{$v.id}").hasClass("t")){$(".tr_{$v.id}").removeClass("t").show();$(".icon_{$v.id}").removeClass("layui-icon-triangle-r");$(".icon_{$v.id}").addClass("layui-icon-triangle-d");}else{$(".tr_{$v.id}").addClass("t").hide();$(".icon_{$v.id}").removeClass("layui-icon-triangle-d");$(".icon_{$v.id}").addClass("layui-icon-triangle-r");}'>
+                    <span class="color-desc" style="margin-left: 15px; margin-right: 10px"></span>{$v.subjects|default=''}
+                    {if count($v['children']) > 0}
+                    <i class="layui-icon layui-icon-triangle-r margin-right-5 icon_{$v.id}"></i>
+                    {/if}
+                </td>
+                <td class='text-left nowrap'>{$v.costs_are_excluded_interval|default='-'}</td>
+                <td class='text-left nowrap'>{$v.costs_are_excluded_arithmetic_mean|default=''}</td>
+                <td class='text-left nowrap'>{$v.costs_are_excluded_valid_sample_size|default=''}</td>
+                <td class='text-left nowrap'>{$v.total_vat_interval|default=''}</td>
+                <td class='text-left nowrap'>{$v.total_vat_arithmetic_mean|default='-'}</td>
+                <td class='text-left nowrap'>{$v.total_vat_valid_sample_size|default=''}</td>
+                <td class='text-left nowrap'>{$v.measurement_cost_interval|default=''}</td>
+                <td class='text-left nowrap'>{$v.measurement_cost_arithmetic_mean|default='-'}</td>
+                <td class='text-left nowrap'>{$v.measurement_cost_valid_sample_size|default=''}</td>
+                <td class='text-left nowrap'>{$v.unilateral_cost_indicator_interval|default=''}</td>
+                <td class='text-left nowrap'>{$v.unilateral_cost_indicator_arithmetic_mean|default='-'}</td>
+                <td class='text-left nowrap'>{$v.unilateral_cost_indicator_valid_sample_size|default=''}</td>
+                <td class='text-left nowrap'>{$v.single_cost_indicator_interval|default=''}</td>
+                <td class='text-left nowrap'>{$v.single_cost_indicator_arithmetic_mean|default='-'}</td>
+                <td class='text-left nowrap'>{$v.single_cost_indicator_valid_sample_size|default=''}</td>
+                <td class='text-left nowrap'>{$v.single_party_cost_tax_interval|default=''}</td>
+                <td class='text-left nowrap'>{$v.single_party_cost_tax_arithmetic_mean|default='-'}</td>
+                <td class='text-left nowrap'>{$v.single_party_cost_tax_valid_sample_size|default=''}</td>
+                <td class='text-left nowrap'>{$v.single_party_cost_no_tax_interval|default=''}</td>
+                <td class='text-left nowrap'>{$v.single_party_cost_no_tax_arithmetic_mean|default='-'}</td>
+                <td class='text-left nowrap'>{$v.single_party_cost_no_tax_valid_sample_size|default=''}</td>
+                <td class='text-left nowrap'>
+                    {if auth("see")}
+                    <a data-dbclick class="layui-btn layui-btn-sm" data-title="查看" style="background-color: #DC2219" data-open='{:url("see")}?subjects={$v.subjects}&ids={$ids}'>查 看</a>
+                    {/if}
+                </td>
+            </tr>
+
+                {foreach $v['children'] as $k=>$vv}
+                <tr  class="t tr_{$v.id} tr_{$vo.id}" style="display: none">
+                    <td class='text-left nowrap'
+                        onclick='if($(".tr_{$vv.id}").hasClass("t")){$(".tr_{$vv.id}").removeClass("t").show();$(".icon_{$vv.id}").removeClass("layui-icon-triangle-r");$(".icon_{$vv.id}").addClass("layui-icon-triangle-d");}else{$(".tr_{$vv.id}").addClass("t").hide();$(".icon_{$vv.id}").removeClass("layui-icon-triangle-d");$(".icon_{$vv.id}").addClass("layui-icon-triangle-r");}'>
+                        <span class="color-desc" style="margin-left: 15px; margin-right: 20px"></span>
+                        {$vv.subjects|default=''}
+                        {if count($vv['children']) > 0}
+                        <i class="layui-icon layui-icon-triangle-r margin-right-5 icon_{$vv.id}"></i>
+                        {/if}
+                    </td>
+                    <td class='text-left nowrap'>{$vv.costs_are_excluded_interval|default='-'}</td>
+                    <td class='text-left nowrap'>{$vv.costs_are_excluded_arithmetic_mean|default=''}</td>
+                    <td class='text-left nowrap'>{$vv.costs_are_excluded_valid_sample_size|default=''}</td>
+                    <td class='text-left nowrap'>{$vv.total_vat_interval|default=''}</td>
+                    <td class='text-left nowrap'>{$vv.total_vat_arithmetic_mean|default='-'}</td>
+                    <td class='text-left nowrap'>{$vv.total_vat_valid_sample_size|default=''}</td>
+                    <td class='text-left nowrap'>{$vv.measurement_cost_interval|default=''}</td>
+                    <td class='text-left nowrap'>{$vv.measurement_cost_arithmetic_mean|default='-'}</td>
+                    <td class='text-left nowrap'>{$vv.measurement_cost_valid_sample_size|default=''}</td>
+                    <td class='text-left nowrap'>{$vv.unilateral_cost_indicator_interval|default=''}</td>
+                    <td class='text-left nowrap'>{$vv.unilateral_cost_indicator_arithmetic_mean|default='-'}</td>
+                    <td class='text-left nowrap'>{$vv.unilateral_cost_indicator_valid_sample_size|default=''}</td>
+                    <td class='text-left nowrap'>{$vv.single_cost_indicator_interval|default=''}</td>
+                    <td class='text-left nowrap'>{$vv.single_cost_indicator_arithmetic_mean|default='-'}</td>
+                    <td class='text-left nowrap'>{$vv.single_cost_indicator_valid_sample_size|default=''}</td>
+                    <td class='text-left nowrap'>{$vv.single_party_cost_tax_interval|default=''}</td>
+                    <td class='text-left nowrap'>{$vv.single_party_cost_tax_arithmetic_mean|default='-'}</td>
+                    <td class='text-left nowrap'>{$vv.single_party_cost_tax_valid_sample_size|default=''}</td>
+                    <td class='text-left nowrap'>{$vv.single_party_cost_no_tax_interval|default=''}</td>
+                    <td class='text-left nowrap'>{$vv.single_party_cost_no_tax_arithmetic_mean|default='-'}</td>
+                    <td class='text-left nowrap'>{$vv.single_party_cost_no_tax_valid_sample_size|default=''}</td>
+                    <td class='text-left nowrap'>
+                        {if auth("see")}
+                        <a data-dbclick class="layui-btn layui-btn-sm" style="background-color: #DC2219" data-title="查看" data-open='{:url("see")}?subjects={$vv.subjects}&ids={$ids}'>查 看</a>
+                        {/if}
+                    </td>
+                </tr>
+                    {foreach $vv['children'] as $k=>$vvv}
+                    <tr  class="t tr_{$vv.id} tr_{$v.id} tr_{$vo.id}" style="display: none">
+                        <td class='text-left nowrap'
+                            onclick='if($(".tr_{$vvv.id}").hasClass("t")){$(".tr_{$vvv.id}").removeClass("t").show();$(".icon_{$vvv.id}").removeClass("layui-icon-triangle-r");$(".icon_{$vvv.id}").addClass("layui-icon-triangle-d");}else{$(".tr_{$vvv.id}").addClass("t").hide();$(".icon_{$vvv.id}").removeClass("layui-icon-triangle-d");$(".icon_{$vvv.id}").addClass("layui-icon-triangle-r");}'>
+                            <span class="color-desc" style="margin-left: 15px; margin-right: 30px"></span>
+                            {$vvv.subjects|default=''}
+                            {if count($vvv['children']) > 0}
+                            <i class="layui-icon layui-icon-triangle-r margin-right-5 icon_{$vvv.id}"></i>
+                            {/if}
+                        </td>
+                        <td class='text-left nowrap'>{$vvv.costs_are_excluded_interval|default='-'}</td>
+                        <td class='text-left nowrap'>{$vvv.costs_are_excluded_arithmetic_mean|default=''}</td>
+                        <td class='text-left nowrap'>{$vvv.costs_are_excluded_valid_sample_size|default=''}</td>
+                        <td class='text-left nowrap'>{$vvv.total_vat_interval|default=''}</td>
+                        <td class='text-left nowrap'>{$vvv.total_vat_arithmetic_mean|default='-'}</td>
+                        <td class='text-left nowrap'>{$vvv.total_vat_valid_sample_size|default=''}</td>
+                        <td class='text-left nowrap'>{$vvv.measurement_cost_interval|default=''}</td>
+                        <td class='text-left nowrap'>{$vvv.measurement_cost_arithmetic_mean|default='-'}</td>
+                        <td class='text-left nowrap'>{$vvv.measurement_cost_valid_sample_size|default=''}</td>
+                        <td class='text-left nowrap'>{$vvv.unilateral_cost_indicator_interval|default=''}</td>
+                        <td class='text-left nowrap'>{$vvv.unilateral_cost_indicator_arithmetic_mean|default='-'}</td>
+                        <td class='text-left nowrap'>{$vvv.unilateral_cost_indicator_valid_sample_size|default=''}</td>
+                        <td class='text-left nowrap'>{$vvv.single_cost_indicator_interval|default=''}</td>
+                        <td class='text-left nowrap'>{$vvv.single_cost_indicator_arithmetic_mean|default='-'}</td>
+                        <td class='text-left nowrap'>{$vvv.single_cost_indicator_valid_sample_size|default=''}</td>
+                        <td class='text-left nowrap'>{$vvv.single_party_cost_tax_interval|default=''}</td>
+                        <td class='text-left nowrap'>{$vvv.single_party_cost_tax_arithmetic_mean|default='-'}</td>
+                        <td class='text-left nowrap'>{$vvv.single_party_cost_tax_valid_sample_size|default=''}</td>
+                        <td class='text-left nowrap'>{$vvv.single_party_cost_no_tax_interval|default=''}</td>
+                        <td class='text-left nowrap'>{$vvv.single_party_cost_no_tax_arithmetic_mean|default='-'}</td>
+                        <td class='text-left nowrap'>{$vvv.single_party_cost_no_tax_valid_sample_size|default=''}</td>
+                        <td class='text-left nowrap'>
+                            {if auth("see")}
+                            <a data-dbclick class="layui-btn layui-btn-sm" style="background-color: #DC2219" data-title="查看" data-open='{:url("see")}?subjects={$vvv.subjects}&ids={$ids}'>查 看</a>
+                            {/if}
+                        </td>
+                    </tr>
+                        {foreach $vvv['children'] as $k=>$vvvv}
+                        <tr  class="t tr_{$vvv.id} tr_{$vv.id} tr_{$v.id} tr_{$vo.id}" style="display: none">
+                            <td class='text-left nowrap'
+                                onclick='if($(".tr_{$vvvv.id}").hasClass("t")){$(".tr_{$vvvv.id}").removeClass("t").show();$(".icon_{$vvvv.id}").removeClass("layui-icon-triangle-r");$(".icon_{$vvvv.id}").addClass("layui-icon-triangle-d");}else{$(".tr_{$vvvv.id}").addClass("t").hide();$(".icon_{$vvvv.id}").removeClass("layui-icon-triangle-d");$(".icon_{$vvvv.id}").addClass("layui-icon-triangle-r");}'>
+                                <span class="color-desc" style="margin-left: 15px; margin-right: 40px"></span>
+                                {$vvvv.subjects|default=''}
+                                {if count($vvvv['children']) > 0}
+                                <i class="layui-icon layui-icon-triangle-r margin-right-5 icon_{$vvvv.id}"></i>
+                                {/if}
+                            </td>
+                            <td class='text-left nowrap'>{$vvvv.costs_are_excluded_interval|default='-'}</td>
+                            <td class='text-left nowrap'>{$vvvv.costs_are_excluded_arithmetic_mean|default=''}</td>
+                            <td class='text-left nowrap'>{$vvvv.costs_are_excluded_valid_sample_size|default=''}</td>
+                            <td class='text-left nowrap'>{$vvvv.total_vat_interval|default=''}</td>
+                            <td class='text-left nowrap'>{$vvvv.total_vat_arithmetic_mean|default='-'}</td>
+                            <td class='text-left nowrap'>{$vvvv.total_vat_valid_sample_size|default=''}</td>
+                            <td class='text-left nowrap'>{$vvvv.measurement_cost_interval|default=''}</td>
+                            <td class='text-left nowrap'>{$vvvv.measurement_cost_arithmetic_mean|default='-'}</td>
+                            <td class='text-left nowrap'>{$vvvv.measurement_cost_valid_sample_size|default=''}</td>
+                            <td class='text-left nowrap'>{$vvvv.unilateral_cost_indicator_interval|default=''}</td>
+                            <td class='text-left nowrap'>{$vvvv.unilateral_cost_indicator_arithmetic_mean|default='-'}</td>
+                            <td class='text-left nowrap'>{$vvvv.unilateral_cost_indicator_valid_sample_size|default=''}</td>
+                            <td class='text-left nowrap'>{$vvvv.single_cost_indicator_interval|default=''}</td>
+                            <td class='text-left nowrap'>{$vvvv.single_cost_indicator_arithmetic_mean|default='-'}</td>
+                            <td class='text-left nowrap'>{$vvvv.single_cost_indicator_valid_sample_size|default=''}</td>
+                            <td class='text-left nowrap'>{$vvvv.single_party_cost_tax_interval|default=''}</td>
+                            <td class='text-left nowrap'>{$vvvv.single_party_cost_tax_arithmetic_mean|default='-'}</td>
+                            <td class='text-left nowrap'>{$vvvv.single_party_cost_tax_valid_sample_size|default=''}</td>
+                            <td class='text-left nowrap'>{$vvvv.single_party_cost_no_tax_interval|default=''}</td>
+                            <td class='text-left nowrap'>{$vvvv.single_party_cost_no_tax_arithmetic_mean|default='-'}</td>
+                            <td class='text-left nowrap'>{$vvvv.single_party_cost_no_tax_valid_sample_size|default=''}</td>
+                            <td class='text-left nowrap'>
+                                {if auth("see")}
+                                <a data-dbclick class="layui-btn layui-btn-sm" style="background-color: #DC2219" data-title="查看" data-open='{:url("see")}?subjects={$vvvv.subjects}&ids={$ids}'>查 看</a>
+                                {/if}
+                            </td>
+                        </tr>
+                            {foreach $vvvv['children'] as $k=>$vvvvv}
+                            <tr  class="t tr_{$vvvv.id} tr_{$vvv.id} tr_{$vv.id} tr_{$v.id} tr_{$vo.id}" style="display: none">
+                                <td class='text-left nowrap'
+                                    onclick='if($(".tr_{$vvvvv.id}").hasClass("t")){$(".tr_{$vvvvv.id}").removeClass("t").show();$(".icon_{$vvvvv.id}").removeClass("layui-icon-triangle-r");$(".icon_{$vvvvv.id}").addClass("layui-icon-triangle-d");}else{$(".tr_{$vvvvv.id}").addClass("t").hide();$(".icon_{$vvvv.id}").removeClass("layui-icon-triangle-d");$(".icon_{$vvvv.id}").addClass("layui-icon-triangle-r");}'>
+                                    <span class="color-desc" style="margin-left: 15px; margin-right: 50px"></span>
+                                    {$vvvvv.subjects|default=''}
+                                    {if count($vvvvv['children']) > 0}
+                                    <i class="layui-icon layui-icon-triangle-r margin-right-5 icon_{$vvvvv.id}"></i>
+                                    {/if}
+                                </td>
+                                <td class='text-left nowrap'>{$vvvvv.costs_are_excluded_interval|default='-'}</td>
+                                <td class='text-left nowrap'>{$vvvvv.costs_are_excluded_arithmetic_mean|default=''}</td>
+                                <td class='text-left nowrap'>{$vvvvv.costs_are_excluded_valid_sample_size|default=''}</td>
+                                <td class='text-left nowrap'>{$vvvvv.total_vat_interval|default=''}</td>
+                                <td class='text-left nowrap'>{$vvvvv.total_vat_arithmetic_mean|default='-'}</td>
+                                <td class='text-left nowrap'>{$vvvvv.total_vat_valid_sample_size|default=''}</td>
+                                <td class='text-left nowrap'>{$vvvvv.measurement_cost_interval|default=''}</td>
+                                <td class='text-left nowrap'>{$vvvvv.measurement_cost_arithmetic_mean|default='-'}</td>
+                                <td class='text-left nowrap'>{$vvvvv.measurement_cost_valid_sample_size|default=''}</td>
+                                <td class='text-left nowrap'>{$vvvvv.unilateral_cost_indicator_interval|default=''}</td>
+                                <td class='text-left nowrap'>{$vvvvv.unilateral_cost_indicator_arithmetic_mean|default='-'}</td>
+                                <td class='text-left nowrap'>{$vvvvv.unilateral_cost_indicator_valid_sample_size|default=''}</td>
+                                <td class='text-left nowrap'>{$vvvvv.single_cost_indicator_interval|default=''}</td>
+                                <td class='text-left nowrap'>{$vvvvv.single_cost_indicator_arithmetic_mean|default='-'}</td>
+                                <td class='text-left nowrap'>{$vvvvv.single_cost_indicator_valid_sample_size|default=''}</td>
+                                <td class='text-left nowrap'>{$vvvvv.single_party_cost_tax_interval|default=''}</td>
+                                <td class='text-left nowrap'>{$vvvvv.single_party_cost_tax_arithmetic_mean|default='-'}</td>
+                                <td class='text-left nowrap'>{$vvvvv.single_party_cost_tax_valid_sample_size|default=''}</td>
+                                <td class='text-left nowrap'>{$vvvvv.single_party_cost_no_tax_interval|default=''}</td>
+                                <td class='text-left nowrap'>{$vvvvv.single_party_cost_no_tax_arithmetic_mean|default='-'}</td>
+                                <td class='text-left nowrap'>{$vvvvv.single_party_cost_no_tax_valid_sample_size|default=''}</td>
+                                <td class='text-left nowrap'>
+                                    {if auth("see")}
+                                    <a data-dbclick class="layui-btn layui-btn-sm" style="background-color: #DC2219" data-title="查看" data-open='{:url("see")}?subjects={$vvvvv.subjects}&ids={$ids}'>查 看</a>
+                                    {/if}
+                                </td>
+                            </tr>
+                            {/foreach}
+                        {/foreach}
+                    {/foreach}
+                {/foreach}
+            {/foreach}
+        {/foreach}
+        </tbody>
+    </table>
+
+    {empty name='list'}<span class="notdata">没有记录哦</span>{else}{$pagehtml|raw|default=''}{/empty}
+
+</div>
+<script>
+    function getIds()
+    {
+        var ids = $("#ids").val();
+        window.location = '{:url("admin/main_project/download")}?ids=' +ids;
+    }
+</script>
+{/block}

+ 459 - 0
application/admin/view/main_project/form.html

@@ -0,0 +1,459 @@
+{extend name='main'}
+{block name="button"}
+<button class="layui-btn" style="height: 30px;line-height:28px;background-color:#DC2219;color: #FFFFFF;border: 1px solid #C9C9C9 " type='button' onclick="window.history.back()">返 回</button>
+
+
+{/block}
+{block name="content"}
+
+<style>
+    .layui-anim .layui-anim-fadein{
+        display: none !important;
+    }
+</style>
+
+<form onsubmit="return false;" id="GoodsForm" data-auto="true" method="post" class='layui-form layui-card' autocomplete="off">
+
+    <div class="layui-card-body think-box-shadow padding-left-40">
+
+        <div class="layui-form-item layui-row layui-col-space15">
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">项目名称</span>
+                <input name="project_name" required class="layui-input" placeholder="请输入项目名称" value="{$vo.project_name|default=''}">
+            </label>
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">造价类别</span>
+                <select name="cost_categories" required class="province-selector layui-select" id="cost_categories" lay-verify="required" lay-search   >
+                    <option value="">请选择</option>
+                    {if isset($vo.id) && $vo.id neq ''}
+                    {foreach ['投标价'=>'投标价','合同价'=>'合同价','结算价'=>'结算价','重计量'=>'重计量','清单控制价'=>'清单控制价','估算'=>'估算','概算'=>'概算','其他'=>'其他','目标成本'=>'目标成本'] as $k=>$v}
+                        {if $v eq $vo.cost_categories}
+                        <option selected value="{$k}">{$v}</option>
+                        {else}
+                        <option value="{$k}">{$v}</option>
+                        {/if}
+                    {/foreach}
+                    {else}
+                    {foreach ['投标价'=>'投标价','合同价'=>'合同价','结算价'=>'结算价','重计量'=>'重计量','清单控制价'=>'清单控制价','估算'=>'估算','概算'=>'概算','其他'=>'其他','目标成本'=>'目标成本'] as $k=>$v}
+                    <option value="{$k}">{$v}</option>
+                    {/foreach}
+                    {/if}
+
+                </select>
+            </label>
+            <label class="layui-col-xs3 relative">
+                <span  class="color-green">编制日期</span>
+                <input required type="text" class="layui-input" name="prepare_date" value="{$vo.prepare_date|default=''}" id="test1" placeholder="yyyy-MM-dd">
+            </label>
+
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">模板类型</span>
+
+                <select name='template' class='layui-select' required lay-verify="required" lay-search>
+                    <option value=''>请选择</option>
+                    {if isset($vo.id)}
+                    <!--{foreach $template as $menu}-->
+                    <!--{eq name='menu.id' value='$vo.template'}-->
+                    <option selected value='{$menu.id}'>{$menu.title}</option>
+                    <!--{else}-->
+                    <option value='{$menu.id}'>{$menu.title}</option>
+                    <!--{/eq}-->
+                    <!--{/foreach}-->
+                    {else}
+                    <!--{foreach $template as $menu}-->
+                    <option value='{$menu.id}'>{$menu.title}</option>
+                    <!--{/foreach}-->
+                    {/if}
+                </select>
+
+            </label>
+        </div>
+
+        <div class="layui-form-item layui-row layui-col-space15">
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">清单编制依据</span>
+                <input name="basis_for_listing" class="layui-input" placeholder="请输入清单编制依据" value="{$vo.basis_for_listing|default=''}">
+            </label>
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">工程范围</span>
+                <input name="project_scope" class="layui-input" placeholder="请输入工程范围" value="{$vo.project_scope|default=''}">
+            </label>
+        </div>
+        <h3 style="margin-bottom: 15px">项目业态</h3>
+        <div class="layui-form-item layui-row layui-col-space15">
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">建筑分类</span>
+
+                <select name='category_id' class='layui-select' required lay-verify="required" lay-search>
+                    <option value=''>请选择</option>
+                    {if isset($vo.id)}
+                    <!--{foreach $menus as $menu}-->
+                    <!--{eq name='menu.id' value='$vo.category_id'}-->
+                    <option selected value='{$menu.id}'>{$menu.spl|raw}{$menu.title}</option>
+                    <!--{else}-->
+                    <option value='{$menu.id}'>{$menu.spl|raw}{$menu.title}</option>
+                    <!--{/eq}-->
+                    <!--{/foreach}-->
+                    {else}
+                    <!--{foreach $menus as $menu}-->
+                    <option value='{$menu.id}'>{$menu.spl|raw}{$menu.title}</option>
+                    <!--{/foreach}-->
+                    {/if}
+                </select>
+
+            </label>
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">工程类别</span>
+                <select required name="engineering_category" class="province-selector" id="engineering_category" lay-verify="required" lay-search >
+                    <option value="">请选择</option>
+                    {if isset($vo.id) && $vo.id neq ''}
+                    {foreach ['新建工程'=>'新建工程','改扩建加固工程'=>'改扩建加固工程','其他'=>'其他'] as $k=>$v}
+                    {if $v eq $vo.engineering_category}
+                    <option selected value="{$k}">{$v}</option>
+                    {else}
+                    <option value="{$k}">{$v}</option>
+                    {/if}
+                    {/foreach}
+                    {else}
+                    {foreach ['新建工程'=>'新建工程','改扩建加固工程'=>'改扩建加固工程','其他'=>'其他'] as $k=>$v}
+                    <option value="{$k}">{$v}</option>
+                    {/foreach}
+                    {/if}
+                </select>
+            </label>
+            <label class="layui-col-xs3 relative">
+                <span class="color-green" required>建设地点</span>
+                <div class="layui-form-item layui-row layui-col-space12">
+                    <label class="layui-col-xs4 relative">
+                        <select name="construction_site_province" class="province-selector" id="province" lay-filter="province" lay-verify="required" lay-search >
+                            <option value="">请选择省</option>
+                            {if isset($vo.id) && $vo.id neq ''}
+                                {foreach $province as $k=>$v}
+                                    {if $v.name eq $vo.construction_site_province}
+                                        <option selected value="{$v.name}">{$v.name}</option>
+                                    {else}
+                                        <option value="{$v.name}">{$v.name}</option>
+                                    {/if}
+                                {/foreach}
+                            {else}
+                                {foreach $province as $k=>$v}
+                                    <option value="{$v.name}">{$v.name}</option>
+                                {/foreach}
+                            {/if}
+                        </select>
+                    </label>
+                    <label class="layui-col-xs4 relative">
+                        <select name="construction_site_city" class="city-selector" data-value="" id="city" lay-filter="city" lay-verify="required" lay-search>
+                            <option value="">请选择市</option>
+                            {if isset($vo.id) && $vo.id neq ''}
+                                {foreach $city as $k=>$v}
+                                    {if $v.name eq $vo.construction_site_city}
+                                        <option selected value="{$v.name}">{$v.name}</option>
+                                    {else}
+                                        <option value="{$v.name}">{$v.name}</option>
+                                    {/if}
+                                {/foreach}
+                            {/if}
+                        </select>
+                    </label>
+                    <label class="layui-col-xs4 relative">
+                        <select name="construction_site_area" class="county-selector" data-value="" id="area" lay-filter="area" lay-search>
+                            <option value="">请选择区</option>
+                            {if isset($vo.id) && $vo.id neq ''}
+                                {foreach $area as $k=>$v}
+                                    {if $v.name eq $vo.construction_site_area}
+                                        <option selected value="{$v.name}">{$v.name}</option>
+                                    {else}
+                                        <option value="{$v.name}">{$v.name}</option>
+                                    {/if}
+                                {/foreach}
+                            {/if}
+                        </select>
+                    </label>
+                </div>
+            </label>
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">标准(档次)</span>
+                <input  name="grade" class="layui-input" placeholder="请输入标准(档次)" value="{$vo.grade|default=''}">
+            </label>
+        </div>
+        <h3 style="margin-bottom: 15px">项目总体特征</h3>
+
+        <div class="layui-form-item layui-row layui-col-space15">
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">建筑类别及组成</span>
+                <input  name="building_composition" class="layui-input" placeholder="请输入建筑类别及组成" value="{$vo.building_composition|default=''}">
+            </label>
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">总用地面积</span>
+                <input  name="total_land_area" class="layui-input" placeholder="请输入总用地面积" value="{$vo.total_land_area|default=''}">
+            </label>
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">总建筑面积</span>
+                <input  name="gross_floor_area" required class="layui-input" lay-verify="number" placeholder="请输入总建筑面积" value="{$vo.gross_floor_area|default=''}">
+            </label>
+        </div>
+        <div class="layui-form-item layui-row layui-col-space15">
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">地上面积</span>
+                <input  name="floor_area" required class="layui-input" lay-verify="number" placeholder="请输入地上面积" value="{$vo.floor_area|default=''}">
+            </label>
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">地下面积</span>
+                <input  name="underground_area" required class="layui-input" lay-verify="number" placeholder="请输入地下面积" value="{$vo.underground_area|default=''}">
+            </label>
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">建筑密度</span>
+                <input  name="building_density"  class="layui-input"  placeholder="请输入建筑密度" value="{$vo.building_density|default=''}">
+            </label>
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">绿化面积</span>
+                <input  name="green_area"  class="layui-input"  placeholder="请输入绿化面积" value="{$vo.green_area|default=''}">
+            </label>
+        </div>
+        <div class="layui-form-item layui-row layui-col-space15">
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">道路面积</span>
+                <input  name="road_area" class="layui-input"  placeholder="请输入道路面积" value="{$vo.road_area|default=''}">
+            </label>
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">道路长度</span>
+                <input  name="road_length" class="layui-input"  placeholder="请输入道路长度" value="{$vo.road_length|default=''}">
+            </label>
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">建筑分期或分期建设情况描述密度</span>
+                <input  name="case_description"  class="layui-input" placeholder="请输入分期或分期建设情况描述" value="{$vo.case_description|default=''}">
+            </label>
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">功能参数</span>
+                <input  name="function_parameters"  class="layui-input" placeholder="请输入功能参数" value="{$vo.function_parameters|default=''}">
+            </label>
+        </div>
+        <div class="layui-form-item layui-row layui-col-space15">
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">人防面积</span>
+                <input  name="defense" class="layui-input" placeholder="请输入人防面积" value="{$vo.defense|default=''}">
+            </label>
+
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">人防类型</span>
+                <input  name="defense_type" class="layui-input" placeholder="请输入人防类型" value="{$vo.defense_type|default=''}">
+            </label>
+        </div>
+        <h3 style="margin-bottom: 15px">投融资模式</h3>
+        <div class="layui-form-item layui-row layui-col-space15">
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">投资主体</span>
+                <input  name="investment_subject" class="layui-input" placeholder="请输入投资主体" value="{$vo.investment_subject|default=''}">
+            </label>
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">资金来源</span>
+                <input  name="sources_funding" class="layui-input" placeholder="请输入资金来源" value="{$vo.sources_funding|default=''}">
+            </label>
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">承发包模式</span>
+                <input  name="contract_mode"  class="layui-input" placeholder="请输入承发包模式" value="{$vo.contract_mode|default=''}">
+            </label>
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">组织管理模式</span>
+                <input  name="management_mode"  class="layui-input" placeholder="请输入组织管理模式" value="{$vo.management_mode|default=''}">
+            </label>
+        </div>
+        <h3 style="margin-bottom: 15px">项目主要参与单位</h3>
+        <div class="layui-form-item layui-row layui-col-space15">
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">业主</span>
+                <input  name="owner" class="layui-input" placeholder="请输入业主" value="{$vo.owner|default=''}">
+            </label>
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">总包</span>
+                <input  name="total_package"  class="layui-input" placeholder="请输入总包" value="{$vo.total_package|default=''}">
+            </label>
+        </div>
+        <h3 style="margin-bottom: 15px">日期</h3>
+        <div class="layui-form-item layui-row layui-col-space15">
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">开工时间</span>
+                <input  name="starting_time" readonly required  class="layui-input" id="test2" placeholder="yyyy-MM-dd" value="{$vo.starting_time|default=''}">
+            </label>
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">竣工时间</span>
+                <input  name="ending_time" readonly required class="layui-input" id="test3" placeholder="yyyy-MM-dd" value="{$vo.ending_time|default=''}">
+            </label>
+            <label class="layui-col-xs3 relative">
+                <span class="color-green">工期(单位:天)</span>
+                <input  name="project_time" readonly class="layui-input" id="project_time" placeholder="自动计算" value="{$vo.project_time|default=''}">
+            </label>
+        </div>
+
+        <div class="layui-form-item layui-row layui-col-space15">
+            <label class="layui-col-xs6 relative">
+                <span class="color-green">获奖情况</span>
+                <textarea placeholder="请输入" name="awards" class="layui-textarea">{$vo.awards|default=''}</textarea>
+            </label>
+            <label class="layui-col-xs6 relative">
+                <span class="color-green">其他说明</span>
+                <textarea placeholder="请输入" name="other_instructions" class="layui-textarea">{$vo.other_instructions|default=''}</textarea>
+            </label>
+        </div>
+
+        <div class="layui-form-item text-center">
+            {if isset($vo.id) && $vo.id neq ''}<input type='hidden' value="<?php echo date('Y-m-d H:i:s'); ?>" name='update_at'>{else}<input type='hidden' value="<?php echo date('Y-m-d H:i:s'); ?>" name='create_at'>{/if}
+            {notempty name='vo.id'}<input type="hidden" name="id" value="{$vo.id}">{/notempty}
+            <button class="layui-btn layui-btn-danger" ng-click="hsitoryBack()" onclick="window.history.back()" type="button">取消</button>
+            <button class="layui-btn" type="submit" lay-submit >确定</button>
+        </div>
+
+
+    </div>
+</form>
+{/block}
+
+{block name='script'}
+<script>
+    window.form.render();
+    layui.config({
+        base: 'static/modules/'
+    }).extend({
+        numinput: 'numinput/numinput'
+    });
+    layui.use(['form', 'layedit', 'laydate','numinput'], function(){
+        var form = layui.form
+            ,layer = layui.layer
+            ,layedit = layui.layedit
+            ,laydate = layui.laydate,
+            numinp = layui.numinput;
+
+        // numinp.init({
+        //     // 123:123键置顶, 789:789键置顶
+        //     topBtns: 789,
+        //     // 右侧功能按钮开关
+        //     rightBtns: false,
+        //     // 功能按钮提示开关
+        //     showTips: true,
+        //     // 是否监听键盘事件
+        //     listening: true,
+        //     // 批量配置默认小数精确度,默认 -1 不处理精确度,0 表示禁止输入小数
+        //     defaultPrec: -1,
+        //     // 初始化回调,无参
+        //     initEnd: $.noop,
+        //     // 触发显示回调,参数为当前输入框和数字键盘的 jQuery 对象
+        //     showEnd: $.noop,
+        //     // 隐藏键盘回调,参数为当前输入框的 jQuery 对象
+        //     hideEnd: $.noop,
+        //     // 自定义 z-index
+        //     zIndex: 19999999
+        // });
+        //常规用法
+        laydate.render({
+            elem: '#test1'
+        });
+        laydate.render({
+            elem: '#test2',
+            done:function (value,date) {
+                var endtime = $("#test3").val()
+                if (endtime!=''){
+                    changeday(value,endtime)
+                }
+            }
+
+        });
+        laydate.render({
+            elem: '#test3',
+            done:function (value,date) {
+                var starttime = $("#test2").val()
+                if (starttime!=''){
+                    changeday(starttime,value)
+                }
+
+            }
+        });
+
+        form.on('select(province)', function (data) {
+            var val = data.value;
+             console.log(val)
+            $.ajax({
+                type:"get",
+                url:"{:url('MainProject/get_city')}",  //数据传输的控制器方法
+                data: {id:val},//这里data传递过去的是序列化以后的字符串
+                success:function(data){
+                    //console.log(data)
+                    var arr = data.data;
+                    //console.log(arr)
+                    if (arr.length>0){
+                        //$("#tow").attr("style","display:block;");//显示div
+                        var options='<option value="">请选择市</option>';
+                        for (var i = 0; i < arr.length; i++) {
+                            var tag = arr[i];
+                            options+=' <option value="'+tag.name+'">'+tag.name+'</option>';
+                        }
+                        $("select[name='construction_site_city']").html(options)
+                        form.render('select');
+                    }else {
+                        var options='<option value="">请选择市</option>';
+                        $("select[name='construction_site_city']").html(options)
+                        form.render('select');
+                    }
+                }
+            });
+        });
+
+        form.on('select(city)', function (data) {
+            var val = data.value;
+            // console.log(val)
+            $.ajax({
+                type:"get",
+                url:"{:url('MainProject/get_area')}",  //数据传输的控制器方法
+                data: {id:val},//这里data传递过去的是序列化以后的字符串
+                success:function(data){
+                    //console.log(data)
+                    var arr = data.data;
+                    // console.log(arr)
+                    if (arr.length>0){
+                        var options='<option value="">请选择区</option>';
+                        for (var i = 0; i < arr.length; i++) {
+                            var tag = arr[i];
+                            options+=' <option value="'+tag.name+'">'+tag.name+'</option>';
+                        }
+                        $("select[name='construction_site_area']").html(options)
+                        form.render('select');
+                    }else {
+                        var options='<option value="">请选择区</option>';
+                        $("select[name='construction_site_area']").html(options)
+                        form.render('select');
+                    }
+                }
+            });
+        });
+
+    });
+
+    function changeday(startdate,enddate) {
+        var day = 0;
+        if (startdate==enddate){
+            day = 1;
+        }else if (startdate>enddate){
+            day = 0;
+        }else {
+            day = getDaysBetween(startdate,enddate) + 1
+        }
+        $("#project_time").attr("value",day);
+    }
+
+    //计算两个日期相差的天数
+    function  getDaysBetween(dateString1,dateString2){
+        var  startDate = Date.parse(dateString1);
+        var  endDate = Date.parse(dateString2);
+        if (startDate>endDate){
+            return 0;
+        }
+        if (startDate==endDate){
+            return 1;
+        }
+        var days=(endDate - startDate)/(1*24*60*60*1000);
+        return  days;
+    }
+
+
+</script>
+{/block}

+ 163 - 0
application/admin/view/main_project/index.html

@@ -0,0 +1,163 @@
+{extend name='main'}
+
+{block name="button"}
+
+{if auth("contrast")}
+<button class="layui-btn layui-btn-sm" style="background-color: #DC2219" onclick="getIds()">去对比</button>
+{/if}
+
+{if auth("add")}
+<a data-dbclick data-title="新建主项目" class="layui-btn layui-btn-sm" style="background-color: #DC2219;" data-open='{:url("add")}'>新建项目</a>
+{/if}
+
+{/block}
+
+{block name="content"}
+<div class="think-box-shadow">
+    {include file='main_project/index_search'}
+    <table class="layui-table margin-top-10">
+        {notempty name='list'}
+        <thead>
+        <tr>
+            <th class='list-table-check-td think-checkbox'>
+                <label><input data-auto-none data-check-target='.list-check-box' type='checkbox'></label>
+            </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>
+        {/notempty}
+        <tbody>
+        {foreach $list as $key=>$vo}
+        <tr>
+            <td class='list-table-check-td think-checkbox'>
+                {if $vo.url neq ''}  <label><input class="list-check-box" name="ids" value='{$vo.id}' type='checkbox'></label>{/if}
+            </td>
+            <td class='text-left nowrap'>{$vo.project_name|default=''}</td>
+            <td class='text-left nowrap'>{$vo.construction_site_province|default='-'}-{$vo.construction_site_city|default='-'}-{$vo.construction_site_area|default='-'}</td>
+            <td class='text-left nowrap'>{$vo.starting_time|default='-'}~{$vo.ending_time|default='-'}</td>
+            <td class='text-left nowrap'>{$vo.category_name|default=''}</td>
+            <td class='text-left nowrap'>{$vo.create_at|format_datetime}</td>
+            <td class='text-left nowrap'>
+
+
+                {if auth("index2")}
+                <a class="layui-btn layui-btn-normal layui-btn-sm" style="background-color: #DC2219"  data-open='{:url("index2")}?id={$vo.id}'>子项目列表</a>
+                {/if}
+
+                {if auth("import")}
+                <a class='layui-btn layui-btn-normal layui-btn-sm dr' id="dr" style="background-color:#DC2219;margin-right: 10px;width: 65px " onclick="changename('{$vo.id}')">
+                    {if $vo.url eq ''}待导入{else}重新导入{/if}
+                </a>
+                {/if}
+
+                {if auth("edit")}
+                <a data-dbclick class="layui-btn layui-btn-sm" data-title="编辑" style="background-color: #FFB822" data-open='{:url("edit")}?id={$vo.id}'>编 辑</a>
+                {/if}
+
+<!--                {if auth("projectinfo")}-->
+<!--                <a data-title="项目详情" class="layui-btn layui-btn-sm" data-modal='{:url("projectinfo")}?id={$vo.id}'>项目详情</a>-->
+<!--                {/if}-->
+
+
+
+                {if $vo.url neq '' && auth("look")}
+                <a data-dbclick class="layui-btn layui-btn-sm" data-title="查看" style="background-color:#5AD729 " data-open='{:url("look")}?id={$vo.id}'>查 看</a>
+                {/if}
+
+                {if $vo.url neq '' && auth("down")}
+                <a href="{$vo.url}" class="layui-btn layui-btn-sm" style="background-color:#29B2D7 " download data-title="下载" >下 载</a>
+                {/if}
+
+                {if auth("remove")}
+                <a class="layui-btn layui-btn-sm layui-btn-danger" style="background-color: #2944D7" data-confirm="确定要删除吗?" data-action="{:url('remove')}" data-value="id#{$vo.id}" data-csrf="{:systoken('remove')}">删 除</a>
+                {/if}
+
+            </td>
+        </tr>
+        {/foreach}
+        </tbody>
+    </table>
+
+    {empty name='list'}<span class="notdata">没有记录哦</span>{else}{$pagehtml|raw|default=''}{/empty}
+
+</div>
+<script>
+
+    function getIds()
+    {
+        var id = document.getElementsByName('ids');
+        var value = new Array();
+        for (var i=0;i<id.length;i++){
+            if (id[i].checked){
+                value.push(id[i].value);
+            }
+        }
+        if (value.length<1){
+            layer.msg('请选择需要对比的数据');
+        }else if (value.length<2){
+            layer.msg('请选择至少两条数据');
+        }else{
+            $.form.href('{:url("admin/main_project/contrast")}?ids=' +value.toString());
+           //window.location = '{:url("admin/main_project/contrast")}?ids=' +value.toString();
+        }
+
+    }
+
+
+    var project_id = ''
+    function changename(val){
+        project_id = val
+    }
+    layui.use('upload', function(){
+        var upload = layui.upload;
+
+        //执行实例
+        var uploadInst = upload.render({
+            elem: '.dr' //绑定元素
+            ,url: 'admin/api.plugs/upload'
+            ,accept: 'file', //普通文件,
+            // ,data:{
+            //     id:function () {
+            //         return project_id
+            //     }
+            // },
+            before: function(obj){ //obj参数包含的信息,跟 choose回调完全一致,可参见上文。
+                console.log(obj)
+                // layer.load(); //上传loading
+            }
+            ,done: function(res){
+                if (res.uploaded == true){
+                    var value = {path:res.key,project_id:project_id,url:res.url}
+                    $.ajax({
+                        url:"/admin/main_project/import",
+                        type:'get',
+                        data:value
+                        ,success:function(result){
+                            console.log(result.code);
+                            if (result.code==1){
+                                layer.msg('上传成功',{time:2000,end:function () {
+                                        location.reload();
+                                       // $.form.href('{:url("admin/main_project/index")}');
+                                }});
+                            }else {
+                                layer.msg('上传失败,请核对表格模板是否正确!',{icon: 5});
+                            }
+                        }
+                    });
+                }else {
+                   layer.msg(res.error.message,{icon: 5});
+                }
+               // layer.closeAll('loading'); //关闭loading
+            }
+            ,error: function(){
+                layer.msg('上传失败');
+            }
+        });
+    });
+</script>
+{/block}

+ 144 - 0
application/admin/view/main_project/index2.html

@@ -0,0 +1,144 @@
+{extend name='main'}
+
+{block name="button"}
+
+{if auth("contrast")}
+<button class="layui-btn layui-btn-sm " style="background-color: #DC2219 " onclick="getIds()" >去对比</button>
+{/if}
+
+
+{/block}
+
+{block name="content"}
+<div class="think-box-shadow">
+    {include file='child_project/index_search'}
+    <table class="layui-table margin-top-10">
+        {notempty name='list'}
+        <thead>
+        <tr>
+            <th class='list-table-check-td think-checkbox'>
+                <label><input data-auto-none data-check-target='.list-check-box' type='checkbox'></label>
+            </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-center nowrap'></th>
+        </tr>
+        </thead>
+        {/notempty}
+        <tbody>
+        {foreach $list as $key=>$vo}
+        <tr>
+            <td class='list-table-check-td think-checkbox'>
+                {if $vo.url neq ''}  <label><input class="list-check-box" name="ids" value='{$vo.id}' type='checkbox'></label>{/if}
+            </td>
+            <td class='text-left nowrap'>{$vo.project_name|default=''}</td>
+            <td class='text-left nowrap'>{$vo.main_project_name|default='-'}</td>
+            <td class='text-left nowrap'>{$vo.category_name|default=''}</td>
+            <td class='text-left nowrap'>{$vo.create_at|format_datetime}</td>
+            <td class='text-left nowrap'>
+
+                {if auth("admin/child_project/import")}
+                <a class='layui-btn layui-btn-normal layui-btn-sm dr' id="dr" style="background-color:#DC2219;margin-right: 10px;width: 65px " onclick="changename('{$vo.id}')">
+                    {if $vo.url eq ''}待导入{else}重新导入{/if}
+                </a>
+                {/if}
+
+                {if auth("admin/child_project/edit")}
+                <a data-dbclick class="layui-btn layui-btn-sm" style="background-color: #FFB822" data-title="编辑" data-open='{:url("edit")}?id={$vo.id}'>编 辑</a>
+                {/if}
+
+
+                {if $vo.url neq '' && auth("admin/child_project/look")}
+                <a data-dbclick class="layui-btn layui-btn-sm" style="background-color: #5AD729" data-title="查看" data-open='{:url("admin/child_project/look")}?id={$vo.id}'>查 看</a>
+                {/if}
+
+                {if $vo.url neq '' && auth("admin/child_project/down")}
+                <a href="{$vo.url}" class="layui-btn layui-btn-sm" style="background-color:#29B2D7 " download data-title="下载" >下 载</a>
+                {/if}
+
+                {if auth("admin/child_project/remove")}
+                <a class="layui-btn layui-btn-sm layui-btn-danger" style="background-color: #2944D7" data-confirm="确定要删除吗?" data-action="{:url('admin/child_project/remove')}" data-value="id#{$vo.id}" data-csrf="{:systoken('remove')}">删 除</a>
+                {/if}
+
+
+            </td>
+        </tr>
+        {/foreach}
+        </tbody>
+    </table>
+
+    {empty name='list'}<span class="notdata">没有记录哦</span>{else}{$pagehtml|raw|default=''}{/empty}
+
+</div>
+<script>
+
+    function getIds()
+    {
+        var id = document.getElementsByName('ids');
+        var value = new Array();
+        for (var i=0;i<id.length;i++){
+            if (id[i].checked){
+                value.push(id[i].value);
+            }
+        }
+        if (value.length<1){
+            layer.msg('请选择需要对比的数据');
+        }else if (value.length<2){
+            layer.msg('请选择至少两条数据');
+        }else{
+            $.form.href('{:url("admin/child_project/contrast")}?ids=' +value.toString());
+            //window.location = '{:url("admin/main_project/contrast")}?ids=' +value.toString();
+        }
+
+    }
+
+
+    var project_id = ''
+    function changename(val){
+        project_id = val
+    }
+    layui.use('upload', function(){
+        var upload = layui.upload;
+
+        //执行实例
+        var uploadInst = upload.render({
+            elem: '.dr' //绑定元素
+            ,url: 'admin/api.plugs/upload'
+            ,accept: 'file', //普通文件,
+            before: function(obj){ //obj参数包含的信息,跟 choose回调完全一致,可参见上文。
+                console.log(obj)
+                // layer.load(); //上传loading
+            }
+            ,done: function(res){
+                if (res.uploaded == true){
+                    var value = {path:res.key,project_id:project_id,url:res.url}
+                    $.ajax({
+                        url:"/admin/child_project/import",
+                        type:'get',
+                        data:value
+                        ,success:function(result){
+                            console.log(result.code);
+                            if (result.code==1){
+                                layer.msg('上传成功',{time:2000,end:function () {
+                                        location.reload();
+                                      //  $.form.href('{:url("admin/child_project/index")}');
+                                    }});
+                            }else {
+                                layer.msg('上传失败',{icon: 5});
+                            }
+                        }
+                    });
+                }else {
+                    layer.msg('上传失败',{icon: 5});
+                }
+                // layer.closeAll('loading'); //关闭loading
+            }
+            ,error: function(){
+                layer.msg('上传失败');
+            }
+        });
+    });
+</script>
+{/block}

+ 625 - 0
application/admin/view/main_project/index_search.html

@@ -0,0 +1,625 @@
+<style>
+    .layui-col-space12>*{
+        padding: 6px 0 6px 0 !important;
+    }
+</style>
+<fieldset>
+
+    <legend>条件搜索</legend>
+    <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">
+                <select class="layui-select" name="category_id">
+                    {foreach $menus as $k=>$v}
+                    {eq name='Think.get.category_id' value='$v.id.""'}
+                    <option selected value="{$v.id}">{$v.spl|raw}{$v.title}</option>
+                    {else}
+                    <option value="{$v.id}">{$v.spl|raw}{$v.title}</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 class="layui-select" name="engineering_category">
+                    {foreach [''=>'-- 全部 --','新建工程'=>'新建工程','改扩建加固工程'=>'改扩建加固工程','其他'=>'其他'] as $k=>$v}
+                    {eq name='Think.get.engineering_category' 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="project_scope" value="{$Think.get.project_scope|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="cost_categories">
+                    {foreach [''=>'-- 全部 --','投标价'=>'投标价','合同价'=>'合同价','结算价'=>'结算价','重计量'=>'重计量','清单控制价'=>'清单控制价','估算'=>'估算','概算'=>'概算','目标成本'=>'目标成本','其他'=>'其他'] as $k=>$v}
+                    {eq name='Think.get.cost_categories' 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">
+                <select class="layui-select" name="template">
+                    {foreach $template as $k=>$v}
+                    {eq name='Think.get.template' value='$v.id.""'}
+                    <option selected value="{$v.id}">{$v.title}</option>
+                    {else}
+                    <option value="{$v.id}">{$v.title}</option>
+                    {/eq}
+                    {/foreach}
+                </select>
+            </div>
+        </div>
+
+        <br />
+
+
+        <div class="layui-form-item layui-inline ">
+            <label class="layui-form-label">建设地点</label>
+            <div class="layui-input-inline layui-col-space18" style="width: 350px">
+                <label class="layui-col-xs4">
+                    <select name="construction_site_province"  id="province" lay-filter="province">
+                        <option value="">选择省</option>
+                        {foreach $province as $k=>$v}
+                        {eq name='Think.get.construction_site_province' value='$v.name.""'}
+                        <option selected value="{$v.name}">{$v.name}</option>
+                        {else}
+                        <option value="{$v.name}">{$v.name}</option>
+                        {/eq}
+                        {/foreach}
+                    </select>
+                </label>
+                <label class="layui-col-xs4">
+                    <select name="construction_site_city" class="city-selector" data-value="" id="city" lay-filter="city">
+                        <option value="">选择市</option>
+                        {foreach $city as $k=>$v}
+                        {eq name='Think.get.construction_site_city' value='$v.name.""'}
+                        <option selected value="{$v.name}">{$v.name}</option>
+                        {else}
+                        <option value="{$v.name}">{$v.name}</option>
+                        {/eq}
+                        {/foreach}
+                    </select>
+                </label>
+                <label class="layui-col-xs4">
+                    <select name="construction_site_area" class="county-selector" data-value="" id="area" lay-filter="area">
+                        <option value="">选择区</option>
+                        {foreach $area as $k=>$v}
+                        {eq name='Think.get.construction_site_area' value='$v.name.""'}
+                        <option selected value="{$v.name}">{$v.name}</option>
+                        {else}
+                        <option value="{$v.name}">{$v.name}</option>
+                        {/eq}
+                        {/foreach}
+                    </select>
+                </label>
+            </div>
+        </div>
+
+
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">编制日期</label>
+            <div class="layui-input-inline">
+<!--                <input type="text" class="layui-input" readonly name="prepare_date" value="{$Think.get.prepare_date|default=''}" id="test1" placeholder="yyyy-MM-dd">-->
+                <input data-date-range name="prepare_date" readonly value="{$Think.get.prepare_date|default=''}" placeholder="请选择编制日期" class="layui-input">
+            </div>
+        </div>
+
+        <br />
+
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">项目名称</label>
+            <div class="layui-input-inline">
+                <input name="project_name" value="{$Think.get.project_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 name="basis_for_listing" value="{$Think.get.basis_for_listing|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="building_composition" value="{$Think.get.building_composition|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="grade" value="{$Think.get.grade|default=''}" placeholder="请输入标准(档次)" class="layui-input">
+            </div>
+        </div>
+
+        <br />
+
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">总用地面积</label>
+            <div class="layui-input-inline layui-col-space12">
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="total_land_area_start" id="total_land_area_start" placeholder="" value="{$Think.get.total_land_area_start|default=''}" class="layui-input">
+                </div>
+                <div class="layui-form-mid">-</div>
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="total_land_area_end" id="total_land_area_end" placeholder="" value="{$Think.get.total_land_area_end|default=''}" class="layui-input">
+                </div>
+            </div>
+        </div>
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">总建筑面积</label>
+            <div class="layui-input-inline layui-col-space12">
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="gross_floor_area_start" id="gross_floor_area_start" placeholder="" value="{$Think.get.gross_floor_area_start|default=''}" class="layui-input">
+                </div>
+                <div class="layui-form-mid">-</div>
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="gross_floor_area_end" id="gross_floor_area_end" placeholder="" value="{$Think.get.gross_floor_area_end|default=''}" class="layui-input">
+                </div>
+            </div>
+        </div>
+
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">地上面积</label>
+            <div class="layui-input-inline layui-col-space12">
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="floor_area_start" id="floor_area_start" placeholder="" value="{$Think.get.floor_area_start|default=''}" class="layui-input">
+                </div>
+                <div class="layui-form-mid">-</div>
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="floor_area_end" id="floor_area_end" placeholder="" value="{$Think.get.floor_area_end|default=''}" class="layui-input">
+                </div>
+            </div>
+        </div>
+
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">地下面积</label>
+            <div class="layui-input-inline layui-col-space12">
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="underground_area_start" id="underground_area_start" placeholder="" value="{$Think.get.underground_area_start|default=''}" class="layui-input">
+                </div>
+                <div class="layui-form-mid">-</div>
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="underground_area_end" id="underground_area_end" placeholder="" value="{$Think.get.underground_area_end|default=''}" class="layui-input">
+                </div>
+            </div>
+        </div>
+
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">建筑密度</label>
+            <div class="layui-input-inline layui-col-space12">
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="building_density_start" id="building_density_start" placeholder="" value="{$Think.get.building_density_start|default=''}" class="layui-input">
+                </div>
+                <div class="layui-form-mid">-</div>
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="building_density_end" id="building_density_end" placeholder="" value="{$Think.get.building_density_end|default=''}" class="layui-input">
+                </div>
+            </div>
+        </div>
+
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">绿化面积</label>
+            <div class="layui-input-inline layui-col-space12">
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="green_area_start" id="green_area_start" placeholder="" value="{$Think.get.green_area_start|default=''}" class="layui-input">
+                </div>
+                <div class="layui-form-mid">-</div>
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="green_area_end" id="green_area_end" placeholder="" value="{$Think.get.green_area_end|default=''}" class="layui-input">
+                </div>
+            </div>
+        </div>
+
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">道路面积</label>
+            <div class="layui-input-inline layui-col-space12">
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="road_area_start" id="road_area_start" placeholder="" value="{$Think.get.road_area_start|default=''}" class="layui-input">
+                </div>
+                <div class="layui-form-mid">-</div>
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="road_area_end" id="road_area_end" placeholder="" value="{$Think.get.road_area_end|default=''}" class="layui-input">
+                </div>
+            </div>
+        </div>
+
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">道路长度</label>
+            <div class="layui-input-inline layui-col-space12">
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="road_length_start" id="road_length_start" placeholder="" value="{$Think.get.road_length_start|default=''}" class="layui-input">
+                </div>
+                <div class="layui-form-mid">-</div>
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="road_length_end" id="road_length_end" placeholder="" value="{$Think.get.road_length_end|default=''}" class="layui-input">
+                </div>
+            </div>
+        </div>
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">分期或分期建设情况描述</label>
+            <div class="layui-input-inline" style="width: 187px">
+                <input name="case_description" value="{$Think.get.case_description|default=''}" style="width: 190px !important;" 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="function_parameters" value="{$Think.get.function_parameters|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">
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="defense_start" id="defense_start" placeholder="" value="{$Think.get.defense_start|default=''}" class="layui-input">
+                </div>
+                <div class="layui-form-mid">-</div>
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="defense_end" id="defense_end" placeholder="" value="{$Think.get.defense_end|default=''}" class="layui-input">
+                </div>
+            </div>
+        </div>
+
+        <br />
+
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">人防类型</label>
+            <div class="layui-input-inline">
+                <input name="defense_type" value="{$Think.get.defense_type|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="investment_subject" value="{$Think.get.investment_subject|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="sources_funding" value="{$Think.get.sources_funding|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="contract_mode" value="{$Think.get.contract_mode|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="management_mode" value="{$Think.get.management_mode|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="owner" value="{$Think.get.owner|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="total_package" value="{$Think.get.total_package|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="starting_time" readonly value="{$Think.get.starting_time|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="ending_time" readonly value="{$Think.get.ending_time|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 layui-col-space12">
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="project_time_start" id="project_time_start" placeholder="" value="{$Think.get.project_time_start|default=''}" class="layui-input">
+                </div>
+                <div class="layui-form-mid">-</div>
+                <div class="layui-input-inline" style="width: 68px;">
+                    <input type="text" name="project_time_end" id="project_time_end" placeholder="" value="{$Think.get.project_time_end|default=''}" class="layui-input">
+                </div>
+            </div>
+        </div>
+        <div class="layui-form-item layui-inline">
+            <label class="layui-form-label">获奖情况</label>
+            <div class="layui-input-inline">
+                <input name="awards" value="{$Think.get.awards|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="other_instructions" value="{$Think.get.other_instructions|default=''}" placeholder="请输入其他说明" class="layui-input">
+            </div>
+        </div>
+
+
+        <div class="layui-form-item layui-inline">
+            <button class="layui-btn layui-btn-primary" style="color: #FFFFFF;background-color: #DC2219" lay-submit lay-filter="tijiao"><i class="layui-icon">&#xe615;</i>立即搜索</button>
+        </div>
+    </form>
+
+</fieldset>
+
+<script>
+    form.render();
+    layui.use(['form', 'layedit', 'laydate'], function(){
+        var form = layui.form
+            ,layer = layui.layer
+            ,layedit = layui.layedit
+            ,laydate = layui.laydate;
+
+        //常规用法
+        laydate.render({
+            elem: '#test1'
+        });
+
+        form.on('submit(tijiao)', function(data) {
+            var total_land_area_start = data.field.total_land_area_start;
+            var total_land_area_end = data.field.total_land_area_end;
+            if (total_land_area_start=='' && total_land_area_end!=''){
+                layer.msg('请输入起始值');
+                $("#total_land_area_start").focus();
+                return false
+            }else if (total_land_area_start!='' && total_land_area_end==''){
+                layer.msg('请输入终止值');
+                $("#total_land_area_end").focus();
+                return false
+            }else if (total_land_area_end<total_land_area_start){
+                layer.msg('终止值小于起始值');
+                $("#total_land_area_start").focus();
+                return false
+            }
+
+            var gross_floor_area_start = data.field.gross_floor_area_start;
+            var gross_floor_area_end = data.field.gross_floor_area_end;
+            if (gross_floor_area_start=='' && gross_floor_area_end!=''){
+                layer.msg('请输入起始值');
+                $("#gross_floor_area_start").focus();
+                return false
+            }else if (gross_floor_area_start!='' && gross_floor_area_end==''){
+                layer.msg('请输入终止值');
+                $("#gross_floor_area_end").focus();
+                return false
+            }else if (gross_floor_area_end<gross_floor_area_start){
+                layer.msg('终止值小于起始值');
+                $("#gross_floor_area_start").focus();
+                return false
+            }
+
+
+            var floor_area_start = data.field.floor_area_start;
+            var floor_area_end = data.field.floor_area_end;
+            if (floor_area_start=='' && floor_area_end!=''){
+                layer.msg('请输入起始值');
+                $("#floor_area_start").focus();
+                return false
+            }else if (floor_area_start!='' && floor_area_end==''){
+                layer.msg('请输入终止值');
+                $("#floor_area_end").focus();
+                return false
+            }else if (floor_area_end<floor_area_start){
+                layer.msg('终止值小于起始值');
+                $("#floor_area_start").focus();
+                return false
+            }
+
+            var underground_area_start = data.field.underground_area_start;
+            var underground_area_end = data.field.underground_area_end;
+            if (underground_area_start=='' && underground_area_end!=''){
+                layer.msg('请输入起始值');
+                $("#underground_area_start").focus();
+                return false
+            }else if (underground_area_start!='' && underground_area_end==''){
+                layer.msg('请输入终止值');
+                $("#underground_area_end").focus();
+                return false
+            }else if (underground_area_end<underground_area_start){
+                layer.msg('终止值小于起始值');
+                $("#underground_area_start").focus();
+                return false
+            }
+
+            var building_density_start = data.field.building_density_start;
+            var building_density_end = data.field.building_density_end;
+            if (building_density_start=='' && building_density_end!=''){
+                layer.msg('请输入起始值');
+                $("#building_density_start").focus();
+                return false
+            }else if (building_density_start!='' && building_density_end==''){
+                layer.msg('请输入终止值');
+                $("#building_density_end").focus();
+                return false
+            }else if (building_density_end<building_density_start){
+                layer.msg('终止值小于起始值');
+                $("#building_density_start").focus();
+                return false
+            }
+
+
+            var green_area_start = data.field.green_area_start;
+            var green_area_end = data.field.green_area_end;
+            if (green_area_start=='' && green_area_end!=''){
+                layer.msg('请输入起始值');
+                $("#green_area_start").focus();
+                return false
+            }else if (green_area_start!='' && green_area_end==''){
+                layer.msg('请输入终止值');
+                $("#green_area_end").focus();
+                return false
+            }else if (green_area_end<green_area_start){
+                layer.msg('终止值小于起始值');
+                $("#green_area_start").focus();
+                return false
+            }
+
+            var road_area_start = data.field.road_area_start;
+            var road_area_end = data.field.road_area_end;
+            if (road_area_start=='' && road_area_end!=''){
+                layer.msg('请输入起始值');
+                $("#road_area_start").focus();
+                return false
+            }else if (road_area_start!='' && road_area_end==''){
+                layer.msg('请输入终止值');
+                $("#road_area_end").focus();
+                return false
+            }else if (road_area_end<road_area_start){
+                layer.msg('终止值小于起始值');
+                $("#road_area_start").focus();
+                return false
+            }
+
+            var road_length_start = data.field.road_length_start;
+            var road_length_end = data.field.road_length_end;
+            if (road_length_start=='' && road_length_end!=''){
+                layer.msg('请输入起始值');
+                $("#road_length_start").focus();
+                return false
+            }else if (road_length_start!='' && road_length_end==''){
+                layer.msg('请输入终止值');
+                $("#road_length_end").focus();
+                return false
+            }else if (road_length_end<road_length_start){
+                layer.msg('终止值小于起始值');
+                $("#road_length_start").focus();
+                return false
+            }
+
+            var project_time_start = data.field.project_time_start;
+            var project_time_end = data.field.project_time_end;
+            if (project_time_start=='' && project_time_end!=''){
+                layer.msg('请输入起始值');
+                $("#project_time_start").focus();
+                return false
+            }else if (project_time_start!='' && project_time_end==''){
+                layer.msg('请输入终止值');
+                $("#project_time_end").focus();
+                return false
+            }else if (project_time_end<project_time_start){
+                layer.msg('终止值小于起始值');
+                $("#project_time_start").focus();
+                return false
+            }
+
+            var defense_start = data.field.defense_start;
+            var defense_end = data.field.defense_end;
+            if (defense_start=='' && defense_end!=''){
+                layer.msg('请输入起始值');
+                $("#defense_start").focus();
+                return false
+            }else if (defense_start!='' && defense_end==''){
+                layer.msg('请输入终止值');
+                $("#defense_end").focus();
+                return false
+            }else if (defense_end<defense_start){
+                layer.msg('终止值小于起始值');
+                $("#defense_start").focus();
+                return false
+            }
+
+
+
+        });
+
+        form.on('select(province)', function (data) {
+            var val = data.value;
+            $.ajax({
+                type:"get",
+                url:"{:url('MainProject/get_city')}",  //数据传输的控制器方法
+                data: {id:val},//这里data传递过去的是序列化以后的字符串
+                success:function(data){
+                    //console.log(data)
+                    var arr = data.data;
+                    //console.log(arr)
+                    if (arr.length>0){
+                        //$("#tow").attr("style","display:block;");//显示div
+                        var options='<option value="">选择市</option>';
+                        for (var i = 0; i < arr.length; i++) {
+                            var tag = arr[i];
+                            options+=' <option value="'+tag.name+'">'+tag.name+'</option>';
+                        }
+                        $("select[name='construction_site_city']").html(options)
+                        form.render('select');
+                    }else {
+                        var options='<option value="">选择市</option>';
+                        $("select[name='construction_site_city']").html(options)
+                        form.render('select');
+                    }
+                }
+            });
+        });
+
+        form.on('select(city)', function (data) {
+            var val = data.value;
+            // console.log(val)
+            $.ajax({
+                type:"get",
+                url:"{:url('MainProject/get_area')}",  //数据传输的控制器方法
+                data: {id:val},//这里data传递过去的是序列化以后的字符串
+                success:function(data){
+                    //console.log(data)
+                    var arr = data.data;
+                    // console.log(arr)
+                    if (arr.length>0){
+                        var options='<option value="">选择区</option>';
+                        for (var i = 0; i < arr.length; i++) {
+                            var tag = arr[i];
+                            options+=' <option value="'+tag.name+'">'+tag.name+'</option>';
+                        }
+                        $("select[name='construction_site_area']").html(options)
+                        form.render('select');
+                    }else {
+                        var options='<option value="">选择区</option>';
+                        $("select[name='construction_site_area']").html(options)
+                        form.render('select');
+                    }
+                }
+            });
+        });
+
+    });
+
+</script>

+ 88 - 0
application/admin/view/main_project/info.html

@@ -0,0 +1,88 @@
+<div style="padding: 20px; background-color: #F2F2F2;">
+    <div class="layui-row layui-col-space15">
+        <div class="layui-col-md12">
+            <div class="layui-card">
+                <div class="layui-card-body">
+                    <div class="layui-col-md6">项目名称:{$vo.project_name|default='--'}</div>
+                    <div class="layui-col-md6">造价类别:{$vo.cost_categories|default='--'}</div><hr />
+                    <div class="layui-col-md6">编制日期:{$vo.prepare_date|default='0'}</div>
+                    <div class="layui-col-md6">清单编制依据:{$vo.basis_for_listing|default='--'}</div><hr />
+                    <div class="layui-col-md6">工程范围:{$vo.project_scope|default='--'}</div><hr />
+
+                </div>
+            </div>
+        </div>
+        <div class="layui-col-md12">
+            <div class="layui-card">
+                <div class="layui-card-header">项目业态</div>
+                <div class="layui-card-body">
+                    <div class="layui-col-md6">建筑分类:{$vo.category_name|default='--'}</div>
+                    <div class="layui-col-md6">工程类别:{$vo.engineering_category|default='--'}</div><hr />
+                    <div class="layui-col-md6">建设地点:{$vo.construction_site_province|default='--'}-{$vo.construction_site_city|default='--'}-{$vo.construction_site_area|default='--'}</div>
+                    <div class="layui-col-md6">标准(档次):{$vo.grade|default='--'}</div><hr />
+                </div>
+            </div>
+        </div>
+        <div class="layui-col-md12">
+            <div class="layui-card">
+                <div class="layui-card-header">项目总体特征</div>
+                <div class="layui-card-body">
+                    <div class="layui-col-md12">建筑类别及组成:{$vo.building_composition|default='--'}</div><hr />
+                    <div class="layui-col-md6">总用地面积:{$vo.total_land_area|default='--'}</div>
+                    <div class="layui-col-md6">总建筑面积:{$vo.gross_floor_area|default='--'}</div><hr />
+                    <div class="layui-col-md6">地上面积:{$vo.floor_area|default='--'}</div>
+                    <div class="layui-col-md6">地下面积:{$vo.underground_area|default='--'}</div><hr />
+                    <div class="layui-col-md6">建筑密度:{$vo.building_density|default='--'}</div>
+                    <div class="layui-col-md6">绿化面积:{$vo.green_area|default='--'}</div><hr />
+                    <div class="layui-col-md6">道路面积:{$vo.road_area|default='--'}</div>
+                    <div class="layui-col-md6">道路长度:{$vo.road_length|default='--'}</div><hr />
+                    <div class="layui-col-md12">分期或分期建设情况描述:{$vo.case_description|default='--'}</div><hr />
+                    <div class="layui-col-md12">功能参数:{$vo.function_parameters|default='--'}</div><hr />
+                    <div class="layui-col-md12">人防类型/级别/面积:{$vo.defense|default='--'}</div><hr />
+                </div>
+            </div>
+        </div>
+
+        <div class="layui-col-md12">
+            <div class="layui-card">
+                <div class="layui-card-header">投融资模式</div>
+                <div class="layui-card-body">
+                    <div class="layui-col-md6">投资主体:{$vo.investment_subject|default='--'}</div>
+                    <div class="layui-col-md6">资金来源:{$vo.sources_funding|default='--'}</div><hr />
+                    <div class="layui-col-md6">承发包模式:{$vo.contract_mode|default='--'}</div>
+                    <div class="layui-col-md6">组织管理模式:{$vo.management_mode|default='--'}</div><hr />
+                </div>
+            </div>
+        </div>
+
+        <div class="layui-col-md12">
+            <div class="layui-card">
+                <div class="layui-card-header">项目主要参与单位</div>
+                <div class="layui-card-body">
+                    <div class="layui-col-md6">业主:{$vo.owner|default='--'}</div>
+                    <div class="layui-col-md6">总包:{$vo.total_package|default='--'}</div><hr />
+                </div>
+            </div>
+        </div>
+
+        <div class="layui-col-md12">
+            <div class="layui-card">
+                <div class="layui-card-header">日期</div>
+                <div class="layui-card-body">
+                    <div class="layui-col-md4">开工时间:{$vo.starting_time|default='--'}</div>
+                    <div class="layui-col-md4">竣工时间:{$vo.ending_time|default='--'}</div>
+                    <div class="layui-col-md4">工期:{$vo.project_time|default='--'}</div><hr />
+                </div>
+            </div>
+        </div>
+
+        <div class="layui-col-md12">
+            <div class="layui-card">
+                <div class="layui-card-body">
+                    <div class="layui-col-md12">获奖情况:{$vo.awards|default='--'}</div><hr />
+                    <div class="layui-col-md12">其他说明:{$vo.other_instructions|default='--'}</div><hr />
+                </div>
+            </div>
+        </div>
+    </div>
+</div>

+ 53 - 0
application/admin/view/main_project/look.html

@@ -0,0 +1,53 @@
+{extend name='main'}
+
+{block name="button"}
+{if auth("add")}
+<button class="layui-btn" style="height: 30px;line-height:28px;color:#FFFFFF;background-color: #DC2219;border: 1px solid #C9C9C9 " type='button' onclick="window.history.back()">返 回</button>
+{/if}
+
+
+{/block}
+
+{block name="content"}
+<div class="think-box-shadow">
+    <table class="layui-table margin-top-10">
+        {notempty name='list'}
+        <thead>
+        <tr>
+            <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>
+            <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='text-left nowrap' style="background-color:#f2f2f2">{$vo.number|default=''}</td>
+            <td class='text-left nowrap'>{$vo.subjects|default='0'}</td>
+            <td class='text-left nowrap'>{$vo.costs_are_excluded|default='0'}</td>
+            <td class='text-left nowrap'>{$vo.total_vat|default='0'}</td>
+            <td class='text-left nowrap'>{$vo.measurement_cost|default='0'}</td>
+            <td class='text-left nowrap'>{$vo.area|default='0'}</td>
+            <td class='text-left nowrap'>{$vo.unilateral_cost_indicator|default='0'}</td>
+            <td class='text-left nowrap'>{$vo.single_cost_indicator|default='0'}</td>
+            <td class='text-left nowrap'>{$vo.single_party_cost_tax|default='0'}</td>
+            <td class='text-left nowrap'>{$vo.single_party_cost_no_tax|default='0'}</td>
+            <td class='text-left nowrap'>{$vo.note|default='-'}</td>
+        </tr>
+        {/foreach}
+        </tbody>
+    </table>
+
+    {empty name='list'}<span class="notdata">没有记录哦</span>{else}{$pagehtml|raw|default=''}{/empty}
+
+</div>
+{/block}

+ 250 - 0
application/admin/view/main_project/see.html

@@ -0,0 +1,250 @@
+{extend name='main'}
+
+{block name="button"}
+{if auth("add")}
+<button class="layui-btn" style="height: 30px;line-height:28px;background-color: #DC2219;color: #FFFFFF;border: 1px solid #C9C9C9 " type='button' onclick="window.history.back()">返 回</button>
+{/if}
+
+
+{/block}
+
+{block name="content"}
+<style>
+    .tu{
+        width: 75%;height:600px;float: left
+    }
+    .layui-table td, .layui-table th, .layui-table-col-set, .layui-table-fixed-r, .layui-table-grid-down, .layui-table-header, .layui-table-page, .layui-table-tips-main, .layui-table-tool, .layui-table-total, .layui-table-view{
+        border: none !important;
+
+
+    }
+    .layui-table{
+        background-color:initial !important;
+    }
+</style>
+
+<div class="layui-tab">
+    <input type="hidden" id="subjects" value="{$subjects}">
+    <input type="hidden" id="ids" value="{$ids}">
+
+    <ul class="layui-tab-title">
+        <li class="layui-this" onclick="change()">不含增值税测算成本 (万元)</li>
+        <li onclick="change1()">增值税总额</li>
+        <li onclick="change2()">含增值税测算成本</li>
+        <li onclick="change3()">建面单方成本指标(不含税)</li>
+        <li onclick="change4()">建面单方成本指标(含税)</li>
+        <li onclick="change5()">可售单方成本指标(不含税)</li>
+        <li onclick="change6()">可售单方成本指标(含税)</li>
+    </ul>
+    <div class="layui-tab-content" style="height: 100px;">
+        <div class="layui-tab-item layui-show" style="width:100%;">
+            <div id="main" class="tu"></div>
+        </div>
+        <div class="layui-tab-item" style="width:100%;">
+            <div id="main1" class="tu" ></div>
+        </div>
+        <div class="layui-tab-item" style="width:100%;">
+            <div id="main2" class="tu" ></div>
+        </div>
+        <div class="layui-tab-item" style="width:100%;">
+            <div id="main3" class="tu"></div>
+        </div>
+        <div class="layui-tab-item" style="width:100%;">
+            <div id="main4" class="tu"></div>
+        </div>
+        <div class="layui-tab-item" style="width:100%;">
+            <div id="main5" class="tu"></div>
+        </div>
+        <div class="layui-tab-item" style="width:100%;">
+            <div id="main6" class="tu"></div>
+        </div>
+        <div style="width: 25%;float: right">
+            <table class="layui-table margin-top-10">
+                <tr>
+                    <th style="font-weight:bold">样本名称</th>
+                    <th style="font-weight:bold">数值</th>
+                    <th style="font-weight:bold">备注</th>
+                </tr>
+                <tbody id="right">
+
+                </tbody>
+            </table>
+
+        </div>
+    </div>
+</div>
+
+<script type="text/javascript">
+
+    setinfo('main','costs_are_excluded')
+
+    function change () {
+        setinfo('main','costs_are_excluded')
+    }
+    function change1 () {
+        // setTimeout(() => {
+        //     // 基于准备好的dom,初始化echarts实例
+        //     var myChart1 = echarts.init(document.getElementById('main1'));
+        //     // 指定图表的配置项和数据
+        //     var option1 = {
+        //         title: {
+        //             text: ''
+        //         },
+        //         tooltip: {},
+        //         legend: {
+        //             // data: ['销量']
+        //         },
+        //         xAxis: {
+        //             axisLabel:{
+        //                 interval:0,
+        //                 // rotate:20
+        //             },
+        //             data:result1.data.total_vat.title
+        //         },
+        //         yAxis: {},
+        //         series: [
+        //             {
+        //                 name: result1.data.subjects,
+        //                 type: 'bar',
+        //                 data:result1.data.total_vat.value
+        //             }
+        //         ]
+        //     };
+        //     // 使用刚指定的配置项和数据显示图表。
+        //     myChart1.setOption(option1);
+        // },200)
+        setinfo('main1','total_vat')
+    }
+    function change2 () {
+        setinfo('main2','measurement_cost')
+    }
+    function change3 () {
+        setinfo('main3','unilateral_cost_indicator')
+    }
+    function change4 () {
+        setinfo('main4','single_cost_indicator')
+    }
+    function change5 () {
+        setinfo('main5','single_party_cost_tax')
+    }
+    function change6 () {
+        setinfo('main6','single_party_cost_no_tax')
+    }
+
+    //ajax获取数据
+    function setinfo(where,field) {
+        var subjects = $("#subjects").val()
+        var ids = $("#ids").val()
+        var value = {subjects:subjects,ids:ids,field:field}
+        $.ajax({
+            url:"/admin/main_project/get_see_info",
+            type:'get',
+            data:value
+            ,success:function(result){
+                console.log(result);
+
+                setchart(where,result,field);
+
+                var arr = result.data.right;
+                htmlright(arr)
+            }
+        });
+    }
+
+    //画图
+    function setchart(where,result,field) {
+        var len = result.data.field.title.length
+        var xname = ''
+        if (field=='costs_are_excluded'){
+            xname = '不含增值税测算成本 (万元)'
+        }else if (field=='total_vat'){
+            xname = '增值税总额';
+        }else if (field=='measurement_cost'){
+            xname = '含增值税测算成本';
+        }else if (field=='unilateral_cost_indicator'){
+            xname = '单方成本指标(不含税)';
+        }else if (field=='single_cost_indicator'){
+            xname = '单方成本指标(含税)';
+        }else if (field=='single_party_cost_tax'){
+            xname = '可售单方成本指标(不含税)';
+        }else if (field=='single_party_cost_no_tax'){
+            xname = '可售单方成本指标(含税)';
+        }
+        var cid = document.getElementById(where)
+        //echarts重新渲染
+        if (cid.hasAttribute("_echarts_instance_"))
+            cid.removeAttribute("_echarts_instance_")
+        // 基于准备好的dom,初始化echarts实例
+        var myChart = echarts.init(cid);
+
+        // 指定图表的配置项和数据
+        var option = {
+            title: {
+                text: ''
+            },
+            tooltip: {},
+            legend: {
+               //  data: ['销量']
+            },
+            xAxis: {
+                show:true,
+                name:xname,
+                nameTextStyle:{				//---坐标轴名称样式
+                    padding:[40,100,-50,-105],	//---坐标轴名称相对位置
+                },
+                axisLabel:{
+                    interval:0,
+                    // rotate:20
+                    formatter: function (value) {
+                        value = value.replace(/[^\x00-\xff]/g, "$&\x01").replace(/.{12}\x01?/g, "$&\n").replace(/\x01/g, "");
+                        return value;
+                    }
+                },
+                //data: ['100-113.8', '113.8-127.6', '127.6-141.4', '141.4-155.2', '155.2-169', '155.2-169', '155.2-169', '155.2-169', '155.2-169', '155.2-169']
+                data:result.data.field.title
+            },
+            yAxis: {
+                show:true,
+                name:'工程数量',
+                nameTextStyle:{				//---坐标轴名称样式
+                    padding:[5,100,-20,15],	//---坐标轴名称相对位置
+                },
+            },
+            series: [
+                {
+                    name: result.data.subjects,
+                    type: 'bar',
+                    barMaxWidth:'10%',
+                    label:{
+                        show:true,
+                        position:'top',
+                        color:'#000000'
+                    },
+                    // data: [5, 0, 36, 10, 12, 14, 13, 30, 40, 1076872]
+                    data:result.data.field.value
+                }
+            ]
+        };
+        myChart.setOption(option);
+    }
+
+    //填充右边栏
+    function htmlright(arr) {
+        if (arr.length>0) {
+            var html = '';
+            for (var i = 0; i < arr.length; i++) {
+                var tag = arr[i];
+                html += '<tr>' +
+                    '<th style="color:red;">' + tag.project_name + '</th>' +
+                    '<th>' + tag.value + '</th>' +
+                    '<th>' + tag.note + '</th>' +
+                    '</tr>';
+            }
+            $('#right').html(html);
+        }
+    }
+
+</script>
+
+
+{/block}

+ 89 - 0
application/admin/view/menu/form.html

@@ -0,0 +1,89 @@
+<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">
+                <select name='pid' class='layui-select' lay-search>
+                    <!--{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">必选,请选择上级菜单或顶级菜单(目前最多支持三级菜单)</p>
+            </div>
+        </div>
+
+        <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">必填,请填写菜单名称(如:系统管理),建议字符不要太长,一般4-6个汉字</p>
+            </div>
+        </div>
+
+        <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">
+                    必填,请填写系统节点(如:admin/user/index),节点加入权限管理时菜单才会自动隐藏,非规则内的不会隐藏;
+                    <br>正常情况下,在输入的时候会有自动提示。如果是上级菜单时,请填写"#"符号,不要填写地址或节点地址
+                </p>
+            </div>
+        </div>
+
+        <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">可选,设置菜单链接的GET访问参数(如:name=1&age=3)</p>
+            </div>
+        </div>
+
+        <div class="layui-form-item">
+            <label class="layui-form-label">菜单图标</label>
+            <div class="layui-input-block">
+                <div class="layui-input-inline">
+                    <input placeholder="请输入或选择图标" 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;margin:0" class='{$vo.icon|default=""}'></i>
+                </span>
+                <button data-icon='icon' type='button' class='layui-btn layui-btn-primary'>选择图标</button>
+                <p class="help-block">可选,设置菜单选项前置图标,目前只支持 Font Awesome 5.2.0 字体图标</p>
+            </div>
+        </div>
+
+    </div>
+
+    <div class="hr-line-dashed"></div>
+    {notempty name='vo.id'}<input type='hidden' value='{$vo.id}' name='id'>{/notempty}
+
+    <div class="layui-form-item text-center">
+        <button class="layui-btn" type='submit'>保存数据</button>
+        <button class="layui-btn layui-btn-danger" type='button' data-confirm="确定要取消编辑吗?" data-close>取消编辑</button>
+    </div>
+
+</form>
+
+{block name='script'}
+<script>
+    require(['jquery.autocompleter'], function () {
+        form.render();
+        $('[name="icon"]').on('change', function () {
+            $(this).parent().next().find('i').get(0).className = this.value
+        });
+        $('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}

+ 80 - 0
application/admin/view/menu/index.html

@@ -0,0 +1,80 @@
+{extend name='main'}
+
+{block name="button"}
+
+{if auth("add")}
+<button data-modal='{:url("add")}' data-title="添加菜单" class='layui-btn layui-btn-sm layui-btn-primary'>添加菜单</button>
+{/if}
+
+{if auth("remove")}
+<button data-action='{:url("remove")}' data-csrf="{:systoken('remove')}" data-rule="id#{key}" class='layui-btn layui-btn-sm layui-btn-primary'>删除菜单</button>
+{/if}
+
+{/block}
+
+{block name="content"}
+<div class="think-box-shadow">
+    {empty name='list'}
+    <blockquote class="layui-elem-quote">没 有 记 录 哦!</blockquote>
+    {else}
+    <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 colspan="2"></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 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="color-red">已禁用</span>{else}<span class="color-green">使用中</span>{/eq}</td>
+            <td class='text-center nowrap notselect'>
+
+                {if auth("add")}
+                <span class="text-explode">|</span>
+                <!--{if $vo.spt < 2}-->
+                <a class="layui-btn layui-btn-xs layui-btn-primary" data-title="添加子菜单" data-modal='{:url("add")}?pid={$vo.id}'>添 加</a>
+                <!--{else}-->
+                <a class="layui-btn layui-btn-xs layui-btn-disabled">添 加</a>
+                <!--{/if}-->
+                {/if}
+
+                {if auth("edit")}
+                <a data-dbclick class="layui-btn layui-btn-xs" data-title="编辑菜单" data-modal='{:url("edit")}?id={$vo.id}'>编 辑</a>
+                {/if}
+
+                {if $vo.status eq 1 and auth("forbid")}
+                <a class="layui-btn layui-btn-warm layui-btn-xs" data-confirm="确定要禁用菜单吗?" data-action="{:url('forbid')}" data-value="id#{$vo.ids};status#0" data-csrf="{:systoken('forbid')}">禁 用</a>
+                {elseif auth("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('resume')}">启 用</a>
+                {/if}
+
+                {if auth("remove")}
+                <a class="layui-btn layui-btn-danger layui-btn-xs" data-confirm="确定要删除数据吗?" data-action="{:url('remove')}" data-value="id#{$vo.ids}" data-csrf="{:systoken('remove')}">删 除</a>
+                {/if}
+
+            </td>
+        </tr>
+        {/foreach}
+        </tbody>
+    </table>
+    {/empty}
+</div>
+{/block}

+ 68 - 0
application/admin/view/oplog/index.html

@@ -0,0 +1,68 @@
+{extend name='main'}
+
+{block name="button"}
+
+{if auth("clear")}
+<button data-load='{:url("clear")}' data-confirm="确定要消除所有日志吗?" class='layui-btn layui-btn-sm layui-btn-primary'>清理日志</button>
+{/if}
+
+{if auth("remove")}
+<button data-action='{:url("remove")}' data-rule="id#{key}" data-csrf="{:systoken('remove')}" data-confirm="确定要删除日志吗?" class='layui-btn layui-btn-sm layui-btn-primary'>删除日志</button>
+{/if}
+
+{/block}
+
+{block name="content"}
+<div class="think-box-shadow">
+    {include file='oplog/index_search'}
+    <table class="layui-table margin-top-10" lay-skin="line">
+        {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>
+            <th></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">
+                <span class="font-w7">{$vo.username|default='-'}</span><br>
+                <span class="color-desc">{$vo.node|default='-'}</span>
+            </td>
+            <td class='text-left nowrap'>
+                <p class="color-text">{$vo.action|default='-'}</p>
+                <p class="color-desc">{$vo.content|default='-'}</p>
+            </td>
+            <td class='text-left nowrap'>
+                <p class="color-text">{$vo.geoip|default='-'}</p>
+                <p class="color-desc">{$vo.isp|default='-'}</p>
+            </td>
+            <td class='text-left nowrap'>
+                日期:{$vo.create_at|format_datetime|str_replace=' ','<br><span class="color-desc">时间:',###|raw}</span>
+            </td>
+            <td class='text-left nowrap'>
+                {if auth("remove")}
+                <a data-dbclick class="layui-btn layui-btn-sm layui-btn-danger" data-confirm="确定要删除该日志吗?" data-action="{:url('remove')}" data-value="id#{$vo.id}" data-csrf="{:systoken('remove')}">删 除</a>
+                {/if}
+            </td>
+        </tr>
+        {/foreach}
+        </tbody>
+        {/notempty}
+    </table>
+
+    {empty name='list'}<span class="notdata">没有记录哦</span>{else}{$pagehtml|raw|default=''}{/empty}
+
+</div>
+
+{/block}

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

@@ -0,0 +1,56 @@
+<fieldset>
+
+    <legend>条件搜索</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>

+ 31 - 0
application/admin/view/template/form.html

@@ -0,0 +1,31 @@
+<form onsubmit="return false;" action="{:request()->url()}" 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-col-xs2 think-form-label">名称</label>
+            <label class="layui-col-xs10">
+                <input name="title" required value='{$vo.title|default=""}' placeholder="请输入名称" class="layui-input">
+            </label>
+        </div>
+
+        <div class="layui-row margin-bottom-15">
+            <label class="layui-col-xs2 think-form-label">模板</label>
+            <label class="layui-col-xs8 think-form-group-left">
+                <input name="url" required readonly value='{$vo.url|default=""}' placeholder="请上传模板" class="layui-input">
+            </label>
+            <a class="layui-col-xs2 layui-btn think-form-group-right" data-file="btn" data-field="url" data-type="xls,xlsx">
+                <i class="layui-icon layui-icon-upload"></i> 上传模板
+            </a>
+        </div>
+    </div>
+
+    <div class="hr-line-dashed"></div>
+    <div class="layui-form-item text-center">
+        {if isset($vo.id)}<input type='hidden' value="<?php echo date('Y-m-d H:i:s'); ?>" name='update_at'>{else}<input type='hidden' value="<?php echo date('Y-m-d H:i:s'); ?>" name='create_at'>{/if}
+        {notempty name='vo.id'}<input type='hidden' value='{$vo.id}' name='id'>{/notempty}
+        <button class="layui-btn" type='submit'>保存数据</button>
+    </div>
+</form>
+<script>window.form.render();
+</script>

+ 50 - 0
application/admin/view/template/index.html

@@ -0,0 +1,50 @@
+{extend name='main'}
+{block name="button"}
+
+{if auth("upload")}
+<a data-title="上传模板" class="layui-btn layui-btn-sm" style="background-color: #DC2219" data-modal='{:url("upload")}'>上传</a>
+{/if}
+
+{/block}
+{block name="content"}
+<div class="think-box-shadow">
+    <table class="layui-table margin-top-10">
+        {notempty name='list'}
+        <thead>
+        <tr>
+            <th style="width: 70%" class='text-center nowrap'>名称</th>
+            <th style="width: 30%" class='text-center nowrap'>操作</th>
+        </tr>
+        </thead>
+        {/notempty}
+        <tbody>
+        {foreach $list as $key=>$vo}
+        <tr>
+            <td class='text-center nowrap'>{$vo.title|default=''}</td>
+            <td class='text-center nowrap'>
+<!--                {if auth("upload")}-->
+<!--                     <a data-title="上传模板" class="layui-btn layui-btn-sm" style="background-color: #DC2219" data-modal='{:url("upload")}?id={$vo.id}'>上传</a>-->
+<!--                {/if}-->
+
+                {if auth("edit")}
+                <a data-dbclick class="layui-btn layui-btn-sm" style="background-color: #FFB822" data-title="编辑" data-modal='{:url("edit")}?id={$vo.id}'>编辑</a>
+                {/if}
+
+                {if auth("down")}
+                <a href="{$vo.url}" style="background-color: #DC2219" download="{$vo.title}" class="layui-btn layui-btn-sm">下载</a>
+                {/if}
+
+                {if auth("remove")}
+                <a class="layui-btn layui-btn-sm layui-btn-danger" style="background-color: #2944D7" data-confirm="确定要删除吗?" data-action="{:url('remove')}" data-value="id#{$vo.id}" data-csrf="{:systoken('remove')}">删 除</a>
+                {/if}
+
+            </td>
+        </tr>
+        {/foreach}
+        </tbody>
+    </table>
+    {empty name='list'}<span class="notdata">没有记录哦</span>{else}{$pagehtml|raw|default=''}{/empty}
+
+</div>
+
+{/block}

+ 62 - 0
application/admin/view/user/form.html

@@ -0,0 +1,62 @@
+
+<form class="layui-form layui-card" action="{:request()->url()}" data-auto="true" method="post" autocomplete="off">
+    <div class="layui-card-body padding-left-40">
+        <div class="layui-form-item">
+            <label class="layui-col-xs2 think-form-label">姓名</label>
+            <label class="layui-col-xs10">
+                <input name="name" required value='{$vo.name|default=""}' placeholder="请输入姓名" class="layui-input">
+            </label>
+        </div>
+        <div class="layui-form-item">
+            <label class="layui-col-xs2 think-form-label">手机号</label>
+            <label class="layui-col-xs10">
+                <input type="tel" required maxlength="11" autocomplete="off" name="phone" value='{$vo.phone|default=""}' pattern="^1[3-9][0-9]{9}$" placeholder="请输入用户联系手机" class="layui-input">
+            </label>
+        </div>
+        <div class="layui-form-item">
+            <label class="layui-col-xs2 think-form-label">登录账号</label>
+            <label class="layui-col-xs10">
+                <input name="username" required value='{$vo.username|default=""}' pattern="^.{4,}$" placeholder="请输入4位及以上字符登录用户账号" class="layui-input">
+            </label>
+        </div>
+
+        {if !isset($vo.id)}
+        <div class="layui-form-item">
+            <label class="layui-col-xs2 think-form-label">登录密码</label>
+            <label class="layui-col-xs10">
+                <input type="password" name="password" maxlength="32" pattern="^(?![\d]+$)(?![a-zA-Z]+$)(?![^\da-zA-Z]+$).{6,32}$" required placeholder="必需包含大小写字母、数字、符号的任意两者组合。" class="layui-input">
+            </label>
+        </div>
+        {/if}
+        {if isset($vo.username) and $vo.username eq 'admin'}
+        {else}
+        <div class="layui-form-item">
+            <label class="layui-col-xs2 think-form-label" >选择权限</label>
+            <label class="layui-col-xs10">
+                <select name="authorize" required  id="authorize" lay-verify="required" lay-search>
+                    <option value="">请选择</option>
+                    {foreach $authorizes as $authorize}
+                    {if isset($vo.id) && ($vo.authorize eq $authorize.id)}
+                    <option selected value="{$authorize.id}">{$authorize.title}</option>
+                    {else}
+                    <option value="{$authorize.id}">{$authorize.title}</option>
+                    {/if}
+                    {/foreach}
+                </select>
+            </label>
+        </div>
+        {/if}
+
+    </div>
+
+    <div class="hr-line-dashed"></div>
+    {notempty name='vo.id'}<input type='hidden' value='{$vo.id}' name='id'>{/notempty}
+
+    <div class="layui-form-item text-center">
+        <button class="layui-btn" type='submit' lay-submit style="background: #DC0619">确认</button>
+        <button class="layui-btn layui-btn-danger" type='button' data-confirm="确定要取消吗?" data-close style="background: #BDBDBD">取消</button>
+    </div>
+    <script>
+        layui.form.render();
+    </script>
+</form>

+ 121 - 0
application/admin/view/user/index.html

@@ -0,0 +1,121 @@
+{extend name='main'}
+
+{block name="button"}
+
+{if auth("add")}
+<button data-modal='{:url("add")}' data-title="添加" style="background-color: #DC2219" class='layui-btn layui-btn-sm'>添加</button>
+{/if}
+
+
+{/block}
+
+{block name="content"}
+<style>
+    .invisible {
+        background-image: url('/static/yicang.png');
+        height: .5rem;
+        top: .7rem;
+        display: inline-block;
+        width: 20px;
+        background-size: 100% 100%;
+    }
+
+    .visible {
+        background-image: url('/static/xianshi.png');
+        height: .8rem;
+        top: .55rem;
+        display: inline-block;
+        width: 20px;
+        background-size: 100% 100%;
+    }
+</style>
+<div class="think-box-shadow">
+<!--    {include file='user/index_search'}-->
+    <table class="layui-table margin-top-10">
+        {notempty name='list'}
+        <thead>
+        <tr>
+            <th class='text-center nowrap'>编号</th>
+            <th class='text-center nowrap'>姓名</th>
+            <th class='text-center nowrap'>账号</th>
+            <th class='text-center nowrap'>身份</th>
+            <th class='text-center nowrap'>密码</th>
+            <th class='text-center nowrap'>手机号</th>
+            <th class='text-center nowrap'>使用状态</th>
+            <th class='text-center nowrap'>创建时间</th>
+            <th class='text-center nowrap'>操作</th>
+        </tr>
+        </thead>
+        {/notempty}
+        <tbody>
+        {foreach $list as $key=>$vo}
+        <tr>
+            <td class='text-center nowrap'>{$vo.id|default=''}</td>
+            <td class='text-center nowrap'>{$vo.name|default=''}</td>
+            <td class='text-center nowrap'>{$vo.username|default=''}</td>
+            <td class='text-center nowrap'>{if $vo.id eq '10000'}总管理员{else}{$vo.auth_name}{/if}</td>
+            <td class='text-center nowrap'>
+                        <input type="password" disabled class="password"  id="password_{$vo.id}" maxlength="10" value="{$vo.password1}" style="border: none;text-align: center;background-color: white"/>
+                        <a href="javascript:void(0);" onclick="changepassword('{$vo.id}')" id="passwordeye_{$vo.id}" class="invisible bgImg"></a>
+                </ul>
+            </td>
+            <td class='text-center nowrap'>{$vo.phone|default=''}</td>
+            <td class='text-center nowrap'>{eq name='vo.status' value='0'}<span class="color-red">已禁用</span>{else}<span class="color-green">使用中</span>{/eq}</td>
+            <td class='text-center nowrap'>{$vo.create_at|format_datetime}</td>
+            <td class='text-center nowrap'>
+
+                {if auth("pass")}
+                <a class="layui-btn layui-btn-normal layui-btn-sm" data-title="设置密码" data-modal='{:url("pass")}?id={$vo.id}'>密 码</a>
+                {/if}
+
+                {if auth("edit")}
+                <a data-dbclick class="layui-btn layui-btn-sm" style="background-color: #DC2219" data-title="编辑用户" data-modal='{:url("edit")}?id={$vo.id}'>修 改</a>
+                {/if}
+
+                {if $vo.status eq 1 and auth("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('forbid')}">禁 用</a>
+                {elseif $vo.status eq 0 and auth("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('resume')}">启 用</a>
+                {/if}
+
+                {if auth("remove")}
+                <a class="layui-btn layui-btn-sm layui-btn-danger" style="background-color: #5AD729" data-confirm="确定要删除该用户吗?" data-action="{:url('remove')}" data-value="id#{$vo.id}" data-csrf="{:systoken('remove')}">删 除</a>
+                {/if}
+
+            </td>
+        </tr>
+        {/foreach}
+        </tbody>
+    </table>
+
+    {empty name='list'}<span class="notdata">没有记录哦</span>{else}{$pagehtml|raw|default=''}{/empty}
+
+</div>
+<script>
+
+    function changepassword(id){
+        var passwordeye = $('#passwordeye_'+id);
+        var showPwd = $("#password_"+id);
+        if(passwordeye.hasClass('invisible')){
+            passwordeye.removeClass('invisible').addClass('visible');//密码可见
+            showPwd.prop('type','text');
+        }else{
+            passwordeye.removeClass('visible').addClass('invisible');//密码不可见
+            showPwd.prop('type','password');
+        };
+    }
+
+    // $("#passwordeye").click(function () {
+    //     var passwordeye = $('#passwordeye');
+    //     var showPwd = $("#password");
+    //     if(passwordeye.hasClass('invisible')){
+    //         passwordeye.removeClass('invisible').addClass('visible');//密码可见
+    //         showPwd.prop('type','text');
+    //     }else{
+    //         passwordeye.removeClass('visible').addClass('invisible');//密码不可见
+    //         showPwd.prop('type','password');
+    //     };
+    // })
+
+</script>
+{/block}

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

@@ -0,0 +1,57 @@
+<fieldset>
+
+    <legend>条件搜索</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>

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

@@ -0,0 +1,57 @@
+<form class="layui-form layui-card" action="{:request()->url()}" data-auto="true" method="post" autocomplete="off">
+
+    <div class="layui-card-body padding-left-40">
+
+        <div class="layui-form-item">
+            <label class="relative block">
+                <span class="color-green font-w7">登录用户账号</span>
+                <span class="color-desc margin-left-5">Username</span>
+                <!--{if isset($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}-->
+            </label>
+            <p class="help-block">登录用户账号创建后,不允许再次修改。</p>
+        </div>
+
+        <!--{if $verify}-->
+        <div class="layui-form-item">
+            <label class="relative block">
+                <span class="color-green font-w7">旧的登录密码</span>
+                <span class="color-desc margin-left-5">Old Password</span>
+                <input type="password" autofocus name="oldpassword" value='' pattern="^\S{1,}$" required placeholder="请输入旧的登录密码" class="layui-input">
+            </label>
+            <p class="color-desc">请输入旧密码来验证修改权限,旧密码不限制格式。</p>
+        </div>
+        <!--{/if}-->
+
+        <div class="layui-form-item">
+            <label class="relative block">
+                <span class="color-green font-w7">新的登录密码</span>
+                <span class="color-desc margin-left-5">New Password</span>
+                <input type="password" name="password" maxlength="32" pattern="^(?![\d]+$)(?![a-zA-Z]+$)(?![^\da-zA-Z]+$).{6,32}$" required placeholder="请输入新的登录密码" class="layui-input">
+            </label>
+            <p class="color-desc">密码必需包含大小写字母、数字、符号的任意两者组合。</p>
+        </div>
+
+        <div class="layui-form-item">
+            <label class="relative block">
+                <span class="color-green font-w7">重复登录密码</span>
+                <span class="color-desc margin-left-5">Retype Password</span>
+                <input type="password" name="repassword" maxlength="32" pattern="^(?![\d]+$)(?![a-zA-Z]+$)(?![^\da-zA-Z]+$).{6,32}$" required placeholder="请输入重复登录密码" class="layui-input">
+            </label>
+            <p class="color-desc">密码必需包含大小写字母、数字、符号的任意两者组合。</p>
+        </div>
+
+    </div>
+
+    <div class="hr-line-dashed"></div>
+    {notempty name='vo.id'}<input type='hidden' value='{$vo.id}' name='id'>{/notempty}
+
+    <div class="layui-form-item text-center">
+        <button class="layui-btn" type='submit'>保存数据</button>
+        <button class="layui-btn layui-btn-danger" type='button' data-confirm="确定要取消编辑吗?" data-close>取消编辑</button>
+    </div>
+
+</form>

+ 69 - 0
application/common.php

@@ -0,0 +1,69 @@
+<?php
+function IntToChr($index, $start = 65) {
+    $str = '';
+    if (floor($index / 26) > 0) {
+        $str .= IntToChr(floor($index / 26)-1);
+    }
+    return $str . chr($index % 26 + $start);
+}
+
+/********************php验证身份证号码是否正确函数*********************/
+function is_idcard($id)
+{
+    $id = strtoupper($id);
+    $regx = "/(^\d{15}$)|(^\d{17}([0-9]|X)$)/";
+    $arr_split = array();
+    if(!preg_match($regx, $id))
+    {
+        return FALSE;
+    }
+    if(15==strlen($id)) //检查15位
+    {
+        $regx = "/^(\d{6})+(\d{2})+(\d{2})+(\d{2})+(\d{3})$/";
+
+        @preg_match($regx, $id, $arr_split);
+        //检查生日日期是否正确
+        $dtm_birth = "19".$arr_split[2] . '/' . $arr_split[3]. '/' .$arr_split[4];
+        if(!strtotime($dtm_birth))
+        {
+            return FALSE;
+        } else {
+            return TRUE;
+        }
+    }
+    else      //检查18位
+    {
+        $regx = "/^(\d{6})+(\d{4})+(\d{2})+(\d{2})+(\d{3})([0-9]|X)$/";
+        @preg_match($regx, $id, $arr_split);
+        $dtm_birth = $arr_split[2] . '/' . $arr_split[3]. '/' .$arr_split[4];
+        if(!strtotime($dtm_birth)) //检查生日日期是否正确
+        {
+            return FALSE;
+        }
+        else
+        {
+            //检验18位身份证的校验码是否正确。
+            //校验位按照ISO 7064:1983.MOD 11-2的规定生成,X可以认为是数字10。
+            $arr_int = array(7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2);
+            $arr_ch = array('1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2');
+            $sign = 0;
+            for ( $i = 0; $i < 17; $i++ )
+            {
+                $b = (int) $id{$i};
+                $w = $arr_int[$i];
+                $sign += $b * $w;
+            }
+            $n = $sign % 11;
+            $val_num = $arr_ch[$n];
+            if ($val_num != substr($id,17, 1))
+            {
+                return FALSE;
+            } //phpfensi.com
+            else
+            {
+                return TRUE;
+            }
+        }
+    }
+
+}

+ 53 - 0
application/common/Api/ConfigApi.php

@@ -0,0 +1,53 @@
+<?php
+// +----------------------------------------------------------------------
+// | TwoThink [ WE CAN DO IT JUST THINK ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2013 http://www.twothink.cn All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
+// +----------------------------------------------------------------------
+// | Author: 田建龙 <864491238@qq.com>
+// +----------------------------------------------------------------------
+
+namespace app\common\Api;
+class ConfigApi {
+    /**
+     * 获取数据库中的配置列表
+     * @return array 配置数组
+     */
+    public static function lists(){
+        $map  = array('status' => 1);
+        $data = \think\Db::name('Config')->where($map)->field('type,name,value')->select();
+        
+        $config = array();
+        if($data){
+            foreach ($data as $value) {
+                $config[$value['name']] = self::parse($value['type'], $value['value']);
+            }
+        }
+        return $config;
+    }
+
+    /**
+     * 根据配置类型解析配置
+     * @param  integer $type  配置类型
+     * @param  string  $value 配置值
+     */
+    private static function parse($type, $value){
+        switch ($type) {
+            case 3: //解析数组
+                $array = preg_split('/[,;\r\n]+/', trim($value, ",;\r\n"));
+                if(strpos($value,':')){
+                    $value  = array();
+                    foreach ($array as $val) {
+                        list($k, $v) = explode(':', $val);
+                        $value[$k]   = $v;
+                    }
+                }else{
+                    $value =    $array;
+                }
+                break;
+        }
+        return $value;
+    }	
+}

+ 76 - 0
application/common/behavior/Common.php

@@ -0,0 +1,76 @@
+<?php
+
+namespace app\common\behavior;
+
+use think\Config;
+use think\Lang;
+use think\Loader;
+
+class Common
+{
+
+    public function moduleInit(&$request)
+    {
+        // 设置mbstring字符编码
+        mb_internal_encoding("UTF-8");
+
+        // 如果修改了index.php入口地址,则需要手动修改cdnurl的值
+        $url = preg_replace("/\/(\w+)\.php$/i", '', $request->root());
+        // 如果未设置__CDN__则自动匹配得出
+        if (!Config::get('view_replace_str.__CDN__'))
+        {
+            Config::set('view_replace_str.__CDN__', $url);
+        }
+        // 如果未设置__PUBLIC__则自动匹配得出
+        if (!Config::get('view_replace_str.__PUBLIC__'))
+        {
+            Config::set('view_replace_str.__PUBLIC__', $url . '/');
+        }
+        // 如果未设置__ROOT__则自动匹配得出
+        if (!Config::get('view_replace_str.__ROOT__'))
+        {
+            Config::set('view_replace_str.__ROOT__', preg_replace("/\/public\/$/", '', $url . '/'));
+        }
+        // 如果未设置cdnurl则自动匹配得出
+        if (!Config::get('site.cdnurl'))
+        {
+            Config::set('site.cdnurl', $url);
+        }
+        // 如果未设置cdnurl则自动匹配得出
+        if (!Config::get('upload.cdnurl'))
+        {
+            Config::set('upload.cdnurl', $url);
+        }
+        if (Config::get('app_debug'))
+        {
+            // 如果是调试模式将version置为当前的时间戳可避免缓存
+            Config::set('site.version', time());
+            // 如果是开发模式那么将异常模板修改成官方的
+            Config::set('exception_tmpl', THINK_PATH . 'tpl' . DS . 'think_exception.tpl');
+        }
+        // 如果是trace模式且Ajax的情况下关闭trace
+        if (Config::get('app_trace') && $request->isAjax())
+        {
+            Config::set('app_trace', false);
+        }
+        // 切换多语言
+        if (Config::get('lang_switch_on') && $request->get('lang'))
+        {
+            \think\Cookie::set('think_var', $request->get('lang'));
+        }
+        // Form别名
+        if (!class_exists('Form')) {
+            class_alias('fast\\Form', 'Form');
+        }
+    }
+
+    public function addonBegin(&$request)
+    {
+        // 加载插件语言包
+        Lang::load([
+            APP_PATH . 'common' . DS . 'lang' . DS . $request->langset() . DS . 'addon' . EXT,
+        ]);
+        $this->moduleInit($request);
+    }
+
+}

+ 197 - 0
application/common/controller/Api.php

@@ -0,0 +1,197 @@
+<?php
+
+namespace app\common\controller;
+
+use app\common\library\Common;
+use app\common\model\Config;
+use app\common\model\User;
+use Firebase\JWT\JWT;
+use think\exception\HttpResponseException;
+use think\facade\Request;
+use think\Response;
+
+/**
+ * API控制器基类
+ */
+class Api
+{
+
+    /**
+     * @var Request Request 实例
+     */
+    protected $request;
+
+    /**
+     * @var bool 验证失败是否抛出异常
+     */
+    protected $failException = true;
+
+    /**
+     * 默认响应输出类型,支持json/xml
+     * @var string 
+     */
+    protected $responseType = 'json';
+
+
+    /**
+     * 操作成功返回的数据
+     * @param string $msg   提示信息
+     * @param mixed $data   要返回的数据
+     * @param int   $code   错误码,默认为1
+     * @param string $type  输出类型
+     * @param array $header 发送的 Header 信息
+     */
+    protected function success($msg = '', $data = null , $is_login = 1,$is_disable = 0, $code = 1, $type = null, array $header = [])
+    {
+        $this->result($msg, $data, $is_login,$is_disable, $code, $type, $header);
+    }
+
+    /**
+     * 操作失败返回的数据
+     * @param string $msg   提示信息
+     * @param mixed $data   要返回的数据
+     * @param int   $code   错误码,默认为0
+     * @param string $type  输出类型
+     * @param array $header 发送的 Header 信息
+     */
+    protected function error($msg = '', $data = null, $is_login = 1, $is_disable = 0, $code = 0, $type = null, array $header = [])
+    {
+        $this->result($msg, $data, $is_login, $is_disable, $code, $type, $header);
+    }
+
+    /**
+     * 返回封装后的 API 数据到客户端
+     * @access protected
+     * @param mixed  $msg    提示信息
+     * @param mixed  $data   要返回的数据
+     * @param int    $code   错误码,默认为0
+     * @param string $type   输出类型,支持json/xml/jsonp
+     * @param array  $header 发送的 Header 信息
+     * @return void
+     * @throws HttpResponseException
+     */
+    protected function result($msg, $data = null, $is_login,$is_disable, $code = 0, $type = null, array $header = [])
+    {
+        $result = [
+            'code' => $code,
+            'is_login' => $is_login,
+            'is_disable' => $is_disable,
+            'msg'  => $msg,
+            'time' => Request::instance()->server('REQUEST_TIME'),
+            'data' => $data,
+        ];
+        // 如果未设置类型则自动判断
+        $type = $type ? $type : 'json';
+
+        if (isset($header['statuscode']))
+        {
+            $code = $header['statuscode'];
+            unset($header['statuscode']);
+        }
+        else
+        {
+            //未设置状态码,根据code值判断
+            $code = $code >= 1000 || $code < 200 ? 200 : $code;
+        }
+        $response = Response::create($result, $type, $code)->header($header);
+        throw new HttpResponseException($response);
+    }
+
+    /**
+     * 获取用户信息
+     */
+    protected function check_user(){
+        $token = app()->request->header('Authorization');
+        if (!$token){
+            return false;
+        }else{
+            $user = JWT::decode($token, config('jwt.key'), ['HS256']);
+            if (!$user) {
+                return false;
+            }
+            return $user->id;
+        }
+
+    }
+
+
+
+    /**
+     * 判断登录
+     * @return bool
+     */
+    protected function check_login(){
+        try {
+            $token = app()->request->header('Authorization');
+            if ( ! $token) {
+                $this->error('请先登录', '', 0);
+            }
+            $user = JWT::decode($token, config('jwt.key'), ['HS256']);
+            if ( ! $user) {
+                $this->error('请先登录', '', 0);
+            }
+            $userinfo = User::where('id', $user->id)->find();
+            if (1 != $userinfo['status']) {
+                $this->error('账号被禁用', '', 0);
+            }
+
+            return $user->id;
+        } catch (\UnexpectedValueException $e) {
+            $this->error('请先登录', '', 0);
+        }
+    }
+
+
+    /**
+     * 获取单个配置信息.
+     */
+    public static function getOneValues($config_name)
+    {
+        return Config::where('name', $config_name)->value('value');
+    }
+
+    /**
+     * 获取多个配置信息.
+     */
+    public static function getMoreValues($config_names)
+    {
+        $menus = is_array($config_names) ? implode(',', $config_names) : $config_names;
+        $list = Config::where('name', 'IN', $menus)->column('value', 'name') ?: [];
+        foreach ($list as $menu => $value) {
+            $list[$menu] = $value;
+        }
+
+        return $list;
+    }
+
+
+    /**
+     * 微信文字和图片违规检测
+     */
+    public static function wx_check($param,$type){
+        $appid = Config::get_values('wechat_appid');
+        $secret = Config::get_values('wechat_appsecret');
+        $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={$appid}&secret={$secret}";
+        $result = Common::curlRequest($url);
+        if ($type==1){
+            $url2 = "https://api.weixin.qq.com/wxa/img_sec_check?access_token={$result['access_token']}";
+            $data = ['media'=>$param];
+        }elseif ($type==2){
+            $url2 = "https://api.weixin.qq.com/wxa/msg_sec_check?access_token={$result['access_token']}";
+            $data = ['content'=>$param];
+        }
+        $headers = ['Content-Type:application/json'];
+        $ch = curl_init();
+        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); // 关键点
+        curl_setopt($ch, CURLOPT_URL, $url2);
+        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+        curl_setopt($ch, CURLOPT_POST, 1);
+        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data, JSON_UNESCAPED_UNICODE)); // 【* 关键点】
+        $res = curl_exec($ch);
+        curl_close($ch);
+        $res = json_decode($res,true);
+        return $res;
+    }
+
+
+}

+ 471 - 0
application/common/controller/Backend.php

@@ -0,0 +1,471 @@
+<?php
+
+namespace app\common\controller;
+
+use think\Config;
+use think\Controller;
+use think\Hook;
+use think\Lang;
+use think\Session;
+
+/**
+ * 后台控制器基类
+ */
+class Backend extends Controller
+{
+
+    /**
+     * 无需登录的方法,同时也就不需要鉴权了
+     * @var array
+     */
+    protected $noNeedLogin = [];
+
+    /**
+     * 无需鉴权的方法,但需要登录
+     * @var array
+     */
+    protected $noNeedRight = [];
+
+    /**
+     * 布局模板
+     * @var string
+     */
+    protected $layout = 'default';
+
+    /**
+     * 权限控制类
+     * @var Auth
+     */
+    protected $auth = null;
+
+    /**
+     * 模型对象
+     * @var \think\Model
+     */
+    protected $model = null;
+
+    /**
+     * 快速搜索时执行查找的字段
+     */
+    protected $searchFields = 'id';
+
+    /**
+     * 是否是关联查询
+     */
+    protected $relationSearch = false;
+
+    /**
+     * 是否开启数据限制
+     * 支持auth/personal
+     * 表示按权限判断/仅限个人
+     * 默认为禁用,若启用请务必保证表中存在admin_id字段
+     */
+    protected $dataLimit = false;
+
+    /**
+     * 数据限制字段
+     */
+    protected $dataLimitField = 'admin_id';
+
+    /**
+     * 数据限制开启时自动填充限制字段值
+     */
+    protected $dataLimitFieldAutoFill = true;
+
+    /**
+     * 是否开启Validate验证
+     */
+    protected $modelValidate = false;
+
+    /**
+     * 是否开启模型场景验证
+     */
+    protected $modelSceneValidate = false;
+
+    /**
+     * Multi方法可批量修改的字段
+     */
+    protected $multiFields = 'status';
+
+    /**
+     * Selectpage可显示的字段
+     */
+    protected $selectpageFields = '*';
+
+    /**
+     * 导入文件首行类型
+     * 支持comment/name
+     * 表示注释或字段名
+     */
+    protected $importHeadType = 'comment';
+
+    /**
+     * 引入后台控制器的traits
+     */
+
+    public function _initialize()
+    {
+        $modulename = $this->request->module();
+        $controllername = strtolower($this->request->controller());
+        $actionname = strtolower($this->request->action());
+
+        $path = str_replace('.', '/', $controllername) . '/' . $actionname;
+
+        // 定义是否Addtabs请求
+        !defined('IS_ADDTABS') && define('IS_ADDTABS', input("addtabs") ? TRUE : FALSE);
+
+        // 定义是否Dialog请求
+        !defined('IS_DIALOG') && define('IS_DIALOG', input("dialog") ? TRUE : FALSE);
+
+        // 定义是否AJAX请求
+        !defined('IS_AJAX') && define('IS_AJAX', $this->request->isAjax());
+
+        $this->auth = Auth::instance();
+
+        // 设置当前请求的URI
+        $this->auth->setRequestUri($path);
+        // 检测是否需要验证登录
+        if (!$this->auth->match($this->noNeedLogin)) {
+            //检测是否登录
+            if (!$this->auth->isLogin()) {
+                Hook::listen('admin_nologin', $this);
+                $url = Session::get('referer');
+                $url = $url ? $url : $this->request->url();
+                $this->error(__('Please login first'), url('index/login', ['url' => $url]));
+            }
+            // 判断是否需要验证权限
+            if (!$this->auth->match($this->noNeedRight)) {
+                // 判断控制器和方法判断是否有对应权限
+                if (!$this->auth->check($path)) {
+                    Hook::listen('admin_nopermission', $this);
+                    $this->error(__('You have no permission'), '');
+                }
+            }
+        }
+
+        // 非选项卡时重定向
+        if (!$this->request->isPost() && !IS_AJAX && !IS_ADDTABS && !IS_DIALOG && input("ref") == 'addtabs') {
+            $url = preg_replace_callback("/([\?|&]+)ref=addtabs(&?)/i", function ($matches) {
+                return $matches[2] == '&' ? $matches[1] : '';
+            }, $this->request->url());
+            if (Config::get('url_domain_deploy')) {
+                if (stripos($url, $this->request->server('SCRIPT_NAME')) === 0) {
+                    $url = substr($url, strlen($this->request->server('SCRIPT_NAME')));
+                }
+                $url = url($url, '', false);
+            }
+            $this->redirect('index/index', [], 302, ['referer' => $url]);
+            exit;
+        }
+
+        // 设置面包屑导航数据
+        $breadcrumb = $this->auth->getBreadCrumb($path);
+        array_pop($breadcrumb);
+        $this->view->breadcrumb = $breadcrumb;
+
+        // 如果有使用模板布局
+        if ($this->layout) {
+            $this->view->engine->layout('layout/' . $this->layout);
+        }
+
+        // 语言检测
+        $lang = strip_tags($this->request->langset());
+
+        $site = Config::get("site");
+
+        $upload = \app\common\model\Config::upload();
+
+        // 上传信息配置后
+        Hook::listen("upload_config_init", $upload);
+
+        // 配置信息
+        $config = [
+            'site'           => array_intersect_key($site, array_flip(['name', 'indexurl', 'cdnurl', 'version', 'timezone', 'languages'])),
+            'upload'         => $upload,
+            'modulename'     => $modulename,
+            'controllername' => $controllername,
+            'actionname'     => $actionname,
+            'jsname'         => 'backend/' . str_replace('.', '/', $controllername),
+            'moduleurl'      => rtrim(url("/{$modulename}", '', false), '/'),
+            'language'       => $lang,
+            'fastadmin'      => Config::get('fastadmin'),
+            'referer'        => Session::get("referer")
+        ];
+        $config = array_merge($config, Config::get("view_replace_str"));
+
+        Config::set('upload', array_merge(Config::get('upload'), $upload));
+
+        // 配置信息后
+        Hook::listen("config_init", $config);
+        //加载当前控制器语言包
+        $this->loadlang($controllername);
+        //渲染站点配置
+        $this->assign('site', $site);
+        //渲染配置信息
+        $this->assign('config', $config);
+        //渲染权限对象
+        $this->assign('auth', $this->auth);
+        //渲染管理员对象
+        $this->assign('admin', Session::get('admin'));
+    }
+
+    /**
+     * 加载语言文件
+     * @param string $name
+     */
+    protected function loadlang($name)
+    {
+        Lang::load(APP_PATH . $this->request->module() . '/lang/' . $this->request->langset() . '/' . str_replace('.', '/', $name) . '.php');
+    }
+
+    /**
+     * 渲染配置信息
+     * @param mixed $name 键名或数组
+     * @param mixed $value 值
+     */
+    protected function assignconfig($name, $value = '')
+    {
+        $this->view->config = array_merge($this->view->config ? $this->view->config : [], is_array($name) ? $name : [$name => $value]);
+    }
+
+    /**
+     * 生成查询所需要的条件,排序方式
+     * @param mixed $searchfields 快速查询的字段
+     * @param boolean $relationSearch 是否关联查询
+     * @return array
+     */
+    protected function buildparams($searchfields = null, $relationSearch = null)
+    {
+        $searchfields = is_null($searchfields) ? $this->searchFields : $searchfields;
+        $relationSearch = is_null($relationSearch) ? $this->relationSearch : $relationSearch;
+        $search = $this->request->get("search", '');
+        $filter = $this->request->get("filter", '');
+        $op = $this->request->get("op", '', 'trim');
+        $sort = $this->request->get("sort", "id");
+        $order = $this->request->get("order", "DESC");
+        $offset = $this->request->get("offset", 0);
+        $limit = $this->request->get("limit", 0);
+        $filter = (array)json_decode($filter, TRUE);
+        $op = (array)json_decode($op, TRUE);
+        $filter = $filter ? $filter : [];
+        $where = [];
+        $tableName = '';
+        if ($relationSearch) {
+            if (!empty($this->model)) {
+                $name = \think\Loader::parseName(basename(str_replace('\\', '/', get_class($this->model))));
+                $tableName = $name . '.';
+            }
+            $sortArr = explode(',', $sort);
+            foreach ($sortArr as $index => & $item) {
+                $item = stripos($item, ".") === false ? $tableName . trim($item) : $item;
+            }
+            unset($item);
+            $sort = implode(',', $sortArr);
+        }
+        $adminIds = $this->getDataLimitAdminIds();
+        if (is_array($adminIds)) {
+            $where[] = [$tableName . $this->dataLimitField, 'in', $adminIds];
+        }
+        if ($search) {
+            $searcharr = is_array($searchfields) ? $searchfields : explode(',', $searchfields);
+            foreach ($searcharr as $k => &$v) {
+                $v = stripos($v, ".") === false ? $tableName . $v : $v;
+            }
+            unset($v);
+            $where[] = [implode("|", $searcharr), "LIKE", "%{$search}%"];
+        }
+        foreach ($filter as $k => $v) {
+            $sym = isset($op[$k]) ? $op[$k] : '=';
+            if (stripos($k, ".") === false) {
+                $k = $tableName . $k;
+            }
+            $v = !is_array($v) ? trim($v) : $v;
+            $sym = strtoupper(isset($op[$k]) ? $op[$k] : $sym);
+            switch ($sym) {
+                case '=':
+                case '!=':
+                    $where[] = [$k, $sym, (string)$v];
+                    break;
+                case 'LIKE':
+                case 'NOT LIKE':
+                case 'LIKE %...%':
+                case 'NOT LIKE %...%':
+                    $where[] = [$k, trim(str_replace('%...%', '', $sym)), "%{$v}%"];
+                    break;
+                case '>':
+                case '>=':
+                case '<':
+                case '<=':
+                    $where[] = [$k, $sym, intval($v)];
+                    break;
+                case 'FINDIN':
+                case 'FINDINSET':
+                case 'FIND_IN_SET':
+                    $where[] = "FIND_IN_SET('{$v}', " . ($relationSearch ? $k : '`' . str_replace('.', '`.`', $k) . '`') . ")";
+                    break;
+                case 'IN':
+                case 'IN(...)':
+                case 'NOT IN':
+                case 'NOT IN(...)':
+                    $where[] = [$k, str_replace('(...)', '', $sym), is_array($v) ? $v : explode(',', $v)];
+                    break;
+                case 'BETWEEN':
+                case 'NOT BETWEEN':
+                    $arr = array_slice(explode(',', $v), 0, 2);
+                    if (stripos($v, ',') === false || !array_filter($arr))
+                        continue 2;
+                    //当出现一边为空时改变操作符
+                    if ($arr[0] === '') {
+                        $sym = $sym == 'BETWEEN' ? '<=' : '>';
+                        $arr = $arr[1];
+                    } else if ($arr[1] === '') {
+                        $sym = $sym == 'BETWEEN' ? '>=' : '<';
+                        $arr = $arr[0];
+                    }
+                    $where[] = [$k, $sym, $arr];
+                    break;
+                case 'RANGE':
+                case 'NOT RANGE':
+                    $v = str_replace(' - ', ',', $v);
+                    $arr = array_slice(explode(',', $v), 0, 2);
+                    if (stripos($v, ',') === false || !array_filter($arr))
+                        continue 2;
+                    //当出现一边为空时改变操作符
+                    if ($arr[0] === '') {
+                        $sym = $sym == 'RANGE' ? '<=' : '>';
+                        $arr = $arr[1];
+                    } else if ($arr[1] === '') {
+                        $sym = $sym == 'RANGE' ? '>=' : '<';
+                        $arr = $arr[0];
+                    }
+                    $where[] = [$k, str_replace('RANGE', 'BETWEEN', $sym) . ' time', $arr];
+                    break;
+                case 'LIKE':
+                case 'LIKE %...%':
+                    $where[] = [$k, 'LIKE', "%{$v}%"];
+                    break;
+                case 'NULL':
+                case 'IS NULL':
+                case 'NOT NULL':
+                case 'IS NOT NULL':
+                    $where[] = [$k, strtolower(str_replace('IS ', '', $sym))];
+                    break;
+                default:
+                    break;
+            }
+        }
+        $where = function ($query) use ($where) {
+            foreach ($where as $k => $v) {
+                if (is_array($v)) {
+                    call_user_func_array([$query, 'where'], $v);
+                } else {
+                    $query->where($v);
+                }
+            }
+        };
+        return [$where, $sort, $order, $offset, $limit];
+    }
+
+    /**
+     * 获取数据限制的管理员ID
+     * 禁用数据限制时返回的是null
+     * @return mixed
+     */
+    protected function getDataLimitAdminIds()
+    {
+        if (!$this->dataLimit) {
+            return null;
+        }
+        if ($this->auth->isSuperAdmin()) {
+            return null;
+        }
+        $adminIds = [];
+        if (in_array($this->dataLimit, ['auth', 'personal'])) {
+            $adminIds = $this->dataLimit == 'auth' ? $this->auth->getChildrenAdminIds(true) : [$this->auth->id];
+        }
+        return $adminIds;
+    }
+
+    /**
+     * Selectpage的实现方法
+     *
+     * 当前方法只是一个比较通用的搜索匹配,请按需重载此方法来编写自己的搜索逻辑,$where按自己的需求写即可
+     * 这里示例了所有的参数,所以比较复杂,实现上自己实现只需简单的几行即可
+     *
+     */
+    protected function selectpage()
+    {
+        //设置过滤方法
+        $this->request->filter(['strip_tags', 'htmlspecialchars']);
+
+        //搜索关键词,客户端输入以空格分开,这里接收为数组
+        $word = (array)$this->request->request("q_word/a");
+        //当前页
+        $page = $this->request->request("pageNumber");
+        //分页大小
+        $pagesize = $this->request->request("pageSize");
+        //搜索条件
+        $andor = $this->request->request("andOr", "and", "strtoupper");
+        //排序方式
+        $orderby = (array)$this->request->request("orderBy/a");
+        //显示的字段
+        $field = $this->request->request("showField");
+        //主键
+        $primarykey = $this->request->request("keyField");
+        //主键值
+        $primaryvalue = $this->request->request("keyValue");
+        //搜索字段
+        $searchfield = (array)$this->request->request("searchField/a");
+        //自定义搜索条件
+        $custom = (array)$this->request->request("custom/a");
+        $order = [];
+        foreach ($orderby as $k => $v) {
+            $order[$v[0]] = $v[1];
+        }
+        $field = $field ? $field : 'name';
+
+        //如果有primaryvalue,说明当前是初始化传值
+        if ($primaryvalue !== null) {
+            $where = [$primarykey => ['in', $primaryvalue]];
+        } else {
+            $where = function ($query) use ($word, $andor, $field, $searchfield, $custom) {
+                $logic = $andor == 'AND' ? '&' : '|';
+                $searchfield = is_array($searchfield) ? implode($logic, $searchfield) : $searchfield;
+                foreach ($word as $k => $v) {
+                    $query->where(str_replace(',', $logic, $searchfield), "like", "%{$v}%");
+                }
+                if ($custom && is_array($custom)) {
+                    foreach ($custom as $k => $v) {
+                        $query->where($k, '=', $v);
+                    }
+                }
+            };
+        }
+        $adminIds = $this->getDataLimitAdminIds();
+        if (is_array($adminIds)) {
+            $this->model->where($this->dataLimitField, 'in', $adminIds);
+        }
+        $list = [];
+        $total = $this->model->where($where)->count();
+        if ($total > 0) {
+            if (is_array($adminIds)) {
+                $this->model->where($this->dataLimitField, 'in', $adminIds);
+            }
+            $datalist = $this->model->where($where)
+                ->order($order)
+                ->page($page, $pagesize)
+                ->field($this->selectpageFields)
+                ->select();
+            foreach ($datalist as $index => $item) {
+                unset($item['password'], $item['salt']);
+                $list[] = [
+                    $primarykey => isset($item[$primarykey]) ? $item[$primarykey] : '',
+                    $field      => isset($item[$field]) ? $item[$field] : ''
+                ];
+            }
+        }
+        //这里一定要返回有list这个字段,total是可选的,如果total<=list的数量,则会隐藏分页按钮
+        return json(['list' => $list, 'total' => $total]);
+    }
+
+}

+ 137 - 0
application/common/controller/Frontend.php

@@ -0,0 +1,137 @@
+<?php
+
+namespace app\common\controller;
+
+use app\common\library\Auth;
+use think\Config;
+use think\Controller;
+use think\Hook;
+use think\Lang;
+
+/**
+ * 前台控制器基类
+ */
+class Frontend extends Controller
+{
+
+    /**
+     * 布局模板
+     * @var string
+     */
+    protected $layout = '';
+
+    /**
+     * 无需登录的方法,同时也就不需要鉴权了
+     * @var array
+     */
+    protected $noNeedLogin = [];
+
+    /**
+     * 无需鉴权的方法,但需要登录
+     * @var array
+     */
+    protected $noNeedRight = [];
+
+    /**
+     * 权限Auth
+     * @var Auth
+     */
+    protected $auth = null;
+
+    public function _initialize()
+    {
+        //移除HTML标签
+        $this->request->filter('strip_tags');
+        $modulename = $this->request->module();
+        $controllername = strtolower($this->request->controller());
+        $actionname = strtolower($this->request->action());
+
+        // 如果有使用模板布局
+        if ($this->layout) {
+            $this->view->engine->layout('layout/' . $this->layout);
+        }
+        $this->auth = Auth::instance();
+
+        // token
+        $token = $this->request->server('HTTP_TOKEN', $this->request->request('token', \think\Cookie::get('token')));
+
+        $path = str_replace('.', '/', $controllername) . '/' . $actionname;
+        // 设置当前请求的URI
+        $this->auth->setRequestUri($path);
+        // 检测是否需要验证登录
+        if (!$this->auth->match($this->noNeedLogin)) {
+            //初始化
+            $this->auth->init($token);
+            //检测是否登录
+            if (!$this->auth->isLogin()) {
+                $this->error(__('Please login first'), 'user/login');
+            }
+            // 判断是否需要验证权限
+            if (!$this->auth->match($this->noNeedRight)) {
+                // 判断控制器和方法判断是否有对应权限
+                if (!$this->auth->check($path)) {
+                    $this->error(__('You have no permission'));
+                }
+            }
+        } else {
+            // 如果有传递token才验证是否登录状态
+            if ($token) {
+                $this->auth->init($token);
+            }
+        }
+
+        $this->view->assign('user', $this->auth->getUser());
+
+        // 语言检测
+        $lang = strip_tags($this->request->langset());
+
+        $site = Config::get("site");
+
+        $upload = \app\common\model\Config::upload();
+
+        // 上传信息配置后
+        Hook::listen("upload_config_init", $upload);
+
+        // 配置信息
+        $config = [
+            'site'           => array_intersect_key($site, array_flip(['name', 'cdnurl', 'version', 'timezone', 'languages'])),
+            'upload'         => $upload,
+            'modulename'     => $modulename,
+            'controllername' => $controllername,
+            'actionname'     => $actionname,
+            'jsname'         => 'frontend/' . str_replace('.', '/', $controllername),
+            'moduleurl'      => rtrim(url("/{$modulename}", '', false), '/'),
+            'language'       => $lang
+        ];
+        $config = array_merge($config, Config::get("view_replace_str"));
+
+        Config::set('upload', array_merge(Config::get('upload'), $upload));
+
+        // 配置信息后
+        Hook::listen("config_init", $config);
+        // 加载当前控制器语言包
+        $this->loadlang($controllername);
+        $this->assign('site', $site);
+        $this->assign('config', $config);
+    }
+
+    /**
+     * 加载语言文件
+     * @param string $name
+     */
+    protected function loadlang($name)
+    {
+        Lang::load(APP_PATH . $this->request->module() . '/lang/' . $this->request->langset() . '/' . str_replace('.', '/', $name) . '.php');
+    }
+
+    /**
+     * 渲染配置信息
+     * @param mixed $name 键名或数组
+     * @param mixed $value 值
+     */
+    protected function assignconfig($name, $value = '')
+    {
+        $this->view->config = array_merge($this->view->config ? $this->view->config : [], is_array($name) ? $name : [$name => $value]);
+    }
+
+}

+ 104 - 0
application/common/lang/zh-cn/addon.php

@@ -0,0 +1,104 @@
+<?php
+
+return [
+    'addon %s not found'                          => '插件未找到',
+    'addon %s is disabled'                        => '插件已禁用',
+    'addon controller %s not found'               => '插件控制器未找到',
+    'addon action %s not found'                   => '插件控制器方法未找到',
+    'addon can not be empty'                      => '插件不能为空',
+    'Keep login'                                  => '保持会话',
+    'Forgot password'                             => '忘记密码?',
+    'Sign in'                                     => '登入',
+    'Username'                                    => '用户名',
+    'User id'                                     => '会员ID',
+    'Username'                                    => '用户名',
+    'Nickname'                                    => '昵称',
+    'Password'                                    => '密码',
+    'Sign up'                                     => '注 册',
+    'Sign in'                                     => '登 录',
+    'Sign out'                                    => '注 销',
+    'Guest'                                       => '游客',
+    'Welcome'                                     => '%s,你好!',
+    'Add'                                         => '添加',
+    'Edit'                                        => '编辑',
+    'Delete'                                      => '删除',
+    'Move'                                        => '移动',
+    'Name'                                        => '名称',
+    'Status'                                      => '状态',
+    'Weigh'                                       => '权重',
+    'Operate'                                     => '操作',
+    'Warning'                                     => '温馨提示',
+    'Default'                                     => '默认',
+    'Article'                                     => '文章',
+    'Page'                                        => '单页',
+    'OK'                                          => '确定',
+    'Cancel'                                      => '取消',
+    'Loading'                                     => '加载中',
+    'More'                                        => '更多',
+    'Normal'                                      => '正常',
+    'Hidden'                                      => '隐藏',
+    'Submit'                                      => '提交',
+    'Reset'                                       => '重置',
+    'Execute'                                     => '执行',
+    'Close'                                       => '关闭',
+    'Search'                                      => '搜索',
+    'Refresh'                                     => '刷新',
+    'First'                                       => '首页',
+    'Previous'                                    => '上一页',
+    'Next'                                        => '下一页',
+    'Last'                                        => '末页',
+    'None'                                        => '无',
+    'Home'                                        => '主页',
+    'Online'                                      => '在线',
+    'Logout'                                      => '注销',
+    'Profile'                                     => '个人资料',
+    'Index'                                       => '首页',
+    'Hot'                                         => '热门',
+    'Recommend'                                   => '推荐',
+    'Dashboard'                                   => '控制台',
+    'Code'                                        => '编号',
+    'Message'                                     => '内容',
+    'Line'                                        => '行号',
+    'File'                                        => '文件',
+    'Menu'                                        => '菜单',
+    'Name'                                        => '名称',
+    'Weigh'                                       => '权重',
+    'Type'                                        => '类型',
+    'Title'                                       => '标题',
+    'Content'                                     => '内容',
+    'Status'                                      => '状态',
+    'Operate'                                     => '操作',
+    'Append'                                      => '追加',
+    'Memo'                                        => '备注',
+    'Parent'                                      => '父级',
+    'Params'                                      => '参数',
+    'Permission'                                  => '权限',
+    'Begin time'                                  => '开始时间',
+    'End time'                                    => '结束时间',
+    'Create time'                                 => '创建时间',
+    'Flag'                                        => '标志',
+    'Home'                                        => '首页',
+    'Store'                                       => '插件市场',
+    'Services'                                    => '服务',
+    'Download'                                    => '下载',
+    'Demo'                                        => '演示',
+    'Donation'                                    => '捐赠',
+    'Forum'                                       => '社区',
+    'Docs'                                        => '文档',
+    'Go back'                                     => '返回首页',
+    'Jump now'                                    => '立即跳转',
+    'Please login first'                          => '请登录后再操作',
+    'Send verification code'                      => '发送验证码',
+    'Redirect now'                                => '立即跳转',
+    'Operation completed'                         => '操作成功!',
+    'Operation failed'                            => '操作失败!',
+    'Unknown data format'                         => '未知的数据格式!',
+    'Network error'                               => '网络错误!',
+    'Advanced search'                             => '高级搜索',
+    'Invalid parameters'                          => '未知参数',
+    'No results were found'                       => '记录未找到',
+    'Parameter %s can not be empty'               => '参数%s不能为空',
+    'You have no permission'                      => '你没有权限访问',
+    'An unexpected error occurred'                => '发生了一个意外错误,程序猿正在紧急处理中',
+    'This page will be re-directed in %s seconds' => '页面将在 %s 秒后自动跳转',
+];

+ 141 - 0
application/common/library/AliPay.php

@@ -0,0 +1,141 @@
+<?php
+namespace app\common\library;
+use app\common\model\Config;
+use think\Controller;
+
+class AliPay extends Controller
+{
+    /*
+   配置参数
+   */
+    public function __construct()
+    {
+        $this->appId = Config::get_values('alipay_appid');
+        $this->rsaPrivateKey =  Config::get_values('alipay_rsaPrivateKey');
+        $this->aliPayRsaPublicKey = Config::get_values('alipay_RsaPublicKey');
+    }
+
+    /*
+     * 支付宝支付
+     */
+    public function aliPay($body, $total_amount, $product_code, $notify_url)
+    {
+        /**
+         * 调用支付宝接口。
+         */
+        $isdir = dirname(__DIR__)."/library/";//绝对路径
+        require_once($isdir.'/alipay/aop/AopClient.php');
+        require_once($isdir.'/alipay/aop/request/AlipayTradeAppPayRequest.php');
+        $total_amount = floatval($total_amount);
+        $aop = new AopClient();
+        $aop->gatewayUrl = "https://openapi.alipay.com/gateway.do";
+        $aop->appId = $this->appId;
+        $aop->rsaPrivateKey = $this->rsaPrivateKey;
+        $aop->format = "json";
+        $aop->charset = "UTF-8";
+        $aop->signType = "RSA2";
+        $aop->alipayrsaPublicKey = $this->aliPayRsaPublicKey;
+        $request = new AlipayTradeAppPayRequest();
+        $arr['body'] = $body;
+        $arr['subject'] = $body;
+        $arr['out_trade_no'] = $product_code;
+        $arr['timeout_express'] = '30m';
+        $arr['total_amount'] = $total_amount;
+        $arr['product_code'] = 'QUICK_MSECURITY_PAY';
+        $json = json_encode($arr);
+        $request->setNotifyUrl($notify_url);
+        $request->setBizContent($json);
+        $response = $aop->sdkExecute($request);
+        return $response;
+
+
+    }
+
+    //支付宝退款
+    public function zfbrefund($out_trade_no,$out_refund_no,$total_fee,$refund_reason){
+        $total_fee  = sprintf("%.2f",substr(sprintf("%.4f", $total_fee), 0, -2));
+        $isdir = dirname(__DIR__)."/library/";//绝对路径
+        require_once($isdir.'/alipay/aop/AopClient.php');
+        require_once($isdir.'/alipay/aop/request/AlipayTradeRefundRequest.php');
+        $aop = new AopClient();
+        $aop->gatewayUrl = "https://openapi.alipay.com/gateway.do";
+        $aop->appId = $this->appId;
+        $aop->rsaPrivateKey = $this->rsaPrivateKey;
+        $aop->format = "json";
+        $aop->charset = "UTF-8";
+        $aop->signType = "RSA2";
+        $aop->apiVersion = '1.0';
+//        $aop->alipayrsaPublicKey = $this->aliPayRsaPublicKey;
+        $request = new \AlipayTradeRefundRequest();
+        //$arr['trade_no'] = $out_refund_no;
+        $arr['out_trade_no'] = $out_trade_no;
+        $arr['refund_amount'] = $total_fee;
+        $arr['refund_reason'] = $refund_reason;
+        $arr['refund_currency'] = "CNY";
+        $arr['operator_id'] = "OP001";
+        $arr['store_id'] = "NJ_S_001";
+        $arr['terminal_id'] = "NJ_T_001";
+        $json = json_encode($arr);
+        $request->setBizContent($json);
+        $result = $aop->execute($request);
+        $responseNode = str_replace(".", "_", $request->getApiMethodName()) . "_response";
+        $resultCode = $result->$responseNode->code;
+        return $resultCode;
+    }
+
+
+    //支付宝转账个人账户
+    public function FundTransToaccount($out_trade_no,$account,$account_real_name,$amount,$remark){
+        $amount  = sprintf("%.2f",substr(sprintf("%.4f", $amount), 0, -2));
+        $isdir = dirname(__DIR__)."/library/";//绝对路径
+        require_once($isdir.'/alipay/aop/AopClient.php');
+        $aop = new AopClient();
+        $aop->gatewayUrl = "https://openapi.alipay.com/gateway.do";
+        $aop->appId = $this->appId;
+        $aop->rsaPrivateKey = $this->rsaPrivateKey;
+        $aop->format = 'json';
+        $aop->charset = 'UTF-8';
+        $aop->signType = 'RSA2';
+        //$aop->alipayrsaPublicKey = $this->aliPayRsaPublicKey;
+        require_once($isdir.'/alipay/aop/request/AlipayFundTransToaccountTransferRequest.php');
+        $request = new \AlipayFundTransToaccountTransferRequest();
+        $arr['out_biz_no'] = $out_trade_no;      //订单号
+        $arr['payee_type'] = 'ALIPAY_LOGONID';
+        $arr['payee_account'] = $account;        //对方支付宝账号
+        $arr['payee_real_name'] = $account_real_name;   //支付宝实名姓名
+        $arr['amount']  = $amount;
+        $arr['remark']  = $remark;
+        $json = json_encode($arr,true);
+        $request->setBizContent($json);
+        $result = $aop->execute($request);
+        $responseNode = str_replace(".", "_", $request->getApiMethodName()) . "_response";
+        $resultCode = $result->$responseNode->code;
+        return $resultCode;
+    }
+
+
+    function createLinkstring($para)
+    {
+        $arg = "";
+        while (list ($key, $val) = each($para)) {
+            $arg .= $key . "=" . $val . "&";
+        }
+        //去掉最后一个&字符
+        $arg = substr($arg, 0, count($arg) - 2);
+
+        //如果存在转义字符,那么去掉转义
+        if (get_magic_quotes_gpc()) {
+            $arg = stripslashes($arg);
+        }
+
+        return $arg;
+    }
+
+
+    function argSort($para)
+    {
+        ksort($para);
+        reset($para);
+        return $para;
+    }
+}

+ 613 - 0
application/common/library/Auth.php

@@ -0,0 +1,613 @@
+<?php
+
+namespace app\common\library;
+
+use app\common\model\User;
+use app\common\model\UserRule;
+use fast\Random;
+use think\Config;
+use think\Db;
+use think\Hook;
+use think\Request;
+use think\Validate;
+
+class Auth
+{
+
+    protected static $instance = null;
+    protected $_error = '';
+    protected $_logined = FALSE;
+    protected $_user = NULL;
+    protected $_token = '';
+    //Token默认有效时长
+    protected $keeptime = 2592000;
+    protected $requestUri = '';
+    protected $rules = [];
+    //默认配置
+    protected $config = [];
+    protected $options = [];
+    protected $allowFields = ['id', 'username', 'nickname', 'mobile', 'avatar', 'score','money','city','gender'];
+
+    public function __construct($options = [])
+    {
+        if ($config = Config::get('user'))
+        {
+            $this->config = array_merge($this->config, $config);
+        }
+        $this->options = array_merge($this->config, $options);
+    }
+
+    /**
+     * 
+     * @param array $options 参数
+     * @return Auth
+     */
+    public static function instance($options = [])
+    {
+        if (is_null(self::$instance))
+        {
+            self::$instance = new static($options);
+        }
+
+        return self::$instance;
+    }
+
+    /**
+     * 获取User模型
+     * @return User
+     */
+    public function getUser()
+    {
+        return $this->_user;
+    }
+
+    /**
+     * 兼容调用user模型的属性
+     * 
+     * @param string $name
+     * @return mixed
+     */
+    public function __get($name)
+    {
+        return $this->_user ? $this->_user->$name : NULL;
+    }
+
+    /**
+     * 根据Token初始化
+     *
+     * @param string       $token    Token
+     * @return boolean
+     */
+    public function init($token)
+    {
+        if ($this->_logined)
+        {
+            return TRUE;
+        }
+        if ($this->_error)
+            return FALSE;
+        $data = Token::get($token);
+        if (!$data)
+        {
+            return FALSE;
+        }
+        $user_id = intval($data['user_id']);
+        if ($user_id > 0)
+        {
+            $user = User::get($user_id);
+            if (!$user)
+            {
+                $this->setError('Account not exist');
+                return FALSE;
+            }
+            if ($user['status'] != 'normal')
+            {
+                $this->setError('Account is locked');
+                return FALSE;
+            }
+            $this->_user = $user;
+            $this->_logined = TRUE;
+            $this->_token = $token;
+
+            //初始化成功的事件
+            Hook::listen("user_init_successed", $this->_user);
+
+            return TRUE;
+        }
+        else
+        {
+            $this->setError('You are not logged in');
+            return FALSE;
+        }
+    }
+
+    /**
+     * 注册用户
+     *
+     * @param string $username  用户名
+     * @param string $password  密码
+     * @param string $email     邮箱
+     * @param string $mobile    手机号
+     * @param array $extend    扩展参数
+     * @return boolean
+     */
+    public function register($username, $password, $email = '', $mobile = '', $extend = [])
+    {
+        // 检测用户名或邮箱、手机号是否存在
+        if (User::getByUsername($username))
+        {
+            $this->setError('Username already exist');
+            return FALSE;
+        }
+        if ($email && User::getByEmail($email))
+        {
+            $this->setError('Email already exist');
+            return FALSE;
+        }
+        //if ($mobile && User::getByMobile($mobile))
+        //{
+        //    $this->setError('Mobile already exist');
+        //    return FALSE;
+        //}
+
+        $ip = request()->ip();
+        $time = time();
+
+        $data = [
+            'username' => $username,
+            'password' => $password,
+            'email'    => $email,
+            'mobile'   => $mobile,
+            'level'    => 1,
+            'score'    => 0,
+            'avatar'   => '',
+        ];
+        $params = array_merge($data, [
+            'nickname'  => $username,
+            'salt'      => Random::alnum(),
+            'jointime'  => $time,
+            'joinip'    => $ip,
+            'logintime' => $time,
+            'loginip'   => $ip,
+            'prevtime'  => $time,
+            'status'    => 'normal'
+        ]);
+        $params['password'] = $this->getEncryptPassword($password, $params['salt']);
+        $params = array_merge($params, $extend);
+
+        //账号注册时需要开启事务,避免出现垃圾数据
+        Db::startTrans();
+        try
+        {
+            $user = User::create($params);
+            Db::commit();
+
+            // 此时的Model中只包含部分数据
+            $this->_user = User::get($user->id);
+
+            //设置Token
+            $this->_token = Random::uuid();
+            Token::set($this->_token, $user->id, $this->keeptime);
+
+            //注册成功的事件
+            Hook::listen("user_register_successed", $this->_user);
+
+            return TRUE;
+        }
+        catch (Exception $e)
+        {
+            $this->setError($e->getMessage());
+            Db::rollback();
+            return FALSE;
+        }
+    }
+
+    /**
+     * 用户登录
+     *
+     * @param string    $account    账号,用户名、邮箱、手机号
+     * @param string    $password   密码
+     * @return boolean
+     */
+    public function login($account, $password)
+    {
+        $field = Validate::is($account, 'email') ? 'email' : (Validate::regex($account, '/^1\d{10}$/') ? 'mobile' : 'username');
+        $user = User::get([$field => $account]);
+        if (!$user)
+        {
+            $this->setError('Account is incorrect');
+            return FALSE;
+        }
+
+        if (!empty($user->email_chkcode))
+        {
+            $this->setError('请验证邮箱后登陆');
+            return FALSE;
+        }
+
+        if ($user->status != 'normal')
+        {
+            $this->setError('Account is locked');
+            return FALSE;
+        }
+        if ($user->password != $this->getEncryptPassword($password, $user->salt))
+        {
+            $this->setError('Password is incorrect');
+            return FALSE;
+        }
+
+        //直接登录会员
+        $this->direct($user->id);
+
+        return TRUE;
+    }
+
+    /**
+     * 注销
+     * 
+     * @return boolean
+     */
+    public function logout()
+    {
+        if (!$this->_logined)
+        {
+            $this->setError('You are not logged in');
+            return false;
+        }
+        //设置登录标识
+        $this->_logined = FALSE;
+        //删除Token
+        Token::delete($this->_token);
+        //注销成功的事件
+        Hook::listen("user_logout_successed", $this->_user);
+        return TRUE;
+    }
+
+    /**
+     * 修改密码
+     * @param string    $newpassword        新密码
+     * @param string    $oldpassword        旧密码
+     * @param bool      $ignoreoldpassword  忽略旧密码
+     * @return boolean
+     */
+    public function changepwd($newpassword, $oldpassword = '', $ignoreoldpassword = false)
+    {
+        if (!$this->_logined)
+        {
+            $this->setError('You are not logged in');
+            return false;
+        }
+        //判断旧密码是否正确
+        if ($this->_user->password == $this->getEncryptPassword($oldpassword, $this->_user->salt) || $ignoreoldpassword)
+        {
+            $salt = Random::alnum();
+            $newpassword = $this->getEncryptPassword($newpassword, $salt);
+            $this->_user->save(['password' => $newpassword, 'salt' => $salt]);
+
+            Token::delete($this->_token);
+            //修改密码成功的事件
+            Hook::listen("user_changepwd_successed", $this->_user);
+            return true;
+        }
+        else
+        {
+            $this->setError('Password is incorrect');
+            return false;
+        }
+    }
+
+    /**
+     * 直接登录账号
+     * @param int $user_id
+     * @return boolean
+     */
+    public function direct($user_id)
+    {
+        $user = User::get($user_id);
+        if ($user)
+        {
+            ////////////////同步到Ucenter////////////////
+            if (defined('UC_STATUS') && UC_STATUS)
+            {
+                $uc = new \addons\ucenter\library\client\Client();
+                $re = $uc->uc_user_login($this->user->id, $this->user->password . '#split#' . $this->user->salt, 3);
+                // 如果小于0则说明发生错误
+                if ($re <= 0)
+                {
+                    $this->setError('Username or password is incorrect');
+                    return FALSE;
+                }
+            }
+
+            $ip = request()->ip();
+            $time = time();
+
+            //判断连续登录和最大连续登录
+            if ($user->logintime < \fast\Date::unixtime('day'))
+            {
+                $user->successions = $user->logintime < \fast\Date::unixtime('day', -1) ? 1 : $user->successions + 1;
+                $user->maxsuccessions = max($user->successions, $user->maxsuccessions);
+            }
+
+            $user->prevtime = $user->logintime;
+            //记录本次登录的IP和时间
+            $user->loginip = $ip;
+            $user->logintime = $time;
+
+            $user->save();
+
+            $this->_user = $user;
+
+            $this->_token = Random::uuid();
+            Token::set($this->_token, $user->id, $this->keeptime);
+
+            $this->_logined = TRUE;
+
+            //登录成功的事件
+            Hook::listen("user_login_successed", $this->_user);
+            return TRUE;
+        }
+        else
+        {
+            return FALSE;
+        }
+    }
+
+    /**
+     * 检测是否是否有对应权限
+     * @param string $path      控制器/方法
+     * @param string $module    模块 默认为当前模块
+     * @return boolean
+     */
+    public function check($path = NULL, $module = NULL)
+    {
+        if (!$this->_logined)
+            return false;
+
+        $ruleList = $this->getRuleList();
+        $rules = [];
+        foreach ($ruleList as $k => $v)
+        {
+            $rules[] = $v['name'];
+        }
+        $url = ($module ? $module : request()->module()) . '/' . (is_null($path) ? $this->getRequestUri() : $path);
+        $url = strtolower(str_replace('.', '/', $url));
+        return in_array($url, $rules) ? TRUE : FALSE;
+    }
+
+    /**
+     * 判断是否登录
+     * @return boolean
+     */
+    public function isLogin()
+    {
+        if ($this->_logined)
+        {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * 获取当前Token
+     * @return string
+     */
+    public function getToken()
+    {
+        return $this->_token;
+    }
+
+    /**
+     * 获取会员基本信息
+     */
+    public function getUserinfo()
+    {
+        $data = $this->_user->toArray();
+        $allowFields = $this->getAllowFields();
+        $userinfo = array_intersect_key($data, array_flip($allowFields));
+        $userinfo = array_merge($userinfo, Token::get($this->_token));
+        return $userinfo;
+    }
+
+    /**
+     * 获取会员组别规则列表
+     * @return array
+     */
+    public function getRuleList()
+    {
+        if ($this->rules)
+            return $this->rules;
+        $group = $this->_user->group;
+        if (!$group)
+        {
+            return [];
+        }
+        $rules = explode(',', $group->rules);
+        $this->rules = UserRule::where('status', 'normal')->where('id', 'in', $rules)->field('id,pid,name,title,ismenu')->select();
+        return $this->rules;
+    }
+
+    /**
+     * 获取当前请求的URI
+     * @return string
+     */
+    public function getRequestUri()
+    {
+        return $this->requestUri;
+    }
+
+    /**
+     * 设置当前请求的URI
+     * @param string $uri
+     */
+    public function setRequestUri($uri)
+    {
+        $this->requestUri = $uri;
+    }
+
+    /**
+     * 获取允许输出的字段
+     * @return array
+     */
+    public function getAllowFields()
+    {
+        return $this->allowFields;
+    }
+
+    /**
+     * 设置允许输出的字段
+     * @param array $fields
+     */
+    public function setAllowFields($fields)
+    {
+        $this->allowFields = $fields;
+    }
+
+    /**
+     * 删除一个指定会员
+     * @param int $user_id 会员ID
+     * @return boolean
+     */
+    public function delete($user_id)
+    {
+        $user = User::get($user_id);
+        if (!$user)
+        {
+            return FALSE;
+        }
+
+        ////////////////同步到Ucenter////////////////
+        if (defined('UC_STATUS') && UC_STATUS)
+        {
+            $uc = new \addons\ucenter\library\client\Client();
+            $re = $uc->uc_user_delete($user['id']);
+            // 如果小于0则说明发生错误
+            if ($re <= 0)
+            {
+                $this->setError('Account is locked');
+                return FALSE;
+            }
+        }
+
+        // 调用事务删除账号
+        $result = Db::transaction(function($db) use($user_id) {
+                    // 删除会员
+                    User::destroy($user_id);
+                    // 删除会员指定的所有Token
+                    Token::clear($user_id);
+                    return TRUE;
+                });
+        if ($result)
+        {
+            Hook::listen("user_delete_successed", $user);
+        }
+        return $result ? TRUE : FALSE;
+    }
+
+    /**
+     * 获取密码加密后的字符串
+     * @param string $password  密码
+     * @param string $salt      密码盐
+     * @return string
+     */
+    public function getEncryptPassword($password, $salt = '')
+    {
+        return md5(md5($password) . $salt);
+    }
+
+    /**
+     * 检测当前控制器和方法是否匹配传递的数组
+     *
+     * @param array $arr 需要验证权限的数组
+     * @return boolean
+     */
+    public function match($arr = [])
+    {
+        $request = Request::instance();
+        $arr = is_array($arr) ? $arr : explode(',', $arr);
+        if (!$arr)
+        {
+            return FALSE;
+        }
+        $arr = array_map('strtolower', $arr);
+        // 是否存在
+        if (in_array(strtolower($request->action()), $arr) || in_array('*', $arr))
+        {
+            return TRUE;
+        }
+
+        // 没找到匹配
+        return FALSE;
+    }
+
+    /**
+     * 设置会话有效时间
+     * @param int $keeptime 默认为永久
+     */
+    public function keeptime($keeptime = 0)
+    {
+        $this->keeptime = $keeptime;
+    }
+
+    /**
+     * 渲染用户数据
+     * @param array     $datalist   二维数组
+     * @param mixed     $fields     加载的字段列表
+     * @param string    $fieldkey   渲染的字段
+     * @param string    $renderkey  结果字段
+     * @return array
+     */
+    public function render(&$datalist, $fields = [], $fieldkey = 'user_id', $renderkey = 'userinfo')
+    {
+        $fields = !$fields ? ['id', 'nickname', 'level', 'avatar'] : (is_array($fields) ? $fields : explode(',', $fields));
+        $ids = [];
+        foreach ($datalist as $k => $v)
+        {
+            if (!isset($v[$fieldkey]))
+                continue;
+            $ids[] = $v[$fieldkey];
+        }
+        $list = [];
+        if ($ids)
+        {
+            if (!in_array('id', $fields))
+            {
+                $fields[] = 'id';
+            }
+            $ids = array_unique($ids);
+            $selectlist = User::where('id', 'in', $ids)->column($fields);
+            foreach ($selectlist as $k => $v)
+            {
+                $list[$v['id']] = $v;
+            }
+        }
+        foreach ($datalist as $k => &$v)
+        {
+            $v[$renderkey] = isset($list[$v[$fieldkey]]) ? $list[$v[$fieldkey]] : NULL;
+        }
+        unset($v);
+        return $datalist;
+    }
+
+    /**
+     * 设置错误信息
+     *
+     * @param $error 错误信息
+     * @return Auth
+     */
+    public function setError($error)
+    {
+        $this->_error = $error;
+        return $this;
+    }
+
+    /**
+     * 获取错误信息
+     * @return string
+     */
+    public function getError()
+    {
+        return $this->_error ? __($this->_error) : '';
+    }
+
+}

+ 553 - 0
application/common/library/Common.php

@@ -0,0 +1,553 @@
+<?php
+
+namespace app\common\library;
+
+use app\common\model\Config;
+use app\common\model\OrderStatus;
+use app\common\model\User;
+use think\Cache;
+use think\Hook;
+use think\Request;
+use app\common\library\QRcode;
+
+/**
+ * 公共类
+ */
+class Common
+{
+
+
+    public static function httpcurl($url, $type = 'get', $res = 'json', $arr = '')
+    {
+        //1.初始化curl
+        $ch = curl_init();
+        //2.设置curl的参数
+        curl_setopt($ch, CURLOPT_URL, $url);
+        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); //不验证证书
+        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); //不验证证书
+        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+        if ($type == 'post') {
+            curl_setopt($ch, CURLOPT_POST, 1);
+            curl_setopt($ch, CURLOPT_POSTFIELDS, $arr);
+        }
+        //3.采集
+        $output = curl_exec($ch);
+        //4.关闭
+        curl_close($ch);
+        if ($res == 'json') {
+            return json_decode($output, true);
+        }
+    }
+
+
+
+    /**
+     * curl 请求
+     * @param $url string 请求地址
+     * @param $headers json 请求头
+     * @param $body json 请求体
+     * @return mixed
+     */
+    public static function curlRequest($url, $headers = [], $body = [], $method = "GET")
+    {
+        $ch = curl_init();
+        curl_setopt($ch, CURLOPT_URL, $url);
+        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);//设置请求头
+        curl_setopt($ch, CURLOPT_POSTFIELDS, $body);//设置请求体
+        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method); //定义请求类型
+        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
+        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
+        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+        curl_setopt($ch, CURLOPT_HTTP_VERSION, 'CURL_HTTP_VERSION_1_1');
+        $output = curl_exec($ch);
+        curl_close($ch);
+        $arr = json_decode($output, true);
+        return $arr;
+    }
+
+    public static function http_curl($url, $type = 'get', $res = 'json', $arr = '')
+    {
+        //1.初始化curl
+        $ch = curl_init();
+        //2.设置curl的参数
+        curl_setopt($ch, CURLOPT_URL, $url);
+        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); //不验证证书
+        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); //不验证证书
+        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+        if ($type == 'post') {
+            curl_setopt($ch, CURLOPT_POST, 1);
+            curl_setopt($ch, CURLOPT_POSTFIELDS, $arr);
+        }
+        //3.采集
+        $output = curl_exec($ch);
+        //4.关闭
+        curl_close($ch);
+        if ($res == 'json') {
+            return json_decode($output, true);
+        }
+    }
+    /**
+     * 成功
+     * @param $msg
+     * @return array
+     */
+    public static function return_success($msg,$data = null){
+        $result = [
+            'code' => 1,
+            'msg'  => $msg,
+            'data' =>$data
+        ];
+        return $result;
+        die;
+    }
+
+    /**
+     * 失败
+     * @param $msg
+     * @return array
+     */
+    public static function return_error($msg,$data = null){
+        $result = [
+            'code' => 0,
+            'msg'  => $msg,
+            'data' => $data
+        ];
+        return $result;
+        die;
+    }
+
+
+    public static function get_ffid($invite_code){
+        $f = \app\common\model\User::where('id',$invite_code)->field('fid')->find();
+        if ($f)
+            return $f->fid;
+        else
+            return 0;
+    }
+
+
+    /**
+     * 生成二维码
+     */
+    public static function generate_qrcode($value){
+        $dir = dirname(realpath(dirname($_SERVER['SCRIPT_FILENAME']))) . '/public/verify';
+        if(!file_exists($dir)){
+            //检查是否有该文件夹,如果没有就创建,并给予最高权限
+            mkdir($dir, 0700,true);
+        }
+        $filename = $dir.'/'.$value.'.png';
+        QRcode::png($value,$filename);
+        return 'http://'.$_SERVER['SERVER_NAME']."/verify/".$value.'.png';
+    }
+
+
+    /**
+     * 订单操作记录
+     * @param int $change_message    操作备注
+     * @param int $oid  订单id
+     */
+    public static function order_status($oid, $change_message)
+    {
+        OrderStatus::create(['oid' => $oid,'change_message' => $change_message, 'change_time' => time()]);
+    }
+
+
+    /**
+     * 判断金额在哪个区间
+     */
+    public static function checkMoneyGrade($money){
+        if ($money<50000){
+            return false;
+        }elseif ($money>=50000 && $money<150000){
+            return 50000;
+        }elseif ($money>=150000 && $money<450000){
+            return 150000;
+        }elseif ($money>=450000 && $money<1350000){
+            return 450000;
+        }elseif ($money>=1350000 && $money<4000000){
+            return 1350000;
+        }elseif ($money>=4000000 && $money<12000000){
+            return 4000000;
+        }elseif ($money>=12000000 && $money<36000000){
+            return 12000000;
+        }elseif ($money>=36000000 && $money<100000000){
+            return 36000000;
+        }elseif ($money>=100000000 && $money<300000000){
+            return 100000000;
+        }elseif ($money>=300000000 && $money<600000000){
+            return 300000000;
+        }elseif ($money>=600000000){
+            return 600000000;
+        }
+    }
+
+
+    /**
+     * 生成订单唯一id
+     * $user_id  用户id
+     * @return string
+     */
+    public static function getNewOrderId($user_id)
+    {
+        $str = date('Ymd').$user_id.substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);
+        return $str;
+    }
+
+
+
+    /**
+     * 身份证验证
+     * @param $card
+     * @return bool
+     */
+    public static function setCard($card){
+        $city = [11=>"北京",12=>"天津",13=>"河北",14=>"山西",15=>"内蒙古",21=>"辽宁",22=>"吉林",23=>"黑龙江 ",31=>"上海",32=>"江苏",33=>"浙江",34=>"安徽",35=>"福建",36=>"江西",37=>"山东",41=>"河南",42=>"湖北 ",43=>"湖南",44=>"广东",45=>"广西",46=>"海南",50=>"重庆",51=>"四川",52=>"贵州",53=>"云南",54=>"西藏 ",61=>"陕西",62=>"甘肃",63=>"青海",64=>"宁夏",65=>"新疆",71=>"台湾",81=>"香港",82=>"澳门",91=>"国外 "];
+        $tip = "";
+        $match = "/^\d{6}(18|19|20)?\d{2}(0[1-9]|1[012])(0[1-9]|[12]\d|3[01])\d{3}(\d|X)$/";
+        $pass= true;
+        if(!$card || !preg_match($match,$card)){
+            //身份证格式错误
+            $pass = false;
+        }else if(!$city[substr($card,0,2)]){
+            //地址错误
+            $pass = false;
+        }else{
+            //18位身份证需要验证最后一位校验位
+            if(strlen($card) == 18){
+                $card = str_split($card);
+                //∑(ai×Wi)(mod 11)
+                //加权因子
+                $factor = [ 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2 ];
+                //校验位
+                $parity = [ 1, 0, 'X', 9, 8, 7, 6, 5, 4, 3, 2 ];
+                $sum = 0;
+                $ai = 0;
+                $wi = 0;
+                for ($i = 0; $i < 17; $i++)
+                {
+                    $ai = $card[$i];
+                    $wi = $factor[$i];
+                    $sum += $ai * $wi;
+                }
+                $last = $parity[$sum % 11];
+                if($parity[$sum % 11] != $card[17]){
+                    $pass =false;
+                }
+            }else{
+                $pass =false;
+            }
+        }
+        if(!$pass) return false;/* 身份证格式错误*/
+        return true;/* 身份证格式正确*/
+    }
+
+
+    /**
+     * 获取当前的经纬度
+     */
+    public static function get_ipjwd(){
+        $ip = request()->ip();
+        //获取百度地图apikey
+        $api_key = Config::get_values('baidu_api_server');
+        if ($ip=='127.0.0.1') {//如果获取到的ip为127.0.0.1 会报错  在这随便给一个ip
+            $ip='58.30.228.35';
+        }
+        $content = file_get_contents("http://api.map.baidu.com/location/ip?ak=$api_key&ip={$ip}&coor=bd09ll");
+        $json = json_decode($content);
+        $data=array();
+        $data['log']=$json->{'content'}->{'point'}->{'x'};//按层级关系提取经度数据
+        $data['lat']=$json->{'content'}->{'point'}->{'y'};//按层级关系提取纬度数据
+        $data['address']=$json->{'content'}->{'address'};//按层级关系提取address数据
+        return $data;
+    }
+
+
+    /**
+     * 计算距离
+     * 1.纬度1,经度1,纬度2,经度2
+     * 2.返回结果是单位是KM。
+     * 3.保留一位小数
+    */
+    public static function getDistance($lat2,$lng2,$lat1,$lng1)
+    {
+        if (!$lat2 || !$lng2 || !$lat1 || !$lng1){
+            return 0;
+        }
+
+
+        //将角度转为狐度
+        $radLat1 = deg2rad($lat1);//deg2rad()函数将角度转换为弧度
+        $radLat2 = deg2rad($lat2);
+        $radLng1 = deg2rad($lng1);
+        $radLng2 = deg2rad($lng2);
+        $a = $radLat1 - $radLat2;
+        $b = $radLng1 - $radLng2;
+        $s = 2*asin(sqrt(pow(sin($a/2),2)+cos($radLat1)*cos($radLat2)*pow(sin($b/2),2)))*6371;
+        return round($s,1);
+    }
+
+
+    /**
+     * Notes: 根据传送过来的时间戳判断时间是多久前
+     * @param $the_time 时间戳 (亦可为日期格式,转换好就行)
+     */
+    public static function timeTran($time)
+    {
+        $nowTime = time();
+        $showTime = strtotime($time);
+        $difference = $nowTime - $showTime;
+        if ($difference < 0) {
+            return $time;
+        }
+        if ($difference < 60) {
+            return $difference . '秒前';
+        }
+        if ($difference < 3600) {
+            return floor($difference / 60).'分钟前';
+        }
+        if ($difference < 86400) {
+            return floor($difference / 3600).'小时前';
+        }
+        if ($difference < 2592000)  {
+            return floor($difference / 86400) . '天前'; //30天内
+        }
+        if ($difference < 31104000) {
+            return floor($difference / 2592000) . '个月前'; //12个月内
+        }
+        return floor($difference / 31536000) . '年前';
+    }
+
+
+    /**
+     * Notes: 根据传送过来的时间戳判断时间剩几天
+     * @param $the_time 时间戳 (亦可为日期格式,转换好就行)
+     */
+    public static function timeTranRun($time)
+    {
+        $now = date('Y-m-d H:i:s');
+        $date=floor((strtotime($time)-strtotime($now))/86400);
+        if ($date==0){
+            $hour=floor((strtotime($time)-strtotime($now))%86400/3600);
+            if ($hour==0){
+                $minute=floor((strtotime($time)-strtotime($now))%86400/60);
+                if ($minute==0){
+                    $second=floor((strtotime($time)-strtotime($now))%86400%60);
+                    return $second.'秒后';
+                }else{
+                    return $minute.'分钟后';
+                }
+            }else{
+                return $hour.'小时后';
+            }
+        }else{
+            return $date.'天后';
+        }
+    }
+
+    /**
+     * Notes: 根据传送过来的时间戳
+     * @param $the_time 时间戳 (亦可为日期格式,转换好就行)
+     */
+    public static function timeTranRun2($time)
+    {
+        //计算两个日期之间的时间差
+        $diff = abs(strtotime($time) - time());
+
+        //转换时间差的格式
+        $years = floor($diff/(365*60*60*24));
+
+        $months = floor(($diff - $years * 365*60*60*24)  / (30*60*60*24));
+
+        $days = floor(($diff - $years * 365*60*60*24 -  $months*30*60*60*24)/ (60*60*24));
+
+        $hours = floor(($diff - $years * 365*60*60*24   - $months*30*60*60*24 - $days*60*60*24)  / (60*60));
+
+        $minutes = floor(($diff - $years * 365*60*60*24  - $months*30*60*60*24 - $days*60*60*24  - $hours*60*60)/ 60);
+        $seconds = floor(($diff - $years * 365*60*60*24  - $months*30*60*60*24 - $days*60*60*24  - $hours*60*60 - $minutes*60));
+        $array['date'] = $days;
+        $array['hour'] = $hours;
+        $array['minute'] = $minutes;
+        $array['seconds'] = $seconds;
+        return $array;
+    }
+
+
+    /**
+     * 公众号推送消息
+     */
+    public static function sendTemplateMsg($openid,$template_id,$path,$data){
+        $appid = Config::get_values('wechat_appid');
+        $appsecret = Config::get_values('wechat_appsecret');
+        $url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=' . $appid . '&secret=' . $appsecret;
+        $res = json_decode(file_get_contents($url),true);
+        $access_token = $res['access_token'];
+        //请求url
+        $url='https://api.weixin.qq.com/cgi-bin/message/wxopen/template/uniform_send?access_token='.$access_token;
+        $arr=[
+            'touser'=>$openid,
+            'mp_template_msg'=>[
+                "appid"=>"wxad3ed96c8ce52359",
+                "template_id"=>$template_id,
+                "url"=>$path,
+                'miniprogram'=>[
+                    "appid"=>Config::get_values('wechat_appid')
+                ],
+                'data'=>$data
+            ],
+        ];
+
+        //将数组->json
+        $postJson = json_encode($arr,JSON_UNESCAPED_UNICODE) ;
+        $res = self::curlPost($url,$postJson);
+        $result = json_decode($res, true);
+        return $result;
+    }
+
+
+
+    /**
+     * 订阅消息发送
+     */
+    public function sendMessage($data){
+        $appid = Config::get_values('wechat_appid');
+        $appsecret = Config::get_values('wechat_appsecret');
+        $url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=' . $appid . '&secret=' . $appsecret;
+        $res = json_decode(file_get_contents($url),true);
+        $access_token = $res['access_token'] ;
+        //请求url
+        $url = 'https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=' . $access_token ;
+        self::curlPost($url,json_encode($data));
+    }
+
+    //发送post请求
+    static function curlPost($url,$data)
+    {
+        $ch = curl_init();
+        $params[CURLOPT_URL] = $url;    //请求url地址
+        $params[CURLOPT_HEADER] = FALSE; //是否返回响应头信息
+        $params[CURLOPT_SSL_VERIFYPEER] = false;
+        $params[CURLOPT_SSL_VERIFYHOST] = false;
+        $params[CURLOPT_RETURNTRANSFER] = true; //是否将结果返回
+        $params[CURLOPT_POST] = true;
+        $params[CURLOPT_POSTFIELDS] = $data;
+        curl_setopt_array($ch, $params); //传入curl参数
+        $content = curl_exec($ch); //执行
+        curl_close($ch); //关闭连接
+        return $content;
+    }
+
+
+    /**
+     * 获取token
+     */
+    static function getToken(){
+        $token = cache('hx_token');
+        if (!$token){
+            $data = array(
+                "grant_type" => "client_credentials",
+                "client_id" => 'YXA6Uqa7s6m-Q2C50FPfWBUCcg',
+                "client_secret" => 'YXA6xidhOogqAOxu0HLQjNIBoXTSUwE'
+            );
+            $url = "https://a1.easemob.com/1101210401193729/demo/token";
+            $rs = json_decode(self::curl($url, $data), true);
+            cache('hx_token',$rs['access_token'],$rs['expires_in']-1500);
+            $token = $rs['access_token'];
+        }
+        return $token;
+    }
+
+
+    /**
+     * 环信注册
+     */
+    static function huanxin_zhuce($username,$nickname){
+        $param = array (
+            "username" => $username,
+            "password" => '12345678',
+            "nickname" => $nickname
+        );
+        // $url = "https://a1.easemob.com/".huanxin_get_org_name()."/".huanxin_get_app_name()."/users";
+        $url = "https://a1.easemob.com/1101210401193729/demo/users";
+        $res = self::huanxin_curl_request($url, json_encode($param));
+        $tokenResult =  json_decode($res, true);
+    }
+
+    /**
+     * 好友列表
+     */
+    static function friend_list($owner_username){
+        $param = array ();
+        $header = array(
+            'Authorization: Bearer '.self::getToken()
+        );
+        $url = "https://a1.easemob.com/1101210401193729/demo/users/".$owner_username."/contacts/users";
+        $res = self::huanxin_curl_request($url,$param,$header,'GET');
+        $Result =  json_decode($res, true);
+        return $Result['data'];
+    }
+
+    static function huanxin_curl_request($url, $body, $header = array(), $method = "POST") {
+        array_push ( $header, 'Accept:application/json' );
+        array_push ( $header, 'Content-Type:application/json' );
+        $ch = curl_init ();
+        curl_setopt ( $ch, CURLOPT_CONNECTTIMEOUT, 60 );
+        curl_setopt ( $ch, CURLOPT_URL, $url );
+        curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, 1 );
+        // curl_setopt($ch, $method, 1);
+
+        switch (strtoupper($method)) {
+            case "GET" :
+                curl_setopt ( $ch, CURLOPT_HTTPGET, true );
+                break;
+            case "POST" :
+                curl_setopt ( $ch, CURLOPT_POST, true );
+                break;
+            case "PUT" :
+                curl_setopt ( $ch, CURLOPT_CUSTOMREQUEST, "PUT" );
+                break;
+            case "DELETE" :
+                curl_setopt ( $ch, CURLOPT_CUSTOMREQUEST, "DELETE" );
+                break;
+        }
+
+        curl_setopt ( $ch, CURLOPT_USERAGENT, 'SSTS Browser/1.0' );
+        curl_setopt ( $ch, CURLOPT_ENCODING, 'gzip' );
+        curl_setopt ( $ch, CURLOPT_SSL_VERIFYPEER, FALSE );
+        curl_setopt ( $ch, CURLOPT_SSL_VERIFYHOST, 2 );
+        if (isset ( $body {3} ) > 0) {
+            curl_setopt ( $ch, CURLOPT_POSTFIELDS, $body );
+        }
+        if (count ( $header ) > 0) {
+            curl_setopt ( $ch, CURLOPT_HTTPHEADER, $header );
+        }
+        $ret = curl_exec ( $ch );
+        $err = curl_error ( $ch );
+        curl_close ( $ch );
+        if ($err) {
+            return $err;
+        }
+        return $ret;
+    }
+
+
+    static function curl($url, $data, $header = false, $method = "POST")
+    {
+        $ch = curl_init($url);
+        curl_setopt($ch, CURLOPT_URL, $url);
+        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+        if ($header) {
+            curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
+        }
+        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
+        if ($data) {
+            curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
+        }
+        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
+        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
+        $ret = curl_exec($ch);
+        return $ret;
+    }
+
+
+
+}

+ 144 - 0
application/common/library/Menu.php

@@ -0,0 +1,144 @@
+<?php
+
+namespace app\common\library;
+
+use app\admin\model\AuthRule;
+use fast\Tree;
+use think\Exception;
+use think\exception\PDOException;
+
+class Menu
+{
+
+    /**
+     * 创建菜单
+     * @param array $menu
+     * @param mixed $parent 父类的name或pid
+     */
+    public static function create($menu, $parent = 0)
+    {
+        if (!is_numeric($parent))
+        {
+            $parentRule = AuthRule::getByName($parent);
+            $pid = $parentRule ? $parentRule['id'] : 0;
+        }
+        else
+        {
+            $pid = $parent;
+        }
+        $allow = array_flip(['file', 'name', 'title', 'icon', 'condition', 'remark', 'ismenu']);
+        foreach ($menu as $k => $v)
+        {
+            $hasChild = isset($v['sublist']) && $v['sublist'] ? true : false;
+
+            $data = array_intersect_key($v, $allow);
+
+            $data['ismenu'] = isset($data['ismenu']) ? $data['ismenu'] : ($hasChild ? 1 : 0);
+            $data['icon'] = isset($data['icon']) ? $data['icon'] : ($hasChild ? 'fa fa-list' : 'fa fa-circle-o');
+            $data['pid'] = $pid;
+            $data['status'] = 'normal';
+            try
+            {
+                $menu = AuthRule::create($data);
+                if ($hasChild)
+                {
+                    self::create($v['sublist'], $menu->id);
+                }
+            }
+            catch (PDOException $e)
+            {
+                throw new Exception($e->getMessage());
+            }
+        }
+    }
+
+    /**
+     * 删除菜单
+     * @param string $name 规则name 
+     * @return boolean
+     */
+    public static function delete($name)
+    {
+        $ids = self::getAuthRuleIdsByName($name);
+        if (!$ids)
+        {
+            return false;
+        }
+        AuthRule::destroy($ids);
+        return true;
+    }
+
+    /**
+     * 启用菜单
+     * @param string $name
+     * @return boolean
+     */
+    public static function enable($name)
+    {
+        $ids = self::getAuthRuleIdsByName($name);
+        if (!$ids)
+        {
+            return false;
+        }
+        AuthRule::where('id', 'in', $ids)->update(['status' => 'normal']);
+        return true;
+    }
+
+    /**
+     * 禁用菜单
+     * @param string $name
+     * @return boolean
+     */
+    public static function disable($name)
+    {
+        $ids = self::getAuthRuleIdsByName($name);
+        if (!$ids)
+        {
+            return false;
+        }
+        AuthRule::where('id', 'in', $ids)->update(['status' => 'hidden']);
+        return true;
+    }
+
+    /**
+     * 导出指定名称的菜单规则
+     * @param string $name
+     * @return array
+     */
+    public static function export($name)
+    {
+        $ids = self::getAuthRuleIdsByName($name);
+        if (!$ids)
+        {
+            return [];
+        }
+        $menuList = [];
+        $menu = AuthRule::getByName($name);
+        if ($menu)
+        {
+            $ruleList = collection(AuthRule::where('id', 'in', $ids)->select())->toArray();
+            $menuList = Tree::instance()->init($ruleList)->getTreeArray($menu['id']);
+        }
+        return $menuList;
+    }
+
+    /**
+     * 根据名称获取规则IDS
+     * @param string $name
+     * @return array
+     */
+    public static function getAuthRuleIdsByName($name)
+    {
+        $ids = [];
+        $menu = AuthRule::getByName($name);
+        if ($menu)
+        {
+            // 必须将结果集转换为数组
+            $ruleList = collection(AuthRule::order('weigh', 'desc')->field('id,pid,name')->select())->toArray();
+            // 构造菜单数据
+            $ids = Tree::instance()->init($ruleList)->getChildrenIds($menu['id'], true);
+        }
+        return $ids;
+    }
+
+}

+ 158 - 0
application/common/library/Token.php

@@ -0,0 +1,158 @@
+<?php
+
+namespace app\common\library;
+
+use app\common\library\token\Driver;
+use think\App;
+use think\Config;
+use think\Log;
+
+/**
+ * Token操作类
+ */
+class Token
+{
+    /**
+     * @var array Token的实例
+     */
+    public static $instance = [];
+
+    /**
+     * @var object 操作句柄
+     */
+    public static $handler;
+
+    /**
+     * 连接Token驱动
+     * @access public
+     * @param  array $options 配置数组
+     * @param  bool|string $name Token连接标识 true 强制重新连接
+     * @return Driver
+     */
+    public static function connect(array $options = [], $name = false)
+    {
+        $type = !empty($options['type']) ? $options['type'] : 'File';
+
+        if (false === $name) {
+            $name = md5(serialize($options));
+        }
+
+        if (true === $name || !isset(self::$instance[$name])) {
+            $class = false === strpos($type, '\\') ?
+                '\\app\\common\\library\\token\\driver\\' . ucwords($type) :
+                $type;
+
+            // 记录初始化信息
+            App::$debug && Log::record('[ TOKEN ] INIT ' . $type, 'info');
+
+            if (true === $name) {
+                return new $class($options);
+            }
+
+            self::$instance[$name] = new $class($options);
+        }
+
+        return self::$instance[$name];
+    }
+
+    /**
+     * 自动初始化Token
+     * @access public
+     * @param  array $options 配置数组
+     * @return Driver
+     */
+    public static function init(array $options = [])
+    {
+        if (is_null(self::$handler)) {
+            if (empty($options) && 'complex' == Config::get('token.type')) {
+                $default = Config::get('token.default');
+                // 获取默认Token配置,并连接
+                $options = Config::get('token.' . $default['type']) ?: $default;
+            } elseif (empty($options)) {
+                $options = Config::get('token');
+            }
+            self::$handler = self::connect($options);
+        }
+
+        return self::$handler;
+    }
+
+    /**
+     * 判断Token是否可用(check别名)
+     * @access public
+     * @param  string $token Token标识
+     * @return bool
+     */
+    public static function has($token, $user_id)
+    {
+        return self::check($token, $user_id);
+    }
+
+    /**
+     * 判断Token是否可用
+     * @param string $token Token标识
+     * @return bool
+     */
+    public static function check($token, $user_id)
+    {
+        return self::init()->check($token, $user_id);
+    }
+
+    /**
+     * 读取Token
+     * @access public
+     * @param  string $token Token标识
+     * @param  mixed $default 默认值
+     * @return mixed
+     */
+    public static function get($token, $default = false)
+    {
+        return self::init()->get($token, $default);
+    }
+
+    /**
+     * 写入Token
+     * @access public
+     * @param  string $token Token标识
+     * @param  mixed $user_id 存储数据
+     * @param  int|null $expire 有效时间 0为永久
+     * @return boolean
+     */
+    public static function set($token, $user_id, $expire = null)
+    {
+        return self::init()->set($token, $user_id, $expire);
+    }
+
+    /**
+     * 删除Token(delete别名)
+     * @access public
+     * @param  string $token Token标识
+     * @return boolean
+     */
+    public static function rm($token)
+    {
+        return self::delete($token);
+    }
+
+    /**
+     * 删除Token
+     * @param string $token 标签名
+     * @return bool
+     */
+    public static function delete($token)
+    {
+        return self::init()->delete($token);
+    }
+
+    /**
+     * 清除Token
+     * @access public
+     * @param  string $token Token标记
+     * @return boolean
+     */
+    public static function clear($user_id = null)
+    {
+        return self::init()->clear($user_id);
+    }
+
+}

+ 70 - 0
application/common/library/WXBizDataCrypt.php

@@ -0,0 +1,70 @@
+<?php
+
+/**
+ * 对微信小程序用户加密数据的解密示例代码.
+ *
+ * @copyright Copyright (c) 1998-2014 Tencent Inc.
+ */
+
+namespace app\common\library;
+use think\Controller;
+
+include_once "errorCode.php";
+
+class WXBizDataCrypt extends Controller
+{
+    private $appid;
+    private $sessionKey;
+
+    /**
+     * 构造函数
+     * @param $sessionKey string 用户在小程序登录后获取的会话密钥
+     * @param $appid string 小程序的appid
+     */
+    public function __construct( $appid, $sessionKey)
+    {
+        $this->sessionKey = $sessionKey;
+        $this->appid = $appid;
+    }
+
+
+    /**
+     * 检验数据的真实性,并且获取解密后的明文.
+     * @param $encryptedData string 加密的用户数据
+     * @param $iv string 与用户数据一同返回的初始向量
+     * @param $data string 解密后的原文
+     *
+     * @return int 成功0,失败返回对应的错误码
+     */
+    public function decryptData( $encryptedData, $iv, &$data )
+    {
+        if (strlen($this->sessionKey) != 24) {
+            return ErrorCode::$IllegalAesKey;
+        }
+        $aesKey=base64_decode($this->sessionKey);
+
+
+        if (strlen($iv) != 24) {
+            return ErrorCode::$IllegalIv;
+        }
+        $aesIV=base64_decode($iv);
+
+        $aesCipher=base64_decode($encryptedData);
+
+        $result=openssl_decrypt( $aesCipher, "AES-128-CBC", $aesKey, 1, $aesIV);
+
+        $dataObj=json_decode( $result );
+        if( $dataObj  == NULL )
+        {
+            return ErrorCode::$IllegalBuffer;
+        }
+        if( $dataObj->watermark->appid != $this->appid )
+        {
+            return ErrorCode::$IllegalBuffer;
+        }
+        $data = $result;
+        return ErrorCode::$OK;
+    }
+
+}
+

+ 377 - 0
application/common/library/WxPay.php

@@ -0,0 +1,377 @@
+<?php
+namespace app\common\library;
+
+use app\common\model\Config;
+use think\Controller;
+use think\Facade;
+use EasyWeChat\Factory;
+
+class WxPay extends Controller
+{
+    /*
+   配置参数
+   */
+    public function __construct()
+    {
+       // $this->appid = Config::get_values('small_wechat_id');
+        $this->appid = Config::get_values('wechat_appid');
+        $this->api_key = Config::get_values('wechat_mch_key');
+        $this->mch_id = Config::get_values('wechat_mch_id');
+
+    }
+
+    public function retrunconfig(){
+        $config = [
+            'app_id' => Config::get_values('wechat_appid'),
+            'mch_id' =>Config::get_values('wechat_mch_id'),
+            'key' =>Config::get_values('wechat_mch_key')
+        ];
+        return $config;
+    }
+
+    //获取预支付订单
+    public function getPrePayOrder($body, $out_trade_no, $total_fee, $notify_url,$come,$openid){
+
+        $url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
+
+        $onoce_str = $this->getRandChar(32);
+
+        $data["appid"] =  $this->appid;
+        $data["body"] = $body;
+        $data["mch_id"] = $this->mch_id;
+        $data["nonce_str"] = $onoce_str;
+        $data["notify_url"] = $notify_url;
+        $data["out_trade_no"] = $out_trade_no;
+        $data["spbill_create_ip"] = $this->get_client_ip();
+        $data["total_fee"] = floatval($total_fee);
+        //$data["trade_type"] = $come=='weixin' ? "JSAPI" : "APP";
+        $data["trade_type"] = "APP";
+        $data['sign_type'] = "MD5";
+//        if ($come=='weixin'){
+//            $data['openid'] = $openid;
+//        }
+        $s = $this->getSign($data);
+
+        $data["sign"] = $s;
+
+        $xml = $this->arrayToXml($data);
+
+        $response = $this->postXmlCurl($xml, $url);
+
+        //将微信返回的结果xml转成数组
+       //return $this->xmlstr_to_array($response);
+        return $this->xmlToArray($response);
+    }
+
+
+    public function wxrefund($out_trade_no,$out_refund_no,$total_fee,$refund_fee)
+    {
+        $param = array(
+            'appid'=> $this->appid,
+            'mch_id'=> $this->mch_id,
+            'nonce_str'=>  $this->getRandChar(32),
+            'out_trade_no'=>$out_trade_no,
+            'out_refund_no'=>$out_refund_no,//订单号
+          //  'transaction_id'=> $transactionId,//微信订单号
+            'total_fee'=> $total_fee*100,
+            'refund_fee'=>$refund_fee*100
+        );
+
+        $param['sign'] = $this->getSign($param);
+        $xmldata = $this->arrayToXml($param);
+        $xmlresult = $this->postXmlSSLCurl($xmldata,'https://api.mch.weixin.qq.com/secapi/pay/refund');
+        $result = $this->xmlToArray($xmlresult);
+        return $result;
+    }
+
+
+    //执行第二次签名,才能返回给客户端使用
+    public function getOrder($prepayId){
+        $data["appid"] = $this->appid;
+        $data["noncestr"] = $this->getRandChar(32);
+        $data["package"] = "Sign=WXPay";
+       // $data['package'] = "prepay_id=".$prepayId;
+        $data["partnerid"] = $this->mch_id;
+        $data["prepayid"] = $prepayId;
+        $data["signType"] = "MD5";
+        $data["timestamp"] = '' . time() . '';
+        $s = $this->getSign($data, false);
+        $data["sign"] = $s;
+
+        return $data;
+    }
+
+    /*
+        生成签名
+    */
+    function getSign($Obj)
+    {
+        foreach ($Obj as $k => $v)
+        {
+            $Parameters[strtolower($k)] = $v;
+        }
+        //签名步骤一:按字典序排序参数
+        ksort($Parameters);
+        $String = $this->formatBizQueryParaMap($Parameters, false);
+        //echo "【string】 =".$String."</br>";
+        //签名步骤二:在string后加入KEY
+        $String = $String."&key=".$this->api_key;
+//        echo "<textarea style='width: 50%; height: 150px;'>$String</textarea> <br />";
+        //签名步骤三:MD5加密
+        $result_ = strtoupper(md5($String));
+        return $result_;
+    }
+
+
+
+
+    //获取指定长度的随机字符串
+    function getRandChar($length){
+        $str = null;
+        $strPol = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
+        $max = strlen($strPol)-1;
+
+        for($i=0;$i<$length;$i++){
+            $str.=$strPol[rand(0,$max)];//rand($min,$max)生成介于min和max两个数之间的一个随机整数
+        }
+
+        return $str;
+    }
+
+    //数组转xml
+    function arrayToXml($arr)
+    {
+        $xml = "<xml>";
+        foreach ($arr as $key=>$val)
+        {
+
+            if (is_numeric($val))
+            {
+                $xml.="<".$key.">".$val."</".$key.">";
+
+            }
+            else
+                $xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
+        }
+        $xml.="</xml>";
+        return $xml;
+    }
+
+    //post https请求,CURLOPT_POSTFIELDS xml格式
+    function postXmlCurl($xml,$url,$second=30)
+    {
+        //初始化curl
+        $ch = curl_init();
+        //超时时间
+        curl_setopt($ch,CURLOPT_TIMEOUT,$second);
+        //这里设置代理,如果有的话
+        //curl_setopt($ch,CURLOPT_PROXY, '8.8.8.8');
+        //curl_setopt($ch,CURLOPT_PROXYPORT, 8080);
+        curl_setopt($ch,CURLOPT_URL, $url);
+        curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE);
+        curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,FALSE);
+        //设置header
+        curl_setopt($ch, CURLOPT_HEADER, FALSE);
+        //要求结果为字符串且输出到屏幕上
+        curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
+        //post提交方式
+        curl_setopt($ch, CURLOPT_POST, TRUE);
+        curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
+        //运行curl
+        $data = curl_exec($ch);
+        //返回结果
+        if($data)
+        {
+            curl_close($ch);
+            return $data;
+        }
+        else
+        {
+            $error = curl_errno($ch);
+            echo "curl出错,错误码:$error"."<br>";
+            echo "<a href='http://curl.haxx.se/libcurl/c/libcurl-errors.html'>错误原因查询</a></br>";
+            curl_close($ch);
+            return false;
+        }
+    }
+
+
+
+   //需要使用证书的请求
+    private function postXmlSSLCurl($xml,$url,$second=30)
+    {
+        $ch = curl_init();
+        //超时时间
+        curl_setopt($ch,CURLOPT_TIMEOUT,$second);
+        //这里设置代理,如果有的话
+        //curl_setopt($ch,CURLOPT_PROXY, '8.8.8.8');
+        //curl_setopt($ch,CURLOPT_PROXYPORT, 8080);
+        curl_setopt($ch,CURLOPT_URL, $url);
+        curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE);
+        curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,FALSE);
+        //设置header
+        curl_setopt($ch,CURLOPT_HEADER,FALSE);
+        //要求结果为字符串且输出到屏幕上
+        curl_setopt($ch,CURLOPT_RETURNTRANSFER,TRUE);
+        //设置证书
+        //使用证书:cert 与 key 分别属于两个.pem文件
+        //默认格式为PEM,可以注释
+        curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM');
+        curl_setopt($ch,CURLOPT_SSLCERT, dirname(__DIR__) . '/wxcert/apiclient_cert.pem');
+        //默认格式为PEM,可以注释
+        curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
+        curl_setopt($ch,CURLOPT_SSLKEY, dirname(__DIR__) . '/wxcert/apiclient_key.pem');
+        //post提交方式
+        curl_setopt($ch,CURLOPT_POST, true);
+        curl_setopt($ch,CURLOPT_POSTFIELDS,$xml);
+        $data = curl_exec($ch);
+        //返回结果
+        if($data){
+            curl_close($ch);
+            return $data;
+        }
+        else {
+            $error = curl_errno($ch);
+            echo "curl出错,错误码:$error"."<br>";
+            curl_close($ch);
+            return false;
+        }
+    }
+    /*
+        获取当前服务器的IP
+    */
+    function get_client_ip()
+    {
+        if ($_SERVER['REMOTE_ADDR']) {
+            $cip = $_SERVER['REMOTE_ADDR'];
+        } elseif (getenv("REMOTE_ADDR")) {
+            $cip = getenv("REMOTE_ADDR");
+        } elseif (getenv("HTTP_CLIENT_IP")) {
+            $cip = getenv("HTTP_CLIENT_IP");
+        } else {
+            $cip = "unknown";
+        }
+        return $cip;
+    }
+
+    //将数组转成uri字符串
+    function formatBizQueryParaMap($paraMap, $urlencode)
+    {
+        $buff = "";
+        ksort($paraMap);
+        foreach ($paraMap as $k => $v)
+        {
+            if($urlencode)
+            {
+                $v = urlencode($v);
+            }
+            $buff .= strtolower($k) . "=" . $v . "&";
+        }
+        $reqPar;
+        if (strlen($buff) > 0)
+        {
+            $reqPar = substr($buff, 0, strlen($buff)-1);
+        }
+        return $reqPar;
+    }
+
+    /**
+    xml转成数组
+     */
+//    function xmlstr_to_array($xmlstr) {
+//        $doc = new DOMDocument();
+//        $doc->loadXML($xmlstr);
+//        return $this->domnode_to_array($doc->documentElement);
+//    }
+    function domnode_to_array($node) {
+        $output = array();
+        switch ($node->nodeType) {
+            case XML_CDATA_SECTION_NODE:
+            case XML_TEXT_NODE:
+                $output = trim($node->textContent);
+                break;
+            case XML_ELEMENT_NODE:
+                for ($i=0, $m=$node->childNodes->length; $i<$m; $i++) {
+                    $child = $node->childNodes->item($i);
+                    $v = $this->domnode_to_array($child);
+                    if(isset($child->tagName)) {
+                        $t = $child->tagName;
+                        if(!isset($output[$t])) {
+                            $output[$t] = array();
+                        }
+                        $output[$t][] = $v;
+                    }
+                    elseif($v) {
+                        $output = (string) $v;
+                    }
+                }
+                if(is_array($output)) {
+                    if($node->attributes->length) {
+                        $a = array();
+                        foreach($node->attributes as $attrName => $attrNode) {
+                            $a[$attrName] = (string) $attrNode->value;
+                        }
+                        $output['@attributes'] = $a;
+                    }
+                    foreach ($output as $t => $v) {
+                        if(is_array($v) && count($v)==1 && $t!='@attributes') {
+                            $output[$t] = $v[0];
+                        }
+                    }
+                }
+                break;
+        }
+        return $output;
+    }
+//    public function xmltoarray( $xml )
+//    {
+//        $arr = $this->xml_to_array($xml);
+//        $key = array_keys($arr);
+//        return $arr[$key[0]];
+//    }
+
+    /**
+     * 	作用:将xml转为array
+     */
+    public function xmlToArray($xml)
+    {
+        //将XML转为array
+        $array_data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
+        return $array_data;
+    }
+
+
+    public function xml_to_array( $xml )
+    {
+        $reg = "/<(\\w+)[^>]*?>([\\x00-\\xFF]*?)<\\/\\1>/";
+        if(preg_match_all($reg, $xml, $matches))
+        {
+            $count = count($matches[0]);
+            $arr = array();
+            for($i = 0; $i < $count; $i++)
+            {
+                $key = $matches[1][$i];
+                $val = $this->xml_to_array( $matches[2][$i] );  // 递归
+                if(array_key_exists($key, $arr))
+                {
+                    if(is_array($arr[$key]))
+                    {
+                        if(!array_key_exists(0,$arr[$key]))
+                        {
+                            $arr[$key] = array($arr[$key]);
+                        }
+                    }else{
+                        $arr[$key] = array($arr[$key]);
+                    }
+                    $arr[$key][] = $val;
+                }else{
+                    $arr[$key] = $val;
+                }
+            }
+            return $arr;
+        }else{
+            return $xml;
+        }
+    }
+
+}

+ 161 - 0
application/common/library/WxService.php

@@ -0,0 +1,161 @@
+<?php
+namespace app\common\library;
+class WxService
+{
+    protected $appid;
+    protected $appKey;
+
+    public $data = null;
+
+    public function __construct($appid, $appKey)
+    {
+        $this->appid = $appid; //微信支付申请对应的公众号的APPID
+        $this->appKey = $appKey; //微信支付申请对应的公众号的APP Key
+    }
+
+    /**
+     * 通过跳转获取用户的openid,跳转流程如下:
+     * 1、设置自己需要调回的url及其其他参数,跳转到微信服务器https://open.weixin.qq.com/connect/oauth2/authorize
+     * 2、微信服务处理完成之后会跳转回用户redirect_uri地址,此时会带上一些参数,如:code
+     *
+     * @return 用户的openid
+     */
+    public function GetOpenid()
+    {
+        //通过code获得openid
+        if (!isset($_GET['code'])){
+            //触发微信返回code码
+            $baseUrl = $this->getCurrentUrl();
+            $url = $this->__CreateOauthUrlForCode($baseUrl);
+            Header("Location: $url");
+            exit();
+        } else {
+            //获取code码,以获取openid
+            $code = $_GET['code'];
+            $openid = $this->getOpenidFromMp($code);
+            return $openid;
+        }
+    }
+
+    public function getCurrentUrl()
+    {
+        $scheme = $_SERVER['HTTPS']=='on' ? 'https://' : 'http://';
+        $uri = $_SERVER['PHP_SELF'].$_SERVER['QUERY_STRING'];
+        if($_SERVER['REQUEST_URI']) $uri = $_SERVER['REQUEST_URI'];
+        $baseUrl = urlencode($scheme.$_SERVER['HTTP_HOST'].$uri);
+        return $baseUrl;
+    }
+
+    /**
+     * 通过code从工作平台获取openid机器access_token
+     * @param string $code 微信跳转回来带上的code
+     * @return openid
+     */
+    public function GetOpenidFromMp($code)
+    {
+        $url = $this->__CreateOauthUrlForOpenid($code);
+        $res = self::curlGet($url);
+        $data = json_decode($res,true);
+        $this->data = $data;
+        return $data;
+    }
+
+    /**
+     * 构造获取open和access_toke的url地址
+     * @param string $code,微信跳转带回的code
+     * @return 请求的url
+     */
+    private function __CreateOauthUrlForOpenid($code)
+    {
+        $urlObj["appid"] = $this->appid;
+        $urlObj["secret"] = $this->appKey;
+        $urlObj["code"] = $code;
+        $urlObj["grant_type"] = "authorization_code";
+        $bizString = $this->ToUrlParams($urlObj);
+        return "https://api.weixin.qq.com/sns/oauth2/access_token?".$bizString;
+    }
+
+    /**
+     * 构造获取code的url连接
+     * @param string $redirectUrl 微信服务器回跳的url,需要url编码
+     * @return 返回构造好的url
+     */
+    private function __CreateOauthUrlForCode($redirectUrl)
+    {
+        $urlObj["appid"] = $this->appid;
+        $urlObj["redirect_uri"] = "$redirectUrl";
+        $urlObj["response_type"] = "code";
+        $urlObj["scope"] = "snsapi_userinfo";
+        $urlObj["state"] = "STATE";
+        $bizString = $this->ToUrlParams($urlObj);
+        return "https://open.weixin.qq.com/connect/oauth2/authorize?".$bizString;
+    }
+
+    /**
+     * 拼接签名字符串
+     * @param array $urlObj
+     * @return 返回已经拼接好的字符串
+     */
+    private function ToUrlParams($urlObj)
+    {
+        $buff = "";
+        foreach ($urlObj as $k => $v)
+        {
+            if($k != "sign") $buff .= $k . "=" . $v . "&";
+        }
+        $buff = trim($buff, "&");
+        return $buff;
+    }
+
+    /**
+     * 获取用户信息
+     * @param string $openid 调用【网页授权获取用户信息】接口获取到用户在该公众号下的Openid
+     * @return string
+     */
+    public function getUserInfo($openid,$access_token)
+    {
+
+        $response = self::curlGet('https://api.weixin.qq.com/sns/userinfo?access_token='.$access_token.'&openid='.$openid.'&lang=zh_CN');
+        return json_decode($response,true);
+
+    }
+
+    public static function curlGet($url = '', $options = array())
+    {
+        $ch = curl_init($url);
+        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+        curl_setopt($ch, CURLOPT_TIMEOUT, 30);
+        if (!empty($options)) {
+            curl_setopt_array($ch, $options);
+        }
+        //https请求 不验证证书和host
+        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
+        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
+        $data = curl_exec($ch);
+        curl_close($ch);
+        return $data;
+    }
+
+    public static function curlPost($url = '', $postData = '', $options = array())
+    {
+        if (is_array($postData)) {
+            $postData = http_build_query($postData);
+        }
+        $ch = curl_init();
+        curl_setopt($ch, CURLOPT_URL, $url);
+        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+        curl_setopt($ch, CURLOPT_POST, 1);
+        curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
+        curl_setopt($ch, CURLOPT_TIMEOUT, 30); //设置cURL允许执行的最长秒数
+        if (!empty($options)) {
+            curl_setopt_array($ch, $options);
+        }
+        //https请求 不验证证书和host
+        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
+        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
+        $data = curl_exec($ch);
+        curl_close($ch);
+        return $data;
+    }
+
+}

+ 188 - 0
application/common/library/alipay/aop/AlipayMobilePublicMultiMediaClient.php

@@ -0,0 +1,188 @@
+<?php
+
+/**
+ * 多媒体文件客户端
+ * @author yikai.hu
+ * @version $Id: AlipayMobilePublicMultiMediaClient.php, v 0.1 Aug 15, 2014 10:19:01 AM yikai.hu Exp $
+ */
+
+include("AlipayMobilePublicMultiMediaExecute.php");
+
+class AlipayMobilePublicMultiMediaClient
+{
+    private $DEFAULT_CHARSET = 'UTF-8';
+    private $METHOD_POST = "POST";
+    private $METHOD_GET = "GET";
+    private $SIGN = 'sign'; //get name
+
+    private $timeout = 10;// 超时时间
+    private $serverUrl;
+    private $appId;
+    private $privateKey;
+    private $prodCode;
+    private $format = 'json'; //todo
+    private $sign_type = 'RSA'; //todo
+
+    private $charset;
+    private $apiVersion = "1.0";
+    private $apiMethodName = "alipay.mobile.public.multimedia.download";
+    private $media_id = "L21pZnMvVDFQV3hYWGJKWFhYYUNucHJYP3Q9YW13ZiZ4c2lnPTU0MzRhYjg1ZTZjNWJmZTMxZGJiNjIzNDdjMzFkNzkw575";
+    //此处写死的,实际开发中,请传入
+
+    private $connectTimeout = 3000;
+    private $readTimeout = 15000;
+
+    function __construct($serverUrl = '', $appId = '', $partner_private_key = '', $format = '', $charset = 'GBK')
+    {
+        $this->serverUrl = $serverUrl;
+        $this->appId = $appId;
+        $this->privateKey = $partner_private_key;
+        $this->format = $format;
+        $this->charset = $charset;
+    }
+
+    /**
+     * getContents 获取网址内容
+     * @param $request
+     * @return text | bin
+     */
+    public function getContents()
+    {
+        $datas = array(
+            "app_id" => $this->appId,
+            "method" => $this->METHOD_POST,
+            "sign_type" => $this->sign_type,
+            "version" => $this->apiVersion,
+            "timestamp" => date('Y-m-d H:i:s'),//yyyy-MM-dd HH:mm:ss
+            "biz_content" => '{"mediaId":"' . $this->media_id . '"}',
+            "charset" => $this->charset
+        );
+
+        //要提交的数据
+        $data_sign = $this->buildGetUrl($datas);
+
+        $post_data = $data_sign;
+        //初始化 curl
+        $ch = curl_init();
+        //设置目标服务器
+        curl_setopt($ch, CURLOPT_URL, $this->serverUrl);
+        curl_setopt($ch, CURLOPT_HEADER, TRUE);
+        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+        //超时时间
+        curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout);
+
+        if ($this->METHOD_POST == 'POST') {
+            // post数据
+            curl_setopt($ch, CURLOPT_POST, 1);
+            // post的变量
+            curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
+        }
+
+
+        $output = curl_exec($ch);
+        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+        curl_close($ch);
+
+        echo $output;
+
+        $datas = explode("\r\n\r\n", $output, 2);
+        $header = $datas[0];
+
+        if ($httpCode == '200') {
+            $body = $datas[1];
+        } else {
+            $body = '';
+
+        }
+
+        return $this->execute($header, $body, $httpCode);
+    }
+
+    /**
+     *
+     * @param $request
+     * @return text | bin
+     */
+    public function execute($header = '', $body = '', $httpCode = '')
+    {
+        $exe = new AlipayMobilePublicMultiMediaExecute($header, $body, $httpCode);
+        return $exe;
+    }
+
+    public function buildGetUrl($query = array())
+    {
+        if (!is_array($query)) {
+            //exit;
+        }
+        //排序参数,
+        $data = $this->buildQuery($query);
+
+        // 私钥密码
+        $passphrase = '';
+        $key_width = 64;
+
+        //私钥
+        $privateKey = $this->privateKey;
+        $p_key = array();
+        //如果私钥是 1行
+        if (!stripos($privateKey, "\n")) {
+            $i = 0;
+            while ($key_str = substr($privateKey, $i * $key_width, $key_width)) {
+                $p_key[] = $key_str;
+                $i++;
+            }
+        } else {
+            //echo '一行?';
+        }
+        $privateKey = "-----BEGIN RSA PRIVATE KEY-----\n" . implode("\n", $p_key);
+        $privateKey = $privateKey . "\n-----END RSA PRIVATE KEY-----";
+
+        //私钥
+        $private_id = openssl_pkey_get_private($privateKey, $passphrase);
+
+        // 签名
+        $signature = '';
+
+        if ("RSA2" == $this->sign_type) {
+
+            openssl_sign($data, $signature, $private_id, OPENSSL_ALGO_SHA256);
+        } else {
+
+            openssl_sign($data, $signature, $private_id, OPENSSL_ALGO_SHA1);
+        }
+
+        openssl_free_key($private_id);
+
+        //加密后的内容通常含有特殊字符,需要编码转换下
+        $signature = base64_encode($signature);
+
+        $signature = urlencode($signature);
+
+        //$signature = 'XjUN6YM1Mc9HXebKMv7GTLy7gmyhktyOgKk2/Jf+cz4DtP6udkzTdpkjW2j/Z4ZSD7xD6CNYI1Spz4yS93HPT0a5X9LgFWYY8SaADqe+ArXg+FBSiTwUz49SE//Xd9+LEiIRsSFkbpkuiGoO6mqJmB7vXjlD5lx6qCM3nb41wb8=';
+
+        $out = $data . '&' . $this->SIGN . '=' . $signature;
+
+        return $out;
+    }
+
+    /*
+     * 查询参数排序 a-z
+     * */
+    public function buildQuery($query)
+    {
+        if (!$query) {
+            return null;
+        }
+        //将要 参数 排序
+        ksort($query);
+
+        //重新组装参数
+        $params = array();
+        foreach ($query as $key => $value) {
+            $params[] = $key . '=' . $value;
+        }
+        $data = implode('&', $params);
+        return $data;
+    }
+
+}

+ 115 - 0
application/common/library/alipay/aop/AlipayMobilePublicMultiMediaExecute.php

@@ -0,0 +1,115 @@
+<?php
+
+/**
+ * 多媒体文件客户端
+ * @author yuanwai.wang
+ * @version $Id: AlipayMobilePublicMultiMediaExecute.php, v 0.1 Aug 15, 2014 10:19:01 AM yuanwai.wang Exp $
+ */
+
+//namespace alipay\api ;
+
+
+class AlipayMobilePublicMultiMediaExecute
+{
+
+    private $code = 200;
+    private $msg = '';
+    private $body = '';
+    private $params = '';
+
+    private $fileSuffix = array(
+        "image/jpeg" => 'jpg', //+
+        "text/plain" => 'text'
+    );
+
+    /*
+     * @$header : 头部
+     * */
+    function __construct($header, $body, $httpCode)
+    {
+        $this->code = $httpCode;
+        $this->msg = '';
+        $this->params = $header;
+        $this->body = $body;
+    }
+
+    /**
+     *
+     * @return text | bin
+     */
+    public function getCode()
+    {
+        return $this->code;
+    }
+
+    /**
+     *
+     * @return text | bin
+     */
+    public function getMsg()
+    {
+        return $this->msg;
+    }
+
+    /**
+     *
+     * @return text | bin
+     */
+    public function getType()
+    {
+        $subject = $this->params;
+        $pattern = '/Content\-Type:([^;]+)/';
+        preg_match($pattern, $subject, $matches);
+        if ($matches) {
+            $type = $matches[1];
+        } else {
+            $type = 'application/download';
+        }
+
+        return str_replace(' ', '', $type);
+    }
+
+    /**
+     *
+     * @return text | bin
+     */
+    public function getContentLength()
+    {
+        $subject = $this->params;
+        $pattern = '/Content-Length:\s*([^\n]+)/';
+        preg_match($pattern, $subject, $matches);
+        return (int)(isset($matches[1]) ? $matches[1] : '');
+    }
+
+
+    public function getFileSuffix($fileType)
+    {
+        $type = isset($this->fileSuffix[$fileType]) ? $this->fileSuffix[$fileType] : 'text/plain';
+        if (!$type) {
+            $type = 'json';
+        }
+        return $type;
+    }
+
+
+    /**
+     *
+     * @return text | bin
+     */
+    public function getBody()
+    {
+        //header('Content-type: image/jpeg');
+        return $this->body;
+    }
+
+    /**
+     * 获取参数
+     * @return text | bin
+     */
+    public function getParams()
+    {
+        return $this->params;
+    }
+
+
+}

+ 1237 - 0
application/common/library/alipay/aop/AopCertClient.php

@@ -0,0 +1,1237 @@
+<?php
+
+require_once 'AopEncrypt.php';
+require_once 'AopCertification.php';
+require_once 'EncryptParseItem.php';
+require_once 'EncryptResponseData.php';
+require_once 'SignData.php';
+
+class AopCertClient
+{
+    //应用证书地址
+    public $appCertSN;
+
+    //支付宝公钥证书地址
+    public $alipayCertSN;
+
+    //支付宝根证书地址
+    public $alipayRootCertSN;
+
+    //支付宝根证书地址
+    public $alipayRootCertContent;
+
+    //是否校验支付宝公钥证书
+    public $isCheckAlipayPublicCert;
+
+    //应用ID
+    public $appId;
+
+    //私钥文件路径
+    public $rsaPrivateKeyFilePath;
+
+    //私钥值
+    public $rsaPrivateKey;
+
+    //网关
+    public $gatewayUrl = "https://openapi.alipay.com/gateway.do";
+    //返回数据格式
+    public $format = "json";
+
+    //api版本
+    public $apiVersion = "1.0";
+
+    // 表单提交字符集编码
+    public $postCharset = "UTF-8";
+
+    //使用文件读取文件格式,请只传递该值
+    public $alipayPublicKey = null;
+
+    //使用读取字符串格式,请只传递该值
+    public $alipayrsaPublicKey;
+
+    public $debugInfo = false;
+
+    //签名类型
+    public $signType = "RSA";
+
+    //加密密钥和类型
+    public $encryptKey;
+
+    public $encryptType = "AES";
+
+    protected $alipaySdkVersion = "alipay-sdk-php-2020-04-15";
+
+    private $fileCharset = "UTF-8";
+
+    private $RESPONSE_SUFFIX = "_response";
+
+    private $ERROR_RESPONSE = "error_response";
+
+    private $SIGN_NODE_NAME = "sign";
+
+    private $ALIPAY_CERT_SN = "alipay_cert_sn";
+
+
+    //加密XML节点名称
+    private $ENCRYPT_XML_NODE_NAME = "response_encrypted";
+
+    private $needEncrypt = false;
+
+    private $targetServiceUrl = "";
+
+    /**
+     * 从证书中提取序列号
+     * @param $cert
+     * @return string
+     */
+    public function getCertSN($certPath)
+    {
+        $cert = file_get_contents($certPath);
+        $ssl = openssl_x509_parse($cert);
+        $SN = md5(array2string(array_reverse($ssl['issuer'])) . $ssl['serialNumber']);
+        return $SN;
+    }
+
+    /**
+     * 提取根证书序列号
+     * @param $cert  根证书
+     * @return string|null
+     */
+    public function getRootCertSN($certPath)
+    {
+        $cert = file_get_contents($certPath);
+        $this->alipayRootCertContent = $cert;
+        $array = explode("-----END CERTIFICATE-----", $cert);
+        $SN = null;
+        for ($i = 0; $i < count($array) - 1; $i++) {
+            $ssl[$i] = openssl_x509_parse($array[$i] . "-----END CERTIFICATE-----");
+            if(strpos($ssl[$i]['serialNumber'],'0x') === 0){
+                $ssl[$i]['serialNumber'] = $this->hex2dec($ssl[$i]['serialNumber']);
+            }
+            if ($ssl[$i]['signatureTypeLN'] == "sha1WithRSAEncryption" || $ssl[$i]['signatureTypeLN'] == "sha256WithRSAEncryption") {
+                if ($SN == null) {
+                    $SN = md5(array2string(array_reverse($ssl[$i]['issuer'])) . $ssl[$i]['serialNumber']);
+                } else {
+
+                    $SN = $SN . "_" . md5(array2string(array_reverse($ssl[$i]['issuer'])) . $ssl[$i]['serialNumber']);
+                }
+            }
+        }
+        return $SN;
+    }
+
+    /**
+     * 0x转高精度数字
+     * @param $hex
+     * @return int|string
+     */
+    function hex2dec($hex)
+    {
+        $dec = 0;
+        $len = strlen($hex);
+        for ($i = 1; $i <= $len; $i++) {
+            $dec = bcadd($dec, bcmul(strval(hexdec($hex[$i - 1])), bcpow('16', strval($len - $i))));
+        }
+        return round($dec,0);
+    }
+
+    /**
+     * 从证书中提取公钥
+     * @param $cert
+     * @return mixed
+     */
+    public function getPublicKey($certPath)
+    {
+        $cert = file_get_contents($certPath);
+        $pkey = openssl_pkey_get_public($cert);
+        $keyData = openssl_pkey_get_details($pkey);
+        $public_key = str_replace('-----BEGIN PUBLIC KEY-----', '', $keyData['key']);
+        $public_key = trim(str_replace('-----END PUBLIC KEY-----', '', $public_key));
+        return $public_key;
+    }
+
+
+    /**
+     * 验证签名
+     * 在使用本方法前,必须初始化AopCertClient且传入公钥参数。
+     * 公钥是否是读取字符串还是读取文件,是根据初始化传入的值判断的。
+     *
+     * @param $params
+     * @param $rsaPublicKeyFilePath
+     * @param string $signType
+     * @return bool
+     */
+    public function rsaCheckV1($params, $rsaPublicKeyFilePath,$signType='RSA') {
+        $sign = $params['sign'];
+        unset($params['sign']);
+        unset($params['sign_type']);
+        return $this->verify($this->getCheckSignContent($params), $sign, $rsaPublicKeyFilePath,$signType);
+    }
+
+    /**
+     * 验证签名
+     * 在使用本方法前,必须初始化AopCertClient且传入公钥参数。
+     * 公钥是否是读取字符串还是读取文件,是根据初始化传入的值判断的。
+     *
+     * @param $params
+     * @param $rsaPublicKeyFilePath
+     * @param string $signType
+     * @return bool
+     */
+    public function rsaCheckV2($params, $rsaPublicKeyFilePath, $signType='RSA') {
+        $sign = $params['sign'];
+        unset($params['sign']);
+        unset($params['sign_type']);
+        return $this->verify($this->getCheckSignContent($params), $sign, $rsaPublicKeyFilePath, $signType);
+    }
+
+
+    function getCheckSignContent($params)
+    {
+        ksort($params);
+
+        $stringToBeSigned = "";
+        $i = 0;
+        foreach ($params as $k => $v) {
+            // 转换成目标字符集
+            $v = $this->characet($v, $this->postCharset);
+
+            if ($i == 0) {
+                $stringToBeSigned .= "$k" . "=" . "$v";
+            } else {
+                $stringToBeSigned .= "&" . "$k" . "=" . "$v";
+            }
+            $i++;
+        }
+
+        unset ($k, $v);
+        return $stringToBeSigned;
+    }
+
+
+    /**
+     *  在使用本方法前,必须初始化AopCertClient且传入公私钥参数。
+     *  公钥是否是读取字符串还是读取文件,是根据初始化传入的值判断的。
+     **/
+    public function checkSignAndDecrypt($params, $rsaPublicKeyPem, $rsaPrivateKeyPem, $isCheckSign, $isDecrypt, $signType='RSA') {
+        $charset = $params['charset'];
+        $bizContent = $params['biz_content'];
+        if ($isCheckSign) {
+            if (!$this->rsaCheckV2($params, $rsaPublicKeyPem, $signType)) {
+                echo "<br/>checkSign failure<br/>";
+                exit;
+            }
+        }
+        if ($isDecrypt) {
+            return $this->rsaDecrypt($bizContent, $rsaPrivateKeyPem, $charset);
+        }
+
+        return $bizContent;
+    }
+
+    /**
+     *  在使用本方法前,必须初始化AopCertClient且传入公私钥参数。
+     *  公钥是否是读取字符串还是读取文件,是根据初始化传入的值判断的。
+     **/
+    public function encryptAndSign($bizContent, $rsaPublicKeyPem, $rsaPrivateKeyPem, $charset, $isEncrypt, $isSign, $signType='RSA') {
+        // 加密,并签名
+        if ($isEncrypt && $isSign) {
+            $encrypted = $this->rsaEncrypt($bizContent, $rsaPublicKeyPem, $charset);
+            $sign = $this->sign($encrypted, $signType);
+            $response = "<?xml version=\"1.0\" encoding=\"$charset\"?><alipay><response>$encrypted</response><encryption_type>RSA</encryption_type><sign>$sign</sign><sign_type>$signType</sign_type></alipay>";
+            return $response;
+        }
+        // 加密,不签名
+        if ($isEncrypt && (!$isSign)) {
+            $encrypted = $this->rsaEncrypt($bizContent, $rsaPublicKeyPem, $charset);
+            $response = "<?xml version=\"1.0\" encoding=\"$charset\"?><alipay><response>$encrypted</response><encryption_type>$signType</encryption_type></alipay>";
+            return $response;
+        }
+        // 不加密,但签名
+        if ((!$isEncrypt) && $isSign) {
+            $sign = $this->sign($bizContent, $signType);
+            $response = "<?xml version=\"1.0\" encoding=\"$charset\"?><alipay><response>$bizContent</response><sign>$sign</sign><sign_type>$signType</sign_type></alipay>";
+            return $response;
+        }
+        // 不加密,不签名
+        $response = "<?xml version=\"1.0\" encoding=\"$charset\"?>$bizContent";
+        return $response;
+    }
+
+    /**
+     *  在使用本方法前,必须初始化AopCertClient且传入公私钥参数。
+     **/
+    public function rsaEncrypt($data, $rsaPublicKeyFilePath, $charset) {
+        if($this->checkEmpty($this->alipayPublicKey)){
+            //读取字符串
+            $pubKey= $this->alipayrsaPublicKey;
+            $res = "-----BEGIN PUBLIC KEY-----\n" .
+                wordwrap($pubKey, 64, "\n", true) .
+                "\n-----END PUBLIC KEY-----";
+        }else {
+            //读取公钥文件
+            $pubKey = file_get_contents($rsaPublicKeyFilePath);
+            //转换为openssl格式密钥
+            $res = openssl_get_publickey($pubKey);
+        }
+
+        ($res) or die('支付宝RSA公钥错误。请检查公钥文件格式是否正确');
+        $blocks = $this->splitCN($data, 0, 30, $charset);
+        $chrtext  = null;
+        $encodes  = array();
+        foreach ($blocks as $n => $block) {
+            if (!openssl_public_encrypt($block, $chrtext , $res)) {
+                echo "<br/>" . openssl_error_string() . "<br/>";
+            }
+            $encodes[] = $chrtext ;
+        }
+        $chrtext = implode(",", $encodes);
+
+        return base64_encode($chrtext);
+    }
+
+    /**
+     *  在使用本方法前,必须初始化AopCertClient且传入公私钥参数。
+     *  公钥是否是读取字符串还是读取文件,是根据初始化传入的值判断的。
+     **/
+    public function rsaDecrypt($data, $rsaPrivateKeyPem, $charset) {
+
+        if($this->checkEmpty($this->rsaPrivateKeyFilePath)){
+            //读字符串
+            $priKey=$this->rsaPrivateKey;
+            $res = "-----BEGIN RSA PRIVATE KEY-----\n" .
+                wordwrap($priKey, 64, "\n", true) .
+                "\n-----END RSA PRIVATE KEY-----";
+        }else {
+            $priKey = file_get_contents($this->rsaPrivateKeyFilePath);
+            $res = openssl_get_privatekey($priKey);
+        }
+        ($res) or die('您使用的私钥格式错误,请检查RSA私钥配置');
+        //转换为openssl格式密钥
+        $decodes = explode(',', $data);
+        $strnull = "";
+        $dcyCont = "";
+        foreach ($decodes as $n => $decode) {
+            if (!openssl_private_decrypt($decode, $dcyCont, $res)) {
+                echo "<br/>" . openssl_error_string() . "<br/>";
+            }
+            $strnull .= $dcyCont;
+        }
+        return $strnull;
+    }
+
+    function splitCN($cont, $n = 0, $subnum, $charset) {
+        //$len = strlen($cont) / 3;
+        $arrr = array();
+        for ($i = $n; $i < strlen($cont); $i += $subnum) {
+            $res = $this->subCNchar($cont, $i, $subnum, $charset);
+            if (!empty ($res)) {
+                $arrr[] = $res;
+            }
+        }
+
+        return $arrr;
+    }
+
+    function subCNchar($str, $start = 0, $length, $charset = "gbk") {
+        if (strlen($str) <= $length) {
+            return $str;
+        }
+        $re['utf-8'] = "/[\x01-\x7f]|[\xc2-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xff][\x80-\xbf]{3}/";
+        $re['gb2312'] = "/[\x01-\x7f]|[\xb0-\xf7][\xa0-\xfe]/";
+        $re['gbk'] = "/[\x01-\x7f]|[\x81-\xfe][\x40-\xfe]/";
+        $re['big5'] = "/[\x01-\x7f]|[\x81-\xfe]([\x40-\x7e]|\xa1-\xfe])/";
+        preg_match_all($re[$charset], $str, $match);
+        $slice = join("", array_slice($match[0], $start, $length));
+        return $slice;
+    }
+
+    /**
+     * 生成用于调用收银台SDK的字符串
+     * @param $request SDK接口的请求参数对象
+     * @param $appAuthToken 三方应用授权token
+     * @return string
+     */
+    public function sdkExecute($request, $appAuthToken = null) {
+
+        $this->setupCharsets($request);
+        $params['app_id'] = $this->appId;
+        $params['method'] = $request->getApiMethodName();
+        $params['format'] = $this->format;
+        $params['sign_type'] = $this->signType;
+        $params['timestamp'] = date("Y-m-d H:i:s");
+        $params['alipay_sdk'] = $this->alipaySdkVersion;
+        $params['charset'] = $this->postCharset;
+        $version = $request->getApiVersion();
+        $params['version'] = $this->checkEmpty($version) ? $this->apiVersion : $version;
+        $params["app_cert_sn"] = $this->appCertSN;
+        $params["alipay_root_cert_sn"] = $this->alipayRootCertSN;
+        if ($notify_url = $request->getNotifyUrl()) {
+            $params['notify_url'] = $notify_url;
+        }
+        $params['app_auth_token'] = $appAuthToken;
+        $dict = $request->getApiParas();
+        $params['biz_content'] = $dict['biz_content'];
+        ksort($params);
+        $params['sign'] = $this->generateSign($params, $this->signType);
+        foreach ($params as &$value) {
+            $value = $this->characet($value, $params['charset']);
+        }
+        return http_build_query($params);
+    }
+
+
+    /**
+     * 页面提交执行方法
+     * @param $request 跳转类接口的request
+     * @param string $httpmethod 提交方式,两个值可选:post、get;
+     * @param null $appAuthToken 三方应用授权token
+     * @return 构建好的、签名后的最终跳转URL(GET)或String形式的form(POST)
+     * @throws Exception
+     */
+    public function pageExecute($request, $httpmethod = "POST", $appAuthToken = null) {
+
+        $this->setupCharsets($request);
+        if (strcasecmp($this->fileCharset, $this->postCharset)) {
+            throw new Exception("文件编码:[" . $this->fileCharset . "] 与表单提交编码:[" . $this->postCharset . "]两者不一致!");
+        }
+        $iv=null;
+        if(!$this->checkEmpty($request->getApiVersion())){
+            $iv=$request->getApiVersion();
+        }else{
+            $iv=$this->apiVersion;
+        }
+
+        //组装系统参数
+        $sysParams["app_id"] = $this->appId;
+        $sysParams["version"] = $iv;
+        $sysParams["format"] = $this->format;
+        $sysParams["sign_type"] = $this->signType;
+        $sysParams["method"] = $request->getApiMethodName();
+        $sysParams["timestamp"] = date("Y-m-d H:i:s");
+        $sysParams["alipay_sdk"] = $this->alipaySdkVersion;
+        $sysParams["terminal_type"] = $request->getTerminalType();
+        $sysParams["terminal_info"] = $request->getTerminalInfo();
+        $sysParams["prod_code"] = $request->getProdCode();
+        $sysParams["notify_url"] = $request->getNotifyUrl();
+        $sysParams["return_url"] = $request->getReturnUrl();
+        $sysParams["charset"] = $this->postCharset;
+        $sysParams["app_auth_token"] = $appAuthToken;
+        $sysParams["app_cert_sn"] = $this->appCertSN;
+        $sysParams["alipay_root_cert_sn"] = $this->alipayRootCertSN;
+
+        //获取业务参数
+        $apiParams = $request->getApiParas();
+        if (method_exists($request,"getNeedEncrypt") &&$request->getNeedEncrypt()){
+            $sysParams["encrypt_type"] = $this->encryptType;
+            if ($this->checkEmpty($apiParams['biz_content'])) {
+                throw new Exception(" api request Fail! The reason : encrypt request is not supperted!");
+            }
+            if ($this->checkEmpty($this->encryptKey) || $this->checkEmpty($this->encryptType)) {
+                throw new Exception(" encryptType and encryptKey must not null! ");
+            }
+            if ("AES" != $this->encryptType) {
+                throw new Exception("加密类型只支持AES");
+            }
+            // 执行加密
+            $enCryptContent = encrypt($apiParams['biz_content'], $this->encryptKey);
+            $apiParams['biz_content'] = $enCryptContent;
+        }
+        $totalParams = array_merge($apiParams, $sysParams);
+        //待签名字符串
+        $preSignStr = $this->getSignContent($totalParams);
+        //签名
+        $totalParams["sign"] = $this->generateSign($totalParams, $this->signType);
+
+        if ("GET" == strtoupper($httpmethod)) {
+            //value做urlencode
+            $preString=$this->getSignContentUrlencode($totalParams);
+            //拼接GET请求串
+            $requestUrl = $this->gatewayUrl."?".$preString;
+            return $requestUrl;
+        } else {
+            //拼接表单字符串
+            return $this->buildRequestForm($totalParams);
+        }
+    }
+
+    //此方法对value做urlencode
+    public function getSignContentUrlencode($params) {
+        ksort($params);
+        $stringToBeSigned = "";
+        $i = 0;
+        foreach ($params as $k => $v) {
+            if (false === $this->checkEmpty($v) && "@" != substr($v, 0, 1)) {
+
+                // 转换成目标字符集
+                $v = $this->characet($v, $this->postCharset);
+
+                if ($i == 0) {
+                    $stringToBeSigned .= "$k" . "=" . urlencode($v);
+                } else {
+                    $stringToBeSigned .= "&" . "$k" . "=" . urlencode($v);
+                }
+                $i++;
+            }
+        }
+        unset ($k, $v);
+        return $stringToBeSigned;
+    }
+
+
+    /**
+     * 建立请求,以表单HTML形式构造(默认)
+     * @param $para_temp 请求参数数组
+     * @return 提交表单HTML文本
+     */
+    protected function buildRequestForm($para_temp) {
+        $sHtml = "<form id='alipaysubmit' name='alipaysubmit' action='".$this->gatewayUrl."?charset=".trim($this->postCharset)."' method='POST'>";
+        while (list ($key, $val) = $this->fun_adm_each($para_temp)) {
+            if (false === $this->checkEmpty($val)) {
+                //$val = $this->characet($val, $this->postCharset);
+                $val = str_replace("'","&apos;",$val);
+                //$val = str_replace("\"","&quot;",$val);
+                $sHtml.= "<input type='hidden' name='".$key."' value='".$val."'/>";
+            }
+        }
+        //submit按钮控件请不要含有name属性
+        $sHtml = $sHtml."<input type='submit' value='ok' style='display:none;''></form>";
+        $sHtml = $sHtml."<script>document.forms['alipaysubmit'].submit();</script>";
+        return $sHtml;
+    }
+
+    protected function fun_adm_each(&$array)
+    {
+        $res = array();
+        $key = key($array);
+        if ($key !== null) {
+            next($array);
+            $res[1] = $res['value'] = $array[$key];
+            $res[0] = $res['key'] = $key;
+        } else {
+            $res = false;
+        }
+        return $res;
+    }
+
+    public function execute($request, $authToken = null, $appInfoAuthtoken = null,$targetAppId = null) {
+        $this->setupCharsets($request);
+        //如果两者编码不一致,会出现签名验签或者乱码
+        if (strcasecmp($this->fileCharset, $this->postCharset)) {
+            throw new Exception("文件编码:[" . $this->fileCharset . "] 与表单提交编码:[" . $this->postCharset . "]两者不一致!");
+        }
+        $iv = null;
+        if (!$this->checkEmpty($request->getApiVersion())) {
+            $iv = $request->getApiVersion();
+        } else {
+            $iv = $this->apiVersion;
+        }
+        //组装系统参数
+        $sysParams["app_id"] = $this->appId;
+        $sysParams["version"] = $iv;
+        $sysParams["format"] = $this->format;
+        $sysParams["sign_type"] = $this->signType;
+        $sysParams["method"] = $request->getApiMethodName();
+        $sysParams["timestamp"] = date("Y-m-d H:i:s");
+        $sysParams["auth_token"] = $authToken;
+        $sysParams["alipay_sdk"] = $this->alipaySdkVersion;
+        $sysParams["terminal_type"] = $request->getTerminalType();
+        $sysParams["terminal_info"] = $request->getTerminalInfo();
+        $sysParams["prod_code"] = $request->getProdCode();
+        $sysParams["notify_url"] = $request->getNotifyUrl();
+        $sysParams["charset"] = $this->postCharset;
+        $sysParams["app_auth_token"] = $appInfoAuthtoken;
+        $sysParams["app_cert_sn"] = $this->appCertSN;
+        $sysParams["alipay_root_cert_sn"] = $this->alipayRootCertSN;
+        $sysParams["target_app_id"] = $targetAppId;
+        if(!$this->checkEmpty($this->targetServiceUrl)){
+            $sysParams["ws_service_url"] = $this->targetServiceUrl;
+        }
+
+        //获取业务参数
+        $apiParams = $request->getApiParas();
+
+        if (method_exists($request,"getNeedEncrypt") && $request->getNeedEncrypt()){
+            $sysParams["encrypt_type"] = $this->encryptType;
+            if ($this->checkEmpty($apiParams['biz_content'])) {
+                throw new Exception(" api request Fail! The reason : encrypt request is not supperted!");
+            }
+            if ($this->checkEmpty($this->encryptKey) || $this->checkEmpty($this->encryptType)) {
+                throw new Exception(" encryptType and encryptKey must not null! ");
+            }
+            if ("AES" != $this->encryptType) {
+                throw new Exception("加密类型只支持AES");
+            }
+            // 执行加密
+            $enCryptContent = encrypt($apiParams['biz_content'], $this->encryptKey);
+            $apiParams['biz_content'] = $enCryptContent;
+        }
+
+        //签名
+        $sysParams["sign"] = $this->generateSign(array_merge($apiParams, $sysParams), $this->signType);
+
+        //系统参数放入GET请求串
+        $requestUrl = $this->gatewayUrl . "?";
+        foreach ($sysParams as $sysParamKey => $sysParamValue) {
+            $requestUrl .= "$sysParamKey=" . urlencode($this->characet($sysParamValue, $this->postCharset)) . "&";
+        }
+        $requestUrl = substr($requestUrl, 0, -1);
+
+        //发起HTTP请求
+        try {
+            $resp = $this->curl($requestUrl, $apiParams);
+        } catch (Exception $e) {
+            $this->logCommunicationError($sysParams["method"], $requestUrl, "HTTP_ERROR_" . $e->getCode(), $e->getMessage());
+            return false;
+        }
+
+        //解析AOP返回结果
+        $respWellFormed = false;
+
+        // 将返回结果转换本地文件编码
+        $r = iconv($this->postCharset, $this->fileCharset . "//IGNORE", $resp);
+        $signData = null;
+
+        if ("json" == $this->format) {
+            $respObject = json_decode($r);
+            if (null !== $respObject) {
+                $respWellFormed = true;
+                $signData = $this->parserJSONSignData($request, $resp, $respObject);
+            }
+        } else if ("xml" == $this->format) {
+            $disableLibxmlEntityLoader = libxml_disable_entity_loader(true);
+            $respObject = @ simplexml_load_string($resp);
+            if (false !== $respObject) {
+                $respWellFormed = true;
+                $signData = $this->parserXMLSignData($request, $resp);
+            }
+            libxml_disable_entity_loader($disableLibxmlEntityLoader);
+        }
+
+        //返回的HTTP文本不是标准JSON或者XML,记下错误日志
+        if (false === $respWellFormed) {
+            $this->logCommunicationError($sysParams["method"], $requestUrl, "HTTP_RESPONSE_NOT_WELL_FORMED", $resp);
+            return false;
+        }
+
+        // 验签
+        $this->checkResponseSign($request, $signData, $resp, $respObject);
+
+        // 解密
+        if (method_exists($request,"getNeedEncrypt") &&$request->getNeedEncrypt()){
+
+            if ("json" == $this->format) {
+                $resp = $this->encryptJSONSignSource($request, $resp);
+                // 将返回结果转换本地文件编码
+                $r = iconv($this->postCharset, $this->fileCharset . "//IGNORE", $resp);
+                $respObject = json_decode($r);
+            }else{
+                $resp = $this->encryptXMLSignSource($request, $resp);
+                $r = iconv($this->postCharset, $this->fileCharset . "//IGNORE", $resp);
+                $disableLibxmlEntityLoader = libxml_disable_entity_loader(true);
+                $respObject = @ simplexml_load_string($r);
+                libxml_disable_entity_loader($disableLibxmlEntityLoader);
+            }
+        }
+        return $respObject;
+    }
+
+
+    /**
+     * 设置编码格式
+     * @param $request
+     */
+    private function setupCharsets($request) {
+        if ($this->checkEmpty($this->postCharset)) {
+            $this->postCharset = 'UTF-8';
+        }
+        $str = preg_match('/[\x80-\xff]/', $this->appId) ? $this->appId : print_r($request, true);
+        $this->fileCharset = mb_detect_encoding($str, "UTF-8, GBK") == 'UTF-8' ? 'UTF-8' : 'GBK';
+    }
+
+    /**
+     * 校验$value是否非空
+     *  if not set ,return true;
+     *    if is null , return true;
+     **/
+    protected function checkEmpty($value) {
+        if (!isset($value))
+            return true;
+        if ($value === null)
+            return true;
+        if (trim($value) === "")
+            return true;
+
+        return false;
+    }
+
+    /**
+     * 加签
+     * @param $params
+     * @param string $signType
+     * @return mixed
+     */
+    public function generateSign($params, $signType = "RSA") {
+        return $this->sign($this->getSignContent($params), $signType);
+    }
+
+    public function rsaSign($params, $signType = "RSA") {
+        return $this->sign($this->getSignContent($params), $signType);
+    }
+
+    protected function sign($data, $signType = "RSA") {
+        if($this->checkEmpty($this->rsaPrivateKeyFilePath)){
+            $priKey=$this->rsaPrivateKey;
+            $res = "-----BEGIN RSA PRIVATE KEY-----\n" .
+                wordwrap($priKey, 64, "\n", true) .
+                "\n-----END RSA PRIVATE KEY-----";
+        }else {
+            $priKey = file_get_contents($this->rsaPrivateKeyFilePath);
+            $res = openssl_get_privatekey($priKey);
+        }
+
+        ($res) or die('您使用的私钥格式错误,请检查RSA私钥配置');
+
+        if ("RSA2" == $signType) {
+            openssl_sign($data, $sign, $res, OPENSSL_ALGO_SHA256);
+        } else {
+            openssl_sign($data, $sign, $res);
+        }
+
+        if(!$this->checkEmpty($this->rsaPrivateKeyFilePath)){
+            openssl_free_key($res);
+        }
+        $sign = base64_encode($sign);
+        return $sign;
+    }
+
+    public function getSignContent($params) {
+        ksort($params);
+
+        $stringToBeSigned = "";
+        $i = 0;
+        foreach ($params as $k => $v) {
+            if (false === $this->checkEmpty($v) && "@" != substr($v, 0, 1)) {
+
+                // 转换成目标字符集
+                $v = $this->characet($v, $this->postCharset);
+
+                if ($i == 0) {
+                    $stringToBeSigned .= "$k" . "=" . "$v";
+                } else {
+                    $stringToBeSigned .= "&" . "$k" . "=" . "$v";
+                }
+                $i++;
+            }
+        }
+        unset ($k, $v);
+        return $stringToBeSigned;
+    }
+
+
+    /**
+     * RSA单独签名方法,未做字符串处理,字符串处理见getSignContent()
+     * @param $data 待签名字符串
+     * @param $privatekey 商户私钥,根据keyfromfile来判断是读取字符串还是读取文件,false:填写私钥字符串去回车和空格 true:填写私钥文件路径
+     * @param $signType 签名方式,RSA:SHA1     RSA2:SHA256
+     * @param $keyfromfile 私钥获取方式,读取字符串还是读文件
+     * @return string
+     */
+    public function alonersaSign($data,$privatekey,$signType = "RSA",$keyfromfile=false) {
+        if(!$keyfromfile){
+            $priKey=$privatekey;
+            $res = "-----BEGIN RSA PRIVATE KEY-----\n" .
+                wordwrap($priKey, 64, "\n", true) .
+                "\n-----END RSA PRIVATE KEY-----";
+        }
+        else{
+            $priKey = file_get_contents($privatekey);
+            $res = openssl_get_privatekey($priKey);
+        }
+        ($res) or die('您使用的私钥格式错误,请检查RSA私钥配置');
+        if ("RSA2" == $signType) {
+            openssl_sign($data, $sign, $res, OPENSSL_ALGO_SHA256);
+        } else {
+            openssl_sign($data, $sign, $res);
+        }
+        if($keyfromfile){
+            openssl_free_key($res);
+        }
+        $sign = base64_encode($sign);
+        return $sign;
+    }
+
+    /**
+     * 转换字符集编码
+     * @param $data
+     * @param $targetCharset
+     * @return string
+     */
+    function characet($data, $targetCharset) {
+
+        if (!empty($data)) {
+            $fileType = $this->fileCharset;
+            if (strcasecmp($fileType, $targetCharset) != 0) {
+                $data = mb_convert_encoding($data, $targetCharset, $fileType);
+            }
+        }
+        return $data;
+    }
+
+    /**
+     * 发送curl请求
+     * @param $url
+     * @param null $postFields
+     * @return bool|string
+     * @throws Exception
+     */
+    protected function curl($url, $postFields = null) {
+        $ch = curl_init();
+        curl_setopt($ch, CURLOPT_URL, $url);
+        curl_setopt($ch, CURLOPT_FAILONERROR, false);
+        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
+        $postBodyString = "";
+        $encodeArray = Array();
+        $postMultipart = false;
+
+        if (is_array($postFields) && 0 < count($postFields)) {
+            foreach ($postFields as $k => $v) {
+                if ("@" != substr($v, 0, 1)) //判断是不是文件上传
+                {
+                    $postBodyString .= "$k=" . urlencode($this->characet($v, $this->postCharset)) . "&";
+                    $encodeArray[$k] = $this->characet($v, $this->postCharset);
+                } else //文件上传用multipart/form-data,否则用www-form-urlencoded
+                {
+                    $postMultipart = true;
+                    $encodeArray[$k] = new \CURLFile(substr($v, 1));
+                }
+            }
+            unset ($k, $v);
+            curl_setopt($ch, CURLOPT_POST, true);
+            if ($postMultipart) {
+                curl_setopt($ch, CURLOPT_POSTFIELDS, $encodeArray);
+            } else {
+                curl_setopt($ch, CURLOPT_POSTFIELDS, substr($postBodyString, 0, -1));
+            }
+        }
+
+        if (!$postMultipart) {
+            $headers = array('content-type: application/x-www-form-urlencoded;charset=' . $this->postCharset);
+            curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
+        }
+        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
+        $reponse = curl_exec($ch);
+        if (curl_errno($ch)) {
+            throw new Exception(curl_error($ch), 0);
+        } else {
+            $httpStatusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+            if (200 !== $httpStatusCode) {
+                throw new Exception($reponse, $httpStatusCode);
+            }
+        }
+        curl_close($ch);
+        return $reponse;
+    }
+
+    protected function getMillisecond() {
+        list($s1, $s2) = explode(' ', microtime());
+        return (float)sprintf('%.0f', (floatval($s1) + floatval($s2)) * 1000);
+    }
+
+    /**
+     * 打印日志信息
+     * @param $apiName
+     * @param $requestUrl
+     * @param $errorCode
+     * @param $responseTxt
+     */
+    protected function logCommunicationError($apiName, $requestUrl, $errorCode, $responseTxt) {
+        $logData = array(
+            date("Y-m-d H:i:s"),
+            $apiName,
+            $this->appId,
+            PHP_OS,
+            $this->alipaySdkVersion,
+            $requestUrl,
+            $errorCode,
+            str_replace("\n", "", $responseTxt)
+        );
+        echo json_encode($logData);
+    }
+
+    /**
+     * Json格式签名内容
+     * @param $request
+     * @param $responseContent
+     * @param $responseJSON
+     * @return SignData
+     */
+    function parserJSONSignData($request, $responseContent, $responseJSON) {
+        $signData = new SignData();
+        $signData->sign = $this->parserJSONSign($responseJSON);
+        $signData->signSourceData = $this->parserJSONSignSource($request, $responseContent);
+        return $signData;
+    }
+
+    function parserJSONSign($responseJSon) {
+        return $responseJSon->sign;
+    }
+
+    function parserJSONSignSource($request, $responseContent) {
+        $apiName = $request->getApiMethodName();
+        $rootNodeName = str_replace(".", "_", $apiName) . $this->RESPONSE_SUFFIX;
+        $rootIndex = strpos($responseContent, $rootNodeName);
+        $errorIndex = strpos($responseContent, $this->ERROR_RESPONSE);
+        if ($rootIndex > 0) {
+            return $this->parserJSONSource($responseContent, $rootNodeName, $rootIndex);
+        } else if ($errorIndex > 0) {
+            return $this->parserJSONSource($responseContent, $this->ERROR_RESPONSE, $errorIndex);
+        } else {
+            return null;
+        }
+    }
+
+    function parserJSONSource($responseContent, $nodeName, $nodeIndex) {
+        $signDataStartIndex = $nodeIndex + strlen($nodeName) + 2;
+        if(strrpos($responseContent, $this->ALIPAY_CERT_SN)){
+            $signIndex = strrpos($responseContent, "\"" . $this->ALIPAY_CERT_SN . "\"");
+        }else{
+            $signIndex = strrpos($responseContent, "\"" . $this->SIGN_NODE_NAME . "\"");
+        }
+        // 签名前-逗号
+        $signDataEndIndex = $signIndex - 1;
+        $indexLen = $signDataEndIndex - $signDataStartIndex;
+        if ($indexLen < 0) {
+            return null;
+        }
+        return substr($responseContent, $signDataStartIndex, $indexLen);
+    }
+
+    /**
+     * XML格式签名内容
+     * @param $request
+     * @param $responseContent
+     * @return SignData
+     */
+    function parserXMLSignData($request, $responseContent) {
+        $signData = new SignData();
+        $signData->sign = $this->parserXMLSign($responseContent);
+        $signData->signSourceData = $this->parserXMLSignSource($request, $responseContent);
+        return $signData;
+    }
+
+    function parserXMLSign($responseContent) {
+        if(strrpos($responseContent, $this->ALIPAY_CERT_SN)){
+            $signNodeName = "<" . $this->ALIPAY_CERT_SN . ">";
+            $signEndNodeName = "</" . $this->ALIPAY_CERT_SN . ">";
+        }else{
+            $signNodeName = "<" . $this->SIGN_NODE_NAME . ">";
+            $signEndNodeName = "</" . $this->SIGN_NODE_NAME . ">";
+        }
+
+        $indexOfSignNode = strpos($responseContent, $signNodeName);
+        $indexOfSignEndNode = strpos($responseContent, $signEndNodeName);
+        if ($indexOfSignNode < 0 || $indexOfSignEndNode < 0) {
+            return null;
+        }
+        $nodeIndex = ($indexOfSignNode + strlen($signNodeName));
+        $indexLen = $indexOfSignEndNode - $nodeIndex;
+        if ($indexLen < 0) {
+            return null;
+        }
+        // 签名
+        return substr($responseContent, $nodeIndex, $indexLen);
+    }
+
+    function parserXMLSignSource($request, $responseContent) {
+        $apiName = $request->getApiMethodName();
+        $rootNodeName = str_replace(".", "_", $apiName) . $this->RESPONSE_SUFFIX;
+        $rootIndex = strpos($responseContent, $rootNodeName);
+        $errorIndex = strpos($responseContent, $this->ERROR_RESPONSE);
+        if ($rootIndex > 0) {
+            return $this->parserXMLSource($responseContent, $rootNodeName, $rootIndex);
+        } else if ($errorIndex > 0) {
+            return $this->parserXMLSource($responseContent, $this->ERROR_RESPONSE, $errorIndex);
+        } else {
+            return null;
+        }
+    }
+
+
+    function parserXMLSource($responseContent, $nodeName, $nodeIndex) {
+        $signDataStartIndex = $nodeIndex + strlen($nodeName) + 1;
+        if(strrpos($responseContent, $this->ALIPAY_CERT_SN)){
+            $signIndex = strrpos($responseContent, "<" . $this->ALIPAY_CERT_SN . ">");
+        }else{
+            $signIndex = strrpos($responseContent, "<" . $this->SIGN_NODE_NAME . ">");
+        }
+
+        // 签名前-逗号
+        $signDataEndIndex = $signIndex - 1;
+        $indexLen = $signDataEndIndex - $signDataStartIndex + 1;
+
+        if ($indexLen < 0) {
+            return null;
+        }
+        return substr($responseContent, $signDataStartIndex, $indexLen);
+    }
+
+
+    /**
+     * 验签
+     * @param $request
+     * @param $signData
+     * @param $resp
+     * @param $respObject
+     * @throws Exception
+     */
+    public function checkResponseSign($request, $signData, $resp, $respObject) {
+        if (!$this->checkEmpty($this->alipayPublicKey) || !$this->checkEmpty($this->alipayrsaPublicKey)) {
+            if ($signData == null || $this->checkEmpty($signData->sign) || $this->checkEmpty($signData->signSourceData)) {
+                throw new Exception(" check sign Fail! The reason : signData is Empty");
+            }
+            // 获取结果sub_code
+            $responseSubCode = $this->parserResponseSubCode($request, $resp, $respObject, $this->format);
+            if (!$this->checkEmpty($responseSubCode) || ($this->checkEmpty($responseSubCode) && !$this->checkEmpty($signData->sign))) {
+                $checkResult = $this->verify($signData->signSourceData, $signData->sign, $this->alipayPublicKey, $this->signType);
+
+                if (!$checkResult) {
+
+                    //请求网关下载新的支付宝公钥证书
+                    if(!$respObject->alipay_cert_sn && ($request->getApiMethodName()=="alipay.open.app.alipaycert.download")){
+                        throw new Exception(" check sign Fail! The reason : alipay_cert_sn is Empty");
+                    }
+                    //组装系统参数
+                    $sysParams["app_id"] = $this->appId;
+                    $sysParams["format"] = $this->format;
+                    $sysParams["sign_type"] = $this->signType;
+                    $sysParams["method"] = "alipay.open.app.alipaycert.download";
+                    $sysParams["timestamp"] = date("Y-m-d H:i:s");
+                    $sysParams["alipay_sdk"] = $this->alipaySdkVersion;
+                    $sysParams["terminal_type"] = $request->getTerminalType();
+                    $sysParams["terminal_info"] = $request->getTerminalInfo();
+                    $sysParams["prod_code"] = $request->getProdCode();
+                    $sysParams["notify_url"] = $request->getNotifyUrl();
+                    $sysParams["charset"] = $this->postCharset;
+                    $sysParams["app_cert_sn"] = $this->appCertSN;
+                    $sysParams["alipay_root_cert_sn"] = $this->alipayRootCertSN;
+                    //获取业务参数
+                    $apiParas = array();
+                    $apiParas["biz_content"] = "{\"alipay_cert_sn\":\"".$respObject->alipay_cert_sn."\"}";
+                    $apiParams = $apiParas;
+
+                    //签名
+                    $sysParams["sign"] = $this->generateSign(array_merge($apiParams, $sysParams), $this->signType);
+
+                    //系统参数放入GET请求串
+                    $requestUrl = $this->gatewayUrl . "?";
+                    foreach ($sysParams as $sysParamKey => $sysParamValue) {
+                        $requestUrl .= "$sysParamKey=" . urlencode($this->characet($sysParamValue, $this->postCharset)) . "&";
+                    }
+                    $requestUrl = substr($requestUrl, 0, -1);
+                    //发起HTTP请求
+                    try {
+                        $resp = $this->curl($requestUrl, $apiParams);
+                    } catch (Exception $e) {
+                        $this->logCommunicationError($sysParams["method"], $requestUrl, "HTTP_ERROR_" . $e->getCode(), $e->getMessage());
+                        return false;
+                    }
+
+                    // 将返回结果转换本地文件编码
+                    $r = iconv($this->postCharset, $this->fileCharset . "//IGNORE", $resp);
+
+                    $respObject = json_decode($r);
+                    $resultCode = $respObject->alipay_open_app_alipaycert_download_response->code;
+                    $certContent = $respObject->alipay_open_app_alipaycert_download_response->alipay_cert_content;
+
+                    if (!empty($resultCode) && $resultCode == 10000 && !empty($certContent)) {
+                        $cert = base64_decode($certContent);
+                        $certCheck = true;
+                        if(!empty($this->alipayRootCertContent) && $this->isCheckAlipayPublicCert){
+                            $certCheck = isTrusted($cert,$this->alipayRootCertContent);
+                        }
+                        if($certCheck){
+                            $pkey = openssl_pkey_get_public($cert);
+                            $keyData = openssl_pkey_get_details($pkey);
+                            $public_key = str_replace('-----BEGIN PUBLIC KEY-----', '', $keyData['key']);
+                            $public_key = trim(str_replace('-----END PUBLIC KEY-----', '', $public_key));
+                            $this->alipayrsaPublicKey = $public_key;
+                            $checkResult = $this->verify($signData->signSourceData, $signData->sign, $this->alipayrsaPublicKey, $this->signType);
+                        }else{
+                            //如果下载下来的支付宝公钥证书使用根证书检查失败直接抛异常
+                            throw new Exception("check sign Fail! [sign=" . $signData->sign . ", signSourceData=" . $signData->signSourceData . "]");
+                        }
+                    }
+
+                    if(!$checkResult){
+                        if (strpos($signData->signSourceData, "\\/") > 0) {
+                            $signData->signSourceData = str_replace("\\/", "/", $signData->signSourceData);
+                            $checkResult = $this->verify($signData->signSourceData, $signData->sign, $this->alipayPublicKey, $this->signType);
+                            if (!$checkResult) {
+                                throw new Exception("check sign Fail! [sign=" . $signData->sign . ", signSourceData=" . $signData->signSourceData . "]");
+                            }
+                        } else {
+                            throw new Exception("check sign Fail! [sign=" . $signData->sign . ", signSourceData=" . $signData->signSourceData . "]");
+                        }
+                    }
+
+                }
+            }
+        }
+    }
+
+
+    function parserResponseSubCode($request, $responseContent, $respObject, $format) {
+        if ("json" == $format) {
+            $apiName = $request->getApiMethodName();
+            $rootNodeName = str_replace(".", "_", $apiName) . $this->RESPONSE_SUFFIX;
+            $errorNodeName = $this->ERROR_RESPONSE;
+            $rootIndex = strpos($responseContent, $rootNodeName);
+            $errorIndex = strpos($responseContent, $errorNodeName);
+            if ($rootIndex > 0) {
+                // 内部节点对象
+                $rInnerObject = $respObject->$rootNodeName;
+            } elseif ($errorIndex > 0) {
+                $rInnerObject = $respObject->$errorNodeName;
+            } else {
+                return null;
+            }
+            // 存在属性则返回对应值
+            if (isset($rInnerObject->sub_code)) {
+                return $rInnerObject->sub_code;
+            } else {
+                return null;
+            }
+        } elseif ("xml" == $format) {
+            // xml格式sub_code在同一层级
+            return $respObject->sub_code;
+        }
+    }
+
+    function verify($data, $sign, $rsaPublicKeyFilePath, $signType = 'RSA') {
+        if($this->checkEmpty($this->alipayPublicKey)){
+            $pubKey= $this->alipayrsaPublicKey;
+            $res = "-----BEGIN PUBLIC KEY-----\n" .
+                wordwrap($pubKey, 64, "\n", true) .
+                "\n-----END PUBLIC KEY-----";
+        }else {
+            //读取公钥文件
+            $pubKey = file_get_contents($rsaPublicKeyFilePath);
+            //转换为openssl格式密钥
+            $res = openssl_get_publickey($pubKey);
+        }
+        ($res) or die('支付宝RSA公钥错误。请检查公钥文件格式是否正确');
+        //调用openssl内置方法验签,返回bool值
+        $result = FALSE;
+        if ("RSA2" == $signType) {
+            $result = (openssl_verify($data, base64_decode($sign), $res, OPENSSL_ALGO_SHA256)===1);
+        } else {
+            $result = (openssl_verify($data, base64_decode($sign), $res)===1);
+        }
+        if(!$this->checkEmpty($this->alipayPublicKey)) {
+            //释放资源
+            openssl_free_key($res);
+        }
+        return $result;
+    }
+
+
+    // 获取加密内容
+    private function encryptJSONSignSource($request, $responseContent) {
+        $parsetItem = $this->parserEncryptJSONSignSource($request, $responseContent);
+        $bodyIndexContent = substr($responseContent, 0, $parsetItem->startIndex);
+        $bodyEndContent = substr($responseContent, $parsetItem->endIndex, strlen($responseContent) + 1 - $parsetItem->endIndex);
+        $bizContent = decrypt($parsetItem->encryptContent, $this->encryptKey);
+        return $bodyIndexContent . $bizContent . $bodyEndContent;
+    }
+
+
+    private function parserEncryptJSONSignSource($request, $responseContent) {
+        $apiName = $request->getApiMethodName();
+        $rootNodeName = str_replace(".", "_", $apiName) . $this->RESPONSE_SUFFIX;
+        $rootIndex = strpos($responseContent, $rootNodeName);
+        $errorIndex = strpos($responseContent, $this->ERROR_RESPONSE);
+        if ($rootIndex > 0) {
+            return $this->parserEncryptJSONItem($responseContent, $rootNodeName, $rootIndex);
+        } else if ($errorIndex > 0) {
+            return $this->parserEncryptJSONItem($responseContent, $this->ERROR_RESPONSE, $errorIndex);
+        } else {
+            return null;
+        }
+    }
+
+    private function parserEncryptJSONItem($responseContent, $nodeName, $nodeIndex) {
+        $signDataStartIndex = $nodeIndex + strlen($nodeName) + 2;
+        if(strrpos($responseContent, $this->ALIPAY_CERT_SN)){
+            $signIndex = strpos($responseContent, "\"" . $this->ALIPAY_CERT_SN . "\"");
+        }else{
+            $signIndex = strpos($responseContent, "\"" . $this->SIGN_NODE_NAME . "\"");
+        }
+
+        // 签名前-逗号
+        $signDataEndIndex = $signIndex - 1;
+        if ($signDataEndIndex < 0) {
+            $signDataEndIndex = strlen($responseContent)-1 ;
+        }
+        $indexLen = $signDataEndIndex - $signDataStartIndex;
+        $encContent = substr($responseContent, $signDataStartIndex+1, $indexLen-2);
+        $encryptParseItem = new EncryptParseItem();
+        $encryptParseItem->encryptContent = $encContent;
+        $encryptParseItem->startIndex = $signDataStartIndex;
+        $encryptParseItem->endIndex = $signDataEndIndex;
+        return $encryptParseItem;
+    }
+
+    // 获取加密内容
+    private function encryptXMLSignSource($request, $responseContent) {
+        $parsetItem = $this->parserEncryptXMLSignSource($request, $responseContent);
+        $bodyIndexContent = substr($responseContent, 0, $parsetItem->startIndex);
+        $bodyEndContent = substr($responseContent, $parsetItem->endIndex, strlen($responseContent) + 1 - $parsetItem->endIndex);
+        $bizContent = decrypt($parsetItem->encryptContent, $this->encryptKey);
+        return $bodyIndexContent . $bizContent . $bodyEndContent;
+
+    }
+
+    private function parserEncryptXMLSignSource($request, $responseContent) {
+        $apiName = $request->getApiMethodName();
+        $rootNodeName = str_replace(".", "_", $apiName) . $this->RESPONSE_SUFFIX;
+        $rootIndex = strpos($responseContent, $rootNodeName);
+        $errorIndex = strpos($responseContent, $this->ERROR_RESPONSE);
+        if ($rootIndex > 0) {
+            return $this->parserEncryptXMLItem($responseContent, $rootNodeName, $rootIndex);
+        } else if ($errorIndex > 0) {
+            return $this->parserEncryptXMLItem($responseContent, $this->ERROR_RESPONSE, $errorIndex);
+        } else {
+            return null;
+        }
+    }
+
+    private function parserEncryptXMLItem($responseContent, $nodeName, $nodeIndex) {
+        $signDataStartIndex = $nodeIndex + strlen($nodeName) + 1;
+        $xmlStartNode="<".$this->ENCRYPT_XML_NODE_NAME.">";
+        $xmlEndNode="</".$this->ENCRYPT_XML_NODE_NAME.">";
+        $indexOfXmlNode=strpos($responseContent,$xmlEndNode);
+        if($indexOfXmlNode<0){
+            $item = new EncryptParseItem();
+            $item->encryptContent = null;
+            $item->startIndex = 0;
+            $item->endIndex = 0;
+            return $item;
+        }
+        $startIndex=$signDataStartIndex+strlen($xmlStartNode);
+        $bizContentLen=$indexOfXmlNode-$startIndex;
+        $bizContent=substr($responseContent,$startIndex,$bizContentLen);
+        $encryptParseItem = new EncryptParseItem();
+        $encryptParseItem->encryptContent = $bizContent;
+        $encryptParseItem->startIndex = $signDataStartIndex;
+        $encryptParseItem->endIndex = $indexOfXmlNode+strlen($xmlEndNode);
+        return $encryptParseItem;
+    }
+
+    function echoDebug($content) {
+        if ($this->debugInfo) {
+            echo "<br/>" . $content;
+        }
+    }
+}

+ 527 - 0
application/common/library/alipay/aop/AopCertification.php

@@ -0,0 +1,527 @@
+<?php
+
+/**
+ * 验证支付宝公钥证书是否可信
+ * @param $alipayCert 支付宝公钥证书
+ * @param $rootCert 支付宝根证书
+ */
+function isTrusted($alipayCert, $rootCert)
+{
+    $alipayCerts = readPemCertChain($alipayCert);
+    $rootCerts = readPemCertChain($rootCert);
+    if (verifyCertChain($alipayCerts, $rootCerts)) {
+        return verifySignature($alipayCert, $rootCert);
+    } else {
+        return false;
+    }
+
+}
+
+function verifySignature($alipayCert, $rootCert)
+{
+    $alipayCertArray = explode("-----END CERTIFICATE-----", $alipayCert);
+    $rootCertArray = explode("-----END CERTIFICATE-----", $rootCert);
+    $length = count($rootCertArray) - 1;
+    $checkSign = isCertSigner($alipayCertArray[0] . "-----END CERTIFICATE-----", $alipayCertArray[1] . "-----END CERTIFICATE-----");
+    if (!$checkSign) {
+        $checkSign = isCertSigner($alipayCertArray[1] . "-----END CERTIFICATE-----", $alipayCertArray[0] . "-----END CERTIFICATE-----");
+        if ($checkSign) {
+            $issuer = openssl_x509_parse($alipayCertArray[0] . "-----END CERTIFICATE-----")['issuer'];
+            for ($i = 0; $i < $length; $i++) {
+                $subject = openssl_x509_parse($rootCertArray[$i] . "-----END CERTIFICATE-----")['subject'];
+                if ($issuer == $subject) {
+                    isCertSigner($alipayCertArray[0] . "-----END CERTIFICATE-----", $rootCertArray[$i] . $rootCertArray);
+                    return $checkSign;
+                }
+            }
+        } else {
+            return $checkSign;
+        }
+    } else {
+        $issuer = openssl_x509_parse($alipayCertArray[1] . "-----END CERTIFICATE-----")['issuer'];
+        for ($i = 0; $i < $length; $i++) {
+            $subject = openssl_x509_parse($rootCertArray[$i] . "-----END CERTIFICATE-----")['subject'];
+            if ($issuer == $subject) {
+                $checkSign = isCertSigner($alipayCertArray[1] . "-----END CERTIFICATE-----", $rootCertArray[$i] . "-----END CERTIFICATE-----");
+                return $checkSign;
+            }
+        }
+        return $checkSign;
+    }
+}
+
+function readPemCertChain($cert)
+{
+    $array = explode("-----END CERTIFICATE-----", $cert);
+    $certs[] = null;
+    for ($i = 0; $i < count($array) - 1; $i++) {
+        $certs[$i] = openssl_x509_parse($array[$i] . "-----END CERTIFICATE-----");
+    }
+    return $certs;
+}
+
+function verifyCert($prev, $rootCerts)
+{
+    $nowTime = time();
+    if ($nowTime < $prev['validFrom_time_t']) {
+        echo "证书未激活";
+        return false;
+    }
+    if ($nowTime > $prev['validTo_time_t']) {
+        echo "证书已经过期";
+        return false;
+    }
+    $subjectMap = null;
+    for ($i = 0; $i < count($rootCerts); $i++) {
+        $subjectDN = array2string($rootCerts[$i]['subject']);
+        $subjectMap[$subjectDN] = $rootCerts[$i];
+    }
+    $issuerDN = array2string(($prev['issuer']));
+    if (!array_key_exists($issuerDN, $subjectMap)) {
+        echo "证书链验证失败";
+        return false;
+    }
+    return true;
+}
+
+/**
+ * 验证证书链是否是信任证书库中证书签发的
+ * @param $alipayCerts 目标验证证书列表
+ * @param $rootCerts 可信根证书列表
+ */
+function verifyCertChain($alipayCerts, $rootCerts)
+{
+    $sorted = sortByDn($alipayCerts);
+    if (!$sorted) {
+        echo "证书链验证失败:不是完整的证书链";
+        return false;
+    }
+    //先验证第一个证书是不是信任库中证书签发的
+    $prev = $alipayCerts[0];
+    $firstOK = verifyCert($prev, $rootCerts);
+    $length = count($alipayCerts);
+    if (!$firstOK || $length == 1) {
+        return $firstOK;
+    }
+
+    $nowTime = time();
+    //验证证书链
+    for ($i = 1; $i < $length; $i++) {
+        $cert = $alipayCerts[$i];
+        if ($nowTime < $cert['validFrom_time_t']) {
+            echo "证书未激活";
+            return false;
+        }
+        if ($nowTime > $cert['validTo_time_t']) {
+            echo "证书已经过期";
+            return false;
+        }
+    }
+    return true;
+}
+
+/**
+ * 将证书链按照完整的签发顺序进行排序,排序后证书链为:[issuerA, subjectA]-[issuerA, subjectB]-[issuerB, subjectC]-[issuerC, subjectD]...
+ * @param $certs 证书链
+ */
+function sortByDn(&$certs)
+{
+    //是否包含自签名证书
+    $hasSelfSignedCert = false;
+    $subjectMap = null;
+    $issuerMap = null;
+    for ($i = 0; $i < count($certs); $i++) {
+        if (isSelfSigned($certs[$i])) {
+            if ($hasSelfSignedCert) {
+                return false;
+            }
+            $hasSelfSignedCert = true;
+        }
+        $subjectDN = array2string($certs[$i]['subject']);
+        $issuerDN = array2string(($certs[$i]['issuer']));
+        $subjectMap[$subjectDN] = $certs[$i];
+        $issuerMap[$issuerDN] = $certs[$i];
+    }
+    $certChain = null;
+    addressingUp($subjectMap, $certChain, $certs[0]);
+    addressingDown($issuerMap, $certChain, $certs[0]);
+
+    //说明证书链不完整
+    if (count($certs) != count($certChain)) {
+        return false;
+    }
+    //将证书链复制到原先的数据
+    for ($i = 0; $i < count($certs); $i++) {
+        $certs[$i] = $certChain[count($certs) - $i - 1];
+    }
+    return true;
+}
+
+/**
+ * 验证证书是否是自签发的
+ * @param $cert 目标证书
+ */
+function isSelfSigned($cert)
+{
+    $subjectDN = array2string($cert['subject']);
+    $issuerDN = array2string($cert['issuer']);
+    return ($subjectDN == $issuerDN);
+}
+
+
+function array2string($array)
+{
+    $string = [];
+    if ($array && is_array($array)) {
+        foreach ($array as $key => $value) {
+            $string[] = $key . '=' . $value;
+        }
+    }
+    return implode(',', $string);
+}
+
+/**
+ * 向上构造证书链
+ * @param $subjectMap 主题和证书的映射
+ * @param $certChain 证书链
+ * @param $current 当前需要插入证书链的证书,include
+ */
+function addressingUp($subjectMap, &$certChain, $current)
+{
+    $certChain[] = $current;
+    if (isSelfSigned($current)) {
+        return;
+    }
+    $issuerDN = array2string($current['issuer']);
+
+    if (!array_key_exists($issuerDN, $subjectMap)) {
+        return;
+    }
+    addressingUp($subjectMap, $certChain, $subjectMap[$issuerDN]);
+}
+
+/**
+ * 向下构造证书链
+ * @param $issuerMap 签发者和证书的映射
+ * @param $certChain 证书链
+ * @param $current 当前需要插入证书链的证书,exclude
+ */
+function addressingDown($issuerMap, &$certChain, $current)
+{
+    $subjectDN = array2string($current['subject']);
+    if (!array_key_exists($subjectDN, $issuerMap)) {
+        return $certChain;
+    }
+    $certChain[] = $issuerMap[$subjectDN];
+    addressingDown($issuerMap, $certChain, $issuerMap[$subjectDN]);
+}
+
+
+/**
+ * Extract signature from der encoded cert.
+ * Expects x509 der encoded certificate consisting of a section container
+ * containing 2 sections and a bitstream.  The bitstream contains the
+ * original encrypted signature, encrypted by the public key of the issuing
+ * signer.
+ * @param string $der
+ * @return string on success
+ * @return bool false on failures
+ */
+function extractSignature($der = false)
+{
+    if (strlen($der) < 5) {
+        return false;
+    }
+    // skip container sequence
+    $der = substr($der, 4);
+    // now burn through two sequences and the return the final bitstream
+    while (strlen($der) > 1) {
+        $class = ord($der[0]);
+        $classHex = dechex($class);
+        switch ($class) {
+            // BITSTREAM
+            case 0x03:
+                $len = ord($der[1]);
+                $bytes = 0;
+                if ($len & 0x80) {
+                    $bytes = $len & 0x0f;
+                    $len = 0;
+                    for ($i = 0; $i < $bytes; $i++) {
+                        $len = ($len << 8) | ord($der[$i + 2]);
+                    }
+                }
+                return substr($der, 3 + $bytes, $len);
+                break;
+            // SEQUENCE
+            case 0x30:
+                $len = ord($der[1]);
+                $bytes = 0;
+                if ($len & 0x80) {
+                    $bytes = $len & 0x0f;
+                    $len = 0;
+                    for ($i = 0; $i < $bytes; $i++) {
+                        $len = ($len << 8) | ord($der[$i + 2]);
+                    }
+                }
+                $contents = substr($der, 2 + $bytes, $len);
+                $der = substr($der, 2 + $bytes + $len);
+                break;
+            default:
+                return false;
+                break;
+        }
+    }
+    return false;
+}
+
+/**
+ * Get signature algorithm oid from der encoded signature data.
+ * Expects decrypted signature data from a certificate in der format.
+ * This ASN1 data should contain the following structure:
+ * SEQUENCE
+ *    SEQUENCE
+ *       OID    (signature algorithm)
+ *       NULL
+ * OCTET STRING (signature hash)
+ * @return bool false on failures
+ * @return string oid
+ */
+function getSignatureAlgorithmOid($der = null)
+{
+    // Validate this is the der we need...
+    if (!is_string($der) or strlen($der) < 5) {
+        return false;
+    }
+    $bit_seq1 = 0;
+    $bit_seq2 = 2;
+    $bit_oid = 4;
+    if (ord($der[$bit_seq1]) !== 0x30) {
+        die('Invalid DER passed to getSignatureAlgorithmOid()');
+    }
+    if (ord($der[$bit_seq2]) !== 0x30) {
+        die('Invalid DER passed to getSignatureAlgorithmOid()');
+    }
+    if (ord($der[$bit_oid]) !== 0x06) {
+        die('Invalid DER passed to getSignatureAlgorithmOid');
+    }
+    // strip out what we don't need and get the oid
+    $der = substr($der, $bit_oid);
+    // Get the oid
+    $len = ord($der[1]);
+    $bytes = 0;
+    if ($len & 0x80) {
+        $bytes = $len & 0x0f;
+        $len = 0;
+        for ($i = 0; $i < $bytes; $i++) {
+            $len = ($len << 8) | ord($der[$i + 2]);
+        }
+    }
+    $oid_data = substr($der, 2 + $bytes, $len);
+    // Unpack the OID
+    $oid = floor(ord($oid_data[0]) / 40);
+    $oid .= '.' . ord($oid_data[0]) % 40;
+    $value = 0;
+    $i = 1;
+    while ($i < strlen($oid_data)) {
+        $value = $value << 7;
+        $value = $value | (ord($oid_data[$i]) & 0x7f);
+        if (!(ord($oid_data[$i]) & 0x80)) {
+            $oid .= '.' . $value;
+            $value = 0;
+        }
+        $i++;
+    }
+    return $oid;
+}
+
+/**
+ * Get signature hash from der encoded signature data.
+ * Expects decrypted signature data from a certificate in der format.
+ * This ASN1 data should contain the following structure:
+ * SEQUENCE
+ *    SEQUENCE
+ *       OID    (signature algorithm)
+ *       NULL
+ * OCTET STRING (signature hash)
+ * @return bool false on failures
+ * @return string hash
+ */
+function getSignatureHash($der = null)
+{
+    // Validate this is the der we need...
+    if (!is_string($der) or strlen($der) < 5) {
+        return false;
+    }
+    if (ord($der[0]) !== 0x30) {
+        die('Invalid DER passed to getSignatureHash()');
+    }
+    // strip out the container sequence
+    $der = substr($der, 2);
+    if (ord($der[0]) !== 0x30) {
+        die('Invalid DER passed to getSignatureHash()');
+    }
+    // Get the length of the first sequence so we can strip it out.
+    $len = ord($der[1]);
+    $bytes = 0;
+    if ($len & 0x80) {
+        $bytes = $len & 0x0f;
+        $len = 0;
+        for ($i = 0; $i < $bytes; $i++) {
+            $len = ($len << 8) | ord($der[$i + 2]);
+        }
+    }
+    $der = substr($der, 2 + $bytes + $len);
+    // Now we should have an octet string
+    if (ord($der[0]) !== 0x04) {
+        die('Invalid DER passed to getSignatureHash()');
+    }
+    $len = ord($der[1]);
+    $bytes = 0;
+    if ($len & 0x80) {
+        $bytes = $len & 0x0f;
+        $len = 0;
+        for ($i = 0; $i < $bytes; $i++) {
+            $len = ($len << 8) | ord($der[$i + 2]);
+        }
+    }
+    return bin2hex(substr($der, 2 + $bytes, $len));
+}
+
+/**
+ * Determine if one cert was used to sign another
+ * Note that more than one CA cert can give a positive result, some certs
+ * re-issue signing certs after having only changed the expiration dates.
+ * @param string $cert - PEM encoded cert
+ * @param string $caCert - PEM encoded cert that possibly signed $cert
+ * @return bool
+ */
+function isCertSigner($certPem = null, $caCertPem = null)
+{
+    if (!function_exists('openssl_pkey_get_public')) {
+        die('Need the openssl_pkey_get_public() function.');
+    }
+    if (!function_exists('openssl_public_decrypt')) {
+        die('Need the openssl_public_decrypt() function.');
+    }
+    if (!function_exists('hash')) {
+        die('Need the php hash() function.');
+    }
+    if (empty($certPem) or empty($caCertPem)) {
+        return false;
+    }
+    // Convert the cert to der for feeding to extractSignature.
+    $certDer = pemToDer($certPem);
+    if (!is_string($certDer)) {
+        die('invalid certPem');
+    }
+    // Grab the encrypted signature from the der encoded cert.
+    $encryptedSig = extractSignature($certDer);
+    if (!is_string($encryptedSig)) {
+        die('Failed to extract encrypted signature from certPem.');
+    }
+    // Extract the public key from the ca cert, which is what has
+    // been used to encrypt the signature in the cert.
+    $pubKey = openssl_pkey_get_public($caCertPem);
+    if ($pubKey === false) {
+        die('Failed to extract the public key from the ca cert.');
+    }
+    // Attempt to decrypt the encrypted signature using the CA's public
+    // key, returning the decrypted signature in $decryptedSig.  If
+    // it can't be decrypted, this ca was not used to sign it for sure...
+    $rc = openssl_public_decrypt($encryptedSig, $decryptedSig, $pubKey);
+    if ($rc === false) {
+        return false;
+    }
+    // We now have the decrypted signature, which is der encoded
+    // asn1 data containing the signature algorithm and signature hash.
+    // Now we need what was originally hashed by the issuer, which is
+    // the original DER encoded certificate without the issuer and
+    // signature information.
+    $origCert = stripSignerAsn($certDer);
+    if ($origCert === false) {
+        die('Failed to extract unsigned cert.');
+    }
+    // Get the oid of the signature hash algorithm, which is required
+    // to generate our own hash of the original cert.  This hash is
+    // what will be compared to the issuers hash.
+    $oid = getSignatureAlgorithmOid($decryptedSig);
+    if ($oid === false) {
+        die('Failed to determine the signature algorithm.');
+    }
+    switch ($oid) {
+        case '1.2.840.113549.2.2':
+            $algo = 'md2';
+            break;
+        case '1.2.840.113549.2.4':
+            $algo = 'md4';
+            break;
+        case '1.2.840.113549.2.5':
+            $algo = 'md5';
+            break;
+        case '1.3.14.3.2.18':
+            $algo = 'sha';
+            break;
+        case '1.3.14.3.2.26':
+            $algo = 'sha1';
+            break;
+        case '2.16.840.1.101.3.4.2.1':
+            $algo = 'sha256';
+            break;
+        case '2.16.840.1.101.3.4.2.2':
+            $algo = 'sha384';
+            break;
+        case '2.16.840.1.101.3.4.2.3':
+            $algo = 'sha512';
+            break;
+        default:
+            die('Unknown signature hash algorithm oid: ' . $oid);
+            break;
+    }
+    // Get the issuer generated hash from the decrypted signature.
+    $decryptedHash = getSignatureHash($decryptedSig);
+    // Ok, hash the original unsigned cert with the same algorithm
+    // and if it matches $decryptedHash we have a winner.
+    $certHash = hash($algo, $origCert);
+    return ($decryptedHash === $certHash);
+}
+
+/**
+ * Convert pem encoded certificate to DER encoding
+ * @return string $derEncoded on success
+ * @return bool false on failures
+ */
+function pemToDer($pem = null)
+{
+    if (!is_string($pem)) {
+        return false;
+    }
+    $cert_split = preg_split('/(-----((BEGIN)|(END)) CERTIFICATE-----)/', $pem);
+    if (!isset($cert_split[1])) {
+        return false;
+    }
+    return base64_decode($cert_split[1]);
+}
+
+/**
+ * Obtain der cert with issuer and signature sections stripped.
+ * @param string $der - der encoded certificate
+ * @return string $der on success
+ * @return bool false on failures.
+ */
+function stripSignerAsn($der = null)
+{
+    if (!is_string($der) or strlen($der) < 8) {
+        return false;
+    }
+    $bit = 4;
+    $len = ord($der[($bit + 1)]);
+    $bytes = 0;
+    if ($len & 0x80) {
+        $bytes = $len & 0x0f;
+        $len = 0;
+        for ($i = 0; $i < $bytes; $i++) {
+            $len = ($len << 8) | ord($der[$bit + $i + 2]);
+        }
+    }
+    return substr($der, 4, $len + 4);
+}

+ 1299 - 0
application/common/library/alipay/aop/AopClient.php

@@ -0,0 +1,1299 @@
+<?php
+namespace app\common\library;
+use think\Controller;
+require_once 'AopEncrypt.php';
+require_once 'EncryptParseItem.php';
+require_once 'EncryptResponseData.php';
+require_once 'SignData.php';
+
+class AopClient
+{
+    //应用ID
+    public $appId;
+
+    //私钥文件路径
+    public $rsaPrivateKeyFilePath;
+
+    //私钥值
+    public $rsaPrivateKey;
+
+    //网关
+    public $gatewayUrl = "https://openapi.alipay.com/gateway.do";
+    //返回数据格式
+    public $format = "json";
+    //api版本
+    public $apiVersion = "1.0";
+
+    // 表单提交字符集编码
+    public $postCharset = "UTF-8";
+
+    //使用文件读取文件格式,请只传递该值
+    public $alipayPublicKey = null;
+
+    //使用读取字符串格式,请只传递该值
+    public $alipayrsaPublicKey;
+
+
+    public $debugInfo = false;
+
+    private $fileCharset = "UTF-8";
+
+    private $RESPONSE_SUFFIX = "_response";
+
+    private $ERROR_RESPONSE = "error_response";
+
+    private $SIGN_NODE_NAME = "sign";
+
+
+    //加密XML节点名称
+    private $ENCRYPT_XML_NODE_NAME = "response_encrypted";
+
+    private $needEncrypt = false;
+
+
+    //签名类型
+    public $signType = "RSA";
+
+
+    //加密密钥和类型
+
+    public $encryptKey;
+
+    public $encryptType = "AES";
+
+    private $targetServiceUrl = "";
+
+    protected $alipaySdkVersion = "alipay-sdk-php-20200415";
+
+    public function generateSign($params, $signType = "RSA")
+    {
+        return $this->sign($this->getSignContent($params), $signType);
+    }
+
+    public function rsaSign($params, $signType = "RSA")
+    {
+        return $this->sign($this->getSignContent($params), $signType);
+    }
+
+    public function getSignContent($params)
+    {
+        ksort($params);
+
+        $stringToBeSigned = "";
+        $i = 0;
+        foreach ($params as $k => $v) {
+            if (false === $this->checkEmpty($v) && "@" != substr($v, 0, 1)) {
+                // 转换成目标字符集
+                $v = $this->characet($v, $this->postCharset);
+
+                if ($i == 0) {
+                    $stringToBeSigned .= "$k" . "=" . "$v";
+                } else {
+                    $stringToBeSigned .= "&" . "$k" . "=" . "$v";
+                }
+                $i++;
+            }
+        }
+
+        unset ($k, $v);
+        return $stringToBeSigned;
+    }
+
+
+    //此方法对value做urlencode
+    public function getSignContentUrlencode($params)
+    {
+        ksort($params);
+
+        $stringToBeSigned = "";
+        $i = 0;
+        foreach ($params as $k => $v) {
+            if (false === $this->checkEmpty($v) && "@" != substr($v, 0, 1)) {
+
+                // 转换成目标字符集
+                $v = $this->characet($v, $this->postCharset);
+
+                if ($i == 0) {
+                    $stringToBeSigned .= "$k" . "=" . urlencode($v);
+                } else {
+                    $stringToBeSigned .= "&" . "$k" . "=" . urlencode($v);
+                }
+                $i++;
+            }
+        }
+
+        unset ($k, $v);
+        return $stringToBeSigned;
+    }
+
+    protected function sign($data, $signType = "RSA")
+    {
+        if ($this->checkEmpty($this->rsaPrivateKeyFilePath)) {
+            $priKey = $this->rsaPrivateKey;
+            $res = "-----BEGIN RSA PRIVATE KEY-----\n" .
+                wordwrap($priKey, 64, "\n", true) .
+                "\n-----END RSA PRIVATE KEY-----";
+        } else {
+            $priKey = file_get_contents($this->rsaPrivateKeyFilePath);
+            $res = openssl_get_privatekey($priKey);
+        }
+
+        ($res) or die('您使用的私钥格式错误,请检查RSA私钥配置');
+
+        if ("RSA2" == $signType) {
+            openssl_sign($data, $sign, $res, OPENSSL_ALGO_SHA256);
+        } else {
+            openssl_sign($data, $sign, $res);
+        }
+
+        if (!$this->checkEmpty($this->rsaPrivateKeyFilePath)) {
+            openssl_free_key($res);
+        }
+        $sign = base64_encode($sign);
+        return $sign;
+    }
+
+    /**
+     * RSA单独签名方法,未做字符串处理,字符串处理见getSignContent()
+     * @param $data 待签名字符串
+     * @param $privatekey 商户私钥,根据keyfromfile来判断是读取字符串还是读取文件,false:填写私钥字符串去回车和空格 true:填写私钥文件路径
+     * @param $signType 签名方式,RSA:SHA1     RSA2:SHA256
+     * @param $keyfromfile 私钥获取方式,读取字符串还是读文件
+     * @return string
+     */
+    public function alonersaSign($data, $privatekey, $signType = "RSA", $keyfromfile = false)
+    {
+
+        if (!$keyfromfile) {
+            $priKey = $privatekey;
+            $res = "-----BEGIN RSA PRIVATE KEY-----\n" .
+                wordwrap($priKey, 64, "\n", true) .
+                "\n-----END RSA PRIVATE KEY-----";
+        } else {
+            $priKey = file_get_contents($privatekey);
+            $res = openssl_get_privatekey($priKey);
+        }
+
+        ($res) or die('您使用的私钥格式错误,请检查RSA私钥配置');
+
+        if ("RSA2" == $signType) {
+            openssl_sign($data, $sign, $res, OPENSSL_ALGO_SHA256);
+        } else {
+            openssl_sign($data, $sign, $res);
+        }
+
+        if ($keyfromfile) {
+            openssl_free_key($res);
+        }
+        $sign = base64_encode($sign);
+        return $sign;
+    }
+
+
+    protected function curl($url, $postFields = null)
+    {
+        $ch = curl_init();
+        curl_setopt($ch, CURLOPT_URL, $url);
+        curl_setopt($ch, CURLOPT_FAILONERROR, false);
+        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
+
+        $postBodyString = "";
+        $encodeArray = Array();
+        $postMultipart = false;
+
+
+        if (is_array($postFields) && 0 < count($postFields)) {
+
+            foreach ($postFields as $k => $v) {
+                if ("@" != substr($v, 0, 1)) //判断是不是文件上传
+                {
+
+                    $postBodyString .= "$k=" . urlencode($this->characet($v, $this->postCharset)) . "&";
+                    $encodeArray[$k] = $this->characet($v, $this->postCharset);
+                } else //文件上传用multipart/form-data,否则用www-form-urlencoded
+                {
+                    $postMultipart = true;
+                    $encodeArray[$k] = new \CURLFile(substr($v, 1));
+                }
+
+            }
+            unset ($k, $v);
+            curl_setopt($ch, CURLOPT_POST, true);
+            if ($postMultipart) {
+                curl_setopt($ch, CURLOPT_POSTFIELDS, $encodeArray);
+            } else {
+                curl_setopt($ch, CURLOPT_POSTFIELDS, substr($postBodyString, 0, -1));
+            }
+        }
+
+        if (!$postMultipart) {
+            $headers = array('content-type: application/x-www-form-urlencoded;charset=' . $this->postCharset);
+            curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
+        }
+
+        $reponse = curl_exec($ch);
+
+        if (curl_errno($ch)) {
+
+            throw new Exception(curl_error($ch), 0);
+        } else {
+            $httpStatusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+            if (200 !== $httpStatusCode) {
+                throw new Exception($reponse, $httpStatusCode);
+            }
+        }
+
+        curl_close($ch);
+        return $reponse;
+    }
+
+    protected function getMillisecond()
+    {
+        list($s1, $s2) = explode(' ', microtime());
+        return (float)sprintf('%.0f', (floatval($s1) + floatval($s2)) * 1000);
+    }
+
+
+    protected function logCommunicationError($apiName, $requestUrl, $errorCode, $responseTxt)
+    {
+        $logData = array(
+            date("Y-m-d H:i:s"),
+            $apiName,
+            $this->appId,
+            PHP_OS,
+            $this->alipaySdkVersion,
+            $requestUrl,
+            $errorCode,
+            str_replace("\n", "", $responseTxt)
+        );
+
+        echo json_encode($logData);
+    }
+
+    /**
+     * 生成用于调用收银台SDK的字符串
+     * @param $request SDK接口的请求参数对象
+     * @param $appAuthToken 三方应用授权token
+     * @return string
+     */
+    public function sdkExecute($request, $appAuthToken = null)
+    {
+
+        $this->setupCharsets($request);
+
+        $params['app_id'] = $this->appId;
+        $params['method'] = $request->getApiMethodName();
+        $params['format'] = $this->format;
+        $params['sign_type'] = $this->signType;
+        $params['timestamp'] = date("Y-m-d H:i:s");
+        $params['alipay_sdk'] = $this->alipaySdkVersion;
+        $params['charset'] = $this->postCharset;
+
+        $version = $request->getApiVersion();
+        $params['version'] = $this->checkEmpty($version) ? $this->apiVersion : $version;
+
+        if ($notify_url = $request->getNotifyUrl()) {
+            $params['notify_url'] = $notify_url;
+        }
+
+        $params['app_auth_token'] = $appAuthToken;
+
+        $dict = $request->getApiParas();
+        $params['biz_content'] = $dict['biz_content'];
+
+        ksort($params);
+
+        $params['sign'] = $this->generateSign($params, $this->signType);
+
+        foreach ($params as &$value) {
+            $value = $this->characet($value, $params['charset']);
+        }
+
+        return http_build_query($params);
+    }
+
+    /**
+     * 页面提交执行方法
+     * @param $request 跳转类接口的request
+     * @param string $httpmethod 提交方式,两个值可选:post、get;
+     * @param null $appAuthToken 三方应用授权token
+     * @return 构建好的、签名后的最终跳转URL(GET)或String形式的form(POST)
+     * @throws Exception
+     */
+    public function pageExecute($request, $httpmethod = "POST", $appAuthToken = null)
+    {
+
+        $this->setupCharsets($request);
+
+        if (strcasecmp($this->fileCharset, $this->postCharset)) {
+
+            // writeLog("本地文件字符集编码与表单提交编码不一致,请务必设置成一样,属性名分别为postCharset!");
+            throw new Exception("文件编码:[" . $this->fileCharset . "] 与表单提交编码:[" . $this->postCharset . "]两者不一致!");
+        }
+
+        $iv = null;
+
+        if (!$this->checkEmpty($request->getApiVersion())) {
+            $iv = $request->getApiVersion();
+        } else {
+            $iv = $this->apiVersion;
+        }
+
+        //组装系统参数
+        $sysParams["app_id"] = $this->appId;
+        $sysParams["version"] = $iv;
+        $sysParams["format"] = $this->format;
+        $sysParams["sign_type"] = $this->signType;
+        $sysParams["method"] = $request->getApiMethodName();
+        $sysParams["timestamp"] = date("Y-m-d H:i:s");
+        $sysParams["alipay_sdk"] = $this->alipaySdkVersion;
+        $sysParams["terminal_type"] = $request->getTerminalType();
+        $sysParams["terminal_info"] = $request->getTerminalInfo();
+        $sysParams["prod_code"] = $request->getProdCode();
+        $sysParams["notify_url"] = $request->getNotifyUrl();
+        $sysParams["return_url"] = $request->getReturnUrl();
+        $sysParams["charset"] = $this->postCharset;
+        $sysParams["app_auth_token"] = $appAuthToken;
+
+        //获取业务参数
+        $apiParams = $request->getApiParas();
+
+        if (method_exists($request, "getNeedEncrypt") && $request->getNeedEncrypt()) {
+
+            $sysParams["encrypt_type"] = $this->encryptType;
+
+            if ($this->checkEmpty($apiParams['biz_content'])) {
+
+                throw new Exception(" api request Fail! The reason : encrypt request is not supperted!");
+            }
+
+            if ($this->checkEmpty($this->encryptKey) || $this->checkEmpty($this->encryptType)) {
+
+                throw new Exception(" encryptType and encryptKey must not null! ");
+            }
+
+            if ("AES" != $this->encryptType) {
+
+                throw new Exception("加密类型只支持AES");
+            }
+
+            // 执行加密
+            $enCryptContent = encrypt($apiParams['biz_content'], $this->encryptKey);
+            $apiParams['biz_content'] = $enCryptContent;
+
+        }
+
+        //print_r($apiParams);
+        $totalParams = array_merge($apiParams, $sysParams);
+
+        //待签名字符串
+        $preSignStr = $this->getSignContent($totalParams);
+
+        //签名
+        $totalParams["sign"] = $this->generateSign($totalParams, $this->signType);
+
+        if ("GET" == strtoupper($httpmethod)) {
+
+            //value做urlencode
+            $preString = $this->getSignContentUrlencode($totalParams);
+            //拼接GET请求串
+            $requestUrl = $this->gatewayUrl . "?" . $preString;
+
+            return $requestUrl;
+        } else {
+            //拼接表单字符串
+            return $this->buildRequestForm($totalParams);
+        }
+
+
+    }
+
+
+    /**
+     * 建立请求,以表单HTML形式构造(默认)
+     * @param $para_temp 请求参数数组
+     * @return 提交表单HTML文本
+     */
+    protected function buildRequestForm($para_temp)
+    {
+
+        $sHtml = "<form id='alipaysubmit' name='alipaysubmit' action='" . $this->gatewayUrl . "?charset=" . trim($this->postCharset) . "' method='POST'>";
+        while (list ($key, $val) = $this->fun_adm_each($para_temp)) {
+            if (false === $this->checkEmpty($val)) {
+                //$val = $this->characet($val, $this->postCharset);
+                $val = str_replace("'", "&apos;", $val);
+                //$val = str_replace("\"","&quot;",$val);
+                $sHtml .= "<input type='hidden' name='" . $key . "' value='" . $val . "'/>";
+            }
+        }
+
+        //submit按钮控件请不要含有name属性
+        $sHtml = $sHtml . "<input type='submit' value='ok' style='display:none;''></form>";
+
+        $sHtml = $sHtml . "<script>document.forms['alipaysubmit'].submit();</script>";
+
+        return $sHtml;
+    }
+
+    protected function fun_adm_each(&$array)
+    {
+        $res = array();
+        $key = key($array);
+        if ($key !== null) {
+            next($array);
+            $res[1] = $res['value'] = $array[$key];
+            $res[0] = $res['key'] = $key;
+        } else {
+            $res = false;
+        }
+        return $res;
+    }
+
+
+    public function execute($request, $authToken = null, $appInfoAuthtoken = null, $targetAppId = null)
+    {
+
+        $this->setupCharsets($request);
+
+        //如果两者编码不一致,会出现签名验签或者乱码
+        if (strcasecmp($this->fileCharset, $this->postCharset)) {
+
+            // writeLog("本地文件字符集编码与表单提交编码不一致,请务必设置成一样,属性名分别为postCharset!");
+            throw new Exception("文件编码:[" . $this->fileCharset . "] 与表单提交编码:[" . $this->postCharset . "]两者不一致!");
+        }
+
+        $iv = null;
+
+        if (!$this->checkEmpty($request->getApiVersion())) {
+            $iv = $request->getApiVersion();
+        } else {
+            $iv = $this->apiVersion;
+        }
+
+
+        //组装系统参数
+        $sysParams["app_id"] = $this->appId;
+        $sysParams["version"] = $iv;
+        $sysParams["format"] = $this->format;
+        $sysParams["sign_type"] = $this->signType;
+        $sysParams["method"] = $request->getApiMethodName();
+        $sysParams["timestamp"] = date("Y-m-d H:i:s");
+        $sysParams["auth_token"] = $authToken;
+        $sysParams["alipay_sdk"] = $this->alipaySdkVersion;
+        $sysParams["terminal_type"] = $request->getTerminalType();
+        $sysParams["terminal_info"] = $request->getTerminalInfo();
+        $sysParams["prod_code"] = $request->getProdCode();
+        $sysParams["notify_url"] = $request->getNotifyUrl();
+        $sysParams["charset"] = $this->postCharset;
+        $sysParams["app_auth_token"] = $appInfoAuthtoken;
+        $sysParams["target_app_id"] = $targetAppId;
+        if (!$this->checkEmpty($this->targetServiceUrl)) {
+            $sysParams["ws_service_url"] = $this->targetServiceUrl;
+        }
+
+
+        //获取业务参数
+        $apiParams = $request->getApiParas();
+
+        if (method_exists($request, "getNeedEncrypt") && $request->getNeedEncrypt()) {
+
+            $sysParams["encrypt_type"] = $this->encryptType;
+
+            if ($this->checkEmpty($apiParams['biz_content'])) {
+
+                throw new Exception(" api request Fail! The reason : encrypt request is not supperted!");
+            }
+
+            if ($this->checkEmpty($this->encryptKey) || $this->checkEmpty($this->encryptType)) {
+
+                throw new Exception(" encryptType and encryptKey must not null! ");
+            }
+
+            if ("AES" != $this->encryptType) {
+
+                throw new Exception("加密类型只支持AES");
+            }
+
+            // 执行加密
+            $enCryptContent = encrypt($apiParams['biz_content'], $this->encryptKey);
+            $apiParams['biz_content'] = $enCryptContent;
+
+        }
+
+
+        //签名
+        $sysParams["sign"] = $this->generateSign(array_merge($apiParams, $sysParams), $this->signType);
+
+
+        //系统参数放入GET请求串
+        $requestUrl = $this->gatewayUrl . "?";
+        foreach ($sysParams as $sysParamKey => $sysParamValue) {
+            $requestUrl .= "$sysParamKey=" . urlencode($this->characet($sysParamValue, $this->postCharset)) . "&";
+        }
+        $requestUrl = substr($requestUrl, 0, -1);
+
+
+        //发起HTTP请求
+        try {
+            $resp = $this->curl($requestUrl, $apiParams);
+        } catch (Exception $e) {
+
+            $this->logCommunicationError($sysParams["method"], $requestUrl, "HTTP_ERROR_" . $e->getCode(), $e->getMessage());
+            return false;
+        }
+
+        //解析AOP返回结果
+        $respWellFormed = false;
+
+
+        // 将返回结果转换本地文件编码
+        $r = iconv($this->postCharset, $this->fileCharset . "//IGNORE", $resp);
+
+
+        $signData = null;
+
+        if ("json" == $this->format) {
+
+            $respObject = json_decode($r);
+            if (null !== $respObject) {
+                $respWellFormed = true;
+                $signData = $this->parserJSONSignData($request, $resp, $respObject);
+            }
+        } else if ("xml" == $this->format) {
+            $disableLibxmlEntityLoader = libxml_disable_entity_loader(true);
+            $respObject = @ simplexml_load_string($resp);
+            if (false !== $respObject) {
+                $respWellFormed = true;
+
+                $signData = $this->parserXMLSignData($request, $resp);
+            }
+            libxml_disable_entity_loader($disableLibxmlEntityLoader);
+        }
+
+
+        //返回的HTTP文本不是标准JSON或者XML,记下错误日志
+        if (false === $respWellFormed) {
+            $this->logCommunicationError($sysParams["method"], $requestUrl, "HTTP_RESPONSE_NOT_WELL_FORMED", $resp);
+            return false;
+        }
+
+        // 验签
+        $this->checkResponseSign($request, $signData, $resp, $respObject);
+
+        // 解密
+        if (method_exists($request, "getNeedEncrypt") && $request->getNeedEncrypt()) {
+
+            if ("json" == $this->format) {
+
+
+                $resp = $this->encryptJSONSignSource($request, $resp);
+
+                // 将返回结果转换本地文件编码
+                $r = iconv($this->postCharset, $this->fileCharset . "//IGNORE", $resp);
+                $respObject = json_decode($r);
+            } else {
+
+                $resp = $this->encryptXMLSignSource($request, $resp);
+
+                $r = iconv($this->postCharset, $this->fileCharset . "//IGNORE", $resp);
+                $disableLibxmlEntityLoader = libxml_disable_entity_loader(true);
+                $respObject = @ simplexml_load_string($r);
+                libxml_disable_entity_loader($disableLibxmlEntityLoader);
+
+            }
+        }
+
+        return $respObject;
+    }
+
+    /**
+     * 转换字符集编码
+     * @param $data
+     * @param $targetCharset
+     * @return string
+     */
+    function characet($data, $targetCharset)
+    {
+
+        if (!empty($data)) {
+            $fileType = $this->fileCharset;
+            if (strcasecmp($fileType, $targetCharset) != 0) {
+                $data = mb_convert_encoding($data, $targetCharset, $fileType);
+                //				$data = iconv($fileType, $targetCharset.'//IGNORE', $data);
+            }
+        }
+
+
+        return $data;
+    }
+
+    public function exec($paramsArray)
+    {
+        if (!isset ($paramsArray["method"])) {
+            trigger_error("No api name passed");
+        }
+        $inflector = new LtInflector;
+        $inflector->conf["separator"] = ".";
+        $requestClassName = ucfirst($inflector->camelize(substr($paramsArray["method"], 7))) . "Request";
+        if (!class_exists($requestClassName)) {
+            trigger_error("No such api: " . $paramsArray["method"]);
+        }
+
+        $session = isset ($paramsArray["session"]) ? $paramsArray["session"] : null;
+
+        $req = new $requestClassName;
+        foreach ($paramsArray as $paraKey => $paraValue) {
+            $inflector->conf["separator"] = "_";
+            $setterMethodName = $inflector->camelize($paraKey);
+            $inflector->conf["separator"] = ".";
+            $setterMethodName = "set" . $inflector->camelize($setterMethodName);
+            if (method_exists($req, $setterMethodName)) {
+                $req->$setterMethodName ($paraValue);
+            }
+        }
+        return $this->execute($req, $session);
+    }
+
+    /**
+     * 校验$value是否非空
+     *  if not set ,return true;
+     *    if is null , return true;
+     **/
+    protected function checkEmpty($value)
+    {
+        if (!isset($value))
+            return true;
+        if ($value === null)
+            return true;
+        if (trim($value) === "")
+            return true;
+
+        return false;
+    }
+
+    /** rsaCheckV1 & rsaCheckV2
+     *  验证签名
+     *  在使用本方法前,必须初始化AopClient且传入公钥参数。
+     *  公钥是否是读取字符串还是读取文件,是根据初始化传入的值判断的。
+     **/
+    public function rsaCheckV1($params, $rsaPublicKeyFilePath, $signType = 'RSA')
+    {
+        $sign = $params['sign'];
+
+        unset($params['sign']);
+        unset($params['sign_type']);
+        return $this->verify($this->getCheckSignContent($params), $sign, $rsaPublicKeyFilePath, $signType);
+    }
+
+    public function rsaCheckV2($params, $rsaPublicKeyFilePath, $signType = 'RSA')
+    {
+        $sign = $params['sign'];
+
+        unset($params['sign']);
+        unset($params['sign_type']);
+        return $this->verify($this->getCheckSignContent($params), $sign, $rsaPublicKeyFilePath, $signType);
+    }
+
+    function getCheckSignContent($params)
+    {
+        ksort($params);
+
+        $stringToBeSigned = "";
+        $i = 0;
+        foreach ($params as $k => $v) {
+            // 转换成目标字符集
+            $v = $this->characet($v, $this->postCharset);
+
+            if ($i == 0) {
+                $stringToBeSigned .= "$k" . "=" . "$v";
+            } else {
+                $stringToBeSigned .= "&" . "$k" . "=" . "$v";
+            }
+            $i++;
+        }
+
+        unset ($k, $v);
+        return $stringToBeSigned;
+    }
+
+    function verify($data, $sign, $rsaPublicKeyFilePath, $signType = 'RSA')
+    {
+
+        if ($this->checkEmpty($this->alipayPublicKey)) {
+
+            $pubKey = $this->alipayrsaPublicKey;
+            $res = "-----BEGIN PUBLIC KEY-----\n" .
+                wordwrap($pubKey, 64, "\n", true) .
+                "\n-----END PUBLIC KEY-----";
+        } else {
+            //读取公钥文件
+            $pubKey = file_get_contents($rsaPublicKeyFilePath);
+            //转换为openssl格式密钥
+            $res = openssl_get_publickey($pubKey);
+        }
+
+        ($res) or die('支付宝RSA公钥错误。请检查公钥文件格式是否正确');
+
+        //调用openssl内置方法验签,返回bool值
+
+        $result = FALSE;
+        if ("RSA2" == $signType) {
+            $result = (openssl_verify($data, base64_decode($sign), $res, OPENSSL_ALGO_SHA256) === 1);
+        } else {
+            $result = (openssl_verify($data, base64_decode($sign), $res) === 1);
+        }
+
+        if (!$this->checkEmpty($this->alipayPublicKey)) {
+            //释放资源
+            openssl_free_key($res);
+        }
+
+        return $result;
+    }
+
+    /**
+     *  在使用本方法前,必须初始化AopClient且传入公私钥参数。
+     *  公钥是否是读取字符串还是读取文件,是根据初始化传入的值判断的。
+     **/
+    public function checkSignAndDecrypt($params, $rsaPublicKeyPem, $rsaPrivateKeyPem, $isCheckSign, $isDecrypt, $signType = 'RSA')
+    {
+        $charset = $params['charset'];
+        $bizContent = $params['biz_content'];
+        if ($isCheckSign) {
+            if (!$this->rsaCheckV2($params, $rsaPublicKeyPem, $signType)) {
+                echo "<br/>checkSign failure<br/>";
+                exit;
+            }
+        }
+        if ($isDecrypt) {
+            return $this->rsaDecrypt($bizContent, $rsaPrivateKeyPem, $charset);
+        }
+
+        return $bizContent;
+    }
+
+    /**
+     *  在使用本方法前,必须初始化AopClient且传入公私钥参数。
+     *  公钥是否是读取字符串还是读取文件,是根据初始化传入的值判断的。
+     **/
+    public function encryptAndSign($bizContent, $rsaPublicKeyPem, $rsaPrivateKeyPem, $charset, $isEncrypt, $isSign, $signType = 'RSA')
+    {
+        // 加密,并签名
+        if ($isEncrypt && $isSign) {
+            $encrypted = $this->rsaEncrypt($bizContent, $rsaPublicKeyPem, $charset);
+            $sign = $this->sign($encrypted, $signType);
+            $response = "<?xml version=\"1.0\" encoding=\"$charset\"?><alipay><response>$encrypted</response><encryption_type>RSA</encryption_type><sign>$sign</sign><sign_type>$signType</sign_type></alipay>";
+            return $response;
+        }
+        // 加密,不签名
+        if ($isEncrypt && (!$isSign)) {
+            $encrypted = $this->rsaEncrypt($bizContent, $rsaPublicKeyPem, $charset);
+            $response = "<?xml version=\"1.0\" encoding=\"$charset\"?><alipay><response>$encrypted</response><encryption_type>$signType</encryption_type></alipay>";
+            return $response;
+        }
+        // 不加密,但签名
+        if ((!$isEncrypt) && $isSign) {
+            $sign = $this->sign($bizContent, $signType);
+            $response = "<?xml version=\"1.0\" encoding=\"$charset\"?><alipay><response>$bizContent</response><sign>$sign</sign><sign_type>$signType</sign_type></alipay>";
+            return $response;
+        }
+        // 不加密,不签名
+        $response = "<?xml version=\"1.0\" encoding=\"$charset\"?>$bizContent";
+        return $response;
+    }
+
+    /**
+     *  在使用本方法前,必须初始化AopClient且传入公私钥参数。
+     *  公钥是否是读取字符串还是读取文件,是根据初始化传入的值判断的。
+     **/
+    public function rsaEncrypt($data, $rsaPublicKeyFilePath, $charset)
+    {
+        if ($this->checkEmpty($this->alipayPublicKey)) {
+            //读取字符串
+            $pubKey = $this->alipayrsaPublicKey;
+            $res = "-----BEGIN PUBLIC KEY-----\n" .
+                wordwrap($pubKey, 64, "\n", true) .
+                "\n-----END PUBLIC KEY-----";
+        } else {
+            //读取公钥文件
+            $pubKey = file_get_contents($rsaPublicKeyFilePath);
+            //转换为openssl格式密钥
+            $res = openssl_get_publickey($pubKey);
+        }
+
+        ($res) or die('支付宝RSA公钥错误。请检查公钥文件格式是否正确');
+        $blocks = $this->splitCN($data, 0, 30, $charset);
+        $chrtext  = null;
+        $encodes  = array();
+        foreach ($blocks as $n => $block) {
+            if (!openssl_public_encrypt($block, $chrtext , $res)) {
+                echo "<br/>" . openssl_error_string() . "<br/>";
+            }
+            $encodes[] = $chrtext ;
+        }
+        $chrtext = implode(",", $encodes);
+
+        return base64_encode($chrtext);
+    }
+
+    /**
+     *  在使用本方法前,必须初始化AopClient且传入公私钥参数。
+     *  公钥是否是读取字符串还是读取文件,是根据初始化传入的值判断的。
+     **/
+    public function rsaDecrypt($data, $rsaPrivateKeyPem, $charset)
+    {
+
+        if ($this->checkEmpty($this->rsaPrivateKeyFilePath)) {
+            //读字符串
+            $priKey = $this->rsaPrivateKey;
+            $res = "-----BEGIN RSA PRIVATE KEY-----\n" .
+                wordwrap($priKey, 64, "\n", true) .
+                "\n-----END RSA PRIVATE KEY-----";
+        } else {
+            $priKey = file_get_contents($this->rsaPrivateKeyFilePath);
+            $res = openssl_get_privatekey($priKey);
+        }
+        ($res) or die('您使用的私钥格式错误,请检查RSA私钥配置');
+        //转换为openssl格式密钥
+        $decodes = explode(',', $data);
+        $strnull = "";
+        $dcyCont = "";
+        foreach ($decodes as $n => $decode) {
+            if (!openssl_private_decrypt($decode, $dcyCont, $res)) {
+                echo "<br/>" . openssl_error_string() . "<br/>";
+            }
+            $strnull .= $dcyCont;
+        }
+        return $strnull;
+    }
+
+    function splitCN($cont, $n = 0, $subnum, $charset)
+    {
+        //$len = strlen($cont) / 3;
+        $arrr = array();
+        for ($i = $n; $i < strlen($cont); $i += $subnum) {
+            $res = $this->subCNchar($cont, $i, $subnum, $charset);
+            if (!empty ($res)) {
+                $arrr[] = $res;
+            }
+        }
+
+        return $arrr;
+    }
+
+    function subCNchar($str, $start = 0, $length, $charset = "gbk")
+    {
+        if (strlen($str) <= $length) {
+            return $str;
+        }
+        $re['utf-8'] = "/[\x01-\x7f]|[\xc2-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xff][\x80-\xbf]{3}/";
+        $re['gb2312'] = "/[\x01-\x7f]|[\xb0-\xf7][\xa0-\xfe]/";
+        $re['gbk'] = "/[\x01-\x7f]|[\x81-\xfe][\x40-\xfe]/";
+        $re['big5'] = "/[\x01-\x7f]|[\x81-\xfe]([\x40-\x7e]|\xa1-\xfe])/";
+        preg_match_all($re[$charset], $str, $match);
+        $slice = join("", array_slice($match[0], $start, $length));
+        return $slice;
+    }
+
+    function parserResponseSubCode($request, $responseContent, $respObject, $format)
+    {
+
+        if ("json" == $format) {
+
+            $apiName = $request->getApiMethodName();
+            $rootNodeName = str_replace(".", "_", $apiName) . $this->RESPONSE_SUFFIX;
+            $errorNodeName = $this->ERROR_RESPONSE;
+
+            $rootIndex = strpos($responseContent, $rootNodeName);
+            $errorIndex = strpos($responseContent, $errorNodeName);
+
+            if ($rootIndex > 0) {
+                // 内部节点对象
+                $rInnerObject = $respObject->$rootNodeName;
+            } elseif ($errorIndex > 0) {
+
+                $rInnerObject = $respObject->$errorNodeName;
+            } else {
+                return null;
+            }
+
+            // 存在属性则返回对应值
+            if (isset($rInnerObject->sub_code)) {
+
+                return $rInnerObject->sub_code;
+            } else {
+
+                return null;
+            }
+
+
+        } elseif ("xml" == $format) {
+
+            // xml格式sub_code在同一层级
+            return $respObject->sub_code;
+
+        }
+
+
+    }
+
+    function parserJSONSignData($request, $responseContent, $responseJSON)
+    {
+
+        $signData = new \SignData();
+
+        $signData->sign = $this->parserJSONSign($responseJSON);
+        $signData->signSourceData = $this->parserJSONSignSource($request, $responseContent);
+
+
+        return $signData;
+
+    }
+
+    function parserJSONSignSource($request, $responseContent)
+    {
+
+        $apiName = $request->getApiMethodName();
+        $rootNodeName = str_replace(".", "_", $apiName) . $this->RESPONSE_SUFFIX;
+
+        $rootIndex = strpos($responseContent, $rootNodeName);
+        $errorIndex = strpos($responseContent, $this->ERROR_RESPONSE);
+
+
+        if ($rootIndex > 0) {
+
+            return $this->parserJSONSource($responseContent, $rootNodeName, $rootIndex);
+        } else if ($errorIndex > 0) {
+
+            return $this->parserJSONSource($responseContent, $this->ERROR_RESPONSE, $errorIndex);
+        } else {
+
+            return null;
+        }
+
+
+    }
+
+    function parserJSONSource($responseContent, $nodeName, $nodeIndex)
+    {
+        $signDataStartIndex = $nodeIndex + strlen($nodeName) + 2;
+        $signIndex = strrpos($responseContent, "\"" . $this->SIGN_NODE_NAME . "\"");
+        // 签名前-逗号
+        $signDataEndIndex = $signIndex - 1;
+        $indexLen = $signDataEndIndex - $signDataStartIndex;
+        if ($indexLen < 0) {
+
+            return null;
+        }
+
+        return substr($responseContent, $signDataStartIndex, $indexLen);
+
+    }
+
+    function parserJSONSign($responseJSon)
+    {
+
+        return $responseJSon->sign;
+    }
+
+    function parserXMLSignData($request, $responseContent)
+    {
+
+
+        $signData = new SignData();
+
+        $signData->sign = $this->parserXMLSign($responseContent);
+        $signData->signSourceData = $this->parserXMLSignSource($request, $responseContent);
+
+
+        return $signData;
+
+
+    }
+
+    function parserXMLSignSource($request, $responseContent)
+    {
+
+
+        $apiName = $request->getApiMethodName();
+        $rootNodeName = str_replace(".", "_", $apiName) . $this->RESPONSE_SUFFIX;
+
+
+        $rootIndex = strpos($responseContent, $rootNodeName);
+        $errorIndex = strpos($responseContent, $this->ERROR_RESPONSE);
+        //		$this->echoDebug("<br/>rootNodeName:" . $rootNodeName);
+        //		$this->echoDebug("<br/> responseContent:<xmp>" . $responseContent . "</xmp>");
+
+
+        if ($rootIndex > 0) {
+
+            return $this->parserXMLSource($responseContent, $rootNodeName, $rootIndex);
+        } else if ($errorIndex > 0) {
+
+            return $this->parserXMLSource($responseContent, $this->ERROR_RESPONSE, $errorIndex);
+        } else {
+
+            return null;
+        }
+
+
+    }
+
+    function parserXMLSource($responseContent, $nodeName, $nodeIndex)
+    {
+        $signDataStartIndex = $nodeIndex + strlen($nodeName) + 1;
+        $signIndex = strrpos($responseContent, "<" . $this->SIGN_NODE_NAME . ">");
+        // 签名前-逗号
+        $signDataEndIndex = $signIndex - 1;
+        $indexLen = $signDataEndIndex - $signDataStartIndex + 1;
+
+        if ($indexLen < 0) {
+            return null;
+        }
+
+
+        return substr($responseContent, $signDataStartIndex, $indexLen);
+
+
+    }
+
+    function parserXMLSign($responseContent)
+    {
+        $signNodeName = "<" . $this->SIGN_NODE_NAME . ">";
+        $signEndNodeName = "</" . $this->SIGN_NODE_NAME . ">";
+
+        $indexOfSignNode = strpos($responseContent, $signNodeName);
+        $indexOfSignEndNode = strpos($responseContent, $signEndNodeName);
+
+
+        if ($indexOfSignNode < 0 || $indexOfSignEndNode < 0) {
+            return null;
+        }
+
+        $nodeIndex = ($indexOfSignNode + strlen($signNodeName));
+
+        $indexLen = $indexOfSignEndNode - $nodeIndex;
+
+        if ($indexLen < 0) {
+            return null;
+        }
+
+        // 签名
+        return substr($responseContent, $nodeIndex, $indexLen);
+
+    }
+
+    /**
+     * 验签
+     * @param $request
+     * @param $signData
+     * @param $resp
+     * @param $respObject
+     * @throws Exception
+     */
+    public function checkResponseSign($request, $signData, $resp, $respObject)
+    {
+
+        if (!$this->checkEmpty($this->alipayPublicKey) || !$this->checkEmpty($this->alipayrsaPublicKey)) {
+
+
+            if ($signData == null || $this->checkEmpty($signData->sign) || $this->checkEmpty($signData->signSourceData)) {
+
+                throw new Exception(" check sign Fail! The reason : signData is Empty");
+            }
+
+
+            // 获取结果sub_code
+            $responseSubCode = $this->parserResponseSubCode($request, $resp, $respObject, $this->format);
+
+
+            if (!$this->checkEmpty($responseSubCode) || ($this->checkEmpty($responseSubCode) && !$this->checkEmpty($signData->sign))) {
+
+                $checkResult = $this->verify($signData->signSourceData, $signData->sign, $this->alipayPublicKey, $this->signType);
+
+                if (!$checkResult) {
+
+                    if (strpos($signData->signSourceData, "\\/") > 0) {
+
+                        $signData->signSourceData = str_replace("\\/", "/", $signData->signSourceData);
+
+                        $checkResult = $this->verify($signData->signSourceData, $signData->sign, $this->alipayPublicKey, $this->signType);
+
+                        if (!$checkResult) {
+                            throw new Exception("check sign Fail! [sign=" . $signData->sign . ", signSourceData=" . $signData->signSourceData . "]");
+                        }
+                    } else {
+                        throw new \Exception("check sign Fail! [sign=" . $signData->sign . ", signSourceData=" . $signData->signSourceData . "]");
+                    }
+
+                }
+            }
+
+
+        }
+    }
+
+    private function setupCharsets($request)
+    {
+        if ($this->checkEmpty($this->postCharset)) {
+            $this->postCharset = 'UTF-8';
+        }
+        $str = preg_match('/[\x80-\xff]/', $this->appId) ? $this->appId : print_r($request, true);
+        $this->fileCharset = mb_detect_encoding($str, "UTF-8, GBK") == 'UTF-8' ? 'UTF-8' : 'GBK';
+    }
+
+    // 获取加密内容
+
+    private function encryptJSONSignSource($request, $responseContent)
+    {
+
+        $parsetItem = $this->parserEncryptJSONSignSource($request, $responseContent);
+
+        $bodyIndexContent = substr($responseContent, 0, $parsetItem->startIndex);
+        $bodyEndContent = substr($responseContent, $parsetItem->endIndex, strlen($responseContent) + 1 - $parsetItem->endIndex);
+
+        $bizContent = decrypt($parsetItem->encryptContent, $this->encryptKey);
+        return $bodyIndexContent . $bizContent . $bodyEndContent;
+
+    }
+
+
+    private function parserEncryptJSONSignSource($request, $responseContent)
+    {
+
+        $apiName = $request->getApiMethodName();
+        $rootNodeName = str_replace(".", "_", $apiName) . $this->RESPONSE_SUFFIX;
+
+        $rootIndex = strpos($responseContent, $rootNodeName);
+        $errorIndex = strpos($responseContent, $this->ERROR_RESPONSE);
+
+
+        if ($rootIndex > 0) {
+
+            return $this->parserEncryptJSONItem($responseContent, $rootNodeName, $rootIndex);
+        } else if ($errorIndex > 0) {
+
+            return $this->parserEncryptJSONItem($responseContent, $this->ERROR_RESPONSE, $errorIndex);
+        } else {
+
+            return null;
+        }
+
+
+    }
+
+
+    private function parserEncryptJSONItem($responseContent, $nodeName, $nodeIndex)
+    {
+        $signDataStartIndex = $nodeIndex + strlen($nodeName) + 2;
+        $signIndex = strpos($responseContent, "\"" . $this->SIGN_NODE_NAME . "\"");
+        // 签名前-逗号
+        $signDataEndIndex = $signIndex - 1;
+
+        if ($signDataEndIndex < 0) {
+
+            $signDataEndIndex = strlen($responseContent) - 1;
+        }
+
+        $indexLen = $signDataEndIndex - $signDataStartIndex;
+
+        $encContent = substr($responseContent, $signDataStartIndex + 1, $indexLen - 2);
+
+
+        $encryptParseItem = new EncryptParseItem();
+
+        $encryptParseItem->encryptContent = $encContent;
+        $encryptParseItem->startIndex = $signDataStartIndex;
+        $encryptParseItem->endIndex = $signDataEndIndex;
+
+        return $encryptParseItem;
+
+    }
+
+    // 获取加密内容
+
+    private function encryptXMLSignSource($request, $responseContent)
+    {
+
+        $parsetItem = $this->parserEncryptXMLSignSource($request, $responseContent);
+
+        $bodyIndexContent = substr($responseContent, 0, $parsetItem->startIndex);
+        $bodyEndContent = substr($responseContent, $parsetItem->endIndex, strlen($responseContent) + 1 - $parsetItem->endIndex);
+        $bizContent = decrypt($parsetItem->encryptContent, $this->encryptKey);
+
+        return $bodyIndexContent . $bizContent . $bodyEndContent;
+
+    }
+
+    private function parserEncryptXMLSignSource($request, $responseContent)
+    {
+
+
+        $apiName = $request->getApiMethodName();
+        $rootNodeName = str_replace(".", "_", $apiName) . $this->RESPONSE_SUFFIX;
+
+
+        $rootIndex = strpos($responseContent, $rootNodeName);
+        $errorIndex = strpos($responseContent, $this->ERROR_RESPONSE);
+        //		$this->echoDebug("<br/>rootNodeName:" . $rootNodeName);
+        //		$this->echoDebug("<br/> responseContent:<xmp>" . $responseContent . "</xmp>");
+
+
+        if ($rootIndex > 0) {
+
+            return $this->parserEncryptXMLItem($responseContent, $rootNodeName, $rootIndex);
+        } else if ($errorIndex > 0) {
+
+            return $this->parserEncryptXMLItem($responseContent, $this->ERROR_RESPONSE, $errorIndex);
+        } else {
+
+            return null;
+        }
+
+
+    }
+
+    private function parserEncryptXMLItem($responseContent, $nodeName, $nodeIndex)
+    {
+
+        $signDataStartIndex = $nodeIndex + strlen($nodeName) + 1;
+
+        $xmlStartNode = "<" . $this->ENCRYPT_XML_NODE_NAME . ">";
+        $xmlEndNode = "</" . $this->ENCRYPT_XML_NODE_NAME . ">";
+
+        $indexOfXmlNode = strpos($responseContent, $xmlEndNode);
+        if ($indexOfXmlNode < 0) {
+
+            $item = new EncryptParseItem();
+            $item->encryptContent = null;
+            $item->startIndex = 0;
+            $item->endIndex = 0;
+            return $item;
+        }
+
+        $startIndex = $signDataStartIndex + strlen($xmlStartNode);
+        $bizContentLen = $indexOfXmlNode - $startIndex;
+        $bizContent = substr($responseContent, $startIndex, $bizContentLen);
+
+        $encryptParseItem = new EncryptParseItem();
+        $encryptParseItem->encryptContent = $bizContent;
+        $encryptParseItem->startIndex = $signDataStartIndex;
+        $encryptParseItem->endIndex = $indexOfXmlNode + strlen($xmlEndNode);
+
+        return $encryptParseItem;
+
+    }
+
+
+    function echoDebug($content)
+    {
+
+        if ($this->debugInfo) {
+            echo "<br/>" . $content;
+        }
+
+    }
+
+
+}

+ 81 - 0
application/common/library/alipay/aop/AopEncrypt.php

@@ -0,0 +1,81 @@
+<?php
+/**
+ *   加密工具类
+ *
+ * User: jiehua
+ * Date: 16/3/30
+ * Time: 下午3:25
+ */
+
+
+/**
+ * 加密方法
+ * @param string $str
+ * @return string
+ */
+function encrypt($str, $screct_key)
+{
+    //AES, 128 模式加密数据 CBC
+    $screct_key = base64_decode($screct_key);
+    $str = trim($str);
+    $str = addPKCS7Padding($str);
+
+    //设置全0的IV
+    $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
+    $iv = str_repeat("\0", $iv_size);
+
+    $encrypt_str = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $screct_key, $str, MCRYPT_MODE_CBC, $iv);
+    return base64_encode($encrypt_str);
+}
+
+/**
+ * 解密方法
+ * @param string $str
+ * @return string
+ */
+function decrypt($str, $screct_key)
+{
+    //AES, 128 模式加密数据 CBC
+    $str = base64_decode($str);
+    $screct_key = base64_decode($screct_key);
+
+    //设置全0的IV
+    $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
+    $iv = str_repeat("\0", $iv_size);
+
+    $decrypt_str = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $screct_key, $str, MCRYPT_MODE_CBC, $iv);
+    $decrypt_str = stripPKSC7Padding($decrypt_str);
+    return $decrypt_str;
+}
+
+/**
+ * 填充算法
+ * @param string $source
+ * @return string
+ */
+function addPKCS7Padding($source)
+{
+    $source = trim($source);
+    $block = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
+
+    $pad = $block - (strlen($source) % $block);
+    if ($pad <= $block) {
+        $char = chr($pad);
+        $source .= str_repeat($char, $pad);
+    }
+    return $source;
+}
+
+/**
+ * 移去填充算法
+ * @param string $source
+ * @return string
+ */
+function stripPKSC7Padding($source)
+{
+    $char = substr($source, -1);
+    $num = ord($char);
+    if ($num == 62) return $source;
+    $source = substr($source, 0, -$num);
+    return $source;
+}

+ 18 - 0
application/common/library/alipay/aop/EncryptParseItem.php

@@ -0,0 +1,18 @@
+<?php
+/**
+ *  TODO 补充说明
+ *
+ * User: jiehua
+ * Date: 16/3/30
+ * Time: 下午8:55
+ */
+
+class EncryptParseItem
+{
+    public $startIndex;
+
+    public $endIndex;
+
+    public $encryptContent;
+
+} 

+ 16 - 0
application/common/library/alipay/aop/EncryptResponseData.php

@@ -0,0 +1,16 @@
+<?php
+/**
+ *  TODO 补充说明
+ *
+ * User: jiehua
+ * Date: 16/3/30
+ * Time: 下午8:51
+ */
+
+class EncryptResponseData
+{
+    public $realContent;
+
+    public $returnContent;
+
+} 

+ 15 - 0
application/common/library/alipay/aop/SignData.php

@@ -0,0 +1,15 @@
+<?php
+/**
+ * Created by PhpStorm.
+ * User: jiehua
+ * Date: 15/5/2
+ * Time: 下午6:21
+ */
+
+class SignData
+{
+    public $signSourceData = null;
+
+    public $sign = null;
+
+} 

+ 14 - 0
application/common/library/alipay/aop/readme

@@ -0,0 +1,14 @@
+SDK版本升级说明
+1、去除已经放弃维护的lotusphp框架
+2、公私钥模式开发者请直接初始化AopClient,使用方法详见:aop/test/AopClientTest.php
+3、证书模式开发者请直接初始化AopCertClient,使用方法详见:aop/test/AopCertClientTest.php
+4、兼容PHP7.2以上版本
+
+使用过程中有任何问题,请加入钉钉群咨询:23311489
+
+更新时间:2020-04-15
+
+备注:
+使用证书模式本地必须开始SSL
+如果出现SSL certificate: unable to get local issuer certificate错误信息
+解决办法:到http://curl.haxx.se/ca/cacert.pem下载pem文件,并将文件拷贝到D:\phpStudy\PHPTutorial\cacert.pem 在php.ini 增加curl.cainfo = "D:\phpStudy\PHPTutorial\cacert.pem"

+ 118 - 0
application/common/library/alipay/aop/request/AftAifinFireeyeOcrImageQueryRequest.php

@@ -0,0 +1,118 @@
+<?php
+/**
+ * ALIPAY API: aft.aifin.fireeye.ocr.image.query request
+ *
+ * @author auto create
+ * @since 1.0, 2019-01-07 20:51:15
+ */
+class AftAifinFireeyeOcrImageQueryRequest
+{
+	/** 
+	 * OCR火眼识别
+	 **/
+	private $bizContent;
+
+	private $apiParas = array();
+	private $terminalType;
+	private $terminalInfo;
+	private $prodCode;
+	private $apiVersion="1.0";
+	private $notifyUrl;
+	private $returnUrl;
+    private $needEncrypt=false;
+
+	
+	public function setBizContent($bizContent)
+	{
+		$this->bizContent = $bizContent;
+		$this->apiParas["biz_content"] = $bizContent;
+	}
+
+	public function getBizContent()
+	{
+		return $this->bizContent;
+	}
+
+	public function getApiMethodName()
+	{
+		return "aft.aifin.fireeye.ocr.image.query";
+	}
+
+	public function setNotifyUrl($notifyUrl)
+	{
+		$this->notifyUrl=$notifyUrl;
+	}
+
+	public function getNotifyUrl()
+	{
+		return $this->notifyUrl;
+	}
+
+	public function setReturnUrl($returnUrl)
+	{
+		$this->returnUrl=$returnUrl;
+	}
+
+	public function getReturnUrl()
+	{
+		return $this->returnUrl;
+	}
+
+	public function getApiParas()
+	{
+		return $this->apiParas;
+	}
+
+	public function getTerminalType()
+	{
+		return $this->terminalType;
+	}
+
+	public function setTerminalType($terminalType)
+	{
+		$this->terminalType = $terminalType;
+	}
+
+	public function getTerminalInfo()
+	{
+		return $this->terminalInfo;
+	}
+
+	public function setTerminalInfo($terminalInfo)
+	{
+		$this->terminalInfo = $terminalInfo;
+	}
+
+	public function getProdCode()
+	{
+		return $this->prodCode;
+	}
+
+	public function setProdCode($prodCode)
+	{
+		$this->prodCode = $prodCode;
+	}
+
+	public function setApiVersion($apiVersion)
+	{
+		$this->apiVersion=$apiVersion;
+	}
+
+	public function getApiVersion()
+	{
+		return $this->apiVersion;
+	}
+
+  public function setNeedEncrypt($needEncrypt)
+  {
+
+     $this->needEncrypt=$needEncrypt;
+
+  }
+
+  public function getNeedEncrypt()
+  {
+    return $this->needEncrypt;
+  }
+
+}

+ 118 - 0
application/common/library/alipay/aop/request/AftFinsecureRiskplusSecurityPolicyQueryRequest.php

@@ -0,0 +1,118 @@
+<?php
+/**
+ * ALIPAY API: aft.finsecure.riskplus.security.policy.query request
+ *
+ * @author auto create
+ * @since 1.0, 2019-01-07 20:51:15
+ */
+class AftFinsecureRiskplusSecurityPolicyQueryRequest
+{
+	/** 
+	 * 策略咨询服务输出
+	 **/
+	private $bizContent;
+
+	private $apiParas = array();
+	private $terminalType;
+	private $terminalInfo;
+	private $prodCode;
+	private $apiVersion="1.0";
+	private $notifyUrl;
+	private $returnUrl;
+    private $needEncrypt=false;
+
+	
+	public function setBizContent($bizContent)
+	{
+		$this->bizContent = $bizContent;
+		$this->apiParas["biz_content"] = $bizContent;
+	}
+
+	public function getBizContent()
+	{
+		return $this->bizContent;
+	}
+
+	public function getApiMethodName()
+	{
+		return "aft.finsecure.riskplus.security.policy.query";
+	}
+
+	public function setNotifyUrl($notifyUrl)
+	{
+		$this->notifyUrl=$notifyUrl;
+	}
+
+	public function getNotifyUrl()
+	{
+		return $this->notifyUrl;
+	}
+
+	public function setReturnUrl($returnUrl)
+	{
+		$this->returnUrl=$returnUrl;
+	}
+
+	public function getReturnUrl()
+	{
+		return $this->returnUrl;
+	}
+
+	public function getApiParas()
+	{
+		return $this->apiParas;
+	}
+
+	public function getTerminalType()
+	{
+		return $this->terminalType;
+	}
+
+	public function setTerminalType($terminalType)
+	{
+		$this->terminalType = $terminalType;
+	}
+
+	public function getTerminalInfo()
+	{
+		return $this->terminalInfo;
+	}
+
+	public function setTerminalInfo($terminalInfo)
+	{
+		$this->terminalInfo = $terminalInfo;
+	}
+
+	public function getProdCode()
+	{
+		return $this->prodCode;
+	}
+
+	public function setProdCode($prodCode)
+	{
+		$this->prodCode = $prodCode;
+	}
+
+	public function setApiVersion($apiVersion)
+	{
+		$this->apiVersion=$apiVersion;
+	}
+
+	public function getApiVersion()
+	{
+		return $this->apiVersion;
+	}
+
+  public function setNeedEncrypt($needEncrypt)
+  {
+
+     $this->needEncrypt=$needEncrypt;
+
+  }
+
+  public function getNeedEncrypt()
+  {
+    return $this->needEncrypt;
+  }
+
+}

+ 118 - 0
application/common/library/alipay/aop/request/AliosOpenAutoInfoQueryRequest.php

@@ -0,0 +1,118 @@
+<?php
+/**
+ * ALIPAY API: alios.open.auto.info.query request
+ *
+ * @author auto create
+ * @since 1.0, 2020-05-06 14:05:09
+ */
+class AliosOpenAutoInfoQueryRequest
+{
+	/** 
+	 * 查询阿里车的车辆信息
+	 **/
+	private $bizContent;
+
+	private $apiParas = array();
+	private $terminalType;
+	private $terminalInfo;
+	private $prodCode;
+	private $apiVersion="1.0";
+	private $notifyUrl;
+	private $returnUrl;
+    private $needEncrypt=false;
+
+	
+	public function setBizContent($bizContent)
+	{
+		$this->bizContent = $bizContent;
+		$this->apiParas["biz_content"] = $bizContent;
+	}
+
+	public function getBizContent()
+	{
+		return $this->bizContent;
+	}
+
+	public function getApiMethodName()
+	{
+		return "alios.open.auto.info.query";
+	}
+
+	public function setNotifyUrl($notifyUrl)
+	{
+		$this->notifyUrl=$notifyUrl;
+	}
+
+	public function getNotifyUrl()
+	{
+		return $this->notifyUrl;
+	}
+
+	public function setReturnUrl($returnUrl)
+	{
+		$this->returnUrl=$returnUrl;
+	}
+
+	public function getReturnUrl()
+	{
+		return $this->returnUrl;
+	}
+
+	public function getApiParas()
+	{
+		return $this->apiParas;
+	}
+
+	public function getTerminalType()
+	{
+		return $this->terminalType;
+	}
+
+	public function setTerminalType($terminalType)
+	{
+		$this->terminalType = $terminalType;
+	}
+
+	public function getTerminalInfo()
+	{
+		return $this->terminalInfo;
+	}
+
+	public function setTerminalInfo($terminalInfo)
+	{
+		$this->terminalInfo = $terminalInfo;
+	}
+
+	public function getProdCode()
+	{
+		return $this->prodCode;
+	}
+
+	public function setProdCode($prodCode)
+	{
+		$this->prodCode = $prodCode;
+	}
+
+	public function setApiVersion($apiVersion)
+	{
+		$this->apiVersion=$apiVersion;
+	}
+
+	public function getApiVersion()
+	{
+		return $this->apiVersion;
+	}
+
+  public function setNeedEncrypt($needEncrypt)
+  {
+
+     $this->needEncrypt=$needEncrypt;
+
+  }
+
+  public function getNeedEncrypt()
+  {
+    return $this->needEncrypt;
+  }
+
+}

+ 118 - 0
application/common/library/alipay/aop/request/AlipayAccountExrateAdviceAcceptRequest.php

@@ -0,0 +1,118 @@
+<?php
+/**
+ * ALIPAY API: alipay.account.exrate.advice.accept request
+ *
+ * @author auto create
+ * @since 1.0, 2019-01-07 20:51:15
+ */
+class AlipayAccountExrateAdviceAcceptRequest
+{
+	/** 
+	 * 标准的兑换交易受理接口
+	 **/
+	private $bizContent;
+
+	private $apiParas = array();
+	private $terminalType;
+	private $terminalInfo;
+	private $prodCode;
+	private $apiVersion="1.0";
+	private $notifyUrl;
+	private $returnUrl;
+    private $needEncrypt=false;
+
+	
+	public function setBizContent($bizContent)
+	{
+		$this->bizContent = $bizContent;
+		$this->apiParas["biz_content"] = $bizContent;
+	}
+
+	public function getBizContent()
+	{
+		return $this->bizContent;
+	}
+
+	public function getApiMethodName()
+	{
+		return "alipay.account.exrate.advice.accept";
+	}
+
+	public function setNotifyUrl($notifyUrl)
+	{
+		$this->notifyUrl=$notifyUrl;
+	}
+
+	public function getNotifyUrl()
+	{
+		return $this->notifyUrl;
+	}
+
+	public function setReturnUrl($returnUrl)
+	{
+		$this->returnUrl=$returnUrl;
+	}
+
+	public function getReturnUrl()
+	{
+		return $this->returnUrl;
+	}
+
+	public function getApiParas()
+	{
+		return $this->apiParas;
+	}
+
+	public function getTerminalType()
+	{
+		return $this->terminalType;
+	}
+
+	public function setTerminalType($terminalType)
+	{
+		$this->terminalType = $terminalType;
+	}
+
+	public function getTerminalInfo()
+	{
+		return $this->terminalInfo;
+	}
+
+	public function setTerminalInfo($terminalInfo)
+	{
+		$this->terminalInfo = $terminalInfo;
+	}
+
+	public function getProdCode()
+	{
+		return $this->prodCode;
+	}
+
+	public function setProdCode($prodCode)
+	{
+		$this->prodCode = $prodCode;
+	}
+
+	public function setApiVersion($apiVersion)
+	{
+		$this->apiVersion=$apiVersion;
+	}
+
+	public function getApiVersion()
+	{
+		return $this->apiVersion;
+	}
+
+  public function setNeedEncrypt($needEncrypt)
+  {
+
+     $this->needEncrypt=$needEncrypt;
+
+  }
+
+  public function getNeedEncrypt()
+  {
+    return $this->needEncrypt;
+  }
+
+}

+ 118 - 0
application/common/library/alipay/aop/request/AlipayAccountExrateAllclientrateQueryRequest.php

@@ -0,0 +1,118 @@
+<?php
+/**
+ * ALIPAY API: alipay.account.exrate.allclientrate.query request
+ *
+ * @author auto create
+ * @since 1.0, 2019-09-27 17:03:52
+ */
+class AlipayAccountExrateAllclientrateQueryRequest
+{
+	/** 
+	 * 查询客户的所有币种对最新有效汇率
+	 **/
+	private $bizContent;
+
+	private $apiParas = array();
+	private $terminalType;
+	private $terminalInfo;
+	private $prodCode;
+	private $apiVersion="1.0";
+	private $notifyUrl;
+	private $returnUrl;
+    private $needEncrypt=false;
+
+	
+	public function setBizContent($bizContent)
+	{
+		$this->bizContent = $bizContent;
+		$this->apiParas["biz_content"] = $bizContent;
+	}
+
+	public function getBizContent()
+	{
+		return $this->bizContent;
+	}
+
+	public function getApiMethodName()
+	{
+		return "alipay.account.exrate.allclientrate.query";
+	}
+
+	public function setNotifyUrl($notifyUrl)
+	{
+		$this->notifyUrl=$notifyUrl;
+	}
+
+	public function getNotifyUrl()
+	{
+		return $this->notifyUrl;
+	}
+
+	public function setReturnUrl($returnUrl)
+	{
+		$this->returnUrl=$returnUrl;
+	}
+
+	public function getReturnUrl()
+	{
+		return $this->returnUrl;
+	}
+
+	public function getApiParas()
+	{
+		return $this->apiParas;
+	}
+
+	public function getTerminalType()
+	{
+		return $this->terminalType;
+	}
+
+	public function setTerminalType($terminalType)
+	{
+		$this->terminalType = $terminalType;
+	}
+
+	public function getTerminalInfo()
+	{
+		return $this->terminalInfo;
+	}
+
+	public function setTerminalInfo($terminalInfo)
+	{
+		$this->terminalInfo = $terminalInfo;
+	}
+
+	public function getProdCode()
+	{
+		return $this->prodCode;
+	}
+
+	public function setProdCode($prodCode)
+	{
+		$this->prodCode = $prodCode;
+	}
+
+	public function setApiVersion($apiVersion)
+	{
+		$this->apiVersion=$apiVersion;
+	}
+
+	public function getApiVersion()
+	{
+		return $this->apiVersion;
+	}
+
+  public function setNeedEncrypt($needEncrypt)
+  {
+
+     $this->needEncrypt=$needEncrypt;
+
+  }
+
+  public function getNeedEncrypt()
+  {
+    return $this->needEncrypt;
+  }
+
+}

+ 118 - 0
application/common/library/alipay/aop/request/AlipayAccountExrateRatequeryRequest.php

@@ -0,0 +1,118 @@
+<?php
+/**
+ * ALIPAY API: alipay.account.exrate.ratequery request
+ *
+ * @author auto create
+ * @since 1.0, 2019-01-07 20:51:15
+ */
+class AlipayAccountExrateRatequeryRequest
+{
+	/** 
+	 * 对于部分签约境内当面付的商家,为了能够在境外进行推广,因此需要汇率进行币种之间的转换,本接口提供此业务场景下的汇率查询服务
+	 **/
+	private $bizContent;
+
+	private $apiParas = array();
+	private $terminalType;
+	private $terminalInfo;
+	private $prodCode;
+	private $apiVersion="1.0";
+	private $notifyUrl;
+	private $returnUrl;
+    private $needEncrypt=false;
+
+	
+	public function setBizContent($bizContent)
+	{
+		$this->bizContent = $bizContent;
+		$this->apiParas["biz_content"] = $bizContent;
+	}
+
+	public function getBizContent()
+	{
+		return $this->bizContent;
+	}
+
+	public function getApiMethodName()
+	{
+		return "alipay.account.exrate.ratequery";
+	}
+
+	public function setNotifyUrl($notifyUrl)
+	{
+		$this->notifyUrl=$notifyUrl;
+	}
+
+	public function getNotifyUrl()
+	{
+		return $this->notifyUrl;
+	}
+
+	public function setReturnUrl($returnUrl)
+	{
+		$this->returnUrl=$returnUrl;
+	}
+
+	public function getReturnUrl()
+	{
+		return $this->returnUrl;
+	}
+
+	public function getApiParas()
+	{
+		return $this->apiParas;
+	}
+
+	public function getTerminalType()
+	{
+		return $this->terminalType;
+	}
+
+	public function setTerminalType($terminalType)
+	{
+		$this->terminalType = $terminalType;
+	}
+
+	public function getTerminalInfo()
+	{
+		return $this->terminalInfo;
+	}
+
+	public function setTerminalInfo($terminalInfo)
+	{
+		$this->terminalInfo = $terminalInfo;
+	}
+
+	public function getProdCode()
+	{
+		return $this->prodCode;
+	}
+
+	public function setProdCode($prodCode)
+	{
+		$this->prodCode = $prodCode;
+	}
+
+	public function setApiVersion($apiVersion)
+	{
+		$this->apiVersion=$apiVersion;
+	}
+
+	public function getApiVersion()
+	{
+		return $this->apiVersion;
+	}
+
+  public function setNeedEncrypt($needEncrypt)
+  {
+
+     $this->needEncrypt=$needEncrypt;
+
+  }
+
+  public function getNeedEncrypt()
+  {
+    return $this->needEncrypt;
+  }
+
+}

+ 118 - 0
application/common/library/alipay/aop/request/AlipayAccountExrateTraderequestCreateRequest.php

@@ -0,0 +1,118 @@
+<?php
+/**
+ * ALIPAY API: alipay.account.exrate.traderequest.create request
+ *
+ * @author auto create
+ * @since 1.0, 2019-01-07 20:51:15
+ */
+class AlipayAccountExrateTraderequestCreateRequest
+{
+	/** 
+	 * 受理外汇交易请求
+	 **/
+	private $bizContent;
+
+	private $apiParas = array();
+	private $terminalType;
+	private $terminalInfo;
+	private $prodCode;
+	private $apiVersion="1.0";
+	private $notifyUrl;
+	private $returnUrl;
+    private $needEncrypt=false;
+
+	
+	public function setBizContent($bizContent)
+	{
+		$this->bizContent = $bizContent;
+		$this->apiParas["biz_content"] = $bizContent;
+	}
+
+	public function getBizContent()
+	{
+		return $this->bizContent;
+	}
+
+	public function getApiMethodName()
+	{
+		return "alipay.account.exrate.traderequest.create";
+	}
+
+	public function setNotifyUrl($notifyUrl)
+	{
+		$this->notifyUrl=$notifyUrl;
+	}
+
+	public function getNotifyUrl()
+	{
+		return $this->notifyUrl;
+	}
+
+	public function setReturnUrl($returnUrl)
+	{
+		$this->returnUrl=$returnUrl;
+	}
+
+	public function getReturnUrl()
+	{
+		return $this->returnUrl;
+	}
+
+	public function getApiParas()
+	{
+		return $this->apiParas;
+	}
+
+	public function getTerminalType()
+	{
+		return $this->terminalType;
+	}
+
+	public function setTerminalType($terminalType)
+	{
+		$this->terminalType = $terminalType;
+	}
+
+	public function getTerminalInfo()
+	{
+		return $this->terminalInfo;
+	}
+
+	public function setTerminalInfo($terminalInfo)
+	{
+		$this->terminalInfo = $terminalInfo;
+	}
+
+	public function getProdCode()
+	{
+		return $this->prodCode;
+	}
+
+	public function setProdCode($prodCode)
+	{
+		$this->prodCode = $prodCode;
+	}
+
+	public function setApiVersion($apiVersion)
+	{
+		$this->apiVersion=$apiVersion;
+	}
+
+	public function getApiVersion()
+	{
+		return $this->apiVersion;
+	}
+
+  public function setNeedEncrypt($needEncrypt)
+  {
+
+     $this->needEncrypt=$needEncrypt;
+
+  }
+
+  public function getNeedEncrypt()
+  {
+    return $this->needEncrypt;
+  }
+
+}

+ 171 - 0
application/common/library/alipay/aop/request/AlipayAcquireCancelRequest.php

@@ -0,0 +1,171 @@
+<?php
+/**
+ * ALIPAY API: alipay.acquire.cancel request
+ *
+ * @author auto create
+ * @since 1.0, 2019-03-08 15:29:11
+ */
+class AlipayAcquireCancelRequest
+{
+	/** 
+	 * 操作员ID。
+	 **/
+	private $operatorId;
+	
+	/** 
+	 * 操作员的类型:
+0:支付宝操作员
+1:商户的操作员
+如果传入其它值或者为空,则默认设置为1
+	 **/
+	private $operatorType;
+	
+	/** 
+	 * 支付宝合作商户网站唯一订单号。
+	 **/
+	private $outTradeNo;
+	
+	/** 
+	 * 该交易在支付宝系统中的交易流水号。
+最短16位,最长64位。
+如果同时传了out_trade_no和trade_no,则以trade_no为准。
+	 **/
+	private $tradeNo;
+
+	private $apiParas = array();
+	private $terminalType;
+	private $terminalInfo;
+	private $prodCode;
+	private $apiVersion="1.0";
+	private $notifyUrl;
+	private $returnUrl;
+    private $needEncrypt=false;
+
+	
+	public function setOperatorId($operatorId)
+	{
+		$this->operatorId = $operatorId;
+		$this->apiParas["operator_id"] = $operatorId;
+	}
+
+	public function getOperatorId()
+	{
+		return $this->operatorId;
+	}
+
+	public function setOperatorType($operatorType)
+	{
+		$this->operatorType = $operatorType;
+		$this->apiParas["operator_type"] = $operatorType;
+	}
+
+	public function getOperatorType()
+	{
+		return $this->operatorType;
+	}
+
+	public function setOutTradeNo($outTradeNo)
+	{
+		$this->outTradeNo = $outTradeNo;
+		$this->apiParas["out_trade_no"] = $outTradeNo;
+	}
+
+	public function getOutTradeNo()
+	{
+		return $this->outTradeNo;
+	}
+
+	public function setTradeNo($tradeNo)
+	{
+		$this->tradeNo = $tradeNo;
+		$this->apiParas["trade_no"] = $tradeNo;
+	}
+
+	public function getTradeNo()
+	{
+		return $this->tradeNo;
+	}
+
+	public function getApiMethodName()
+	{
+		return "alipay.acquire.cancel";
+	}
+
+	public function setNotifyUrl($notifyUrl)
+	{
+		$this->notifyUrl=$notifyUrl;
+	}
+
+	public function getNotifyUrl()
+	{
+		return $this->notifyUrl;
+	}
+
+	public function setReturnUrl($returnUrl)
+	{
+		$this->returnUrl=$returnUrl;
+	}
+
+	public function getReturnUrl()
+	{
+		return $this->returnUrl;
+	}
+
+	public function getApiParas()
+	{
+		return $this->apiParas;
+	}
+
+	public function getTerminalType()
+	{
+		return $this->terminalType;
+	}
+
+	public function setTerminalType($terminalType)
+	{
+		$this->terminalType = $terminalType;
+	}
+
+	public function getTerminalInfo()
+	{
+		return $this->terminalInfo;
+	}
+
+	public function setTerminalInfo($terminalInfo)
+	{
+		$this->terminalInfo = $terminalInfo;
+	}
+
+	public function getProdCode()
+	{
+		return $this->prodCode;
+	}
+
+	public function setProdCode($prodCode)
+	{
+		$this->prodCode = $prodCode;
+	}
+
+	public function setApiVersion($apiVersion)
+	{
+		$this->apiVersion=$apiVersion;
+	}
+
+	public function getApiVersion()
+	{
+		return $this->apiVersion;
+	}
+
+  public function setNeedEncrypt($needEncrypt)
+  {
+
+     $this->needEncrypt=$needEncrypt;
+
+  }
+
+  public function getNeedEncrypt()
+  {
+    return $this->needEncrypt;
+  }
+
+}

+ 152 - 0
application/common/library/alipay/aop/request/AlipayAcquireCloseRequest.php

@@ -0,0 +1,152 @@
+<?php
+/**
+ * ALIPAY API: alipay.acquire.close request
+ *
+ * @author auto create
+ * @since 1.0, 2019-03-08 15:29:11
+ */
+class AlipayAcquireCloseRequest
+{
+	/** 
+	 * 卖家的操作员ID
+	 **/
+	private $operatorId;
+	
+	/** 
+	 * 支付宝合作商户网站唯一订单号
+	 **/
+	private $outTradeNo;
+	
+	/** 
+	 * 该交易在支付宝系统中的交易流水号。
+最短16位,最长64位。
+如果同时传了out_trade_no和trade_no,则以trade_no为准
+	 **/
+	private $tradeNo;
+
+	private $apiParas = array();
+	private $terminalType;
+	private $terminalInfo;
+	private $prodCode;
+	private $apiVersion="1.0";
+	private $notifyUrl;
+	private $returnUrl;
+    private $needEncrypt=false;
+
+	
+	public function setOperatorId($operatorId)
+	{
+		$this->operatorId = $operatorId;
+		$this->apiParas["operator_id"] = $operatorId;
+	}
+
+	public function getOperatorId()
+	{
+		return $this->operatorId;
+	}
+
+	public function setOutTradeNo($outTradeNo)
+	{
+		$this->outTradeNo = $outTradeNo;
+		$this->apiParas["out_trade_no"] = $outTradeNo;
+	}
+
+	public function getOutTradeNo()
+	{
+		return $this->outTradeNo;
+	}
+
+	public function setTradeNo($tradeNo)
+	{
+		$this->tradeNo = $tradeNo;
+		$this->apiParas["trade_no"] = $tradeNo;
+	}
+
+	public function getTradeNo()
+	{
+		return $this->tradeNo;
+	}
+
+	public function getApiMethodName()
+	{
+		return "alipay.acquire.close";
+	}
+
+	public function setNotifyUrl($notifyUrl)
+	{
+		$this->notifyUrl=$notifyUrl;
+	}
+
+	public function getNotifyUrl()
+	{
+		return $this->notifyUrl;
+	}
+
+	public function setReturnUrl($returnUrl)
+	{
+		$this->returnUrl=$returnUrl;
+	}
+
+	public function getReturnUrl()
+	{
+		return $this->returnUrl;
+	}
+
+	public function getApiParas()
+	{
+		return $this->apiParas;
+	}
+
+	public function getTerminalType()
+	{
+		return $this->terminalType;
+	}
+
+	public function setTerminalType($terminalType)
+	{
+		$this->terminalType = $terminalType;
+	}
+
+	public function getTerminalInfo()
+	{
+		return $this->terminalInfo;
+	}
+
+	public function setTerminalInfo($terminalInfo)
+	{
+		$this->terminalInfo = $terminalInfo;
+	}
+
+	public function getProdCode()
+	{
+		return $this->prodCode;
+	}
+
+	public function setProdCode($prodCode)
+	{
+		$this->prodCode = $prodCode;
+	}
+
+	public function setApiVersion($apiVersion)
+	{
+		$this->apiVersion=$apiVersion;
+	}
+
+	public function getApiVersion()
+	{
+		return $this->apiVersion;
+	}
+
+  public function setNeedEncrypt($needEncrypt)
+  {
+
+     $this->needEncrypt=$needEncrypt;
+
+  }
+
+  public function getNeedEncrypt()
+  {
+    return $this->needEncrypt;
+  }
+
+}

+ 550 - 0
application/common/library/alipay/aop/request/AlipayAcquireCreateandpayRequest.php

@@ -0,0 +1,550 @@
+<?php
+/**
+ * ALIPAY API: alipay.acquire.createandpay request
+ *
+ * @author auto create
+ * @since 1.0, 2019-07-18 14:08:22
+ */
+class AlipayAcquireCreateandpayRequest
+{
+	/** 
+	 * 证书签名
+	 **/
+	private $alipayCaRequest;
+	
+	/** 
+	 * 对一笔交易的具体描述信息。如果是多种商品,请将商品描述字符串累加传给body。
+	 **/
+	private $body;
+	
+	/** 
+	 * 买家支付宝账号,可以为email或者手机号。
+	 **/
+	private $buyerEmail;
+	
+	/** 
+	 * 买家支付宝账号对应的支付宝唯一用户号。
+以2088开头的纯16位数字。
+	 **/
+	private $buyerId;
+	
+	/** 
+	 * 描述多渠道收单的渠道明细信息,json格式,具体请参见“4.5 渠道明细说明”。
+	 **/
+	private $channelParameters;
+	
+	/** 
+	 * 订单金额币种。
+目前只支持传入156(人民币)。
+如果为空,则默认设置为156。
+	 **/
+	private $currency;
+	
+	/** 
+	 * 动态ID。
+	 **/
+	private $dynamicId;
+	
+	/** 
+	 * 动态ID类型:
+&#1048698;
+soundwave:声波
+&#1048698;
+qrcode:二维码
+&#1048698;
+barcode:条码
+&#1048698;
+wave_code:声波,等同soundwave
+&#1048698;
+qr_code:二维码,等同qrcode
+&#1048698;
+bar_code:条码,等同barcode
+建议取值wave_code、qr_code、bar_code。
+	 **/
+	private $dynamicIdType;
+	
+	/** 
+	 * 用于商户的特定业务信息的传递,只有商户与支付宝约定了传递此参数且约定了参数含义,此参数才有效。
+比如可传递声波支付场景下的门店ID等信息,以json格式传输,具体请参见“4.7 业务扩展参数说明”。
+	 **/
+	private $extendParams;
+	
+	/** 
+	 * xml或json
+	 **/
+	private $formatType;
+	
+	/** 
+	 * 描述商品明细信息,json格式,具体请参见“4.3 商品明细说明”。
+	 **/
+	private $goodsDetail;
+	
+	/** 
+	 * 设置未付款交易的超时时间,一旦超时,该笔交易就会自动被关闭。
+取值范围:1m~15d。
+m-分钟,h-小时,d-天,1c-当天(无论交易何时创建,都在0点关闭)。
+该参数数值不接受小数点,如1.5h,可转换为90m。
+该功能需要联系支付宝配置关闭时间。
+	 **/
+	private $itBPay;
+	
+	/** 
+	 * 描述预付卡相关的明细信息,json格式,具体请参见“4.8 预付卡明细参数说明”。
+	 **/
+	private $mcardParameters;
+	
+	/** 
+	 * 卖家的操作员ID。
+	 **/
+	private $operatorId;
+	
+	/** 
+	 * 操作员的类型:
+&#1048698;
+0:支付宝操作员
+&#1048698;
+1:商户的操作员
+如果传入其它值或者为空,则默认设置为1。
+	 **/
+	private $operatorType;
+	
+	/** 
+	 * 支付宝合作商户网站唯一订单号。
+	 **/
+	private $outTradeNo;
+	
+	/** 
+	 * 订单中商品的单价。
+如果请求时传入本参数,则必须满足total_fee=price×quantity的条件。
+	 **/
+	private $price;
+	
+	/** 
+	 * 订单中商品的数量。
+如果请求时传入本参数,则必须满足total_fee=price×quantity的条件。
+	 **/
+	private $quantity;
+	
+	/** 
+	 * 业务关联ID集合,用于放置商户的订单号、支付流水号等信息,json格式,具体请参见“4.6 业务关联ID集合说明”。
+	 **/
+	private $refIds;
+	
+	/** 
+	 * 描述分账明细信息,json格式,具体请参见“4.4 分账明细说明”。
+	 **/
+	private $royaltyParameters;
+	
+	/** 
+	 * 卖家的分账类型,目前只支持传入ROYALTY(普通分账类型)。
+	 **/
+	private $royaltyType;
+	
+	/** 
+	 * 卖家支付宝账号,可以为email或者手机号。
+如果seller_id不为空,则以seller_id的值作为卖家账号,忽略本参数。
+	 **/
+	private $sellerEmail;
+	
+	/** 
+	 * 卖家支付宝账号对应的支付宝唯一用户号。
+以2088开头的纯16位数字。
+如果和seller_email同时为空,则本参数默认填充partner的值。
+	 **/
+	private $sellerId;
+	
+	/** 
+	 * 收银台页面上,商品展示的超链接。
+	 **/
+	private $showUrl;
+	
+	/** 
+	 * 商品的标题/交易标题/订单标题/订单关键字等。
+该参数最长为128个汉字。
+	 **/
+	private $subject;
+	
+	/** 
+	 * 该笔订单的资金总额,取值范围[0.01,100000000],精确到小数点后2位。
+	 **/
+	private $totalFee;
+
+	private $apiParas = array();
+	private $terminalType;
+	private $terminalInfo;
+	private $prodCode;
+	private $apiVersion="1.0";
+	private $notifyUrl;
+	private $returnUrl;
+    private $needEncrypt=false;
+
+	
+	public function setAlipayCaRequest($alipayCaRequest)
+	{
+		$this->alipayCaRequest = $alipayCaRequest;
+		$this->apiParas["alipay_ca_request"] = $alipayCaRequest;
+	}
+
+	public function getAlipayCaRequest()
+	{
+		return $this->alipayCaRequest;
+	}
+
+	public function setBody($body)
+	{
+		$this->body = $body;
+		$this->apiParas["body"] = $body;
+	}
+
+	public function getBody()
+	{
+		return $this->body;
+	}
+
+	public function setBuyerEmail($buyerEmail)
+	{
+		$this->buyerEmail = $buyerEmail;
+		$this->apiParas["buyer_email"] = $buyerEmail;
+	}
+
+	public function getBuyerEmail()
+	{
+		return $this->buyerEmail;
+	}
+
+	public function setBuyerId($buyerId)
+	{
+		$this->buyerId = $buyerId;
+		$this->apiParas["buyer_id"] = $buyerId;
+	}
+
+	public function getBuyerId()
+	{
+		return $this->buyerId;
+	}
+
+	public function setChannelParameters($channelParameters)
+	{
+		$this->channelParameters = $channelParameters;
+		$this->apiParas["channel_parameters"] = $channelParameters;
+	}
+
+	public function getChannelParameters()
+	{
+		return $this->channelParameters;
+	}
+
+	public function setCurrency($currency)
+	{
+		$this->currency = $currency;
+		$this->apiParas["currency"] = $currency;
+	}
+
+	public function getCurrency()
+	{
+		return $this->currency;
+	}
+
+	public function setDynamicId($dynamicId)
+	{
+		$this->dynamicId = $dynamicId;
+		$this->apiParas["dynamic_id"] = $dynamicId;
+	}
+
+	public function getDynamicId()
+	{
+		return $this->dynamicId;
+	}
+
+	public function setDynamicIdType($dynamicIdType)
+	{
+		$this->dynamicIdType = $dynamicIdType;
+		$this->apiParas["dynamic_id_type"] = $dynamicIdType;
+	}
+
+	public function getDynamicIdType()
+	{
+		return $this->dynamicIdType;
+	}
+
+	public function setExtendParams($extendParams)
+	{
+		$this->extendParams = $extendParams;
+		$this->apiParas["extend_params"] = $extendParams;
+	}
+
+	public function getExtendParams()
+	{
+		return $this->extendParams;
+	}
+
+	public function setFormatType($formatType)
+	{
+		$this->formatType = $formatType;
+		$this->apiParas["format_type"] = $formatType;
+	}
+
+	public function getFormatType()
+	{
+		return $this->formatType;
+	}
+
+	public function setGoodsDetail($goodsDetail)
+	{
+		$this->goodsDetail = $goodsDetail;
+		$this->apiParas["goods_detail"] = $goodsDetail;
+	}
+
+	public function getGoodsDetail()
+	{
+		return $this->goodsDetail;
+	}
+
+	public function setItBPay($itBPay)
+	{
+		$this->itBPay = $itBPay;
+		$this->apiParas["it_b_pay"] = $itBPay;
+	}
+
+	public function getItBPay()
+	{
+		return $this->itBPay;
+	}
+
+	public function setMcardParameters($mcardParameters)
+	{
+		$this->mcardParameters = $mcardParameters;
+		$this->apiParas["mcard_parameters"] = $mcardParameters;
+	}
+
+	public function getMcardParameters()
+	{
+		return $this->mcardParameters;
+	}
+
+	public function setOperatorId($operatorId)
+	{
+		$this->operatorId = $operatorId;
+		$this->apiParas["operator_id"] = $operatorId;
+	}
+
+	public function getOperatorId()
+	{
+		return $this->operatorId;
+	}
+
+	public function setOperatorType($operatorType)
+	{
+		$this->operatorType = $operatorType;
+		$this->apiParas["operator_type"] = $operatorType;
+	}
+
+	public function getOperatorType()
+	{
+		return $this->operatorType;
+	}
+
+	public function setOutTradeNo($outTradeNo)
+	{
+		$this->outTradeNo = $outTradeNo;
+		$this->apiParas["out_trade_no"] = $outTradeNo;
+	}
+
+	public function getOutTradeNo()
+	{
+		return $this->outTradeNo;
+	}
+
+	public function setPrice($price)
+	{
+		$this->price = $price;
+		$this->apiParas["price"] = $price;
+	}
+
+	public function getPrice()
+	{
+		return $this->price;
+	}
+
+	public function setQuantity($quantity)
+	{
+		$this->quantity = $quantity;
+		$this->apiParas["quantity"] = $quantity;
+	}
+
+	public function getQuantity()
+	{
+		return $this->quantity;
+	}
+
+	public function setRefIds($refIds)
+	{
+		$this->refIds = $refIds;
+		$this->apiParas["ref_ids"] = $refIds;
+	}
+
+	public function getRefIds()
+	{
+		return $this->refIds;
+	}
+
+	public function setRoyaltyParameters($royaltyParameters)
+	{
+		$this->royaltyParameters = $royaltyParameters;
+		$this->apiParas["royalty_parameters"] = $royaltyParameters;
+	}
+
+	public function getRoyaltyParameters()
+	{
+		return $this->royaltyParameters;
+	}
+
+	public function setRoyaltyType($royaltyType)
+	{
+		$this->royaltyType = $royaltyType;
+		$this->apiParas["royalty_type"] = $royaltyType;
+	}
+
+	public function getRoyaltyType()
+	{
+		return $this->royaltyType;
+	}
+
+	public function setSellerEmail($sellerEmail)
+	{
+		$this->sellerEmail = $sellerEmail;
+		$this->apiParas["seller_email"] = $sellerEmail;
+	}
+
+	public function getSellerEmail()
+	{
+		return $this->sellerEmail;
+	}
+
+	public function setSellerId($sellerId)
+	{
+		$this->sellerId = $sellerId;
+		$this->apiParas["seller_id"] = $sellerId;
+	}
+
+	public function getSellerId()
+	{
+		return $this->sellerId;
+	}
+
+	public function setShowUrl($showUrl)
+	{
+		$this->showUrl = $showUrl;
+		$this->apiParas["show_url"] = $showUrl;
+	}
+
+	public function getShowUrl()
+	{
+		return $this->showUrl;
+	}
+
+	public function setSubject($subject)
+	{
+		$this->subject = $subject;
+		$this->apiParas["subject"] = $subject;
+	}
+
+	public function getSubject()
+	{
+		return $this->subject;
+	}
+
+	public function setTotalFee($totalFee)
+	{
+		$this->totalFee = $totalFee;
+		$this->apiParas["total_fee"] = $totalFee;
+	}
+
+	public function getTotalFee()
+	{
+		return $this->totalFee;
+	}
+
+	public function getApiMethodName()
+	{
+		return "alipay.acquire.createandpay";
+	}
+
+	public function setNotifyUrl($notifyUrl)
+	{
+		$this->notifyUrl=$notifyUrl;
+	}
+
+	public function getNotifyUrl()
+	{
+		return $this->notifyUrl;
+	}
+
+	public function setReturnUrl($returnUrl)
+	{
+		$this->returnUrl=$returnUrl;
+	}
+
+	public function getReturnUrl()
+	{
+		return $this->returnUrl;
+	}
+
+	public function getApiParas()
+	{
+		return $this->apiParas;
+	}
+
+	public function getTerminalType()
+	{
+		return $this->terminalType;
+	}
+
+	public function setTerminalType($terminalType)
+	{
+		$this->terminalType = $terminalType;
+	}
+
+	public function getTerminalInfo()
+	{
+		return $this->terminalInfo;
+	}
+
+	public function setTerminalInfo($terminalInfo)
+	{
+		$this->terminalInfo = $terminalInfo;
+	}
+
+	public function getProdCode()
+	{
+		return $this->prodCode;
+	}
+
+	public function setProdCode($prodCode)
+	{
+		$this->prodCode = $prodCode;
+	}
+
+	public function setApiVersion($apiVersion)
+	{
+		$this->apiVersion=$apiVersion;
+	}
+
+	public function getApiVersion()
+	{
+		return $this->apiVersion;
+	}
+
+  public function setNeedEncrypt($needEncrypt)
+  {
+
+     $this->needEncrypt=$needEncrypt;
+
+  }
+
+  public function getNeedEncrypt()
+  {
+    return $this->needEncrypt;
+  }
+
+}

+ 402 - 0
application/common/library/alipay/aop/request/AlipayAcquirePrecreateRequest.php

@@ -0,0 +1,402 @@
+<?php
+/**
+ * ALIPAY API: alipay.acquire.precreate request
+ *
+ * @author auto create
+ * @since 1.0, 2019-03-08 15:29:11
+ */
+class AlipayAcquirePrecreateRequest
+{
+	/** 
+	 * 对一笔交易的具体描述信息。如果是多种商品,请将商品描述字符串累加传给body
+	 **/
+	private $body;
+	
+	/** 
+	 * 描述多渠道收单的渠道明细信息,json格式
+	 **/
+	private $channelParameters;
+	
+	/** 
+	 * 订单金额币种。目前只支持传入156(人民币)。
+如果为空,则默认设置为156
+	 **/
+	private $currency;
+	
+	/** 
+	 * 公用业务扩展信息。用于商户的特定业务信息的传递,只有商户与支付宝约定了传递此参数且约定了参数含义,此参数才有效。
+比如可传递二维码支付场景下的门店ID等信息,以json格式传输。
+	 **/
+	private $extendParams;
+	
+	/** 
+	 * 描述商品明细信息,json格式。
+	 **/
+	private $goodsDetail;
+	
+	/** 
+	 * 订单支付超时时间。设置未付款交易的超时时间,一旦超时,该笔交易就会自动被关闭。
+取值范围:1m~15d。
+m-分钟,h-小时,d-天,1c-当天(无论交易何时创建,都在0点关闭)。
+该参数数值不接受小数点,如1.5h,可转换为90m。
+该功能需要联系支付宝配置关闭时间。
+	 **/
+	private $itBPay;
+	
+	/** 
+	 * 操作员的类型:
+0:支付宝操作员
+1:商户的操作员
+如果传入其它值或者为空,则默认设置为1
+	 **/
+	private $operatorCode;
+	
+	/** 
+	 * 卖家的操作员ID
+	 **/
+	private $operatorId;
+	
+	/** 
+	 * 支付宝合作商户网站唯一订单号
+	 **/
+	private $outTradeNo;
+	
+	/** 
+	 * 订单中商品的单价。
+如果请求时传入本参数,则必须满足total_fee=price×quantity的条件
+	 **/
+	private $price;
+	
+	/** 
+	 * 订单中商品的数量。
+如果请求时传入本参数,则必须满足total_fee=price×quantity的条件
+	 **/
+	private $quantity;
+	
+	/** 
+	 * 分账信息。
+描述分账明细信息,json格式
+	 **/
+	private $royaltyParameters;
+	
+	/** 
+	 * 分账类型。卖家的分账类型,目前只支持传入ROYALTY(普通分账类型)
+	 **/
+	private $royaltyType;
+	
+	/** 
+	 * 卖家支付宝账号,可以为email或者手机号。如果seller_id不为空,则以seller_id的值作为卖家账号,忽略本参数
+	 **/
+	private $sellerEmail;
+	
+	/** 
+	 * 卖家支付宝账号对应的支付宝唯一用户号,以2088开头的纯16位数字。如果和seller_email同时为空,则本参数默认填充partner的值
+	 **/
+	private $sellerId;
+	
+	/** 
+	 * 收银台页面上,商品展示的超链接
+	 **/
+	private $showUrl;
+	
+	/** 
+	 * 商品购买
+	 **/
+	private $subject;
+	
+	/** 
+	 * 订单金额。该笔订单的资金总额,取值范围[0.01,100000000],精确到小数点后2位。
+	 **/
+	private $totalFee;
+
+	private $apiParas = array();
+	private $terminalType;
+	private $terminalInfo;
+	private $prodCode;
+	private $apiVersion="1.0";
+	private $notifyUrl;
+	private $returnUrl;
+    private $needEncrypt=false;
+
+	
+	public function setBody($body)
+	{
+		$this->body = $body;
+		$this->apiParas["body"] = $body;
+	}
+
+	public function getBody()
+	{
+		return $this->body;
+	}
+
+	public function setChannelParameters($channelParameters)
+	{
+		$this->channelParameters = $channelParameters;
+		$this->apiParas["channel_parameters"] = $channelParameters;
+	}
+
+	public function getChannelParameters()
+	{
+		return $this->channelParameters;
+	}
+
+	public function setCurrency($currency)
+	{
+		$this->currency = $currency;
+		$this->apiParas["currency"] = $currency;
+	}
+
+	public function getCurrency()
+	{
+		return $this->currency;
+	}
+
+	public function setExtendParams($extendParams)
+	{
+		$this->extendParams = $extendParams;
+		$this->apiParas["extend_params"] = $extendParams;
+	}
+
+	public function getExtendParams()
+	{
+		return $this->extendParams;
+	}
+
+	public function setGoodsDetail($goodsDetail)
+	{
+		$this->goodsDetail = $goodsDetail;
+		$this->apiParas["goods_detail"] = $goodsDetail;
+	}
+
+	public function getGoodsDetail()
+	{
+		return $this->goodsDetail;
+	}
+
+	public function setItBPay($itBPay)
+	{
+		$this->itBPay = $itBPay;
+		$this->apiParas["it_b_pay"] = $itBPay;
+	}
+
+	public function getItBPay()
+	{
+		return $this->itBPay;
+	}
+
+	public function setOperatorCode($operatorCode)
+	{
+		$this->operatorCode = $operatorCode;
+		$this->apiParas["operator_code"] = $operatorCode;
+	}
+
+	public function getOperatorCode()
+	{
+		return $this->operatorCode;
+	}
+
+	public function setOperatorId($operatorId)
+	{
+		$this->operatorId = $operatorId;
+		$this->apiParas["operator_id"] = $operatorId;
+	}
+
+	public function getOperatorId()
+	{
+		return $this->operatorId;
+	}
+
+	public function setOutTradeNo($outTradeNo)
+	{
+		$this->outTradeNo = $outTradeNo;
+		$this->apiParas["out_trade_no"] = $outTradeNo;
+	}
+
+	public function getOutTradeNo()
+	{
+		return $this->outTradeNo;
+	}
+
+	public function setPrice($price)
+	{
+		$this->price = $price;
+		$this->apiParas["price"] = $price;
+	}
+
+	public function getPrice()
+	{
+		return $this->price;
+	}
+
+	public function setQuantity($quantity)
+	{
+		$this->quantity = $quantity;
+		$this->apiParas["quantity"] = $quantity;
+	}
+
+	public function getQuantity()
+	{
+		return $this->quantity;
+	}
+
+	public function setRoyaltyParameters($royaltyParameters)
+	{
+		$this->royaltyParameters = $royaltyParameters;
+		$this->apiParas["royalty_parameters"] = $royaltyParameters;
+	}
+
+	public function getRoyaltyParameters()
+	{
+		return $this->royaltyParameters;
+	}
+
+	public function setRoyaltyType($royaltyType)
+	{
+		$this->royaltyType = $royaltyType;
+		$this->apiParas["royalty_type"] = $royaltyType;
+	}
+
+	public function getRoyaltyType()
+	{
+		return $this->royaltyType;
+	}
+
+	public function setSellerEmail($sellerEmail)
+	{
+		$this->sellerEmail = $sellerEmail;
+		$this->apiParas["seller_email"] = $sellerEmail;
+	}
+
+	public function getSellerEmail()
+	{
+		return $this->sellerEmail;
+	}
+
+	public function setSellerId($sellerId)
+	{
+		$this->sellerId = $sellerId;
+		$this->apiParas["seller_id"] = $sellerId;
+	}
+
+	public function getSellerId()
+	{
+		return $this->sellerId;
+	}
+
+	public function setShowUrl($showUrl)
+	{
+		$this->showUrl = $showUrl;
+		$this->apiParas["show_url"] = $showUrl;
+	}
+
+	public function getShowUrl()
+	{
+		return $this->showUrl;
+	}
+
+	public function setSubject($subject)
+	{
+		$this->subject = $subject;
+		$this->apiParas["subject"] = $subject;
+	}
+
+	public function getSubject()
+	{
+		return $this->subject;
+	}
+
+	public function setTotalFee($totalFee)
+	{
+		$this->totalFee = $totalFee;
+		$this->apiParas["total_fee"] = $totalFee;
+	}
+
+	public function getTotalFee()
+	{
+		return $this->totalFee;
+	}
+
+	public function getApiMethodName()
+	{
+		return "alipay.acquire.precreate";
+	}
+
+	public function setNotifyUrl($notifyUrl)
+	{
+		$this->notifyUrl=$notifyUrl;
+	}
+
+	public function getNotifyUrl()
+	{
+		return $this->notifyUrl;
+	}
+
+	public function setReturnUrl($returnUrl)
+	{
+		$this->returnUrl=$returnUrl;
+	}
+
+	public function getReturnUrl()
+	{
+		return $this->returnUrl;
+	}
+
+	public function getApiParas()
+	{
+		return $this->apiParas;
+	}
+
+	public function getTerminalType()
+	{
+		return $this->terminalType;
+	}
+
+	public function setTerminalType($terminalType)
+	{
+		$this->terminalType = $terminalType;
+	}
+
+	public function getTerminalInfo()
+	{
+		return $this->terminalInfo;
+	}
+
+	public function setTerminalInfo($terminalInfo)
+	{
+		$this->terminalInfo = $terminalInfo;
+	}
+
+	public function getProdCode()
+	{
+		return $this->prodCode;
+	}
+
+	public function setProdCode($prodCode)
+	{
+		$this->prodCode = $prodCode;
+	}
+
+	public function setApiVersion($apiVersion)
+	{
+		$this->apiVersion=$apiVersion;
+	}
+
+	public function getApiVersion()
+	{
+		return $this->apiVersion;
+	}
+
+  public function setNeedEncrypt($needEncrypt)
+  {
+
+     $this->needEncrypt=$needEncrypt;
+
+  }
+
+  public function getNeedEncrypt()
+  {
+    return $this->needEncrypt;
+  }
+
+}

+ 136 - 0
application/common/library/alipay/aop/request/AlipayAcquireQueryRequest.php

@@ -0,0 +1,136 @@
+<?php
+/**
+ * ALIPAY API: alipay.acquire.query request
+ *
+ * @author auto create
+ * @since 1.0, 2019-03-08 15:29:11
+ */
+class AlipayAcquireQueryRequest
+{
+	/** 
+	 * 支付宝合作商户网站唯一订单号
+	 **/
+	private $outTradeNo;
+	
+	/** 
+	 * 该交易在支付宝系统中的交易流水号。
+最短16位,最长64位。
+如果同时传了out_trade_no和trade_no,则以trade_no为准。
+	 **/
+	private $tradeNo;
+
+	private $apiParas = array();
+	private $terminalType;
+	private $terminalInfo;
+	private $prodCode;
+	private $apiVersion="1.0";
+	private $notifyUrl;
+	private $returnUrl;
+    private $needEncrypt=false;
+
+	
+	public function setOutTradeNo($outTradeNo)
+	{
+		$this->outTradeNo = $outTradeNo;
+		$this->apiParas["out_trade_no"] = $outTradeNo;
+	}
+
+	public function getOutTradeNo()
+	{
+		return $this->outTradeNo;
+	}
+
+	public function setTradeNo($tradeNo)
+	{
+		$this->tradeNo = $tradeNo;
+		$this->apiParas["trade_no"] = $tradeNo;
+	}
+
+	public function getTradeNo()
+	{
+		return $this->tradeNo;
+	}
+
+	public function getApiMethodName()
+	{
+		return "alipay.acquire.query";
+	}
+
+	public function setNotifyUrl($notifyUrl)
+	{
+		$this->notifyUrl=$notifyUrl;
+	}
+
+	public function getNotifyUrl()
+	{
+		return $this->notifyUrl;
+	}
+
+	public function setReturnUrl($returnUrl)
+	{
+		$this->returnUrl=$returnUrl;
+	}
+
+	public function getReturnUrl()
+	{
+		return $this->returnUrl;
+	}
+
+	public function getApiParas()
+	{
+		return $this->apiParas;
+	}
+
+	public function getTerminalType()
+	{
+		return $this->terminalType;
+	}
+
+	public function setTerminalType($terminalType)
+	{
+		$this->terminalType = $terminalType;
+	}
+
+	public function getTerminalInfo()
+	{
+		return $this->terminalInfo;
+	}
+
+	public function setTerminalInfo($terminalInfo)
+	{
+		$this->terminalInfo = $terminalInfo;
+	}
+
+	public function getProdCode()
+	{
+		return $this->prodCode;
+	}
+
+	public function setProdCode($prodCode)
+	{
+		$this->prodCode = $prodCode;
+	}
+
+	public function setApiVersion($apiVersion)
+	{
+		$this->apiVersion=$apiVersion;
+	}
+
+	public function getApiVersion()
+	{
+		return $this->apiVersion;
+	}
+
+  public function setNeedEncrypt($needEncrypt)
+  {
+
+     $this->needEncrypt=$needEncrypt;
+
+  }
+
+  public function getNeedEncrypt()
+  {
+    return $this->needEncrypt;
+  }
+
+}

Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff