lizuxiao 2 lat temu
rodzic
commit
e4ec64a95c
100 zmienionych plików z 15242 dodań i 0 usunięć
  1. 3 0
      .constant
  2. 7 0
      .gitignore
  3. 8 0
      .htaccess
  4. 42 0
      .travis.yml
  5. 2 0
      .version
  6. 33 0
      LICENSE.txt
  7. 1 0
      app/.htaccess
  8. 24 0
      app/AppService.php
  9. 68 0
      app/ExceptionHandle.php
  10. 24 0
      app/Request.php
  11. 151 0
      app/admin/common.php
  12. 25 0
      app/admin/config/route.php
  13. 20 0
      app/admin/config/view.php
  14. 36 0
      app/admin/controller/AdminException.php
  15. 87 0
      app/admin/controller/AuthController.php
  16. 473 0
      app/admin/controller/Index.php
  17. 67 0
      app/admin/controller/Login.php
  18. 118 0
      app/admin/controller/SystemBasic.php
  19. 43 0
      app/admin/controller/Test.php
  20. 420 0
      app/admin/controller/article/Article.php
  21. 175 0
      app/admin/controller/article/ArticleCategory.php
  22. 196 0
      app/admin/controller/article/WechatNews.php
  23. 73 0
      app/admin/controller/enterprise/Apply.php
  24. 115 0
      app/admin/controller/enterprise/Auth.php
  25. 94 0
      app/admin/controller/enterprise/Job.php
  26. 182 0
      app/admin/controller/enterprise/Lists.php
  27. 159 0
      app/admin/controller/enterprise/Style.php
  28. 288 0
      app/admin/controller/setting/SystemAdmin.php
  29. 376 0
      app/admin/controller/setting/SystemConfig.php
  30. 179 0
      app/admin/controller/setting/SystemConfigTab.php
  31. 127 0
      app/admin/controller/setting/SystemGroup.php
  32. 279 0
      app/admin/controller/setting/SystemGroupData.php
  33. 208 0
      app/admin/controller/setting/SystemMenus.php
  34. 130 0
      app/admin/controller/setting/SystemNotice.php
  35. 142 0
      app/admin/controller/setting/SystemRole.php
  36. 86 0
      app/admin/controller/system/Clear.php
  37. 50 0
      app/admin/controller/system/SystemAttachment.php
  38. 250 0
      app/admin/controller/system/SystemCleardata.php
  39. 245 0
      app/admin/controller/system/SystemDatabackup.php
  40. 303 0
      app/admin/controller/system/SystemFile.php
  41. 39 0
      app/admin/controller/system/SystemLog.php
  42. 626 0
      app/admin/controller/user/User.php
  43. 101 0
      app/admin/controller/user/UserGroup.php
  44. 303 0
      app/admin/controller/user/UserNotice.php
  45. 42 0
      app/admin/controller/wechat/Menus.php
  46. 195 0
      app/admin/controller/wechat/Reply.php
  47. 168 0
      app/admin/controller/wechat/StoreService.php
  48. 34 0
      app/admin/controller/wechat/WechatMessage.php
  49. 279 0
      app/admin/controller/wechat/WechatNewsCategory.php
  50. 135 0
      app/admin/controller/wechat/WechatTemplate.php
  51. 390 0
      app/admin/controller/wechat/WechatUser.php
  52. 7 0
      app/admin/controller/wechat/index.php
  53. 279 0
      app/admin/controller/widget/Images.php
  54. 75 0
      app/admin/controller/widget/Video.php
  55. 53 0
      app/admin/controller/widget/Widgets.php
  56. 21 0
      app/admin/event.php
  57. 50 0
      app/admin/logic/BaseLogic.php
  58. 138 0
      app/admin/logic/enterprise/ApplyLogic.php
  59. 102 0
      app/admin/logic/enterprise/JobLogic.php
  60. 164 0
      app/admin/model/article/Article.php
  61. 121 0
      app/admin/model/article/ArticleCategory.php
  62. 61 0
      app/admin/model/article/ArticleReply.php
  63. 130 0
      app/admin/model/enterprise/EnterCategory.php
  64. 27 0
      app/admin/model/enterprise/EnterPriseType.php
  65. 63 0
      app/admin/model/enterprise/EnterPriseUser.php
  66. 174 0
      app/admin/model/system/SystemAdmin.php
  67. 147 0
      app/admin/model/system/SystemAttachment.php
  68. 110 0
      app/admin/model/system/SystemAttachmentCategory.php
  69. 51 0
      app/admin/model/system/SystemAttachmentType.php
  70. 545 0
      app/admin/model/system/SystemConfig.php
  71. 108 0
      app/admin/model/system/SystemConfigTab.php
  72. 35 0
      app/admin/model/system/SystemFile.php
  73. 43 0
      app/admin/model/system/SystemGroup.php
  74. 147 0
      app/admin/model/system/SystemGroupData.php
  75. 142 0
      app/admin/model/system/SystemLog.php
  76. 226 0
      app/admin/model/system/SystemMenus.php
  77. 147 0
      app/admin/model/system/SystemNotice.php
  78. 91 0
      app/admin/model/system/SystemRole.php
  79. 1231 0
      app/admin/model/user/User.php
  80. 61 0
      app/admin/model/user/UserAddress.php
  81. 330 0
      app/admin/model/user/UserBill.php
  82. 340 0
      app/admin/model/user/UserExtract.php
  83. 44 0
      app/admin/model/user/UserGroup.php
  84. 86 0
      app/admin/model/user/UserLevel.php
  85. 80 0
      app/admin/model/user/UserNotice.php
  86. 33 0
      app/admin/model/user/UserNoticeSee.php
  87. 129 0
      app/admin/model/user/UserPoint.php
  88. 176 0
      app/admin/model/user/UserRecharge.php
  89. 41 0
      app/admin/model/user/UserTaskFinish.php
  90. 70 0
      app/admin/model/wechat/StoreService.php
  91. 46 0
      app/admin/model/wechat/StoreServiceLog.php
  92. 288 0
      app/admin/model/wechat/WechatMessage.php
  93. 138 0
      app/admin/model/wechat/WechatNews.php
  94. 105 0
      app/admin/model/wechat/WechatNewsCategory.php
  95. 122 0
      app/admin/model/wechat/WechatQrcode.php
  96. 225 0
      app/admin/model/wechat/WechatReply.php
  97. 53 0
      app/admin/model/wechat/WechatTemplate.php
  98. 736 0
      app/admin/model/wechat/WechatUser.php
  99. 19 0
      app/admin/provider.php
  100. 11 0
      app/admin/readme.txt

+ 3 - 0
.constant

@@ -0,0 +1,3 @@
+<?php
+define('INSTALL_DATE',1648690394);
+define('SERIALNUMBER','HbnTxH');

+ 7 - 0
.gitignore

@@ -0,0 +1,7 @@
+/.idea
+/.vscode
+*.log
+/.env
+**/*.pid
+runtime/
+public/uploads

+ 8 - 0
.htaccess

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

+ 42 - 0
.travis.yml

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

+ 2 - 0
.version

@@ -0,0 +1,2 @@
+version=CRMEB-DT v3.2.2
+version_code=134

+ 33 - 0
LICENSE.txt

@@ -0,0 +1,33 @@
+版权所有 (c)2017-2027,西安众邦网络科技有限公司 保留所有权利。
+感谢您选择CrmEb开源客户管理+电商系统(简称CRMEB),CRMEB是国内最稳定、最强大、最先进的互联网电商平台解决方案之一,CRMEB基于 PHP + MySQL 的技术,采用ThinkPHP5.0框架开发。
+为了使你正确并合法的使用本软件,请你在使用前务必阅读清楚下面的协议条款:
+本授权协议适用且仅适用于CRMEB任何版本,CRMEB官方对本授权协议的最终解释权和修改权。
+
+一、协议许可的权利
+1、您可以在完全遵守本最终用户授权协议的基础上,将本软件应用于非商业用途,而不必支付软件版权授权费用。
+2、您可以在协议规定的约束和限制范围内修改 CRMEB 源代码或界面风格以适应您的网站要求。
+3、您拥有使用本软件构建的网站全部内容所有权,并独立承担与这些内容的相关法律义务。
+4、获得商业授权之后,您可以将本软件应用于商业用途,同时依据所购买的授权类型中确定的技术支持内容。商业授权用户享有反映和提出意见的权力,相关意见将被作为首要考虑,但没有一定被采纳的承诺或保证。
+
+二、协议许可的权利和限制
+1、未获商业授权之前,不得删除网站底部及相应的官方版权信息和链接。购买商业授权请联系西安众邦网络科技有限公司了解最新说明。CRMEB著作权已在中华人民共和国国家版权局注册(中国国家版权局著作权登记号 2018SR024463),著作权受到法律和国际公约保护。
+2、未经官方许可,不得对本软件或与之关联的商业授权进行出租、出售、抵押或发放子许可证。
+3、不管你的网站是否整体使用 CRMEB ,还是部份栏目使用 CRMEB,在你使用了 CRMEB 的网站主页上必须加上 CRMEB 官方网址(www.crmeb.com)的链接。
+4、未经官方许可,禁止在 CRMEB 的整体或任何部分基础上以发展任何派生版本、修改版本或第三方版本用于重新分发。
+5、如果您未能遵守本协议的条款,您的授权将被终止,所被许可的权利将被收回,并承担相应法律责任。
+
+三、有限担保和免责声明
+1、本软件及所附带的文件是作为不提供任何明确的或隐含的赔偿或担保的形式提供的。 
+2、用户出于自愿而使用本软件,您必须了解使用本软件的风险,在尚未购买产品技术服务之前,我们不承诺对免费用户提供任何形式的技术支持、使用担保,也不承担任何因使用本软件而产生问题的相关责任。
+3、电子文本形式的授权协议如同双方书面签署的协议一样,具有完全的和等同的法律效力。您一旦开始确认本协议并安装 CRMEB,即被视为完全理解并接受本协议的各项条款,在享有上述条款授予的权力的同时,受到相关的约束和限制。协议许可范围以外的行为,将直接违反本授权协议并构成侵权,我们有权随时终止授权,责令停止损害,并保留追究相关责任的权力。
+
+协议发布时间: 2017年8月01日
+版本最新更新: 2019年8月15日 By CRMEB
+
+CRMEB官方网站:http://www.crmeb.com
+CRMEB演示站:http://demo.crmeb.com
+-----------------------------------------------------
+运营团队: 众邦科技
+电   话: 400-8888-794
+邮   箱: admin@xazbkj.com
+网   址: http://www.xazbkj.com

+ 1 - 0
app/.htaccess

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

+ 24 - 0
app/AppService.php

@@ -0,0 +1,24 @@
+<?php
+
+namespace app;
+
+use crmeb\services\SystemConfigService;
+use crmeb\services\GroupDataService;
+use crmeb\utils\Json;
+use think\facade\Db;
+use think\Service;
+
+class AppService extends Service
+{
+
+    public $bind = [
+        'json' => Json::class,
+        'sysConfig' => SystemConfigService::class,
+        'sysGroupData' => GroupDataService::class
+    ];
+
+    public function boot()
+    {
+
+    }
+}

+ 68 - 0
app/ExceptionHandle.php

@@ -0,0 +1,68 @@
+<?php
+// +----------------------------------------------------------------------
+// | ThinkPHP [ WE CAN DO IT JUST THINK ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
+// +----------------------------------------------------------------------
+// | Author: liu21st <liu21st@gmail.com>
+// +----------------------------------------------------------------------
+
+namespace app;
+
+use think\db\exception\DataNotFoundException;
+use think\db\exception\ModelNotFoundException;
+use think\exception\Handle;
+use think\exception\HttpException;
+use think\exception\HttpResponseException;
+use think\exception\ValidateException;
+use think\Response;
+use Throwable;
+
+/**
+ * 应用异常处理类
+ */
+class ExceptionHandle extends Handle
+{
+    /**
+     * 不需要记录信息(日志)的异常类列表
+     * @var array
+     */
+    protected $ignoreReport = [
+        HttpException::class,
+        HttpResponseException::class,
+        ModelNotFoundException::class,
+        DataNotFoundException::class,
+        ValidateException::class,
+    ];
+
+    /**
+     * 记录异常信息(包括日志或者其它方式记录)
+     *
+     * @access public
+     * @param  Throwable $exception
+     * @return void
+     */
+    public function report(Throwable $exception): void
+    {
+        // 使用内置的方式记录异常日志
+        parent::report($exception);
+    }
+
+    /**
+     * Render an exception into an HTTP response.
+     *
+     * @access public
+     * @param \think\Request   $request
+     * @param Throwable $e
+     * @return Response
+     */
+    public function render($request, Throwable $e): Response
+    {
+        // 添加自定义异常处理机制
+
+        // 其他错误交给系统处理
+        return parent::render($request, $e);
+    }
+}

+ 24 - 0
app/Request.php

@@ -0,0 +1,24 @@
+<?php
+// +----------------------------------------------------------------------
+// | ThinkPHP [ WE CAN DO IT JUST THINK ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
+// +----------------------------------------------------------------------
+// | Author: liu21st <liu21st@gmail.com>
+// +----------------------------------------------------------------------
+
+namespace app;
+
+use Spatie\Macroable\Macroable;
+
+/**
+ * @method user()
+ * @method uid()
+ * @method isLogin()
+ */
+class Request extends \think\Request
+{
+    use Macroable;
+}

+ 151 - 0
app/admin/common.php

@@ -0,0 +1,151 @@
+<?php
+// +----------------------------------------------------------------------
+// | ThinkPHP [ WE CAN DO IT JUST THINK ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
+// +----------------------------------------------------------------------
+// | Author: 流年 <liu21st@gmail.com>
+// +----------------------------------------------------------------------
+
+// 应用公共文件
+if (!function_exists('attr_format')) {
+    /**
+     * 格式化属性
+     * @param $arr
+     * @return array
+     */
+    function attr_format($arr)
+    {
+        $data = [];
+        $res = [];
+        $count = count($arr);
+        if ($count > 1) {
+            for ($i = 0; $i < $count - 1; $i++) {
+                if ($i == 0) $data = $arr[$i]['detail'];
+                //替代变量1
+                foreach ($data as $v) {
+                    foreach ($arr[$i + 1]['detail'] as $g) {
+                        //替代变量2
+                        $rep2 = ($i != 0 ? '' : $arr[$i]['value'] . '_$_') . $v . '-$-' . $arr[$i + 1]['value'] . '_$_' . $g;
+                        $tmp[] = $rep2;
+                        if ($i == $count - 2) {
+                            foreach (explode('-$-', $rep2) as $k => $h) {
+                                //替代变量3
+                                $rep3 = explode('_$_', $h);
+                                //替代变量4
+                                $rep4['detail'][$rep3[0]] = isset($rep3[1]) ? $rep3[1] : '';
+                            }
+                            if ($count == count($rep4['detail'])) {
+                                $res_sort = [];
+                                foreach ($arr as $re) {
+                                    $res_sort[$re['value']] = $rep4['detail'][$re['value']];
+                                }
+                                $rep4['detail'] = $res_sort;
+                                $res[] = $rep4;
+                            }
+                        }
+                    }
+                }
+                $data = isset($tmp) ? $tmp : [];
+            }
+        } else {
+            $dataArr = [];
+            foreach ($arr as $k => $v) {
+                foreach ($v['detail'] as $kk => $vv) {
+                    $dataArr[$kk] = $v['value'] . '_' . $vv;
+                    $res[$kk]['detail'][$v['value']] = $vv;
+                }
+            }
+            $data[] = implode('-', $dataArr);
+        }
+        return [$data, $res];
+    }
+}
+if (!function_exists('get_month')) {
+    /**
+     * 格式化月份
+     * @param string $time
+     * @param int $ceil
+     * @return array
+     */
+    function get_month($time = '', $ceil = 0)
+    {
+        if (empty($time)) {
+            $firstday = date("Y-m-01", time());
+            $lastday = date("Y-m-d", strtotime("$firstday +1 month -1 day"));
+        } else if ($time == 'n') {
+            if ($ceil != 0)
+                $season = ceil(date('n') / 3) - $ceil;
+            else
+                $season = ceil(date('n') / 3);
+            $firstday = date('Y-m-01', mktime(0, 0, 0, ($season - 1) * 3 + 1, 1, date('Y')));
+            $lastday = date('Y-m-t', mktime(0, 0, 0, $season * 3, 1, date('Y')));
+        } else if ($time == 'y') {
+            $firstday = date('Y-01-01');
+            $lastday = date('Y-12-31');
+        } else if ($time == 'h') {
+            $firstday = date('Y-m-d', strtotime('this week +' . $ceil . ' day')) . ' 00:00:00';
+            $lastday = date('Y-m-d', strtotime('this week +' . ($ceil + 1) . ' day')) . ' 23:59:59';
+        }
+        return array($firstday, $lastday);
+    }
+}
+if (!function_exists('clearfile')) {
+    /**删除目录下所有文件
+     * @param $path 目录或者文件路径
+     * @param string $ext
+     * @return bool
+     */
+    function clearfile($path, $ext = '*.log')
+    {
+        $files = (array)glob($path . DS . '*');
+        foreach ($files as $path) {
+            if (is_dir($path)) {
+                $matches = glob($path . '/' . $ext);
+                if (is_array($matches)) {
+                    array_map('unlink', $matches);
+                }
+                rmdir($path);
+            } else {
+                unlink($path);
+            }
+        }
+        return true;
+    }
+}
+if (!function_exists('get_this_class_methods')) {
+    /**获取当前类方法
+     * @param $class
+     * @return array
+     */
+    function get_this_class_methods($class, $unarray = [])
+    {
+        $arrayall = get_class_methods($class);
+        if ($parent_class = get_parent_class($class)) {
+            $arrayparent = get_class_methods($parent_class);
+            $arraynow = array_diff($arrayall, $arrayparent);//去除父级的
+        } else {
+            $arraynow = $arrayall;
+        }
+        return array_diff($arraynow, $unarray);//去除无用的
+    }
+}
+
+if (!function_exists('verify_domain')) {
+
+    /**
+     * 验证域名是否合法
+     * @param string $domain
+     * @return bool
+     */
+    function verify_domain(string $domain): bool
+    {
+        $res = "/^(?=^.{3,255}$)(http(s)?:\/\/)?(www\.)?[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+(:\d+)*(\/\w+\.\w+)*$/";
+        if (preg_match($res, $domain))
+            return true;
+        else
+            return false;
+    }
+}

+ 25 - 0
app/admin/config/route.php

@@ -0,0 +1,25 @@
+<?php
+// +----------------------------------------------------------------------
+// | ThinkPHP [ WE CAN DO IT JUST THINK ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
+// +----------------------------------------------------------------------
+// | Author: liu21st <liu21st@gmail.com>
+// +----------------------------------------------------------------------
+
+// +----------------------------------------------------------------------
+// | 应用设置
+// +----------------------------------------------------------------------
+
+return [
+    // 是否强制使用路由
+    'url_route_must'        => false,
+    // 合并路由规则
+    'route_rule_merge'      => true,
+    // 路由是否完全匹配
+    'route_complete_match'  => false,
+    // 是否自动转换URL中的控制器和操作名
+    'url_convert'           => true,
+];

+ 20 - 0
app/admin/config/view.php

@@ -0,0 +1,20 @@
+<?php
+// +----------------------------------------------------------------------
+// | 模板设置
+// +----------------------------------------------------------------------
+
+return [
+    // 模板后缀
+    'view_suffix'  => 'php',
+    // 模板路径
+    'view_path'    => app_path('view'),
+    // 视图输出字符串内容替换
+    'tpl_replace_string'       => [
+        '{__PUBLIC_PATH}' =>  '/',              //public 目录
+        '{__STATIC_PATH}' =>  '/static/',       //全局静态目录
+        '{__PLUG_PATH}'   =>  '/static/plug/',  //全局静态插件
+        '{__ADMIN_PATH}'  =>  '/system/',        //后台目录
+        '{__FRAME_PATH}'  =>  '/system/frame/',  //后台框架
+        '{__MODULE_PATH}' =>  '/system/module/', //后台模块
+    ]
+];

+ 36 - 0
app/admin/controller/AdminException.php

@@ -0,0 +1,36 @@
+<?php
+/**
+ *
+ * @author: xaboy<365615158@qq.com>
+ * @day: 2018/01/10
+ */
+
+namespace app\admin\controller;
+
+use think\exception\Handle;
+use think\exception\ValidateException;
+use think\Response;
+use Throwable;
+
+/**
+ * 后台异常处理
+ *
+ * Class AdminException
+ * @package app\admin\controller
+ */
+class AdminException extends Handle
+{
+
+    public function render($request, Throwable $e): Response
+    {
+        // 参数验证错误
+        if ($e instanceof ValidateException) {
+            return app('json')->make(422, $e->getError());
+        }
+        if ($e instanceof \Exception && request()->isAjax()) {
+            return app('json')->fail($e->getMessage(), ['code' => $e->getCode(), 'line' => $e->getLine(), 'message' => $e->getMessage(), 'file' => $e->getFile()]);
+        }
+
+        return parent::render($request, $e);
+    }
+}

+ 87 - 0
app/admin/controller/AuthController.php

@@ -0,0 +1,87 @@
+<?php
+
+namespace app\admin\controller;
+
+use app\admin\model\system\SystemAdmin;
+use app\admin\model\system\SystemMenus;
+use app\admin\model\system\SystemRole;
+use think\facade\Route as Url;
+
+/**
+ * 基类 所有控制器继承的类
+ * Class AuthController
+ * @package app\admin\controller
+ */
+class AuthController extends SystemBasic
+{
+    /**
+     * 当前登陆管理员信息
+     * @var
+     */
+    protected $adminInfo;
+
+    /**
+     * 当前登陆管理员ID
+     * @var
+     */
+    protected $adminId;
+
+    /**
+     * 当前管理员权限
+     * @var array
+     */
+    protected $auth = [];
+
+    protected $skipLogController = ['index', 'common'];
+
+    protected function initialize()
+    {
+        parent::initialize();
+        if (!SystemAdmin::hasActiveAdmin()) return $this->redirect(Url::buildUrl('login/index')->suffix(false)->build());
+        try {
+            $adminInfo = SystemAdmin::activeAdminInfoOrFail();
+        } catch (\Exception $e) {
+            return $this->failed(SystemAdmin::getErrorInfo($e->getMessage()), Url::buildUrl('login/index')->suffix(false)->build());
+        }
+        $this->adminInfo = $adminInfo;
+        $this->adminId = $adminInfo['id'];
+        $this->getActiveAdminInfo();
+        $this->auth = SystemAdmin::activeAdminAuthOrFail();
+        $this->adminInfo->level === 0 || $this->checkAuth();
+        $this->assign('_admin', $this->adminInfo);
+        $type = 'system';
+        event('AdminVisit', [$this->adminInfo, $type]);
+    }
+
+
+    protected function checkAuth($action = null, $controller = null, $module = null, array $route = [])
+    {
+        static $allAuth = null;
+        if ($allAuth === null) $allAuth = SystemRole::getAllAuth();
+        if ($module === null) $module = app('http')->getName();
+        if ($controller === null) $controller = $this->request->controller();
+        if ($action === null) $action = $this->request->action();
+        if (!count($route)) $route = $this->request->route();
+        if (in_array(strtolower($controller), $this->skipLogController, true)) return true;
+        $nowAuthName = SystemMenus::getAuthName($action, $controller, $module, $route);
+        $baseNowAuthName = SystemMenus::getAuthName($action, $controller, $module, []);
+        if ((in_array($nowAuthName, $allAuth) && !in_array($nowAuthName, $this->auth)) || (in_array($baseNowAuthName, $allAuth) && !in_array($baseNowAuthName, $this->auth)))
+            exit($this->failed('没有权限访问!'));
+        return true;
+    }
+
+
+    /**
+     * 获得当前用户最新信息
+     * @return SystemAdmin
+     */
+    protected function getActiveAdminInfo()
+    {
+        $adminId = $this->adminId;
+        $adminInfo = SystemAdmin::getValidAdminInfoOrFail($adminId);
+        if (!$adminInfo) $this->failed(SystemAdmin::getErrorInfo('请登陆!'));
+        $this->adminInfo = $adminInfo;
+        SystemAdmin::setLoginInfo($adminInfo);
+        return $adminInfo;
+    }
+}

+ 473 - 0
app/admin/controller/Index.php

@@ -0,0 +1,473 @@
+<?php
+
+namespace app\admin\controller;
+
+use FormBuilder\Json;
+use think\facade\Config;
+use app\admin\model\system\{SystemConfig, SystemMenus, SystemRole};
+use app\admin\model\user\{User, UserExtract as UserExtractModel, User as UserModel};
+
+/**
+ * 首页控制器
+ * Class Index
+ * @package app\admin\controller
+ *
+ */
+class Index extends AuthController
+{
+    public function index()
+    {
+        //获取当前登录后台的管理员信息
+        $adminInfo = $this->adminInfo->toArray();
+        $roles = explode(',', $adminInfo['roles']);
+        $site_logo = SystemConfig::getOneConfig('menu_name', 'site_logo')->toArray();
+
+        $this->assign([
+            'menuList' => SystemMenus::menuList(),
+            'site_logo' => json_decode($site_logo['value'], true),
+            'new_order_audio_link' => sys_config('new_order_audio_link'),
+            'role_name' => SystemRole::where('id', $roles[0])->field('role_name')->find(),
+            'workermanPort' => Config::get('workerman.admin.port')
+        ]);
+        return $this->fetch();
+    }
+
+    //后台首页内容
+    public function main()
+    {
+        /*首页第一行统计*/
+        $now_month = strtotime(date('Y-m'));//本月
+        $pre_month = strtotime(date('Y-m', strtotime('-1 month')));//上月
+        $now_day = strtotime(date('Y-m-d'));//今日
+        $pre_day = strtotime(date('Y-m-d', strtotime('-1 day')));//昨天时间戳
+        $beforyester_day = strtotime(date('Y-m-d', strtotime('-2 day')));//前天时间戳
+        //待发货数量
+
+        //新粉丝->日
+        $now_day_user = User::where('add_time', '>', $now_day)->count();
+        $pre_day_user = User::where('add_time', '>', $pre_day)->where('add_time', '<', $now_day)->count();
+        $pre_day_user = $pre_day_user ? $pre_day_user : 0;
+        $first_line['day'] = [
+            'data' => $now_day_user ? $now_day_user : 0,
+            'percent' => abs($now_day_user - $pre_day_user),
+            'is_plus' => $now_day_user - $pre_day_user > 0 ? 1 : ($now_day_user - $pre_day_user == 0 ? -1 : 0)
+        ];
+
+        //新粉丝->月
+        $now_month_user = User::where('add_time', '>', $now_month)->count();
+        $pre_month_user = User::where('add_time', '>', $pre_month)->where('add_time', '<', $now_month)->count();
+        $first_line['month'] = [
+            'data' => $now_month_user ? $now_month_user : 0,
+            'percent' => abs($now_month_user - $pre_month_user),
+            'is_plus' => $now_month_user - $pre_month_user > 0 ? 1 : ($now_month_user - $pre_month_user == 0 ? -1 : 0)
+        ];
+
+
+        $this->assign([
+            'first_line' => $first_line,
+        ]);
+        return $this->fetch();
+    }
+
+    /**
+     * 订单图表
+     */
+    public function orderchart()
+    {
+        header('Content-type:text/json');
+        $cycle = $this->request->param('cycle') ?: 'thirtyday';//默认30天
+        $datalist = [];
+        switch ($cycle) {
+            case 'thirtyday':
+                $datebefor = date('Y-m-d', strtotime('-30 day'));
+                $dateafter = date('Y-m-d');
+                //上期
+                $pre_datebefor = date('Y-m-d', strtotime('-60 day'));
+                $pre_dateafter = date('Y-m-d', strtotime('-30 day'));
+                for ($i = -30; $i < 0; $i++) {
+                    $datalist[date('m-d', strtotime($i . ' day'))] = date('m-d', strtotime($i . ' day'));
+                }
+                $order_list = [];
+                if (empty($order_list)) return Json::fail('无数据');
+                foreach ($order_list as $k => &$v) {
+                    $order_list[$v['day']] = $v;
+                }
+                $cycle_list = [];
+                foreach ($datalist as $dk => $dd) {
+                    if (!empty($order_list[$dd])) {
+                        $cycle_list[$dd] = $order_list[$dd];
+                    } else {
+                        $cycle_list[$dd] = ['count' => 0, 'day' => $dd, 'price' => ''];
+                    }
+                }
+                $chartdata = [];
+                $data = [];//临时
+                $chartdata['yAxis']['maxnum'] = 0;//最大值数量
+                $chartdata['yAxis']['maxprice'] = 0;//最大值金额
+                foreach ($cycle_list as $k => $v) {
+                    $data['day'][] = $v['day'];
+                    $data['count'][] = $v['count'];
+                    $data['price'][] = round($v['price'], 2);
+                    if ($chartdata['yAxis']['maxnum'] < $v['count'])
+                        $chartdata['yAxis']['maxnum'] = $v['count'];//日最大订单数
+                    if ($chartdata['yAxis']['maxprice'] < $v['price'])
+                        $chartdata['yAxis']['maxprice'] = $v['price'];//日最大金额
+                }
+                $chartdata['legend'] = ['订单金额', '订单数'];//分类
+                $chartdata['xAxis'] = $data['day'];//X轴值
+                //,'itemStyle'=>$series
+                $series = ['normal' => ['label' => ['show' => true, 'position' => 'top']]];
+                $chartdata['series'][] = ['name' => $chartdata['legend'][0], 'type' => 'bar', 'itemStyle' => $series, 'data' => $data['price']];//分类1值
+                $chartdata['series'][] = ['name' => $chartdata['legend'][1], 'type' => 'bar', 'itemStyle' => $series, 'data' => $data['count']];//分类2值
+                //统计总数上期
+                $pre_total = null;
+                if ($pre_total) {
+                    $chartdata['pre_cycle']['count'] = [
+                        'data' => $pre_total['count'] ?: 0
+                    ];
+                    $chartdata['pre_cycle']['price'] = [
+                        'data' => $pre_total['price'] ?: 0
+                    ];
+                }
+                //统计总数
+                $total = null;
+                if ($total) {
+                    $cha_count = intval($pre_total['count']) - intval($total['count']);
+                    //$pre_total['count'] = $pre_total['count'] == 0 ? 1 : $pre_total['count'];
+                    $chartdata['cycle']['count'] = [
+                        'data' => $total['count'] ?: 0,
+                        'percent' => intval($pre_total['count']) == 0 ? 100 : round((abs($cha_count) / intval($pre_total['count']) * 100), 2),
+                        'is_plus' => $cha_count > 0 ? -1 : ($cha_count == 0 ? 0 : 1)
+                    ];
+                    $cha_price = round($pre_total['price'], 2) - round($total['price'], 2);
+                    //$pre_total['price'] = $pre_total['price'] == 0 ? 1 : $pre_total['price'];
+                    $chartdata['cycle']['price'] = [
+                        'data' => $total['price'] ?: 0,
+                        'percent' => (intval($pre_total['price']) == 0 || !$pre_total['price'] || $pre_total['price'] == 0.00) ? 100 : round(abs($cha_price) / $pre_total['price'] * 100, 2),
+                        'is_plus' => $cha_price > 0 ? -1 : ($cha_price == 0 ? 0 : 1)
+                    ];
+                }
+                return app('json')->success('ok', $chartdata);
+                break;
+            case 'week':
+                $weekarray = array(['周日'], ['周一'], ['周二'], ['周三'], ['周四'], ['周五'], ['周六']);
+                $datebefor = date('Y-m-d', strtotime('-1 week Monday'));
+                $dateafter = date('Y-m-d', strtotime('-1 week Sunday'));
+                $order_list = [];
+                //数据查询重新处理
+                $new_order_list = [];
+                foreach ($order_list as $k => $v) {
+                    $new_order_list[$v['day']] = $v;
+                }
+                $now_datebefor = date('Y-m-d', (time() - ((date('w') == 0 ? 7 : date('w')) - 1) * 24 * 3600));
+                $now_dateafter = date('Y-m-d', strtotime("+1 day"));
+                $now_order_list = [];
+                //数据查询重新处理 key 变为当前值
+                $new_now_order_list = [];
+                foreach ($now_order_list as $k => $v) {
+                    $new_now_order_list[$v['day']] = $v;
+                }
+                foreach ($weekarray as $dk => $dd) {
+                    if (!empty($new_order_list[$dk])) {
+                        $weekarray[$dk]['pre'] = $new_order_list[$dk];
+                    } else {
+                        $weekarray[$dk]['pre'] = ['count' => 0, 'day' => $weekarray[$dk][0], 'price' => '0'];
+                    }
+                    if (!empty($new_now_order_list[$dk])) {
+                        $weekarray[$dk]['now'] = $new_now_order_list[$dk];
+                    } else {
+                        $weekarray[$dk]['now'] = ['count' => 0, 'day' => $weekarray[$dk][0], 'price' => '0'];
+                    }
+                }
+                $chartdata = [];
+                $data = [];//临时
+                $chartdata['yAxis']['maxnum'] = 0;//最大值数量
+                $chartdata['yAxis']['maxprice'] = 0;//最大值金额
+                foreach ($weekarray as $k => $v) {
+                    $data['day'][] = $v[0];
+                    $data['pre']['count'][] = $v['pre']['count'];
+                    $data['pre']['price'][] = round($v['pre']['price'], 2);
+                    $data['now']['count'][] = $v['now']['count'];
+                    $data['now']['price'][] = round($v['now']['price'], 2);
+                    if ($chartdata['yAxis']['maxnum'] < $v['pre']['count'] || $chartdata['yAxis']['maxnum'] < $v['now']['count']) {
+                        $chartdata['yAxis']['maxnum'] = $v['pre']['count'] > $v['now']['count'] ? $v['pre']['count'] : $v['now']['count'];//日最大订单数
+                    }
+                    if ($chartdata['yAxis']['maxprice'] < $v['pre']['price'] || $chartdata['yAxis']['maxprice'] < $v['now']['price']) {
+                        $chartdata['yAxis']['maxprice'] = $v['pre']['price'] > $v['now']['price'] ? $v['pre']['price'] : $v['now']['price'];//日最大金额
+                    }
+                }
+                $chartdata['legend'] = ['上周金额', '本周金额', '上周订单数', '本周订单数'];//分类
+                $chartdata['xAxis'] = $data['day'];//X轴值
+                //,'itemStyle'=>$series
+                $series = ['normal' => ['label' => ['show' => true, 'position' => 'top']]];
+                $chartdata['series'][] = ['name' => $chartdata['legend'][0], 'type' => 'bar', 'itemStyle' => $series, 'data' => $data['pre']['price']];//分类1值
+                $chartdata['series'][] = ['name' => $chartdata['legend'][1], 'type' => 'bar', 'itemStyle' => $series, 'data' => $data['now']['price']];//分类1值
+                $chartdata['series'][] = ['name' => $chartdata['legend'][2], 'type' => 'line', 'itemStyle' => $series, 'data' => $data['pre']['count']];//分类2值
+                $chartdata['series'][] = ['name' => $chartdata['legend'][3], 'type' => 'line', 'itemStyle' => $series, 'data' => $data['now']['count']];//分类2值
+
+                //统计总数上期
+                $pre_total =[];
+                if ($pre_total) {
+                    $chartdata['pre_cycle']['count'] = [
+                        'data' => $pre_total['count'] ?: 0
+                    ];
+                    $chartdata['pre_cycle']['price'] = [
+                        'data' => $pre_total['price'] ?: 0
+                    ];
+                }
+                //统计总数
+                $total =[];
+                if ($total) {
+                    $cha_count = intval($pre_total['count']) - intval($total['count']);
+                    //$pre_total['count'] = $pre_total['count'] == 0 ? 1 : $pre_total['count'];
+                    $chartdata['cycle']['count'] = [
+                        'data' => $total['count'] ?: 0,
+                        'percent' => intval($pre_total['count']) == 0 ? 100 : round((abs($cha_count) / intval($pre_total['count']) * 100), 2),
+                        'is_plus' => $cha_count > 0 ? -1 : ($cha_count == 0 ? 0 : 1)
+                    ];
+                    $cha_price = round($pre_total['price'], 2) - round($total['price'], 2);
+                    //$pre_total['price'] = $pre_total['price'] == 0 ? 1 : $pre_total['price'];
+                    $chartdata['cycle']['price'] = [
+                        'data' => $total['price'] ?: 0,
+                        'percent' => (intval($pre_total['price']) == 0 || !$pre_total['price'] || $pre_total['price'] == 0.00) ? 100 : round(abs($cha_price) / $pre_total['price'] * 100, 2),
+                        'is_plus' => $cha_price > 0 ? -1 : ($cha_price == 0 ? 0 : 1)
+                    ];
+                }
+                return app('json')->success('ok', $chartdata);
+                break;
+            case 'month':
+                $weekarray = array('01' => ['1'], '02' => ['2'], '03' => ['3'], '04' => ['4'], '05' => ['5'], '06' => ['6'], '07' => ['7'], '08' => ['8'], '09' => ['9'], '10' => ['10'], '11' => ['11'], '12' => ['12'], '13' => ['13'], '14' => ['14'], '15' => ['15'], '16' => ['16'], '17' => ['17'], '18' => ['18'], '19' => ['19'], '20' => ['20'], '21' => ['21'], '22' => ['22'], '23' => ['23'], '24' => ['24'], '25' => ['25'], '26' => ['26'], '27' => ['27'], '28' => ['28'], '29' => ['29'], '30' => ['30'], '31' => ['31']);
+
+                $datebefor = date('Y-m-01', strtotime('-1 month'));
+                $dateafter = date('Y-m-d', strtotime(date('Y-m-01')));
+                $order_list = [];
+                //数据查询重新处理
+                $new_order_list = [];
+                foreach ($order_list as $k => $v) {
+                    $new_order_list[$v['day']] = $v;
+                }
+                $now_datebefor = date('Y-m-01');
+                $now_dateafter = date('Y-m-d', strtotime("+1 day"));
+                $now_order_list = [];
+                //数据查询重新处理 key 变为当前值
+                $new_now_order_list = [];
+                foreach ($now_order_list as $k => $v) {
+                    $new_now_order_list[$v['day']] = $v;
+                }
+                foreach ($weekarray as $dk => $dd) {
+                    if (!empty($new_order_list[$dk])) {
+                        $weekarray[$dk]['pre'] = $new_order_list[$dk];
+                    } else {
+                        $weekarray[$dk]['pre'] = ['count' => 0, 'day' => $weekarray[$dk][0], 'price' => '0'];
+                    }
+                    if (!empty($new_now_order_list[$dk])) {
+                        $weekarray[$dk]['now'] = $new_now_order_list[$dk];
+                    } else {
+                        $weekarray[$dk]['now'] = ['count' => 0, 'day' => $weekarray[$dk][0], 'price' => '0'];
+                    }
+                }
+                $chartdata = [];
+                $data = [];//临时
+                $chartdata['yAxis']['maxnum'] = 0;//最大值数量
+                $chartdata['yAxis']['maxprice'] = 0;//最大值金额
+                foreach ($weekarray as $k => $v) {
+                    $data['day'][] = $v[0];
+                    $data['pre']['count'][] = $v['pre']['count'];
+                    $data['pre']['price'][] = round($v['pre']['price'], 2);
+                    $data['now']['count'][] = $v['now']['count'];
+                    $data['now']['price'][] = round($v['now']['price'], 2);
+                    if ($chartdata['yAxis']['maxnum'] < $v['pre']['count'] || $chartdata['yAxis']['maxnum'] < $v['now']['count']) {
+                        $chartdata['yAxis']['maxnum'] = $v['pre']['count'] > $v['now']['count'] ? $v['pre']['count'] : $v['now']['count'];//日最大订单数
+                    }
+                    if ($chartdata['yAxis']['maxprice'] < $v['pre']['price'] || $chartdata['yAxis']['maxprice'] < $v['now']['price']) {
+                        $chartdata['yAxis']['maxprice'] = $v['pre']['price'] > $v['now']['price'] ? $v['pre']['price'] : $v['now']['price'];//日最大金额
+                    }
+
+                }
+                $chartdata['legend'] = ['上月金额', '本月金额', '上月订单数', '本月订单数'];//分类
+                $chartdata['xAxis'] = $data['day'];//X轴值
+                //,'itemStyle'=>$series
+                $series = ['normal' => ['label' => ['show' => true, 'position' => 'top']]];
+                $chartdata['series'][] = ['name' => $chartdata['legend'][0], 'type' => 'bar', 'itemStyle' => $series, 'data' => $data['pre']['price']];//分类1值
+                $chartdata['series'][] = ['name' => $chartdata['legend'][1], 'type' => 'bar', 'itemStyle' => $series, 'data' => $data['now']['price']];//分类1值
+                $chartdata['series'][] = ['name' => $chartdata['legend'][2], 'type' => 'line', 'itemStyle' => $series, 'data' => $data['pre']['count']];//分类2值
+                $chartdata['series'][] = ['name' => $chartdata['legend'][3], 'type' => 'line', 'itemStyle' => $series, 'data' => $data['now']['count']];//分类2值
+
+                //统计总数上期
+                $pre_total = null;
+                if ($pre_total) {
+                    $chartdata['pre_cycle']['count'] = [
+                        'data' => $pre_total['count'] ?: 0
+                    ];
+                    $chartdata['pre_cycle']['price'] = [
+                        'data' => $pre_total['price'] ?: 0
+                    ];
+                }
+                //统计总数
+                $total = null;
+                if ($total) {
+                    $cha_count = intval($pre_total['count']) - intval($total['count']);
+                    //$pre_total['count'] = $pre_total['count'] == 0 ? 1 : $pre_total['count'];
+                    $chartdata['cycle']['count'] = [
+                        'data' => $total['count'] ?: 0,
+                        'percent' => intval($pre_total['count']) == 0 ? 100 : round((abs($cha_count) / intval($pre_total['count']) * 100), 2),
+                        'is_plus' => $cha_count > 0 ? -1 : ($cha_count == 0 ? 0 : 1)
+                    ];
+                    $cha_price = round($pre_total['price'], 2) - round($total['price'], 2);
+                    //$pre_total['price'] = $pre_total['price'] == 0 ? 1 : $pre_total['price'];
+                    $chartdata['cycle']['price'] = [
+                        'data' => $total['price'] ?: 0,
+                        'percent' => (intval($pre_total['price']) == 0 || !$pre_total['price'] || $pre_total['price'] == 0.00) ? 100 : round(abs($cha_price) / $pre_total['price'] * 100, 2),
+                        'is_plus' => $cha_price > 0 ? -1 : ($cha_price == 0 ? 0 : 1)
+                    ];
+                }
+                return app('json')->success('ok', $chartdata);
+                break;
+            case 'year':
+                $weekarray = array('01' => ['一月'], '02' => ['二月'], '03' => ['三月'], '04' => ['四月'], '05' => ['五月'], '06' => ['六月'], '07' => ['七月'], '08' => ['八月'], '09' => ['九月'], '10' => ['十月'], '11' => ['十一月'], '12' => ['十二月']);
+                $datebefor = date('Y-01-01', strtotime('-1 year'));
+                $dateafter = date('Y-12-31', strtotime('-1 year'));
+                $order_list = [];
+                //数据查询重新处理
+                $new_order_list = [];
+                foreach ($order_list as $k => $v) {
+                    $new_order_list[$v['day']] = $v;
+                }
+                $now_datebefor = date('Y-01-01');
+                $now_dateafter = date('Y-m-d');
+                $now_order_list = [];
+                //数据查询重新处理 key 变为当前值
+                $new_now_order_list = [];
+                foreach ($now_order_list as $k => $v) {
+                    $new_now_order_list[$v['day']] = $v;
+                }
+                foreach ($weekarray as $dk => $dd) {
+                    if (!empty($new_order_list[$dk])) {
+                        $weekarray[$dk]['pre'] = $new_order_list[$dk];
+                    } else {
+                        $weekarray[$dk]['pre'] = ['count' => 0, 'day' => $weekarray[$dk][0], 'price' => '0'];
+                    }
+                    if (!empty($new_now_order_list[$dk])) {
+                        $weekarray[$dk]['now'] = $new_now_order_list[$dk];
+                    } else {
+                        $weekarray[$dk]['now'] = ['count' => 0, 'day' => $weekarray[$dk][0], 'price' => '0'];
+                    }
+                }
+                $chartdata = [];
+                $data = [];//临时
+                $chartdata['yAxis']['maxnum'] = 0;//最大值数量
+                $chartdata['yAxis']['maxprice'] = 0;//最大值金额
+                foreach ($weekarray as $k => $v) {
+                    $data['day'][] = $v[0];
+                    $data['pre']['count'][] = $v['pre']['count'];
+                    $data['pre']['price'][] = round($v['pre']['price'], 2);
+                    $data['now']['count'][] = $v['now']['count'];
+                    $data['now']['price'][] = round($v['now']['price'], 2);
+                    if ($chartdata['yAxis']['maxnum'] < $v['pre']['count'] || $chartdata['yAxis']['maxnum'] < $v['now']['count']) {
+                        $chartdata['yAxis']['maxnum'] = $v['pre']['count'] > $v['now']['count'] ? $v['pre']['count'] : $v['now']['count'];//日最大订单数
+                    }
+                    if ($chartdata['yAxis']['maxprice'] < $v['pre']['price'] || $chartdata['yAxis']['maxprice'] < $v['now']['price']) {
+                        $chartdata['yAxis']['maxprice'] = $v['pre']['price'] > $v['now']['price'] ? $v['pre']['price'] : $v['now']['price'];//日最大金额
+                    }
+                }
+                $chartdata['legend'] = ['去年金额', '今年金额', '去年订单数', '今年订单数'];//分类
+                $chartdata['xAxis'] = $data['day'];//X轴值
+                //,'itemStyle'=>$series
+                $series = ['normal' => ['label' => ['show' => true, 'position' => 'top']]];
+                $chartdata['series'][] = ['name' => $chartdata['legend'][0], 'type' => 'bar', 'itemStyle' => $series, 'data' => $data['pre']['price']];//分类1值
+                $chartdata['series'][] = ['name' => $chartdata['legend'][1], 'type' => 'bar', 'itemStyle' => $series, 'data' => $data['now']['price']];//分类1值
+                $chartdata['series'][] = ['name' => $chartdata['legend'][2], 'type' => 'line', 'itemStyle' => $series, 'data' => $data['pre']['count']];//分类2值
+                $chartdata['series'][] = ['name' => $chartdata['legend'][3], 'type' => 'line', 'itemStyle' => $series, 'data' => $data['now']['count']];//分类2值
+
+                //统计总数上期
+                $pre_total = null;
+                if ($pre_total) {
+                    $chartdata['pre_cycle']['count'] = [
+                        'data' => $pre_total['count'] ?: 0
+                    ];
+                    $chartdata['pre_cycle']['price'] = [
+                        'data' => $pre_total['price'] ?: 0
+                    ];
+                }
+                //统计总数
+                $total = null;
+                if ($total) {
+                    $cha_count = intval($pre_total['count']) - intval($total['count']);
+                    //$pre_total['count'] = $pre_total['count'] == 0 ? 1 : $pre_total['count'];
+                    $chartdata['cycle']['count'] = [
+                        'data' => $total['count'] ?: 0,
+                        'percent' => intval($pre_total['count']) == 0 ? 100 : round((abs($cha_count) / intval($pre_total['count']) * 100), 2),
+                        'is_plus' => $cha_count > 0 ? -1 : ($cha_count == 0 ? 0 : 1)
+                    ];
+                    $cha_price = round($pre_total['price'], 2) - round($total['price'], 2);
+                    //$pre_total['price'] = $pre_total['price'] == 0 ? 1 : $pre_total['price'];
+                    $chartdata['cycle']['price'] = [
+                        'data' => $total['price'] ?: 0,
+                        'percent' => (intval($pre_total['price']) == 0 || !$pre_total['price'] || $pre_total['price'] == 0.00) ? 100 : round(abs($cha_price) / $pre_total['price'] * 100, 2),
+                        'is_plus' => $cha_price > 0 ? -1 : ($cha_price == 0 ? 0 : 1)
+                    ];
+                }
+                return app('json')->success('ok', $chartdata);
+                break;
+            default:
+                break;
+        }
+    }
+
+    /**
+     * 用户图表
+     */
+    public function userchart()
+    {
+        header('Content-type:text/json');
+
+        $starday = date('Y-m-d', strtotime('-30 day'));
+        $yesterday = date('Y-m-d');
+
+        $user_list = UserModel::where('add_time', 'between time', [$starday, $yesterday])
+            ->field("FROM_UNIXTIME(add_time,'%m-%e') as day,count(*) as count")
+            ->group("FROM_UNIXTIME(add_time, '%Y%m%e')")
+            ->order('add_time asc')
+            ->select()->toArray();
+        $chartdata = [];
+        $data = [];
+        $chartdata['legend'] = ['用户数'];//分类
+        $chartdata['yAxis']['maxnum'] = 0;//最大值数量
+        $chartdata['xAxis'] = [date('m-d')];//X轴值
+        $chartdata['series'] = [0];//分类1值
+        if (!empty($user_list)) {
+            foreach ($user_list as $k => $v) {
+                $data['day'][] = $v['day'];
+                $data['count'][] = $v['count'];
+                if ($chartdata['yAxis']['maxnum'] < $v['count'])
+                    $chartdata['yAxis']['maxnum'] = $v['count'];
+            }
+            $chartdata['xAxis'] = $data['day'];//X轴值
+            $chartdata['series'] = $data['count'];//分类1值
+        }
+        return app('json')->success('ok', $chartdata);
+    }
+
+    /**
+     * 待办事统计
+     * @param int $newTime
+     * @return false|string
+     */
+    public function Jnotice($newTime = 30)
+    {
+        header('Content-type:text/json');
+        $data = [];
+        $data['ordernum'] = 0;//待发货
+        $replenishment_num = sys_config('store_stock') > 0 ? sys_config('store_stock') : 2;//库存预警界限
+        $data['inventory'] = 0;//库存
+        $data['commentnum'] = 0;//评论
+        $data['reflectnum'] = UserExtractModel::where('status', 0)->count();;//提现
+        $data['msgcount'] = intval($data['ordernum']) + intval($data['inventory']) + intval($data['commentnum']) + intval($data['reflectnum']);
+        //新订单提醒
+        $data['newOrderId'] = [];
+//        if (count($data['newOrderId'])) StoreOrderModel::where('order_id', 'in', $data['newOrderId'])->update(['is_remind' => 1]);
+        return app('json')->success('ok', $data);
+    }
+}
+
+

+ 67 - 0
app/admin/controller/Login.php

@@ -0,0 +1,67 @@
+<?php
+
+namespace app\admin\controller;
+
+
+use app\admin\model\system\SystemAdmin;
+use crmeb\services\UtilService;
+use think\facade\Session;
+use think\facade\Route as Url;
+
+/**
+ * 登录验证控制器
+ * Class Login
+ * @package app\admin\controller
+ */
+class Login extends SystemBasic
+{
+    public function index()
+    {
+        return $this->fetch();
+    }
+
+    /**
+     * 登录验证 + 验证码验证
+     */
+    public function verify()
+    {
+        if (!request()->isPost()) return $this->failed('请登陆!');
+        list($account, $pwd, $verify) = UtilService::postMore([
+            'account', 'pwd', 'verify'
+        ], null, true);
+        //检验验证码
+        if (!captcha_check($verify)) return $this->failed('验证码错误,请重新输入');
+        $error = Session::get('login_error') ?: ['num' => 0, 'time' => time()];
+        $error['num'] = 0;
+        if ($error['num'] >= 5 && $error['time'] > strtotime('- 5 minutes'))
+            return $this->failed('错误次数过多,请稍候再试!');
+        //检验帐号密码
+        $res = SystemAdmin::login($account, $pwd);
+        if ($res) {
+            Session::set('login_error', null);
+            Session::save();
+            return $this->successful(['url' => Url::buildUrl('Index/index')->build()]);
+        } else {
+            $error['num'] += 1;
+            $error['time'] = time();
+            Session::set('login_error', $error);
+            Session::save();
+            return $this->failed(SystemAdmin::getErrorInfo('用户名错误,请重新输入'));
+        }
+    }
+
+    public function captcha()
+    {
+        ob_clean();
+        return captcha();
+    }
+
+    /**
+     * 退出登陆
+     */
+    public function logout()
+    {
+        SystemAdmin::clearLoginInfo();
+        $this->redirect(Url::buildUrl('index')->build());
+    }
+}

+ 118 - 0
app/admin/controller/SystemBasic.php

@@ -0,0 +1,118 @@
+<?php
+/**
+ *
+ * @author: xaboy<365615158@qq.com>
+ * @day: 2017/10/09
+ */
+
+namespace app\admin\controller;
+
+use crmeb\services\JsonService;
+use crmeb\basic\BaseController;
+
+
+class SystemBasic extends BaseController
+{
+    /**
+     * 操作失败提示框
+     * @param string $msg 提示信息
+     * @param string $backUrl 跳转地址
+     * @param string $title 标题
+     * @param int $duration 持续时间
+     * @return mixed
+     */
+    protected function failedNotice($msg = '操作失败', $backUrl = 0, $info = '', $duration = 3)
+    {
+        $type = 'error';
+        $this->assign(compact('msg', 'backUrl', 'info', 'duration', 'type'));
+        return $this->fetch('public/notice');
+    }
+
+    /**
+     * 失败提示一直持续
+     * @param $msg
+     * @param int $backUrl
+     * @param string $title
+     * @return mixed
+     */
+    protected function failedNoticeLast($msg = '操作失败', $backUrl = 0, $info = '')
+    {
+        return $this->failedNotice($msg, $backUrl, $info, 0);
+    }
+
+    /**
+     * 操作成功提示框
+     * @param string $msg 提示信息
+     * @param string $backUrl 跳转地址
+     * @param string $title 标题
+     * @param int $duration 持续时间
+     * @return mixed
+     */
+    protected function successfulNotice($msg = '操作成功', $backUrl = 0, $info = '', $duration = 3)
+    {
+        $type = 'success';
+        $this->assign(compact('msg', 'backUrl', 'info', 'duration', 'type'));
+        return $this->fetch('public/notice');
+    }
+
+    /**
+     * 成功提示一直持续
+     * @param $msg
+     * @param int $backUrl
+     * @param string $title
+     * @return mixed
+     */
+    protected function successfulNoticeLast($msg = '操作成功', $backUrl = 0, $info = '')
+    {
+        return $this->successfulNotice($msg, $backUrl, $info, 0);
+    }
+
+    /**
+     * 错误提醒页面
+     * @param string $msg
+     * @param int $url
+     */
+    protected function failed($msg = '哎呀…亲…您访问的页面出现错误', $url = 0)
+    {
+        if ($this->request->isAjax()) {
+            exit(JsonService::fail($msg, $url)->getContent());
+        } else {
+            $this->assign(compact('msg', 'url'));
+            exit($this->fetch('public/error'));
+        }
+    }
+
+    /**
+     * 成功提醒页面
+     * @param string $msg
+     * @param int $url
+     */
+    protected function successful($msg, $url = 0)
+    {
+        if ($this->request->isAjax()) {
+            exit(JsonService::successful($msg, $url)->getContent());
+        } else {
+            $this->assign(compact('msg', 'url'));
+            exit($this->fetch('public/success'));
+        }
+    }
+
+    /**异常抛出
+     * @param $name
+     */
+    protected function exception($msg = '无法打开页面')
+    {
+        $this->assign(compact('msg'));
+        exit($this->fetch('public/exception'));
+    }
+
+    /**找不到页面
+     * @param $name
+     */
+    public function _empty($name)
+    {
+        exit($this->fetch('public/404'));
+    }
+
+
+}

+ 43 - 0
app/admin/controller/Test.php

@@ -0,0 +1,43 @@
+<?php
+
+namespace app\admin\controller;
+
+
+use app\admin\model\system\SystemCity;
+use crmeb\services\ExpressService;
+use crmeb\services\HttpService;
+use crmeb\services\JsonService;
+use crmeb\utils\Queue;
+use think\facade\Queue as QueueJob;
+
+class Test
+{
+    public function index($page = 1, $limit = 50, $level = 0)
+    {
+
+
+//        var_dump(is_file('uploads/981_1_user.jpg'));
+
+
+        $appCode = '4a5b910fc344434cacb2edd36e0e56aa';
+        $list = ExpressService::query('75341495702624');
+        dump($list);
+//        $data = [];
+//        foreach ($list['data'] as $item) {
+//            $data[] = [
+//                'level' => $item['level'],
+//                'parent_id' => $item['parent_id'],
+//                'area_code' => $item['area_code'],
+//                'name' => $item['name'],
+//                'merger_name' => $item['merger_name'],
+//                'lng' => $item['lng'],
+//                'lat' => $item['lat'],
+//                'city_id' => $item['id'],
+//            ];
+//        }
+//        $res = SystemCity::insertAll($data);
+//        return JsonService::successful(['count' => $res]);
+    }
+
+
+}

+ 420 - 0
app/admin/controller/article/Article.php

@@ -0,0 +1,420 @@
+<?php
+
+namespace app\admin\controller\article;
+
+use app\admin\controller\AuthController;
+use app\admin\model\system\SystemAttachment;
+use app\admin\model\enterprise\EnterPriseUser;
+use app\models\user\InterestUser;
+use crmeb\services\{JsonService, UtilService as Util, JsonService as Json, UtilService};
+use app\admin\model\article\{ArticleCategory as ArticleCategoryModel, Article as ArticleModel, ArticleReply};
+use crmeb\services\FormBuilder as Form;
+use think\facade\Route as Url;
+
+/**
+ * 图文管理
+ * Class WechatNews
+ * @package app\admin\controller\wechat
+ */
+class Article extends AuthController
+{
+    /**
+     * TODO 显示后台管理员添加的图文
+     * @return mixed
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function index()
+    {
+        $where = Util::getMore([
+            ['title', ''],
+            ['cid', $this->request->param('pid', '')],
+        ], $this->request);
+        $where['merchant'] = $this->adminInfo['mer_id'];//区分是管理员添加的图文显示  0 还是 商户添加的图文显示  1
+        $tree = sort_list_tier(ArticleCategoryModel::getArticleCategoryList());
+        $this->assign(compact('tree'));
+        $this->assign('mer_id', $this->adminInfo['mer_id']);
+        $this->assign('where', $where);
+        $this->assign(ArticleModel::getAll($where));
+        return $this->fetch();
+    }
+
+    /**
+     * TODO 文件添加和修改
+     * @return mixed
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function create()
+    {
+        $id = $this->request->param('id');
+        $cid = $this->request->param('cid');
+        $news = [];
+        $all = [];
+        $news['id'] = '';
+        $news['image_input'] = '';
+        $news['title'] = '';
+        $news['author'] = '';
+        $news['is_banner'] = '';
+        $news['is_hot'] = '';
+        $news['content'] = '';
+        $news['synopsis'] = '';
+        $news['url'] = '';
+        $news['cid'] = [];
+        $news['mer_id'] = [];
+        $news['mer'] = [];
+        $news['add_time']='';
+        $mer_id = $this->adminInfo['mer_id'];
+        $select = 0;
+        if ($id) {
+            $news = ArticleModel::where('n.id', $id)->alias('n')->field('n.*,c.content')->join('ArticleContent c', 'c.nid=n.id', 'left')->find();
+            if (!$news) return $this->failed('数据不存在!');
+            $news['image_input'] = explode(',', $news['image_input']);
+            $news['cid'] = explode(',', $news['cid']);
+//            通过文章ID获取文章企业名
+             $news['add_time']=date("Y-m-d H:i:s",$news['add_time']);
+            $news['rename'] =EnterPriseUser::where('id',$news['mer_id'])->value('name');
+            $news['mer_id'] = explode(',', $news['mer_id']);
+            $news['content'] = htmlspecialchars_decode($news['content']);
+        }
+        if ($cid && in_array($cid, ArticleCategoryModel::getArticleCategoryInfo(0, 'id'))) {
+            $all = ArticleCategoryModel::getArticleCategoryInfo($cid);
+            $select = 1;
+        }
+        if (!$select) {
+            $list = ArticleCategoryModel::getTierList();
+            foreach ($list as $menu) {
+                $all[$menu['id']] = $menu['html'] . $menu['title'];
+            }
+        }
+        $this->assign('all', $all);
+        $this->assign('news', $news);
+        $this->assign('mer_id', $mer_id);
+        $this->assign('cid', $cid);
+        $this->assign('select', $select);
+        return $this->fetch();
+    }
+
+    public function preview()
+    {
+      return $this->create();
+
+    }
+
+    /**
+     * 上传图文图片
+     * @return \think\response\Json
+     */
+    public function upload_image()
+    {
+        $res = Upload::instance()->setUploadPath('wechat/image/' . date('Ymd'))->image($_POST['file']);
+        if (!is_array($res)) return Json::fail($res);
+        SystemAttachment::attachmentAdd($res['name'], $res['size'], $res['type'], $res['dir'], $res['thumb_path'], 5, $res['image_type'], $res['time'], 1, $this->adminInfo['mer_id']);
+        return Json::successful('上传成功!', ['url' => $res['dir']]);
+    }
+
+    /**
+     * 添加和修改图文
+     */
+    public function add_new()
+    {
+        $data = Util::postMore([
+            ['id', 0],
+            ['cid', []],
+            ['mer',0],
+            'title',
+            'author',
+            'content',
+            'synopsis',
+            'share_title',
+            'share_synopsis',
+            ['visit', 0],
+            ['sort', 0],
+            'url',
+            ['is_banner', 0],
+             'add_time',
+            ['is_hot', 0],
+            ['status', 1],]);
+        $data['image_input'] = implode(',', $this->request->post('image_input'));
+        $data['cid'] = implode(',', $data['cid']);
+        $content = $data['content'];
+		$data['add_time'] =strtotime($data['add_time']); 
+		//判断是新增还是修改
+			if($this->adminInfo['mer_id']==0){
+				$data['is_check'] =1;
+			}else{
+				$data['is_check'] =0;
+			}
+        unset($data['content']);
+        if ($data['id']) {
+            $id = $data['id'];
+            unset($data['id']);
+            $res = false;
+            ArticleModel::beginTrans();
+            $res1 = ArticleModel::edit($data, $id, 'id');
+            $res2 = ArticleModel::setContent($id, $content);
+            if ($res1 && $res2) {
+                $res = true;
+            }
+            ArticleModel::checkTrans($res);
+            if ($res)
+                return Json::successful('修改图文成功!', $id);
+            else
+                return Json::fail('修改图文失败,您并没有修改什么!', $id);
+        } else {
+			$data['mer_id'] = $this->adminInfo['mer_id'];
+			$data['admin_id'] = $this->adminId;
+			//判断是否是总后台添加的文章
+				if($data['mer_id']==0){
+					$data['is_check'] =1;
+				}else{
+					$data['is_check'] =0;
+				}
+            $res = false;
+            ArticleModel::beginTrans();
+            $res1 = ArticleModel::create($data);
+            $res2 = false;
+            if ($res1)
+                $res2 = ArticleModel::setContent($res1->id, $content);
+            if ($res1 && $res2) {
+                $res = true;
+            }
+            ArticleModel::checkTrans($res);
+            if ($res)
+                return Json::successful('添加图文成功!', $res1->id);
+            else
+                return Json::successful('添加图文失败!', $res1->id);
+        }
+    }
+
+    /**
+     * 删除图文
+     * @param $id
+     * @return \think\response\Json
+     */
+    public function delete($id)
+    {
+        $res = ArticleModel::del($id);
+        if (!$res)
+            return Json::fail('删除失败,请稍候再试!');
+        else
+            return Json::successful('删除成功!');
+    }
+
+    public function merchantIndex()
+    {
+        $where = Util::getMore([
+            ['title', '']
+        ], $this->request);
+        $this->assign('where', $where);
+        $where['cid'] = input('cid');
+        $where['merchant'] = 1;//区分是管理员添加的图文显示  0 还是 商户添加的图文显示  1
+        $this->assign(ArticleModel::getAll($where));
+        return $this->fetch();
+    }
+
+    /**
+     * 关联文章 id
+     * @param int $id
+     */
+    public function relation($id = 0)
+    {
+        $this->assign('id', $id);
+        return $this->fetch();
+    }
+    /**
+     * 取消绑定的产品id
+     * @param int $id
+     */
+    public function unrelation($id = 0)
+    {
+        if (!$id) return Json::fail('缺少参数');
+        if (ArticleModel::edit(['product_id' => 0], $id))
+            return Json::successful('取消关联成功!');
+        else
+            return Json::fail('取消失败');
+    }
+
+
+    /**
+     * 文章评论
+     * @param $id
+     * @return void
+     */
+    public function reply_list($id)
+    {
+        $where = Util::getMore([
+            ['title', ''],
+        ], $this->request);
+
+        $this->assign('where', $where);
+        $this->assign(ArticleReply::list($where, $id));
+        $this->assign('id', $id);
+        return $this->fetch();
+    }
+
+    public function delete_reply($id)
+    {
+        $res = ArticleReply::del($id);
+        if (!$res)
+            return Json::fail('删除失败,请稍候再试!');
+        else
+            return Json::successful('删除成功!');
+    }
+
+    public function reply($id)
+    {
+
+        $this->assign('id', $id);
+        return $this->fetch();
+    }
+
+	/*
+	 * 创建form表单
+	 * */
+	public function upcreate($id =0)
+	{
+		$vipinfo = ArticleModel::where('id',$id)->find();
+	    $field[] = Form::input('off', '拒绝理由', isset($vipinfo) ? $vipinfo->off: '')->col(Form::col(24));
+	    $form = Form::make_post_form('添加拒绝理由', $field, Url::buildUrl('save', ['id' => $id]), 2);
+	    $this->assign(compact('form'));
+	    return $this->fetch('public/form-builder');
+	}
+	/*
+	 * 审核/拒绝
+	 * @param $id 文章id
+	 * @return json
+	 * */
+	public function save($id = 0)
+	{
+	    $data = UtilService::postMore([
+	        ['off', ''],
+	    ]);
+	    if (!$data['off']) return JsonService::fail('请输入拒绝理由');
+		if($data['off']){
+			 $res=ArticleModel::where('id',$id)->update(['reason' =>$data['off'],'is_check' =>2]);
+			if($res>0){
+				return Json::successful('审核成功');
+			}else{
+				 return Json::fail('审核失败');
+			}
+		}
+	}
+    public function add_reply()
+    {
+        $data = Util::postMore([
+            'content',
+            'id'
+        ]);
+        $reply = ArticleReply::where('id', $data['id'])->find();
+        if (empty($reply)) return Json::fail('数据不存在');
+        $admin = $this->adminInfo;
+        $res = ArticleReply::create([
+            'aid' => $reply['aid'],
+            'content' => $data['content'],
+            'uid' => $admin['mer_id'],
+            'to_id' => $data['id'],
+            'add_time' => time()
+        ]);
+        if (!$res)
+            return Json::fail('回复失败!');
+        else
+            return Json::successful('回复成功!');
+
+    }
+
+
+    public function fans()
+    {
+        return $this->fetch();
+    }
+
+    public function fansList()
+    {
+        $where = UtilService::getMore([
+            ['page', 1],
+            ['limit', 20],
+        ]);
+        $where['mer_id'] = $this->adminInfo['mer_id'];
+        JsonService::successlayui(InterestUser::getList($where));
+    }
+
+    public function delete_fan($id)
+    {
+        $info = InterestUser::where('id', $id)->find();
+        if (!$info) {
+            JsonService::fail('移除失败,找不到记录');
+        }
+        if ($this->adminInfo['mer_id'] > 0 && $this->adminInfo['mer_id'] != $info['mer_id']) {
+            JsonService::fail('移除失败,不可移除非自己媒体的粉丝');
+        }
+        $res = InterestUser::remove($id);
+        if ($res) {
+            JsonService::success('移除成功');
+        } else {
+            JsonService::fail('移除失败');
+        }
+    }
+
+    public function set_top($id)
+    {
+        if ($this->adminInfo['mer_id']) {
+            JsonService::fail('权限不足');
+        }
+        $info = \app\models\article\Article::where('id', $id)->find();
+        if (!$info) {
+            JsonService::fail('置顶失败,找不到记录');
+        }
+        $res1 = \app\models\article\Article::where('is_top',1)->find();
+        if($res1){
+            $res = \app\models\article\Article::where(1)->update(['is_top' => 0]) && \app\models\article\Article::where('id', $id)->update(['is_top' => 1]);
+        }else{
+            $res=\app\models\article\Article::where('id', $id)->update(['is_top' => 1]);
+        }
+        if ($res) {
+            JsonService::success('置顶成功');
+        } else {
+            JsonService::fail('置顶失败');
+        }
+    }
+    public function set_check($id)
+    {
+        if ($this->adminInfo['mer_id']) {
+            JsonService::fail('权限不足');
+        }
+        $info = \app\models\article\Article::where('id', $id)->find();
+        if (!$info) {
+            JsonService::fail('审核失败,找不到记录');
+        }
+        $res=\app\models\article\Article::where('id', $id)->update(['is_check' => 1]);
+        if ($res) {
+            JsonService::success('审核成功');
+        } else {
+            JsonService::fail('审核失败');
+        }
+    }
+
+    public function set_hot($id)
+    {
+        if ($this->adminInfo['mer_id']) {
+            JsonService::fail('权限不足');
+        }
+        $info = \app\models\article\Article::where('id', $id)->find();
+        if (!$info) {
+            JsonService::fail('推荐失败,找不到记录');
+        }
+		if($info['is_hot']==0){
+			$type=1;
+		}else{
+			$type=0;
+		}
+        $res=\app\models\article\Article::where('id', $id)->update(['is_hot' =>$type]);
+        if ($res) {
+            JsonService::success('成功');
+        } else {
+            JsonService::fail('失败');
+        }
+    }
+}

+ 175 - 0
app/admin/controller/article/ArticleCategory.php

@@ -0,0 +1,175 @@
+<?php
+
+namespace app\admin\controller\article;
+
+use think\facade\Route as Url;
+use app\admin\controller\AuthController;
+use app\admin\model\system\SystemAttachment;
+use app\admin\model\article\{ArticleCategory as ArticleCategoryModel,Article as ArticleModel};
+use crmeb\services\{FormBuilder as Form,UtilService as Util,JsonService as Json};
+
+
+/**
+ * 文章分类管理  控制器
+ * */
+class ArticleCategory extends AuthController
+{
+
+    /**
+     * 分类管理
+     * */
+    public function index()
+    {
+        $where = Util::getMore([
+            ['status', ''],
+            ['title', ''],
+        ], $this->request);
+        $this->assign('where', $where);
+        $this->assign(ArticleCategoryModel::systemPage($where));
+        return $this->fetch();
+    }
+
+    /**
+     * 添加分类管理
+     * */
+
+    public function create()
+    {
+        $f = array();
+        $f[] = Form::select('pid', '父级id')->setOptions(function () {
+            $list = ArticleCategoryModel::getTierList();
+            $menus[] = ['value' => 0, 'label' => '顶级分类'];
+            foreach ($list as $menu) {
+                $menus[] = ['value' => $menu['id'], 'label' => $menu['html'] . $menu['title']];
+            }
+            return $menus;
+        })->filterable(1);
+        $f[] = Form::input('title', '分类名称');
+        $f[] = Form::input('intr', '分类简介')->type('textarea');
+//        $f[] = Form::select('new_id','图文列表')->setOptions(function(){
+//            $list = ArticleModel::getNews();
+//            $options = [];
+//            foreach ($list as $id=>$roleName){
+//                $options[] = ['label'=>$roleName,'value'=>$id];
+//            }
+//            return $options;
+//        })->multiple(1)->filterable(1);
+        $f[] = Form::frameImageOne('image', '分类图片', Url::buildUrl('admin/widget.images/index', array('fodder' => 'image')))->icon('image')->width('100%')->height('500px');
+        $f[] = Form::number('sort', '排序', 0);
+        $f[] = Form::radio('status', '状态', 1)->options([['value' => 1, 'label' => '显示'], ['value' => 0, 'label' => '隐藏']]);
+        $form = Form::make_post_form('添加分类', $f, Url::buildUrl('save'));
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+
+    }
+
+    /**
+     * s上传图片
+     * */
+    public function upload()
+    {
+        $res = Upload::instance()->setUploadPath('article')->image('file');
+        if (!is_array($res)) return Json::fail($res);
+        SystemAttachment::attachmentAdd($res['name'], $res['size'], $res['type'], $res['dir'], $res['thumb_path'], 5, $res['image_type'], $res['time'], 1, $this->adminInfo['mer_id']);
+        return Json::successful('图片上传成功!', ['name' => $res['name'], 'url' => path_to_url($res['thumb_path'])]);
+    }
+
+    /**
+     * 保存分类管理
+     * */
+    public function save()
+    {
+        $data = Util::postMore([
+            'title',
+            'pid',
+            'intr',
+            ['new_id', []],
+            ['image', []],
+            ['sort', 0],
+            'status',]);
+        if (!$data['title']) return Json::fail('请输入分类名称');
+        if (count($data['image']) != 1) return Json::fail('请选择分类图片,并且只能上传一张');
+        if ($data['sort'] < 0) return Json::fail('排序不能是负数');
+        $data['add_time'] = time();
+        $data['image'] = $data['image'][0];
+        $new_id = $data['new_id'];
+        unset($data['new_id']);
+        $res = ArticleCategoryModel::create($data);
+        if (!ArticleModel::saveBatchCid($res['id'], implode(',', $new_id))) return Json::fail('文章列表添加失败');
+        return Json::successful('添加分类成功!');
+    }
+
+    /**
+     * 修改分类
+     * */
+
+    public function edit($id)
+    {
+        if (!$id) return $this->failed('参数错误');
+        $article = ArticleCategoryModel::get($id)->getData();
+        if (!$article) return Json::fail('数据不存在!');
+        $f = array();
+        $f[] = Form::select('pid', '父级id', (string)$article['pid'])->setOptions(function () {
+            $list = ArticleCategoryModel::getTierList();
+            $menus[] = ['value' => 0, 'label' => '顶级分类'];
+            foreach ($list as $menu) {
+                $menus[] = ['value' => $menu['id'], 'label' => $menu['html'] . $menu['title']];
+            }
+            return $menus;
+        })->filterable(1);
+        $f[] = Form::input('title', '分类名称', $article['title']);
+        $f[] = Form::input('intr', '分类简介', $article['intr'])->type('textarea');
+//        $f[] = Form::select('new_id','图文列表',explode(',',$article->getData('new_id')))->setOptions(function(){
+//            $list = ArticleModel::getNews();
+//            $options = [];
+//            foreach ($list as $id=>$roleName){
+//                $options[] = ['label'=>$roleName,'value'=>$id];
+//            }
+//            return $options;
+//        })->multiple(1)->filterable(1);
+        $f[] = Form::frameImageOne('image', '分类图片', Url::buildUrl('admin/widget.images/index', array('fodder' => 'image')), $article['image'])->icon('image')->width('100%')->height('500px');
+        $f[] = Form::number('sort', '排序', 0);
+        $f[] = Form::radio('status', '状态', $article['status'])->options([['value' => 1, 'label' => '显示'], ['value' => 0, 'label' => '隐藏']]);
+        $form = Form::make_post_form('编辑分类', $f, Url::buildUrl('update', array('id' => $id)));
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+
+    }
+
+
+    public function update($id)
+    {
+        $data = Util::postMore([
+            'pid',
+            'title',
+            'intr',
+//            ['new_id',[]],
+            ['image', []],
+            ['sort', 0],
+            'status',]);
+        if (!$data['title']) return Json::fail('请输入分类名称');
+        if (count($data['image']) != 1) return Json::fail('请选择分类图片,并且只能上传一张');
+        if ($data['sort'] < 0) return Json::fail('排序不能是负数');
+        $data['image'] = $data['image'][0];
+        if (!ArticleCategoryModel::get($id)) return Json::fail('编辑的记录不存在!');
+//        if(!ArticleModel::saveBatchCid($id,implode(',',$data['new_id']))) return Json::fail('文章列表添加失败');
+//        unset($data['new_id']);
+        ArticleCategoryModel::edit($data, $id);
+        return Json::successful('修改成功!');
+    }
+
+    /**
+     * 删除分类
+     * */
+    public function delete($id)
+    {
+        $res = ArticleCategoryModel::delArticleCategory($id);
+        if (!$res)
+            return Json::fail(ArticleCategoryModel::getErrorInfo('删除失败,请稍候再试!'));
+        else
+            return Json::successful('删除成功!');
+    }
+
+
+}
+

+ 196 - 0
app/admin/controller/article/WechatNews.php

@@ -0,0 +1,196 @@
+<?php
+
+namespace app\admin\controller\article;
+
+use app\admin\controller\AuthController;
+use app\admin\model\system\SystemAttachment;
+use app\admin\model\wechat\WechatNews as WechatNewsModel;
+use crmeb\services\{
+    UtilService as Util, JsonService as Json
+};
+use app\admin\model\article\{
+    Article as ArticleModel, ArticleCategory as ArticleCategoryModel
+};
+use crmeb\services\upload\Upload;
+
+/**
+ * 图文管理
+ * Class WechatNews
+ * @package app\admin\controller\wechat
+ */
+class WechatNews extends AuthController
+{
+    /**
+     * 显示后台管理员添加的图文
+     * @return mixed
+     */
+    public function index($cid = 0)
+    {
+        $where = Util::getMore([
+            ['title', '']
+        ], $this->request);
+        if ($cid)
+            $where['cid'] = $cid;
+        else
+            $where['cid'] = '';
+        $this->assign('where', $where);
+        $where['merchant'] = 0;//区分是管理员添加的图文显示  0 还是 商户添加的图文显示  1
+        $this->assign('cid', $cid);
+        $this->assign(ArticleModel::getAll($where));
+        return $this->fetch();
+    }
+
+    /**
+     * 展示页面   添加和删除
+     * @return mixed
+     */
+    public function create()
+    {
+        $id = input('id');
+        $cid = input('cid');
+        $news = array();
+        $news['id'] = '';
+        $news['image_input'] = '';
+        $news['title'] = '';
+        $news['author'] = '';
+        $news['content'] = '';
+        $news['synopsis'] = '';
+        $news['url'] = '';
+        $news['cid'] = array();
+        if ($id) {
+            $news = WechatNewsModel::where('n.id', $id)->alias('n')->field('n.*,c.content')->join('wechat_news_content c', 'c.nid=n.id')->find();
+            if (!$news) return $this->failedNotice('数据不存在!');
+            $news['cid'] = explode(',', $news['cid']);
+        }
+        $all = array();
+        $select = 0;
+        if (!$cid)
+            $cid = '';
+        else {
+            if ($id) {
+                $all = ArticleCategoryModel::where('id', $cid)->where('hidden', '<>', 0)->column('title', 'id');
+                $select = 1;
+            } else {
+                $all = ArticleCategoryModel::where('id', $cid)->column('title', 'id');
+                $select = 1;
+            }
+
+        }
+        if (empty($all)) {
+            $all = ArticleCategoryModel::getField();//新闻分类
+            $select = 0;
+        }
+        $this->assign('all', $all);
+        $this->assign('news', $news);
+        $this->assign('cid', $cid);
+        $this->assign('select', $select);
+        return $this->fetch();
+    }
+
+    /**
+     * 上传图文图片
+     * @return \think\response\Json
+     */
+    public function upload_image()
+    {
+        $uploadType = (int)sys_config('upload_type', 1);
+        $upload = new Upload($uploadType, [
+            'accessKey' => sys_config('accessKey'),
+            'secretKey' => sys_config('secretKey'),
+            'uploadUrl' => sys_config('uploadUrl'),
+            'storageName' => sys_config('storage_name'),
+            'storageRegion' => sys_config('storage_region'),
+        ]);
+        $resInfo = $upload->to('wechat/image/' . date('Ymd'))->validate()->move($this->request->post('file'));
+        if ($resInfo === false) {
+            return Json::fail($upload->getError());
+        }
+        $res = $upload->getUploadInfo();
+        $res['image_type'] = $uploadType;
+        SystemAttachment::attachmentAdd($res['name'], $res['size'], $res['type'], $res['dir'], $res['thumb_path'], 5, $res['image_type'], $res['time'], 1, $this->adminInfo['mer_id']);
+        return Json::successful('上传成功!', ['url' => $res['thumb_path']]);
+    }
+
+    /**
+     * 添加和修改图文
+     */
+    public function add_new()
+    {
+        $data = Util::postMore([
+            ['id', 0],
+            ['cid', []],
+            'title',
+            'author',
+            'image_input',
+            'content',
+            'synopsis',
+            'share_title',
+            'share_synopsis',
+            ['visit', 0],
+            ['sort', 0],
+            'url',
+            ['status', 1],]);
+        $data['cid'] = implode(',', $data['cid']);
+        $content = $data['content'];
+        unset($data['content']);
+        if ($data['id']) {
+            $id = $data['id'];
+            unset($data['id']);
+            ArticleModel::beginTrans();
+            $res1 = ArticleModel::edit($data, $id, 'id');
+            $res2 = ArticleModel::setContent($id, $content);
+            if ($res1 && $res2)
+                $res = true;
+            else
+                $res = false;
+            ArticleModel::checkTrans($res);
+            if ($res)
+                return Json::successful('修改图文成功!', $id);
+            else
+                return Json::fail('修改图文失败!', $id);
+        } else {
+            $data['add_time'] = time();
+            $data['admin_id'] = $this->adminId;
+            ArticleModel::beginTrans();
+            $res1 = ArticleModel::create($data);
+            $res2 = false;
+            if ($res1)
+                $res2 = ArticleModel::setContent($res1->id, $content);
+            if ($res1 && $res2)
+                $res = true;
+            else
+                $res = false;
+            ArticleModel::checkTrans($res);
+            if ($res)
+                return Json::successful('添加图文成功!', $res1->id);
+            else
+                return Json::successful('添加图文失败!', $res1->id);
+        }
+    }
+
+    /**
+     * 删除图文
+     * @param $id
+     * @return \think\response\Json
+     */
+    public function delete($id)
+    {
+        $res = ArticleModel::del($id);
+        if (!$res)
+            return Json::fail('删除失败,请稍候再试!');
+        else
+            return Json::successful('删除成功!');
+    }
+
+    public function merchantIndex()
+    {
+        $where = Util::getMore([
+            ['title', '']
+        ], $this->request);
+        $this->assign('where', $where);
+        $where['cid'] = input('cid');
+        $where['merchant'] = 1;//区分是管理员添加的图文显示  0 还是 商户添加的图文显示  1
+        $this->assign(ArticleModel::getAll($where));
+        return $this->fetch();
+    }
+}

+ 73 - 0
app/admin/controller/enterprise/Apply.php

@@ -0,0 +1,73 @@
+<?php
+/**
+ * Created by Administrator.
+ * User: 向往那片天空
+ * Date: 2022\5\21 0021
+ * Time: 15:08
+ * 格言: 抓住中心,宁精勿杂,宁专勿多
+ * QQ/微信: 250023777
+ * 描述: 无
+ */
+
+namespace app\admin\controller\enterprise;
+
+
+use app\admin\controller\AuthController;
+use crmeb\services\UtilService;
+use crmeb\services\{JsonService as Json, JsonService, UtilService as Util};
+use crmeb\traits\CurdControllerTrait;
+
+class Apply extends AuthController
+{
+    use CurdControllerTrait;
+
+    public function index()
+    {
+        return $this->fetch();
+    }
+
+    public function get_apply_list()
+    {
+        $where = UtilService::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['audit_status', -1],
+            ['apply_user_name', ''],
+            ['mer_id', ''],
+        ]);
+
+//        return JsonService::fail('找不到记录',$where);
+
+        return app('ApplyLogic')->getPageList($where);
+    }
+
+    public function auditPage($id)
+    {
+        $this->assign('id', $id);
+        return $this->fetch('audit');
+    }
+
+    public function audit()
+    {
+        $data = Util::postMore([
+            ['id', 0],
+            ['audit_status', 0],
+            ['text', '']
+        ]);
+
+        if (empty($data['id'])) {
+            return JsonService::fail('id不能为空');
+        }
+
+        if (empty($data['audit_status'])) {
+            return JsonService::fail('请选择操作');
+        }
+
+        return app('ApplyLogic')->audit($data);
+    }
+
+    public function isDel($id)
+    {
+        return app('ApplyLogic')->delById($id);
+    }
+}

+ 115 - 0
app/admin/controller/enterprise/Auth.php

@@ -0,0 +1,115 @@
+<?php
+
+namespace app\admin\controller\enterprise;
+
+use app\admin\controller\AuthController;
+use think\facade\Route as Url;
+use crmeb\traits\CurdControllerTrait;
+use app\admin\model\enterprise\EnterPriseUser as UserModel;
+use app\admin\model\user\UserBill as UserBillAdmin;
+use app\admin\model\system\SystemAdmin as Admin;
+use app\admin\model\system\{SystemUserLevel,SystemUserTask};
+use crmeb\services\{UtilService,JsonService,FormBuilder as Form};
+/**
+ * 会员设置
+ * Class UserLevel
+ * @package app\admin\controller\user
+ */
+class Auth extends AuthController
+{
+    use CurdControllerTrait;
+
+    /*
+     * 审核展示
+     * */
+    public function index()
+    {
+        return $this->fetch();
+    }
+
+    /*
+     * 创建form表单
+     * */
+    public function create($uid =0)
+    {
+		if ($uid) $vipinfo = UserModel::get($uid);
+        $field[] = Form::input('off', '拒绝理由', isset($vipinfo) ? $vipinfo->off: '')->col(Form::col(24));
+        $form = Form::make_post_form('添加拒绝理由', $field, Url::buildUrl('save', ['uid' => $uid]), 2);
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /*
+     * 审核/拒绝
+     * @param $uid 审核的用户uid
+     * @return json
+     * */
+    public function save($uid = 0)
+    {
+        $data = UtilService::postMore([
+            ['off', ''],
+        ]);
+        if (!$data['off']) return JsonService::fail('请输入拒绝理由');
+		if($data['off']){
+			// 查询是否已审核
+			$res1=UserModel::where(['uid' => $uid])->find();
+			if($res1['is_auth']==0||$res1['is_auth']==2){
+				 return JsonService::fail('该信息已审核!不可操作');
+			}
+			$res=UserModel::where(['uid' => $uid])->update(['reason' =>$data['off'],'is_auth'=>"0"]);
+			if($res>0){
+				return JsonService::successful('审核成功');
+			}else{
+				 return JsonService::fail('该信息已审核!不可重复');
+			}
+		}
+    }
+	
+	/*
+	 * 审核通过
+	 * @param int $id
+	 * */
+	 //9db06bcff9248837f86d1a6bcf41c9e75c5b46740f277f2c87dd023e960c5cfc
+	public function pass($uid = 0,$id,$name){
+		 if($uid){
+			// 查询是否已审核
+			$res1=UserModel::where(['uid' => $uid])->find();
+			if($res1['is_auth']==0||$res1['is_auth']==2){
+				 return JsonService::fail('该信息已审核!不可操作');
+			}
+			$res=UserModel::where(['uid' => $uid])->update(['is_auth' =>2,'reason'=>'审核通过']);
+			if($res>0){
+				// 取出用户名和密码放到后台管理员中
+				$salt= substr(md5(rand(1, 999999)), 0, 6);
+				$pwd= md5($res1['password'] . md5($salt));
+				$data = ['account' =>$res1['user'], 'pwd' =>$pwd,'salt'=>$salt,'status'=>1,'mer_id'=>$id,'roles'=>7,'real_name'=>$name,'add_time'=>time(),'level'=>2];
+				$rslut=Admin::insert($data);
+				if($rslut){
+					return JsonService::successful('审核成功');
+				}
+				
+				
+			}else{
+				 return JsonService::fail('审核失败');
+			} 
+		 }		 
+	    return JsonService::fail('参数错误!'); 
+
+	
+	}
+    /*
+     * 获取列表
+     * @param int page
+     * @param int limit
+     * */
+    public function get_system_user_list()
+    {
+       $where =UtilService::getMore([
+           ['page', 1],
+           ['limit', 20],
+		   ['is_auth',0]
+       ]);
+        return JsonService::successlayui(UserModel::authlist($where));
+    }
+  
+}

+ 94 - 0
app/admin/controller/enterprise/Job.php

@@ -0,0 +1,94 @@
+<?php
+
+namespace app\admin\controller\enterprise;
+
+use app\admin\controller\AuthController;
+use app\logic\JobLogic;
+use crmeb\traits\CurdControllerTrait;
+use app\admin\model\enterprise\EnterPriseUser as UserModel;
+use crmeb\services\{JsonService as Json, UtilService, JsonService, UtilService as Util};
+use think\facade\App;
+use think\facade\Db;
+
+/**
+ * 会员设置
+ * Class UserLevel
+ * @package app\admin\controller\user
+ */
+class Job extends AuthController
+{
+    use CurdControllerTrait;
+
+    /*
+     * 职务列表
+     * */
+    public function index()
+    {
+        return $this->fetch();
+    }
+
+    /*
+     * 获取列表
+     * @param int page
+     * @param int limit
+     * */
+    public function get_job_list()
+    {
+        $where = UtilService::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['is_show', -1]
+        ]);
+
+        return app('JobLogic')->getPageList($where);
+    }
+
+    public static function isShow($id)
+    {
+        return app('JobLogic')->toggleIsShow($id);
+    }
+
+    public function create()
+    {
+        return $this->fetch();
+    }
+
+    public function add_job()
+    {
+        $data = Util::postMore([
+            'job_name',
+            'is_show',
+            'rank'
+        ]);
+
+        return app('JobLogic')->add($data);
+    }
+
+    public function isDel($id)
+    {
+        return app('JobLogic')->delById($id);
+    }
+
+    public function edit($id)
+    {
+        $this->assign('model', app('JobLogic')::get($id));
+
+        return $this->fetch();
+    }
+
+    public function edit_job()
+    {
+        $data = Util::postMore([
+            'id',
+            'job_name',
+            'is_show',
+            'rank',
+        ]);
+
+        if (empty($data['id'])) {
+            return JsonService::fail('id不能为空');
+        }
+
+        return app('JobLogic')->edit($data);
+    }
+}

+ 182 - 0
app/admin/controller/enterprise/Lists.php

@@ -0,0 +1,182 @@
+<?php
+
+namespace app\admin\controller\enterprise;
+
+use app\admin\controller\AuthController;
+use app\admin\model\enterprise\EnterCategory as ArticleCategoryModel;
+use crmeb\traits\CurdControllerTrait;
+use app\admin\model\enterprise\EnterPriseUser as UserModel;
+use app\admin\model\user\User as User;
+use app\admin\model\article\Article;
+use app\admin\model\system\SystemAdmin;
+use crmeb\services\{JsonService as Json, UtilService, JsonService, UtilService as Util};
+
+/**
+ * 会员设置
+ * Class UserLevel
+ * @package app\admin\controller\user
+ */
+class Lists extends AuthController
+{
+    use CurdControllerTrait;
+
+    /*
+     * 企业列表
+     * */
+    public function index()
+    {
+
+        return $this->fetch();
+    }
+
+    /*
+     * 获取列表
+     * @param int page
+     * @param int limit
+     * */
+    public function get_system_user_list()
+    {
+        $where = UtilService::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['is_auth', 0]
+        ]);
+        return JsonService::successlayui(UserModel::lists($where));
+    }
+
+    //推荐企业
+    public static function isput($id, $type)
+    {
+        $res1 = UserModel::where(['id' => $id])->find();
+        $a = 1;
+        if ($res1[$type] == 1) {
+            $a = 0;
+        }
+        $res = UserModel::where(['id' => $id])->update([$type => $a]);
+        if ($type == 'is_dle') {
+            // 查找该企业下的文章进行删除
+            $wz = Article::where('mer_id', $id)->update(['status' => 0]);
+            // 冻结后台登录权限
+            $st = SystemAdmin::where('mer_id', $id)->update(['status' => 0]);
+        }
+        if ($res) {
+            return JsonService::successful('成功');
+
+        } else {
+            return JsonService::fail('失败');
+        }
+        return JsonService::fail('参数错误!');
+    }
+
+    /**
+     * 添加第三方企业
+     * */
+    public function create()
+    {
+        $cid = $this->request->param('cid');
+        $all = [];
+        $select = 0;
+        if ($cid && in_array($cid, \app\admin\model\article\ArticleCategory::getArticleCategoryInfo(0, 'id'))) {
+            $all = ArticleCategoryModel::getArticleCategoryInfo($cid);
+            $select = 1;
+        }
+        if (!$select) {
+            $list = ArticleCategoryModel::getTierLists();
+            foreach ($list as $menu) {
+                $all[$menu['id']] = $menu['html'] . $menu['title'];
+            }
+        }
+        $a = [];
+        $list = User::select();
+        foreach ($list as $menu) {
+            $a[$menu['uid']] = $menu['nickname'];
+        }
+
+        $this->assign('all', $all);
+        $this->assign('uid', $a);
+        $this->assign('cid', $cid);
+        $this->assign('select', $select);
+        $this->assign('jobList', app('JobLogic')->getList([]));
+        return $this->fetch();
+    }
+
+    /**
+     * 保存第三方企业
+     * */
+    public function add_mer()
+    {
+        $data = Util::postMore([
+            'name',
+            'contacts',
+            'post',
+            'phone',
+            'password',
+            'introduce',
+            'contacts',
+            ['uid', 0],
+            'headimg',
+            ['type', 0],
+            ['is_auth', 1],
+            ['is_third', 1],
+            ['is_put', 0],
+            ['reason', "审核中"],
+
+        ]);
+
+        if (!empty($data['post'])) {
+            $arr = explode(',', $data['post']);
+            $data['post'] = $arr[1];
+            $data['post_id'] = $arr[0];
+        }
+
+        $data['password'] = md5($data['password']);
+        $data['user'] = $data['phone'];
+//        $data['type'] = $data['cid'];
+//        查询该用户是否绑定其他企业
+        $mer = UserModel::where(['uid' => $data['uid']])->count();
+        $findUser = User::get($data['uid']);
+        if (empty($findUser)) {
+            return JsonService::fail('找不到用户');
+        }
+
+        if ($mer > 0 || !empty($findUser['mer_id'])) {
+            return JsonService::fail('该用户已绑定其他企业!请重新选择');
+        }
+        $res = UserModel::insert($data);
+        if ($res) {
+
+            return Json::successful('添加成功!');
+        }
+        return JsonService::fail('添加失败!');
+    }
+
+    public function employeList($mer_id)
+    {
+        $this->assign('mer_id', $mer_id);
+        return $this->fetch('employe');
+    }
+
+    public function delEmploye($uid)
+    {
+        $updateUser = [];
+        $updateUser['mer_id'] = '';
+        if (!User::edit($updateUser, $uid)) {
+            return Json::fail('删除失败!');
+        }
+
+        return Json::successful('删除成功!');
+    }
+
+    public function employeData()
+    {
+        $where = UtilService::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['audit_status', -1],
+            ['apply_user_name', ''],
+            ['mer_id', ''],
+        ]);
+
+        return app('ApplyLogic')->getEmployeeList($where);
+    }
+}

+ 159 - 0
app/admin/controller/enterprise/Style.php

@@ -0,0 +1,159 @@
+<?php
+
+namespace app\admin\controller\enterprise;
+
+use think\facade\Route as Url;
+use app\admin\controller\AuthController;
+use app\admin\model\system\SystemAttachment;
+use app\admin\model\enterprise\EnterCategory as ArticleCategoryModel;
+use crmeb\services\{FormBuilder as Form,UtilService as Util,JsonService as Json};
+
+
+/**
+ * 企业类型管理  控制器
+ * */
+class Style extends AuthController
+{
+
+    /**
+     * 类型管理
+     * */
+    public function index()
+    {
+        $where = Util::getMore([
+            ['status', ''],
+            ['title', ''],
+        ], $this->request);
+        $this->assign('where', $where);
+        $this->assign(ArticleCategoryModel::systemPage($where));
+        return $this->fetch();
+    }
+
+    /**
+     * 添加类型管理
+     * */
+
+    public function create()
+    {
+        $f = array();
+        $f[] = Form::select('pid', '父级id')->setOptions(function () {
+            $list = ArticleCategoryModel::getTierList();
+            $menus[] = ['value' => 0, 'label' => '顶级类型'];
+            foreach ($list as $menu) {
+                $menus[] = ['value' => $menu['id'], 'label' => $menu['html'] . $menu['title']];
+            }
+            return $menus;
+        })->filterable(1);
+        $f[] = Form::input('title', '类型名称');
+        $f[] = Form::input('intr', '类型简介')->type('textarea');
+        $f[] = Form::frameImageOne('image', '类型图片', Url::buildUrl('admin/widget.images/index', array('fodder' => 'image')))->icon('image')->width('100%')->height('500px');
+        $f[] = Form::number('sort', '排序', 0);
+        $f[] = Form::radio('status', '状态', 1)->options([['value' => 1, 'label' => '显示'], ['value' => 0, 'label' => '隐藏']]);
+		$f[] = Form::radio('is_type', '是否第三方', 1)->options([['value' => 1, 'label' => '是'], ['value' => 0, 'label' => '否']]);
+        $form = Form::make_post_form('添加类型', $f, Url::buildUrl('save'));
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+
+    }
+
+    /**
+     * s上传图片
+     * */
+    public function upload()
+    {
+        $res = Upload::instance()->setUploadPath('article')->image('file');
+        if (!is_array($res)) return Json::fail($res);
+        SystemAttachment::attachmentAdd($res['name'], $res['size'], $res['type'], $res['dir'], $res['thumb_path'], 5, $res['image_type'], $res['time']);
+        return Json::successful('图片上传成功!', ['name' => $res['name'], 'url' => path_to_url($res['thumb_path'])]);
+    }
+
+    /**
+     * 保存类型管理
+     * */
+    public function save()
+    {
+        $data = Util::postMore([
+            'title',
+            'pid',
+            'intr',
+            ['new_id', []],
+            ['image', []],
+            ['sort', 0],
+			['is_type', 0],
+            'status',]);
+        if (!$data['title']) return Json::fail('请输入类型名称');
+        if (count($data['image']) != 1) return Json::fail('请选择类型图片,并且只能上传一张');
+        if ($data['sort'] < 0) return Json::fail('排序不能是负数');
+        $data['add_time'] = time();
+        $data['image'] = $data['image'][0];
+        $new_id = $data['new_id'];
+        unset($data['new_id']);
+        $res = ArticleCategoryModel::create($data);
+        return Json::successful('添加类型成功!');
+    }
+
+    /**
+     * 修改类型
+     * */
+
+    public function edit($id)
+    {
+        if (!$id) return $this->failed('参数错误');
+        $article = ArticleCategoryModel::get($id)->getData();
+        if (!$article) return Json::fail('数据不存在!');
+        $f = array();
+        $f[] = Form::select('pid', '父级id', (string)$article['pid'])->setOptions(function () {
+            $list = ArticleCategoryModel::getTierList();
+            $menus[] = ['value' => 0, 'label' => '顶级类型'];
+            foreach ($list as $menu) {
+                $menus[] = ['value' => $menu['id'], 'label' => $menu['html'] . $menu['title']];
+            }
+            return $menus;
+        })->filterable(1);
+        $f[] = Form::input('title', '类型名称', $article['title']);
+        $f[] = Form::input('intr', '类型简介', $article['intr'])->type('textarea');
+        $f[] = Form::frameImageOne('image', '类型图片', Url::buildUrl('admin/widget.images/index', array('fodder' => 'image')), $article['image'])->icon('image')->width('100%')->height('500px');
+        $f[] = Form::number('sort', '排序', 0);
+		$f[] = Form::radio('is_type', '是否第三方', $article['is_type'])->options([['value' => 1, 'label' => '是'], ['value' => 0, 'label' => '否']]);
+        $f[] = Form::radio('status', '状态', $article['status'])->options([['value' => 1, 'label' => '显示'], ['value' => 0, 'label' => '隐藏']]);
+        $form = Form::make_post_form('编辑类型', $f, Url::buildUrl('update', array('id' => $id)));
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+
+    }
+
+
+    public function update($id)
+    {
+        $data = Util::postMore([
+            'pid',
+            'title',
+            'intr',
+            ['image', []],
+            ['sort', 0],
+			 ['is_type', 0],
+            'status',]);
+        if (!$data['title']) return Json::fail('请输入类型名称');
+        if (count($data['image']) != 1) return Json::fail('请选择类型图片,并且只能上传一张');
+        if ($data['sort'] < 0) return Json::fail('排序不能是负数');
+        $data['image'] = $data['image'][0];
+        if (!ArticleCategoryModel::get($id)) return Json::fail('编辑的记录不存在!');
+        ArticleCategoryModel::edit($data, $id);
+        return Json::successful('修改成功!');
+    }
+
+    /**
+     * 删除类型
+     * */
+    public function delete($id)
+    {
+        $res = ArticleCategoryModel::delArticleCategory($id);
+        if (!$res)
+            return Json::fail(ArticleCategoryModel::getErrorInfo('删除失败,请稍候再试!'));
+        else
+            return Json::successful('删除成功!');
+    }
+
+
+}
+

+ 288 - 0
app/admin/controller/setting/SystemAdmin.php

@@ -0,0 +1,288 @@
+<?php
+
+namespace app\admin\controller\setting;
+use app\admin\controller\AuthController;
+use crmeb\services\{FormBuilder as Form, JsonService as Json, UtilService as Util};
+use app\admin\model\system\{SystemRole, SystemAdmin as AdminModel};
+use think\facade\Route as Url;
+use app\admin\model\enterprise\EnterCategory as ArticleCategoryModel;
+use crmeb\traits\CurdControllerTrait;
+use app\admin\model\enterprise\EnterPriseUser as UserModel;
+use app\admin\model\user\User as User;
+
+/**
+ * 管理员列表控制器
+ * Class SystemAdmin
+ * @package app\admin\controller\system
+ */
+class SystemAdmin extends AuthController
+{
+    /**
+     * 显示资源列表
+     *
+     * @return \think\Response
+     */
+    public function index()
+    {
+        $admin = $this->adminInfo;
+        $where = Util::getMore([
+            ['name', ''],
+            ['roles', ''],
+            ['level', bcadd($admin->level, 1, 0)]
+        ]);
+        $this->assign('where', $where);
+        $this->assign('role', SystemRole::getRole(bcadd($admin->level, 1, 0)));
+        $this->assign(AdminModel::systemPage($where));
+        return $this->fetch();
+    }
+
+    /**
+     * 显示创建资源表单页.
+     *
+     * @return \think\Response
+     */
+    public function create()
+    {
+        $admin = $this->adminInfo;
+        $f = array();
+        $f[] = Form::input('account', '管理员账号');
+        $f[] = Form::input('pwd', '管理员密码')->type('password');
+        $f[] = Form::input('conf_pwd', '确认密码')->type('password');
+        $f[] = Form::input('real_name', '管理员姓名');
+        $f[] = Form::select('roles', '管理员身份')->setOptions(function () use ($admin) {
+            $list = SystemRole::getRole(bcadd($admin->level, 1, 0));
+            $options = [];
+            foreach ($list as $id => $roleName) {
+                $options[] = ['label' => $roleName, 'value' => $id];
+            }
+            return $options;
+        })->multiple(1);
+        $f[] = Form::radio('status', '状态', 1)->options([['label' => '开启', 'value' => 1], ['label' => '关闭', 'value' => 0]]);
+        $form = Form::make_post_form('添加管理员', $f, Url::buildUrl('save'));
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 保存新建的资源
+     *
+     * @param \think\Request $request
+     * @return \think\Response
+     */
+    public function save()
+    {
+        $data = Util::postMore([
+            'account',
+            'conf_pwd',
+            'pwd',
+            'real_name',
+            ['roles', []],
+            ['status', 0]
+        ]);
+        if (!$data['account']) return Json::fail('请输入管理员账号');
+        if (!$data['roles']) return Json::fail('请选择至少一个管理员身份');
+        if (!$data['pwd']) return Json::fail('请输入管理员登陆密码');
+        if ($data['pwd'] != $data['conf_pwd']) return Json::fail('两次输入密码不想同');
+        if (AdminModel::be($data['account'], 'account')) return Json::fail('管理员账号已存在');
+        $salt = substr(md5(rand(1, 999999)), 0, 6);
+        $data['pwd'] = md5(md5($data['pwd']) . md5($salt));
+        $data['salt'] = $salt;
+        $data['add_time'] = time();
+        unset($data['conf_pwd']);
+        $data['level'] = $this->adminInfo['level'] + 1;
+        $data['add_time'] = time();
+        $data['mer_id'] = $this->adminInfo['mer_id'];
+        if (!AdminModel::create($data)) return Json::fail('添加管理员失败');
+        return Json::successful('添加管理员成功!');
+    }
+	// 修改企业信息
+	    public function createinfo()
+	    {
+	        $cid = $this->request->param('cid');
+	        $all = [];
+	        $select = 0;
+	        if ($cid && in_array($cid, \app\admin\model\article\ArticleCategory::getArticleCategoryInfo(0, 'id'))) {
+	            $all = ArticleCategoryModel::getArticleCategoryInfo($cid);
+	            $select = 1;
+	        }
+	        if (!$select) {
+	            $list = ArticleCategoryModel::getTierLists();
+	            foreach ($list as $menu) {
+	                $all[$menu['id']] = $menu['html'] . $menu['title'];
+	            }
+	        }
+	        $a = [];
+	        $list =User::select();
+	            foreach ($list as $menu) {
+	                $a[$menu['uid']] = $menu['nickname'];
+	            }
+			 $adminInfo = $this->adminInfo;//获取当前登录的管理员
+			// 获取企业信息
+			$info=UserModel::where('id',$adminInfo['mer_id'])->find();
+	        $this->assign('all', $all);
+			$this->assign('info',$info);
+	        $this->assign('uid', $a);
+	        $this->assign('cid', $cid);
+	        $this->assign('select', $select);
+	        return $this->fetch();
+	    }
+	    /**
+	     * 保存企业修改
+	     * */
+	    public function add_mer()
+	    {
+	        $data = Util::postMore([
+	            'name',
+	            'contacts',
+	            'post',
+	            'phone',
+	            'introduce',
+	            'contacts',
+	            ['uid',0],
+	            'headimg',
+	            ['type',0],
+	            ['is_auth', 1],
+	            ['is_third', 1]
+	            ]);
+			$adminInfo = $this->adminInfo;//获取当前登录的管理员
+			// 获取企业信息
+			$info=UserModel::where('id',$adminInfo['mer_id'])->find();
+			if($data['uid'] !=$info['uid']){
+				$mer=UserModel::where(['uid'=>$data['uid']])->count();
+				if($mer>0){
+				    return  Json::fail('该用户已绑定其他企业');
+				}	
+			}
+			//修改企业信息
+	        $res = UserModel::where('id',$info['id'])->update($data);
+	        if($res){
+	            return Json::successful('修改成功!');
+	        }
+	         return Json::fail('修改失败!');
+	    }
+
+    /**
+     * 显示编辑资源表单页.
+     *
+     * @param int $id
+     * @return \think\Response
+     */
+    public function edit($id)
+    {
+        if (!$id) return $this->failed('参数错误');
+        $admin = AdminModel::get($id);
+        if (!$admin) return Json::fail('数据不存在!');
+        $f = array();
+        $f[] = Form::input('account', '管理员账号', $admin->account);
+        $f[] = Form::input('pwd', '管理员密码')->type('password');
+        $f[] = Form::input('conf_pwd', '确认密码')->type('password');
+        $f[] = Form::input('real_name', '管理员姓名', $admin->real_name);
+        $f[] = Form::select('roles', '管理员身份', explode(',', $admin->roles))->setOptions(function () use ($admin) {
+            $list = SystemRole::getRole($admin->level);
+            $options = [];
+            foreach ($list as $id => $roleName) {
+                $options[] = ['label' => $roleName, 'value' => $id];
+            }
+            return $options;
+        })->multiple(1);
+        $f[] = Form::radio('status', '状态', 1)->options([['label' => '开启', 'value' => 1], ['label' => '关闭', 'value' => 0]]);
+        $form = Form::make_post_form('编辑管理员', $f, Url::buildUrl('update', compact('id')));
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 保存更新的资源
+     *
+     * @param \think\Request $request
+     * @param int $id
+     * @return \think\Response
+     */
+    public function update($id)
+    {
+        $data = Util::postMore([
+            'account',
+            'conf_pwd',
+            'pwd',
+            'real_name',
+            ['roles', []],
+            ['status', 0]
+        ]);
+        if (!$data['account']) return Json::fail('请输入管理员账号');
+        if (!$data['roles']) return Json::fail('请选择至少一个管理员身份');
+        if (!$data['pwd'])
+            unset($data['pwd']);
+        else {
+            if (isset($data['pwd']) && $data['pwd'] != $data['conf_pwd']) return Json::fail('两次输入密码不想同');
+            $salt = substr(md5(rand(1, 999999)), 0, 6);
+            $data['pwd'] = md5(md5($data['pwd']) . md5($salt));
+            $data['salt'] = $salt;
+        }
+        if (AdminModel::where('account', $data['account'])->where('id', '<>', $id)->count()) return Json::fail('管理员账号已存在');
+        unset($data['conf_pwd']);
+        if (!AdminModel::edit($data, $id)) return Json::fail('修改失败');
+        return Json::successful('修改成功!');
+    }
+
+    /**
+     * 删除指定资源
+     *
+     * @param int $id
+     * @return \think\Response
+     */
+    public function delete($id)
+    {
+        if (!$id)
+            return Json::fail('删除失败!');
+        if (AdminModel::edit(['is_del' => 1, 'status' => 0], $id, 'id'))
+            return Json::successful('删除成功!');
+        else
+            return Json::fail('删除失败!');
+    }
+
+    /**
+     * 个人资料 展示
+     * @return string
+     */
+    public function admin_info()
+    {
+        $adminInfo = $this->adminInfo;//获取当前登录的管理员
+        $this->assign('adminInfo', $adminInfo);
+        return $this->fetch();
+    }
+
+    /**
+     * 保存信息
+     */
+    public function setAdminInfo()
+    {
+        $adminInfo = $this->adminInfo;//获取当前登录的管理员
+        if ($this->request->isPost()) {
+            $data = Util::postMore([
+                ['new_pwd', ''],
+                ['new_pwd_ok', ''],
+                ['pwd', ''],
+                'real_name',
+            ]);
+            if ($data['pwd'] != '') {
+                $pwd = md5(md5($data['pwd']) . md5($adminInfo['salt']));
+                if ($adminInfo['pwd'] != $pwd) return Json::fail('原始密码错误');
+            }
+            if ($data['new_pwd'] != '') {
+                if (!$data['new_pwd_ok']) return Json::fail('请输入确认新密码');
+                if ($data['new_pwd'] != $data['new_pwd_ok']) return Json::fail('俩次密码不一样');
+            }
+            if ($data['pwd'] != '' && $data['new_pwd'] != '') {
+                $salt = substr(md5(rand(1, 999999)), 0, 6);
+                $data['pwd'] = md5(md5($data['new_pwd']) . md5($salt));
+                $data['salt'] = $salt;
+            } else {
+                unset($data['pwd']);
+            }
+            unset($data['new_pwd']);
+            unset($data['new_pwd_ok']);
+            if (!AdminModel::edit($data, $adminInfo['id'])) return Json::fail('修改失败');
+            return Json::successful('修改成功!,请重新登录');
+        }
+    }
+}

+ 376 - 0
app/admin/controller/setting/SystemConfig.php

@@ -0,0 +1,376 @@
+<?php
+
+namespace app\admin\controller\setting;
+
+use think\facade\Route as Url;
+use app\admin\controller\AuthController;
+use app\admin\model\system\{
+    SystemConfig as ConfigModel, SystemConfigTab as ConfigTabModel
+};
+use crmeb\services\{
+    CacheService,
+    FormBuilder as Form,
+    UtilService as Util,
+    JsonService as Json
+};
+use crmeb\services\upload\Upload;
+
+
+/**
+ *  配置列表控制器
+ * Class SystemConfig
+ * @package app\admin\controller\system
+ */
+class SystemConfig extends AuthController
+{
+    /**
+     * 基础配置
+     * */
+    public function index()
+    {
+        [$type, $tab_id, $children_tab_id] = Util::getMore([
+            ['type', 0],//配置类型
+            ['tab_id', 1],//当前分类ID
+            ['children_tab_id', null],//当前子集分类ID
+        ], null, true);
+
+        $config_tab = null;//顶级分类
+        $children_config_tab = null;//二级分类
+
+        if ($type == 3) {//其它分类
+            $config_tab = null;
+        } else {
+            $config_tab = ConfigModel::getConfigTabAll($type);//获取一级tab
+        }
+        $children_config_tab = ConfigModel::getConfigChildrenTabAll($tab_id);//获取二级tab
+
+        if (!$children_tab_id && $children_config_tab) {
+            $children_tab_id = $children_config_tab[0]['id'];
+        }
+
+        if ($children_tab_id) {
+            $tid = $children_tab_id;
+        } else {
+            $tid = $tab_id;
+        }
+
+        //获取分类配置参数
+        $list = ConfigModel::getAll($tid);
+        $formbuider = ConfigModel::builder_config_from_data($list);//生产表单json
+        $form = Form::make_post_form('编辑配置', $formbuider, Url::buildUrl('save_basics'));
+
+        $this->assign('tab_id', $tab_id);
+        $this->assign('children_tab_id', $children_tab_id);
+        $this->assign('config_tab', $config_tab);
+        $this->assign('children_config_tab', $children_config_tab);
+
+        $this->assign(compact('form'));
+        $this->assign('list', $list);
+        return $this->fetch();
+    }
+
+
+
+    /**
+     * 基础配置  单个
+     * @return mixed|void
+     */
+    public function index_alone()
+    {
+        $tab_id = input('tab_id');
+        if (!$tab_id) return $this->failed('参数错误,请重新打开');
+        $this->assign('tab_id', $tab_id);
+        $list = ConfigModel::getAll($tab_id);
+        foreach ($list as $k => $v) {
+            if (!is_null(json_decode($v['value'])))
+                $list[$k]['value'] = json_decode($v['value'], true);
+            if ($v['type'] == 'upload' && !empty($v['value'])) {
+                if ($v['upload_type'] == 1 || $v['upload_type'] == 3) $list[$k]['value'] = explode(',', $v['value']);
+            }
+        }
+        $this->assign('list', $list);
+        return $this->fetch();
+    }
+
+    /**
+     * 添加字段
+     * @return string
+     * @throws \FormBuilder\exception\FormBuilderException
+     */
+    public function create()
+    {
+        $data = Util::getMore(['type',]);//接收参数
+        $tab_id = !empty(request()->param('tab_id')) ? request()->param('tab_id') : 1;
+        //前面通用字段
+        $formbuiderheader = array();
+        $formbuiderheader[] = Form::select('config_tab_id', '分类', 0)->setOptions(function () {
+            $menuList = ConfigTabModel::field(['id', 'pid', 'title'])->select()->toArray();
+            $list = sort_list_tier($menuList, '顶级', 'pid', 'id');
+            $options = [['value' => 0, 'label' => '顶级按钮']];
+            foreach ($list as $option) {
+                $options[] = ['value' => $option['id'], 'label' => $option['html'] . $option['title']];
+            }
+            return $options;
+        })->filterable(1);
+        $formbuiderheader[] = Form::select('input_type', '类型')->setOptions(ConfigModel::texttype());
+        $formbuiderheader[] = Form::input('info', '配置名称')->autofocus(1);
+        $formbuiderheader[] = Form::input('menu_name', '字段变量')->placeholder('例如:site_url');
+        $formbuiderheader[] = Form::input('desc', '配置简介');
+        //不同类型不同字段
+        $formbuider = array();
+        switch ($data['type']) {
+            case 0://文本框
+                $formbuider = ConfigModel::createInputRule($tab_id);
+                break;
+            case 1://多行文本框
+                $formbuider = ConfigModel::createTextAreaRule($tab_id);
+                break;
+            case 2://单选框
+                $formbuider = ConfigModel::createRadioRule($tab_id);
+                break;
+            case 3://文件上传
+                $formbuider = ConfigModel::createUploadRule($tab_id);
+                break;
+            case 4://多选框
+                $formbuider = ConfigModel::createCheckboxRule($tab_id);
+                break;
+            case 5://下拉框
+                $formbuider = ConfigModel::createSelectRule($tab_id);
+                break;
+        }
+        //后面通用字段
+        $formbuiderfoot = array();
+        $formbuiderfoot[] = Form::number('sort', '排序');
+        $formbuiderfoot[] = Form::radio('status', '状态', 1)->options(ConfigModel::formstatus());
+        $formbuiders = array_merge($formbuiderheader, $formbuider, $formbuiderfoot);
+        $form = Form::make_post_form('添加字段', $formbuiders, Url::buildUrl('save'));
+        $this->assign(compact('form'));
+        $this->assign('get', request()->param());
+        return $this->fetch();
+    }
+
+    /**
+     * 保存字段
+     * */
+    public function save()
+    {
+        $data = Util::postMore([
+            'menu_name',
+            'type',
+            'input_type',
+            'config_tab_id',
+            'parameter',
+            'upload_type',
+            'required',
+            'width',
+            'high',
+            'value',
+            'info',
+            'desc',
+            'sort',
+            'status',]);
+        if (!$data['info']) return Json::fail('请输入配置名称');
+        if (!$data['menu_name']) return Json::fail('请输入字段名称');
+        if ($data['menu_name']) {
+            $oneConfig = ConfigModel::getOneConfig('menu_name', $data['menu_name']);
+            if (!empty($oneConfig)) return Json::fail('请重新输入字段名称,之前的已经使用过了');
+        }
+        if (!$data['desc']) return Json::fail('请输入配置简介');
+        if ($data['sort'] < 0) {
+            $data['sort'] = 0;
+        }
+        if ($data['type'] == 'text') {
+            if (!ConfigModel::valiDateTextRole($data)) return Json::fail(ConfigModel::getErrorInfo());
+        }
+        if ($data['type'] == 'textarea') {
+            if (!ConfigModel::valiDateTextareaRole($data)) return Json::fail(ConfigModel::getErrorInfo());
+        }
+        $data['parameter'] = htmlspecialchars_decode($data['parameter']);
+        if ($data['type'] == 'radio' || $data['type'] == 'checkbox') {
+            if (!$data['parameter']) return Json::fail('请输入配置参数');
+            if (!ConfigModel::valiDateRadioAndCheckbox($data)) return Json::fail(ConfigModel::getErrorInfo());
+            $data['value'] = json_encode($data['value']);
+        }
+        ConfigModel::create($data);
+        CacheService::clear();
+        return Json::successful('添加菜单成功!');
+    }
+
+    /**
+     * @param $id
+     */
+    public function update_config($id)
+    {
+        $type = request()->post('type');
+        if ($type == 'text' || $type == 'textarea' || $type == 'radio' || ($type == 'upload' && (request()->post('upload_type') == 1 || request()->post('upload_type') == 3))) {
+            $value = request()->post('value');
+        } else {
+            $value = request()->post('value/a');
+        }
+        $data = Util::postMore(['status', 'info', 'desc', 'sort', 'config_tab_id', 'required', 'parameter', ['value', $value], 'upload_type', 'input_type']);
+        $data['value'] = htmlspecialchars_decode(json_encode($data['value']));
+        $data['parameter'] = htmlspecialchars_decode($data['parameter']);
+        if (!ConfigModel::get($id)) return Json::fail('编辑的记录不存在!');
+        ConfigModel::edit($data, $id);
+        return Json::successful('修改成功!');
+    }
+
+    /**
+     * 修改是否显示子子段
+     * @param $id
+     * @return mixed
+     */
+    public function edit_config($id)
+    {
+        $menu = ConfigModel::get($id)->getData();
+        if (!$menu) return Json::fail('数据不存在!');
+        $formbuider = array();
+        $formbuider[] = Form::input('menu_name', '字段变量', $menu['menu_name'])->disabled(1);
+        $formbuider[] = Form::hidden('type', $menu['type']);
+//        $formbuider[] = Form::select('config_tab_id', '分类', (string)$menu['config_tab_id'])->setOptions(ConfigModel::getConfigTabAll(-1));
+        $formbuider[] = Form::select('config_tab_id', '分类', (string)$menu['config_tab_id'])->setOptions(function () {
+            $menuList = ConfigTabModel::field(['id', 'pid', 'title'])->select()->toArray();
+            $list = sort_list_tier($menuList, '顶级', 'pid', 'id');
+            $options = [['value' => 0, 'label' => '顶级按钮']];
+            foreach ($list as $option) {
+                $options[] = ['value' => $option['id'], 'label' => $option['html'] . $option['title']];
+            }
+            return $options;
+        })->filterable(1);
+        $formbuider[] = Form::input('info', '配置名称', $menu['info'])->autofocus(1);
+        $formbuider[] = Form::input('desc', '配置简介', $menu['desc']);
+        switch ($menu['type']) {
+            case 'text':
+                $menu['value'] = json_decode($menu['value'], true);
+                $formbuider[] = Form::select('input_type', '类型', $menu['input_type'])->setOptions(ConfigModel::texttype());
+                //输入框验证规则
+                $formbuider[] = Form::input('value', '默认值', $menu['value']);
+                if (!empty($menu['required'])) {
+                    $formbuider[] = Form::number('width', '文本框宽(%)', $menu['width']);
+                    $formbuider[] = Form::input('required', '验证规则', $menu['required'])->placeholder('多个请用,隔开例如:required:true,url:true');
+                }
+                break;
+            case 'textarea':
+                $menu['value'] = json_decode($menu['value'], true);
+                //多行文本
+                if (!empty($menu['high'])) {
+                    $formbuider[] = Form::textarea('value', '默认值', $menu['value'])->rows(5);
+                    $formbuider[] = Form::number('width', '文本框宽(%)', $menu['width']);
+                    $formbuider[] = Form::number('high', '多行文本框高(%)', $menu['high']);
+                } else {
+                    $formbuider[] = Form::input('value', '默认值', $menu['value']);
+                }
+                break;
+            case 'radio':
+                $menu['value'] = json_decode($menu['value'], true);
+                $parameter = explode("\n", htmlspecialchars_decode($menu['parameter']));
+                $options = [];
+                if ($parameter) {
+                    foreach ($parameter as $v) {
+                        $data = explode("=>", $v);
+                        $options[] = ['label' => $data[1], 'value' => $data[0]];
+                    }
+                    $formbuider[] = Form::radio('value', '默认值', $menu['value'])->options($options);
+                }
+                //单选和多选参数配置
+                if (!empty($menu['parameter'])) {
+                    $formbuider[] = Form::textarea('parameter', '配置参数', $menu['parameter'])->placeholder("参数方式例如:\n1=白色\n2=红色\n3=黑色");
+                }
+                break;
+            case 'checkbox':
+                $menu['value'] = json_decode($menu['value'], true) ?: [];
+                $parameter = explode("\n", htmlspecialchars_decode($menu['parameter']));
+                $options = [];
+                if ($parameter) {
+                    foreach ($parameter as $v) {
+                        $data = explode("=>", $v);
+                        $options[] = ['label' => $data[1], 'value' => $data[0]];
+                    }
+                    $formbuider[] = Form::checkbox('value', '默认值', $menu['value'])->options($options);
+                }
+                //单选和多选参数配置
+                if (!empty($menu['parameter'])) {
+                    $formbuider[] = Form::textarea('parameter', '配置参数', $menu['parameter'])->placeholder("参数方式例如:\n1=白色\n2=红色\n3=黑色");
+                }
+                break;
+            case 'upload':
+                if ($menu['upload_type'] == 1) {
+                    $menu['value'] = json_decode($menu['value'], true);
+                    $formbuider[] = Form::frameImageOne('value', '图片', Url::buildUrl('admin/widget.images/index', array('fodder' => 'value')), (string)$menu['value'])->icon('image')->width('100%')->height('550px');
+                } elseif ($menu['upload_type'] == 2) {
+                    $menu['value'] = json_decode($menu['value'], true) ?: [];
+                    $formbuider[] = Form::frameImages('value', '多图片', Url::buildUrl('admin/widget.images/index', array('fodder' => 'value')), $menu['value'])->maxLength(5)->icon('images')->width('100%')->height('550px')->spin(0);
+                } else {
+                    $menu['value'] = json_decode($menu['value'], true);
+                    $formbuider[] = Form::uploadFileOne('value', '文件', Url::buildUrl('file_upload'), $menu['value'])->name('file');
+                }
+                //上传类型选择
+                if (!empty($menu['upload_type'])) {
+                    $formbuider[] = Form::radio('upload_type', '上传类型', $menu['upload_type'])->options([['value' => 1, 'label' => '单图'], ['value' => 2, 'label' => '多图'], ['value' => 3, 'label' => '文件']]);
+                }
+                break;
+
+        }
+        $formbuider[] = Form::number('sort', '排序', $menu['sort']);
+        $formbuider[] = Form::radio('status', '状态', $menu['status'])->options([['value' => 1, 'label' => '显示'], ['value' => 2, 'label' => '隐藏']]);
+
+        $form = Form::make_post_form('编辑字段', $formbuider, Url::buildUrl('update_config', array('id' => $id)));
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 删除子字段
+     * @return \think\response\Json
+     */
+    public function delete_config()
+    {
+        $id = input('id');
+        if (!ConfigModel::del($id)) {
+            return Json::fail(ConfigModel::getErrorInfo('删除失败,请稍候再试!'));
+        } else {
+            CacheService::clear();
+            return Json::successful('删除成功!');
+        }
+    }
+
+    /**
+     * 保存数据    true
+     * */
+    public function save_basics()
+    {
+        $request = app('request');
+        if ($request->isPost()) {
+            $post = $request->post();
+            foreach ($post as $k => $v) {
+                if (is_array($v)) {
+                    $res = ConfigModel::where('menu_name', $k)->column('upload_type', 'type');
+                    foreach ($res as $kk => $vv) {
+                        if ($kk == 'upload') {
+                            if ($vv == 1 || $vv == 3) {
+                                $post[$k] = $v[0];
+                            }
+                        }
+                    }
+                }
+            }
+            foreach ($post as $k => $v) {
+                ConfigModel::edit(['value' => json_encode($v)], $k, 'menu_name');
+            }
+            CacheService::clear();
+            return $this->successful('修改成功');
+        }
+    }
+
+    /**
+     * 文件上传
+     * */
+    public function file_upload()
+    {
+        $upload = new Upload('local');
+        $res = $upload->to('config/file')->validate()->move($this->request->param('file', 'file'));
+        if ($res === false) return Json::fail($upload->getError());
+        return Json::successful('上传成功!', ['filePath' => $res->filePath]);
+    }
+
+}

+ 179 - 0
app/admin/controller/setting/SystemConfigTab.php

@@ -0,0 +1,179 @@
+<?php
+
+namespace app\admin\controller\setting;
+
+use think\facade\Route as Url;
+use app\admin\controller\AuthController;
+use crmeb\services\{
+    FormBuilder as Form, UtilService as Util, JsonService as Json
+};
+use app\admin\model\system\{
+    SystemConfig as ConfigModel, SystemConfigTab as ConfigTabModel
+};
+
+/**
+ * 配置分类控制器
+ * Class SystemConfigTab
+ * @package app\admin\controller\system
+ */
+class SystemConfigTab extends AuthController
+{
+    /** 定义配置分类,需要添加分类可以手动添加
+     * @return array
+     */
+    public function getConfigType()
+    {
+        return [
+            ['value' => 0, 'label' => '系统']
+            , ['value' => 1, 'label' => '应用']
+            , ['value' => 2, 'label' => '支付']
+            , ['value' => 3, 'label' => '其它']
+        ];
+    }
+
+    /**
+     * 子子段
+     * @return mixed|\think\response\Json
+     */
+    public function sonconfigtab()
+    {
+        $tab_id = input('tab_id');
+        if (!$tab_id) return Json::fail('参数错误');
+        $this->assign('tab_id', $tab_id);
+        $list = ConfigModel::getAll($tab_id, 2);
+        foreach ($list as $k => $v) {
+            $list[$k]['value'] = json_decode($v['value'], true) ?: '';
+            if ($v['type'] == 'radio' || $v['type'] == 'checkbox') {
+                $list[$k]['value'] = ConfigTabModel::getRadioOrCheckboxValueInfo($v['menu_name'], $v['value']);
+            }
+            if ($v['type'] == 'upload' && !empty($v['value'])) {
+                if ($v['upload_type'] == 1 || $v['upload_type'] == 3) $list[$k]['value'] = explode(',', $v['value']);
+            }
+        }
+        $this->assign('list', $list);
+        return $this->fetch();
+    }
+
+    /**
+     * 基础配置
+     * @return mixed
+     */
+    public function index()
+    {
+        $where = Util::getMore([
+            ['status', ''],
+            ['title', ''],
+            ['pid', 0],
+        ], $this->request);
+        $this->assign('where', $where);
+        $this->assign(ConfigTabModel::getSystemConfigTabPage($where));
+        return $this->fetch();
+    }
+
+
+    /**
+     * 添加配置分类
+     * @return mixed
+     */
+    public function create()
+    {
+        $field = [];
+        $field[] = Form::select('pid', '父级分类', 0)->setOptions(function () {
+            $menuList = ConfigTabModel::field(['id', 'pid', 'title'])->select()->toArray();//var_dump($menuList);
+            $list = sort_list_tier($menuList, '顶级', 'pid', 'id');//var_dump($list);
+            $menus = [['value' => 0, 'label' => '顶级按钮']];
+            foreach ($list as $menu) {
+                $menus[] = ['value' => $menu['id'], 'label' => $menu['html'] . $menu['title']];
+            }
+            return $menus;
+        })->filterable(1);
+        $field[] = Form::input('title', '分类名称');
+        $field[] = Form::input('eng_title', '分类字段英文');
+        $field[] = Form::frameInputOne('icon', '图标', Url::buildUrl('admin/widget.widgets/icon', array('fodder' => 'icon')))->icon('ionic')->height('500px');
+        $field[] = Form::radio('type', '类型', 0)->options(self::getConfigType());
+        $field[] = Form::radio('status', '状态', 1)->options([['value' => 1, 'label' => '显示'], ['value' => 2, 'label' => '隐藏']]);
+        $field[] = Form::radio('type', '类型', 0)->options(self::getConfigType());
+        $field[] = Form::number('sort', '排序', 0);
+        $form = Form::make_post_form('添加分类配置', $field, Url::buildUrl('save'), 3);
+        $form->setMethod('post')->setTitle('添加分类配置');
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 保存分类名称
+     */
+    public function save()
+    {
+        $data = Util::postMore([
+            'eng_title',
+            'status',
+            'title',
+            'pid',
+            'icon',
+            'type',
+            ['sort', 0]
+        ]);
+        if (!$data['title']) return Json::fail('请输入按钮名称');
+        ConfigTabModel::create($data);
+        return Json::successful('添加菜单成功!');
+    }
+
+    /**
+     * 修改分类
+     * @param $id
+     * @return string|void
+     * @throws \FormBuilder\exception\FormBuilderException
+     */
+    public function edit($id)
+    {
+        $menu = ConfigTabModel::get($id)->getData();
+        if (!$menu) return Json::fail('数据不存在!');
+        $form = Form::create(Url::buildUrl('update', array('id' => $id)), [
+            Form::select('pid', '父级分类', (string)$menu['pid'])->setOptions(function () {
+                $menuList = ConfigTabModel::field(['id', 'pid', 'title'])->select()->toArray();
+                $list = sort_list_tier($menuList, '顶级', 'pid', 'id');
+                $options = [['value' => 0, 'label' => '顶级按钮']];
+                foreach ($list as $option) {
+                    $options[] = ['value' => $option['id'], 'label' => $option['html'] . $option['title']];
+                }
+                return $options;
+            })->filterable(1),
+            Form::input('title', '分类名称', $menu['title']),
+            Form::input('eng_title', '分类字段英文', $menu['eng_title']),
+            Form::frameInputOne('icon', '图标', Url::buildUrl('admin/widget.widgets/icon', array('fodder' => 'icon')), $menu['icon'])->icon('ionic')->height('500px'),
+            Form::radio('type', '类型', $menu['type'])->options(self::getConfigType()),
+            Form::radio('status', '状态', $menu['status'])->options([['value' => 1, 'label' => '显示'], ['value' => 2, 'label' => '隐藏']]),
+            Form::number('sort', '排序', $menu['sort'] ?? 0),
+        ]);
+        $form->setMethod('post')->setTitle('添加分类配置');
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * @param $id
+     */
+    public function update($id)
+    {
+        $data = Util::postMore(['title', 'pid', 'status', 'eng_title', 'icon', 'type','sort']);
+        if (!$data['title']) return Json::fail('请输入分类昵称');
+        if (!$data['eng_title']) return Json::fail('请输入分类字段');
+        if (!ConfigTabModel::get($id)) return Json::fail('编辑的记录不存在!');
+        ConfigTabModel::edit($data, $id);
+        return Json::successful('修改成功!');
+    }
+
+    /**
+     * @param $id
+     */
+    public function delete($id)
+    {
+        if (!$id) return Json::fail('参数有误!');
+        if (ConfigTabModel::be(['pid' => $id])) return Json::fail('有子分类,不能直接删除');
+        if (!ConfigTabModel::del($id))
+            return Json::fail(ConfigTabModel::getErrorInfo('删除失败,请稍候再试!'));
+        else
+            return Json::successful('删除成功!');
+    }
+}

+ 127 - 0
app/admin/controller/setting/SystemGroup.php

@@ -0,0 +1,127 @@
+<?php
+
+namespace app\admin\controller\setting;
+
+use crmeb\services\UtilService as Util;
+use crmeb\services\JsonService as Json;
+use think\facade\Route as Url;
+use app\admin\model\system\SystemGroup as GroupModel;
+use app\admin\model\system\SystemGroupData as GroupDataModel;
+use app\admin\controller\AuthController;
+
+/**
+ * 组合数据控制器
+ * Class SystemGroup
+ * @package app\admin\controller\system
+ */
+class SystemGroup extends AuthController
+{
+    /**
+     * 显示资源列表
+     *
+     * @return \think\Response
+     */
+    public function index()
+    {
+        $this->assign(GroupModel::page());
+        return $this->fetch();
+    }
+
+    /**
+     * 显示创建资源表单页.
+     *
+     * @return \think\Response
+     */
+    public function create()
+    {
+        $this->assign(['title'=>'添加数据组','save'=>Url::buildUrl('save')]);
+        return $this->fetch();
+    }
+
+    /**
+     * 保存新建的资源
+     *
+     * @param  \think\Request  $request
+     * @return \think\Response
+     */
+    public function save()
+    {
+        $params = Util::postMore([
+            ['id',''],
+            ['name',''],
+            ['config_name',''],
+            ['info',''],
+            ['typelist',[]],
+        ],$this->request);
+
+        //数据组名称判断
+        if(!$params['name'])return Json::fail('请输入数据组名称!');
+        if(!$params['config_name'])return Json::fail('请输入配置名称!');
+        //判断ID是否存在,存在就是编辑,不存在就是添加
+        if(!$params['id']){
+            if(GroupModel::be($params['config_name'],'config_name')) return Json::fail('数据关键字已存在!');
+        }
+        $data["name"] = $params['name'];
+        $data["config_name"] = $params['config_name'];
+        $data["info"] = $params['info'];
+        //字段信息判断
+        if(!count($params['typelist']))
+            return Json::fail('字段至少存在一个!');
+        else{
+            $validate = ["name","type","title","description"];
+            foreach ($params["typelist"] as $key => $value) {
+                foreach ($value as $name => $field) {
+                    if(empty($field["value"]) && in_array($name,$validate))
+                        return Json::fail("字段".($key + 1).":".$field["placeholder"]."不能为空!");
+                    else
+                        $data["fields"][$key][$name] = $field["value"];
+                }
+            }
+        }
+        $data["fields"] = htmlspecialchars_decode(json_encode($data["fields"]));
+        //判断ID是否存在,存在就是编辑,不存在就是添加
+        if(!$params['id']) {
+            GroupModel::create($data);
+            return Json::successful('添加数据组成功!');
+        }else{
+            GroupModel::edit($data,$params['id']);
+            return Json::successful('编辑数据组成功!');
+        }
+    }
+
+    /**编辑数组
+     * @param $id
+     */
+    public function edit($id)
+    {
+        $Groupinfo = GroupModel::get($id);
+        $fields = json_decode($Groupinfo['fields'],true);
+        $typelist = [];
+        foreach ($fields as $key => $v){
+            $typelist[$key]['name']['value'] = $v['name'];
+            $typelist[$key]['title']['value'] = $v['title'];
+            $typelist[$key]['type']['value'] = $v['type'];
+            $typelist[$key]['param']['value'] = $v['param'];
+        }
+        $Groupinfo['fields'] = json_encode($typelist);
+        $this->assign(compact('Groupinfo'));
+        $this->assign(['title'=>'添加数据组','save'=>Url::buildUrl('save')]);
+        return $this->fetch();
+    }
+
+    /**
+     * 删除指定资源
+     *
+     * @param  int  $id
+     * @return \think\Response
+     */
+    public function delete($id)
+    {
+        if(!GroupModel::del($id))
+            return Json::fail(GroupModel::getErrorInfo('删除失败,请稍候再试!'));
+        else{
+            GroupDataModel::del(["gid"=>$id]);
+            return Json::successful('删除成功!');
+        }
+    }
+}

+ 279 - 0
app/admin/controller/setting/SystemGroupData.php

@@ -0,0 +1,279 @@
+<?php
+
+namespace app\admin\controller\setting;
+
+use app\admin\controller\AuthController;
+use app\admin\model\ump\StoreSeckill;
+use crmeb\services\{
+    CacheService,
+    FormBuilder as Form,
+    JsonService as Json,
+    UtilService as Util
+};
+use think\facade\Route as Url;
+use app\admin\model\system\{
+    SystemAttachment, SystemGroup as GroupModel, SystemGroupData as GroupDataModel
+};
+
+/**
+ * 数据列表控制器  在组合数据中
+ * Class SystemGroupData
+ * @package app\admin\controller\system
+ */
+class SystemGroupData extends AuthController
+{
+
+    /**
+     * 显示资源列表
+     * @return \think\Response
+     */
+    public function index($gid = 0)
+    {
+        $where = Util::getMore([
+            ['gid', 0],
+            ['status', ''],
+        ], $this->request);
+        if ($gid) $where['gid'] = $gid;
+        $this->assign('where', $where);
+        $this->assign(compact("gid"));
+        $this->assign(GroupModel::getField($gid));
+        $this->assign(GroupDataModel::getList($where));
+        return $this->fetch();
+    }
+
+    /**
+     * 显示创建资源表单页.
+     * @return \think\Response
+     */
+    public function create($gid)
+    {
+        $Fields = GroupModel::getField($gid);
+        $f = array();
+        foreach ($Fields["fields"] as $key => $value) {
+            $info = [];
+            if (isset($value["param"])) {
+                $value["param"] = str_replace("\r\n", "\n", $value["param"]);//防止不兼容
+                $params = explode("\n", $value["param"]);
+                if (is_array($params) && !empty($params)) {
+                    foreach ($params as $index => $v) {
+                        $vl = explode('=>', $v);
+                        if (isset($vl[0]) && isset($vl[1])) {
+                            $info[$index]["value"] = $vl[0];
+                            $info[$index]["label"] = $vl[1];
+                        }
+                    }
+                }
+            }
+
+            switch ($value["type"]) {
+                case 'input':
+                    $f[] = Form::input($value["title"], $value["name"]);
+                    break;
+                case 'textarea':
+                    $f[] = Form::input($value["title"], $value["name"])->type('textarea')->placeholder($value['param']);
+                    break;
+                case 'radio':
+                    $f[] = Form::radio($value["title"], $value["name"], $info[0]["value"] ?? '')->options($info);
+                    break;
+                case 'checkbox':
+                    $f[] = Form::checkbox($value["title"], $value["name"], $info[0] ?? '')->options($info);
+                    break;
+                case 'select':
+                    $f[] = Form::select($value["title"], $value["name"], $info[0] ?? '')->options($info)->multiple(false);
+                    break;
+                case 'upload':
+                    $f[] = Form::frameImageOne($value["title"], $value["name"], Url::buildUrl('admin/widget.images/index', array('fodder' => $value["title"], 'big' => 1)))->icon('image')->width('100%')->height('500px');
+                    break;
+                case 'uploads':
+                    $f[] = Form::frameImages($value["title"], $value["name"], Url::buildUrl('admin/widget.images/index', array('fodder' => $value["title"], 'big' => 1)))->maxLength(5)->icon('images')->width('100%')->height('500px')->spin(0);
+                    break;
+                case 'number':
+                    $f[] = Form::number($value["title"], $value["name"])->precision('int');
+                    break;
+                default:
+                    $f[] = Form::input($value["title"], $value["name"]);
+                    break;
+
+            }
+        }
+        $f[] = Form::number('sort', '排序', 1);
+        $f[] = Form::radio('status', '状态', 1)->options([['value' => 1, 'label' => '显示'], ['value' => 2, 'label' => '隐藏']]);
+        $form = Form::make_post_form('添加数据', $f, Url::buildUrl('save', compact('gid')), 2);
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 保存新建的资源
+     *
+     * @param \think\Request $request
+     * @return \think\Response
+     */
+    public function save($gid)
+    {
+        $Fields = GroupModel::getField($gid);
+        $params = request()->post();
+        foreach ($params as $key => $param) {
+            foreach ($Fields['fields'] as $index => $field) {
+                if ($key == $field["title"]) {
+//                    if($param == "" || count($param) == 0)
+                    if ($param == "")
+                        return Json::fail($field["name"] . "不能为空!");
+                    else {
+                        $value[$key]["type"] = $field["type"];
+                        $value[$key]["value"] = $param;
+                    }
+                }
+            }
+        }
+
+        $data = array("gid" => $gid, "add_time" => time(), "value" => htmlspecialchars_decode(json_encode($value)), "sort" => $params["sort"], "status" => $params["status"]);
+        GroupDataModel::create($data);
+        CacheService::clear();
+        return Json::successful('添加数据成功!');
+    }
+
+    /**
+     * 显示指定的资源
+     *
+     * @param int $id
+     * @return \think\Response
+     */
+    public function read($id)
+    {
+        //
+    }
+
+    /**
+     * 显示编辑资源表单页.
+     *
+     * @param int $id
+     * @return \think\Response
+     */
+    public function edit($gid, $id)
+    {
+        $GroupData = GroupDataModel::get($id);
+        $GroupDataValue = json_decode($GroupData["value"], true);
+        $Fields = GroupModel::getField($gid);
+        $f = array();
+        if (!isset($Fields['fields'])) return $this->failed('数据解析失败!');
+        foreach ($Fields['fields'] as $key => $value) {
+            $info = [];
+            if (isset($value["param"])) {
+                $value["param"] = str_replace("\r\n", "\n", $value["param"]);//防止不兼容
+                $params = explode("\n", $value["param"]);
+                if (is_array($params) && !empty($params)) {
+                    foreach ($params as $index => $v) {
+                        $vl = explode('=>', $v);
+                        if (isset($vl[0]) && isset($vl[1])) {
+                            $info[$index]["value"] = $vl[0];
+                            $info[$index]["label"] = $vl[1];
+                        }
+                    }
+                }
+            }
+            $fvalue = isset($GroupDataValue[$value['title']]['value']) ? $GroupDataValue[$value['title']]['value'] : '';
+            switch ($value['type']) {
+                case 'input':
+                    $f[] = Form::input($value['title'], $value['name'], $fvalue);
+                    break;
+                case 'textarea':
+                    $f[] = Form::input($value['title'], $value['name'], $fvalue)->type('textarea');
+                    break;
+                case 'radio':
+
+                    $f[] = Form::radio($value['title'], $value['name'], $fvalue)->options($info);
+                    break;
+                case 'checkbox':
+                    $f[] = Form::checkbox($value['title'], $value['name'], $fvalue)->options($info);
+                    break;
+                case 'upload':
+                    if (!empty($fvalue)) {
+                        $image = is_string($fvalue) ? $fvalue : $fvalue[0];
+                    } else {
+                        $image = '';
+                    }
+                    $f[] = Form::frameImageOne($value['title'], $value['name'], Url::buildUrl('admin/widget.images/index', array('fodder' => $value['title'], 'big' => 1)), $image)->icon('image')->width('100%')->height('500px');
+                    break;
+                case 'uploads':
+                    $images = !empty($fvalue) ? $fvalue : [];
+                    $f[] = Form::frameImages($value['title'], $value['name'], Url::buildUrl('admin/widget.images/index', array('fodder' => $value['title'], 'big' => 1)), $images)->maxLength(5)->icon('images')->width('100%')->height('500px')->spin(0);
+                    break;
+                case 'select':
+                    $f[] = Form::select($value['title'], $value['name'], $fvalue)->setOptions($info);
+                    break;
+                case 'number':
+                    $f[] = Form::number($value["title"], $value["name"])->precision('int');
+                    break;
+                default:
+                    $f[] = Form::input($value['title'], $value['name'], $fvalue);
+                    break;
+
+            }
+        }
+        $f[] = Form::number('sort', '排序', $GroupData["sort"]);
+        $f[] = Form::radio('status', '状态', $GroupData["status"])->options([['value' => 1, 'label' => '显示'], ['value' => 2, 'label' => '隐藏']]);
+        $form = Form::make_post_form('添加用户通知', $f, Url::buildUrl('update', compact('id')), 2);
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 保存更新的资源
+     *
+     * @param $id
+     */
+    public function update($id)
+    {
+        $GroupData = GroupDataModel::get($id);
+        $Fields = GroupModel::getField($GroupData["gid"]);
+        $params = request()->post();
+        foreach ($params as $key => $param) {
+            foreach ($Fields['fields'] as $index => $field) {
+                if ($key == $field["title"]) {
+                    if (trim($param) == '')
+                        return Json::fail($field["name"] . "不能为空!");
+                    else {
+                        $value[$key]["type"] = $field["type"];
+                        $value[$key]["value"] = $param;
+                    }
+                }
+            }
+        }
+        $data = array("value" => htmlspecialchars_decode(json_encode($value)), "sort" => $params["sort"], "status" => $params["status"]);
+        GroupDataModel::edit($data, $id);
+        CacheService::clear();
+        return Json::successful('修改成功!');
+    }
+
+    /**
+     * 删除指定资源
+     *
+     * @param int $id
+     * @return \think\Response
+     */
+    public function delete($id)
+    {
+        $gid = GroupDataModel::where('id', $id)->value('gid');
+        $config_name = GroupModel::where('id', $gid)->value('config_name');
+        if ($config_name == 'routine_seckill_time') {
+            if (!StoreSeckill::where('is_del', 0)->find()) {
+                if (!GroupDataModel::del($id))
+                    return Json::fail(GroupDataModel::getErrorInfo('删除失败,请稍候再试!'));
+                else {
+                    CacheService::clear();
+                    return Json::successful('删除成功!');
+                }
+            } else {
+                return Json::fail('有秒杀活动,不能删除秒杀时段,请先删除活动');
+            }
+        } else {
+            if (!GroupDataModel::del($id))
+                return Json::fail(GroupDataModel::getErrorInfo('删除失败,请稍候再试!'));
+            else {
+                CacheService::clear();
+                return Json::successful('删除成功!');
+            }
+        }
+    }
+}

+ 208 - 0
app/admin/controller/setting/SystemMenus.php

@@ -0,0 +1,208 @@
+<?php
+
+namespace app\admin\controller\setting;
+
+use app\admin\controller\AuthController;
+use crmeb\traits\CurdControllerTrait;
+use think\facade\Route as Url;
+use app\admin\model\system\SystemMenus as MenusModel;
+use crmeb\services\{FormBuilder as Form, UtilService as Util, JsonService as Json};
+
+/**
+ * 菜单管理控制器
+ * Class SystemMenus
+ * @package app\admin\controller\system
+ */
+class SystemMenus extends AuthController
+{
+    use CurdControllerTrait;
+
+    public $bindModel = MenusModel::class;
+
+    /**
+     * 显示资源列表
+     *
+     * @return \think\Response
+     */
+    public function index()
+    {
+        $pid = $this->request->param('pid') ? $this->request->param('pid') : 0;
+        $params = Util::getMore([
+            ['is_show', ''],
+//            ['access',''],
+            ['keyword', ''],
+            ['pid', $pid]
+        ], $this->request);
+        $this->assign(MenusModel::getAdminPage($params));
+        $addurl = Url::buildUrl('create', ['cid' => input('pid')]);
+        $this->assign(compact('params', 'addurl'));
+        return $this->fetch();
+    }
+
+
+    /**
+     * 显示创建资源表单页.
+     *
+     * @return \think\Response
+     */
+    public function create($cid = 0)
+    {
+        $field = [];
+        $field[] = Form::input('menu_name', '按钮名称')->required('按钮名称必填');
+        $field[] = Form::select('pid', '父级id', $cid)->setOptions(function () {
+            $menuList = MenusModel::field(['id', 'pid', 'menu_name'])->order('sort DESC,id ASC')->select()->toArray();
+            $list = sort_list_tier($menuList, '顶级', 'pid', 'menu_name');
+            $menus = [['value' => 0, 'label' => '顶级按钮']];
+            foreach ($list as $menu) {
+                $menus[] = ['value' => $menu['id'], 'label' => $menu['html'] . $menu['menu_name']];
+            }
+            return $menus;
+        })->filterable(1);
+        $field[] = Form::select('module', '模块名')->options([['label' => '总后台', 'value' => 'admin']]);
+        if ($cid) $controller = MenusModel::where('id', $cid)->value('controller') ?: '';
+        else $controller = '';
+        $field[] = Form::input('controller', '控制器名', $controller);
+        if (!empty($controller)) {
+            $controller = preg_replace_callback('/([.]+([a-z]{1}))/i', function ($matches) {
+                return '\\' . strtoupper($matches[2]);
+            }, $controller);
+            if (class_exists('\app\admin\controller\\' . $controller)) {
+                $list = get_this_class_methods('\app\admin\controller\\' . $controller);
+
+                $field[] = Form::select('action', '方法名')->setOptions(function () use ($list) {
+                    $menus = [['value' => 0, 'label' => '默认函数']];
+                    foreach ($list as $menu) {
+                        $menus[] = ['value' => $menu, 'label' => $menu];
+                    }
+                    return $menus;
+                })->filterable(1);
+            } else {
+                $field[] = Form::input('action', '方法名');
+            }
+        } else {
+            $field[] = Form::input('action', '方法名');
+        }
+        $field[] = Form::input('params', '参数')->placeholder('举例:a/123/b/234');
+        $field[] = Form::frameInputOne('icon', '图标', Url::buildUrl('admin/widget.widgets/icon', array('fodder' => 'icon')))->icon('ionic')->height('500px');
+        $field[] = Form::number('sort', '排序', 0);
+        $field[] = Form::radio('is_show', '是否菜单', 0)->options([['value' => 0, 'label' => '隐藏'], ['value' => 1, 'label' => '显示(菜单只显示三级)']]);
+        $form = Form::make_post_form('添加权限', $field, Url::buildUrl('save'), 3);
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 保存新建的资源
+     */
+    public function save()
+    {
+        $data = Util::postMore([
+            'menu_name',
+            'controller',
+            ['module', 'admin'],
+            'action',
+            'icon',
+            'params',
+            ['pid', 0],
+            ['sort', 0],
+            ['is_show', 0],
+            ['access', 1]]);
+        if (!$data['menu_name']) return Json::fail('请输入按钮名称');
+        MenusModel::create($data);
+        return Json::successful('添加菜单成功!');
+    }
+
+    /**
+     * 显示编辑资源表单页.
+     *
+     * @param int $id
+     * @return \think\Response
+     */
+    public function edit($id)
+    {
+        $menu = MenusModel::get($id);
+        if (!$menu) return Json::fail('数据不存在!');
+        $field = [];
+        $field[] = Form::input('menu_name', '按钮名称', $menu['menu_name']);
+        $field[] = Form::select('pid', '父级id', (string)$menu->getData('pid'))->setOptions(function () use ($id) {
+            $menuList = MenusModel::field(['id', 'pid', 'menu_name'])->order('sort DESC,id ASC')->select()->toArray();
+            $list = sort_list_tier($menuList, '顶级', 'pid', 'menu_name');
+            $menus = [['value' => 0, 'label' => '顶级按钮']];
+            foreach ($list as $menu) {
+                $menus[] = ['value' => $menu['id'], 'label' => $menu['html'] . $menu['menu_name']];
+            }
+            return $menus;
+        })->filterable(1);
+        $field[] = Form::select('module', '模块名', $menu['module'])->options([['label' => '总后台', 'value' => 'admin']]);
+        $field[] = Form::input('controller', '控制器名', $menu['controller']);
+        if (!empty($menu['controller'])) {
+            $controller = preg_replace_callback('/([.]+([a-z]{1}))/i', function ($matches) {
+                return '\\' . strtoupper($matches[2]);
+            }, $menu['controller']);
+            if (class_exists('\app\admin\controller\\' . $controller)) {
+                $list = get_this_class_methods('\app\admin\controller\\' . $controller);
+
+                $field[] = Form::select('action', '方法名', (string)$menu->getData('action'))->setOptions(function () use ($list) {
+                    $menus = [['value' => 0, 'label' => '默认函数']];
+                    foreach ($list as $menu) {
+                        $menus[] = ['value' => $menu, 'label' => $menu];
+                    }
+                    return $menus;
+                })->filterable(1);
+            } else {
+                $field[] = Form::input('action', '方法名', $menu['action']);
+            }
+        } else {
+            $field[] = Form::input('action', '方法名');
+        }
+        $field[] = Form::input('params', '参数', MenusModel::paramStr($menu['params']))->placeholder('举例:a/123/b/234');
+        $field[] = Form::frameInputOne('icon', '图标', Url::buildUrl('admin/widget.widgets/icon', array('fodder' => 'icon')), $menu['icon'])->icon('ionic')->height('500px');
+        $field[] = Form::number('sort', '排序', $menu['sort']);
+        $field[] = Form::radio('is_show', '是否菜单', $menu['is_show'])->options([['value' => 0, 'label' => '隐藏'], ['value' => 1, 'label' => '显示(菜单只显示三级)']]);
+        $form = Form::make_post_form('添加权限', $field, Url::buildUrl('update', array('id' => $id)), 3);
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 保存更新的资源
+     *
+     * @param $id
+     */
+    public function update($id)
+    {
+//        $this->request->filter('htmlspecialchars');
+        $data = Util::postMore([
+            'menu_name',
+            ['controller', '', 'htmlspecialchars'],
+            ['module', 'admin'],
+            'action',
+            'params',
+            'icon',
+            ['sort', 0],
+            ['pid', 0],
+            ['is_show', 0],
+            ['access', 1]]);
+        if (!$data['menu_name']) return Json::fail('请输入按钮名称');
+        if (!MenusModel::get($id)) return Json::fail('编辑的记录不存在!');
+        MenusModel::edit($data, $id);
+        return Json::successful('修改成功!');
+    }
+
+    /**
+     * 删除指定资源
+     *
+     * @param int $id
+     * @return \think\Response
+     */
+    public function delete($id)
+    {
+        if (!$id) return $this->failed('参数错误,请重新打开');
+        $res = MenusModel::delMenu($id);
+        if (!$res)
+            return Json::fail(MenusModel::getErrorInfo('删除失败,请稍候再试!'));
+        else
+            return Json::successful('删除成功!');
+    }
+
+}

+ 130 - 0
app/admin/controller/setting/SystemNotice.php

@@ -0,0 +1,130 @@
+<?php
+
+namespace app\admin\controller\setting;
+
+use app\admin\controller\AuthController;
+use app\admin\model\system\{SystemAdmin, SystemNotice as NoticeModel};
+use crmeb\services\{JsonService, UtilService, FormBuilder as Form};
+use think\facade\Route as Url;
+
+/**
+ * 管理员消息通知 控制器
+ * Class SystemNotice
+ * @package app\admin\controller\system
+ */
+class SystemNotice extends AuthController
+{
+    public function index()
+    {
+        $this->assign(NoticeModel::page(function ($notice) {
+            $notice->push_admin_name = !empty($notice->push_admin) ? implode(',', SystemAdmin::where('id', 'IN', $notice->push_admin)->column('real_name', 'real_name')) : '';
+        }));
+        return $this->fetch();
+    }
+
+    public function create()
+    {
+        $f = array();
+        $f[] = Form::input('title', '通知标题');
+        $f[] = Form::input('type', '通知类型');
+        $f[] = Form::frameInputOne('icon', '图标', Url::buildUrl('admin/widget.widgets/icon', array('fodder' => 'icon')))->icon('ionic')->height('500px');
+        $f[] = Form::input('template', '通知模板');
+        $f[] = Form::input('table_title', '通知数据')->type('textarea')->placeholder('数据1-key1,数据2-key2');
+        $f[] = Form::select('push_admin', '通知管理员')->setOptions(function () {
+            $list = SystemAdmin::getOrdAdmin('real_name,id') ?: [];
+            $options = [];
+            foreach ($list as $admin) {
+                $options[] = ['label' => $admin['real_name'], 'value' => $admin['id']];
+            }
+            return $options;
+        })->multiple(1);
+        $f[] = Form::radio('status', '状态', 1)->options([['label' => '开启', 'value' => 1], ['label' => '关闭', 'value' => 0]]);
+        $form = Form::make_post_form('添加通知模板', $f, Url::buildUrl('save'));
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    public function save()
+    {
+        $data = UtilService::postMore([
+            'title', 'type', 'icon', 'template', 'table_title',
+            ['push_admin', []], ['status', 0]
+        ]);
+        $data['push_admin'] = array_unique(array_filter($data['push_admin']));
+        if (!$data['template']) return $this->failed('请填写通知模板');
+        if (!$data['title']) return $this->failed('请输入模板标题');
+        if (!$data['type']) return $this->failed('请输入模板类型');
+        if (NoticeModel::create($data))
+            return $this->successful('添加通知成功');
+        else
+            return $this->failed('添加失败!');
+    }
+
+    /**编辑通知模板
+     * @param $id
+     * @return mixed|void
+     */
+    public function edit($id)
+    {
+        $data = NoticeModel::get($id);
+        if (!$data) return JsonService::fail('数据不存在!');
+        $data->tableTitle = implode(',', array_map(function ($value) {
+            return $value['title'] . '-' . $value['key'];
+        }, $data->table_title));
+        $data->tableTitleStr = implode(',', array_map(function ($value) {
+            return $value['title'] . '-' . $value['key'];
+        }, $data->table_title));
+        $f = array();
+        $f[] = Form::input('title', '通知标题', $data->title);
+        $f[] = Form::input('type', '通知类型', $data->type);
+        $f[] = Form::frameInputOne('icon', '图标', Url::buildUrl('admin/widget.widgets/icon', array('fodder' => 'icon')), $data->icon)->icon('ionic')->height('500px');
+        $f[] = Form::input('template', '通知模板', $data->template);
+        $f[] = Form::input('table_title', '通知数据', $data->tableTitleStr)->type('textarea')->placeholder('数据1-key1,数据2-key2');
+        $f[] = Form::select('push_admin', '通知管理员', $data->push_admin)->setOptions(function () {
+            $list = SystemAdmin::getOrdAdmin('real_name,id') ?: [];
+            $options = [];
+            foreach ($list as $admin) {
+                $options[] = ['label' => $admin['real_name'], 'value' => $admin['id']];
+            }
+            return $options;
+        })->multiple(1);
+        $f[] = Form::radio('status', '状态', $data->status)->options([['label' => '开启', 'value' => 1], ['label' => '关闭', 'value' => 0]]);
+        $form = Form::make_post_form('编辑通知模板', $f, Url::buildUrl('update', array('id' => $id)));
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    public function update($id)
+    {
+        $data = UtilService::postMore([
+            'title', 'type', 'icon', 'template', 'table_title',
+            ['push_admin', []], ['status', 0]
+        ]);
+        $data['push_admin'] = array_unique(array_filter($data['push_admin']));
+        if (!$data['template']) return $this->failed('请填写通知模板');
+        if (!$data['title']) return $this->failed('请输入模板标题');
+        if (!$data['type']) return $this->failed('请输入模板类型');
+        NoticeModel::edit($data, $id);
+        return $this->successful('修改成功!');
+    }
+
+    /**
+     * 删除指定资源
+     *
+     * @param int $id
+     * @return \think\Response
+     */
+    public function delete($id)
+    {
+        $res = NoticeModel::del($id);
+        if (!$res)
+            return $this->failed(('删除失败,请稍候再试!'));
+        else
+            return $this->successful('删除成功!');
+    }
+
+    public function message($type = 'all')
+    {
+        return $this->fetch();
+    }
+}

+ 142 - 0
app/admin/controller/setting/SystemRole.php

@@ -0,0 +1,142 @@
+<?php
+
+namespace app\admin\controller\setting;
+
+use app\admin\controller\AuthController;
+use app\admin\model\system\{SystemMenus, SystemRole as RoleModel};
+use crmeb\services\{UtilService as Util, JsonService as Json};
+use think\facade\Route as Url;
+
+/**
+ * 身份管理  控制器
+ * Class SystemRole
+ * @package app\admin\controller\setting
+ */
+class SystemRole extends AuthController
+{
+    /**
+     * 显示资源列表
+     *
+     * @return \think\Response
+     */
+    public function index()
+    {
+        $where = Util::getMore([
+            ['status', ''],
+            ['role_name', ''],
+        ], $this->request);
+        $where['level'] = $this->adminInfo['level'];
+        $this->assign('where', $where);
+        $this->assign(RoleModel::systemPage($where));
+        return $this->fetch();
+    }
+
+    /**
+     * 显示创建资源表单页.
+     *
+     * @return \think\Response
+     */
+    public function create()
+    {
+
+//        if(0 == 0){
+//        }else{
+//            dump($this->adminInfo['level']);
+//        }
+        $menus = $this->adminInfo['level'] == 0 ? SystemMenus::ruleList() : SystemMenus::rolesByRuleList($this->adminInfo['roles']);
+        $this->assign(['menus' => json($menus)->getContent(), 'saveUrl' => Url::buildUrl('save')]);
+        return $this->fetch();
+    }
+
+    /**
+     * 保存新建的资源
+     *
+     * @param \think\Request $request
+     * @return \think\Response
+     */
+    public function save()
+    {
+        $data = Util::postMore([
+            'role_name',
+            ['status', 0],
+            ['checked_menus', [], '', 'rules']
+        ]);
+        if (!$data['role_name']) return Json::fail('请输入身份名称');
+        if (!is_array($data['rules']) || !count($data['rules']))
+            return Json::fail('请选择最少一个权限');
+        foreach ($data['rules'] as $v) {
+            $pid = SystemMenus::where('id', $v)->value('pid');
+            if (!in_array($pid, $data['rules'])) $data['rules'][] = $pid;
+        }
+        $data['rules'] = implode(',', $data['rules']);
+        $data['level'] = $this->adminInfo['level'] + 1;
+        if (!RoleModel::create($data)) return Json::fail('添加身份失败!');
+        return Json::successful('添加身份成功!');
+    }
+
+    /**
+     * 显示指定的资源
+     *
+     * @param int $id
+     * @return \think\Response
+     */
+    public function read($id)
+    {
+        //
+    }
+
+    /**
+     * 显示编辑资源表单页.
+     *
+     * @param int $id
+     * @return \think\Response
+     */
+    public function edit($id)
+    {
+        //
+        $role = RoleModel::get($id);
+        $menus = $this->adminInfo['level'] == 0 ? SystemMenus::ruleList() : SystemMenus::rolesByRuleList($this->adminInfo['roles']);
+        $this->assign(['role' => $role->toJson(), 'menus' => json($menus)->getContent(), 'updateUrl' => Url::buildUrl('update', array('id' => $id))]);
+        return $this->fetch();
+    }
+
+    /**
+     * 保存更新的资源
+     *
+     * @param \think\Request $request
+     * @param int $id
+     * @return \think\Response
+     */
+    public function update($id)
+    {
+        $data = Util::postMore([
+            'role_name',
+            ['status', 0],
+            ['checked_menus', [], '', 'rules']
+        ]);
+        if (!$data['role_name']) return Json::fail('请输入身份名称');
+        if (!is_array($data['rules']) || !count($data['rules']))
+            return Json::fail('请选择最少一个权限');
+        foreach ($data['rules'] as $v) {
+            $pid = SystemMenus::where('id', $v)->value('pid');
+            if (!in_array($pid, $data['rules'])) $data['rules'][] = $pid;
+        }
+        $data['rules'] = implode(',', $data['rules']);
+        if (!RoleModel::edit($data, $id)) return Json::fail('修改失败!');
+        return Json::successful('修改成功!');
+    }
+
+    /**
+     * 删除指定资源
+     *
+     * @param int $id
+     * @return \think\Response
+     */
+    public function delete($id)
+    {
+        if (!RoleModel::del($id))
+            return Json::fail(RoleModel::getErrorInfo('删除失败,请稍候再试!'));
+        else
+            return Json::successful('删除成功!');
+    }
+}

+ 86 - 0
app/admin/controller/system/Clear.php

@@ -0,0 +1,86 @@
+<?php
+
+namespace app\admin\controller\system;
+
+use app\admin\controller\AuthController;
+use crmeb\services\CacheService;
+
+/**
+ * 首页控制器
+ * Class Clear
+ * @package app\admin\controller
+ *
+ */
+class Clear extends AuthController
+{
+    public function index()
+    {
+        return $this->fetch();
+    }
+
+    /**
+     * 刷新数据缓存
+     */
+    public function refresh_cache()
+    {
+        $root       = app()->getRootPath() . 'runtime' . DS;
+        $adminRoute = $root . 'admin';
+        $apiRoute   = $root . 'api';
+        $cacheRoute = $root . 'cache';
+        $cache      = [];
+
+        if (is_dir($adminRoute))
+            $cache[$adminRoute] = scandir($adminRoute);
+        if (is_dir($apiRoute))
+            $cache[$apiRoute] = scandir($apiRoute);
+        if (is_dir($cacheRoute))
+            $cache[$cacheRoute] = scandir($cacheRoute);
+
+        foreach ($cache as $p => $list) {
+            foreach ($list as $file) {
+                if (!in_array($file, ['.', '..', 'log', 'schema', 'route.php'])) {
+                    $path = $p . DS . $file;
+                    if (is_file($path)) {
+                        @unlink($path);
+                    } else {
+                        $this->delDirAndFile($path . DS);
+                    }
+                }
+            }
+        }
+        CacheService::clear();
+        return app('json')->successful('数据缓存刷新成功!');
+    }
+
+
+    /**
+     * 删除日志
+     */
+    public function delete_log()
+    {
+        $root = app()->getRootPath() . 'runtime' . DS;
+        $this->delDirAndFile($root . 'admin' . DS . 'log' . DS);
+        $this->delDirAndFile($root . 'api' . DS . 'log' . DS);
+        $this->delDirAndFile($root . 'log' . DS);
+
+        return app('json')->successful('数据缓存刷新成功!');
+    }
+
+    /** 递归删除文件
+     * @param $dirName
+     * @param bool $subdir
+     */
+    protected function delDirAndFile($dirName)
+    {
+        $list = glob($dirName . '*');
+        foreach ($list as $file) {
+            if (is_dir($file))
+                $this->delDirAndFile($file . DS);
+            else
+                @unlink($file);
+        }
+        @rmdir($dirName);
+    }
+}
+
+

+ 50 - 0
app/admin/controller/system/SystemAttachment.php

@@ -0,0 +1,50 @@
+<?php
+
+namespace app\admin\controller\system;
+
+use app\admin\model\system\SystemAttachment as SystemAttachmentModel;
+use app\admin\controller\AuthController;
+use crmeb\services\upload\Upload;
+
+/**
+ * 附件管理控制器
+ * Class SystemAttachment
+ * @package app\admin\controller\system
+ *
+ */
+class SystemAttachment extends AuthController
+{
+    /**
+     * TODO 编辑器上传图片
+     */
+    public function upload()
+    {
+        $uploadType = (int)sys_config('upload_type', 1);
+        $upload = new Upload($uploadType, [
+            'accessKey' => sys_config('accessKey'),
+            'secretKey' => sys_config('secretKey'),
+            'uploadUrl' => sys_config('uploadUrl'),
+            'storageName' => sys_config('storage_name'),
+            'storageRegion' => sys_config('storage_region'),
+        ]);
+        $resInfo = $upload->to('editor/' . date('Ymd'))->validate()->move('upfile');
+        if ($resInfo === false) {
+            echo json_encode([
+                'msg' => $upload->getError(),
+                'state' => 'ERROR'
+            ]);
+        } else {
+            $res = $upload->getUploadInfo();
+            $res['image_type'] = $uploadType;
+            SystemAttachmentModel::attachmentAdd($res['name'], $res['size'], $res['type'], $res['dir'], $res['thumb_path'], 0, $res['image_type'], $res['time'], 1, $this->adminInfo['mer_id']);
+            $info["originalName"] = $res['name'];
+            $info["name"] = $res['name'];
+            $info["url"] = $res['dir'];
+            $info["size"] = $res['size'];
+            $info["type"] = $res['type'];
+            $info["state"] = "SUCCESS";
+            if ($res['image_type'] == 1) $info['url'] = sys_config('site_url') . str_replace('\\', '/', $res['dir']);
+            echo json_encode($info);
+        }
+    }
+}

+ 250 - 0
app/admin/controller/system/SystemCleardata.php

@@ -0,0 +1,250 @@
+<?php
+/**
+ * Created by PhpStorm.
+ * User: sugar1569
+ * Date: 2018/5/24
+ * Time: 10:58
+ */
+
+namespace app\admin\controller\system;
+
+
+use app\admin\controller\AuthController;
+use app\admin\model\store\StoreProduct;
+use app\admin\model\system\SystemAdmin;
+use crmeb\services\JsonService as Json;
+use crmeb\services\SystemConfigService;
+use think\facade\Config;
+use think\facade\Db;
+
+/**
+ * 清除默认数据理控制器
+ * Class SystemclearData
+ * @package app\admin\controller\system
+ */
+class SystemclearData extends AuthController
+{
+
+    public function index()
+    {
+        return $this->fetch();
+    }
+
+    //清除用户数据
+    public function userRelevantData()
+    {
+        self::clearData('user_recharge', 1);
+        self::clearData('user_address', 1);
+        self::clearData('user_bill', 1);
+        self::clearData('user_enter', 1);
+        self::clearData('user_extract', 1);
+        self::clearData('user_notice', 1);
+        self::clearData('user_notice_see', 1);
+        self::clearData('wechat_qrcode', 1);
+        self::clearData('wechat_message', 1);
+        self::clearData('routine_qrcode', 1);
+        self::clearData('routine_form_id', 1);
+        self::clearData('user_sign', 1);
+        self::clearData('user_task_finish', 1);
+        self::clearData('user_level', 1);
+        self::clearData('user_token', 1);
+        self::clearData('user_group', 1);
+        self::clearData('user_spread', 1);
+        self::clearData('user_visit', 1);
+        self::clearData('enterprise_user', 1);
+        self::clearData('interest_user', 1);
+        SystemAdmin::where('id','>',2)->delete();
+        $this->delDirAndFile('./public/uploads/store/comment');
+//        self::clearData('store_product_relation', 1);
+        return Json::successful('清除数据成功!');
+    }
+
+    //清除商城数据
+    public function storeData()
+    {
+        self::clearData('store_coupon', 1);
+        self::clearData('store_coupon_issue', 1);
+        self::clearData('store_bargain', 1);
+        self::clearData('store_combination', 1);
+        self::clearData('store_product_attr', 1);
+        self::clearData('store_product_attr_result', 1);
+        self::clearData('store_product_attr_value', 1);
+        self::clearData('store_product_description', 1);
+        self::clearData('store_product_reply', 1);
+        self::clearData('store_seckill', 1);
+        self::clearData('store_product', 1);
+        self::clearData('store_visit', 1);
+        return Json::successful('清除数据成功!');
+    }
+
+    //清除产品分类
+    public function categoryData()
+    {
+        self::clearData('store_category', 1);
+        self::clearData('store_product_cate', 1);
+        return Json::successful('清除数据成功!');
+    }
+
+    //清除订单数据
+    public function orderData()
+    {
+        self::clearData('store_order', 1);
+        self::clearData('store_order_cart_info', 1);
+        self::clearData('store_order_status', 1);
+        self::clearData('store_pink', 1);
+        self::clearData('store_cart', 1);
+        self::clearData('store_order_status', 1);
+        return Json::successful('清除数据成功!');
+    }
+
+    //清除客服数据
+    public function kefuData()
+    {
+        self::clearData('store_service', 1);
+        $this->delDirAndFile('./public/uploads/store/service');
+        self::clearData('store_service_log', 1);
+        return Json::successful('清除数据成功!');
+    }
+
+    //清除微信管理数据
+    public function wechatData()
+    {
+        self::clearData('wechat_media', 1);
+        self::clearData('wechat_reply', 1);
+        self::clearData('cache', 1);
+        $this->delDirAndFile('./public/uploads/wechat');
+        return Json::successful('清除数据成功!');
+    }
+
+    //清除所有附件
+    public function uploadData()
+    {
+        self::clearData('system_attachment', 1);
+        self::clearData('system_attachment_category', 1);
+        $this->delDirAndFile('./public/uploads/');
+        return Json::successful('清除上传文件成功!');
+    }
+
+    //清除微信用户
+    public function wechatuserData()
+    {
+        self::clearData('wechat_user', 1);
+        self::clearData('user', 1);
+        return Json::successful('清除数据成功!');
+    }
+
+    //清除内容分类
+    public function articledata()
+    {
+        self::clearData('article_category', 1);
+        self::clearData('article', 1);
+        self::clearData('article_content', 1);
+        self::clearData('article_good', 1);
+        self::clearData('article_reply', 1);
+        return Json::successful('清除数据成功!');
+    }
+
+    //清除系统记录
+    public function systemdata()
+    {
+        self::clearData('system_notice_admin', 1);
+        self::clearData('system_log', 1);
+        return Json::successful('清除数据成功!');
+    }
+
+    /**
+     * 清除数据
+     * @param int $type
+     * @throws \Exception
+     */
+    public function undata($type = 1)
+    {
+        switch ((int)$type) {
+            case 1:
+                $fileImage = \app\admin\model\system\SystemAttachment::where('module_type', 2)->field(['att_dir', 'satt_dir'])->select();
+                foreach ($fileImage as $image) {
+                    if ($image['att_dir'] && ($imagePath = strstr($image['att_dir'], 'uploads')) !== false) {
+                        if (is_file($imagePath))
+                            unlink($imagePath);
+                        unset($imagePath);
+                    }
+
+                    if ($image['satt_dir'] && ($imagePath = strstr($image['satt_dir'], 'uploads')) !== false) {
+                        if (is_file($imagePath))
+                            unlink($imagePath);
+                        unset($imagePath);
+                    }
+                }
+                \app\admin\model\system\SystemAttachment::where('module_type', 2)->delete();
+                @unlink('uploads/follow/follow.jpg');//删除海报二维码
+                break;
+            case 2:
+                StoreProduct::where('is_del', 1)->delete();
+                break;
+            case 3:
+                $value = $this->request->param('value');
+                if (!$value)
+                    return Json::fail('请输入需要更换的域名');
+                if (!verify_domain($value))
+                    return Json::fail('域名不合法');
+                $siteUrl = SystemConfigService::get('site_url', true);
+                $siteUrlJosn = str_replace('http://', 'http:\\/\\/', $siteUrl);
+                $valueJosn = str_replace('http://', 'http:\\/\\/', $value);
+                $prefix = Config::get('database.connections.' . Config::get('database.default') . '.prefix');
+                $sql = [
+                    "UPDATE `{$prefix}system_attachment` SET `att_dir` = replace(att_dir ,'{$siteUrl}','{$value}'),`satt_dir` = replace(satt_dir ,'{$siteUrl}','{$value}')",
+                    "UPDATE `{$prefix}store_product` SET `image` = replace(image ,'{$siteUrl}','{$value}'),`slider_image` = replace(slider_image ,'{$siteUrl}','{$value}')",
+                    "UPDATE `{$prefix}store_product_attr_value` SET `image` = replace(image ,'{$siteUrl}','{$value}')",
+                    "UPDATE `{$prefix}store_seckill` SET `image` = replace(image ,'{$siteUrl}','{$value}'),`images` = replace(images,'{$siteUrl}','{$value}')",
+                    "UPDATE `{$prefix}store_combination` SET `image` = replace(image ,'{$siteUrl}','{$value}'),`images` = replace(images,'{$siteUrl}','{$value}')",
+                    "UPDATE `{$prefix}store_bargain` SET `image` = replace(image ,'{$siteUrl}','{$value}'),`images` = replace(images,'{$siteUrl}','{$value}')",
+                    "UPDATE `{$prefix}system_config` SET `value` = replace(value ,'{$siteUrlJosn}','{$valueJosn}')",
+                    "UPDATE `{$prefix}article_category` SET `image` = replace(`image` ,'{$siteUrl}','{$value}')",
+                    "UPDATE `{$prefix}article` SET `image_input` = replace(`image_input` ,'{$siteUrl}','{$value}')",
+                    "UPDATE `{$prefix}article_content` SET `content` = replace(`content` ,'{$siteUrl}','{$value}')",
+                    "UPDATE `{$prefix}store_category` SET `pic` = replace(`pic` ,'{$siteUrl}','{$value}')",
+                    "UPDATE `{$prefix}system_group_data` SET `value` = replace(value ,'{$siteUrlJosn}','{$valueJosn}')",
+                    "UPDATE `{$prefix}store_product_description` SET `description`= replace(description,'{$siteUrl}','{$value}')"
+                ];
+                try {
+                    foreach ($sql as $item) {
+                        db::execute($item);
+                    }
+                } catch (\Throwable $e) {
+                    return Json::fail('替换失败,失败原因:' . $e->getMessage());
+                }
+                return Json::success('替换成功!');
+                break;
+        }
+        return Json::successful('清除数据成功!');
+    }
+
+    //清除制定表数据
+    public function clearData($table_name, $status)
+    {
+        $table_name = config('database.connections.' . config('database.default'))['prefix'] . $table_name;
+        if ($status) {
+            @db::execute('TRUNCATE TABLE ' . $table_name);
+        } else {
+            @db::execute('DELETE FROM' . $table_name);
+        }
+
+    }
+
+    //递归删除文件
+    function delDirAndFile($dirName, $subdir = true)
+    {
+        if ($handle = @opendir("$dirName")) {
+            while (false !== ($item = readdir($handle))) {
+                if ($item != "." && $item != "..") {
+                    if (is_dir("$dirName/$item"))
+                        $this->delDirAndFile("$dirName/$item", false);
+                    else
+                        @unlink("$dirName/$item");
+                }
+            }
+            closedir($handle);
+            if (!$subdir) @rmdir($dirName);
+        }
+    }
+}

+ 245 - 0
app/admin/controller/system/SystemDatabackup.php

@@ -0,0 +1,245 @@
+<?php
+
+namespace app\admin\controller\system;
+
+use app\admin\controller\AuthController;
+use crmeb\services\JsonService as Json;
+use \crmeb\services\MysqlBackupService as Backup;
+use think\facade\Config;
+use think\facade\Session;
+use think\facade\Db;
+
+/**
+ * 文件校验控制器
+ * Class SystemDatabackup
+ * @package app\admin\controller\system
+ *
+ */
+class SystemDatabackup extends AuthController
+{
+    /**
+     * @var Backup
+     */
+    protected $DB;
+
+    public function initialize()
+    {
+        parent::initialize();
+        $config = array(
+            //数据库备份卷大小
+            'compress' => 1,
+            //数据库备份文件是否启用压缩 0不压缩 1 压缩
+            'level' => 5,
+        );
+        $this->DB = new Backup($config);
+    }
+
+    /**
+     * 数据类表列表
+     */
+    public function index()
+    {
+        return $this->fetch();
+    }
+
+    /**
+     * 获取数据库表
+     */
+    public function tablelist()
+    {
+        $db = $this->DB;
+        return Json::result(0, 'sucess', $db->dataList(), count($db->dataList()));
+    }
+
+    /**
+     * 查看表结构
+     */
+    public function seetable()
+    {
+        request()->filter(['strip_tags', 'trim', 'htmlspecialchars']);
+        $database = Config::get("database.connections." . Config::get('database.default') . '.database');
+        $tablename = request()->param('tablename');
+        $res = Db::query("select * from information_schema.columns where table_name = '" . $tablename . "' and table_schema = '" . $database . "'");
+        $html = '';
+        $html .= '<table border="1" cellspacing="0" cellpadding="0" align="center">';
+        $html .= '<tbody><tr><th>字段名</th><th>数据类型</th><th>默认值</th><th>允许非空</th><th>自动递增</th><th>备注</th></tr>';
+        $html .= '';
+        foreach ($res AS $f) {
+            $html .= '<td class="c1">' . $f['COLUMN_NAME'] . '</td>';
+            $html .= '<td class="c2">' . $f['COLUMN_TYPE'] . '</td>';
+            $html .= '<td class="c3">' . $f['COLUMN_DEFAULT'] . '</td>';
+            $html .= '<td class="c4">' . $f['IS_NULLABLE'] . '</td>';
+            $html .= '<td class="c5">' . ($f['EXTRA'] == 'auto_increment' ? '是' : ' ') . '</td>';
+            $html .= '<td class="c6">' . $f['COLUMN_COMMENT'] . '</td>';
+            $html .= '</tr>';
+        }
+        $html .= '</tbody></table></p>';
+        $html .= '<p style="text-align:left;margin:20px auto;">总共:' . count($res) . '个字段</p>';
+        $html .= '</body></html>';
+        echo '<style>
+                body,td,th {font-family:"宋体"; font-size:12px;}
+                table,h1,p{width:960px;margin:0px auto;}
+                table{border-collapse:collapse;border:1px solid #CCC;background:#efefef;}
+                table caption{text-align:left; background-color:#fff; line-height:2em; font-size:14px; font-weight:bold; }
+                table th{text-align:left; font-weight:bold;height:26px; line-height:26px; font-size:12px; border:1px solid #CCC;padding-left:5px;}
+                table td{height:20px; font-size:12px; border:1px solid #CCC;background-color:#fff;padding-left:5px;}
+                .c1{ width: 150px;}
+                .c2{ width: 150px;}
+                .c3{ width: 80px;}
+                .c4{ width: 100px;}
+                .c5{ width: 100px;}
+                .c6{ width: 300px;}
+            </style>';
+        echo $html;
+    }
+
+    /**
+     * 优化表
+     */
+    public function optimize()
+    {
+        $tables = request()->post('tables/a');
+        $db = $this->DB;
+        try {
+            $db->optimize($tables);
+            return Json::successful('优化成功');
+        } catch (\Exception $e) {
+            return Json::fail($e->getMessage());
+        }
+    }
+
+    /**
+     * 修复表
+     */
+    public function repair()
+    {
+        $tables = request()->post('tables/a');
+        $db = $this->DB;
+        try {
+            $db->repair($tables);
+            return Json::successful('修复成功');
+        } catch (\Exception $e) {
+            return Json::fail($e->getMessage());
+        }
+    }
+
+    /**
+     * 备份表
+     */
+    public function backup()
+    {
+        $tables = request()->post('tables/a');
+        $db = $this->DB;
+        $data = '';
+        foreach ($tables as $t) {
+            $res = $db->backup($t, 0);
+            if ($res == false && $res != 0) {
+                $data .= $t . '|';
+            }
+        }
+        return Json::successful($data ? '备份失败' . $data : '备份成功');
+    }
+
+    /**
+     * 获取备份记录表
+     */
+    public function fileList()
+    {
+        $db = $this->DB;
+        $files = $db->fileList();
+        $data = [];
+        foreach ($files as $key => $t) {
+            $data[$key]['filename'] = $t['filename'];
+            $data[$key]['part'] = $t['part'];
+            $data[$key]['size'] = $t['size'] . 'B';
+            $data[$key]['compress'] = $t['compress'];
+            $data[$key]['backtime'] = $key;
+            $data[$key]['time'] = $t['time'];
+        }
+        krsort($data);//根据时间降序
+        return Json::result(0, 'sucess', $data, count($data));
+    }
+
+    /**
+     * @param string|null $msg
+     * @param string|null $url
+     * @param array|null $data
+     */
+    public function success(?string $msg = null, ?string $url = null, ?array $data = [])
+    {
+        return Json::success($msg, $data);
+    }
+
+    /**
+     * @param string|null $msg
+     */
+    public function error(?string $msg = null)
+    {
+        return Json::fail($msg);
+    }
+
+    /**
+     * 删除备份记录表
+     */
+    public function delFile()
+    {
+        $feilname = intval(request()->post('feilname'));
+        $files = $this->DB->delFile($feilname);
+        return Json::result(0, 'sucess');
+    }
+
+    /**
+     * 导入备份记录表
+     */
+    public function import()
+    {
+        $part = request()->post('part') != '' ? intval(request()->post('part')) : null;
+        $start = request()->post('start') != '' ? intval(request()->post('start')) : null;
+        $time = intval(request()->post('time'));
+        $db = $this->DB;
+        if (is_numeric($time) && is_null($part) && is_null($start)) {
+            $list = $db->getFile('timeverif', $time);
+            if (is_array($list)) {
+                session::set('backup_list', $list);
+                $this->success('初始化完成!', '', array('part' => 1, 'start' => 0));
+            } else {
+                $this->error('备份文件可能已经损坏,请检查!');
+            }
+        } else if (is_numeric($part) && is_numeric($start)) {
+            $list = session::get('backup_list');
+            $start = $db->setFile($list)->import($start);
+            if (false === $start) {
+                $this->error('还原数据出错!');
+            } elseif (0 === $start) {
+                if (isset($list[++$part])) {
+                    $data = array('part' => $part, 'start' => 0);
+                    $this->success("正在还原...#{$part}", '', $data);
+                } else {
+                    session::delete('backup_list');
+                    $this->success('还原完成!');
+                }
+            } else {
+                $data = array('part' => $part, 'start' => $start[0]);
+                if ($start[1]) {
+                    $rate = floor(100 * ($start[0] / $start[1]));
+                    $this->success("正在还原...#{$part}({$rate}%)", '', $data);
+                } else {
+                    $data['gz'] = 1;
+                    $this->success("正在还原...#{$part}", '', $data);
+                }
+                $this->success("正在还原...#{$part}", '');
+            }
+        } else {
+            $this->error('参数错误!');
+        }
+    }
+
+    /**
+     * 下载备份记录表
+     */
+    public function downloadFile()
+    {
+        $time = intval(request()->param('feilname'));
+        $this->DB->downloadFile($time);
+    }
+}

+ 303 - 0
app/admin/controller/system/SystemFile.php

@@ -0,0 +1,303 @@
+<?php
+
+namespace app\admin\controller\system;
+
+use app\admin\model\system\SystemFile as SystemFileModel;
+use app\admin\controller\AuthController;
+use crmeb\services\FormBuilder as Form;
+use crmeb\services\FileService as FileClass;
+use crmeb\services\JsonService as Json;
+
+/**
+ * 文件校验控制器
+ * Class SystemFile
+ * @package app\admin\controller\system
+ *
+ */
+class SystemFile extends AuthController
+{
+    //打开目录
+    public function opendir($filedir = '')
+    {
+        $fileAll = array('dir' => [], 'file' => []);
+        //根目录
+        $rootdir = app()->getRootPath();
+        //当前目录
+        $request_dir = app('request')->param('dir');
+        //防止查看站点以外的目录
+        if (strpos($request_dir, $rootdir) === false) {
+            $request_dir = $rootdir;
+        }
+        //判断是否是返回上级
+        if (app('request')->param('superior') && !empty($request_dir)) {
+            if (strpos(dirname($request_dir), $rootdir) !== false) {
+                $dir = dirname($request_dir);
+            } else {
+                $dir = $rootdir;
+            }
+
+        } else {
+            $dir = !empty($request_dir) ? $request_dir : $rootdir;
+            $dir = rtrim($dir, DS) . DS . app('request')->param('filedir');
+        }
+        $list = scandir($dir);
+        foreach ($list as $key => $v) {
+            if ($v != '.' && $v != '..') {
+                if (is_dir($dir . DS . $v)) {
+                    $fileAll['dir'][] = FileClass::list_info($dir . DS . $v);
+                }
+                if (is_file($dir . DS . $v)) {
+                    $fileAll['file'][] = FileClass::list_info($dir . DS . $v);
+                }
+            }
+        }
+        //兼容windows
+        $uname = php_uname('s');
+        if (strstr($uname, 'Windows') !== false) $dir = ltrim($dir, '\\');
+        $this->assign(compact('fileAll', 'dir'));
+        return $this->fetch();
+    }
+
+    //读取文件
+    public function openfile($file = '')
+    {
+        $file = $this->request->param('file');
+        if (empty($file)) return Json::fail('出现错误');
+        $filepath = $file;
+        $content = FileClass::read_file($filepath);//防止页面内嵌textarea标签
+        $ext = FileClass::get_ext($filepath);
+        $extarray = [
+            'js' => 'text/javascript'
+            , 'php' => 'text/x-php'
+            , 'html' => 'text/html'
+            , 'sql' => 'text/x-mysql'
+            , 'css' => 'text/x-scss'];
+        $mode = empty($extarray[$ext]) ? '' : $extarray[$ext];
+        $this->assign(compact('content', 'mode', 'filepath'));
+        return $this->fetch();
+    }
+
+    //保存文件
+    public function savefile()
+    {
+        $comment = $this->request->post('comment');
+        $filepath = $this->request->post('filepath');
+        if (!empty($comment) && !empty($filepath)) {
+            //兼容windows
+            $uname = php_uname('s');
+            if (strstr($uname, 'Windows') !== false)
+                $filepath = ltrim(str_replace('/', DS, $filepath), '.');
+            if (FileClass::isWritable($filepath)) {
+                $res = FileClass::write_file($filepath, $comment);
+                if ($res) {
+                    return Json::successful('保存成功!');
+                } else {
+                    return Json::fail('保存失败');
+                }
+            } else {
+                return Json::fail('没有权限!');
+            }
+
+        } else {
+            return Json::fail('出现错误');
+        }
+
+    }
+
+    public function index()
+    {
+        $rootPath = app()->getRootPath();
+        $app = $this->getDir($rootPath . 'app');
+        $extend = $this->getDir($rootPath . 'crmeb');
+        $arr = [];
+        $arr = array_merge($app, $extend);
+        $fileAll = [];//本地文件
+        $cha = [];//不同的文件
+        foreach ($arr as $k => $v) {
+            $fp = fopen($v, 'r');
+            if (filesize($v)) $ct = fread($fp, filesize($v));
+            else $ct = null;
+            fclose($fp);
+            $cthash = md5($ct);
+            $update_time = stat($v);
+            $fileAll[$k]['cthash'] = $cthash;
+            $fileAll[$k]['filename'] = str_replace($rootPath, '', $v);
+            $fileAll[$k]['atime'] = $update_time['atime'];
+            $fileAll[$k]['mtime'] = $update_time['mtime'];
+            $fileAll[$k]['ctime'] = $update_time['ctime'];
+        }
+        $file = SystemFileModel::all(function ($query) {
+            $query->order('atime', 'desc');
+        })->toArray();//数据库中的文件
+        if (empty($file)) {
+            $data_num = array_chunk($fileAll, 10);
+            SystemFileModel::beginTrans();
+            $res = true;
+            foreach ($data_num as $k => $v) {
+                $res = $res && SystemFileModel::insertAll($v);
+            }
+            SystemFileModel::checkTrans($res);
+            if ($res) {
+                $cha = [];//不同的文件
+            } else {
+                $cha = $fileAll;
+            }
+        } else {
+            $cha = [];//差异文件
+            foreach ($file as $k => $v) {
+                foreach ($fileAll as $ko => $vo) {
+                    if ($v['filename'] == $vo['filename']) {
+                        if ($v['cthash'] != $vo['cthash']) {
+                            $cha[$k]['filename'] = str_replace($rootPath, '', $v['filename']);
+                            $cha[$k]['cthash'] = $v['cthash'];
+                            $cha[$k]['atime'] = $v['atime'];
+                            $cha[$k]['mtime'] = $v['mtime'];
+                            $cha[$k]['ctime'] = $v['ctime'];
+                            $cha[$k]['type'] = '已修改';
+                        }
+                        unset($fileAll[$ko]);
+                        unset($file[$k]);
+                    }
+                }
+
+            }
+            foreach ($file as $k => $v) {
+                $cha[$k]['filename'] = str_replace($rootPath, '', $v['filename']);
+                $cha[$k]['cthash'] = $v['cthash'];
+                $cha[$k]['atime'] = $v['atime'];
+                $cha[$k]['mtime'] = $v['mtime'];
+                $cha[$k]['ctime'] = $v['ctime'];
+                $cha[$k]['type'] = '已删除';
+            }
+            foreach ($fileAll as $k => $v) {
+                $cha[$k]['filename'] = str_replace($rootPath, '', $v['filename']);
+                $cha[$k]['cthash'] = $v['cthash'];
+                $cha[$k]['atime'] = $v['atime'];
+                $cha[$k]['mtime'] = $v['mtime'];
+                $cha[$k]['ctime'] = $v['ctime'];
+                $cha[$k]['type'] = '新增的';
+            }
+
+        }
+//   dump($file);
+//   dump($fileAll);
+        $this->assign('cha', $cha);
+        return $this->fetch();
+    }
+
+
+    /**
+     * 获取文件夹中的文件 不包括子文件
+     * @param $dir
+     * @return array
+     */
+    public function getNextDir()
+    {
+        $dir = './';
+        $list = scandir($dir);
+        $dirlist = [];
+        $filelist = [];
+        foreach ($list as $key => $v) {
+            if ($v != '.' && $v != '..') {
+                if (is_dir($dir . '/' . $v)) {
+                    $dirlist['dir'][$key] = $v;
+                }
+                if (is_file($dir . '/' . $v)) {
+                    $filelist['file'][$key] = $v;
+                }
+            }
+        }
+        $filesarr = array_merge($dirlist, $filelist);
+        print_r($filesarr);
+    }
+
+    /**
+     * 获取文件夹中的文件 包括子文件 不能直接用  直接使用  $this->getDir()方法 P156
+     * @param $path
+     * @param $data
+     */
+    public function searchDir($path, &$data)
+    {
+        if (is_dir($path) && !strpos($path, 'uploads')) {
+            $dp = dir($path);
+            while ($file = $dp->read()) {
+                if ($file != '.' && $file != '..') {
+                    $this->searchDir($path . '/' . $file, $data);
+                }
+            }
+            $dp->close();
+        }
+        if (is_file($path)) {
+            $data[] = $path;
+        }
+    }
+
+    /**
+     * 获取文件夹中的文件 包括子文件
+     * @param $dir
+     * @return array
+     */
+    public function getDir($dir)
+    {
+        $data = [];
+        $this->searchDir($dir, $data);
+        return $data;
+    }
+
+    //测试
+    public function ceshi()
+    {
+        //创建form
+        $form = Form::create('/save.php', [
+            Form::input('goods_name', '商品名称')
+            , Form::input('goods_name1', 'password')->type('password')
+            , Form::input('goods_name2', 'textarea')->type('textarea')
+            , Form::input('goods_name3', 'email')->type('email')
+            , Form::input('goods_name4', 'date')->type('date')
+            , Form::city('address', 'cityArea',
+                '陕西省', '西安市'
+            )
+            , Form::dateRange('limit_time', 'dateRange',
+                strtotime('- 10 day'),
+                time()
+            )
+            , Form::dateTime('add_time', 'dateTime')
+            , Form::color('color', 'color', '#ff0000')
+            , Form::checkbox('checkbox', 'checkbox', [1])->options([['value' => 1, 'label' => '白色'], ['value' => 2, 'label' => '红色'], ['value' => 31, 'label' => '黑色']])
+            , Form::date('riqi', 'date', '2018-03-1')
+            , Form::dateTimeRange('dateTimeRange', '区间时间段')
+            , Form::year('year', 'year')
+            , Form::month('month', 'month')
+            , Form::frame('frame', 'frame', '/admin/system.system_attachment/index.html?fodder=frame')
+            , Form::frameInputs('frameInputs', 'frameInputs', '/admin/system.system_attachment/index.html?fodder=frameInputs')
+            , Form::frameFiles('month1', 'frameFiles', '/admin/system.system_attachment/index.html?fodder=month1')
+            , Form::frameImages('fodder1', 'frameImages', '/admin/system.system_attachment/index.html?fodder=fodder1')->maxLength(3)->width('800px')->height('400px')
+            , Form::frameImages('fodder11', 'frameImages', '/admin/system.system_attachment/index.html?fodder=fodder11')->icon('images')
+            , Form::frameInputOne('month3', 'frameInputOne', '/admin/system.system_attachment/index.html?fodder=month3')->icon('ionic')
+            , Form::frameFileOne('month4', 'frameFileOne', '/admin/system.system_attachment/index.html?fodder=month4')
+            , Form::frameImageOne('month5', 'frameImageOne', '/admin/system.system_attachment/index.html?fodder=month5')->icon('image')
+            , Form::hidden('month6', 'hidden')
+            , Form::number('month7', 'number')
+//            ,Form::input input输入框,其他type: text类型Form::text,password类型Form::password,textarea类型Form::textarea,url类型Form::url,email类型Form::email,date类型Form::idate
+            , Form::radio('month8', 'radio')->options([['value' => 1, 'label' => '白色'], ['value' => 2, 'label' => '红色'], ['value' => 31, 'label' => '黑色']])
+            , Form::rate('month9', 'rate')
+            , Form::select('month10', 'select')->options([['value' => 1, 'label' => '白色'], ['value' => 2, 'label' => '红色'], ['value' => 31, 'label' => '黑色']])
+            , Form::selectMultiple('month11', 'selectMultiple')
+            , Form::selectOne('month12', 'selectOne')
+            , Form::slider('month13', 'slider', 2)
+            , Form::sliderRange('month23', 'sliderRange', 2, 13)
+            , Form::switches('month14', '区间时间段')
+            , Form::timePicker('month15', '区间时间段')
+            , Form::time('month16', '区间时间段')
+            , Form::timeRange('month17', '区间时间段')
+//            ,Form::upload('month','区间时间段')
+//            ,Form::uploadImages('month','区间时间段')
+//            ,Form::uploadFiles('month','区间时间段')
+//            ,Form::uploadImageOne('month','区间时间段')
+//            ,Form::uploadFileOne('month','区间时间段')
+
+        ]);
+        $html = $form->setMethod('get')->setTitle('编辑商品')->view();
+        echo $html;
+    }
+}

+ 39 - 0
app/admin/controller/system/SystemLog.php

@@ -0,0 +1,39 @@
+<?php
+
+namespace app\admin\controller\system;
+
+use app\admin\controller\AuthController;
+use app\admin\model\system\SystemAdmin;
+use app\admin\model\system\SystemLog as LogModel;
+use crmeb\services\UtilService as Util;
+
+/**
+ * 管理员操作记录表控制器
+ * Class SystemLog
+ * @package app\admin\controller\system
+ */
+class SystemLog extends AuthController
+{
+    /**
+     * 显示操作记录
+     */
+    public function index()
+    {
+        LogModel::deleteLog();
+        $where = Util::getMore([
+            ['pages', ''],
+            ['path', ''],
+            ['ip', ''],
+            ['admin_id', ''],
+            ['data', ''],
+        ], $this->request);
+        $where['level'] = $this->adminInfo['level'];
+        $this->assign('where', $where);
+        $this->assign('admin', SystemAdmin::getOrdAdmin('id,real_name', $this->adminInfo['level']));
+        $this->assign(LogModel::systemPage($where));
+        return $this->fetch();
+    }
+
+
+}
+

+ 626 - 0
app/admin/controller/user/User.php

@@ -0,0 +1,626 @@
+<?php
+/**
+ *
+ * @author: xaboy<365615158@qq.com>
+ * @day: 2017/11/11
+ */
+
+namespace app\admin\controller\user;
+
+use app\admin\controller\AuthController;
+use crmeb\repositories\UserRepository;
+use crmeb\traits\CurdControllerTrait;
+use think\facade\Route as Url;
+use crmeb\basic\BaseModel;
+use app\admin\model\wechat\WechatMessage;
+use crmeb\services\{FormBuilder as Form, UtilService as Util, JsonService as Json};
+use app\admin\model\user\{User as UserModel, UserBill as UserBillAdmin, UserGroup};
+
+/**
+ * 用户管理控制器
+ * Class User
+ * @package app\admin\controller\user
+ */
+class User extends AuthController
+{
+    use CurdControllerTrait;
+
+    /**
+     * 显示资源列表
+     *
+     * @return \think\Response
+     */
+    public function index()
+    {
+        $group = UserGroup::select();
+        $this->assign(compact('group'));
+        $this->assign('count_user', UserModel::getcount());
+        return $this->fetch();
+    }
+
+    /**
+     * 设置分组
+     * @param int $uid
+     */
+    public function set_group($uid = 0)
+    {
+        if (!$uid) return $this->failed('缺少参数');
+        $userGroup = UserGroup::select();
+        $field[] = Form::select('group_id', '会员分组')->setOptions(function () use ($userGroup) {
+            $menus = [];
+            foreach ($userGroup as $menu) {
+                $menus[] = ['value' => $menu['id'], 'label' => $menu['group_name']];
+            }
+            return $menus;
+        })->filterable(1);
+        $form = Form::make_post_form('设置分组', $field, Url::buildUrl('save_set_group', ['uid' => $uid]), 2);
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    public function save_set_group($uid = 0)
+    {
+        if (!$uid) return Json::fail('缺少参数');
+        list($group_id) = Util::postMore([
+            ['group_id', 0],
+        ], $this->request, true);
+        $uids = explode(',', $uid);
+        $res = UserModel::whereIn('uid', $uids)->update(['group_id' => $group_id]);
+        if ($res) {
+            return Json::successful('设置成功');
+        } else {
+            return Json::successful('设置失败');
+        }
+    }
+
+
+    public function edit_other($uid)
+    {
+        if (!$uid) return $this->failed('数据不存在');
+        $user = UserModel::get($uid);
+        if (!$user) return Json::fail('数据不存在!');
+        $f = array();
+        $f[] = Form::radio('money_status', '修改余额', 1)->options([['value' => 1, 'label' => '增加'], ['value' => 2, 'label' => '减少']]);
+        $f[] = Form::number('money', '余额')->min(0);
+        $f[] = Form::radio('integration_status', '修改积分', 1)->options([['value' => 1, 'label' => '增加'], ['value' => 2, 'label' => '减少']]);
+        $f[] = Form::number('integration', '积分')->min(0);
+        $form = Form::make_post_form('修改其他', $f, Url::buildUrl('update_other', array('uid' => $uid)));
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    public function update_other($uid = 0)
+    {
+        $data = Util::postMore([
+            ['money_status', 0],
+            ['money', 0],
+            ['integration_status', 0],
+            ['integration', 0],
+        ], $this->request);
+        if (!$uid) return $this->failed('数据不存在');
+        $user = UserModel::get($uid);
+        if (!$user) return Json::fail('数据不存在!');
+        BaseModel::beginTrans();
+        $res1 = false;
+        $res2 = false;
+        $edit = array();
+        if ($data['money_status'] && $data['money']) {//余额增加或者减少
+            if ($data['money_status'] == 1) {//增加
+                $edit['now_money'] = bcadd($user['now_money'], $data['money'], 2);
+                $res1 = UserBillAdmin::income('系统增加余额', $user['uid'], 'now_money', 'system_add', $data['money'], $this->adminId, $edit['now_money'], '系统增加了' . floatval($data['money']) . '余额');
+                try {
+                    UserRepository::adminAddMoney($user, $data['money']);
+                } catch (\Exception $e) {
+                    BaseModel::rollbackTrans();
+                    return Json::fail($e->getMessage());
+                }
+            } else if ($data['money_status'] == 2) {//减少
+                $edit['now_money'] = bcsub($user['now_money'], $data['money'], 2);
+                $res1 = UserBillAdmin::expend('系统减少余额', $user['uid'], 'now_money', 'system_sub', $data['money'], $this->adminId, $edit['now_money'], '系统扣除了' . floatval($data['money']) . '余额');
+                try {
+                    UserRepository::adminSubMoney($user, $data['money']);
+                } catch (\Exception $e) {
+                    BaseModel::rollbackTrans();
+                    return Json::fail($e->getMessage());
+                }
+            }
+        } else {
+            $res1 = true;
+        }
+        if ($data['integration_status'] && $data['integration']) {//积分增加或者减少
+            if ($data['integration_status'] == 1) {//增加
+                $edit['integral'] = bcadd($user['integral'], $data['integration'], 2);
+                $res2 = UserBillAdmin::income('系统增加积分', $user['uid'], 'integral', 'system_add', $data['integration'], $this->adminId, $edit['integral'], '系统增加了' . floatval($data['integration']) . '积分');
+                try {
+                    UserRepository::adminAddIntegral($user, $data['integration']);
+                } catch (\Exception $e) {
+                    BaseModel::rollbackTrans();
+                    return Json::fail($e->getMessage());
+                }
+            } else if ($data['integration_status'] == 2) {//减少
+                $edit['integral'] = bcsub($user['integral'], $data['integration'], 2);
+                $res2 = UserBillAdmin::expend('系统减少积分', $user['uid'], 'integral', 'system_sub', $data['integration'], $this->adminId, $edit['integral'], '系统扣除了' . floatval($data['integration']) . '积分');
+                try {
+                    UserRepository::adminSubIntegral($user, $data['integration']);
+                } catch (\Exception $e) {
+                    BaseModel::rollbackTrans();
+                    return Json::fail($e->getMessage());
+                }
+            }
+        } else {
+            $res2 = true;
+        }
+        if ($edit) $res3 = UserModel::edit($edit, $uid);
+        else $res3 = true;
+        if ($res1 && $res2 && $res3) $res = true;
+        else $res = false;
+        BaseModel::checkTrans($res);
+        if ($res) return Json::successful('修改成功!');
+        else return Json::fail('修改失败');
+    }
+
+    /**
+     * 修改user表状态
+     *
+     * @return json
+     */
+    public function set_status($status = '', $uid = 0, $is_echo = 0)
+    {
+        if ($is_echo == 0) {
+            if ($status == '' || $uid == 0) return Json::fail('参数错误');
+            UserModel::where(['uid' => $uid])->update(['status' => $status]);
+        } else {
+            $uids = Util::postMore([
+                ['uids', []]
+            ]);
+            UserModel::destrSyatus($uids['uids'], $status);
+        }
+        return Json::successful($status == 0 ? '禁用成功' : '解禁成功');
+    }
+
+    /**
+     * 获取user表
+     *
+     * @return json
+     */
+    public function get_user_list()
+    {
+        $where = Util::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['nickname', ''],
+            ['status', ''],
+            ['pay_count', ''],
+            ['is_promoter', ''],
+            ['order', ''],
+            ['data', ''],
+            ['user_type', ''],
+            ['country', ''],
+            ['province', ''],
+            ['city', ''],
+            ['user_time_type', ''],
+            ['user_time', ''],
+            ['sex', ''],
+            ['level', ''],
+            ['group_id', ''],
+        ]);
+        return Json::successlayui(UserModel::getUserList($where));
+    }
+
+    /**
+     * 编辑模板消息
+     * @param $id
+     * @return mixed|\think\response\Json|void
+     */
+    public function edit($uid)
+    {
+        if (!$uid) return $this->failed('数据不存在');
+        $user = UserModel::get($uid);
+        if (!$user) return Json::fail('数据不存在!');
+        $f = array();
+        $f[] = Form::input('uid', '用户编号', $user->getData('uid'))->disabled(1);
+        $f[] = Form::input('real_name', '真实姓名', $user->getData('real_name'));
+        $f[] = Form::text('phone', '手机号', $user->getData('phone'));
+        $f[] = Form::date('birthday', '生日', $user->getData('birthday') ? date('Y-m-d', $user->getData('birthday')) : 0);
+        $f[] = Form::input('card_id', '身份证号', $user->getData('card_id'));
+        $f[] = Form::textarea('mark', '用户备注', $user->getData('mark'));
+//        $f[] = Form::radio('is_promoter', '推广员', $user->getData('is_promoter'))->options([['value' => 1, 'label' => '开启'], ['value' => 0, 'label' => '关闭']]);
+        $f[] = Form::radio('status', '状态', $user->getData('status'))->options([['value' => 1, 'label' => '开启'], ['value' => 0, 'label' => '锁定']]);
+        $form = Form::make_post_form('添加用户通知', $f, Url::buildUrl('update', array('uid' => $uid)), 5);
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    public function update($uid)
+    {
+        $data = Util::postMore([
+            ['money_status', 0],
+            ['is_promoter', 1],
+            ['real_name', ''],
+            ['phone', 0],
+            ['card_id', ''],
+            ['birthday', ''],
+            ['mark', ''],
+            ['money', 0],
+            ['integration_status', 0],
+            ['integration', 0],
+            ['status', 0],
+        ]);
+        if (!$uid) return $this->failed('数据不存在');
+        $user = UserModel::get($uid);
+        if (!$user) return Json::fail('数据不存在!');
+        BaseModel::beginTrans();
+        $res1 = false;
+        $res2 = false;
+        $edit = array();
+        if ($data['money_status'] && $data['money']) {//余额增加或者减少
+            if ($data['money_status'] == 1) {//增加
+                $edit['now_money'] = bcadd($user['now_money'], $data['money'], 2);
+                $res1 = UserBillAdmin::income('系统增加余额', $user['uid'], 'now_money', 'system_add', $data['money'], $this->adminId, $edit['now_money'], '系统增加了' . floatval($data['money']) . '余额');
+                try {
+                    UserRepository::adminAddMoney($user, $data['money']);
+                } catch (\Exception $e) {
+                    BaseModel::rollbackTrans();
+                    return Json::fail($e->getMessage());
+                }
+            } else if ($data['money_status'] == 2) {//减少
+                $edit['now_money'] = bcsub($user['now_money'], $data['money'], 2);
+                $res1 = UserBillAdmin::expend('系统减少余额', $user['uid'], 'now_money', 'system_sub', $data['money'], $this->adminId, $edit['now_money'], '系统扣除了' . floatval($data['money']) . '余额');
+                try {
+                    UserRepository::adminSubMoney($user, $data['money']);
+                } catch (\Exception $e) {
+                    BaseModel::rollbackTrans();
+                    return Json::fail($e->getMessage());
+                }
+            }
+        } else {
+            $res1 = true;
+        }
+        if ($data['integration_status'] && $data['integration']) {//积分增加或者减少
+            if ($data['integration_status'] == 1) {//增加
+                $edit['integral'] = bcadd($user['integral'], $data['integration'], 2);
+                $res2 = UserBillAdmin::income('系统增加积分', $user['uid'], 'integral', 'system_add', $data['integration'], $this->adminId, $edit['integral'], '系统增加了' . floatval($data['integration']) . '积分');
+                try {
+                    UserRepository::adminAddIntegral($user, $data['integration']);
+                } catch (\Exception $e) {
+                    BaseModel::rollbackTrans();
+                    return Json::fail($e->getMessage());
+                }
+            } else if ($data['integration_status'] == 2) {//减少
+                $edit['integral'] = bcsub($user['integral'], $data['integration'], 2);
+                $res2 = UserBillAdmin::expend('系统减少积分', $user['uid'], 'integral', 'system_sub', $data['integration'], $this->adminId, $edit['integral'], '系统扣除了' . floatval($data['integration']) . '积分');
+                try {
+                    UserRepository::adminSubIntegral($user, $data['integration']);
+                } catch (\Exception $e) {
+                    BaseModel::rollbackTrans();
+                    return Json::fail($e->getMessage());
+                }
+            }
+        } else {
+            $res2 = true;
+        }
+        $edit['status'] = $data['status'];
+        $edit['real_name'] = $data['real_name'];
+        $edit['phone'] = $data['phone'];
+        $edit['card_id'] = $data['card_id'];
+        $edit['birthday'] = strtotime($data['birthday']);
+        $edit['mark'] = $data['mark'];
+        $edit['is_promoter'] = $data['is_promoter'];
+        if ($edit) $res3 = UserModel::edit($edit, $uid);
+        else $res3 = true;
+        if ($res1 && $res2 && $res3) $res = true;
+        else $res = false;
+        BaseModel::checkTrans($res);
+        if ($res) return Json::successful('修改成功!');
+        else return Json::fail('修改失败');
+    }
+
+    /**
+     * 用户图表
+     * @return mixed
+     */
+    public function user_analysis()
+    {
+        $where = Util::getMore([
+            ['nickname', ''],
+            ['status', ''],
+            ['is_promoter', ''],
+            ['date', ''],
+            ['user_type', ''],
+            ['export', 0]
+        ], $this->request);
+        $user_count = UserModel::consume($where, '', true);
+        //头部信息
+        $header = [
+            [
+                'name' => '新增用户',
+                'class' => 'fa-line-chart',
+                'value' => $user_count,
+                'color' => 'red'
+            ],
+            [
+                'name' => '用户留存',
+                'class' => 'fa-area-chart',
+                'value' => $this->gethreaderValue(UserModel::consume($where, '', true), $where) . '%',
+                'color' => 'lazur'
+            ],
+            [
+                'name' => '新增用户总消费',
+                'class' => 'fa-bar-chart',
+                'value' => '¥' . UserModel::consume($where),
+                'color' => 'navy'
+            ],
+            [
+                'name' => '用户活跃度',
+                'class' => 'fa-pie-chart',
+                'value' => $this->gethreaderValue(UserModel::consume($where, '', true)) . '%',
+                'color' => 'yellow'
+            ],
+        ];
+        $name = ['新增用户', '用户消费'];
+        $dates = $this->get_user_index($where, $name);
+        $user_index = ['name' => json_encode($name), 'date' => json_encode($dates['time']), 'series' => json_encode($dates['series'])];
+        //用户浏览分析
+        $view = StoreVisit::getVisit($where['date'], ['', 'warning', 'info', 'danger']);
+        $view_v1 = WechatMessage::getViweList($where['date'], ['', 'warning', 'info', 'danger']);
+        $view = array_merge($view, $view_v1);
+        $view_v2 = [];
+        foreach ($view as $val) {
+            $view_v2['color'][] = '#' . rand(100000, 339899);
+            $view_v2['name'][] = $val['name'];
+            $view_v2['value'][] = $val['value'];
+        }
+        $view = $view_v2;
+        //消费会员排行用户分析
+        $user_null = UserModel::getUserSpend($where['date']);
+        //消费数据
+        $now_number = UserModel::getUserSpend($where['date'], true);
+        list($paren_number, $title) = UserModel::getPostNumber($where['date']);
+        if ($paren_number == 0) {
+            $rightTitle = [
+                'number' => $now_number > 0 ? $now_number : 0,
+                'icon' => 'fa-level-up',
+                'title' => $title
+            ];
+        } else {
+            $number = (float)bcsub($now_number, $paren_number, 4);
+            if ($now_number == 0) {
+                $icon = 'fa-level-down';
+            } else {
+                $icon = $now_number > $paren_number ? 'fa-level-up' : 'fa-level-down';
+            }
+            $rightTitle = ['number' => $number, 'icon' => $icon, 'title' => $title];
+        }
+        unset($title, $paren_number, $now_number);
+        list($paren_user_count, $title) = UserModel::getPostNumber($where['date'], true, 'add_time', '');
+        if ($paren_user_count == 0) {
+            $count = $user_count == 0 ? 0 : $user_count;
+            $icon = $user_count == 0 ? 'fa-level-down' : 'fa-level-up';
+        } else {
+            $count = (float)bcsub($user_count, $paren_user_count, 4);
+            $icon = $user_count < $paren_user_count ? 'fa-level-down' : 'fa-level-up';
+        }
+        $leftTitle = [
+            'count' => $count,
+            'icon' => $icon,
+            'title' => $title
+        ];
+        unset($count, $icon, $title);
+        $consume = [
+            'title' => '消费金额为¥' . UserModel::consume($where),
+            'series' => UserModel::consume($where, 'xiaofei'),
+            'rightTitle' => $rightTitle,
+            'leftTitle' => $leftTitle,
+        ];
+        $form = UserModel::consume($where, 'form');
+        $grouping = UserModel::consume($where, 'grouping');
+        $this->assign(compact('header', 'user_index', 'view', 'user_null', 'consume', 'form', 'grouping', 'where'));
+        return $this->fetch();
+    }
+
+    public function gethreaderValue($chart, $where = [])
+    {
+        if ($where) {
+            switch ($where['date']) {
+                case null:
+                case 'today':
+                case 'week':
+                case 'year':
+                    if ($where['date'] == null) {
+                        $where['date'] = 'month';
+                    }
+                    $sum_user = UserModel::whereTime('add_time', $where['date'])->count();
+                    if ($sum_user == 0) return 0;
+                    $counts = bcdiv($chart, $sum_user, 4) * 100;
+                    return $counts;
+                    break;
+                case 'quarter':
+                    $quarter = UserModel::getMonth('n');
+                    $quarter[0] = strtotime($quarter[0]);
+                    $quarter[1] = strtotime($quarter[1]);
+                    $sum_user = UserModel::where('add_time', 'between', $quarter)->count();
+                    if ($sum_user == 0) return 0;
+                    $counts = bcdiv($chart, $sum_user, 4) * 100;
+                    return $counts;
+                default:
+                    //自定义时间
+                    $quarter = explode('-', $where['date']);
+                    $quarter[0] = strtotime($quarter[0]);
+                    $quarter[1] = strtotime($quarter[1]);
+                    $sum_user = UserModel::where('add_time', 'between', $quarter)->count();
+                    if ($sum_user == 0) return 0;
+                    $counts = bcdiv($chart, $sum_user, 4) * 100;
+                    return $counts;
+                    break;
+            }
+        } else {
+            $num = UserModel::count();
+            $chart = $num != 0 ? bcdiv($chart, $num, 5) * 100 : 0;
+            return $chart;
+        }
+    }
+
+    public function get_user_index($where, $name)
+    {
+        switch ($where['date']) {
+            case null:
+                $days = date("t", strtotime(date('Y-m', time())));
+                $dates = [];
+                $series = [];
+                $times_list = [];
+                foreach ($name as $key => $val) {
+                    for ($i = 1; $i <= $days; $i++) {
+                        if (!in_array($i . '号', $times_list)) {
+                            array_push($times_list, $i . '号');
+                        }
+                        $time = $this->gettime(date("Y-m", time()) . '-' . $i);
+                        if ($key == 0) {
+                            $dates['data'][] = UserModel::where('add_time', 'between', $time)->count();
+                        } else if ($key == 1) {
+                            $dates['data'][] = UserModel::consume(true, $time);
+                        }
+                    }
+                    $dates['name'] = $val;
+                    $dates['type'] = 'line';
+                    $series[] = $dates;
+                    unset($dates);
+                }
+                return ['time' => $times_list, 'series' => $series];
+            case 'today':
+                $dates = [];
+                $series = [];
+                $times_list = [];
+                foreach ($name as $key => $val) {
+                    for ($i = 0; $i <= 24; $i++) {
+                        $strtitle = $i . '点';
+                        if (!in_array($strtitle, $times_list)) {
+                            array_push($times_list, $strtitle);
+                        }
+                        $time = $this->gettime(date("Y-m-d ", time()) . $i);
+                        if ($key == 0) {
+                            $dates['data'][] = UserModel::where('add_time', 'between', $time)->count();
+                        } else if ($key == 1) {
+                            $dates['data'][] = UserModel::consume(true, $time);
+                        }
+                    }
+                    $dates['name'] = $val;
+                    $dates['type'] = 'line';
+                    $series[] = $dates;
+                    unset($dates);
+                }
+                return ['time' => $times_list, 'series' => $series];
+            case "week":
+                $dates = [];
+                $series = [];
+                $times_list = [];
+                foreach ($name as $key => $val) {
+                    for ($i = 0; $i <= 6; $i++) {
+                        if (!in_array('星期' . ($i + 1), $times_list)) {
+                            array_push($times_list, '星期' . ($i + 1));
+                        }
+                        $time = UserModel::getMonth('h', $i);
+                        if ($key == 0) {
+                            $dates['data'][] = UserModel::where('add_time', 'between', [strtotime($time[0]), strtotime($time[1])])->count();
+                        } else if ($key == 1) {
+                            $dates['data'][] = UserModel::consume(true, [strtotime($time[0]), strtotime($time[1])]);
+                        }
+                    }
+                    $dates['name'] = $val;
+                    $dates['type'] = 'line';
+                    $series[] = $dates;
+                    unset($dates);
+                }
+                return ['time' => $times_list, 'series' => $series];
+            case 'year':
+                $dates = [];
+                $series = [];
+                $times_list = [];
+                $year = date('Y');
+                foreach ($name as $key => $val) {
+                    for ($i = 1; $i <= 12; $i++) {
+                        if (!in_array($i . '月', $times_list)) {
+                            array_push($times_list, $i . '月');
+                        }
+                        $t = strtotime($year . '-' . $i . '-01');
+                        $arr = explode('/', date('Y-m-01', $t) . '/' . date('Y-m-', $t) . date('t', $t));
+                        if ($key == 0) {
+                            $dates['data'][] = UserModel::where('add_time', 'between', [strtotime($arr[0]), strtotime($arr[1])])->count();
+                        } else if ($key == 1) {
+                            $dates['data'][] = UserModel::consume(true, [strtotime($arr[0]), strtotime($arr[1])]);
+                        }
+                    }
+                    $dates['name'] = $val;
+                    $dates['type'] = 'line';
+                    $series[] = $dates;
+                    unset($dates);
+                }
+                return ['time' => $times_list, 'series' => $series];
+            case 'quarter':
+                $dates = [];
+                $series = [];
+                $times_list = [];
+                foreach ($name as $key => $val) {
+                    for ($i = 1; $i <= 4; $i++) {
+                        $arr = $this->gettime('quarter', $i);
+                        if (!in_array(implode('--', $arr) . '季度', $times_list)) {
+                            array_push($times_list, implode('--', $arr) . '季度');
+                        }
+                        if ($key == 0) {
+                            $dates['data'][] = UserModel::where('add_time', 'between', [strtotime($arr[0]), strtotime($arr[1])])->count();
+                        } else if ($key == 1) {
+                            $dates['data'][] = UserModel::consume(true, [strtotime($arr[0]), strtotime($arr[1])]);
+                        }
+                    }
+                    $dates['name'] = $val;
+                    $dates['type'] = 'line';
+                    $series[] = $dates;
+                    unset($dates);
+                }
+                return ['time' => $times_list, 'series' => $series];
+            default:
+                $list = UserModel::consume($where, 'default');
+                $dates = [];
+                $series = [];
+                $times_list = [];
+                foreach ($name as $k => $v) {
+                    foreach ($list as $val) {
+                        $date = $val['add_time'];
+                        if (!in_array($date, $times_list)) {
+                            array_push($times_list, $date);
+                        }
+                        if ($k == 0) {
+                            $dates['data'][] = $val['num'];
+                        } else if ($k == 1) {
+                            $dates['data'][] = UserBillAdmin::where(['uid' => $val['uid'], 'type' => 'pay_product'])->sum('number');
+                        }
+                    }
+                    $dates['name'] = $v;
+                    $dates['type'] = 'line';
+                    $series[] = $dates;
+                    unset($dates);
+                }
+                return ['time' => $times_list, 'series' => $series];
+        }
+    }
+
+    public function gettime($time = '', $season = '')
+    {
+        if (!empty($time) && empty($season)) {
+            $timestamp0 = strtotime($time);
+            $timestamp24 = strtotime($time) + 86400;
+            return [$timestamp0, $timestamp24];
+        } else if (!empty($time) && !empty($season)) {
+            $firstday = date('Y-m-01', mktime(0, 0, 0, ($season - 1) * 3 + 1, 1, date('Y')));
+            $lastday = date('Y-m-t', mktime(0, 0, 0, $season * 3, 1, date('Y')));
+            return [$firstday, $lastday];
+        }
+    }
+
+    /**
+     * 会员等级首页
+     */
+    public function group()
+    {
+        return $this->fetch();
+    }
+}

+ 101 - 0
app/admin/controller/user/UserGroup.php

@@ -0,0 +1,101 @@
+<?php
+/**
+ *
+ * @author: wuhaotian<442384644@qq.com>
+ * @day: 2019/12/07
+ */
+
+namespace app\admin\controller\user;
+
+use app\admin\controller\AuthController;
+use app\admin\model\user\UserGroup as GroupModel;
+use crmeb\services\JsonService;
+use crmeb\services\UtilService;
+use crmeb\services\FormBuilder as Form;
+use think\facade\Route as Url;
+
+/**
+ * Class UserGroup
+ * @package app\admin\controller\user
+ */
+class UserGroup extends AuthController
+{
+    /**
+     * 会员分组页面
+     * @return string
+     */
+    public function index()
+    {
+        return $this->fetch();
+    }
+
+    /**
+     * 分组列表
+     */
+    public function groupList()
+    {
+        $where = UtilService::getMore([
+            ['page', 1],
+            ['limit', 20],
+        ]);
+        return JsonService::successlayui(GroupModel::getList($where));
+    }
+
+    /**
+     * 添加/修改分组页面
+     * @param int $id
+     * @return string
+     */
+    public function addGroup($id = 0)
+    {
+        $group = GroupModel::get($id);
+        $f = array();
+        if (!$group) {
+            $f[] = Form::input('group_name', '分组名称', '');
+        } else {
+            $f[] = Form::input('group_name', '分组名称', $group->getData('group_name'));
+        }
+        $form = Form::make_post_form('添加用户通知', $f, Url::buildUrl('saveGroup', array('id' => $id)));
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 添加/修改
+     * @param int $id
+     */
+    public function saveGroup($id = 0)
+    {
+        $data = UtilService::postMore([
+            ['group_name', ''],
+        ]);
+        if ($id) {
+            if (GroupModel::where('id', $id)->update($data)) {
+                return JsonService::success('修改成功');
+            } else {
+                return JsonService::fail('修改失败或者您没有修改什么!');
+            }
+        } else {
+            if ($res = GroupModel::create($data)) {
+                return JsonService::success('保存成功', ['id' => $res->id]);
+            } else {
+                return JsonService::fail('保存失败!');
+            }
+        }
+    }
+
+    /**
+     * 删除
+     * @param $id
+     * @throws \Exception
+     */
+    public function delete($id)
+    {
+        if (!$id) return $this->failed('数据不存在');
+        if (!GroupModel::be(['id' => $id])) return $this->failed('产品数据不存在');
+        if (!GroupModel::where('id', $id)->delete())
+            return JsonService::fail(GroupModel::getErrorInfo('恢复失败,请稍候再试!'));
+        else
+            return JsonService::successful('恢复门店成功!');
+    }
+}

+ 303 - 0
app/admin/controller/user/UserNotice.php

@@ -0,0 +1,303 @@
+<?php
+
+namespace app\admin\controller\user;
+
+use app\admin\controller\AuthController;
+use crmeb\services\{FormBuilder as Form, UtilService as Util, JsonService as Json};
+use crmeb\services\JsonService;
+use think\facade\Route as Url;
+use app\admin\model\user\UserNotice as UserNoticeModel;
+use app\admin\model\user\UserNoticeSee as UserNoticeSeeModel;
+use app\admin\model\wechat\WechatUser as UserModel;
+
+/**
+ * 用户通知
+ * Class UserNotice
+ * @package app\admin\controller\user
+ */
+class UserNotice extends AuthController
+{
+    /**
+     * 显示资源列表
+     *
+     * @return \think\Response
+     */
+    public function index()
+    {
+        if ($this->request->isAjax()) {
+            $where = Util::getMore([
+                ['page', 1],
+                ['limit', 20]
+            ]);
+            return Json::successlayui(UserNoticeModel::getList($where));
+        } else {
+            return $this->fetch();
+        }
+    }
+
+    /**
+     * 显示创建资源表单页.
+     *
+     * @return \think\Response
+     */
+    public function create()
+    {
+        $f = array();
+        $f[] = Form::input('user', '发送人', '系统管理员');
+        $f[] = Form::input('title', '通知标题');
+        $f[] = Form::input('content', '通知内容')->type('textarea');
+        $f[] = Form::radio('type', '消息类型', 1)->options([['label' => '系统消息', 'value' => 1], ['label' => '用户通知', 'value' => 2]]);
+        $form = Form::make_post_form('添加用户通知', $f, Url::buildUrl('save'));
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 保存新建的资源
+     */
+    public function save()
+    {
+        $params = request()->post();
+        if (!$params["user"]) return Json::fail('请输入发送人!');
+        if (!$params["title"]) return Json::fail('请输入通知标题!');
+        if (!$params["content"]) return Json::fail('请输入通知内容!');
+        if ($params["type"] == 2) {
+            $uids = UserModel::order('uid desc')->column("uid", 'uid');
+            $params["uid"] = count($uids) > 0 ? "," . implode(",", $uids) . "," : "";
+        }
+        $params["add_time"] = time();
+        $params["send_time"] = 0;
+        UserNoticeModel::create($params);
+        return Json::successful('添加成功!');
+    }
+
+    /**
+     * 显示编辑资源表单页.
+     *
+     * @param int $id
+     * @return \think\Response
+     */
+    public function edit($id)
+    {
+        $notice = UserNoticeModel::get($id);
+        if (!$notice) return Json::fail('数据不存在!');
+        $f = array();
+        $f[] = Form::input('user', '发送人', $notice["user"]);
+        $f[] = Form::input('title', '通知标题', $notice["title"]);
+        $f[] = Form::input('content', '通知内容', $notice["content"])->type('textarea');
+        $f[] = Form::radio('type', '消息类型', $notice["type"])->options([['label' => '系统消息', 'value' => 1], ['label' => '用户通知', 'value' => 2]]);
+        $form = Form::make_post_form('编辑通知', $f, Url::buildUrl('update', ["id" => $id]), 2);
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 保存新建的资源
+     * @param $id
+     */
+    public function update($id)
+    {
+        $params = request()->post();
+        if (!$params["user"]) return Json::fail('请输入发送人!');
+        if (!$params["title"]) return Json::fail('请输入通知标题!');
+        if (!$params["content"]) return Json::fail('请输入通知内容!');
+        UserNoticeModel::edit($params, $id);
+        return Json::successful('修改成功!');
+    }
+
+    /**
+     * 删除指定资源
+     *
+     * @param int $id
+     * @return \think\Response
+     */
+    public function send($id)
+    {
+        UserNoticeModel::edit(array("is_send" => 1, "send_time" => time()), $id);
+        return Json::successful('发送成功!');
+    }
+
+    /**
+     * 删除指定资源
+     *
+     * @param int $id
+     * @return \think\Response
+     */
+    public function delete($id)
+    {
+        if (!UserNoticeModel::del($id))
+            return Json::fail(UserNoticeModel::getErrorInfo('删除失败,请稍候再试!'));
+        else
+            return Json::successful('删除成功!');
+    }
+
+    /**
+     * 查询发送信息的用户资源
+     *
+     * @param int $id
+     * @return \think\Response
+     */
+    public function user($id)
+    {
+        $notice = UserNoticeModel::get($id)->toArray();
+        $model = new UserModel;
+        $model = $model::alias('A');
+        $model = $model->field('A.*');
+        if ($notice["type"] == 2) {
+            if ($notice["uid"] != "") {
+                $uids = explode(",", $notice["uid"]);
+                array_splice($uids, 0, 1);
+                array_splice($uids, count($uids) - 1, 1);
+                $model = $model->where("A.uid", "in", $uids);
+            } else {
+                $model = $model->where("A.uid", $notice['uid']);
+            }
+            $model->order('A.uid desc');
+        } else {
+            $model = $model->join('UserNoticeSee B', 'A.uid = B.uid', 'RIGHT');
+            $model = $model->where("B.nid", $notice['id']);
+            $model->order('B.add_time desc');
+        }
+        $this->assign(UserModel::page($model, function ($item, $key) use ($notice) {
+            $item["is_see"] = UserNoticeSeeModel::where("uid", $item["uid"])->where("nid", $notice["id"])->count() > 0 ? 1 : 0;
+        }));
+        $this->assign(compact('notice'));
+        return $this->fetch();
+    }
+
+    /**
+     * 添加发送信息的用户
+     *
+     * @param $id
+     * @return string
+     */
+    public function user_create($id)
+    {
+        $where = Util::getMore([
+            ['nickname', ''],
+            ['data', ''],
+        ], $this->request);
+        $this->assign('where', $where);
+        $this->assign(UserModel::systemPage($where));
+        $this->assign(['title' => '添加发送用户', 'save' => Url::buildUrl('user_save', array('id' => $id))]);
+        return $this->fetch();
+    }
+
+    /**
+     * 保存新建的资源
+     * @param $id
+     */
+    public function user_save($id)
+    {
+        $notice = UserNoticeModel::get($id)->toArray();
+        if (!$notice) return Json::fail('通知信息不存在!');
+        if ($notice["type"] == 1) return Json::fail('系统通知不能管理用户!');
+
+        //查找当前选中的uid
+        $params = request()->post();
+        if (isset($params["search"])) {
+            $model = new UserModel;
+            if ($params['search']['nickname'] !== '') $model = $model->where('nickname', 'LIKE', "%" . $params['search']['nickname'] . "%");
+            if ($params['search']['data'] !== '') {
+                list($startTime, $endTime) = explode(' - ', $params['search']['data']);
+                $model = $model->where('add_time', '>', strtotime($startTime));
+                $model = $model->where('add_time', '<', strtotime($endTime));
+            }
+            $model = $model->order('uid desc');
+            $uids = $model->column("uid", 'uid');
+        } else {
+            $uids = $params["checked_menus"];
+        }
+        if (count($uids) <= 0) return Json::fail('请选择要添加的用户!');
+
+        //合并原来和现在的uid
+        if ($notice["uid"] != "") {
+            $now_uids = explode(",", $notice["uid"]);
+            array_splice($now_uids, 0, 1);
+            array_splice($now_uids, count($now_uids) - 1, 1);
+            $now_uids = array_merge($now_uids, $uids);
+        } else {
+            $now_uids = $uids;
+        }
+
+        //编辑合并之后的uid
+        $res_uids = UserModel::where("uid", "in", $now_uids)->order('uid desc')->column("uid", 'uid');
+        UserNoticeModel::edit(array("uid" => "," . implode(",", $res_uids) . ","), $notice["id"]);
+        return Json::successful('添加成功!');
+    }
+
+    /**
+     * 删除指定资源
+     *
+     * @param int $id
+     * @return \think\Response
+     */
+    public function user_delete($id, $uid)
+    {
+        $notice = UserNoticeModel::get($id)->toArray();
+        if (!$notice) return Json::fail('通知信息不存在!');
+        if ($notice["type"] == 1) return Json::fail('系统通知不能管理用户!');
+        if ($notice["uid"] != "") {
+            $res_uids = explode(",", $notice["uid"]);
+            array_splice($res_uids, 0, 1);
+            array_splice($res_uids, count($res_uids) - 1, 1);
+        }
+        array_splice($res_uids, array_search($uid, $res_uids), 1);
+        $value = count($res_uids) > 0 ? "," . implode(",", $res_uids) . "," : "";
+        UserNoticeModel::edit(array("uid" => $value), $notice["id"]);
+        return Json::successful('删除成功!');
+    }
+
+    /**
+     * 删除指定的资源
+     * @param $id
+     */
+    public function user_select_delete($id)
+    {
+        $params = request()->post();
+        if (count($params["checked_menus"]) <= 0) return Json::fail('删除数据不能为空!');
+        $notice = UserNoticeModel::get($id)->toArray();
+        if (!$notice) return Json::fail('通知信息不存在!');
+
+        $res_uids = explode(",", $notice["uid"]);
+        array_splice($res_uids, 0, 1);
+        array_splice($res_uids, count($res_uids) - 1, 1);
+        foreach ($params["checked_menus"] as $key => $value) {
+            array_splice($res_uids, array_search($value, $res_uids), 1);
+        }
+        $value = count($res_uids) > 0 ? "," . implode(",", $res_uids) . "," : "";
+        UserNoticeModel::edit(array("uid" => $value), $notice["id"]);
+        return Json::successful('删除成功!');
+    }
+
+    /**
+     * @param $id
+     * @return mixed
+     */
+    public function notice($id)
+    {
+        $where = Util::getMore([
+            ['title', ''],
+        ], $this->request);
+        $nickname = UserModel::where('uid', 'IN', $id)->column('nickname', 'uid');
+        $this->assign('where', $where);
+        $this->assign('uid', $id);
+        $this->assign('nickname', implode(',', $nickname));
+        $this->assign(UserNoticeModel::getUserList($where));
+        return $this->fetch();
+    }
+
+
+    /**
+     * 给指定用户发送站内信息
+     * @param $id
+     */
+    public function send_user($id = 0, $uid = '')
+    {
+        if (!$id || $uid == '') return Json::fail('参数错误');
+        $uids = UserNoticeModel::where(['id' => $id])->value('uid');
+        $uid = rtrim($uids, ',') . "," . $uid . ",";
+        UserNoticeModel::edit(array("send_time" => time(), 'uid' => $uid), $id);
+        return Json::successful('发送成功!');
+    }
+}

+ 42 - 0
app/admin/controller/wechat/Menus.php

@@ -0,0 +1,42 @@
+<?php
+namespace app\admin\controller\wechat;
+
+use app\admin\controller\AuthController;
+use app\models\system\Cache;
+use crmeb\services\WechatService;
+
+/**
+ * 微信菜单  控制器
+ * Class Menus
+ * @package app\admin\controller\wechat
+ */
+class Menus extends AuthController
+{
+
+    public function index()
+    {
+        $menus = Cache::where('key','wechat_menus')->value('result');
+        $menus = $menus ? : '[]';
+        $this->assign('menus',$menus);
+        return $this->fetch();
+    }
+
+    public function save()
+    {
+        $buttons = request()->post('button/a',[]);
+        if(!count($buttons)) return $this->failed('请添加至少一个按钮');
+        try{
+            WechatService::menuService()->add($buttons);
+            $count = Cache::where('key', 'wechat_menus')->count();
+            if($count){
+                $count = Cache::where('key', 'wechat_menus')->where('result', json_encode($buttons))->count();
+                if(!$count)
+                    Cache::where('key', 'wechat_menus')->update(['result'=>json_encode($buttons),'add_time'=>time()]);
+            }else
+                Cache::insert(['key'=>'wechat_menus','result'=>json_encode($buttons),'add_time'=>time()],true);
+            return $this->successful('修改成功!');
+        }catch (\Exception $e){
+            return $this->failed($e->getMessage());
+        }
+    }
+}

+ 195 - 0
app/admin/controller/wechat/Reply.php

@@ -0,0 +1,195 @@
+<?php
+
+namespace app\admin\controller\wechat;
+
+use app\admin\controller\AuthController;
+use app\admin\model\system\SystemAttachment;
+use app\admin\model\wechat\WechatReply;
+use crmeb\services\UtilService as Util;
+use crmeb\services\JsonService as Json;
+use crmeb\services\upload\Upload;
+
+/**
+ * 关键字管理  控制器
+ * Class Reply
+ * @package app\admin\controller\wechat
+ */
+class Reply extends AuthController
+{
+    /**关注回复
+     * @return mixed|void
+     */
+    public function index()
+    {
+        if (empty(input('key'))) return $this->failed('请输入参数key');
+        if (empty(input('title'))) return $this->failed('请输入参数title');
+        $key = input('key');
+        switch ($key) {
+            case 'subscribe':
+                $title = '编辑关注回复';
+                $type = 0;
+                break;
+            case 'default':
+                $title = '编辑关键字默认回复';
+                $type = 1;
+                break;
+            default:
+                $title = '编辑关键字回复';
+                $type = 1;
+                break;
+        }
+        $this->assign('replay_arr', WechatReply::getDataByKey($key));
+        $this->assign('key', $key);
+        $this->assign('type', $type);
+        $this->assign('title', $title);
+        return $this->fetch();
+    }
+
+    public function one_reply()
+    {
+        $where = Util::postMore([
+            ['key'],
+            ['add', 0],
+        ], $this->request);
+        if (!empty($where['key'])) $replay_arr = WechatReply::getDataByKey($where['key']);
+        $replay_arr['code'] = 200;
+        if (empty($replay_arr)) {
+            $replay_arr['code'] = 0;
+        }
+        if ($where['add'] && empty($where['key'])) {
+            $replay_arr['code'] = 0;
+        }
+        exit(json_encode($replay_arr));
+    }
+
+    public function save()
+    {
+        $data = Util::postMore([
+            'type',
+            'key',
+            ['status', 0],
+            ['data', []],
+        ]);
+        if (!isset($data['type']) && empty($data['type']))
+            return Json::fail('请选择回复类型');
+        if (!in_array($data['type'], WechatReply::$reply_type))
+            return Json::fail('回复类型有误!');
+        if (!isset($data['data']) || !is_array($data['data']))
+            return Json::fail('回复消息参数有误!');
+        $res = WechatReply::redact($data['data'], $data['key'], $data['type'], $data['status']);
+        if (!$res)
+            return Json::fail(WechatReply::getErrorInfo());
+        else
+            return Json::successful('保存成功!', $data);
+    }
+
+    public function upload_img()
+    {
+        $name = $this->request->post('file');
+        if (!$name) return Json::fail('请上传图片');
+        $upload = new Upload('local');
+        $info = $upload->to('wechat/image')->validate()->move($name);
+        if ($info === false) {
+            return Json::fail($upload->getError());
+        }
+        $res = $upload->getUploadInfo();
+        SystemAttachment::attachmentAdd($res['name'], $res['size'], $res['type'], $res['dir'], $res['thumb_path'], 0, 1, $res['time'], 2, $this->adminInfo['mer_id']);
+        return Json::successful('上传成功', $res['dir']);
+    }
+
+    public function upload_file()
+    {
+        $name = $this->request->post('file');
+        if (!$name) return Json::fail('请上传声音');
+        $upload = new Upload('local');
+        $info = $upload->to('wechat/voice')->validate()->move($name);
+        if ($info === false) {
+            return Json::fail($upload->getError());
+        }
+        return Json::successful('上传成功', $info->filePath);
+    }
+
+    /**
+     * 关键字回复
+     * */
+    public function keyword()
+    {
+        $where = Util::getMore([
+            ['key', ''],
+            ['type', ''],
+        ]);
+        $this->assign('where', $where);
+        $this->assign(WechatReply::getKeyAll($where));
+        return $this->fetch();
+
+    }
+
+    /**
+     * 添加关键字
+     * */
+    public function add_keyword()
+    {
+        $key = input('key');
+        if (empty($key)) $key = '';
+        $this->assign('key', $key);
+        $this->assign('dis', 1);
+        $this->assign('replay_arr', []);
+        return $this->fetch();
+    }
+
+    /**
+     * 修改关键字
+     * */
+    public function info_keyword()
+    {
+        $key = input('key');
+        if (empty($key)) return $this->failed('参数错误,请重新修改');
+        $this->assign('replay_arr', WechatReply::getDataByKey($key));
+        $this->assign('key', $key);
+        $this->assign('dis', 2);
+        return $this->fetch('add_keyword');
+    }
+
+    /**
+     * 保存关键字
+     * */
+    public function save_keyword()
+    {
+        $data = Util::postMore([
+            'key',
+            'type',
+            ['status', 0],
+            ['data', []],
+        ]);
+        if (!isset($data['key']) && empty($data['key']))
+            return Json::fail('请输入关键字');
+        if (isset($data['key']) && !empty($data['key'])) {
+            if (trim($data['key']) == 'subscribe') return Json::fail('请重新输入关键字');
+            if (trim($data['key']) == 'default') return Json::fail('请重新输入关键字');
+        }
+        if (!isset($data['type']) && empty($data['type']))
+            return Json::fail('请选择回复类型');
+        if (!in_array($data['type'], WechatReply::$reply_type))
+            return Json::fail('回复类型有误!');
+        if (!isset($data['data']) || !is_array($data['data']))
+            return Json::fail('回复消息参数有误!');
+        $res = WechatReply::redact($data['data'], $data['key'], $data['type'], $data['status']);
+        if (!$res)
+            return Json::fail(WechatReply::getErrorInfo());
+        else
+            return Json::successful('保存成功!', $data);
+    }
+
+    /**
+     * 删除关键字
+     * */
+    public function delete($id)
+    {
+        if (!WechatReply::del($id))
+            return Json::fail(WechatReply::getErrorInfo('删除失败,请稍候再试!'));
+        else
+            return Json::successful('删除成功!');
+    }
+
+
+}

+ 168 - 0
app/admin/controller/wechat/StoreService.php

@@ -0,0 +1,168 @@
+<?php
+
+namespace app\admin\controller\wechat;
+
+use app\admin\controller\AuthController;
+use app\admin\model\system\SystemAttachment;
+use crmeb\services\{
+    CacheService,
+    FormBuilder as Form,
+    UtilService as Util,
+    JsonService as Json
+};
+use think\facade\Route as Url;
+use app\admin\model\wechat\{
+    StoreService as ServiceModel, StoreServiceLog as StoreServiceLog, WechatUser as UserModel
+};
+
+/**
+ * 客服管理
+ * Class StoreService
+ * @package app\admin\controller\store
+ */
+class StoreService extends AuthController
+{
+    /**
+     * 显示资源列表
+     *
+     * @return \think\Response
+     */
+    public function index()
+    {
+        $this->assign(ServiceModel::getList(0));
+        return $this->fetch();
+    }
+
+    /**
+     * 显示创建资源表单页.
+     *
+     * @return \think\Response
+     */
+    public function create()
+    {
+        $where = Util::getMore([
+            ['nickname', ''],
+            ['data', ''],
+            ['tagid_list', ''],
+            ['groupid', '-1'],
+            ['sex', ''],
+            ['export', ''],
+            ['stair', ''],
+            ['second', ''],
+            ['order_stair', ''],
+            ['order_second', ''],
+            ['subscribe', ''],
+            ['now_money', ''],
+            ['is_promoter', ''],
+        ], $this->request);
+        $this->assign('where', $where);
+        $this->assign(UserModel::systemPage($where));
+        $this->assign(['title' => '添加客服', 'save' => Url::buildUrl('save')]);
+        return $this->fetch();
+    }
+
+    /**
+     * 保存新建的资源
+     */
+    public function save()
+    {
+        $params = request()->post();
+        if (count($params["checked_menus"]) <= 0) return Json::fail('请选择要添加的用户!');
+        if (ServiceModel::where('mer_id', 0)->where(array("uid" => array("in", implode(',', $params["checked_menus"]))))->count()) return Json::fail('添加用户中存在已有的客服!');
+        foreach ($params["checked_menus"] as $key => $value) {
+            $now_user = UserModel::get($value);
+            $data[$key]["mer_id"] = 0;
+            $data[$key]["uid"] = $now_user["uid"];
+            $data[$key]["avatar"] = $now_user["headimgurl"];
+            $data[$key]["nickname"] = $now_user["nickname"];
+            $data[$key]["add_time"] = time();
+        }
+        ServiceModel::setAll($data);
+        return Json::successful('添加成功!');
+    }
+
+    /**
+     * 显示编辑资源表单页.
+     *
+     * @param int $id
+     * @return \think\Response
+     */
+    public function edit($id)
+    {
+        $service = ServiceModel::get($id);
+        if (!$service) return Json::fail('数据不存在!');
+        $f = array();
+        $f[] = Form::frameImageOne('avatar', '客服头像', Url::buildUrl('admin/widget.images/index', array('fodder' => 'avatar')), $service['avatar'])->icon('image')->width('100%')->height('500px');
+        $f[] = Form::input('nickname', '客服名称', $service["nickname"]);
+        $f[] = Form::radio('customer', '统计管理', $service['customer'])->options([['value' => 1, 'label' => '开启'], ['value' => 0, 'label' => '关闭']]);
+        $f[] = Form::radio('notify', '订单通知', $service['notify'])->options([['value' => 1, 'label' => '开启'], ['value' => 0, 'label' => '关闭']]);
+        $f[] = Form::radio('status', '客服状态', $service['status'])->options([['value' => 1, 'label' => '在线'], ['value' => 0, 'label' => '离线']]);
+        $form = Form::make_post_form('修改数据', $f, Url::buildUrl('update', compact('id')));
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 保存新建的资源
+     *
+     * @param \think\Request $request
+     * @return \think\Response
+     */
+    public function update($id)
+    {
+        $params = request()->post();
+        if (empty($params["nickname"])) return Json::fail("客服名称不能为空!");
+        $data = array("avatar" => $params["avatar"]
+        , "nickname" => $params["nickname"]
+        , 'status' => $params['status']
+        , 'notify' => $params['notify']
+        , 'customer' => $params['customer']
+        );
+        ServiceModel::edit($data, $id);
+        return Json::successful('修改成功!');
+    }
+
+    /**
+     * 删除指定资源
+     *
+     * @param int $id
+     * @return \think\Response
+     */
+    public function delete($id)
+    {
+        if (!ServiceModel::del($id))
+            return Json::fail(ServiceModel::getErrorInfo('删除失败,请稍候再试!'));
+        else
+            return Json::successful('删除成功!');
+    }
+
+    /**
+     * 显示资源列表
+     *
+     * @return \think\Response
+     */
+    public function chat_user($id)
+    {
+        $now_service = ServiceModel::get($id);
+        if (!$now_service) return Json::fail('数据不存在!');
+        $list = ServiceModel::getChatUser($now_service->toArray(), 0);
+        $this->assign(compact('list', 'now_service'));
+        return $this->fetch();
+    }
+
+    /**
+     * @param int $uid
+     * @param int $to_uid
+     * @return string
+     */
+    public function chat_list()
+    {
+        $where = Util::getMore([['uid', 0], ['to_uid', 0], ['id', 0]]);
+        if ($where['uid'])
+            CacheService::set('admin_chat_list' . $this->adminId, $where);
+        $where = CacheService::get('admin_chat_list' . $this->adminId);
+        $this->assign(StoreServiceLog::getChatList($where, 0));
+        $this->assign('where', $where);
+        return $this->fetch();
+    }
+}

+ 34 - 0
app/admin/controller/wechat/WechatMessage.php

@@ -0,0 +1,34 @@
+<?php
+
+namespace app\admin\controller\wechat;
+
+use app\admin\controller\AuthController;
+use app\admin\model\wechat\WechatMessage as MessageModel;
+use crmeb\services\UtilService as Util;
+
+/**
+ * 用户扫码点击事件
+ * Class SystemMessage
+ * @package app\admin\controller\system
+ */
+class WechatMessage extends AuthController
+{
+    /**
+     * 显示操作记录
+     */
+    public function index()
+    {
+        $where = Util::getMore([
+            ['nickname', ''],
+            ['type', ''],
+            ['data', ''],
+        ], $this->request);
+        $this->assign('where', $where);
+        $this->assign('mold', MessageModel::$mold);
+        $this->assign(MessageModel::systemPage($where));
+        return $this->fetch();
+    }
+
+
+}
+

+ 279 - 0
app/admin/controller/wechat/WechatNewsCategory.php

@@ -0,0 +1,279 @@
+<?php
+
+namespace app\admin\controller\wechat;
+
+use app\admin\controller\AuthController;
+use app\admin\model\article\Article;
+use app\models\article\ArticleContent;
+use think\facade\Route as Url;
+use app\admin\model\article\Article as ArticleModel;
+use app\admin\model\wechat\{WechatReply, WechatUser, WechatNewsCategory as WechatNewsCategoryModel};
+use crmeb\services\{FormBuilder as Form, UtilService as Util, JsonService as Json, UtilService, WechatService};
+
+/**
+ * 图文信息
+ * Class WechatNewsCategory
+ * @package app\admin\controller\wechat
+ *
+ */
+class WechatNewsCategory extends AuthController
+{
+    public function select($callback = '_selectNews$eb')
+    {
+        $where = Util::getMore([
+            ['cate_name', ''],
+            ['type', 1]
+        ], $this->request);
+        $this->assign('where', $where);
+        $this->assign('callback', $callback);
+        if ($where['type'] == 1)
+            $list = WechatNewsCategoryModel::getSendAll($where);
+        else
+            $list = WechatNewsCategoryModel::getAll($where);
+        $newList = $list['list']->toArray();
+        $newList = $newList['data'];
+        $this->assign($list);
+        $this->assign('type',$where['type']);
+        $this->assign('newList', $newList);
+        return $this->fetch();
+    }
+
+    public function index()
+    {
+        $where = Util::getMore([
+            ['cate_name', ''],
+        ], $this->request);
+        $this->assign('where', $where);
+        $this->assign(WechatNewsCategoryModel::getAll($where));
+        return $this->fetch();
+    }
+
+    public function create()
+    {
+        $f = array();
+        $f[] = Form::input('cate_name', '分类名称')->autofocus(1);
+        $f[] = Form::select('new_id', '图文列表')->setOptions(function () {
+            $list = ArticleModel::getNews();
+            $options = [];
+            foreach ($list as $id => $roleName) {
+                $options[] = ['label' => $roleName, 'value' => $id];
+            }
+            return $options;
+        })->filterable(1)->multiple(1);
+        $form = Form::make_post_form('编辑菜单', $f, Url::buildUrl('save'));
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    public function save()
+    {
+        $data = Util::postMore([
+            'cate_name',
+            ['new_id', []],
+            ['sort', 0],
+            ['add_time', time()],
+            ['status', 1],]);
+        if (!$data['cate_name']) return Json::fail('请输入图文名称');
+        if (empty($data['new_id'])) return Json::fail('请选择图文列表');
+        $data['new_id'] = array_unique($data['new_id']);
+        if (count($data['new_id']) > 8) {
+            $data['new_id'] = array_slice($data['new_id'], 0, 8);
+        };
+        $data['new_id'] = implode(',', $data['new_id']);
+        WechatNewsCategoryModel::create($data);
+        return Json::successful('添加菜单成功!');
+    }
+
+    public function edit($id)
+    {
+        $menu = WechatNewsCategoryModel::get($id);
+        if (!$menu) return Json::fail('数据不存在!');
+        $arr_new_id = array_unique(explode(',', $menu->new_id));
+        foreach ($arr_new_id as $k => $v) {
+            $arr_new_id[$k] = intval($v);
+        }
+        $f = array();
+        $f[] = Form::input('cate_name', '分类名称', $menu['cate_name'])->autofocus(1);
+        $f[] = Form::select('new_id', '图文列表', $arr_new_id)->setOptions(function () {
+            $list = ArticleModel::getNews();
+            $options = [];
+            foreach ($list as $id => $roleName) {
+                $options[] = ['label' => $roleName, 'value' => $id];
+            }
+            return $options;
+        })->filterable(1)->multiple(1);
+        $form = Form::make_post_form('编辑图文', $f, Url::buildUrl('update', compact('id')));
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    public function update($id)
+    {
+        $data = Util::postMore([
+            'cate_name',
+            ['new_id', []],
+            ['sort', 0],
+            ['status', 1],]);
+        if (!$data['cate_name']) return Json::fail('请输入图文名称');
+        if (empty($data['new_id'])) return Json::fail('请选择图文列表');
+        if (count($data['new_id']) > 8) {
+            $data['new_id'] = array_slice($data['new_id'], 0, 8);
+        };
+        $data['new_id'] = implode(',', $data['new_id']);;
+        if (!WechatNewsCategoryModel::get($id)) return Json::fail('编辑的记录不存在!');
+        WechatNewsCategoryModel::edit($data, $id);
+        return Json::successful('修改成功!');
+    }
+
+    public function delete($id)
+    {
+        if (!WechatNewsCategoryModel::del($id))
+            return Json::fail(WechatNewsCategoryModel::getErrorInfo('删除失败,请稍候再试!'));
+        else
+            return Json::successful('删除成功!');
+    }
+
+
+    /**
+     * 发送消息
+     * @param int $id
+     * @param string $wechat
+     * $wechat  不为空  发消息  /  空 群发消息
+     */
+    public function push($id = 0, $new_id = 0, $wechat = '')
+    {
+        if ((!$id) || (!$new_id)) return Json::fail('参数错误');
+        $list = WechatNewsCategoryModel::getWechatNewsItem($id, $new_id);
+        $wechatNews = [];
+        if ($list) {
+            if ($list['new'] && is_array($list['new'])) {
+                foreach ($list['new'] as $kk => $vv) {
+                    $wechatNews[$kk]['title'] = $vv['title'];
+                    $wechatNews[$kk]['image'] = $vv['image_input'];
+                    $wechatNews[$kk]['date'] = date('m月d日', time());
+                    $wechatNews[$kk]['description'] = $vv['synopsis'];
+                    $wechatNews[$kk]['id'] = $vv['id'];
+                }
+            }
+        }
+        if ($wechat != '') {//客服消息
+            $wechatNews = WechatReply::tidyNews($wechatNews);
+            $message = WechatService::newsMessage($wechatNews);
+            $errorLog = [];//发送失败的用户
+            $user = WechatUser::where('uid', 'IN', $wechat)->column('nickname,subscribe,openid', 'uid');
+            if ($user) {
+                foreach ($user as $v) {
+                    if ($v['subscribe'] && $v['openid']) {
+                        try {
+                            WechatService::staffService()->message($message)->to($v['openid'])->send();
+                        } catch (\Exception $e) {
+                            $errorLog[] = $v['nickname'] . '发送失败';
+                        }
+                    } else {
+                        $errorLog[] = $v['nickname'] . '没有关注发送失败(不是微信公众号用户)';
+                    }
+                }
+            } else return Json::fail('发送失败,参数不正确');
+            if (!count($errorLog)) return Json::successful('全部发送成功');
+            else return Json::successful(implode(',', $errorLog) . ',剩余的发送成功');
+        }
+    }
+
+    public function send_news($id = '')
+    {
+        if ($id == '') return $this->failed('参数错误');
+        $where = Util::getMore([
+            ['cate_name', ''],
+            ['type', 0]
+        ], $this->request);
+        $this->assign('where', $where);
+        $this->assign('wechat', $id);
+        $this->assign(WechatNewsCategoryModel::getSendAll($where));
+        return $this->fetch();
+    }
+
+    public function append()
+    {
+        $this->assign('list', [
+            [
+                'id' => 0,
+                'title' => '',
+                'author' => $this->adminInfo->real_name,
+                'content' => '',
+                'image_input' => '/system/module/wechat/news/images/image.png',
+                'synopsis' => '',
+            ]
+        ]);
+        $this->assign('id', 0);
+        $this->assign('author', $this->adminInfo->real_name);
+        return $this->fetch();
+    }
+
+    public function append_save()
+    {
+        $data = UtilService::postMore([
+            ['list', []],
+            ['id', 0]
+        ]);
+        $id = [];
+        $countList = count($data['list']);
+        if (!$countList) return Json::fail('请添加图文');
+        Article::beginTrans();
+        foreach ($data['list'] as $k => $v) {
+            if ($v['title'] == '') return Json::fail('标题不能为空');
+            if ($v['author'] == '') return Json::fail('作者不能为空');
+            if ($v['content'] == '') return Json::fail('正文不能为空');
+            if ($v['synopsis'] == '') return Json::fail('摘要不能为空');
+            $v['status'] = 1;
+            $v['add_time'] = time();
+            if ($v['id']) {
+                $idC = $v['id'];
+                unset($v['id']);
+                Article::edit($v, $idC);
+                ArticleContent::where('nid', $idC)->update(['content' => $v['content']]);
+                $data['list'][$k]['id'] = $idC;
+                $id[] = $idC;
+            } else {
+                unset($v['id']);
+                $res = Article::create($v)->toArray();
+                $id[] = $res['id'];
+                $data['list'][$k]['id'] = $res['id'];
+                ArticleContent::insert(['content' => $v['content'], 'nid' => $res['id']]);
+            }
+        }
+        $countId = count($id);
+        if ($countId != $countList) {
+            Article::checkTrans(false);
+            if ($data['id']) return Json::fail('修改失败');
+            else return Json::fail('添加失败');
+        } else {
+            Article::checkTrans(true);
+            $newsCategory['cate_name'] = $data['list'][0]['title'];
+            $newsCategory['new_id'] = implode(',', $id);
+            $newsCategory['sort'] = 0;
+            $newsCategory['add_time'] = time();
+            $newsCategory['status'] = 1;
+            if ($data['id']) {
+                WechatNewsCategoryModel::edit($newsCategory, $data['id']);
+                return Json::successful('修改成功');
+            } else {
+                WechatNewsCategoryModel::create($newsCategory);
+                return Json::successful('添加成功');
+            }
+        }
+    }
+
+    public function modify($id)
+    {
+        if (!strlen(trim($id)) || !$id) return $this->failed('参数错误');
+        $wechatNews = WechatNewsCategoryModel::get($id);
+        if (!$wechatNews) return $this->failed('参数错误');
+        $wechatNews = $wechatNews->toArray();
+        $list = Article::getArticleList($wechatNews['new_id']);
+        $this->assign('list', $list);
+        $this->assign('id', $id);
+        $this->assign('author', $this->adminInfo->real_name);
+        return $this->fetch('append');
+    }
+
+}

+ 135 - 0
app/admin/controller/wechat/WechatTemplate.php

@@ -0,0 +1,135 @@
+<?php
+
+namespace app\admin\controller\wechat;
+
+use app\admin\controller\AuthController;
+use crmeb\services\FormBuilder as Form;
+use crmeb\services\UtilService as Util;
+use crmeb\services\JsonService as Json;
+use crmeb\services\WechatTemplateService;
+use think\facade\Cache;
+use think\facade\Route as Url;
+use app\admin\model\wechat\WechatTemplate as WechatTemplateModel;
+
+/**
+ * 微信模板消息控制器
+ * Class WechatTemplate
+ * @package app\admin\controller\wechat
+ */
+class WechatTemplate extends AuthController
+{
+
+    protected $cacheTag = '_system_wechat';
+
+    public function index()
+    {
+        $where = Util::getMore([
+            ['name', ''],
+            ['status', '']
+        ], $this->request);
+        $this->assign('where', $where);
+        $this->assign(WechatTemplateModel::SystemPage($where));
+        $industry = Cache::tag($this->cacheTag)->remember('_wechat_industry', function () {
+            try {
+                $cache = WechatTemplateService::getIndustry();
+                if (!$cache) return [];
+                Cache::tag($this->cacheTag, ['_wechat_industry']);
+                return $cache->toArray();
+            } catch (\Exception $e) {
+                return $e->getMessage();
+            }
+
+        }, 0) ?: [];
+        !is_array($industry) && $industry = [];
+        $this->assign('industry', $industry);
+        return $this->fetch();
+    }
+
+    /**
+     * 添加模板消息
+     * @return mixed
+     */
+    public function create()
+    {
+        $f = array();
+        $f[] = Form::input('tempkey', '模板编号');
+        $f[] = Form::input('tempid', '模板ID');
+        $f[] = Form::input('name', '模板名');
+        $f[] = Form::input('content', '回复内容')->type('textarea');
+        $f[] = Form::radio('status', '状态', 1)->options([['label' => '开启', 'value' => 1], ['label' => '关闭', 'value' => 0]]);
+        $form = Form::make_post_form('添加模板消息', $f, Url::buildUrl('save'));
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    public function save()
+    {
+        $data = Util::postMore([
+            'tempkey',
+            'tempid',
+            'name',
+            'content',
+            ['status', 0]
+        ]);
+        if ($data['tempkey'] == '') return Json::fail('请输入模板编号');
+        if ($data['tempkey'] != '' && WechatTemplateModel::be($data['tempkey'], 'tempkey'))
+            return Json::fail('请输入模板编号已存在,请重新输入');
+        if ($data['tempid'] == '') return Json::fail('请输入模板ID');
+        if ($data['name'] == '') return Json::fail('请输入模板名');
+        if ($data['content'] == '') return Json::fail('请输入回复内容');
+        $data['add_time'] = time();
+        $data['type'] = 1;
+        WechatTemplateModel::create($data);
+        return Json::successful('添加模板消息成功!');
+    }
+
+    /**
+     * 编辑模板消息
+     * @param $id
+     * @return mixed|\think\response\Json|void
+     */
+    public function edit($id)
+    {
+        if (!$id) return $this->failed('数据不存在');
+        $product = WechatTemplateModel::get($id);
+        if (!$product) return Json::fail('数据不存在!');
+        $f = array();
+        $f[] = Form::input('tempkey', '模板编号', $product->getData('tempkey'))->disabled(1);
+        $f[] = Form::input('name', '模板名', $product->getData('name'))->disabled(1);
+        $f[] = Form::input('tempid', '模板ID', $product->getData('tempid'));
+        $f[] = Form::radio('status', '状态', $product->getData('status'))->options([['label' => '开启', 'value' => 1], ['label' => '关闭', 'value' => 0]]);
+        $form = Form::make_post_form('编辑模板消息', $f, Url::buildUrl('update', compact('id')));
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    public function update($id)
+    {
+        $data = Util::postMore([
+            'tempid',
+            ['status', 0]
+        ]);
+        if ($data['tempid'] == '') return Json::fail('请输入模板ID');
+        if (!$id) return $this->failed('数据不存在');
+        $product = WechatTemplateModel::get($id);
+        if (!$product) return Json::fail('数据不存在!');
+        WechatTemplateModel::edit($data, $id);
+        return Json::successful('修改成功!');
+    }
+
+    /**
+     * 删除模板消息
+     * @param $id
+     * @return \think\response\Json
+     */
+    public function delete($id)
+    {
+        if (!$id) return Json::fail('数据不存在!');
+        if (!WechatTemplateModel::del($id))
+            return Json::fail(WechatTemplateModel::getErrorInfo('删除失败,请稍候再试!'));
+        else
+            return Json::successful('删除成功!');
+    }
+
+
+}

+ 390 - 0
app/admin/controller/wechat/WechatUser.php

@@ -0,0 +1,390 @@
+<?php
+
+namespace app\admin\controller\wechat;
+
+use app\admin\controller\AuthController;
+use app\admin\model\user\User;
+use app\models\user\UserBill;
+use think\Collection;
+use think\facade\Route as Url;
+use app\admin\model\wechat\WechatUser as UserModel;
+use crmeb\services\{FormBuilder as Form, JsonService, UtilService as Util, WechatService};
+
+/**
+ * 管理员操作记录表控制器
+ * Class WechatUser
+ * @package app\admin\controller\wechat
+ */
+class WechatUser extends AuthController
+{
+    /**
+     * 显示操作记录
+     */
+    public function index()
+    {
+        $where = Util::getMore([
+            ['nickname', ''],
+            ['data', ''],
+            ['tagid_list', ''],
+            ['groupid', '-1'],
+            ['sex', ''],
+            ['export', ''],
+            ['stair', ''],
+            ['second', ''],
+            ['order_stair', ''],
+            ['order_second', ''],
+            ['subscribe', ''],
+            ['now_money', ''],
+            ['is_promoter', ''],
+        ], $this->request);
+        $tagidList = explode(',', $where['tagid_list']);
+        foreach ($tagidList as $k => $v) {
+            if (!$v) {
+                unset($tagidList[$k]);
+            }
+        }
+        $tagidList = array_unique($tagidList);
+        $where['tagid_list'] = implode(',', $tagidList);
+        try {
+            $groupList = UserModel::getUserGroup();
+            $tagList = UserModel::getUserTag();
+        } catch (\Exception $e) {
+            $groupList = [];
+            $tagList = [];
+        }
+        $this->assign([
+            'where' => $where,
+            'groupList' => $groupList,
+            'tagList' => $tagList
+        ]);
+        $limitTimeList = [
+            'today' => implode(' - ', [date('Y/m/d'), date('Y/m/d', strtotime('+1 day'))]),
+            'week' => implode(' - ', [
+                date('Y/m/d', (time() - ((date('w') == 0 ? 7 : date('w')) - 1) * 24 * 3600)),
+                date('Y-m-d', (time() + (7 - (date('w') == 0 ? 7 : date('w'))) * 24 * 3600))
+            ]),
+            'month' => implode(' - ', [date('Y/m') . '/01', date('Y/m') . '/' . date('t')]),
+            'quarter' => implode(' - ', [
+                date('Y') . '/' . (ceil((date('n')) / 3) * 3 - 3 + 1) . '/01',
+                date('Y') . '/' . (ceil((date('n')) / 3) * 3) . '/' . date('t', mktime(0, 0, 0, (ceil((date('n')) / 3) * 3), 1, date('Y')))
+            ]),
+            'year' => implode(' - ', [
+                date('Y') . '/01/01', date('Y/m/d', strtotime(date('Y') . '/01/01 + 1year -1 day'))
+            ])
+        ];
+        $uidAll = UserModel::getAll($where);
+        $this->assign(compact('limitTimeList', 'uidAll'));
+        $this->assign(UserModel::systemPage($where));
+        return $this->fetch();
+    }
+
+    public function edit_user_tag($openid)
+    {
+        if (!$openid) return JsonService::fail('参数错误!');
+        $list = Collection::make(UserModel::getUserTag())->each(function ($item) {
+            return ['value' => $item['id'], 'label' => $item['name']];
+        });
+        $tagList = UserModel::where('openid', $openid)->value('tagid_list');
+
+        $tagList = explode(',', $tagList) ?: [];
+        $f = [Form::select('tag_id', '用户标签', $tagList)->setOptions($list->toArray())->multiple(1)];
+        $form = Form::make_post_form('标签名称', $f, Url::buildUrl('update_user_tag', compact('openid')));
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    public function update_user_tag($openid)
+    {
+        if (!$openid) return JsonService::fail('参数错误!');
+        $tagId = request()->post('tag_id/a', []);
+        if (!$tagId) return JsonService::fail('请选择用户标签!');
+        $tagList = explode(',', UserModel::where('openid', $openid)->value('tagid_list')) ?: [];
+        UserModel::edit(['tagid_list' => $tagId], $openid, 'openid');
+        if (!$tagId[0]) unset($tagId[0]);
+        UserModel::edit(['tagid_list' => $tagId], $openid, 'openid');
+        try {
+            foreach ($tagList as $tag) {
+                if ($tag) WechatService::userTagService()->batchUntagUsers([$openid], $tag);
+            }
+            foreach ($tagId as $tag) {
+                WechatService::userTagService()->batchTagUsers([$openid], $tag);
+            }
+        } catch (\Exception $e) {
+            UserModel::rollbackTrans();
+            return JsonService::fail($e->getMessage());
+        }
+        UserModel::commitTrans();
+        return JsonService::successful('修改成功!');
+    }
+
+    public function edit_user_group($openid)
+    {
+        if (!$openid) return JsonService::fail('参数错误!');
+        $list = Collection::make(UserModel::getUserGroup())->each(function ($item) {
+            return ['value' => $item['id'], 'label' => $item['name']];
+        });
+        $groupId = UserModel::where('openid', $openid)->value('groupid');
+        $f = [Form::select('group_id', '用户分组', (string)$groupId)->setOptions($list->toArray())];
+        $form = Form::make_post_form('用户分组', $f, Url::buildUrl('update_user_group', compact('openid')));
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    public function update_user_group($openid)
+    {
+        if (!$openid) return JsonService::fail('参数错误!');
+        $groupId = request()->post('group_id');
+//        if(!$groupId) return JsonService::fail('请选择用户分组!');
+        UserModel::beginTrans();
+        UserModel::edit(['groupid' => $groupId], $openid, 'openid');
+        try {
+            WechatService::userGroupService()->moveUser($openid, $groupId);
+        } catch (\Exception $e) {
+            UserModel::rollbackTrans();
+            return JsonService::fail($e->getMessage());
+        }
+        UserModel::commitTrans();
+        return JsonService::successful('修改成功!');
+    }
+
+    /**
+     * 用户标签列表
+     */
+    public function tag($refresh = 0)
+    {
+        $list = [];
+        if ($refresh == 1) {
+            UserModel::clearUserTag();
+            $this->redirect(Url::buildUrl('tag')->suffix(false)->build());
+        }
+        try {
+            $list = UserModel::getUserTag();
+        } catch (\Exception $e) {
+        }
+        $this->assign(compact('list'));
+        return $this->fetch();
+    }
+
+    /**
+     * 添加标签
+     * @return mixed
+     */
+    public function create_tag()
+    {
+        $f = [Form::input('name', '标签名称')];
+        $form = Form::make_post_form('标签名称', $f, Url::buildUrl('save_tag'));
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 添加
+     */
+    public function save_tag()
+    {
+        $tagName = request()->post('name');
+        if (!$tagName) return JsonService::fail('请输入标签名称!');
+        try {
+            WechatService::userTagService()->create($tagName);
+        } catch (\Exception $e) {
+            return JsonService::fail($e->getMessage());
+        }
+        UserModel::clearUserTag();
+        return JsonService::successful('添加标签成功!');
+    }
+
+    /**
+     * 修改标签
+     * @param $id
+     * @return mixed
+     */
+    public function edit_tag($id)
+    {
+        $f = [Form::input('name', '标签名称')];
+        $form = Form::make_post_form('标签名称', $f, Url::buildUrl('update_tag', ['id' => $id]));
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 修改标签
+     * @param $id
+     */
+    public function update_tag($id)
+    {
+        $tagName = request()->post('name');
+        if (!$tagName) return JsonService::fail('请输入标签名称!');
+        try {
+            WechatService::userTagService()->update($id, $tagName);
+        } catch (\Exception $e) {
+            return JsonService::fail($e->getMessage());
+        }
+        UserModel::clearUserTag();
+        return JsonService::successful('修改标签成功!');
+    }
+
+    /**
+     * 删除标签
+     * @param $id
+     * @return \think\response\Json
+     */
+    public function delete_tag($id)
+    {
+        try {
+            WechatService::userTagService()->delete($id);
+        } catch (\Exception $e) {
+            return JsonService::fail($e->getMessage());
+        }
+        UserModel::clearUserTag();
+        return JsonService::successful('删除标签成功!');
+    }
+
+    /**
+     * 用户分组列表
+     */
+
+    public function group($refresh = 0)
+    {
+        $list = [];
+        try {
+            if ($refresh == 1) {
+                UserModel::clearUserGroup();
+                $this->redirect(Url::buildUrl('group')->suffix(false)->build());
+            }
+            $list = UserModel::getUserGroup();
+        } catch (\Exception $e) {
+        }
+        $this->assign(compact('list'));
+        return $this->fetch();
+    }
+
+    /**
+     * 添加分组
+     * @return mixed
+     */
+    public function create_group()
+    {
+        $f = [Form::input('name', '分组名称')];
+        $form = Form::make_post_form('标签名称', $f, Url::buildUrl('save_group'));
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 添加
+     */
+    public function save_group()
+    {
+        $tagName = request()->post('name');
+        if (!$tagName) return JsonService::fail('请输入分组名称!');
+        try {
+            WechatService::userGroupService()->create($tagName);
+        } catch (\Exception $e) {
+            return JsonService::fail($e->getMessage());
+        }
+        UserModel::clearUserGroup();
+        return JsonService::successful('添加分组成功!');
+    }
+
+    /**
+     * 修改分组
+     * @param $id
+     * @return mixed
+     */
+    public function edit_group($id)
+    {
+        $f = [Form::input('name', '分组名称')];
+        $form = Form::make_post_form('标签名称', $f, Url::buildUrl('update_group', compact('id')));
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 修改分组
+     * @param $id
+     */
+    public function update_group($id)
+    {
+        $tagName = request()->post('name');
+        if (!$tagName) return JsonService::fail('请输入分组名称!');
+        try {
+            WechatService::userGroupService()->update($id, $tagName);
+        } catch (\Exception $e) {
+            return JsonService::fail($e->getMessage());
+        }
+        UserModel::clearUserGroup();
+        return JsonService::successful('修改分组成功!');
+    }
+
+    /**
+     * 删除分组
+     * @param $id
+     * @return \think\response\Json
+     */
+    public function delete_group($id)
+    {
+        try {
+            WechatService::userTagService()->delete($id);
+        } catch (\Exception $e) {
+            return JsonService::fail($e->getMessage());
+        }
+        UserModel::clearUserGroup();
+        return JsonService::successful('删除分组成功!');
+    }
+
+    public function synchro_tag($openid)
+    {
+        if (!$openid) return JsonService::fail('参数错误!');
+        $data = array();
+        if (UserModel::be($openid, 'openid')) {
+            try {
+                $tag = WechatService::userTagService()->userTags($openid)->toArray();
+            } catch (\Exception $e) {
+                return JsonService::fail($e->getMessage());
+            }
+            if ($tag['tagid_list']) $data['tagid_list'] = implode(',', $tag['tagid_list']);
+            else $data['tagid_list'] = '';
+            $res = UserModel::edit($data, $openid, 'openid');
+            if ($res) return JsonService::successful('同步成功');
+            else return JsonService::fail('同步失败!');
+        } else  return JsonService::fail('参数错误!');
+    }
+
+    /**
+     * 一级推荐人页面
+     * @return mixed
+     */
+    public function stair($uid = '')
+    {
+        if ($uid == '') return $this->failed('参数错误');
+        $list = User::alias('u')
+            ->where('u.spread_uid', $uid)
+            ->field('u.avatar,u.nickname,u.now_money,u.add_time,u.uid')
+            ->where('u.status', 1)
+            ->order('u.add_time DESC')
+            ->select()
+            ->toArray();
+        foreach ($list as $key => $value) $list[$key]['orderCount'] = StoreOrder::getOrderCount($value['uid']);
+        $this->assign('list', $list);
+        return $this->fetch();
+    }
+
+    /**
+     * 个人资金详情页面
+     * @return mixed
+     */
+    public function now_money($uid = '')
+    {
+        if ($uid == '') return $this->failed('参数错误');
+        $list = UserBill::where('uid', $uid)->where('category', 'now_money')
+            ->field('mark,pm,number,add_time')
+            ->where('status', 1)->order('add_time DESC')->select()->toArray();
+        foreach ($list as &$v) {
+            $v['add_time'] = date('Y-m-d H:i:s', $v['add_time']);
+        }
+        $this->assign('list', $list);
+        return $this->fetch();
+    }
+
+}
+

+ 7 - 0
app/admin/controller/wechat/index.php

@@ -0,0 +1,7 @@
+<?php
+/**
+ * Created by PhpStorm.
+ * User: Administrator
+ * Date: 2018/4/18 0018
+ * Time: 上午 10:44
+ */

+ 279 - 0
app/admin/controller/widget/Images.php

@@ -0,0 +1,279 @@
+<?php
+
+namespace app\admin\controller\widget;
+
+use app\admin\controller\AuthController;
+use think\facade\Route as Url;
+use app\admin\model\system\{
+    SystemAttachment as SystemAttachmentModel, SystemAttachmentCategory as Category
+};
+use crmeb\services\{JsonService as Json, JsonService, UtilService as Util, FormBuilder as Form};
+use crmeb\services\upload\Upload;
+
+/**
+ * TODO 附件控制器
+ * Class Images
+ * @package app\admin\controller\widget
+ */
+class Images extends AuthController
+{
+    /**
+     * 附件列表
+     * @return \think\response\Json
+     */
+    public function index()
+    {
+        $pid = request()->param('pid');
+        if ($pid === NULL) {
+            $pid = session('pid') ? session('pid') : 0;
+        }
+        session('pid', $pid);
+        $this->assign('pid', $pid);
+////       //TODO 分类标题
+//       $typearray = Category::getAll();
+//       $this->assign(compact('typearray'));
+//       $this->assign(SystemAttachmentModel::getAll($pid));
+        return $this->fetch('widget/images');
+    }
+
+    /**获取图片列表
+     *
+     */
+    public function get_image_list()
+    {
+        $where = Util::getMore([
+            ['page', 1],
+            ['limit', 18],
+            ['pid', 0]
+        ]);
+        $where['mer_id'] = $this->adminInfo['mer_id'];
+        return Json::successful(SystemAttachmentModel::getImageList($where));
+    }
+
+    /**获取分类
+     * @param string $name
+     */
+    public function get_image_cate($name = '')
+    {
+        return Json::successful(Category::getAll($name));
+    }
+
+    /**
+     * 图片管理上传图片
+     * @return \think\response\Json
+     */
+    public function upload()
+    {
+        $pid = $this->request->param('pid', session('pid'));
+        $upload_type = $this->request->get('upload_type', sys_config('upload_type', 1));
+        try {
+            $path = make_path('attach', 2, true);
+            $upload = new Upload((int)$upload_type, [
+                'accessKey' => sys_config('accessKey'),
+                'secretKey' => sys_config('secretKey'),
+                'uploadUrl' => sys_config('uploadUrl'),
+                'storageName' => sys_config('storage_name'),
+                'storageRegion' => sys_config('storage_region'),
+            ]);
+            $res = $upload->to($path)->validate()->move();
+            if ($res === false) {
+                return JsonService::fail('上传失败:' . $upload->getError());
+            } else {
+                $fileInfo = $upload->getUploadInfo();
+                if ($fileInfo) {
+                    SystemAttachmentModel::attachmentAdd($fileInfo['name'], $fileInfo['size'], $fileInfo['type'], $fileInfo['dir'], $fileInfo['thumb_path'], $pid, $upload_type, $fileInfo['time'], 1, $this->adminInfo['mer_id']);
+                }
+                return JsonService::successful('上传成功', ['src' => $res->filePath]);
+            }
+        } catch (\Exception $e) {
+            return JsonService::fail('上传失败:' . $e->getMessage());
+        }
+    }
+
+    /**
+     * ajax 提交删除
+     */
+    public function delete()
+    {
+        $request = app('request');
+        $post = $request->post();
+        if (empty($post['imageid']))
+            Json::fail('还没选择要删除的图片呢?');
+        foreach ($post['imageid'] as $v) {
+            if ($v) self::deleteimganddata($v);
+        }
+        Json::successful('删除成功');
+    }
+
+    /**删除图片和数据记录
+     * @param $att_id
+     */
+    public function deleteimganddata($att_id)
+    {
+
+        $attinfo = SystemAttachmentModel::get($att_id);
+        if ($attinfo) {
+            try {
+                $upload = new Upload((int)$attinfo['image_type'], [
+                    'accessKey' => sys_config('accessKey'),
+                    'secretKey' => sys_config('secretKey'),
+                    'uploadUrl' => sys_config('uploadUrl'),
+                    'storageName' => sys_config('storage_name'),
+                    'storageRegion' => sys_config('storage_region'),
+                ]);
+                if ($attinfo['image_type'] == 1) {
+                    if (strpos($attinfo['att_dir'], '/') == 0) {
+                        $attinfo['att_dir'] = substr($attinfo['att_dir'], 1);
+                    }
+                    $upload->delete($attinfo['att_dir']);
+                } else {
+                    $upload->delete($attinfo['name']);
+                }
+            } catch (\Throwable $e) {
+            }
+            SystemAttachmentModel::where('att_id', $att_id)->delete();
+        }
+    }
+
+    /**
+     * 移动图片分类显示
+     */
+    public function moveimg($imgaes)
+    {
+
+        $formbuider = [];
+        $formbuider[] = Form::hidden('imgaes', $imgaes);
+        $formbuider[] = Form::select('pid', '选择分类')->setOptions(function () {
+            $list = Category::getCateList();
+            $options = [['value' => 0, 'label' => '所有分类']];
+            foreach ($list as $id => $cateName) {
+                $options[] = ['label' => $cateName['html'] . $cateName['name'], 'value' => $cateName['id']];
+            }
+            return $options;
+        })->filterable(1);
+        $form = Form::make_post_form('编辑分类', $formbuider, Url::buildUrl('moveImgCecate'));
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 移动图片分类操作
+     */
+    public function moveImgCecate()
+    {
+        $data = Util::postMore([
+            'pid',
+            'imgaes'
+        ]);
+        if ($data['imgaes'] == '') return Json::fail('请选择图片');
+        if (!$data['pid']) return Json::fail('请选择分类');
+        $res = SystemAttachmentModel::where('att_id', 'in', $data['imgaes'])->update(['pid' => $data['pid']]);
+        if ($res)
+            Json::successful('移动成功');
+        else
+            Json::fail('移动失败!');
+    }
+
+    /**
+     * ajax 添加分类
+     */
+    public function addcate($id = 0)
+    {
+        $formbuider = [];
+        $formbuider[] = Form::select('pid', '上级分类', (string)$id)->setOptions(function () {
+            $list = Category::getCateList(0);
+            $options = [['value' => 0, 'label' => '所有分类']];
+            foreach ($list as $id => $cateName) {
+                $options[] = ['label' => $cateName['html'] . $cateName['name'], 'value' => $cateName['id']];
+            }
+            return $options;
+        })->filterable(1);
+        $formbuider[] = Form::input('name', '分类名称');
+        $jsContent = <<<SCRIPT
+parent.SuccessCateg();
+parent.layer.close(parent.layer.getFrameIndex(window.name));
+SCRIPT;
+        $form = Form::make_post_form('添加分类', $formbuider, Url::buildUrl('saveCate'), $jsContent);
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 添加分类
+     */
+    public function saveCate()
+    {
+        $request = app('request');
+        $post = $request->post();
+        $data['pid'] = $post['pid'];
+        $data['name'] = $post['name'];
+        if (empty($post['name']))
+            Json::fail('分类名称不能为空!');
+        $res = Category::create($data);
+        if ($res)
+            Json::successful('添加成功');
+        else
+            Json::fail('添加失败!');
+
+    }
+
+    /**
+     * 编辑分类
+     */
+    public function editcate($id)
+    {
+        $Category = Category::get($id);
+        if (!$Category) return Json::fail('数据不存在!');
+        $formbuider = [];
+        $formbuider[] = Form::hidden('id', $id);
+        $formbuider[] = Form::select('pid', '上级分类', (string)$Category->getData('pid'))->setOptions(function () use ($id) {
+            $list = Category::getCateList();
+            $options = [['value' => 0, 'label' => '所有分类']];
+            foreach ($list as $id => $cateName) {
+                $options[] = ['label' => $cateName['html'] . $cateName['name'], 'value' => $cateName['id']];
+            }
+            return $options;
+        })->filterable(1);
+        $formbuider[] = Form::input('name', '分类名称', $Category->getData('name'));
+        $jsContent = <<<SCRIPT
+parent.SuccessCateg();
+parent.layer.close(parent.layer.getFrameIndex(window.name));
+SCRIPT;
+        $form = Form::make_post_form('编辑分类', $formbuider, Url::buildUrl('updateCate'), $jsContent);
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 更新分类
+     * @param $id
+     */
+    public function updateCate($id)
+    {
+        $data = Util::postMore([
+            'pid',
+            'name'
+        ]);
+        if ($data['pid'] == '') return Json::fail('请选择父类');
+        if (!$data['name']) return Json::fail('请输入分类名称');
+        Category::edit($data, $id);
+        return Json::successful('分类编辑成功!');
+    }
+
+    /**
+     * 删除分类
+     */
+    public function deletecate($id)
+    {
+        $chdcount = Category::where('pid', $id)->count();
+        if ($chdcount) return Json::fail('有子栏目不能删除');
+        $chdcount = SystemAttachmentModel::where('pid', $id)->count();
+        if ($chdcount) return Json::fail('栏目内有图片不能删除');
+        if (Category::del($id))
+            return Json::successful('删除成功!');
+        else
+            return Json::fail('删除失败');
+
+
+    }
+}

+ 75 - 0
app/admin/controller/widget/Video.php

@@ -0,0 +1,75 @@
+<?php
+/**
+ * Created by PhpStorm.
+ * User: wuhaotian
+ * Date: 2020-02-24
+ * Time: 17:57
+ */
+
+namespace app\admin\controller\widget;
+
+use app\admin\controller\AuthController;
+use crmeb\services\JsonService;
+use crmeb\services\upload\Upload;
+use think\facade\Config;
+
+class Video extends AuthController
+{
+
+
+    /**
+     * 上传类型
+     * @var int
+     */
+    protected $uploadInfo;
+
+    /**
+     * 获取配置信息
+     * Video constructor.
+     */
+    public function initialize()
+    {
+        parent::initialize();
+        $this->uploadInfo['accessKey'] = sys_config('accessKey');
+        $this->uploadInfo['secretKey'] = sys_config('secretKey');
+        $this->uploadInfo['uploadUrl'] = sys_config('uploadUrl');
+        $this->uploadInfo['storageName'] = sys_config('storage_name');
+        $this->uploadInfo['storageRegion'] = sys_config('storage_region');
+        $this->uploadInfo['uploadType'] = sys_config('upload_type');
+    }
+
+    /**
+     * 获取密钥签名
+     */
+    public function get_signature()
+    {
+        if ($this->uploadInfo['uploadType'] == 1) {
+            if (!$this->uploadInfo['accessKey'] || !$this->uploadInfo['secretKey']) {
+                return JsonService::fail('视频上传需要上传到云端,默认使用阿里云OSS上传请配置!');
+            } else {
+                $this->uploadInfo['uploadType'] = 3;
+            }
+        }
+        if ($this->uploadInfo['uploadType'] == 2) {
+            $upload = new Upload('Qiniu', $this->uploadInfo);
+            $res = $upload->getSystem();
+            $this->uploadInfo['uploadToken'] = $res['token'];
+            $this->uploadInfo['domain'] = $res['domain'];
+            $this->uploadInfo['uploadType'] = 'QINIU';
+        } elseif ($this->uploadInfo['uploadType'] == 3) {
+            $this->uploadInfo['uploadType'] = 'OSS';
+            if (($leng = strpos($this->uploadInfo['storageRegion'], 'aliyuncs.com')) !== false) {
+                $this->uploadInfo['storageRegion'] = substr($this->uploadInfo['storageRegion'], 0, $leng - 1);
+            }
+        } elseif ($this->uploadInfo['uploadType'] == 4) {
+            $this->uploadInfo['uploadType'] = 'COS';
+        }
+        return JsonService::successful($this->uploadInfo);
+    }
+
+    public function index($fodder = '')
+    {
+        $this->assign(compact('fodder'));
+        return $this->fetch();
+    }
+}

+ 53 - 0
app/admin/controller/widget/Widgets.php

@@ -0,0 +1,53 @@
+<?php
+
+namespace app\admin\controller\widget;
+
+use app\admin\controller\AuthController;
+
+/**
+ * 文件校验控制器
+ * Class SystemFile
+ * @package app\admin\controller\system
+ *
+ */
+class Widgets extends AuthController
+{
+
+    /**
+     * icon
+     * @return \think\response\Json
+     */
+    public function icon()
+    {
+        return $this->fetch('widget/icon');
+    }
+
+    /**
+     * 会员列页面
+     * @return \think\response\Json
+     */
+    public function userlist()
+    {
+        return $this->fetch('widget/icon');
+    }
+
+    /**
+     * 产品列表页
+     * @return \think\response\Json
+     */
+    public function productlist()
+    {
+        return $this->fetch('widget/icon');
+    }
+
+    /**
+     * 图文列表页
+     * @return \think\response\Json
+     */
+    public function newtlist()
+    {
+        return $this->fetch('widget/icon');
+    }
+
+
+}

+ 21 - 0
app/admin/event.php

@@ -0,0 +1,21 @@
+<?php
+// +----------------------------------------------------------------------
+// | ThinkPHP [ WE CAN DO IT JUST THINK ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
+// +----------------------------------------------------------------------
+// | Author: liu21st <liu21st@gmail.com>
+// +----------------------------------------------------------------------
+
+// 事件定义文件
+return [
+    'listen'    => [
+        'AppInit'  => [],
+        'HttpRun'  => [],
+        'HttpEnd'  => [],
+        'LogLevel' => [],
+        'LogWrite' => [],
+    ]
+];

+ 50 - 0
app/admin/logic/BaseLogic.php

@@ -0,0 +1,50 @@
+<?php
+/**
+ * Created by Administrator.
+ * User: 向往那片天空
+ * Date: 2022\5\21 0021
+ * Time: 12:57
+ * 格言: 抓住中心,宁精勿杂,宁专勿多
+ * QQ/微信: 250023777
+ * 描述: 无
+ */
+
+namespace app\admin\logic;
+
+
+use app\admin\model\system\SystemAdmin;
+use crmeb\basic\BaseModel;
+use crmeb\traits\ModelTrait;
+use crmeb\services\JsonService;
+use think\facade\Route as Url;
+
+class BaseLogic extends BaseModel
+{
+    protected $adminInfo;
+
+    public function __construct(array $data = [])
+    {
+        parent::__construct($data);
+        if (!SystemAdmin::hasActiveAdmin()) return $this->redirect(Url::buildUrl('login/index')->suffix(false)->build());
+        try {
+            $adminInfo = SystemAdmin::activeAdminInfoOrFail();
+        } catch (\Exception $e) {
+            return $this->failed(SystemAdmin::getErrorInfo($e->getMessage()), Url::buildUrl('login/index')->suffix(false)->build());
+        }
+        $this->adminInfo = $adminInfo;
+    }
+
+    public function delById($id)
+    {
+        $res = self::update([
+            'id' => $id,
+            'is_delete' => '1',
+        ]);
+
+        if (empty($res)) {
+            return JsonService::fail('删除失败');
+        }
+
+        return JsonService::successful('删除成功');
+    }
+}

+ 138 - 0
app/admin/logic/enterprise/ApplyLogic.php

@@ -0,0 +1,138 @@
+<?php
+/**
+ * Created by Administrator.
+ * User: 向往那片天空
+ * Date: 2022\5\21 0021
+ * Time: 15:11
+ * 格言: 抓住中心,宁精勿杂,宁专勿多
+ * QQ/微信: 250023777
+ * 描述: 无
+ */
+
+namespace app\admin\logic\enterprise;
+
+
+use app\admin\logic\BaseLogic;
+use app\admin\model\user\User;
+use crmeb\services\JsonService;
+use crmeb\traits\ModelTrait;
+
+class ApplyLogic extends BaseLogic
+{
+    use ModelTrait;
+
+    protected $pk = 'id';
+    protected $name = 'user_apply_enterprise_record';
+
+    public function getPageList($where)
+    {
+        $model = self::where('t1.is_delete', '0');
+        if ($where['audit_status'] != -1) {
+            $model = $model->where('t1.audit_status', $where['audit_status']);
+        }
+        if (!empty($where['mer_id'])) {
+            $model = $model->where('t1.mer_id', $where['mer_id']);
+        }
+        if (!empty($where['apply_user_name'])) {
+            $model = $model->where('t1.apply_user_name', 'like', '%' . $where['apply_user_name'] . '%');
+        }
+
+        $list = $model->field('t1.*,t2.job_name,t3.name as companyName')->alias('t1')->leftJoin('job t2', 't1.apply_job_id=t2.id')->join('enterprise_user t3', 't1.mer_id=t3.id')->page($where['page'], $where['limit'])->order('t1.add_time desc')->select()->toArray();
+
+        $count = count($list);
+        // 通过行业Id获取行业名
+        foreach ($list as &$v) {
+            $v['add_time'] = date('Y-m-d H:i:s', $v['add_time']);
+        }
+        return JsonService::successlayui(['count' => $count, 'data' => $list]);
+    }
+
+    public function audit($data)
+    {
+        $find = self::get($data['id']);
+
+        if (empty($find)) {
+            return JsonService::fail('找不到记录');
+        }
+
+        if ($find['audit_status'] !== 0) {
+            return JsonService::fail('已经审核过');
+        }
+
+
+        $user = User::get($find['apply_user_id']);
+        if (empty($user)) {
+            return JsonService::fail('找不到申请用户');
+        }
+        if (!empty($user['mer_id'])) {
+            return JsonService::fail('用户已经加入过企业');
+        }
+
+        $id = $data['id'];
+        unset($data['id']);
+        $data['audit_admin_id'] = $this->adminInfo['id'];
+        $data['audit_time'] = time();
+        $data['audit_status'] = intval($data['audit_status']);
+        if ($data['audit_status'] == 1) {
+            $data['pass_text'] = $data['text'];
+        } else if ($data['audit_status'] == 2) {
+            $data['fail_text'] = $data['text'];
+        } else {
+            return JsonService::fail('非法操作');
+        }
+
+        if (!self::edit($data, $id)) {
+            return JsonService::fail('审核失败');
+        }
+
+        //更新用户
+        if ($data['audit_status'] == 1) {
+            $updateUser = [];
+            $updateUser['mer_id'] = $find['mer_id'];
+
+            if (!User::edit($updateUser, $find['apply_user_id'])) {
+                return JsonService::fail('关联用户失败');
+            }
+        }
+
+        return JsonService::successful('审核成功');
+    }
+
+    /**
+     * 用户是否有正在审核的记录
+     * @param $userId 用户
+     * @return bool true-有,false-无
+     */
+    public function hasApllying($userId)
+    {
+        $query = [];
+        $query['apply_user_id'] = $userId;
+        $query['is_delete'] = '0';
+        $query['audit_status'] = 0;
+
+        return self::be($query);
+    }
+
+    public function getEmployeeList($where)
+    {
+        $model = self::where('t1.is_delete', '0');
+        if ($where['audit_status'] != -1) {
+            $model = $model->where('t1.audit_status', $where['audit_status']);
+        }
+        if (!empty($where['mer_id'])) {
+            $model = $model->where('t4.mer_id', $where['mer_id']);
+        }
+        if (!empty($where['apply_user_name'])) {
+            $model = $model->where('t1.apply_user_name', 'like', '%' . $where['apply_user_name'] . '%');
+        }
+
+        $list = $model->field('t1.*,t2.job_name,t3.name as companyName')->alias('t1')->leftJoin('job t2', 't1.apply_job_id=t2.id')->join('enterprise_user t3', 't1.mer_id=t3.id')->join('user t4', 't1.apply_user_id=t4.uid')->page($where['page'], $where['limit'])->order('t1.add_time desc')->select()->toArray();
+
+        $count = count($list);
+        // 通过行业Id获取行业名
+        foreach ($list as &$v) {
+            $v['add_time'] = date('Y-m-d H:i:s', $v['add_time']);
+        }
+        return JsonService::successlayui(['count' => $count, 'data' => $list]);
+    }
+}

+ 102 - 0
app/admin/logic/enterprise/JobLogic.php

@@ -0,0 +1,102 @@
+<?php
+/**
+ * Created by Administrator.
+ * User: 向往那片天空
+ * Date: 2022\5\21 0021
+ * Time: 11:33
+ * 格言: 抓住中心,宁精勿杂,宁专勿多
+ * QQ/微信: 250023777
+ * 描述: 无
+ */
+
+namespace app\admin\logic\enterprise;
+
+
+use app\admin\controller\AuthController;
+use app\admin\model\enterprise\EnterPriseType as Type;
+use app\admin\model\system\SystemAdmin;
+use app\admin\logic\BaseLogic;
+use crmeb\exceptions\AuthException;
+use crmeb\services\JsonService;
+use crmeb\traits\ModelTrait;
+use think\facade\Db;
+use think\facade\Route as Url;
+
+class JobLogic extends \app\admin\logic\BaseLogic
+{
+    use ModelTrait;
+
+    protected $pk = 'id';
+    protected $name = 'job';
+
+    public function toggleIsShow($id)
+    {
+        $find = self::find($id);
+        if (empty($find)) {
+            return JsonService::fail('找不到记录');
+        }
+
+        $res = self::update([
+            'id' => $id,
+            'is_show' => $find['is_show'] == 1 ? 0 : 1,
+            'update_time' => time(),
+            'update_admin_id' => $this->adminInfo['id']
+        ]);
+
+        if (empty($res)) {
+            return JsonService::fail('操作失败');
+        }
+
+        return JsonService::successful('操作成功');
+    }
+
+    public function getPageList($where)
+    {
+        $query = [];
+        $query['is_delete'] = '0';
+        if ($where['is_show'] != -1) {
+            $query['is_show'] = $where['is_show'];
+        }
+        $list = self::where($query)->page($where['page'], $where['limit'])->order('rank desc,add_time desc')->select()->toArray();
+
+        $count = count($list);
+        // 通过行业Id获取行业名
+        foreach ($list as &$v) {
+            $v['add_time'] = date('Y-m-d H:i:s', $v['add_time']);
+        }
+        return JsonService::successlayui(['count' => $count, 'data' => $list]);
+    }
+
+    public function add($data)
+    {
+        $data['add_admin_id'] = $this->adminInfo['id'];
+        $data['add_time'] = time();
+
+        $res = self::insert($data);
+
+        if (empty($res)) {
+            return JsonService::fail('添加失败');
+        }
+
+        return JsonService::successful('添加成功');
+    }
+
+    public function edit($data)
+    {
+        $data['update_admin_id'] = $this->adminInfo['id'];
+        $data['edit_time'] = time();
+
+        $res = self::update($data);
+
+        if (empty($res)) {
+            return JsonService::fail('修改失败');
+        }
+
+        return JsonService::successful('修改成功');
+    }
+
+    public function getList($where)
+    {
+        return self::where($where)->order('rank desc,add_time desc')->select()->toArray();
+    }
+}

+ 164 - 0
app/admin/model/article/Article.php

@@ -0,0 +1,164 @@
+<?php
+
+/**
+ *
+ * @author: xaboy<365615158@qq.com>
+ * @day: 2017/11/02
+ */
+
+namespace app\admin\model\article;
+
+use app\admin\model\store\StoreProduct;
+use app\admin\model\system\SystemAdmin;
+use app\models\article\ArticleContent;
+use crmeb\traits\ModelTrait;
+use crmeb\basic\BaseModel;
+
+/**
+ * 图文管理 Model
+ * Class WechatNews
+ * @package app\admin\model\wechat
+ */
+class Article extends BaseModel
+{
+
+    use ModelTrait;
+
+    protected $pk = 'id';
+
+    protected $name = 'article';
+
+    public function profile()
+    {
+        return $this->hasOne(StoreProduct::class, 'id', 'product_id')->field('store_name');
+    }
+
+    /**
+     * 获取配置分类
+     * @param array $where
+     * @return array
+     */
+    public static function getAll($where = [])
+    {
+        $model = new self;
+        if ($where['title'] !== '') $model = $model->where('title', 'LIKE', "%$where[title]%");
+        if ($where['cid'] !== '')
+            $model = $model->where('cid', 'in', $where['cid']);
+     
+        if ($where['merchant'] !=0){
+            $model = $model->where('mer_id', $where['merchant']);
+    
+            }
+			$model = $model->where('status', 1)->where('hide', 0)->order('add_time desc');
+        return self::page($model, function ($item) {
+            if (!$item['mer_id']) $item['admin_name'] = '总后台管理员---》' . SystemAdmin::where('id', $item['admin_id'])->value('real_name');
+            else $item['admin_name'] = '卫视门店';
+            $item['content'] = ArticleContent::where('nid', $item['id'])->value('content');
+            $item['catename'] = ArticleCategory::where('id', $item['cid'])->value('title');
+            $item['image_input'] = explode(',', $item['image_input']);
+        }, $where);
+    }
+
+    /**
+     * 删除图文
+     * @param $id
+     * @return bool
+     */
+    public static function del($id)
+    {
+        return self::edit(['status' => 0], $id, 'id');
+    }
+
+    /**
+     * 获取指定字段的值
+     * @return array
+     */
+    public static function getNews()
+    {
+        return self::where('status', 1)->where('hide', 0)->order('id desc')->column('title', 'id');
+    }
+
+    /**
+     * 给表中的字符串类型追加值
+     * 删除所有有当前分类的id之后重新添加
+     * @param $cid
+     * @param $id
+     * @return bool
+     */
+    public static function saveBatchCid($cid, $id)
+    {
+        $res_all = self::where('cid', 'LIKE', "%$cid%")->select();//获取所有有当前分类的图文
+        foreach ($res_all as $k => $v) {
+            $cid_arr = explode(',', $v['cid']);
+            if (in_array($cid, $cid_arr)) {
+                $key = array_search($cid, $cid_arr);
+                array_splice($cid_arr, $key, 1);
+            }
+            if (empty($cid_arr)) {
+                $data['cid'] = 0;
+                self::edit($data, $v['id']);
+            } else {
+                $data['cid'] = implode(',', $cid_arr);
+                self::edit($data, $v['id']);
+            }
+        }
+        $res = self::where('id', 'IN', $id)->select();
+        foreach ($res as $k => $v) {
+            if (!in_array($cid, explode(',', $v['cid']))) {
+                if (!$v['cid']) {
+                    $data['cid'] = $cid;
+                } else {
+                    $data['cid'] = $v['cid'] . ',' . $cid;
+                }
+                self::edit($data, $v['id']);
+            }
+        }
+        return true;
+    }
+
+    public static function setContent($id, $content)
+    {
+        $count = ArticleContent::where('nid', $id)->count();
+        $data['nid'] = $id;
+        $data['content'] = $content;
+        if ($count) {
+            $contentSql = ArticleContent::where('nid', $id)->value('content');
+            if ($contentSql == $content) $res = true;
+            else $res = ArticleContent::where('nid', $id)->update(['content' => $content]);
+            if ($res !== false) $res = true;
+        } else {
+            $res = ArticleContent::insert($data);
+        }
+        return $res;
+    }
+
+    public static function merchantPage($where = [])
+    {
+        $model = new self;
+        if ($where['title'] !== '') $model = $model->where('title', 'LIKE', "%$where[title]%");
+        if ($where['cid'] !== '') $model = $model->where('cid', 'LIKE', "%$where[cid]%");
+        $model = $model
+            ->where('status', 1)
+            ->where('hide', 0)
+            ->where('admin_id', $where['admin_id'])
+            ->where('mer_id', $where['mer_id']);
+        return self::page($model, function ($item) {
+            $item['content'] = ArticleContent::where('nid', $item['id'])->value('content');
+        }, $where);
+    }
+
+    /**
+     * 获取指定文章列表  图文管理使用
+     * @param string $id
+     * @param string $field
+     * @return false|\PDOStatement|string|\think\Collection
+     */
+    public static function getArticleList($id = '', $field = 'title,author,image_input,synopsis,id')
+    {
+        $list = self::where('id', 'IN', $id)->field($field)->select();
+        foreach ($list as $k => $v) {
+            $list[$k]['content'] = ArticleContent::where('nid', $v['id'])->value('content');
+        }
+        return $list;
+    }
+}

+ 121 - 0
app/admin/model/article/ArticleCategory.php

@@ -0,0 +1,121 @@
+<?php
+/**
+ *
+ * @author: xaboy<365615158@qq.com>
+ * @day: 2017/11/02
+ */
+
+namespace app\admin\model\article;
+
+use crmeb\traits\ModelTrait;
+use crmeb\basic\BaseModel;
+use app\admin\model\article\Article as ArticleModel;
+
+/**
+ * 文章分类model
+ * Class ArticleCategory
+ * @package app\admin\model\wechat
+ */
+class ArticleCategory extends BaseModel
+{
+    use ModelTrait;
+
+    protected $pk = 'id';
+
+    protected $name = 'article_category';
+
+    /**
+     * 获取系统分页数据   分类
+     * @param array $where
+     * @return array
+     */
+    public static function systemPage($where = [])
+    {
+        $model = new self;
+        if ($where['title'] !== '') $model = $model->where('title', 'LIKE', "%$where[title]%");
+        if ($where['status'] !== '') $model = $model->where('status', $where['status']);
+        $model = $model->where('is_del', 0);
+        $model = $model->where('hidden', 0);
+        return self::page($model);
+    }
+
+    /**
+     * 删除分类
+     * @param $id
+     * @return bool
+     */
+    public static function delArticleCategory($id)
+    {
+        if (count(self::getArticle($id, '*')) > 0)
+            return self::setErrorInfo('请先删除改分类下的文章!');
+        return self::edit(['is_del' => 1], $id, 'id');
+    }
+
+    /**
+     * 获取分类名称和id
+     * @return array
+     */
+    public static function getField()
+    {
+        return self::where('is_del', 0)->where('status', 1)->where('hidden', 0)->column('title', 'id');
+    }
+
+    /**
+     * 分级排序列表
+     * @param null $model
+     * @return array
+     */
+    public static function getTierList($model = null)
+    {
+        if ($model === null) $model = new self();
+        return sort_list_tier($model->where('is_del', 0)->where('status', 1)->select()->toArray());
+    }
+
+    /**
+     * 获取分类底下的文章
+     * id  分类表中的分类id
+     * return array
+     * */
+    public static function getArticle($id, $field)
+    {
+        $res     = ArticleModel::where('status', 1)->where('hide', 0)->column($field, 'id');
+        $new_res = array();
+        foreach ($res as $k => $v) {
+            $cid_arr = explode(',', $v['cid']);
+            if (in_array($id, $cid_arr)) {
+                $new_res[$k] = $res[$k];
+            }
+        }
+        return $new_res;
+    }
+
+    /**
+     * TODO 获取文章分类
+     * @return array
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public static function getArticleCategoryList()
+    {
+        $list = self::where('is_del', 0)->where('status', 1)->select();
+        if ($list) return $list->toArray();
+        return [];
+    }
+
+    /**
+     * TODO 获取文章分类信息
+     * @param $id
+     * @param string $field
+     * @return mixed
+     */
+    public static function getArticleCategoryInfo($id, $field = 'title')
+    {
+        $model = new self;
+        if ($id) $model = $model->where('id', $id);
+        $model = $model->where('is_del', 0);
+        $model = $model->where('status', 1);
+        return $model->column($field, 'id');
+    }
+
+}

+ 61 - 0
app/admin/model/article/ArticleReply.php

@@ -0,0 +1,61 @@
+<?php
+
+/**
+ *
+ * @author: xaboy<365615158@qq.com>
+ * @day: 2017/11/02
+ */
+
+namespace app\admin\model\article;
+
+use app\admin\model\store\StoreProduct;
+use app\admin\model\system\SystemAdmin;
+use app\models\article\ArticleContent;
+use crmeb\traits\ModelTrait;
+use crmeb\basic\BaseModel;
+
+/**
+ * 图文管理 Model
+ * Class WechatNews
+ * @package app\admin\model\wechat
+ */
+class ArticleReply extends BaseModel
+{
+
+    use ModelTrait;
+
+    protected $pk = 'id';
+
+    protected $name = 'article_reply';
+
+
+    public static function list($where, $id)
+    {
+        $list = ArticleReply::alias('a')
+            ->order('id DESC')
+            ->field('a.*,u.nickname,u.avatar')
+            ->leftJoin('user u', 'u.uid = a.uid')
+            ->where('a.aid', $id);
+        if (!empty($where['title'])) $list->where('u.nickname', 'like', '%'.$where['title'].'%');
+
+        $where['id'] = $id;
+        return self::page($list, function ($item) {
+            if ($item){
+                $item['to_name'] = [];
+                $item['to_content'] = [];
+                if (!empty($item['to_id'])){
+                    $article =  ArticleReply::alias('a')
+                        ->field('u.nickname,a.content')
+                        ->leftJoin('user u', 'u.uid = a.uid')
+                        ->where('a.id', $item['to_id'])->find();
+                    $item['to_name'] = $article['nickname'];
+                    $item['to_content'] = $article['content'];
+                }
+                if (empty($item['nickname'])) $item['nickname'] = '管理';
+
+            }
+        }, $where);
+
+    }
+
+}

+ 130 - 0
app/admin/model/enterprise/EnterCategory.php

@@ -0,0 +1,130 @@
+<?php
+/**
+ *
+ * @author: xaboy<365615158@qq.com>
+ * @day: 2017/11/02
+ */
+
+namespace app\admin\model\enterprise;
+
+use crmeb\traits\ModelTrait;
+use crmeb\basic\BaseModel;
+use app\admin\model\article\Article as ArticleModel;
+
+/**
+ * 企业分类model
+ * Class EnterCategory
+ * @package app\admin\model\wechat
+ */
+class EnterCategory extends BaseModel
+{
+    use ModelTrait;
+
+    protected $pk = 'id';
+
+    protected $name = 'enterprise_type';
+
+    /**
+     * 获取系统分页数据   分类
+     * @param array $where
+     * @return array
+     */
+    public static function systemPage($where = [])
+    {
+        $model = new self;
+        if ($where['title'] !== '') $model = $model->where('title', 'LIKE', "%$where[title]%");
+        if ($where['status'] !== '') $model = $model->where('status', $where['status']);
+        $model = $model->where('is_del', 0);
+        $model = $model->where('hidden', 0);
+        return self::page($model);
+    }
+
+    /**
+     * 删除分类
+     * @param $id
+     * @return bool
+     */
+    public static function delArticleCategory($id)
+    {
+        if (count(self::getArticle($id, '*')) > 0)
+            return self::setErrorInfo('请先删除该类型下的企业!');
+        return self::edit(['is_del' => 1], $id, 'id');
+    }
+
+    /**
+     * 获取分类名称和id
+     * @return array
+     */
+    public static function getField()
+    {
+        return self::where('is_del', 0)->where('status', 1)->where('hidden', 0)->column('title', 'id');
+    }
+
+    /**
+     * 分级排序列表
+     * @param null $model
+     * @return array
+     */
+    public static function getTierList($model = null)
+    {
+        if ($model === null) $model = new self();
+        return sort_list_tier($model->where('is_del', 0)->where('status', 1)->select()->toArray());
+    }
+/**
+     * 第三方分级排序列表
+     * @param null $model
+     * @return array
+     */
+    public static function getTierLists($model = null)
+    {
+        if ($model === null) $model = new self();
+        return sort_list_tier($model->where('is_del', 0)->where('status', 1)->where('is_type',1)->select()->toArray());
+    }
+    /**
+     * 获取分类底下的企业
+     * id  分类表中的分类id
+     * return array
+     * */
+    public static function getArticle($id, $field)
+    {
+        $res     = ArticleModel::where('status', 1)->where('hide', 0)->column($field, 'id');
+        $new_res = array();
+        foreach ($res as $k => $v) {
+            $cid_arr = explode(',', $v['cid']);
+            if (in_array($id, $cid_arr)) {
+                $new_res[$k] = $res[$k];
+            }
+        }
+        return $new_res;
+    }
+
+    /**
+     * TODO 获取文章分类
+     * @return array
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public static function getArticleCategoryList()
+    {
+        $list = self::where('is_del', 0)->where('status', 1)->select();
+        if ($list) return $list->toArray();
+        return [];
+    }
+
+    /**
+     * TODO 获取文章分类信息
+     * @param $id
+     * @param string $field
+     * @return mixed
+     */
+    public static function getArticleCategoryInfo($id, $field = 'title')
+    {
+        $model = new self;
+        if ($id) $model = $model->where('id', $id);
+        $model = $model->where('is_del', 0);
+        $model = $model->where('status', 1);
+        return $model->column($field, 'id');
+    }
+
+}

+ 27 - 0
app/admin/model/enterprise/EnterPriseType.php

@@ -0,0 +1,27 @@
+<?php
+namespace app\admin\model\enterprise;
+use crmeb\traits\ModelTrait;
+use crmeb\basic\BaseModel;
+use think\facade\Session;
+
+/**
+ * Class EnterPriseType
+ * @package app\admin\model\enterprise
+ */
+class EnterPriseType extends BaseModel
+{
+    /**
+     * 数据表主键
+     * @var string
+     */
+    protected $pk = 'id';
+
+    /**
+     * 模型名称
+     * @var string
+     */
+    protected $name = 'enterprise_type';
+
+    use ModelTrait;
+
+}

+ 63 - 0
app/admin/model/enterprise/EnterPriseUser.php

@@ -0,0 +1,63 @@
+<?php
+namespace app\admin\model\enterprise;
+use crmeb\traits\ModelTrait;
+use crmeb\basic\BaseModel;
+use think\facade\Session;
+use app\admin\model\enterprise\EnterPriseType as Type;
+
+/**
+ * Class EnterPriseUser
+ * @package app\admin\model\enterprise
+ */
+class EnterPriseUser extends BaseModel
+{
+    /**
+     * 数据表主键
+     * @var string
+     */
+    protected $pk = 'id';
+
+    /**
+     * 模型名称
+     * @var string
+     */
+    protected $name = 'enterprise_user';
+
+    use ModelTrait;
+	
+	// 认证列表
+	public static function authlist($where){
+		$list=self::where('is_auth',1)->page($where['page'],$where['limit'])->select();
+		$count=count($list);
+		// 通过行业Id获取行业名
+		foreach($list as &$v){
+		  $res=Type::where('id',$v['type'])->find();
+		  $v['type']=$res['title'];
+		}
+		return ['count' => $count, 'data' =>$list];	
+	} 
+ 
+  // 企业列表
+  public static function lists($where){
+  	$list=self::where('is_auth',2)->where('is_dle',0)->page($where['page'],$where['limit'])->select();
+  	$count=count($list);
+  	// 通过行业Id获取行业名
+  	foreach($list as &$v){
+  	  $res=Type::where('id',$v['type'])->find();
+  	  $v['type']=$res['title'];
+  	}
+  	return ['count' => $count, 'data' =>$list];	
+  } 
+  // 获取第三方企业列表
+    public static function merlst(){
+        $Type=Type::where('is_type',1)->select();
+        $lists=[];
+        foreach ($Type as $v){
+            // 通过获取到的id查企业
+            $list=self::where('type',$v['id'])->select();
+            foreach ($list as $k )
+            $lists[]=$k['name'];
+        }
+        return $lists;
+    }
+}

+ 174 - 0
app/admin/model/system/SystemAdmin.php

@@ -0,0 +1,174 @@
+<?php
+/**
+ * @author: xaboy<365615158@qq.com>
+ * @day: 2017/11/11
+ */
+
+namespace app\admin\model\system;
+
+use crmeb\traits\ModelTrait;
+use crmeb\basic\BaseModel;
+use think\facade\Session;
+
+/**
+ * Class SystemAdmin
+ * @package app\admin\model\system
+ */
+class SystemAdmin extends BaseModel
+{
+    /**
+     * 数据表主键
+     * @var string
+     */
+    protected $pk = 'id';
+
+    /**
+     * 模型名称
+     * @var string
+     */
+    protected $name = 'system_admin';
+
+    use ModelTrait;
+
+    protected $insert = ['add_time'];
+
+    public static function setAddTimeAttr($value)
+    {
+        return time();
+    }
+
+    public static function setRolesAttr($value)
+    {
+        return is_array($value) ? implode(',', $value) : $value;
+    }
+
+
+    /**
+     * 用户登陆
+     * @param $account
+     * @param $pwd
+     * @return bool
+     */
+    public static function login($account, $pwd)
+    {
+        $adminInfo = self::get(compact('account'));
+        if (!$adminInfo) return self::setErrorInfo('登陆的账号不存在!');
+        if ($adminInfo['pwd'] != md5(md5($pwd) . md5($adminInfo['salt']))) return self::setErrorInfo('账号或密码错误,请重新输入');
+        if (!$adminInfo['status']) return self::setErrorInfo('该账号已被关闭!');
+        self::setLoginInfo($adminInfo);
+        event('SystemAdminLoginAfter', [$adminInfo]);
+        return true;
+    }
+
+    /**
+     *  保存当前登陆用户信息
+     */
+    public static function setLoginInfo($adminInfo)
+    {
+        Session::set('adminId', $adminInfo['id']);
+        Session::set('adminInfo', $adminInfo->toArray());
+        Session::save();
+    }
+
+    /**
+     * 清空当前登陆用户信息
+     */
+    public static function clearLoginInfo()
+    {
+        Session::delete('adminInfo');
+        Session::delete('adminId');
+        Session::save();
+    }
+
+    /**
+     * 检查用户登陆状态
+     * @return bool
+     */
+    public static function hasActiveAdmin()
+    {
+        return Session::has('adminId') && Session::has('adminInfo');
+    }
+
+    /**
+     * 获得登陆用户信息
+     * @return mixed
+     * @throws \Exception
+     */
+    public static function activeAdminInfoOrFail()
+    {
+        $adminInfo = Session::get('adminInfo');
+        if (!$adminInfo) exception('请登陆');
+        if (!$adminInfo['status']) exception('该账号已被关闭!');
+        return $adminInfo;
+    }
+
+    /**
+     * 获得登陆用户Id 如果没有直接抛出错误
+     * @return mixed
+     * @throws \Exception
+     */
+    public static function activeAdminIdOrFail()
+    {
+        $adminId = Session::get('adminId');
+        if (!$adminId) exception('访问用户为登陆登陆!');
+        return $adminId;
+    }
+
+    /**
+     * @return array|null
+     * @throws \Exception
+     */
+    public static function activeAdminAuthOrFail()
+    {
+        $adminInfo = self::activeAdminInfoOrFail();
+        if (is_object($adminInfo)) $adminInfo = $adminInfo->toArray();
+        return $adminInfo['level'] === 0 ? SystemRole::getAllAuth() : SystemRole::rolesByAuth($adminInfo['roles']);
+    }
+
+    /**
+     * 获得有效管理员信息
+     * @param $id
+     * @return mixed
+     * @throws \Exception
+     */
+    public static function getValidAdminInfoOrFail($id)
+    {
+        $adminInfo = self::get($id);
+        if (!$adminInfo) exception('用户不能存在!');
+        if (!$adminInfo['status']) exception('该账号已被关闭!');
+        return $adminInfo;
+    }
+
+    /**
+     * @param string $field
+     * @param int $level
+     * @return \think\Collection
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public static function getOrdAdmin($field = 'real_name,id', $level = 0)
+    {
+        return self::where('level', '>=', $level)->field($field)->select();
+    }
+
+    public static function getTopAdmin($field = 'real_name,id')
+    {
+        return self::where('level', 0)->field($field)->select();
+    }
+
+    /**
+     * @param $where
+     * @return array
+     */
+    public static function systemPage($where)
+    {
+        $model = new self;
+        if ($where['name'] != '') $model = $model->where('account|real_name', 'LIKE', "%$where[name]%");
+        if ($where['roles'] != '') $model = $model->where("CONCAT(',',roles,',')  LIKE '%,$where[roles],%'");
+        $model = $model->where('level', $where['level'])->where('is_del', 0);
+        return self::page($model, function ($admin) {
+            $admin->roles = SystemRole::where('id', 'IN', $admin->roles)->column('role_name', 'id');
+        }, $where);
+    }
+}

+ 147 - 0
app/admin/model/system/SystemAttachment.php

@@ -0,0 +1,147 @@
+<?php
+/**
+ * @author: xaboy<365615158@qq.com>
+ * @day: 2017/11/13
+ */
+
+namespace app\admin\model\system;
+
+use crmeb\traits\ModelTrait;
+use crmeb\basic\BaseModel;
+
+/**
+ * 文件检验model
+ * Class SystemFile
+ * @package app\admin\model\system
+ */
+class SystemAttachment extends BaseModel
+{
+
+    /**
+     * 数据表主键
+     * @var string
+     */
+    protected $pk = 'att_id';
+
+    /**
+     * 模型名称
+     * @var string
+     */
+    protected $name = 'system_attachment';
+
+    use ModelTrait;
+
+    /**
+     * TODO 添加附件记录
+     * @param $name
+     * @param $att_size
+     * @param $att_type
+     * @param $att_dir
+     * @param string $satt_dir
+     * @param int $pid
+     * @param int $imageType
+     * @param int $time
+     * @return SystemAttachment
+     */
+    public static function attachmentAdd($name, $att_size, $att_type, $att_dir, $satt_dir = '', $pid = 0, $imageType = 1, $time = 0, $module_type = 1, $mer_id = 0)
+    {
+        $data['name'] = $name;
+        $data['att_dir'] = $att_dir;
+        $data['satt_dir'] = $satt_dir;
+        $data['att_size'] = $att_size;
+        $data['att_type'] = $att_type;
+        $data['image_type'] = $imageType;
+        $data['module_type'] = $module_type;
+        $data['time'] = $time ? $time : time();
+        $data['pid'] = $pid;
+        $data['mer_id'] = $mer_id;
+        return self::create($data);
+    }
+
+    /**
+     * TODO 获取分类图
+     * @param $id
+     * @return array
+     */
+    public static function getAll($id)
+    {
+        $model = new self;
+        $where['pid'] = $id;
+        $where['module_type'] = 1;
+        $model->where($where)->order('att_id desc');
+        return $model->page($model, $where, '', 24);
+    }
+
+    /** 获取图片列表
+     * @param $where
+     * @return array
+     */
+    public static function getImageList($where)
+    {
+        $model = new self;
+        $model = $model->where('module_type', 1);
+        if (isset($where['pid']) && $where['pid']) {
+            $model = $model->where('pid', $where['pid']);
+        } else {
+            $model = $model->where('pid', '<>', 20);
+        }
+        if (isset($where['mer_id']) && $where['mer_id'] > 0) {
+            $model = $model->where('mer_id', $where['mer_id']);
+        }
+        $model = $model->page((int)$where['page'], (int)$where['limit']);
+        $model = $model->order('att_id desc,time desc');
+        $list = $model->select();
+        $list = count($list) ? $list->toArray() : [];
+        $site_url = sys_config('site_url');
+        foreach ($list as &$item) {
+            if ($site_url) {
+                $item['satt_dir'] = (strpos($item['satt_dir'], $site_url) !== false || strstr($item['satt_dir'], 'http') !== false) ? $item['satt_dir'] : $site_url . $item['satt_dir'];
+                $item['att_dir'] = (strpos($item['att_dir'], $site_url) !== false || strstr($item['att_dir'], 'http') !== false) ? $item['satt_dir'] : $site_url . $item['att_dir'];
+            }
+        }
+        $count = $where['pid'] ? self::where(['pid' => $where['pid'], 'module_type' => 1])->count() : self::where('module_type', 1)->count();
+        return compact('list', 'count');
+    }
+
+    /**
+     * TODO 获取单条信息
+     * @param $value
+     * @param string $field
+     * @return array
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public static function getInfo($value, $field = 'att_id')
+    {
+        $where[$field] = $value;
+        $count = self::where($where)->count();
+        if (!$count) return false;
+        return self::where($where)->find()->toArray();
+    }
+
+    /**
+     * 清除昨日海报
+     * @return bool
+     * @throws \Exception
+     */
+    public static function emptyYesterdayAttachment()
+    {
+        $list = self::whereTime('time', 'yesterday')->where(['module_type' => 2])->column('att_dir', 'att_id');
+        foreach ($list as $att_id => $att_dir) {
+            try {
+                if ($att_dir && strstr($att_dir, 'uploads') !== false) {
+                    if (strstr($att_dir, 'http') === false)
+                        @unlink(substr($att_dir, 1));
+                    else {
+                        $filedir = substr($att_dir, strpos($att_dir, 'uploads'));
+                        @unlink($filedir);
+                    }
+                }
+            } catch (\Throwable $e) {
+            }
+            self::del($att_id);
+        }
+    }
+}

+ 110 - 0
app/admin/model/system/SystemAttachmentCategory.php

@@ -0,0 +1,110 @@
+<?php
+
+namespace app\admin\model\system;
+
+use crmeb\traits\ModelTrait;
+use crmeb\basic\BaseModel;
+
+/**
+ * 附件目录
+ * Class SystemAttachmentCategory
+ * @package app\admin\model\system
+ */
+class SystemAttachmentCategory extends BaseModel
+{
+    /**
+     * 数据表主键
+     * @var string
+     */
+    protected $pk = 'id';
+
+    /**
+     * 模型名称
+     * @var string
+     */
+    protected $name = 'system_attachment_category';
+
+    use ModelTrait;
+
+    /**
+     * 添加分类
+     * @param $name
+     * @param $att_size
+     * @param $att_type
+     * @param $att_dir
+     * @param string $satt_dir
+     * @param int $pid
+     * @return SystemAttachmentCategory|\think\Model
+     */
+    public static function Add($name, $att_size, $att_type, $att_dir, $satt_dir = '', $pid = 0)
+    {
+        $data['name'] = $name;
+        $data['att_dir'] = $att_dir;
+        $data['satt_dir'] = $satt_dir;
+        $data['att_size'] = $att_size;
+        $data['att_type'] = $att_type;
+        $data['time'] = time();
+        $data['pid'] = $pid;
+        return self::create($data);
+    }
+
+    /**
+     * 获取分类图
+     * @return array
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public static function getAll($name)
+    {
+        $model = new self;
+        if ($name) $model = $model->where('name', 'LIKE', "%$name%");
+        return self::tidyMenuTier($model->select(), 0);
+    }
+
+    public static function tidyMenuTier($menusList, $pid = 0, $navList = [])
+    {
+
+        foreach ($menusList as $k => $menu) {
+            $menu = $menu->getData();
+            if ($menu['pid'] == $pid) {
+                unset($menusList[$k]);
+                $menu['child'] = self::tidyMenuTier($menusList, $menu['id']);
+                $navList[] = $menu;
+            }
+        }
+        return $navList;
+    }
+
+    /**
+     * 获取分类下拉列表
+     * @param int $id
+     * @return array
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public static function getCateList($id = 10000)
+    {
+        $model = new self();
+        if ($id == 0)
+            $model->where('pid', $id);
+        return sort_list_tier($model->select()->toArray());
+    }
+
+    /**
+     * 获取单条信息
+     * @param $att_id
+     * @return mixed
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public static function getinfo($att_id)
+    {
+        $model = new self;
+        $where['att_id'] = $att_id;
+        return $model->where($where)->select()->toArray()[0];
+    }
+
+}

+ 51 - 0
app/admin/model/system/SystemAttachmentType.php

@@ -0,0 +1,51 @@
+<?php
+/**
+ * 附件目录
+ *
+ */
+
+namespace app\admin\model\system;
+
+use crmeb\traits\ModelTrait;
+use crmeb\basic\BaseModel;
+
+/**
+ * 文件检验model
+ * Class SystemFile
+ * @package app\admin\model\system
+ */
+class SystemAttachmentType extends BaseModel
+{
+    use ModelTrait;
+    /**添加附件记录
+     */
+    public static function attachmentAdd($name,$att_size,$att_type,$att_dir,$satt_dir='',$pid = 0 )
+    {
+        $data['name'] = $name;
+        $data['att_dir'] = $att_dir;
+        $data['satt_dir'] = $satt_dir;
+        $data['att_size'] = $att_size;
+        $data['att_type'] = $att_type;
+        $data['time'] = time();
+        $data['pid'] = $pid;
+        return self::create($data);
+    }
+    /**
+     * 获取分类图
+     * */
+    public static function getAll($id){
+        $model = new self;
+        $where['pid'] = $id;
+        $model->where($where)->order('att_id desc');
+        return $model->page($model,$where,'',30);
+    }
+    /**
+     * 获取单条信息
+     * */
+    public static function getinfo($att_id){
+        $model = new self;
+        $where['att_id'] = $att_id;
+        return $model->where($where)->select()->toArray()[0];
+    }
+
+}

+ 545 - 0
app/admin/model/system/SystemConfig.php

@@ -0,0 +1,545 @@
+<?php
+/**
+ * @author: xaboy<365615158@qq.com>
+ * @day: 2017/11/02
+ */
+
+namespace app\admin\model\system;
+
+use crmeb\basic\BaseModel;
+use crmeb\services\FormBuilder as Form;
+use crmeb\traits\ModelTrait;
+use think\facade\Route as Url;
+
+class SystemConfig extends BaseModel
+{
+
+    /**
+     * 数据表主键
+     * @var string
+     */
+    protected $pk = 'id';
+
+    /**
+     * 模型名称
+     * @var string
+     */
+    protected $name = 'system_config';
+
+    use ModelTrait;
+
+    /**
+     * 修改单个配置
+     * @param $menu
+     * @param $value
+     * @return bool
+     */
+    public static function setValue($menu, $value)
+    {
+        if (empty($menu) || !($config_one = self::get(['menu_name' => $menu]))) return self::setErrorInfo('字段名称错误');
+        if ($config_one['type'] == 'radio' || $config_one['type'] == 'checkbox') {
+            $parameter = [];
+            $option = [];
+            $parameter = explode(',', $config_one['parameter']);
+            foreach ($parameter as $k => $v) {
+                if (isset($v) && !empty($v)) {
+                    $option[$k] = explode('-', $v);
+                }
+            }
+            $value_arr = [];//选项的值
+            foreach ($option as $k => $v) {
+                foreach ($v as $kk => $vv)
+                    if (!$kk) {
+                        $value_arr[$k] = $vv;
+                    }
+            }
+            $i = 0;//
+            if (is_array($value)) {
+                foreach ($value as $value_v) {
+                    if (in_array($value_v, $value_arr)) {
+                        $i++;
+                    }
+                }
+                if (count($value) != $i) return self::setErrorInfo('输入的值不属于选项中的参数');
+            } else {
+                if (in_array($value, $value_arr)) {
+                    $i++;
+                }
+                if (!$i) return self::setErrorInfo('输入的值不属于选项中的参数');
+            }
+            if ($config_one['type'] == 'radio' && is_array($value)) return self::setErrorInfo('单选按钮的值是字符串不是数组');
+        }
+        $bool = self::edit(['value' => json_encode($value)], $menu, 'menu_name');
+        return $bool;
+    }
+
+    /**
+     * 获取单个参数配置
+     * @param $menu
+     * @return bool|mixed
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public static function getConfigValue($menu)
+    {
+        if (empty($menu) || !($config_one = self::where('menu_name', $menu)->find())) return false;
+        return json_decode($config_one['value'], true);
+    }
+
+    /**
+     * 获得多个参数
+     * @param $menus
+     * @return array
+     */
+    public static function getMore($menus)
+    {
+        $menus = is_array($menus) ? implode(',', $menus) : $menus;
+        $list = self::where('menu_name', 'IN', $menus)->column('value', 'menu_name') ?: [];
+        foreach ($list as $menu => $value) {
+            $list[$menu] = json_decode($value, true);
+        }
+        return $list;
+    }
+
+    /**
+     * @return array
+     */
+    public static function getAllConfig()
+    {
+        $list = self::column('value', 'menu_name') ?: [];
+        foreach ($list as $menu => $value) {
+            $list[$menu] = json_decode($value, true);
+        }
+        return $list;
+    }
+
+    /**
+     * text  判断
+     * @param $data
+     * @return bool
+     */
+    public static function valiDateTextRole($data)
+    {
+        if (!$data['width']) return self::setErrorInfo('请输入文本框的宽度');
+        if ($data['width'] <= 0) return self::setErrorInfo('请输入正确的文本框的宽度');
+        return true;
+    }
+
+    /**
+     * radio 和 checkbox规则的判断
+     * @param $data
+     * @return bool
+     */
+    public static function valiDateRadioAndCheckbox($data)
+    {
+        $parameter = [];
+        $option = [];
+        $option_new = [];
+        $data['parameter'] = str_replace("\r\n", "\n", $data['parameter']);//防止不兼容
+        $parameter = explode("\n", $data['parameter']);
+        if (count($parameter) < 2) return self::setErrorInfo('请输入正确格式的配置参数');
+        foreach ($parameter as $k => $v) {
+            if (isset($v) && !empty($v)) {
+                $option[$k] = explode('=>', $v);
+            }
+        }
+        if (count($option) < 2) return self::setErrorInfo('请输入正确格式的配置参数');
+        $bool = 1;
+        foreach ($option as $k => $v) {
+            $option_new[$k] = $option[$k][0];
+            foreach ($v as $kk => $vv) {
+                $vv_num = strlen($vv);
+                if (!$vv_num) {
+                    $bool = 0;
+                }
+            }
+        }
+        if (!$bool) return self::setErrorInfo('请输入正确格式的配置参数');
+        $num1 = count($option_new);//提取该数组的数目
+        $arr2 = array_unique($option_new);//合并相同的元素
+        $num2 = count($arr2);//提取合并后数组个数
+        if ($num1 > $num2) return self::setErrorInfo('请输入正确格式的配置参数');
+        return true;
+    }
+
+    /**
+     * textarea  判断
+     * @param $data
+     * @return bool
+     */
+    public static function valiDateTextareaRole($data)
+    {
+        if (!$data['width']) return self::setErrorInfo('请输入多行文本框的宽度');
+        if (!$data['high']) return self::setErrorInfo('请输入多行文本框的高度');
+        if ($data['width'] < 0) return self::setErrorInfo('请输入正确的多行文本框的宽度');
+        if ($data['high'] < 0) return self::setErrorInfo('请输入正确的多行文本框的宽度');
+        return true;
+    }
+
+    /**
+     * 获取一数据
+     * @param $filed
+     * @param $value
+     * @return array|null|\think\Model
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public static function getOneConfig($filed, $value)
+    {
+        $where[$filed] = $value;
+        return self::where($where)->find();
+    }
+
+    /**
+     * 获取配置分类
+     * @param $id
+     * @return \think\Collection
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public static function getAll($id, int $status = 1)
+    {
+        $where['config_tab_id'] = $id;
+        if ($status == 1) $where['status'] = $status;
+        return self::where($where)->order('sort desc,id asc')->select();
+    }
+
+    /**
+     * 获取所有配置分类
+     * @param int $type
+     * @return array
+     */
+    public static function getConfigTabAll($type = 0)
+    {
+        $configAll = SystemConfigTab::getAll($type);
+        $config_tab = [];
+        foreach ($configAll as $k => $v) {
+            if (!$v['info']) {
+                $config_tab[$k]['id'] = $v['id'];
+                $config_tab[$k]['label'] = $v['title'];
+                $config_tab[$k]['icon'] = $v['icon'];
+                $config_tab[$k]['type'] = $v['type'];
+                $config_tab[$k]['pid'] = $v['pid'];
+
+            }
+        }
+        return $config_tab;
+    }
+
+    /**
+     * 获取所有配置分类
+     * @param int $type
+     * @return array
+     */
+    public static function getConfigChildrenTabAll($pid = 0)
+    {
+        $configAll = SystemConfigTab::getChildrenTab($pid);
+        $config_tab = [];
+        foreach ($configAll as $k => $v) {
+            if (!$v['info']) {
+                $config_tab[$k]['id'] = $v['id'];
+                $config_tab[$k]['label'] = $v['title'];
+                $config_tab[$k]['icon'] = $v['icon'];
+                $config_tab[$k]['type'] = $v['type'];
+                $config_tab[$k]['pid'] = $v['pid'];
+            }
+        }
+        return $config_tab;
+    }
+
+    /**
+     * 选择类型
+     * @param string $type
+     * @return array
+     */
+    public static function radiotype($type = 'text')
+    {
+        return [
+            ['value' => 'text', 'label' => '文本框', 'disabled' => 1]
+            , ['value' => 'textarea', 'label' => '多行文本框', 'disabled' => 1]
+            , ['value' => 'radio', 'label' => '单选按钮', 'disabled' => 1]
+            , ['value' => 'upload', 'label' => '文件上传', 'disabled' => 1]
+            , ['value' => 'checkbox', 'label' => '多选按钮', 'disabled' => 1]
+        ];
+    }
+
+    /**
+     * 选择文本框类型
+     * @param string $type
+     * @return array
+     */
+    public static function texttype($type = 'text')
+    {
+        return [
+            ['value' => 'input', 'label' => '文本框']
+            , ['value' => 'dateTime', 'label' => '时间']
+            , ['value' => 'color', 'label' => '颜色']
+            , ['value' => 'number', 'label' => '数字']
+        ];
+    }
+
+    /**
+     * 选择文文件类型
+     * @param string $type
+     * @return array
+     */
+    public static function uploadtype($type = 'text')
+    {
+        return [['value' => 1, 'label' => '单图']
+            , ['value' => 2, 'label' => '多图']
+            , ['value' => 3, 'label' => '文件']];
+    }
+
+    /**
+     * 字段状态
+     * @param string $type
+     * @return array
+     */
+    public static function formstatus($type = 'text')
+    {
+        return [['value' => 1, 'label' => '显示'], ['value' => 2, 'label' => '隐藏']];
+    }
+
+    /**
+     * 文本框
+     * @param $tab_id
+     * @return array
+     * @throws \FormBuilder\exception\FormBuilderException
+     */
+    public static function createInputRule($tab_id)
+    {
+        $formbuider = [];
+        $formbuider[] = Form::hidden('type', 'text');
+//        $formbuider[] = Form::select('config_tab_id','分类',$tab_id)->setOptions(SystemConfig::getConfigTabAll(-1));
+        $formbuider[] = Form::select('input_type', '类型')->setOptions(self::texttype());
+//        $formbuider[] = Form::input('info','配置名称')->autofocus(1);
+//        $formbuider[] = Form::input('menu_name','字段变量')->placeholder('例如:site_url');
+//        $formbuider[] = Form::input('desc','配置简介');
+        $formbuider[] = Form::input('value', '默认值');
+        $formbuider[] = Form::number('width', '文本框宽(%)', 100);
+        $formbuider[] = Form::input('required', '验证规则')->placeholder('多个请用,隔开例如:required:true,url:true');
+//        $formbuider[] = Form::number('sort','排序');
+//        $formbuider[] = Form::radio('status','状态',1)->options(self::formstatus());
+        return $formbuider;
+    }
+
+    /**
+     * 多行文本框
+     * @param $tab_id
+     * @return array
+     * @throws \FormBuilder\exception\FormBuilderException
+     */
+    public static function createTextAreaRule($tab_id)
+    {
+        $formbuider = [];
+        $formbuider[] = Form::hidden('type', 'textarea');
+//        $formbuider[] = Form::select('config_tab_id','分类',$tab_id)->setOptions(SystemConfig::getConfigTabAll(-1));
+//        $formbuider[] = Form::input('info','配置名称')->autofocus(1);
+//        $formbuider[] = Form::input('menu_name','字段变量')->placeholder('例如:site_url');
+//        $formbuider[] = Form::input('desc','配置简介');
+        $formbuider[] = Form::textarea('value', '默认值');
+        $formbuider[] = Form::number('width', '文本框宽(%)', 100);
+        $formbuider[] = Form::number('high', '多行文本框高(%)', 5);
+//        $formbuider[] = Form::number('sort','排序');
+//        $formbuider[] = Form::radio('status','状态',1)->options(self::formstatus());
+        return $formbuider;
+    }
+
+    /**
+     * 单选按钮
+     * @param $tab_id
+     * @return array
+     * @throws \FormBuilder\exception\FormBuilderException
+     */
+    public static function createRadioRule($tab_id)
+    {
+        $formbuider = [];
+        $formbuider[] = Form::hidden('type', 'radio');
+//        $formbuider[] = Form::select('config_tab_id','分类',$tab_id)->setOptions(SystemConfig::getConfigTabAll(-1));
+//        $formbuider[] = Form::input('info','配置名称')->autofocus(1);
+//        $formbuider[] = Form::input('menu_name','字段变量')->placeholder('例如:site_url');
+//        $formbuider[] = Form::input('desc','配置简介');
+        $formbuider[] = Form::textarea('parameter', '配置参数')->placeholder("参数方式例如:\n1=>男\n2=>女\n3=>保密");
+        $formbuider[] = Form::input('value', '默认值');
+//        $formbuider[] = Form::number('sort','排序');
+//        $formbuider[] = Form::radio('status','状态',1)->options(self::formstatus());
+        return $formbuider;
+    }
+
+    /**
+     * 文件上传
+     * @param $tab_id
+     * @return array
+     * @throws \FormBuilder\exception\FormBuilderException
+     */
+    public static function createUploadRule($tab_id)
+    {
+        $formbuider = [];
+        $formbuider[] = Form::hidden('type', 'upload');
+//        $formbuider[] = Form::select('config_tab_id','分类',$tab_id)->setOptions(SystemConfig::getConfigTabAll(-1));
+//        $formbuider[] = Form::input('info','配置名称')->autofocus(1);
+//        $formbuider[] = Form::input('menu_name','字段变量')->placeholder('例如:site_url');
+//        $formbuider[] = Form::input('desc','配置简介');
+        $formbuider[] = Form::radio('upload_type', '上传类型', 1)->options(self::uploadtype());
+//        $formbuider[] = Form::number('sort','排序');
+//        $formbuider[] = Form::radio('status','状态',1)->options(self::formstatus());
+        return $formbuider;
+
+    }
+
+    /**
+     * 多选框
+     * @param $tab_id
+     * @return array
+     * @throws \FormBuilder\exception\FormBuilderException
+     */
+    public static function createCheckboxRule($tab_id)
+    {
+        $formbuider = [];
+        $formbuider[] = Form::hidden('type', 'checkbox');
+//        $formbuider[] = Form::select('config_tab_id','分类',$tab_id)->setOptions(SystemConfig::getConfigTabAll(-1));
+//        $formbuider[] = Form::input('info','配置名称')->autofocus(1);
+//        $formbuider[] = Form::input('menu_name','字段变量')->placeholder('例如:site_url');
+//        $formbuider[] = Form::input('desc','配置简介');
+        $formbuider[] = Form::textarea('parameter', '配置参数')->placeholder("参数方式例如:\n1=>白色\n2=>红色\n3=>黑色");
+//        $formbuider[] = Form::input('value','默认值');
+//        $formbuider[] = Form::number('sort','排序');
+//        $formbuider[] = Form::radio('status','状态',1)->options(self::formstatus());
+        return $formbuider;
+    }
+
+    /**
+     * 下拉框
+     * @param $tab_id
+     * @return array
+     * @throws \FormBuilder\exception\FormBuilderException
+     */
+    public static function createSelectRule($tab_id)
+    {
+        $formbuider = [];
+        $formbuider[] = Form::hidden('type', 'select');
+//        $formbuider[] = Form::select('config_tab_id','分类',$tab_id)->setOptions(SystemConfig::getConfigTabAll(-1));
+//        $formbuider[] = Form::input('info','配置名称')->autofocus(1);
+//        $formbuider[] = Form::input('menu_name','字段变量')->placeholder('例如:site_url');
+//        $formbuider[] = Form::input('desc','配置简介');
+        $formbuider[] = Form::textarea('parameter', '配置参数')->placeholder("参数方式例如:\n1=>白色\n2=>红色\n3=>黑色");
+//        $formbuider[] = Form::input('value','默认值');
+//        $formbuider[] = Form::number('sort','排序');
+//        $formbuider[] = Form::radio('status','状态',1)->options(self::formstatus());
+        return $formbuider;
+    }
+    /** 生成配置表单
+     * @param $list
+     * @return $this
+     */
+    public static function builder_config_from_data($list)
+    {
+        $formbuider = [];
+        foreach ($list as $data) {
+            switch ($data['type']) {
+                case 'text'://文本框
+                    switch ($data['input_type']) {
+                        case 'input':
+                            $data['value'] = json_decode($data['value'], true) ?: '';
+                            $formbuider[] = Form::input($data['menu_name'], $data['info'], $data['value'])->info($data['desc'])->placeholder($data['desc'])->col(13);
+                            break;
+                        case 'number':
+                            $data['value'] = json_decode($data['value'], true) ?: 0;
+                            $formbuider[] = Form::number($data['menu_name'], $data['info'], $data['value'])->info($data['desc']);
+                            break;
+                        case 'dateTime':
+                            $formbuider[] = Form::dateTime($data['menu_name'], $data['info'], $data['value'])->info($data['desc']);
+                            break;
+                        case 'color':
+                            $data['value'] = json_decode($data['value'], true) ?: '';
+                            $formbuider[] = Form::color($data['menu_name'], $data['info'], $data['value'])->info($data['desc']);
+                            break;
+                        default:
+                            $data['value'] = json_decode($data['value'], true) ?: '';
+                            $formbuider[] = Form::input($data['menu_name'], $data['info'], $data['value'])->info($data['desc'])->placeholder($data['desc'])->col(13);
+                            break;
+                    }
+                    break;
+                case 'textarea'://多行文本框
+                    $data['value'] = json_decode($data['value'], true) ?: '';
+                    $formbuider[] = Form::textarea($data['menu_name'], $data['info'], $data['value'])->placeholder($data['desc'])->info($data['desc'])->rows(6)->col(13);
+                    break;
+                case 'radio'://单选框
+                    $data['value'] = json_decode($data['value'], true) ?: '0';
+                    $parameter = explode("\n", $data['parameter']);
+                    $options = [];
+                    if ($parameter) {
+                        foreach ($parameter as $v) {
+                            $pdata = explode("=>", $v);
+                            $options[] = ['label' => $pdata[1], 'value' => $pdata[0]];
+                        }
+                        $formbuider[] = Form::radio($data['menu_name'], $data['info'], $data['value'])->options($options)->info($data['desc'])->col(13);
+                    }
+                    break;
+                case 'upload'://文件上传
+                    switch ($data['upload_type']) {
+                        case 1:
+                            $data['value'] = json_decode($data['value'], true) ?: '';
+                            $formbuider[] = Form::frameImageOne($data['menu_name'], $data['info'], Url::buildUrl('admin/widget.images/index', array('fodder' => $data['menu_name'])), $data['value'])->icon('image')->width('70%')->height('500px')->info($data['desc'])->col(13);
+                            break;
+                        case 2:
+                            $data['value'] = json_decode($data['value'], true) ?: [];
+                            $formbuider[] = Form::frameImages($data['menu_name'], $data['info'], Url::buildUrl('admin/widget.images/index', array('fodder' => $data['menu_name'])), $data['value'])->maxLength(5)->icon('image')->width('70%')->height('500px')->info($data['desc'])->col(13);
+                            break;
+                        case 3:
+                            $data['value'] = json_decode($data['value'], true);
+                            $formbuider[] = Form::uploadFileOne($data['menu_name'], $data['info'], Url::buildUrl('file_upload'), $data['value'])->name('file')->info($data['desc'])->col(13);
+                            break;
+                    }
+
+                    break;
+                case 'checkbox'://多选框
+                    $data['value'] = json_decode($data['value'], true) ?: [];
+                    $parameter = explode("\n", $data['parameter']);
+                    $options = [];
+                    if ($parameter) {
+                        foreach ($parameter as $v) {
+                            $pdata = explode("=>", $v);
+                            $options[] = ['label' => $pdata[1], 'value' => $pdata[0]];
+                        }
+                        $formbuider[] = Form::checkbox($data['menu_name'], $data['info'], $data['value'])->options($options)->info($data['desc'])->col(13);
+                    }
+                    break;
+                case 'select'://多选框
+                    $data['value'] = json_decode($data['value'], true) ?: [];
+                    $parameter = explode("\n", $data['parameter']);
+                    $options = [];
+                    if ($parameter) {
+                        foreach ($parameter as $v) {
+                            $pdata = explode("=>", $v);
+                            $options[] = ['label' => $pdata[1], 'value' => $pdata[0]];
+                        }
+                        $formbuider[] = Form::select($data['menu_name'], $data['info'], $data['value'])->options($options)->info($data['desc'])->col(13);
+                    }
+                    break;
+            }
+        }
+        return $formbuider;
+    }
+
+    /**
+     * 配置短信信息
+     * @param $account
+     * @param $token
+     * @return bool
+     */
+    public static function setConfigSmsInfo($account, $token)
+    {
+        self::beginTrans();
+        $res1 = self::where('menu_name', 'sms_account')->where('value', '"' . $account . '"')->count();
+        if (!$res1) $res1 = self::where('menu_name', 'sms_account')->update(['value' => '"' . $account . '"']);
+        $res2 = self::where('menu_name', 'sms_token')->where('value', '"' . $token . '"')->count();
+        if (!$res2) $res2 = self::where('menu_name', 'sms_token')->update(['value' => '"' . $token . '"']);
+        $res = $res1 && $res2;
+        self::checkTrans($res);
+        return $res;
+    }
+}

+ 108 - 0
app/admin/model/system/SystemConfigTab.php

@@ -0,0 +1,108 @@
+<?php
+/**
+ * @author: xaboy<365615158@qq.com>
+ * @day: 2017/11/02
+ */
+
+namespace app\admin\model\system;
+
+use crmeb\traits\ModelTrait;
+use crmeb\basic\BaseModel;
+
+/**
+ * 配置分类model
+ * Class SystemConfigTab
+ * @package app\admin\model\system
+ */
+class SystemConfigTab extends BaseModel
+{
+    /**
+     * 数据表主键
+     * @var string
+     */
+    protected $pk = 'id';
+
+    /**
+     * 模型名称
+     * @var string
+     */
+    protected $name = 'system_config_tab';
+
+    use ModelTrait;
+
+    /**
+     * 获取单选按钮或者多选按钮的显示值
+     * @param $menu_name
+     * @param $value
+     * @return string
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public static function getRadioOrCheckboxValueInfo($menu_name, $value)
+    {
+        $parameter = [];
+        $option = [];
+        $config_one = SystemConfig::getOneConfig('menu_name', $menu_name);
+        $parameter = explode("\n", $config_one['parameter']);
+        foreach ($parameter as $k => $v) {
+            if (isset($v) && strlen($v) > 0) {
+                $data = explode('=>', $v);
+                $option[$data[0]] = $data[1];
+            }
+        }
+        $str = '';
+        if (is_array($value)) {
+            foreach ($value as $v) {
+                $str .= $option[$v] . ',';
+            }
+        } else {
+            $str .= !empty($value) ? $option[$value] : $option[0];
+        }
+        return $str;
+    }
+
+    /**
+     * 获取全部
+     * @param int $type
+     * @return \think\Collection
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public static function getAll($type = 0)
+    {
+        $model = new self;
+        $where['status'] = 1;
+        $where['pid'] = 0;
+        if ($type > -1) $where['type'] = $type;
+        return $model::where($where)->order('sort desc,id asc')->select();
+    }
+
+    /**
+     * @param int $type
+     * @return \think\Collection
+     */
+    public static function getChildrenTab($pid)
+    {
+        $model = new self;
+        $where['status'] = 1;
+        $where['pid'] = $pid;
+        return $model::where($where)->order('sort desc,id asc')->select();
+    }
+
+    /**
+     * 获取配置分类
+     * @param array $where
+     * @return array
+     */
+    public static function getSystemConfigTabPage($where = [])
+    {
+        $model = new self;
+        if ($where['title'] != '') $model = $model->where('title', 'LIKE', "%$where[title]%");
+        if ($where['status'] != '') $model = $model->where('status', $where['status']);
+        $model = $model->where('pid', $where['pid']);
+        return self::page($model, $where);
+
+    }
+}

+ 35 - 0
app/admin/model/system/SystemFile.php

@@ -0,0 +1,35 @@
+<?php
+/**
+ * @author: xaboy<365615158@qq.com>
+ * @day: 2017/11/13
+ */
+
+namespace app\admin\model\system;
+
+use crmeb\traits\ModelTrait;
+use crmeb\basic\BaseModel;
+
+/**
+ * 附件管理model
+ * Class SystemAttachment
+ * @package app\admin\model\system
+ */
+class SystemFile extends BaseModel
+{
+
+    /**
+     * 数据表主键
+     * @var string
+     */
+    protected $pk = 'id';
+
+    /**
+     * 模型名称
+     * @var string
+     */
+    protected $name = 'system_file';
+
+    use ModelTrait;
+
+
+}

+ 43 - 0
app/admin/model/system/SystemGroup.php

@@ -0,0 +1,43 @@
+<?php
+/**
+ * @author: xaboy<365615158@qq.com>
+ * @day: 2017/11/13
+ */
+
+namespace app\admin\model\system;
+
+use crmeb\traits\ModelTrait;
+use crmeb\basic\BaseModel;
+
+/**
+ * 数据组model
+ * Class SystemGroup
+ * @package app\admin\model\system
+ */
+class SystemGroup extends BaseModel
+{
+
+    /**
+     * 数据表主键
+     * @var string
+     */
+    protected $pk = 'id';
+
+    /**
+     * 模型名称
+     * @var string
+     */
+    protected $name = 'system_group';
+
+    use ModelTrait;
+
+    /**
+     * 根据id获取当前记录中的fields值
+     * @param $id
+     * @return array
+     */
+    public static function getField($id){
+        $fields = json_decode(self::where('id',$id)->value("fields"),true)?:[];
+        return compact('fields');
+    }
+}

+ 147 - 0
app/admin/model/system/SystemGroupData.php

@@ -0,0 +1,147 @@
+<?php
+/**
+ * @author: xaboy<365615158@qq.com>
+ * @day: 2017/11/13
+ */
+
+namespace app\admin\model\system;
+
+use crmeb\traits\ModelTrait;
+use crmeb\basic\BaseModel;
+
+/**
+ * 数据列表 model
+ * Class SystemGroupData
+ * @package app\admin\model\system
+ */
+class SystemGroupData extends BaseModel
+{
+    /**
+     * 数据表主键
+     * @var string
+     */
+    protected $pk = 'id';
+
+    /**
+     * 模型名称
+     * @var string
+     */
+    protected $name = 'system_group_data';
+
+    use ModelTrait;
+
+    /**
+     * 根据where条件获取当前表中的前20条数据
+     * @param $params
+     * @return array
+     */
+    public static function getList($params)
+    {
+        $model = new self;
+        if ($params['gid'] !== '') $model = $model->where('gid', $params['gid']);
+        if ($params['status'] !== '') $model = $model->where('status', $params['status']);
+        $model = $model->order('sort desc,id ASC');
+        return self::page($model, function ($item, $key) {
+            $info = json_decode($item->value, true);
+            foreach ($info as $index => $value) {
+                if ($value["type"] == "checkbox") $info[$index]["value"] = implode(",", $value["value"]);
+//                if($value["type"] == "upload" || $value["type"] == "uploads"){
+//                    $html_img = '';
+//                    if(is_array($value["value"])){
+//                        foreach ($value["value"] as $img) {
+//                            $html_img .= '<img class="image" data-image="'.$img.'" width="45" height="45" src="'.$img.'" /><br>';
+//                        }
+//                    }else{
+//                        $html_img = '<img class="image" data-image="'.$value["value"].'" width="45" height="45" src="'.$value["value"].'" />';
+//                    }
+//                    $info[$index]["value"] = $html_img;
+//                }
+            }
+            $item->value = $info;
+        });
+    }
+
+    /**
+     * 获得组合数据信息+组合数据列表
+     * @param $config_name
+     * @param int $limit
+     * @return array|bool|null|\think\Model
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public static function getGroupData($config_name, $limit = 0)
+    {
+        $group = SystemGroup::where('config_name', $config_name)->field('name,info,config_name')->find();
+        if (!$group) return false;
+        $group['data'] = self::getAllValue($config_name, $limit);
+        return $group;
+    }
+
+    /**
+     * 获取单个值
+     * @param $config_name
+     * @param int $limit
+     * @return array
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public static function getAllValue($config_name, $limit = 0)
+    {
+        $model = self::alias('a')->field('a.*,b.config_name')->join('system_group b', 'a.gid = b.id')
+            ->where("b.config_name", $config_name)->where("a.status", 1)
+            ->order('sort desc,id ASC');
+        if ($limit > 0) $model->limit($limit);
+        $data = [];
+        $result = $model->select();
+        if (!$result) return $data;
+        foreach ($result as $key => $value) {
+            $data[$key]["id"] = $value["id"];
+            $fields = json_decode($value["value"], true);
+            foreach ($fields as $index => $field) {
+//                $data[$key][$index] = $field['type'] == 'upload' ? (isset($field["value"][0]) ? $field["value"][0]: ''):$field["value"];
+                $data[$key][$index] = $field["value"];
+            }
+        }
+        return $data;
+    }
+
+    /**
+     * @param $result
+     * @return array
+     */
+    public static function tidyList($result)
+    {
+        $data = [];
+        if (!$result) return $data;
+        foreach ($result as $key => $value) {
+            $data[$key]["id"] = $value["id"];
+            $fields = json_decode($value["value"], true);
+            foreach ($fields as $index => $field) {
+                $data[$key][$index] = $field['type'] == 'upload' ? (isset($field["value"][0]) ? $field["value"][0] : '') : $field["value"];
+            }
+        }
+        return $data;
+    }
+
+
+    /**
+     * 根据id获取当前记录中的数据
+     * @param $id
+     * @return mixed
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public static function getDateValue($id)
+    {
+        $value = self::alias('a')->where(array("id" => $id))->find();
+        $data["id"] = $value["id"];
+        $fields = json_decode($value["value"], true);
+        foreach ($fields as $index => $field) {
+            $data[$index] = $field["value"];
+        }
+        return $data;
+    }
+}

+ 142 - 0
app/admin/model/system/SystemLog.php

@@ -0,0 +1,142 @@
+<?php
+/**
+ * @author: xaboy<365615158@qq.com>
+ * @day: 2017/11/28
+ */
+
+namespace app\admin\model\system;
+
+
+use crmeb\traits\ModelTrait;
+use crmeb\basic\BaseModel;
+
+/**
+ * 管理员操作记录
+ * Class SystemLog
+ * @package app\admin\model\system
+ */
+class SystemLog extends BaseModel
+{
+    /**
+     * 数据表主键
+     * @var string
+     */
+    protected $pk = 'id';
+
+    /**
+     * 模型名称
+     * @var string
+     */
+    protected $name = 'system_log';
+
+    use ModelTrait;
+
+    protected $insert = ['add_time'];
+
+    protected function setAddTimeAttr()
+    {
+        return time();
+    }
+
+
+    /**
+     * 管理员访问记录
+     *
+     * @param $adminId
+     * @param $adminName
+     * @param $type
+     * @return SystemLog|\think\Model
+     */
+    public static function adminVisit($adminId,$adminName,$type)
+    {
+        $request = app('request');
+        $module = app('http')->getName();
+        $controller = $request->controller();
+        $action = $request->action();
+        $route = $request->route();
+        self::startTrans();
+        try{
+            $data = [
+                'method'=>app('http')->getName(),
+                'admin_id'=>$adminId,
+                'add_time'=>time(),
+                'admin_name'=>$adminName,
+                'path'=>SystemMenus::getAuthName($action,$controller,$module,$route),
+                'page'=>SystemMenus::getVisitName($action,$controller,$module,$route)?:'未知',
+                'ip'=>$request->ip(),
+                'type'=>$type
+            ];
+            $res = self::create($data);
+            if($res){
+                self::commit();
+                return true;
+            }else{
+                self::rollback();
+                return false;
+            }
+        }catch (\Exception $e){
+            self::rollback();
+            return self::setErrorInfo($e->getMessage());
+        }
+
+    }
+
+    /**
+     * 手动添加管理员当前页面访问记录
+     * @param array $adminInfo
+     * @param string $page 页面名称
+     * @return object
+     */
+    public static function setCurrentVisit($adminInfo, $page)
+    {
+        $request = app('request');
+        $module = app('http')->getName();
+        $controller = $request->controller();
+        $action = $request->action();
+        $route = $request->route();
+        $data = [
+            'method'=>$request->method(),
+            'admin_id'=>$adminInfo['id'],
+            'path'=>SystemMenus::getAuthName($action,$controller,$module,$route),
+            'page'=>$page,
+            'ip'=>$request->ip()
+        ];
+        return self::create($data);
+    }
+
+    /**
+     * 获取管理员访问记录
+     * @param array $where
+     * @return array
+     */
+    public static function systemPage($where = array()){
+        $model = new self;
+        $model = $model->alias('l');
+        if($where['pages'] !== '') $model = $model->where('l.page','LIKE',"%$where[pages]%");
+        if($where['path'] !== '') $model = $model->where('l.path','LIKE',"%$where[path]%");
+        if($where['ip'] !== '') $model = $model->where('l.ip','LIKE',"%$where[ip]%");
+        if($where['admin_id'] != '')
+            $adminIds = $where['admin_id'];
+        else
+            $adminIds = SystemAdmin::where('level','>=',$where['level'])->column('id','id');
+        $model = $model->where('l.admin_id','IN',$adminIds);
+        if($where['data'] !== ''){
+            list($startTime,$endTime) = explode(' - ',$where['data']);
+            $model = $model->where('l.add_time','>',strtotime($startTime));
+            $model = $model->where('l.add_time','<',strtotime($endTime));
+        }
+        $model->where('l.type','system');
+        $model = $model->order('l.id desc');
+        return self::page($model,$where);
+    }
+
+    /**
+     * 删除超过90天的日志
+     * @throws \Exception
+     */
+    public static function deleteLog(){
+        $model = new self;
+        $model->where('add_time','<',time()-7776000);
+        $model->delete();
+    }
+}

+ 226 - 0
app/admin/model/system/SystemMenus.php

@@ -0,0 +1,226 @@
+<?php
+/**
+ * @author: xaboy<365615158@qq.com>
+ * @day: 2017/11/02
+ */
+
+namespace app\admin\model\system;
+
+use crmeb\traits\ModelTrait;
+use crmeb\basic\BaseModel;
+use think\facade\Route as Url;
+
+/**
+ * 菜单  model
+ * Class SystemMenus
+ * @package app\admin\model\system
+ */
+class SystemMenus extends BaseModel
+{
+    /**
+     * 数据表主键
+     * @var string
+     */
+    protected $pk = 'id';
+
+    /**
+     * 模型名称
+     * @var string
+     */
+    protected $name = 'system_menus';
+
+    use ModelTrait;
+
+    public static $isShowStatus = [1 => '显示', 0 => '不显示'];
+
+    public static $accessStatus = [1 => '管理员可用', 0 => '管理员不可用'];
+
+    public static function legalWhere($where = [])
+    {
+        $where['is_show'] = 1;
+    }
+
+    public function setParamsAttr($value)
+    {
+        $value = $value ? explode('/', $value) : [];
+        $params = array_chunk($value, 2);
+        $data = [];
+        foreach ($params as $param) {
+            if (isset($param[0]) && isset($param[1])) $data[$param[0]] = $param[1];
+        }
+        return json_encode($data);
+    }
+
+    protected function setControllerAttr($value)
+    {
+        return lcfirst($value);
+    }
+
+    public function getParamsAttr($_value)
+    {
+        return json_decode($_value, true);
+    }
+
+    public function getPidAttr($value)
+    {
+        return !$value ? '顶级' : self::get($value)['menu_name'];
+    }
+
+    /**
+     * @param string $field
+     * @param bool $filter
+     * @return \think\Collection
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public static function getParentMenu($field = '*', $filter = false)
+    {
+        $where = ['pid' => 0];
+        $query = self::field($field);
+        $query = $filter ? $query->where(self::legalWhere($where)) : $query->where($where);
+        return $query->order('sort DESC')->select();
+    }
+
+    /**
+     * @return array
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public static function menuList()
+    {
+        $menusList = self::where('is_show', '1')->where('access', '1')->order('sort DESC')->select();
+        return self::tidyMenuTier(true, $menusList);
+    }
+
+    /**
+     * @return array
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public static function ruleList()
+    {
+        $ruleList = self::order('sort DESC')->select();
+        return self::tidyMenuTier(false, $ruleList);
+    }
+
+    /**
+     * @param $rules
+     * @return array
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public static function rolesByRuleList($rules)
+    {
+        $res = SystemRole::where('id', 'IN', $rules)->field('GROUP_CONCAT(rules) as ids')->find();
+        $ruleList = self::where('id', 'IN', $res['ids'])->whereOr('pid', 0)->order('sort DESC')->select();
+        return self::tidyMenuTier(false, $ruleList);
+    }
+
+    /**
+     * @param $action
+     * @param $controller
+     * @param $module
+     * @param $route
+     * @return string
+     */
+    public static function getAuthName($action, $controller, $module, $route)
+    {
+        return strtolower($module . '/' . $controller . '/' . $action . '/' . SystemMenus::paramStr($route));
+    }
+
+    /**
+     * @param bool $adminFilter
+     * @param $menusList
+     * @param int $pid
+     * @param array $navList
+     * @return array
+     * @throws \Exception
+     */
+    public static function tidyMenuTier($adminFilter = false, $menusList, $pid = 0, $navList = [])
+    {
+        static $allAuth = null;
+        static $adminAuth = null;
+        if ($allAuth === null) $allAuth = $adminFilter == true ? SystemRole::getAllAuth() : [];//所有的菜单
+        if ($adminAuth === null) $adminAuth = $adminFilter == true ? SystemAdmin::activeAdminAuthOrFail() : [];//当前登录用户的菜单
+        foreach ($menusList as $k => $menu) {
+            $menu = $menu->getData();
+            if ($menu['pid'] == $pid) {
+                unset($menusList[$k]);
+                $params = json_decode($menu['params'], true);//获取参数
+                $authName = self::getAuthName($menu['action'], $menu['controller'], $menu['module'], $params);// 按钮链接
+                if ($pid != 0 && $adminFilter && in_array($authName, $allAuth) && !in_array($authName, $adminAuth)) continue;
+                $menu['child'] = self::tidyMenuTier($adminFilter, $menusList, $menu['id']);
+                if ($pid != 0 && !count($menu['child']) && !$menu['controller'] && !$menu['action']) continue;
+                $menu['url'] = !count($menu['child']) ? Url::buildUrl($menu['module'] . '/' . $menu['controller'] . '/' . $menu['action'], $params) : 'javascript:void(0);';
+                if ($pid == 0 && !count($menu['child'])) continue;
+                $navList[] = $menu;
+            }
+        }
+        return $navList;
+    }
+
+    /**
+     * @param $id
+     * @return bool
+     */
+    public static function delMenu($id)
+    {
+        if (self::where('pid', $id)->count())
+            return self::setErrorInfo('请先删除改菜单下的子菜单!');
+        return self::del($id);
+    }
+
+    /**
+     * @param $params
+     * @return array
+     */
+    public static function getAdminPage($params)
+    {
+        $model = new self;
+        if ($params['is_show'] !== '') $model = $model->where('is_show', $params['is_show']);
+//        if($params['access'] !== '') $model = $model->where('access',$params['access']);//子管理员是否可用
+        if ($params['pid'] !== '' && !$params['keyword']) $model = $model->where('pid', $params['pid']);
+        if ($params['keyword'] !== '') $model = $model->where('menu_name|id|pid', 'LIKE', "%$params[keyword]%");
+        $model = $model->order('sort DESC,id ASC');
+        return self::page($model, $params);
+    }
+
+    /**
+     * @param $params
+     * @return string
+     */
+    public static function paramStr($params)
+    {
+        if (!is_array($params)) $params = json_decode($params, true) ?: [];
+        $p = [];
+        foreach ($params as $key => $param) {
+            $p[] = $key;
+            $p[] = $param;
+        }
+        return implode('/', $p);
+    }
+
+    /**
+     * @param $action
+     * @param $controller
+     * @param $module
+     * @param array $route
+     * @return mixed
+     */
+    public static function getVisitName($action, $controller, $module, array $route = [])
+    {
+        $params = json_encode($route);
+        return self::where('action', $action)
+            ->where('controller', lcfirst($controller))
+            ->where('module', lcfirst($module))
+            ->where('params', $params)
+            ->where("params = '$params' OR params = '[]'")
+            ->order('id DESC')
+            ->value('menu_name');
+    }
+
+}

+ 147 - 0
app/admin/model/system/SystemNotice.php

@@ -0,0 +1,147 @@
+<?php
+/**
+ * @author: xaboy<365615158@qq.com>
+ * @day: 2017/11/02
+ */
+
+namespace app\admin\model\system;
+
+use crmeb\traits\ModelTrait;
+use crmeb\basic\BaseModel;
+use think\facade\Db;
+
+/**
+ * 后台通知model
+ * Class SystemNotice
+ * @package app\admin\model\system
+ */
+class SystemNotice extends BaseModel
+{
+    /**
+     * 数据表主键
+     * @var string
+     */
+    protected $pk = 'id';
+
+    /**
+     * 模型名称
+     * @var string
+     */
+    protected $name = 'system_notice';
+
+    use ModelTrait;
+
+    protected function setResultAttr($value)
+    {
+        return json_encode($value);
+    }
+
+    protected function setTableTitleAttr($value)
+    {
+        $list = [];
+        if (!empty($value)) {
+            $group = explode(',', $value);
+            $list = array_map(function ($v) {
+                list($title, $key) = explode('-', $v);
+                return compact('title', 'key');
+            }, $group);
+        }
+        return json_encode($list);
+    }
+
+    protected function getTableTitleAttr($value)
+    {
+        return json_decode($value, true);
+    }
+
+    protected function getResultAttr($value)
+    {
+        return json_decode($value, true);
+    }
+
+    protected function setPushAdminAttr($value)
+    {
+        $value = is_array($value) ? array_unique(array_filter($value)) : [];
+        return implode(',', $value);
+    }
+
+    protected function getPushAdminAttr($value)
+    {
+        return array_filter(explode(',', $value));
+    }
+
+    public static function typeByAdminList($type, $field = 'id')
+    {
+        return self::where('type', $type)->field($field)->find();
+    }
+
+    public static function systemNoticeAdminDb()
+    {
+        return Db::name('SystemNoticeAdmin');
+    }
+
+    public static function adminMessage($notice_type, $admin_id, $link_id, array $table_data = [])
+    {
+        $table_data = json_encode($table_data);
+        $add_time = time();
+        return self::systemNoticeAdminDb()->insert(compact('notice_type', 'admin_id', 'link_id', 'table_data', 'add_time'));
+    }
+
+    public static function noticeMessage($noticeType, $linkId, array $tableData = [])
+    {
+        $noticeInfo = self::get(['type' => $noticeType]);
+        if (!$noticeInfo) return self::setErrorInfo('通知模板消息不存在!');
+        $adminIds = array_merge(array_map(function ($v) {
+            return $v['id'];
+        }, SystemAdmin::getTopAdmin('id')->toArray()) ?: [], self::typeByAdminList($noticeType, 'push_admin')->push_admin ?: []);
+        $adminIds = array_unique(array_filter($adminIds));
+        if (!count($adminIds)) return self::setErrorInfo('没有有效的通知用户!');
+        foreach ($adminIds as $id) {
+            self::adminMessage($noticeType, $id, $linkId, $tableData);
+        }
+        return true;
+    }
+
+    public static function getAdminNoticeTotal($adminId)
+    {
+        $list = self::alias('A')
+            ->join('system_notice_admin B', 'B.notice_type = A.type')
+            ->where('A.status', 1)
+            ->where('B.is_visit', 0)
+            ->where('B.is_click', 0)
+            ->where('B.admin_id', $adminId)
+            ->field('count(B.id) total')
+            ->group('A.id')
+            ->select()
+            ->toArray();
+        if (!$list) return 0;
+        return array_reduce($list, function ($initial, $res) {
+            return $initial + $res['total'];
+        }, 0);
+    }
+
+    public static function getAdminNotice($adminId)
+    {
+        $list = self::alias('A')
+            ->join('system_notice_admin B', 'B.notice_type = A.type')
+            ->where('A.status', 1)
+            ->where('B.is_visit', 0)
+            ->where('B.is_click', 0)
+            ->where('B.admin_id', $adminId)
+            ->field('A.id,A.type,A.title,A.icon,count(B.id) total,A.template,max(B.add_time) as last_time')
+            ->group('A.id')
+            ->having('total > 0')
+            ->select()
+            ->toArray();
+        $noticeTypeList = [];
+        array_walk($list, function (&$notice) use (&$noticeTypeList) {
+            $notice['message'] = sprintf($notice['template'], $notice['total']);
+            $noticeTypeList[] = $notice['type'];
+        });
+        if (count($noticeTypeList))
+            self::systemNoticeAdminDb()->where('notice_type', 'IN', $noticeTypeList)->where('admin_id', $adminId)
+                ->update(['is_visit' => 1, 'visit_time' => time()]);
+        return $list;
+    }
+
+}

+ 91 - 0
app/admin/model/system/SystemRole.php

@@ -0,0 +1,91 @@
+<?php
+/**
+ * @author: xaboy<365615158@qq.com>
+ * @day: 2017/11/13
+ */
+
+namespace app\admin\model\system;
+
+use crmeb\traits\ModelTrait;
+use crmeb\basic\BaseModel;
+
+/**
+ * 身份管理 model
+ * Class SystemRole
+ * @package app\admin\model\system
+ */
+class SystemRole extends BaseModel
+{
+    /**
+     * 数据表主键
+     * @var string
+     */
+    protected $pk = 'id';
+
+    /**
+     * 模型名称
+     * @var string
+     */
+    protected $name = 'system_role';
+
+    use ModelTrait;
+
+    public static function setRulesAttr($value)
+    {
+        return is_array($value) ? implode(',',$value) : $value;
+    }
+
+    /**
+     * 选择管理员身份
+     * @param int $level
+     * @return array
+     */
+    public static function getRole($level = 0)
+    {
+        return self::where('status',1)->where('level',$level)->column('role_name','id');
+    }
+
+
+    public static function rolesByAuth($rules)
+    {
+        if(empty($rules)) return [];
+        $rules = self::where('id','IN',$rules)->where('status','1')->column('rules','id');
+        $rules = array_unique(explode(',',implode(',',$rules)));
+        $_auth = SystemMenus::all(function($query) use($rules){
+            $query->where('id','IN',$rules)
+                ->where('controller|action','<>','')
+                ->field('module,controller,action,params');
+        });
+        return self::tidyAuth($_auth?:[]);
+    }
+
+    public static function getAllAuth()
+    {
+        static $auth = null;
+        $auth === null  && ($auth = self::tidyAuth(SystemMenus::all(function($query){
+            $query->where('controller|action','<>','')->field('module,controller,action,params');
+        })?:[]));
+        return $auth;
+    }
+
+    protected static function tidyAuth($_auth)
+    {
+        $auth = [];
+        foreach ($_auth as $k=>$val){
+            $auth[] =  SystemMenus::getAuthName($val['action'],$val['controller'],$val['module'],$val['params']);
+        }
+        return $auth;
+    }
+
+
+    public static function systemPage($where){
+        $model = new self;
+        if(strlen(trim($where['role_name']))) $model = $model->where('role_name','LIKE',"%$where[role_name]%");
+        if(strlen(trim($where['status']))) $model = $model->where('status',$where['status']);
+        $model = $model->where('level',bcadd($where['level'],1,0));
+        return self::page($model,(function($item){
+            $item->rules = SystemMenus::where('id','IN',$item->rules)->column('menu_name','id');
+        }),$where);
+    }
+
+}

+ 1231 - 0
app/admin/model/user/User.php

@@ -0,0 +1,1231 @@
+<?php
+/**
+ * @author: xaboy<365615158@qq.com>
+ * @day: 2017/11/11
+ */
+
+namespace app\admin\model\user;
+
+use app\admin\model\order\StoreOrder;
+use app\admin\model\system\SystemUserLevel;
+use crmeb\traits\ModelTrait;
+use crmeb\basic\BaseModel;
+use app\admin\model\wechat\WechatUser;
+use app\admin\model\store\StoreCouponUser;
+use crmeb\services\PHPExcelService;
+
+/**
+ * 用户管理 model
+ * Class User
+ * @package app\admin\model\user
+ */
+class User extends BaseModel
+{
+
+    /**
+     * 数据表主键
+     * @var string
+     */
+    protected $pk = 'uid';
+
+    /**
+     * 模型名称
+     * @var string
+     */
+    protected $name = 'user';
+
+    use ModelTrait;
+
+    /*
+     * 获取和提现金额
+     * @param array $uid
+     * @return float
+     * */
+    public static function getextractPrice($uid, $where = [])
+    {
+        if (is_array($uid)) {
+            if (!count($uid)) return 0;
+        } else
+            $uid = [$uid];
+        $brokerage = UserBill::getBrokerage($uid, 'now_money', 'brokerage', $where);//获取总佣金
+        $recharge = UserBill::getBrokerage($uid, 'now_money', 'recharge', $where);//累计充值
+        $extractTotalPrice = UserExtract::userExtractTotalPrice($uid, 1, $where);//累计提现
+        if ($brokerage > $extractTotalPrice) {
+            $orderYuePrice = self::getModelTime($where, StoreOrder::where('uid', 'in', $uid)->where(['is_del' => 0, 'paid' => 1]))->sum('pay_price');//余额累计消费
+            $systemAdd = UserBill::getBrokerage($uid, 'now_money', 'system_add', $where);//后台添加余额
+            $yueCount = bcadd($recharge, $systemAdd, 2);// 后台添加余额 + 累计充值  = 非佣金的总金额
+            $orderYuePrice = $yueCount > $orderYuePrice ? 0 : bcsub($orderYuePrice, $yueCount, 2);// 余额累计消费(使用佣金消费的金额)
+            $brokerage = bcsub($brokerage, $extractTotalPrice, 2);//减去已提现金额
+            $extract_price = UserExtract::userExtractTotalPrice($uid, 0, $where);
+            $brokerage = $extract_price < $brokerage ? bcsub($brokerage, $extract_price, 2) : 0;//减去审核中的提现金额
+            $brokerage = $brokerage > $orderYuePrice ? bcsub($brokerage, $orderYuePrice, 2) : 0;//减掉余额支付
+        } else {
+            $brokerage = 0;
+        }
+        $num = (float)bcsub($brokerage, $extractTotalPrice, 2);
+        return $num > 0 ? $num : 0;//可提现
+    }
+
+    /**
+     * @param $where
+     * @return array
+     */
+    public static function systemPage($where)
+    {
+        $model = new self;
+        if ($where['status'] != '') $model = $model->where('status', $where['status']);
+        if ($where['is_promoter'] != '') $model = $model->where('is_promoter', $where['is_promoter']);
+        if (isset($where['user_type']) && $where['user_type'] != '') $model = $model->where('user_type', $where['user_type']);
+        if ($where['nickname'] != '') $model = $model->where('nickname|uid', 'like', "%$where[nickname]%");
+        $model = $model->order('uid desc');
+        return self::page($model, function ($item) {
+            if ($item['spread_uid']) {
+                $item['spread_uid_nickname'] = self::where('uid', $item['spread_uid'])->value('nickname');
+            } else {
+                $item['spread_uid_nickname'] = '无';
+            }
+        }, $where);
+    }
+
+    /*
+     * 设置搜索条件
+     *
+     */
+    public static function setWhere($where)
+    {
+        if ($where['order'] != '') {
+            $model = self::order(self::setOrder($where['order']));
+        } else {
+            $model = self::order('u.uid desc');
+        }
+        if ($where['user_time_type'] == 'visitno' && $where['user_time'] != '') {
+            list($startTime, $endTime) = explode(' - ', $where['user_time']);
+            $endTime = strtotime($endTime) + 24 * 3600;
+            $model = $model->where("u.last_time < " . strtotime($startTime) . " OR u.last_time > " . $endTime);
+        }
+        if ($where['user_time_type'] == 'visit' && $where['user_time'] != '') {
+            list($startTime, $endTime) = explode(' - ', $where['user_time']);
+            $model = $model->where('u.last_time', '>', strtotime($startTime));
+            $model = $model->where('u.last_time', '<', strtotime($endTime) + 24 * 3600);
+        }
+        if ($where['user_time_type'] == 'add_time' && $where['user_time'] != '') {
+            list($startTime, $endTime) = explode(' - ', $where['user_time']);
+            $model = $model->where('u.add_time', '>', strtotime($startTime));
+            $model = $model->where('u.add_time', '<', strtotime($endTime) + 24 * 3600);
+        }
+        if ($where['pay_count'] !== '') {
+            if ($where['pay_count'] == '-1') $model = $model->where('pay_count', 0);
+            else $model = $model->where('pay_count', '>', $where['pay_count']);
+        }
+        if ($where['user_type'] != '') {
+            if ($where['user_type'] == 'routine') $model = $model->where('w.routine_openid', 'not null');
+            else if ($where['user_type'] == 'wechat') $model = $model->where('w.openid', 'not null');
+            else $model = $model->where('u.user_type', $where['user_type']);
+        }
+        if ($where['country'] != '') {
+            if ($where['country'] == 'domestic') $model = $model->where('w.country', '中国');
+            else if ($where['country'] == 'abroad') $model = $model->where('w.country', '<>', '中国');
+        }
+        if ($where['level'] !== '') {
+            $model = $model->where('level', $where['level'])->where('clean_time',0);
+        }
+        if ($where['group_id'] !== '') {
+            $model = $model->where('group_id', $where['group_id']);
+        }
+        return $model;
+    }
+
+    /**
+     * 异步获取当前用户 信息
+     * @param $where
+     * @return array
+     */
+    public static function getUserList($where)
+    {
+        $model = self::setWherePage(self::setWhere($where), $where, ['w.sex', 'w.province', 'w.city', 'u.status', 'u.is_promoter'], ['u.nickname', 'u.uid', 'u.phone']);
+        $list = $model->alias('u')
+            ->join('WechatUser w', 'u.uid=w.uid')
+            ->field('u.*,w.country,w.province,w.city,w.sex,w.unionid,w.openid,w.routine_openid,w.groupid,w.tagid_list,w.subscribe,w.subscribe_time')
+            ->page((int)$where['page'], (int)$where['limit'])
+            ->select()
+            ->each(function ($item) {
+                $item['add_time'] = date('Y-m-d H:i:s', $item['add_time']);
+                if ($item['last_time']) $item['last_time'] = date('Y-m-d H:i:s', $item['last_time']);//最近一次访问日期
+                else $item['last_time'] = '无访问';//最近一次访问日期
+                self::edit(['pay_count' => 0], $item['uid']);
+                $item['extract_count_price'] = UserExtract::getUserCountPrice($item['uid']);//累计提现
+                if ($item['spread_uid']) {
+                    $item['spread_uid_nickname'] = self::where('uid', $item['spread_uid'])->value('nickname') . '/' . $item['spread_uid'];
+                } else {
+                    $item['spread_uid_nickname'] = '无';
+                }
+                if ($item['openid'] != '' && $item['routine_openid'] != '') {
+                    $item['user_type'] = '通用';
+                } else if ($item['openid'] == '' && $item['routine_openid'] != '') {
+                    $item['user_type'] = '小程序';
+                } else if ($item['openid'] != '' && $item['routine_openid'] == '') {
+                    $item['user_type'] = '公众号';
+                } else if ($item['user_type'] == 'h5') {
+                    $item['user_type'] = 'H5';
+                } else $item['user_type'] = '其他';
+                if ($item['sex'] == 1) {
+                    $item['sex'] = '男';
+                } else if ($item['sex'] == 2) {
+                    $item['sex'] = '女';
+                } else $item['sex'] = '保密';
+                $item['vip_name'] = false;
+                $levelinfo = UserLevel::where('uid', $item['uid'])->where('is_del', 0)->order('grade desc')->field('level_id,is_forever,valid_time')->find();
+                if ($levelinfo) {
+                    if ($levelinfo['is_forever']) $item['vip_name'] = SystemUserLevel::where('id', $levelinfo['level_id'])->value('name');
+                    else if (time() > $levelinfo['valid_time']) $item['vip_name'] = SystemUserLevel::where('id', $levelinfo['level_id'])->value('name');
+                }
+            });//->toArray();
+        $count = self::setWherePage(self::setWhere($where), $where, ['w.sex', 'w.province', 'w.city', 'u.status', 'u.is_promoter'], ['u.nickname', 'u.uid'])->alias('u')->join('WechatUser w', 'u.uid=w.uid')->count();
+        return ['count' => $count, 'data' => $list];
+    }
+
+    /**
+     *  修改用户状态
+     * @param $uids 用户uid
+     * @param $status 修改状态
+     * @return array
+     */
+    public static function destrSyatus($uids, $status)
+    {
+        if (empty($uids) && !is_array($uids)) return false;
+        if ($status == '') return false;
+        self::beginTrans();
+        try {
+            $res = self::where('uid', 'in', $uids)->update(['status' => $status]);
+            self::checkTrans($res);
+            return true;
+        } catch (\Exception $e) {
+            self::rollbackTrans();
+            return Json::fail($e->getMessage());
+        }
+    }
+
+    /*
+     *  获取某季度,某年某年后的时间戳
+     *
+     * self::getMonth('n',1) 获取当前季度的上个季度的时间戳
+     * self::getMonth('n') 获取当前季度的时间戳
+     */
+    public static function getMonth($time = '', $ceil = 0)
+    {
+        if (empty($time)) {
+            $firstday = date("Y-m-01", time());
+            $lastday = date("Y-m-d", strtotime("$firstday +1 month -1 day"));
+        } else if ($time == 'n') {
+            if ($ceil != 0)
+                $season = ceil(date('n') / 3) - $ceil;
+            else
+                $season = ceil(date('n') / 3);
+            $firstday = date('Y-m-01', mktime(0, 0, 0, ($season - 1) * 3 + 1, 1, date('Y')));
+            $lastday = date('Y-m-t', mktime(0, 0, 0, $season * 3, 1, date('Y')));
+        } else if ($time == 'y') {
+            $firstday = date('Y-01-01');
+            $lastday = date('Y-12-31');
+        } else if ($time == 'h') {
+            $firstday = date('Y-m-d', strtotime('this week +' . $ceil . ' day')) . ' 00:00:00';
+            $lastday = date('Y-m-d', strtotime('this week +' . ($ceil + 1) . ' day')) . ' 23:59:59';
+        }
+        return array($firstday, $lastday);
+    }
+
+    public static function getcount()
+    {
+        return self::count();
+    }
+
+    /*
+    *获取用户某个时间段的消费信息
+    *
+    * reutrn Array || number
+    */
+    public static function consume($where, $status = '', $keep = '')
+    {
+        $model = new self;
+        $user_id = [];
+        if (is_array($where)) {
+            if ($where['is_promoter'] != '') $model = $model->where('is_promoter', $where['is_promoter']);
+            if ($where['status'] != '') $model = $model->where('status', $where['status']);
+            switch ($where['date']) {
+                case null:
+                case 'today':
+                case 'week':
+                case 'year':
+                    if ($where['date'] == null) {
+                        $where['date'] = 'month';
+                    }
+                    if ($keep) {
+                        $model = $model->whereTime('add_time', $where['date'])->whereTime('last_time', $where['date']);
+                    } else {
+                        $model = $model->whereTime('add_time', $where['date']);
+                    }
+                    break;
+                case 'quarter':
+                    $quarter = self::getMonth('n');
+                    $startTime = strtotime($quarter[0]);
+                    $endTime = strtotime($quarter[1]);
+                    if ($keep) {
+                        $model = $model->where('add_time', '>', $startTime)->where('add_time', '<', $endTime)->where('last_time', '>', $startTime)->where('last_time', '<', $endTime);
+                    } else {
+                        $model = $model->where('add_time', '>', $startTime)->where('add_time', '<', $endTime);
+                    }
+                    break;
+                default:
+                    //自定义时间
+                    if (strstr($where['date'], '-') !== FALSE) {
+                        list($startTime, $endTime) = explode('-', $where['date']);
+                        $model = $model->where('add_time', '>', strtotime($startTime))->where('add_time', '<', bcadd(strtotime($endTime), 86400, 0));
+                    } else {
+                        $model = $model->whereTime('add_time', 'month');
+                    }
+                    break;
+            }
+        } else {
+            if (is_array($status)) {
+                $model = $model->where('add_time', '>', $status[0])->where('add_time', '<', $status[1]);
+            }
+        }
+        if ($keep === true) {
+            return $model->count();
+        }
+        if ($status === 'default') {
+            return $model->group('from_unixtime(add_time,\'%Y-%m-%d\')')->field('count(uid) num,from_unixtime(add_time,\'%Y-%m-%d\') add_time,uid')->select()->toArray();
+        }
+        if ($status === 'grouping') {
+            return $model->group('user_type')->field('user_type')->select()->toArray();
+        }
+        $uid = $model->field('uid')->select()->toArray();
+        foreach ($uid as $val) {
+            $user_id[] = $val['uid'];
+        }
+        if (empty($user_id)) {
+            $user_id = [0];
+        }
+        if ($status === 'xiaofei') {
+            $list = UserBill::where('uid', 'in', $user_id)
+                ->group('type')
+                ->field('sum(number) as top_number,title')
+                ->select()
+                ->toArray();
+            $series = [
+                'name' => isset($list[0]['title']) ? $list[0]['title'] : '',
+                'type' => 'pie',
+                'radius' => ['40%', '50%'],
+                'data' => []
+            ];
+            foreach ($list as $key => $val) {
+                $series['data'][$key]['value'] = $val['top_number'];
+                $series['data'][$key]['name'] = $val['title'];
+            }
+            return $series;
+        } else if ($status === 'form') {
+            $list = WechatUser::where('uid', 'in', $user_id)->group('city')->field('count(city) as top_city,city')->limit(0, 10)->select()->toArray();
+            $count = self::getcount();
+            $option = [
+                'legend_date' => [],
+                'series_date' => []
+            ];
+            foreach ($list as $key => $val) {
+                $num = $count != 0 ? (bcdiv($val['top_city'], $count, 2)) * 100 : 0;
+                $t = ['name' => $num . '%  ' . (empty($val['city']) ? '未知' : $val['city']), 'icon' => 'circle'];
+                $option['legend_date'][$key] = $t;
+                $option['series_date'][$key] = ['value' => $num, 'name' => $t['name']];
+            }
+            return $option;
+        } else {
+            $number = UserBill::where('uid', 'in', $user_id)->where('type', 'pay_product')->sum('number');
+            return $number;
+        }
+    }
+
+    /*
+     * 获取 用户某个时间段的钱数或者TOP20排行
+     *
+     * return Array  || number
+     */
+    public static function getUserSpend($date, $status = '')
+    {
+        $model = new self();
+        $model = $model->alias('A');
+        switch ($date) {
+            case null:
+            case 'today':
+            case 'week':
+            case 'year':
+                if ($date == null) $date = 'month';
+                $model = $model->whereTime('A.add_time', $date);
+                break;
+            case 'quarter':
+                list($startTime, $endTime) = User::getMonth('n');
+                $model = $model->where('A.add_time', '>', strtotime($startTime));
+                $model = $model->where('A.add_time', '<', bcadd(strtotime($endTime), 86400, 0));
+                break;
+            default:
+                list($startTime, $endTime) = explode('-', $date);
+                $model = $model->where('A.add_time', '>', strtotime($startTime));
+                $model = $model->where('A.add_time', '<', bcadd(strtotime($endTime), 86400, 0));
+                break;
+        }
+        if ($status === true) {
+            return $model->join('user_bill B', 'B.uid=A.uid')->where('B.type', 'pay_product')->where('B.pm', 0)->sum('B.number');
+        }
+        $list = $model->join('user_bill B', 'B.uid=A.uid')
+            ->where('B.type', 'pay_product')
+            ->where('B.pm', 0)
+            ->field('sum(B.number) as totel_number,A.nickname,A.avatar,A.now_money,A.uid,A.add_time')
+            ->order('totel_number desc')
+            ->limit(0, 20)
+            ->select()
+            ->toArray();
+        if (!isset($list[0]['totel_number'])) {
+            $list = [];
+        }
+        return $list;
+    }
+
+    /*
+     * 获取 相对于上月或者其他的数据
+     *
+     * return Array
+     */
+    public static function getPostNumber($date, $status = false, $field = 'A.add_time', $t = '消费')
+    {
+        $model = new self();
+        if (!$status) $model = $model->alias('A');
+        switch ($date) {
+            case null:
+            case 'today':
+            case 'week':
+            case 'year':
+                if ($date == null) {
+                    $date = 'last month';
+                    $title = '相比上月用户' . $t . '增长';
+                }
+                if ($date == 'today') {
+                    $date = 'yesterday';
+                    $title = '相比昨天用户' . $t . '增长';
+                }
+                if ($date == 'week') {
+                    $date = 'last week';
+                    $title = '相比上周用户' . $t . '增长';
+                }
+                if ($date == 'year') {
+                    $date = 'last year';
+                    $title = '相比去年用户' . $t . '增长';
+                }
+                $model = $model->whereTime($field, $date);
+                break;
+            case 'quarter':
+                $title = '相比上季度用户' . $t . '增长';
+                list($startTime, $endTime) = User::getMonth('n', 1);
+                $model = $model->where($field, '>', $startTime);
+                $model = $model->where($field, '<', $endTime);
+                break;
+            default:
+                list($startTime, $endTime) = explode('-', $date);
+                $title = '相比' . $startTime . '-' . $endTime . '时间段用户' . $t . '增长';
+                $Time = strtotime($endTime) - strtotime($startTime);
+                $model = $model->where($field, '>', strtotime($startTime) + $Time);
+                $model = $model->where($field, '<', strtotime($endTime) + $Time);
+                break;
+        }
+        if ($status) {
+            return [$model->count(), $title];
+        }
+        $number = $model->join('user_bill B', 'B.uid=A.uid')->where('B.type', 'pay_product')->where('B.pm', 0)->sum('B.number');
+        return [$number, $title];
+    }
+
+    //获取用户新增,头部信息
+    public static function getBadgeList($where)
+    {
+        $user_count = self::setWherePage(self::getModelTime($where, new self), $where, ['is_promoter', 'status'])->count();
+        $user_count_old = self::getOldDate($where)->count();
+        $store_brokerage_statu = sys_config('store_brokerage_statu');
+        if ($store_brokerage_statu == 1)
+            $fenxiao = self::setWherePage(self::getModelTime($where, new self), $where, ['is_promoter', 'status'])->where('spread_uid', '<>', 0)->count();
+        else
+            $fenxiao = self::count();
+        $fenxiao_count = self::getOldDate($where)->where('spread_uid', '<>', 0)->count();
+        $newFemxiao_count = bcsub($fenxiao, $fenxiao_count, 0);
+        $order_count = bcsub($user_count, $user_count_old, 0);
+        return [
+            [
+                'name' => '会员人数',
+                'field' => '个',
+                'count' => $user_count,
+                'content' => '会员总人数',
+                'background_color' => 'layui-bg-blue',
+                'sum' => self::count(),
+                'class' => 'fa fa-bar-chart',
+            ],
+            [
+                'name' => '会员增长',
+                'field' => '个',
+                'count' => $order_count,
+                'content' => '会员增长率',
+                'background_color' => 'layui-bg-cyan',
+                'sum' => $user_count_old ? bcdiv($order_count, $user_count_old, 2) * 100 : 0,
+                'class' => 'fa fa-line-chart',
+            ],
+            [
+                'name' => '分销人数',
+                'field' => '个',
+                'count' => $fenxiao,
+                'content' => '分销总人数',
+                'background_color' => 'layui-bg-green',
+                'sum' => $store_brokerage_statu == 1 ? self::where('spread_uid', '<>', 0)->count() : $fenxiao,
+                'class' => 'fa fa-bar-chart',
+            ],
+            [
+                'name' => '分销增长',
+                'field' => '个',
+                'count' => $newFemxiao_count,
+                'content' => '分销总人数',
+                'background_color' => 'layui-bg-orange',
+                'sum' => $fenxiao_count ? bcdiv($newFemxiao_count, $fenxiao_count, 2) * 100 : 0,
+                'class' => 'fa fa-cube',
+            ],
+        ];
+    }
+
+    /*
+     * 获取会员增长曲线图和分布图
+     *  $where 查询条件
+     *  $limit 显示条数,是否有滚动条
+     */
+    public static function getUserChartList($where, $limit = 20)
+    {
+        $list = self::setWherePage(self::getModelTime($where, new self), $where, ['is_promoter', 'status'])
+            ->where('add_time', '<>', 0)
+            ->field('FROM_UNIXTIME(add_time,"%Y-%m-%d") as _add_time,count(uid) as num')
+            ->order('_add_time asc')
+            ->group('_add_time')
+            ->select();
+        count($list) && $list = $list->toArray();
+        $seriesdata = [];
+        $xdata = [];
+        $Zoom = '';
+        foreach ($list as $item) {
+            $seriesdata[] = $item['num'];
+            $xdata[] = $item['_add_time'];
+        }
+        (count($xdata) > $limit) && $Zoom = $xdata[$limit - 5];
+        //多次购物会员数量饼状图
+        $count = self::setWherePage(self::getModelTime($where, new self), $where, ['is_promoter'])->count();
+        $user_count = self::setWherePage(self::getModelTime($where, self::alias('a')->join('store_order r', 'r.uid=a.uid'), 'a.add_time'), $where, ['is_promoter'])
+            ->where('r.paid', 1)->count('a.uid');
+        $shop_xdata = ['多次购买数量占比', '无购买数量占比'];
+        $shop_data = [];
+        $count > 0 && $shop_data = [
+            [
+                'value' => bcdiv($user_count, $count, 2) * 100,
+                'name' => $shop_xdata[0],
+                'itemStyle' => [
+                    'color' => '#D789FF',
+                ]
+            ],
+            [
+                'value' => bcdiv($count - $user_count, $count, 2) * 100,
+                'name' => $shop_xdata[1],
+                'itemStyle' => [
+                    'color' => '#7EF0FB',
+                ]
+            ]
+        ];
+        return compact('shop_data', 'shop_xdata', 'seriesdata', 'Zoom');
+    }
+
+    //获取$date的前一天或者其他的时间段
+    public static function getOldDate($where, $moedls = null)
+    {
+        $model = $moedls === null ? self::setWherePage(new self(), $where, ['is_promoter', 'status']) : $moedls;
+        switch ($where['data']) {
+            case 'today':
+                $model = $model->whereTime('add_time', 'yesterday');
+                break;
+            case 'week':
+                $model = $model->whereTime('add_time', 'last week');
+                break;
+            case 'month':
+                $model = $model->whereTime('add_time', 'last month');
+                break;
+            case 'year':
+                $model = $model->whereTime('add_time', 'last year');
+                break;
+            case 'quarter':
+                $time = self::getMonth('n', 1);
+                $model = $model->where('add_time', 'between', $time);
+                break;
+        }
+        return $model;
+    }
+
+    //获取用户属性和性别分布图
+    public static function getEchartsData($where)
+    {
+        $model = self::alias('a');
+        $data = self::getModelTime($where, $model, 'a.add_time')
+            ->join('wechat_user r', 'r.uid=a.uid')
+            ->group('r.province')
+            ->field('count(r.province) as count,province')
+            ->order('count desc')
+            ->limit(15)
+            ->select();
+        if (count($data)) $data = $data->toArray();
+        $legdata = [];
+        $dataList = [];
+        foreach ($data as $value) {
+            $value['province'] == '' && $value['province'] = '未知省份';
+            $legdata[] = $value['province'];
+            $dataList[] = $value['count'];
+        }
+        $model = self::alias('a');
+        $sex = self::getModelTime($where, $model, 'a.add_time')
+            ->join('wechat_user r', 'r.uid=a.uid')
+            ->group('r.sex')
+            ->field('count(r.uid) as count,sex')
+            ->order('count desc')
+            ->select();
+        if (count($sex)) $sex = $sex->toArray();
+        $sexlegdata = ['男', '女', '未知'];
+        $sexcount = self::getModelTime($where, new self())->count();
+        $sexList = [];
+        $color = ['#FB7773', '#81BCFE', '#91F3FE'];
+        foreach ($sex as $key => $item) {
+            if ($item['sex'] == 1) {
+                $item_date['name'] = '男';
+            } else if ($item['sex'] == 2) {
+                $item_date['name'] = '女';
+            } else {
+                $item_date['name'] = '未知性别';
+            }
+            $item_date['value'] = bcdiv($item['count'], $sexcount, 2) * 100;
+            $item_date['itemStyle']['color'] = $color[$key];
+            $sexList[] = $item_date;
+        }
+        return compact('sexList', 'sexlegdata', 'legdata', 'dataList');
+    }
+
+    //获取佣金记录列表
+    public static function getCommissionList($where)
+    {
+        $model = self::setCommissionWhere($where);
+        if ($where['excel'])
+            $list = $model->select();
+        else
+            $list = $model->page((int)$where['page'], (int)$where['limit'])->select();
+        count($list) && $list = $list->toArray();
+        $export = [];
+        foreach ($list as &$value) {
+            $value['ex_price'] = UserExtract::where('uid', $value['uid'])->sum('extract_price');
+            $value['extract_price'] = UserExtract::where('uid', $value['uid'])->where('status', 1)->sum('extract_price');
+            $cashPrice = UserExtract::where('uid', $value['uid'])->where('status', 0)->sum('extract_price');
+            $value['money'] = bcsub($value['ex_price'], $value['extract_price'], 2);
+            $value['money'] = bcsub($value['money'], $cashPrice, 2);
+            $export[] = [
+                $value['nickname'],
+                $value['sum_number'],
+                $value['now_money'],
+                $value['brokerage_price'],
+                $value['extract_price'],
+            ];
+        }
+        if ($where['excel']) {
+            PHPExcelService::setExcelHeader(['昵称/姓名', '总佣金金额', '账户余额', '账户佣金', '提现到账佣金'])
+                ->setExcelTile('拥金记录', '拥金记录' . time(), ' 生成时间:' . date('Y-m-d H:i:s', time()))
+                ->setExcelContent($export)
+                ->ExcelSave();
+        }
+        $count = self::setCommissionWhere($where)->count();
+        return ['data' => $list, 'count' => $count];
+    }
+
+    //获取佣金记录列表的查询条件
+    public static function setCommissionWhere($where)
+    {
+        $models = self::setWherePage(self::alias('A'), $where, [], ['A.nickname', 'A.uid'])
+            ->join('user_bill B', 'B.uid=A.uid')
+            ->group('A.uid')
+            ->where('B.type', 'brokerage')
+            ->where('B.category', 'now_money')
+            ->field('sum(B.number) as sum_number,A.nickname,A.uid,A.now_money,A.brokerage_price');
+        if ($where['order'] == '') {
+            $models = $models->order('sum_number desc');
+        } else {
+            $models = $models->order($where['order'] == 1 ? 'sum_number desc' : 'sum_number asc');
+        }
+        if ($where['price_max'] != '' && $where['price_min'] != '') {
+            $models = $models->where('now_money', 'between', [$where['price_max'], $where['price_min']]);
+        }
+        return $models;
+    }
+
+    /**获取用户详细信息
+     * @param $uid
+     * @return array
+     */
+    public static function getUserInfos($uid)
+    {
+        $userInfo = self::where('uid', $uid)->find();
+        if (!$userInfo) exception('读取用户信息失败!');
+        return $userInfo->toArray();
+    }
+
+    //获取某人用户推广信息
+    public static function getUserinfo($uid)
+    {
+        $userinfo = self::where('uid', $uid)->field('nickname,spread_uid,now_money,add_time')->find()->toArray();
+        $userinfo['number'] = (float)UserBill::where('category', 'now_money')->where('uid', $uid)->where('type', 'brokerage')->sum('number');
+        $userinfo['spread_name'] = $userinfo['spread_uid'] ? self::where('uid', $userinfo['spread_uid'])->value('nickname') : '';
+        return $userinfo;
+    }
+
+    //获取某用户的详细信息
+    public static function getUserDetailed($uid)
+    {
+        $key_field = ['real_name', 'phone', 'province', 'city', 'district', 'detail', 'post_code'];
+        $Address = ($thisAddress = UserAddress::where('uid', $uid)->where('is_default', 1)->field($key_field)->find()) ?
+            $thisAddress :
+            UserAddress::where('uid', $uid)->field($key_field)->find();
+        $UserInfo = self::get($uid);
+        return [
+            ['col' => 12, 'name' => '默认收货地址', 'value' => $thisAddress ? '收货人:' . $thisAddress['real_name'] . '邮编:' . $thisAddress['post_code'] . ' 收货人电话:' . $thisAddress['phone'] . ' 地址:' . $thisAddress['province'] . ' ' . $thisAddress['city'] . ' ' . $thisAddress['district'] . ' ' . $thisAddress['detail'] : ''],
+//            ['name'=>'微信OpenID','value'=>WechatUser::where('uid', $uid)->value('openid'),'col'=>8],
+            ['name' => '手机号码', 'value' => $UserInfo['phone']],
+//            ['name'=>'ID','value'=>$uid],
+            ['name' => '姓名', 'value' => ''],
+            ['name' => '微信昵称', 'value' => $UserInfo['nickname']],
+            ['name' => '邮箱', 'value' => ''],
+            ['name' => '生日', 'value' => ''],
+            ['name' => '积分', 'value' => $UserInfo['integral']],
+            ['name' => '上级推广人', 'value' => $UserInfo['spread_uid'] ? self::where('uid', $UserInfo['spread_uid'])->value('nickname') : ''],
+            ['name' => '账户余额', 'value' => $UserInfo['now_money']],
+            ['name' => '佣金总收入', 'value' => UserBill::where('category', 'now_money')->where('type', 'brokerage')->where('uid', $uid)->sum('number')],
+            ['name' => '提现总金额', 'value' => UserExtract::where('uid', $uid)->where('status', 1)->sum('extract_price')],
+        ];
+    }
+
+    //获取某用户的订单个数,消费明细
+    public static function getHeaderList($uid)
+    {
+        return [
+            [
+                'title' => '总计订单',
+                'value' => StoreOrder::where('uid', $uid)->count(),
+                'key' => '笔',
+                'class' => '',
+            ],
+            [
+                'title' => '总消费金额',
+                'value' => StoreOrder::where('uid', $uid)->where('paid', 1)->sum('total_price'),
+                'key' => '元',
+                'class' => '',
+            ],
+            [
+                'title' => '本月订单',
+                'value' => StoreOrder::where('uid', $uid)->whereTime('add_time', 'month')->count(),
+                'key' => '笔',
+                'class' => '',
+            ],
+            [
+                'title' => '本月消费金额',
+                'value' => StoreOrder::where('uid', $uid)->where('paid', 1)->whereTime('add_time', 'month')->sum('total_price'),
+                'key' => '元',
+                'class' => '',
+            ]
+        ];
+    }
+
+    /*
+     * 获取 会员 订单个数,积分明细,优惠劵明细
+     *
+     * $uid 用户id;
+     *
+     * return array
+     */
+    public static function getCountInfo($uid)
+    {
+        $order_count = StoreOrder::where('uid', $uid)->count();
+        $integral_count = UserBill::where('uid', $uid)->where('category', 'integral')->where('type', 'in', 'deduction,system_add')->count();
+        $sign_count = UserBill::where('type', 'sign')->where('uid', $uid)->where('category', 'integral')->count();
+        $balanceChang_count = UserBill::where('category', 'now_money')->where('uid', $uid)
+            ->where('type', 'in', 'system_add,pay_product,extract,pay_product_refund,system_sub')
+            ->count();
+        $coupon_count = StoreCouponUser::where('uid', $uid)->count();
+        $spread_count = self::where('spread_uid', $uid)->count();
+        return compact('order_count', 'integral_count', 'sign_count', 'balanceChang_count', 'coupon_count', 'spread_count');
+    }
+
+    /*
+     * 获取 会员业务的
+     * 购物会员统计
+     *  会员访问量
+     *
+     * 曲线图
+     *
+     * $where 查询条件
+     *
+     * return array
+     */
+    public static function getUserBusinessChart($where, $limit = 20)
+    {
+        //获取购物会员人数趋势图
+        $list = self::getModelTime($where, self::where('a.status', 1)->alias('a')->join('store_order r', 'r.uid=a.uid'), 'a.add_time')
+            ->where('r.paid', 1)
+            ->where('a.is_promoter', 0)
+            ->where('a.add_time', '<>', 0)
+            ->field('FROM_UNIXTIME(a.add_time,"%Y-%m-%d") as _add_time,count(r.uid) as count_user')
+            ->group('_add_time')
+            ->order('_add_time asc')
+            ->select();
+        count($list) && $list = $list->toArray();
+        $seriesdata = [];
+        $xdata = [];
+        $zoom = '';
+        foreach ($list as $item) {
+            $seriesdata[] = $item['count_user'];
+            $xdata[] = $item['_add_time'];
+        }
+        count($xdata) > $limit && $zoom = $xdata[$limit - 5];
+        //会员访问量
+        $visit = self::getModelTime($where, self::alias('a')->join('store_visit t', 't.uid=a.uid'), 't.add_time')
+            ->where('a.is_promoter', 0)
+            ->field('FROM_UNIXTIME(t.add_time,"%Y-%m-%d") as _add_time,count(t.uid) as count_user')
+            ->group('_add_time')
+            ->order('_add_time asc')
+            ->select();
+        count($visit) && $visit = $visit->toArray();
+        $visit_data = [];
+        $visit_xdata = [];
+        $visit_zoom = '';
+        foreach ($visit as $item) {
+            $visit_data[] = $item['count_user'];
+            $visit_xdata[] = $item['_add_time'];
+        }
+        count($visit_xdata) > $limit && $visit_zoom = $visit_xdata[$limit - 5];
+        //多次购物会员数量饼状图
+        $count = self::getModelTime($where, self::where('is_promoter', 0))->count();
+        $user_count = self::getModelTime($where, self::alias('a')->join('store_order r', 'r.uid=a.uid'), 'a.add_time')
+            ->where('a.is_promoter', 0)
+            ->where('r.paid', 1)
+            ->group('a.uid')
+            ->count();
+        $shop_xdata = ['多次购买数量占比', '无购买数量占比'];
+        $shop_data = [];
+        $count > 0 && $shop_data = [
+            [
+                'value' => bcdiv($user_count, $count, 2) * 100,
+                'name' => $shop_xdata[0],
+                'itemStyle' => [
+                    'color' => '#D789FF',
+                ]
+            ],
+            [
+                'value' => bcdiv($count - $user_count, $count, 2) * 100,
+                'name' => $shop_xdata[1],
+                'itemStyle' => [
+                    'color' => '#7EF0FB',
+                ]
+            ]
+        ];
+        return compact('seriesdata', 'xdata', 'zoom', 'visit_data', 'visit_xdata', 'visit_zoom', 'shop_data', 'shop_xdata');
+    }
+
+    /*
+     * 获取用户
+     * 积分排行
+     * 会员余额排行榜
+     * 分销商佣金总额排行榜
+     * 购物笔数排行榜
+     * 购物金额排行榜
+     * 分销商佣金提现排行榜
+     * 上月消费排行榜
+     * $limit 查询多少条
+     * return array
+     */
+    public static function getUserTop10List($limit = 10, $is_promoter = 0)
+    {
+        //积分排行
+        $integral = self::where('status', 1)
+            ->where('is_promoter', $is_promoter)
+            ->order('integral desc')
+            ->field('nickname,phone,integral,FROM_UNIXTIME(add_time,"%Y-%m-%d") as add_time')
+            ->limit($limit)
+            ->select();
+        count($integral) && $integral = $integral->toArray();
+        //会员余额排行榜
+        $now_money = self::where('status', 1)
+            ->where('is_promoter', $is_promoter)
+            ->order('now_money desc')
+            ->field('nickname,phone,now_money,FROM_UNIXTIME(add_time,"%Y-%m-%d") as add_time')
+            ->limit($limit)
+            ->select();
+        count($now_money) && $now_money = $now_money->toArray();
+        //购物笔数排行榜
+        $orderPayCount = StoreOrder::getOrderPayCount($is_promoter);
+        if ($orderPayCount) {
+            $shopcount = self::alias('a')
+                ->join('store_order r', 'r.uid=a.uid')
+                ->where('r.paid', 1)
+                ->where('a.is_promoter', $is_promoter)
+                ->group('r.uid')
+                ->field('a.nickname,a.phone,count(r.uid) as sum_count,FROM_UNIXTIME(a.add_time,"%Y-%m-%d") as add_time')
+                ->order('sum_count desc')
+                ->limit($limit)
+                ->select();
+        } else $shopcount = [];
+        count($shopcount) && $shopcount = $shopcount->toArray();
+        //购物金额排行榜
+        if ($orderPayCount) {
+            $order = self::alias('a')
+                ->join('store_order r', 'r.uid=a.uid')
+                ->where('r.paid', 1)
+                ->where('a.is_promoter', $is_promoter)
+                ->group('r.uid')
+                ->field('a.nickname,a.phone,sum(r.pay_price) as sum_price,FROM_UNIXTIME(a.add_time,"%Y-%m-%d") as add_time,r.uid')
+                ->order('sum_price desc')
+                ->limit($limit)
+                ->select();
+        } else $order = [];
+        count($order) && $order = $order->toArray();
+        //上月消费排行
+        $orderPayCount = StoreOrder::getOrderPayMonthCount($is_promoter);
+        if ($orderPayCount) {
+            $lastorder = self::alias('a')
+                ->join('store_order r', 'r.uid=a.uid')
+                ->where('r.paid', 1)
+                ->where('a.is_promoter', $is_promoter)
+//                ->whereTime('r.pay_time','last month')
+                ->where('r.pay_time', 'between', [strtotime(date('Y-m', strtotime('-1 month'))), strtotime(date('Y-m'))])
+                ->group('r.uid')
+                ->field('a.nickname,a.phone,sum(r.pay_price) as sum_price,FROM_UNIXTIME(a.add_time,"%Y-%m-%d") as add_time,r.uid')
+                ->order('sum_price desc')
+                ->limit($limit)
+                ->select();
+        } else $lastorder = [];
+        count($lastorder) && $lastorder = $lastorder->toArray();
+        return compact('integral', 'now_money', 'shopcount', 'order', 'lastorder');
+    }
+
+    /*
+     * 获取 会员业务
+     * 会员总余额 会员总积分
+     * $where 查询条件
+     *
+     * return array
+     */
+    public static function getUserBusinesHeade($where)
+    {
+        return [
+            [
+                'name' => '会员总余额',
+                'field' => '元',
+                'count' => self::getModelTime($where, self::where('status', 1))->sum('now_money'),
+                'background_color' => 'layui-bg-cyan',
+                'col' => 6,
+            ],
+            [
+                'name' => '会员总积分',
+                'field' => '分',
+                'count' => self::getModelTime($where, self::where('status', 1))->sum('integral'),
+                'background_color' => 'layui-bg-cyan',
+                'col' => 6
+            ]
+        ];
+    }
+
+    /*
+     * 分销会员头部信息查询获取
+     *
+     * 分销商总佣金余额
+     * 分销商总提现佣金
+     * 本月分销商业务佣金
+     * 本月分销商佣金提现金额
+     * 上月分销商业务佣金
+     * 上月分销商佣金提现金额
+     * $where array 时间条件
+     *
+     * return array
+     */
+    public static function getDistributionBadgeList($where)
+    {
+        $timeList = [
+            'today' => implode(' - ', [date('Y/m/d'), date('Y/m/d', strtotime('+1 day'))]),
+            'week' => implode(' - ', [
+                date('Y/m/d', (time() - ((date('w') == 0 ? 7 : date('w')) - 1) * 24 * 3600)),
+                date('Y-m-d', (time() + (7 - (date('w') == 0 ? 7 : date('w'))) * 24 * 3600))
+            ]),
+            'month' => implode(' - ', [date('Y/m') . '/01', date('Y/m') . '/' . date('t')]),
+            'quarter' => implode(' - ', [
+                date('Y') . '/' . (ceil((date('n')) / 3) * 3 - 3 + 1) . '/01',
+                date('Y') . '/' . (ceil((date('n')) / 3) * 3) . '/' . date('t', mktime(0, 0, 0, (ceil((date('n')) / 3) * 3), 1, date('Y')))
+            ]),
+            'year' => implode(' - ', [
+                date('Y') . '/01/01', date('Y/m/d', strtotime(date('Y') . '/01/01 + 1year -1 day'))
+            ])
+        ];
+        $timeKey = ['today', 'week', 'month', 'quarter', 'year'];
+        if (in_array($where['data'], $timeKey)) $where['data'] = $timeList[$where['data']];
+        $uid = self::name('user')->where('status', 1)->where('is_promoter', 1)->whereOr('spread_uid', '<>', 0)->column('uid', 'uid');
+        return [
+            [
+                'name' => '分销商总佣金',
+                'field' => '元',
+                'count' => count($uid) ? self::getModelTime($where, UserBill::where('category', 'now_money')->where('type', 'brokerage'))->where('uid', 'in', implode(',', $uid))->sum('number') : 0,
+                'background_color' => 'layui-bg-cyan',
+                'col' => 3,
+            ],
+            [
+                'name' => '分销商总佣金余额',
+                'field' => '元',
+                'count' => self::getModelTime($where, self::where('status', 1)->where('is_promoter', 1))->sum('now_money'),
+                'background_color' => 'layui-bg-cyan',
+                'col' => 3,
+            ],
+            [
+                'name' => '分销商总提现佣金',
+                'field' => '元',
+                'count' => self::getModelTime($where, UserExtract::where('status', 1))->sum('extract_price'),
+                'background_color' => 'layui-bg-cyan',
+                'col' => 3,
+            ],
+            [
+                'name' => '本月分销商业务佣金',
+                'field' => '元',
+                'count' => count($uid) ? self::getModelTime(['data' => 'month'], UserBill::where('category', 'now_money')->where('type', 'brokerage'))
+                    ->where('uid', 'in', implode(',', $uid))->sum('number') : 0,
+                'background_color' => 'layui-bg-cyan',
+                'col' => 3,
+            ],
+            [
+                'name' => '本月分销商佣金提现金额',
+                'field' => '元',
+                'count' => count($uid) ? self::getModelTime(['data' => 'month'], UserExtract::where('status', 1))
+                    ->where('uid', 'in', implode(',', $uid))->sum('extract_price') : 0,
+                'background_color' => 'layui-bg-cyan',
+                'col' => 4,
+            ],
+            [
+                'name' => '上月分销商业务佣金',
+                'field' => '元',
+                'count' => count($uid) ? self::getOldDate(['data' => 'year'], UserBill::where('category', 'now_money')->where('uid', 'in', implode(',', $uid))->where('type', 'brokerage'))->sum('number') : 0,
+                'background_color' => 'layui-bg-cyan',
+                'col' => 4,
+            ],
+            [
+                'name' => '上月分销商佣金提现金额',
+                'field' => '元',
+                'count' => count($uid) ? self::getOldDate(['data' => 'year'], UserBill::where('category', 'now_money')->where('uid', 'in', implode(',', $uid))->where('type', 'brokerage'))->sum('number') : 0,
+                'background_color' => 'layui-bg-cyan',
+                'col' => 4,
+            ],
+        ];
+    }
+
+    /*
+     * 分销会员
+     * 分销数量 饼状图
+     * 分销商会员访问量 曲线
+     * 获取购物会员人数趋势图 曲线
+     * 多次购物分销会员数量 饼状图
+     * $where array 条件
+     * $limit int n条数据后出拖动条
+     * return array
+     */
+    public static function getUserDistributionChart($where, $limit = 20)
+    {
+        //分销数量
+        $fenbu_user = self::getModelTime($where, new self)->field('count(uid) as num')->group('is_promoter')->select();
+        count($fenbu_user) && $fenbu_user = $fenbu_user->toArray();
+        $sum_user = 0;
+        $fenbu_data = [];
+        $fenbu_xdata = ['分销商', '非分销商'];
+        $color = ['#81BCFE', '#91F3FE'];
+        foreach ($fenbu_user as $item) {
+            $sum_user += $item['num'];
+        }
+        foreach ($fenbu_user as $key => $item) {
+            $value['value'] = bcdiv($item['num'], $sum_user, 2) * 100;
+            $value['name'] = isset($fenbu_xdata[$key]) ? $fenbu_xdata[$key] . '  %' . $value['value'] : '';
+            $value['itemStyle']['color'] = $color[$key];
+            $fenbu_data[] = $value;
+        }
+        //分销商会员访问量
+        $visit = self::getModelTime($where, self::alias('a')->join('store_visit t', 't.uid=a.uid'), 't.add_time')
+            ->where('a.is_promoter', 1)
+            ->field(['FROM_UNIXTIME(t.add_time,"%Y-%m-%d") as _add_time', 'count(t.uid) as count_user'])
+            ->group('_add_time')
+            ->order('_add_time asc')
+            ->select();
+//        echo self::getLastSql();die;
+        count($visit) && $visit = $visit->toArray();
+        $visit_data = [];
+        $visit_xdata = [];
+        $visit_zoom = '';
+        foreach ($visit as $item) {
+            $visit_data[] = $item['count_user'];
+            $visit_xdata[] = $item['_add_time'];
+        }
+        count($visit_xdata) > $limit && $visit_zoom = $visit_xdata[$limit - 5];
+        //获取购物会员人数趋势图
+        $list = self::getModelTime($where, self::where('a.status', 1)->alias('a')->join('store_order r', 'r.uid=a.uid'), 'a.add_time')
+            ->where('r.paid', 1)
+            ->where('a.is_promoter', 1)
+            ->where('a.add_time', '<>', 0)
+            ->field('FROM_UNIXTIME(a.add_time,"%Y-%m-%d") as _add_time,count(r.uid) as count_user')
+            ->group('_add_time')
+            ->order('_add_time asc')
+            ->select();
+        count($list) && $list = $list->toArray();
+        $seriesdata = [];
+        $xdata = [];
+        $zoom = '';
+        foreach ($list as $item) {
+            $seriesdata[] = $item['count_user'];
+            $xdata[] = $item['_add_time'];
+        }
+        count($xdata) > $limit && $zoom = $xdata[$limit - 5];
+        //多次购物分销会员数量饼状图
+        $count = self::getModelTime($where, self::where('is_promoter', 1))->count();
+        $user_count = self::getModelTime($where, self::alias('a')
+            ->join('store_order r', 'r.uid=a.uid'), 'a.add_time')
+            ->where('a.is_promoter', 1)
+            ->where('r.paid', 1)
+            ->group('a.uid')
+            ->count();
+        $shop_xdata = ['多次购买数量占比', '无购买数量占比'];
+        $shop_data = [];
+        $count > 0 && $shop_data = [
+            [
+                'value' => bcdiv($user_count, $count, 2) * 100,
+                'name' => $shop_xdata[0] . $user_count . '人',
+                'itemStyle' => [
+                    'color' => '#D789FF',
+                ]
+            ],
+            [
+                'value' => bcdiv($count - $user_count, $count, 2) * 100,
+                'name' => $shop_xdata[1] . ($count - $user_count) . '人',
+                'itemStyle' => [
+                    'color' => '#7EF0FB',
+                ]
+            ]
+        ];
+        return compact('fenbu_data', 'fenbu_xdata', 'visit_data', 'visit_xdata', 'visit_zoom', 'seriesdata', 'xdata', 'zoom', 'shop_xdata', 'shop_data');
+    }
+
+    /*
+     * 分销商佣金提现排行榜
+     * 分销商佣金总额排行榜
+     * $limit 截取条数
+     * return array
+     */
+    public static function getUserDistributionTop10List($limit)
+    {
+        //分销商佣金提现排行榜
+        $extract = self::alias('a')
+            ->join('user_extract t', 'a.uid=t.uid')
+            ->where('t.status', 1)
+            ->where('a.is_promoter', 1)
+            ->group('t.uid')
+            ->field('a.nickname,a.phone,sum(t.extract_price) as sum_price,FROM_UNIXTIME(a.add_time,"%Y-%m-%d") as add_time,t.uid')
+            ->order('sum_price desc')
+            ->limit($limit)
+            ->select();
+        count($extract) && $extract = $extract->toArray();
+        //分销商佣金总额排行榜
+        $commission = UserBill::alias('l')
+            ->join('user a', 'l.uid=a.uid')
+            ->where('l.status', 1)
+            ->where('l.category', 'now_money')
+            ->where('l.type', 'brokerage')
+            ->where('a.is_promoter', 1)
+            ->group('l.uid')
+            ->field('a.nickname,a.phone,sum(number) as sum_number,FROM_UNIXTIME(a.add_time,"%Y-%m-%d") as add_time')
+            ->order('sum_number desc')
+            ->limit($limit)
+            ->select();
+        count($commission) && $commission = $commission->toArray();
+        return compact('extract', 'commission');
+    }
+
+    public static function getSpreadList($uid, $page, $limit)
+    {
+        $list = self::where('spread_uid', $uid)->field('uid,nickname,now_money,integral,add_time')
+            ->order('uid desc')->page((int)$page, (int)$limit)->select();
+        count($list) && $list = $list->toArray();
+        foreach ($list as &$item) {
+            $item['add_time'] = date('Y-m-d H', $item['add_time']);
+        }
+        return $list;
+    }
+
+    /**
+     * 一级分销
+     * @param $orderInfo
+     * @return bool
+     */
+    public static function backOrderBrokerage($orderInfo)
+    {
+        $userInfo = User::getUserInfo($orderInfo['uid']);
+        if (!$userInfo || !$userInfo['spread_uid']) return true;
+        $storeBrokerageStatu = sys_config('store_brokerage_statu') ?: 1;//获取后台分销类型
+        if ($storeBrokerageStatu == 1) {
+            if (!User::be(['uid' => $userInfo['spread_uid'], 'is_promoter' => 1])) return true;
+        }
+        $brokerageRatio = (sys_config('store_brokerage_ratio') ?: 0) / 100;
+        if ($brokerageRatio <= 0) return true;
+        $cost = isset($orderInfo['cost']) ? $orderInfo['cost'] : 0;//成本价
+        if ($cost > $orderInfo['pay_price']) return true;//成本价大于支付价格时直接返回
+        $brokeragePrice = bcmul(bcsub($orderInfo['pay_price'], $cost, 2), $brokerageRatio, 2);
+        //返佣之后余额
+        $spNow_money = User::where('uid', $userInfo['spread_uid'])->value('now_money');
+        $balance = bcadd($spNow_money, $brokeragePrice, 2);
+        if ($brokeragePrice <= 0) return true;
+        $mark = $userInfo['nickname'] . '成功消费' . floatval($orderInfo['pay_price']) . '元,奖励推广佣金' . floatval($brokeragePrice);
+        self::beginTrans();
+        $res1 = UserBill::income('获得推广佣金', $userInfo['spread_uid'], 'now_money', 'brokerage', $brokeragePrice, $orderInfo['id'], $balance, $mark);
+        $res2 = self::bcInc($userInfo['spread_uid'], 'now_money', $brokeragePrice, 'uid');
+        $res = $res1 && $res2;
+        self::checkTrans($res);
+        if ($res) self::backOrderBrokerageTwo($orderInfo);
+        return $res;
+    }
+
+    /**
+     * 二级推广
+     * @param $orderInfo
+     * @return bool
+     */
+    public static function backOrderBrokerageTwo($orderInfo)
+    {
+        $userInfo = User::getUserInfo($orderInfo['uid']);
+        $userInfoTwo = User::getUserInfo($userInfo['spread_uid']);
+        if (!$userInfoTwo || !$userInfoTwo['spread_uid']) return true;
+        $storeBrokerageStatu = sys_config('store_brokerage_statu') ?: 1;//获取后台分销类型
+        if ($storeBrokerageStatu == 1) {
+            if (!User::be(['uid' => $userInfoTwo['spread_uid'], 'is_promoter' => 1])) return true;
+        }
+        $brokerageRatio = (sys_config('store_brokerage_two') ?: 0) / 100;
+        if ($brokerageRatio <= 0) return true;
+        $cost = isset($orderInfo['cost']) ? $orderInfo['cost'] : 0;//成本价
+        if ($cost > $orderInfo['pay_price']) return true;//成本价大于支付价格时直接返回
+        $brokeragePrice = bcmul(bcsub($orderInfo['pay_price'], $cost, 2), $brokerageRatio, 2);
+        //返佣之后余额
+        $spNow_money = User::where('uid', $userInfo['spread_uid'])->value('now_money');
+        $balance = bcadd($spNow_money, $brokeragePrice, 2);
+        if ($brokeragePrice <= 0) return true;
+        $mark = '二级推广人' . $userInfo['nickname'] . '成功消费' . floatval($orderInfo['pay_price']) . '元,奖励推广佣金' . floatval($brokeragePrice);
+        self::beginTrans();
+        $res1 = UserBill::income('获得推广佣金', $userInfoTwo['spread_uid'], 'now_money', 'brokerage', $brokeragePrice, $orderInfo['id'], $balance, $mark);
+        $res2 = self::bcInc($userInfoTwo['spread_uid'], 'now_money', $brokeragePrice, 'uid');
+        $res = $res1 && $res2;
+        self::checkTrans($res);
+        return $res;
+    }
+}

+ 61 - 0
app/admin/model/user/UserAddress.php

@@ -0,0 +1,61 @@
+<?php
+/**
+ * @author: xaboy<365615158@qq.com>
+ * @day: 2017/12/25
+ */
+
+namespace app\admin\model\user;
+
+use crmeb\basic\BaseModel;
+use crmeb\traits\ModelTrait;
+
+class UserAddress extends BaseModel
+{
+    /**
+     * 数据表主键
+     * @var string
+     */
+    protected $pk = 'id';
+
+    /**
+     * 模型名称
+     * @var string
+     */
+    protected $name = 'user_address';
+
+    use ModelTrait;
+
+    protected $insert = ['add_time'];
+
+    protected function setAddTimeAttr()
+    {
+        return time();
+    }
+
+    public static function setDefaultAddress($id,$uid)
+    {
+        self::beginTrans();
+        $res1 = self::where('uid',$uid)->update(['is_default'=>0]);
+        $res2 = self::where('id',$id)->where('uid',$uid)->update(['is_default'=>1]);
+        $res =$res1 !== false && $res2 !== false;
+        self::checkTrans($res);
+        return $res;
+    }
+
+    public static function userValidAddressWhere($model=null,$prefix = '')
+    {
+        if($prefix) $prefix .='.';
+        $model = self::getSelfModel($model);
+        return $model->where("{$prefix}is_del",0);
+    }
+
+    public static function getUserValidAddressList($uid,$field = '*')
+    {
+        return self::userValidAddressWhere()->where('uid',$uid)->order('add_time DESC')->field($field)->select()->toArray()?:[];
+    }
+
+    public static function getUserDefaultAddress($uid,$field = '*')
+    {
+        return self::userValidAddressWhere()->where('uid',$uid)->where('is_default',1)->field($field)->find();
+    }
+}

+ 330 - 0
app/admin/model/user/UserBill.php

@@ -0,0 +1,330 @@
+<?php
+namespace app\admin\model\user;
+
+use crmeb\traits\ModelTrait;
+use crmeb\basic\BaseModel;
+use think\facade\Db;
+
+/**
+ * 用户消费新增金额明细 model
+ * Class User
+ * @package app\admin\model\user
+ */
+class UserBill extends BaseModel
+{
+    /**
+     * 数据表主键
+     * @var string
+     */
+    protected $pk = 'id';
+
+    /**
+     * 模型名称
+     * @var string
+     */
+    protected $name = 'user_bill';
+
+    use ModelTrait;
+
+    /*
+     * 获取总佣金
+     * */
+    public static function getBrokerage($uid,$category = 'now_money',$type='brokerage',$where)
+    {
+        return self::getModelTime($where,self::where('uid','in',$uid)->where('category',$category)
+            ->where('type',$type)->where('pm',1)->where('status',1))->sum('number');
+    }
+
+    //修改积分减少积分记录
+    public static function expend($title,$uid,$category,$type,$number,$link_id = 0,$balance = 0,$mark = '',$status = 1)
+    {
+        $pm = 0;
+        $add_time = time();
+        return self::create(compact('title','uid','link_id','category','type','number','balance','mark','status','pm','add_time'));
+    }
+    //修改积分增加积分记录
+    public static function income($title,$uid,$category,$type,$number,$link_id = 0,$balance = 0,$mark = '',$status = 1){
+        $pm = 1;
+        $add_time = time();
+        return self::create(compact('title','uid','link_id','category','type','number','balance','mark','status','pm','add_time'));
+    }
+    //获取柱状图和饼状图数据
+    public static function getUserBillChart($where,$category='now_money',$type='brokerage',$pm=1,$zoom=15){
+        $model=self::getModelTime($where,new self());
+        $list=$model->field('FROM_UNIXTIME(add_time,"%Y-%c-%d") as un_time,sum(number) as sum_number')
+            ->order('un_time asc')
+            ->where('category', $category)
+            ->where('type', $type)
+            ->where('pm', $pm)
+            ->group('un_time')
+            ->select();
+        if(count($list)) $list=$list->toArray();
+        $legdata = [];
+        $listdata = [];
+        $dataZoom = '';
+        foreach ($list as $item){
+            $legdata[]=$item['un_time'];
+            $listdata[]=$item['sum_number'];
+        }
+        if(count($legdata)>=$zoom) $dataZoom=$legdata[$zoom-1];
+        //获取用户分布钱数
+        $fenbulist=self::getModelTime($where,new self(),'a.add_time')
+            ->alias('a')
+            ->join('user r','a.uid=r.uid')
+            ->field('a.uid,sum(a.number) as sum_number,r.nickname')
+            ->where('a.category',$category)
+            ->where('a.type', $type)
+            ->where('a.pm', $pm)
+            ->order('sum_number desc')
+            ->group('a.uid')
+            ->limit(8)
+            ->select();
+        //获取用户当前时间段总钱数
+        $sum_number=self::getModelTime($where,new self())
+            ->alias('a')
+            ->where('a.category',$category)
+            ->where('a.type', $type)
+            ->where('a.pm', $pm)
+            ->sum('number');
+        if(count($fenbulist)) $fenbulist=$fenbulist->toArray();
+        $fenbudate=[];
+        $fenbu_legend=[];
+        $color=['#ffcccc','#99cc00','#fd99cc','#669966','#66CDAA','#ADFF2F','#00BFFF','#00CED1','#66cccc','#ff9900','#ffcc00','#336699','#cccc00','#99ccff','#990066'];
+        foreach ($fenbulist as $key=>$value){
+            $fenbu_legend[]=$value['nickname'];
+            $items['name']=$value['nickname'];
+            $items['value']=bcdiv($value['sum_number'],$sum_number,2)*100;
+            $items['itemStyle']['color']=$color[$key];
+            $fenbudate[]=$items;
+        }
+        return compact('legdata','listdata','fenbudate','fenbu_legend','dataZoom');
+    }
+    //获取头部信息
+    public static function getRebateBadge($where){
+        $datawhere=['category'=>'now_money','type'=>'brokerage','pm'=>1];
+        return [
+            [
+                'name'=>'返利数(笔)',
+                'field'=>'个',
+                'count'=>self::getModelTime($where,new self())->where($datawhere)->count(),
+                'content'=>'返利总笔数',
+                'background_color'=>'layui-bg-blue',
+                'sum'=>self::where($datawhere)->count(),
+                'class'=>'fa fa-bar-chart',
+            ],
+            [
+                'name'=>'返利金额(元)',
+                'field'=>'个',
+                'count'=>self::getModelTime($where,new self())->where($datawhere)->sum('number'),
+                'content'=>'返利总金额',
+                'background_color'=>'layui-bg-cyan',
+                'sum'=>self::where($datawhere)->sum('number'),
+                'class'=>'fa fa-line-chart',
+            ],
+        ];
+    }
+    //获取返佣用户信息列表
+    public static function getFanList($where){
+        $list=self::alias('a')->join('user r','a.uid=r.uid')
+            ->where('a.category','now_money')
+            ->where('a.type', 'brokerage')
+            ->where('a.pm', 1)
+            ->order('a.number desc')
+            ->join('store_order o','o.id=a.link_id')
+            ->field('o.order_id,FROM_UNIXTIME(a.add_time,"%Y-%c-%d") as add_time,a.uid,o.uid as down_uid,r.nickname,r.avatar,r.spread_uid,r.level,a.number')
+            ->page((int)$where['page'],(int)$where['limit'])
+            ->select();
+        if(count($list)) $list=$list->toArray();
+        return $list;
+    }
+    //获取返佣用户总人数
+    public static function getFanCount(){
+        return self::alias('a')->join('user r','a.uid=r.uid')->join('store_order o','o.id=a.link_id')->where('a.category','now_money')->where('a.type', 'brokerage')->where('a.pm', 1)->count();
+    }
+    //获取用户充值数据
+    public static function getEchartsRecharge($where,$limit=15){
+        $datawhere=['category'=>'now_money','pm'=>1];
+        $list=self::getModelTime($where,self::where($datawhere)->where('type','in',['recharge','system_add']))
+            ->field('sum(number) as sum_money,FROM_UNIXTIME(add_time,"%Y-%c-%d") as un_time,count(id) as count')
+            ->group('un_time')
+            ->order('un_time asc')
+            ->select();
+        if(count($list)) $list=$list->toArray();
+        $sum_count = self::getModelTime($where,self::where($datawhere)->where('type','in','recharge,system_add'))->count();
+        $xdata = [];
+        $seriesdata = [];
+        $data = [];
+        $zoom = '';
+        foreach ($list as $value){
+            $xdata[]=$value['un_time'];
+            $seriesdata[]=$value['sum_money'];
+            $data[]=$value['count'];
+        }
+        if(count($xdata)>$limit){
+            $zoom=$xdata[$limit-5];
+        }
+        return compact('xdata','seriesdata','data','zoom');
+    }
+    //获取佣金提现列表
+    public static function getExtrctOneList($where,$uid){
+        $list=self::setOneWhere($where,$uid)
+            ->field('number,link_id,mark,FROM_UNIXTIME(add_time,"%Y-%m-%d %H:%i:%s") as _add_time,status')
+            ->select();
+        count($list) && $list=$list->toArray();
+        $count=self::setOneWhere($where,$uid)->count();
+        foreach ($list as &$value){
+            $value['order_id'] = Db::name('store_order')->where('order_id', $value['link_id'])->value('order_id');
+        }
+        return ['data'=>$list,'count'=>$count];
+    }
+    //设置单个用户查询
+    public static function setOneWhere($where,$uid){
+        $model=self::where('uid', $uid)->where('category', 'now_money')->where('type', 'brokerage');
+        $time['data'] = '';
+        if(strlen(trim($where['start_time'])) && strlen(trim($where['end_time']))){
+            $time['data'] = $where['start_time'].' - '.$where['end_time'];
+            $model = self::getModelTime($time,$model);
+        }
+        if(strlen(trim($where['nickname']))){
+            $model = $model->where('link_id|mark','like',"%$where[nickname]%");
+        }
+        return $model;
+    }
+    //查询积分个人明细
+    public static function getOneIntegralList($where){
+        return self::setWhereList(
+            $where,'',
+//            ['deduction','system_add','sign'],
+            ['title','number','balance','mark','FROM_UNIXTIME(add_time,"%Y-%m-%d") as add_time'],
+            'integral'
+        );
+    }
+    //查询个人签到明细
+    public static function getOneSignList($where){
+        return self::setWhereList(
+            $where,'sign',
+            ['title','number','mark','FROM_UNIXTIME(add_time,"%Y-%m-%d") as add_time']
+            );
+    }
+    //查询个人余额变动记录
+    public static function getOneBalanceChangList($where){
+         $list=self::setWhereList(
+            $where,'',
+//            ['system_add','pay_product','extract','pay_product_refund','system_sub','brokerage','recharge','user_recharge_refund'],
+            ['FROM_UNIXTIME(add_time,"%Y-%m-%d") as add_time','title','type','mark','number','balance','pm','status'],
+            'now_money'
+        );
+         foreach ($list as &$item){
+            switch ($item['type']){
+                case 'system_add':
+                    $item['_type']='系统添加';
+                    break;
+                case 'pay_product':
+                    $item['_type']='商品购买';
+                    break;
+                case 'extract':
+                    $item['_type']='提现';
+                    break;
+                case 'pay_product_refund':
+                    $item['_type']='退款';
+                    break;
+                case 'system_sub':
+                    $item['_type']='系统减少';
+                    break;
+                case 'brokerage':
+                    $item['_type']='系统返佣';
+                    break;
+                case 'recharge':
+                    $item['_type']='余额充值';
+                    break;
+                case 'user_recharge_refund':
+                    $item['_type']='系统退款';
+                    break;
+            }
+            $item['_pm']=$item['pm']==1 ? '获得': '支出';
+         }
+         return $list;
+    }
+    //设置where条件分页.返回数据
+    public static function setWhereList($where,$type='',$field=[],$category='integral'){
+        $models=self::where('uid',$where['uid'])
+            ->where('category',$category)
+            ->page((int)$where['page'],(int)$where['limit'])
+            ->order('id','desc')
+            ->field($field);
+        if(is_array($type)){
+            $models=$models->where('type','in',$type);
+        }else{
+            if(!empty($type))$models=$models->where('type',$type);
+        }
+        return ($list=$models->select()) && count($list) ? $list->toArray():[];
+    }
+    //获取积分统计头部信息
+    public static function getScoreBadgeList($where){
+        return [
+            [
+                'name'=>'历史总积分',
+                'field'=>'个',
+                'count'=>self::getModelTime($where,new self())->where('category','integral')->where('type','in','gain,system_sub,deduction,sign')->sum('number'),
+                'background_color'=>'layui-bg-blue',
+                'col'=>4,
+            ],
+            [
+                'name'=>'已使用积分',
+                'field'=>'个',
+                'count'=>self::getModelTime($where,new self())->where('category','integral')->where('type','deduction')->sum('number'),
+                'background_color'=>'layui-bg-cyan',
+                'col'=>4,
+            ],
+            [
+                'name'=>'未使用积分',
+                'field'=>'个',
+                'count'=>self::getModelTime($where,Db::name('user'))->sum('integral'),
+                'background_color'=>'layui-bg-cyan',
+                'col'=>4,
+            ],
+        ];
+    }
+    //获取积分统计曲线图和柱状图
+    public static function getScoreCurve($where){
+        //发放积分趋势图
+         $list=self::getModelTime($where,self::where('category','integral')
+            ->field('FROM_UNIXTIME(add_time,"%Y-%m-%d") as _add_time,sum(number) as sum_number')
+            ->group('_add_time')->order('_add_time asc'))->select()->toArray();
+         $date=[];
+         $zoom='';
+         $seriesdata=[];
+         foreach ($list as $item){
+             $date[]=$item['_add_time'];
+             $seriesdata[]=$item['sum_number'];
+         }
+         unset($item);
+         if(count($date)>$where['limit']){
+             $zoom=$date[$where['limit']-5];
+         }
+        //使用积分趋势图
+        $deductionlist=self::getModelTime($where,self::where('category','integral')->where('type','deduction')
+            ->field('FROM_UNIXTIME(add_time,"%Y-%m-%d") as _add_time,sum(number) as sum_number')
+            ->group('_add_time')->order('_add_time asc'))->select()->toArray();
+         $deduction_date=[];
+         $deduction_zoom='';
+         $deduction_seriesdata=[];
+         foreach ($deductionlist as $item){
+             $deduction_date[]=$item['_add_time'];
+             $deduction_seriesdata[]=$item['sum_number'];
+         }
+         if(count($deductionlist)>$where['limit']){
+             $deduction_zoom=$deductionlist[$where['limit']-5];
+         }
+         return compact('date','seriesdata','zoom','deduction_date','deduction_zoom','deduction_seriesdata');
+    }
+
+    /**
+     * 用户获得总佣金
+     * @return float
+     */
+    public static function getBrokerageCount()
+    {
+        return self::where('type', 'brokerage')->where('category', 'now_money')->where('status', 1)->where('pm', 1)->sum('number');
+    }
+}

+ 340 - 0
app/admin/model/user/UserExtract.php

@@ -0,0 +1,340 @@
+<?php
+/**
+ * Created by PhpStorm.
+ * User: lianghuan
+ * Date: 2018-03-03
+ * Time: 16:47
+ */
+
+namespace app\admin\model\user;
+
+use app\admin\model\wechat\WechatUser;
+use app\models\routine\RoutineTemplate;
+use think\facade\Route as Url;
+use crmeb\traits\ModelTrait;
+use crmeb\basic\BaseModel;
+use crmeb\services\WechatTemplateService;
+
+/**
+ * 用户提现管理 model
+ * Class User
+ * @package app\admin\model\user
+ */
+class UserExtract extends BaseModel
+{
+    /**
+     * 数据表主键
+     * @var string
+     */
+    protected $pk = 'id';
+
+    /**
+     * 模型名称
+     * @var string
+     */
+    protected $name = 'user_extract';
+
+    use ModelTrait;
+
+    /**
+     * 获得用户提现总金额
+     * @param $uid
+     * @return mixed
+     */
+    public static function userExtractTotalPrice($uid, $status = 1, $where = [])
+    {
+        return self::getModelTime($where, self::where('uid', 'in', $uid)->where('status', $status))->sum('extract_price') ?: 0;
+    }
+
+    public static function extractStatistics()
+    {
+        //待提现金额
+        $data['price'] = floatval(self::where('status', 0)->sum('extract_price'));
+        //佣金总金额
+        $data['brokerage_count'] = floatval(UserBill::getBrokerageCount());
+        //已提现金额
+        $data['priced'] = floatval(self::where('status', 1)->sum('extract_price'));
+        //未提现金额
+        $data['brokerage_not'] = bcsub(bcsub($data['brokerage_count'], $data['priced'], 2), $data['price'], 2);
+        return compact('data');
+    }
+
+    /**
+     * @param $where
+     * @return array
+     */
+    public static function systemPage($where)
+    {
+        $model = new self;
+        if ($where['date'] != '') {
+            list($startTime, $endTime) = explode(' - ', $where['date']);
+            $model = $model->where('a.add_time', '>', strtotime($startTime));
+            $model = $model->where('a.add_time', '<', (int)bcadd(strtotime($endTime), 86400, 0));
+        }
+        if ($where['status'] != '') $model = $model->where('a.status', $where['status']);
+        if ($where['extract_type'] != '') $model = $model->where('a.extract_type', $where['extract_type']);
+        if ($where['nireid'] != '') $model = $model->where('a.real_name|a.id|b.nickname|a.bank_code|a.alipay_code', 'like', "%$where[nireid]%");
+        $model = $model->alias('a');
+        $model = $model->field('a.*,b.nickname');
+        $model = $model->join('user b', 'b.uid=a.uid', 'LEFT');
+        $model = $model->order('a.id desc');
+        return self::page($model, $where);
+    }
+
+    public static function changeFail($id, $fail_msg)
+    {
+        $fail_time = time();
+        $data = self::get($id);
+        $extract_number = $data['extract_price'];
+        $mark = '提现失败,退回佣金' . $extract_number . '元';
+        $uid = $data['uid'];
+        $status = -1;
+        $User = User::where('uid', $uid)->find()->toArray();
+        UserBill::income('提现失败', $uid, 'now_money', 'extract', $extract_number, $id, bcadd($User['now_money'], $extract_number, 2), $mark);
+        User::bcInc($uid, 'brokerage_price', $extract_number, 'uid');
+        $extract_type = '未知方式';
+        switch ($data['extract_type']) {
+            case 'alipay':
+                $extract_type = '支付宝';
+                break;
+            case 'bank':
+                $extract_type = '银行卡';
+                break;
+            case 'weixin':
+                $extract_type = '微信';
+                break;
+        }
+        if (strtolower($User['user_type']) == 'wechat') {
+            WechatTemplateService::sendTemplate(WechatUser::where('uid', $uid)->value('openid'), WechatTemplateService::USER_BALANCE_CHANGE, [
+                'first' => $mark,
+                'keyword1' => '佣金提现',
+                'keyword2' => date('Y-m-d H:i:s', time()),
+                'keyword3' => $extract_number,
+                'remark' => '错误原因:' . $fail_msg
+            ], Url::buildUrl('/user/cashrecord')->suffix('')->domain(true)->build());
+        } else if (strtolower($User['user_type']) == 'routine') {
+            RoutineTemplate::sendExtractFail($uid, $fail_msg, $extract_number, $User['nickname']);
+        }
+        return self::edit(compact('fail_time', 'fail_msg', 'status'), $id);
+    }
+
+    public static function changeSuccess($id)
+    {
+
+        $data = self::get($id);
+        $extractNumber = $data['extract_price'];
+        $mark = '成功提现佣金' . $extractNumber . '元';
+        $wechatUserInfo = WechatUser::where('uid', $data['uid'])->field('openid,user_type,routine_openid,nickname')->find();
+        $extract_type = '未知方式';
+        switch ($data['extract_type']) {
+            case 'alipay':
+                $extract_type = '支付宝';
+                break;
+            case 'bank':
+                $extract_type = '银行卡';
+                break;
+            case 'weixin':
+                $extract_type = '微信';
+                break;
+        }
+        if ($wechatUserInfo) {
+            if (strtolower($wechatUserInfo->user_type) == 'routine') {
+                RoutineTemplate::sendExtractSuccess($data['uid'], $extractNumber, $wechatUserInfo->nickname);
+            } else if (strtolower($wechatUserInfo->user_type) == 'wechat') {
+                WechatTemplateService::sendTemplate($wechatUserInfo->openid, WechatTemplateService::USER_BALANCE_CHANGE, [
+                    'first' => $mark,
+                    'keyword1' => '佣金提现',
+                    'keyword2' => date('Y-m-d H:i:s', time()),
+                    'keyword3' => $extractNumber,
+                    'remark' => '点击查看我的佣金明细'
+                ], Url::buildUrl('/user/cashrecord')->suffix('')->domain(true)->build());
+            }
+        }
+        return self::edit(['status' => 1], $id);
+    }
+
+    //测试数据
+    public static function test()
+    {
+        $uids = User::order('uid desc')->limit(2, 20)->field(['uid', 'nickname'])->select()->toArray();
+        $type = ['bank', 'alipay', 'weixin'];
+        foreach ($uids as $item) {
+            $data = [
+                'uid' => $item['uid'],
+                'real_name' => $item['nickname'],
+                'extract_type' => isset($type[rand(0, 2)]) ? $type[rand(0, 2)] : 'alipay',
+                'bank_code' => rand(1000000, 999999999),
+                'bank_address' => '中国',
+                'alipay_code' => rand(1000, 9999999),
+                'extract_price' => rand(100, 9999),
+                'mark' => '测试数据',
+                'add_time' => time(),
+                'status' => 1,
+                'wechat' => rand(999, 878788) . $item['uid'],
+            ];
+            self::create($data);
+        }
+    }
+
+    //获取头部提现信息
+    public static function getExtractHead()
+    {
+        //本月提现人数
+        $month = self::getModelTime(['data' => 'month'], self::where('status', 1))->group('uid')->count();
+        //本月提现笔数
+        $new_month = self::getModelTime(['data' => 'month'], self::where('status', 1))->distinct(true)->count();
+        //上月提现人数
+        $last_month = self::whereTime('add_time', 'last month')->where('status', 1)->group('uid')->distinct(true)->count();
+        //上月提现笔数
+        $last_count = self::whereTime('add_time', 'last month')->where('status', 1)->count();
+        //本月提现金额
+        $extract_price = self::getModelTime(['data' => 'month'], self::where('status', 1))->sum('extract_price');
+        //上月提现金额
+        $last_extract_price = self::whereTime('add_time', 'last month')->where('status', 1)->sum('extract_price');
+
+        return [
+            [
+                'name' => '总提现人数',
+                'field' => '个',
+                'count' => self::where('status', 1)->group('uid')->count(),
+                'content' => '',
+                'background_color' => 'layui-bg-blue',
+                'sum' => '',
+                'class' => 'fa fa-bar-chart',
+            ],
+            [
+                'name' => '总提现笔数',
+                'field' => '笔',
+                'count' => self::where('status', 1)->distinct(true)->count(),
+                'content' => '',
+                'background_color' => 'layui-bg-cyan',
+                'sum' => '',
+                'class' => 'fa fa-line-chart',
+            ],
+            [
+                'name' => '本月提现人数',
+                'field' => '人',
+                'count' => $month,
+                'content' => '',
+                'background_color' => 'layui-bg-orange',
+                'sum' => '',
+                'class' => 'fa fa-line-chart',
+            ],
+            [
+                'name' => '本月提现笔数',
+                'field' => '笔',
+                'count' => $new_month,
+                'content' => '',
+                'background_color' => 'layui-bg-green',
+                'sum' => '',
+                'class' => 'fa fa-line-chart',
+            ],
+            [
+                'name' => '本月提现金额',
+                'field' => '元',
+                'count' => $extract_price,
+                'content' => '提现总金额',
+                'background_color' => 'layui-bg-cyan',
+                'sum' => self::where('status', 1)->sum('extract_price'),
+                'class' => 'fa fa-line-chart',
+            ],
+            [
+                'name' => '上月提现人数',
+                'field' => '个',
+                'count' => $last_month,
+                'content' => '环比增幅',
+                'background_color' => 'layui-bg-blue',
+                'sum' => $last_month == 0 ? '100%' : bcdiv($month, $last_month, 2) * 100,
+                'class' => $last_month == 0 ? 'fa fa-level-up' : 'fa fa-level-down',
+            ],
+            [
+                'name' => '上月提现笔数',
+                'field' => '笔',
+                'count' => $last_count,
+                'content' => '环比增幅',
+                'background_color' => 'layui-bg-black',
+                'sum' => $last_count == 0 ? '100%' : bcdiv($new_month, $last_count, 2) * 100,
+                'class' => $last_count == 0 ? 'fa fa-level-up' : 'fa fa-level-down',
+            ],
+            [
+                'name' => '上月提现金额',
+                'field' => '元',
+                'count' => $last_extract_price,
+                'content' => '环比增幅',
+                'background_color' => 'layui-bg-gray',
+                'sum' => $last_extract_price == 0 ? '100%' : bcdiv($extract_price, $last_extract_price, 2) * 100,
+                'class' => $last_extract_price == 0 ? 'fa fa-level-up' : 'fa fa-level-down',
+            ],
+        ];
+    }
+
+    //获取提现分布图和提现人数金额曲线图
+    public static function getExtractList($where, $limit = 15)
+    {
+        $legdata = ['提现人数', '提现金额'];
+        $list = self::getModelTime($where, self::where('status', 1))
+            ->field('FROM_UNIXTIME(add_time,"%Y-%c-%d") as un_time,count(uid) as count,sum(extract_price) as sum_price')->group('un_time')->order('un_time asc')->select();
+        if (count($list)) $list = $list->toArray();
+        $xdata = [];
+        $itemList = [0 => [], 1 => []];
+        $chatrList = [];
+        $zoom = '';
+        foreach ($list as $value) {
+            $xdata[] = $value['un_time'];
+            $itemList[0][] = $value['count'];
+            $itemList[1][] = $value['sum_price'];
+        }
+        foreach ($legdata as $key => $name) {
+            $item['name'] = $name;
+            $item['type'] = 'line';
+            $item['data'] = $itemList[$key];
+            $chatrList[] = $item;
+        }
+        unset($item, $name, $key);
+        if (count($xdata) > $limit) $zoom = $xdata[$limit - 5];
+        //饼状图
+        $cake = ['支付宝', '银行卡', '微信'];
+        $fenbulist = self::getModelTime($where, self::where('status', 1))
+            ->field('count(uid) as count,extract_type')->group('extract_type')->order('count asc')->select();
+        if (count($fenbulist)) $fenbulist = $fenbulist->toArray();
+        $sum_count = self::getModelTime($where, self::where('status', 1))->count();
+        $color = ['#FB7773', '#81BCFE', '#91F3FE'];
+        $fenbudata = [];
+        foreach ($fenbulist as $key => $item) {
+            if ($item['extract_type'] == 'bank') {
+                $item_date['name'] = '银行卡';
+            } else if ($item['extract_type'] == 'alipay') {
+                $item_date['name'] = '支付宝';
+            } else if ($item['extract_type'] == 'weixin') {
+                $item_date['name'] = '微信';
+            }
+            $item_date['value'] = bcdiv($item['count'], $sum_count, 2) * 100;
+            $item_date['itemStyle']['color'] = $color[$key];
+            $fenbudata[] = $item_date;
+        }
+        return compact('xdata', 'chatrList', 'legdata', 'zoom', 'cake', 'fenbudata');
+    }
+
+    /**
+     * 获取用户累计提现金额
+     * @param int $uid
+     * @return int|mixed
+     */
+    public static function getUserCountPrice($uid = 0)
+    {
+        if (!$uid) return 0;
+        $price = self::where('uid', $uid)->where('status', 1)->sum('extract_price');
+        return $price ? $price : 0;
+    }
+
+    /**
+     * 获取用户累计提现次数
+     * @param int $uid
+     * @return int|string
+     */
+    public static function getUserCountNum($uid = 0)
+    {
+        if (!$uid) return 0;
+        return self::where('uid', $uid)->count();
+    }
+}

+ 44 - 0
app/admin/model/user/UserGroup.php

@@ -0,0 +1,44 @@
+<?php
+/**
+ *
+ * @author: wuhaotian<442384644@qq.com>
+ * @day: 2019/12/07
+ */
+
+namespace app\admin\model\user;
+
+use crmeb\basic\BaseModel;
+use crmeb\traits\ModelTrait;
+
+/**
+ * Class UserGroup
+ * @package app\admin\model\user
+ */
+class UserGroup extends BaseModel
+{
+    /**
+     * 数据表主键
+     * @var string
+     */
+    protected $pk = 'id';
+
+    /**
+     * 模型名称
+     * @var string
+     */
+    protected $name = 'user_group';
+
+    use ModelTrait;
+
+    /**
+     * @param $where
+     * @return array
+     */
+    public static function getList($where)
+    {
+
+        $data = self::page((int)$where['page'], (int)$where['limit'])->select();
+        $count = $data->count();
+        return compact('count', 'data');
+    }
+}

+ 86 - 0
app/admin/model/user/UserLevel.php

@@ -0,0 +1,86 @@
+<?php
+
+namespace app\admin\model\user;
+
+use app\admin\model\system\SystemUserLevel;
+use crmeb\traits\ModelTrait;
+use crmeb\basic\BaseModel;
+
+/**
+ * 用户管理 model
+ * Class User
+ * @package app\admin\model\user
+ */
+class UserLevel extends BaseModel
+{
+
+    /**
+     * 数据表主键
+     * @var string
+     */
+    protected $pk = 'id';
+
+    /**
+     * 模型名称
+     * @var string
+     */
+    protected $name = 'user_level';
+
+    use ModelTrait;
+
+    public static function setWhere($where, $alias = '', $userAlias = 'u.', $model = null)
+    {
+        $model = is_null($model) ? new self() : $model;
+        if ($alias) {
+            $model = $model->alias($alias);
+            $alias .= '.';
+        }
+        if (isset($where['nickname']) && $where['nickname'] != '') $model = $model->where("{$userAlias}nickanme", $where['nickname']);
+        if (isset($where['level_id']) && $where['level_id'] != '') $model = $model->where("{$alias}level_id", $where['level_id']);
+        return $model->where("{$alias}status", 1)->where("{$alias}is_del", 0);
+    }
+
+    /*
+     * 查询用户vip列表
+     * @param array $where
+     * */
+    public static function getUserVipList($where)
+    {
+        $data = self::setWhere($where, 'a')->group('a.uid')->order('grade desc')
+            ->field('a.*,u.nickname,u.avatar')
+            ->join('user u', 'a.uid=u.uid')->page((int)$where['page'], (int)$where['limit'])->select();
+        $data = count($data) ? $data->toArray() : [];
+        foreach ($data as &$item) {
+            $info = SystemUserLevel::where('id', $item['level_id'])->find();
+            if ($info) {
+                $item['name'] = $info['name'];
+                $item['icon'] = $info['icon'];
+            }
+            $item['is_forever'] = $item['is_forever'] ? '永久会员' : '限时会员';
+            $item['valid_time'] = $item['is_forever'] ? '永久' : date('Y-m-d H:i:s', $item['valid_time']);
+        }
+        $count = self::setWhere($where, 'a')->group('a.level_id')->order('grade desc')->join('user u', 'a.uid=u.uid')->count();
+        return compact('data', 'count');
+    }
+
+    /*
+     * 清除会员等级
+     * @paran int $uid
+     * @paran boolean
+     * */
+    public static function cleanUpLevel($uid)
+    {
+        self::rollbackTrans();
+        $res = false !== self::where('uid', $uid)->update(['is_del' => 1]);
+        $res = $res && UserTaskFinish::where('uid', $uid)->delete();
+        if ($res) {
+            User::where('uid', $uid)->update(['clean_time' => time()]);
+            self::commitTrans();
+            return true;
+        } else {
+            self::rollbackTrans();
+            return self::setErrorInfo('清除失败');
+        }
+    }
+
+}

+ 80 - 0
app/admin/model/user/UserNotice.php

@@ -0,0 +1,80 @@
+<?php
+/**
+ * @author: xaboy<365615158@qq.com>
+ * @day: 2017/11/11
+ */
+
+namespace app\admin\model\user;
+
+use crmeb\traits\ModelTrait;
+use crmeb\basic\BaseModel;
+
+/**
+ * 用户通知 model
+ * Class UserNotice
+ * @package app\admin\model\user
+ */
+class UserNotice extends BaseModel
+{
+
+    /**
+     * 数据表主键
+     * @var string
+     */
+    protected $pk = 'id';
+
+    /**
+     * 模型名称
+     * @var string
+     */
+    protected $name = 'user_notice';
+
+    use ModelTrait;
+
+    /**
+     * @param array $where
+     * @return array
+     */
+    public static function getList($where = [])
+    {
+        $model = new self;
+        $model->order('id desc');
+        if (!empty($where)) {
+            $data = ($data = $model->page((int)$where['page'], (int)$where['limit'])->select()) && count($data) ? $data->toArray() : [];
+            foreach ($data as &$item) {
+                if ($item["uid"] != '') {
+                    $uids = explode(",", $item["uid"]);
+                    array_splice($uids, 0, 1);
+                    array_splice($uids, count($uids) - 1, 1);
+                    $item["uid"] = $uids;
+                }
+                $item['send_time'] = date('Y-m-d H:i:s', $item['send_time']);
+            }
+            $count = self::count();
+            return compact('data', 'count');
+        }
+        return self::page($model, function ($item, $key) {
+            if ($item["uid"] != '') {
+                $uids = explode(",", $item["uid"]);
+                array_splice($uids, 0, 1);
+                array_splice($uids, count($uids) - 1, 1);
+                $item["uid"] = $uids;
+            }
+        });
+    }
+
+    /**
+     * 获取用户通知
+     * @param array $where
+     * @return array
+     */
+    public static function getUserList($where = array())
+    {
+        $model = new self;
+        if (isset($where['title']) && $where['title'] != '') $model = $model->where('title', 'LIKE', "%" . $where['title'] . "%");
+        $model = $model->where('type', 2);
+//        $model = $model->where('is_send',0);
+        $model = $model->order('id desc');
+        return self::page($model, $where);
+    }
+}

+ 33 - 0
app/admin/model/user/UserNoticeSee.php

@@ -0,0 +1,33 @@
+<?php
+/**
+ * @author: xaboy<365615158@qq.com>
+ * @day: 2017/11/11
+ */
+
+namespace app\admin\model\user;
+
+use crmeb\traits\ModelTrait;
+use crmeb\basic\BaseModel;
+
+/**
+ * 用户通知查看 model
+ * Class UserNoticeSee
+ * @package app\admin\model\user
+ */
+class UserNoticeSee extends BaseModel
+{
+
+    /**
+     * 数据表主键
+     * @var string
+     */
+    protected $pk = 'id';
+
+    /**
+     * 模型名称
+     * @var string
+     */
+    protected $name = 'user_notice_see';
+
+    use ModelTrait;
+}

+ 129 - 0
app/admin/model/user/UserPoint.php

@@ -0,0 +1,129 @@
+<?php
+/**
+ * Created by PhpStorm.
+ * User: liying
+ * Date: 2018/7/20
+ * Time: 18:08
+ */
+
+namespace app\admin\model\user;
+
+use crmeb\traits\ModelTrait;
+use crmeb\basic\BaseModel;
+use crmeb\services\PHPExcelService;
+
+class UserPoint extends BaseModel
+{
+
+    /**
+     * 数据表主键
+     * @var string
+     */
+    protected $pk = 'id';
+
+    /**
+     * 模型名称
+     * @var string
+     */
+    protected $name = 'user_point';
+
+    use ModelTrait;
+
+    /*
+     * 获取积分信息
+     * */
+    public static function systemPage($where)
+    {
+        $model = new UserBill();
+        if ($where['status'] != '') UserBill::where('status', $where['status']);
+        if ($where['title'] != '') UserBill::where('title', 'like', "%$where[status]%");
+        $model->where('category', 'integral')->select();
+        return $model::page($model);
+    }
+
+    /*
+     *
+     * 异步获取积分信息
+     * */
+    public static function getpointlist($where)
+    {
+        $list = self::setWhere($where)
+            ->order('a.add_time desc')
+            ->field(['a.*', 'b.nickname'])
+            ->page((int)$where['page'], (int)$where['limit'])
+            ->select()
+            ->toArray();
+        foreach ($list as $key => $item) {
+            $list[$key]['add_time'] = date('Y-m-d', $item['add_time']);
+        }
+        $count = self::setWhere($where)->field(['a.*', 'b.nickname'])->count();
+        return ['count' => $count, 'data' => $list];
+    }
+
+    //生成Excel表格并下载
+    public static function SaveExport($where)
+    {
+        $list = self::setWhere($where)->field(['a.*', 'b.nickname'])->select();
+        $Export = [];
+        foreach ($list as $key => $item) {
+            $Export[] = [
+                $item['id'],
+                $item['title'],
+                $item['balance'],
+                $item['number'],
+                $item['mark'],
+                $item['nickname'],
+                date('Y-m-d H:i:s', $item['add_time']),
+            ];
+        }
+        PHPExcelService::setExcelHeader(['编号', '标题', '积分余量', '明细数字', '备注', '用户微信昵称', '添加时间'])
+            ->setExcelTile('积分日志', '积分日志' . time(), '生成时间:' . date('Y-m-d H:i:s', time()))
+            ->setExcelContent($Export)
+            ->ExcelSave();
+    }
+
+    public static function setWhere($where)
+    {
+        $model = UserBill::alias('a')->join('user b', 'a.uid=b.uid', 'left')->where('a.category', 'integral');
+        $time['data'] = '';
+        if ($where['start_time'] != '' && $where['end_time'] != '') {
+            $time['data'] = $where['start_time'] . ' - ' . $where['end_time'];
+        }
+        $model = self::getModelTime($time, $model, 'a.add_time');
+        if ($where['nickname'] != '') {
+            $model = $model->where('b.nickname|b.uid', 'like', $where['nickname']);
+        }
+        return $model;
+    }
+
+    //获取积分头部信息
+    public static function getUserpointBadgelist($where)
+    {
+        return [
+            [
+                'name' => '总积分',
+                'field' => '个',
+                'count' => self::setWhere($where)->sum('a.number'),
+                'background_color' => 'layui-bg-blue',
+            ],
+            [
+                'name' => '客户签到次数',
+                'field' => '个',
+                'count' => self::setWhere($where)->where('a.type', 'sign')->group('a.uid')->count(),
+                'background_color' => 'layui-bg-cyan',
+            ],
+            [
+                'name' => '签到送出积分',
+                'field' => '个',
+                'count' => self::setWhere($where)->where('a.type', 'sign')->sum('a.number'),
+                'background_color' => 'layui-bg-cyan',
+            ],
+            [
+                'name' => '使用积分',
+                'field' => '个',
+                'count' => self::setWhere($where)->where('a.type', 'deduction')->sum('a.number'),
+                'background_color' => 'layui-bg-cyan',
+            ],
+        ];
+    }
+}

+ 176 - 0
app/admin/model/user/UserRecharge.php

@@ -0,0 +1,176 @@
+<?php
+/**
+ * @author: xaboy<365615158@qq.com>
+ * @day: 2017/11/28
+ */
+
+namespace app\admin\model\user;
+
+use crmeb\traits\ModelTrait;
+use crmeb\basic\BaseModel;
+use crmeb\services\PHPExcelService;
+
+/**
+ * 用户充值记录
+ * Class UserRecharge
+ * @package app\admin\model\user
+ */
+class UserRecharge extends BaseModel
+{
+
+    /**
+     * 数据表主键
+     * @var string
+     */
+    protected $pk = 'id';
+
+    /**
+     * 模型名称
+     * @var string
+     */
+    protected $name = 'user_recharge';
+
+    use ModelTrait;
+
+    public static function systemPage($where)
+    {
+        $model = new self;
+        $model = $model->alias('A');
+        if ($where['order_id'] != '') {
+            $model = $model->whereOr('A.order_id', 'like', "%$where[order_id]%");
+            $model = $model->whereOr('A.id', (int)$where['order_id']);
+            $model = $model->whereOr('B.nickname', 'like', "%$where[order_id]%");
+        }
+        $model = $model->where('A.recharge_type', 'weixin');
+        $model = $model->where('A.paid', 1);
+        $model = $model->field('A.*,B.nickname');
+        $model = $model->join('user B', 'A.uid = B.uid', 'RIGHT');
+        $model = $model->order('A.id desc');
+
+        return self::page($model, $where);
+    }
+
+    /*
+     * 设置查询条件
+     * @param array $where
+     * @param object $model
+     * */
+    public static function setWhere($where, $model = null, $alias = '', $join = '')
+    {
+        $model = is_null($model) ? new self() : $model;
+        if ($alias) {
+            $model = $model->alias('a');
+            $alias .= '.';
+        }
+        if ($where['data']) $model = self::getModelTime($where, $model, "{$alias}add_time");
+        if ($where['paid'] != '') $model = $model->where("{$alias}paid", $where['paid']);
+        if ($where['nickname']) $model = $model->where("{$alias}uid|{$alias}order_id" . ($join ? '|' . $join : ''), 'LIKE', "%$where[nickname]%");
+        return $model->order("{$alias}add_time desc");
+    }
+
+    /*
+     * 查找用户充值金额记录
+     * @param array $where
+     * @return array
+     *
+     * */
+    public static function getUserRechargeList($where)
+    {
+        $model = self::setWhere($where, null, 'a', 'u.nickname')->join('user u', 'u.uid=a.uid')->field(['a.*', 'u.nickname', 'u.avatar']);
+        if ($where['excel']) self::saveExcel($model->select()->toArray());
+        $data = $model->page($where['page'], $where['limit'])->select();
+        $data = count($data) ? $data->toArray() : [];
+        foreach ($data as &$item) {
+            switch ($item['recharge_type']) {
+                case 'routine':
+                    $item['_recharge_type'] = '小程序充值';
+                    break;
+                case 'weixin':
+                    $item['_recharge_type'] = '公众号充值';
+                    break;
+                default:
+                    $item['_recharge_type'] = '其他充值';
+                    break;
+            }
+            $item['_pay_time'] = $item['pay_time'] ? date('Y-m-d H:i:s', $item['pay_time']) : '暂无';
+            $item['_add_time'] = $item['add_time'] ? date('Y-m-d H:i:s', $item['add_time']) : '暂无';
+            $item['paid_type'] = $item['paid'] ? '已支付' : '未支付';
+        }
+        $count = self::setWhere($where, null, 'a', 'u.nickname')->join('user u', 'u.uid=a.uid')->count();
+        return compact('data', 'count');
+    }
+
+    public static function saveExcel($data)
+    {
+        $excel = [];
+        foreach ($data as $item) {
+            switch ($item['recharge_type']) {
+                case 'routine':
+                    $item['_recharge_type'] = '小程序充值';
+                    break;
+                case 'weixin':
+                    $item['_recharge_type'] = '公众号充值';
+                    break;
+                default:
+                    $item['_recharge_type'] = '其他充值';
+                    break;
+            }
+            $item['_pay_time'] = $item['pay_time'] ? date('Y-m-d H:i:s', $item['pay_time']) : '暂无';
+            $item['_add_time'] = $item['add_time'] ? date('Y-m-d H:i:s', $item['add_time']) : '暂无';
+            $item['paid_type'] = $item['paid'] ? '已支付' : '未支付';
+
+            $excel[] = [
+                $item['nickname'],
+                $item['price'],
+                $item['paid_type'],
+                $item['_recharge_type'],
+                $item['_pay_time'],
+                $item['paid'] == 1 && $item['refund_price'] == $item['price'] ? '已退款' : '未退款',
+                $item['_add_time']
+            ];
+        }
+        PHPExcelService::setExcelHeader(['昵称/姓名', '充值金额', '是否支付', '充值类型', '支付事件', '是否退款', '添加时间'])
+            ->setExcelTile('充值记录', '充值记录' . time(), ' 生成时间:' . date('Y-m-d H:i:s', time()))
+            ->setExcelContent($excel)
+            ->ExcelSave();
+    }
+
+    /*
+     * 获取用户充值数据
+     * @return array
+     * */
+    public static function getDataList($where)
+    {
+        return [
+            [
+                'name' => '充值总金额',
+                'field' => '元',
+                'count' => self::setWhere($where, null, 'a', 'u.nickname')->join('user u', 'u.uid=a.uid')->sum('a.price'),
+                'background_color' => 'layui-bg-cyan',
+                'col' => 3,
+            ],
+            [
+                'name' => '充值退款金额',
+                'field' => '元',
+                'count' => self::setWhere($where, null, 'a', 'u.nickname')->join('user u', 'u.uid=a.uid')->sum('a.refund_price'),
+                'background_color' => 'layui-bg-cyan',
+                'col' => 3,
+            ],
+            [
+                'name' => '小程序充值金额',
+                'field' => '元',
+                'count' => self::setWhere($where, null, 'a', 'u.nickname')->where('a.recharge_type', 'routine')->join('user u', 'u.uid=a.uid')->sum('a.price'),
+                'background_color' => 'layui-bg-cyan',
+                'col' => 3,
+            ],
+            [
+                'name' => '公众号充值金额',
+                'field' => '元',
+                'count' => self::setWhere($where, null, 'a', 'u.nickname')->where('a.recharge_type', 'weixin')->join('user u', 'u.uid=a.uid')->sum('a.price'),
+                'background_color' => 'layui-bg-cyan',
+                'col' => 3,
+            ],
+        ];
+    }
+
+}

+ 41 - 0
app/admin/model/user/UserTaskFinish.php

@@ -0,0 +1,41 @@
+<?php
+namespace app\admin\model\user;
+
+use crmeb\traits\ModelTrait;
+use crmeb\basic\BaseModel;
+
+/**
+ * 用户等级完成任务记录 model
+ * Class UserTaskFinish
+ * @package app\admin\model\user
+ */
+
+class UserTaskFinish extends BaseModel
+{
+    /**
+     * 数据表主键
+     * @var string
+     */
+    protected $pk = 'id';
+
+    /**
+     * 模型名称
+     * @var string
+     */
+    protected $name = 'user_task_finish';
+
+    use ModelTrait;
+
+    /*
+     * 设置任务完成情况
+     * @param int $uid 用户uid
+     * @param int $task_id 任务id
+     * @return Boolean
+     * */
+    public static function setFinish($uid,$task_id)
+    {
+        $add_time=time();
+        if(self::be(['uid'=>$uid,'task_id'=>$task_id])) return true;
+        return self::create(compact('uid','task_id','add_time'));
+    }
+}

+ 70 - 0
app/admin/model/wechat/StoreService.php

@@ -0,0 +1,70 @@
+<?php
+
+namespace app\admin\model\wechat;
+
+use app\admin\model\wechat\StoreServiceLog as ServiceLogModel;
+use crmeb\traits\ModelTrait;
+use crmeb\basic\BaseModel;
+
+/**
+ * 客服管理 model
+ * Class StoreProduct
+ * @package app\admin\model\store
+ */
+class StoreService extends BaseModel
+{
+    /**
+     * 数据表主键
+     * @var string
+     */
+    protected $pk = 'id';
+
+    /**
+     * 模型名称
+     * @var string
+     */
+    protected $name = 'store_service';
+
+    use ModelTrait;
+
+    /**
+     * @param $mer_id
+     * @return array
+     */
+    public static function getList($mer_id)
+    {
+        return self::page(self::where('mer_id', $mer_id)->order('id desc'), function ($item) {
+            $item['wx_name'] = WechatUser::where(['uid' => $item['uid']])->value('nickname');
+        });
+    }
+
+    /**
+     * 获取聊天记录用户
+     * @param $now_service
+     * @param $mer_id
+     * @return array|null
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public static function getChatUser($now_service, $mer_id)
+    {
+        $chat_list = ServiceLogModel::field("uid,to_uid")->where('mer_id', $mer_id)->where('to_uid|uid', $now_service["uid"])->group("uid,to_uid")->select();
+        if (count($chat_list) > 0) {
+            $chat_list = $chat_list->toArray();
+            $arr_user = $arr_to_user = [];
+            foreach ($chat_list as $key => $value) {
+                array_push($arr_user, $value["uid"]);
+                array_push($arr_to_user, $value["to_uid"]);
+            }
+            $uids = array_merge($arr_user, $arr_to_user);
+            $uids = array_flip(array_flip($uids));
+            $uids = array_flip($uids);
+            unset($uids[$now_service["uid"]]);
+            $uids = array_flip($uids);
+            if (!count($uids)) return null;
+            return WechatUser::field("uid,nickname,headimgurl")->whereIn('uid', $uids)->select()->toArray();
+        }
+        return null;
+    }
+}

+ 46 - 0
app/admin/model/wechat/StoreServiceLog.php

@@ -0,0 +1,46 @@
+<?php
+namespace app\admin\model\wechat;
+
+use app\models\user\User;
+use crmeb\traits\ModelTrait;
+use crmeb\basic\BaseModel;
+
+/**
+ * 客服管理 model
+ * Class StoreProduct
+ * @package app\admin\model\store
+ */
+class StoreServiceLog extends BaseModel
+{
+    /**
+     * 数据表主键
+     * @var string
+     */
+    protected $pk = 'id';
+
+    /**
+     * 模型名称
+     * @var string
+     */
+    protected $name = 'store_service_log';
+
+    use ModelTrait;
+
+    /**
+     * @param $where
+     * @return array
+     */
+    public static function getChatList($where, $mer_id){
+        $model = new self;
+        $model = $model->where('mer_id', $mer_id);
+        $model = $model->whereIn('uid', [$where['uid'], $where['to_uid']]);
+        $model = $model->whereIn('to_uid', [$where['uid'], $where['to_uid']]);
+        $model->order("add_time desc");
+        return self::page($model,function($item) use ($mer_id){
+            $user = StoreService::field("nickname,avatar")->where('mer_id',$mer_id)->where(array("uid"=>$item["uid"]))->find();
+            if(!$user)$user = User::field("nickname,avatar")->where(array("uid"=>$item["uid"]))->find();
+            $item["nickname"] = $user["nickname"];
+            $item["avatar"] = $user["avatar"];
+        }, $where);
+    }
+}

+ 288 - 0
app/admin/model/wechat/WechatMessage.php

@@ -0,0 +1,288 @@
+<?php
+/**
+ * @author: xaboy<365615158@qq.com>
+ * @day: 2017/11/28
+ */
+
+namespace app\admin\model\wechat;
+
+use app\admin\model\user\User;
+use think\facade\Cache;
+use crmeb\traits\ModelTrait;
+use crmeb\basic\BaseModel;
+use app\admin\model\wechat\WechatUser as UserModel;
+
+/**
+ * 微信用户行为记录  model
+ * Class WechatMessage
+ * @package app\admin\model\wechat
+ */
+class WechatMessage extends BaseModel
+{
+
+    /**
+     * 数据表主键
+     * @var string
+     */
+    protected $pk = 'id';
+
+    /**
+     * 模型名称
+     * @var string
+     */
+    protected $name = 'wechat_message';
+
+    use ModelTrait;
+
+    protected $insert = ['add_time'];
+
+    /**
+     * 微信用户操作的基本所有操作
+     * @var array
+     */
+    public static $mold = array(
+        'event_subscribe' => '关注微信号',
+        'event_unsubscribe' => '取消关注微信号',
+        'event_scan' => '扫码',
+        'event_templatesendjobfinish' => '进入小程序',
+        'event_location' => '获取位置',
+        'event_click' => '点击微信菜单关键字',
+        'event_view' => '点击微信菜单链接',
+        'event_view_miniprogram' => '点击微信菜单进入小程序',
+        'text' => '收到文本消息',
+        'image' => '收到图片消息',
+        'video' => '收到视频消息',
+        'voice' => '收到声音消息',
+        'location' => '收到位置消息',
+        'link' => '收到链接消息',
+        'event_scan_subscribe' => '扫码关注'
+    );
+
+    public static function setAddTimeAttr($value)
+    {
+        return time();
+    }
+
+    public static function setMessage($result, $openid, $type)
+    {
+        if (is_object($result) || is_array($result)) $result = json_encode($result);
+        $add_time = time();
+        $data = compact('result', 'openid', 'type', 'add_time');
+        return self::create($data);
+    }
+
+    public static function setOnceMessage($result, $openid, $type, $unique, $cacheTime = 172800)
+    {
+        $cacheName = 'wechat_message_' . $type . '_' . $unique;
+        if (Cache::has($cacheName)) return true;
+        $res = self::setMessage($result, $openid, $type);
+        if ($res) Cache::set($cacheName, 1, $cacheTime);
+        return $res;
+    }
+
+    /**
+     * 按钮事件
+     * @param $Event
+     * @return mixed
+     */
+    public static function tidyEvent($Event)
+    {
+        $res = array(
+            'msg' => $Event['EventKey'],
+        );
+        return $res;
+    }
+
+    /**
+     * 取消关注事件扫码
+     * @param $Event
+     * @return mixed
+     */
+    public static function tidyNull()
+    {
+        $res = array(
+            'msg' => '无',
+        );
+        return $res;
+    }
+
+    /**
+     * 整理文本显示的数据
+     * @param $text 收到的文本消息
+     * return 返回收到的消息
+     */
+    public static function tidyText($text)
+    {
+        $res = array(
+            'rep_id' => '1',
+            'MsgId' => $text['MsgId'],
+            'Content' => $text['Content'],
+            'msg' => $text['Content'],
+        );
+        return $res;
+    }
+
+    /**
+     * 整理图片显示的数据
+     * @param $image
+     * @return mixed
+     */
+    public static function tidyImage($image)
+    {
+        $res = array(
+            'rep_id' => '2',
+            'MsgId' => $image['MsgId'],
+            'PicUrl' => $image['PicUrl'],
+            'MediaId' => $image['MediaId'],
+            'msg' => '媒体ID:' . $image['MediaId'],
+        );
+        return $res;
+    }
+
+    /**
+     * 整理视屏显示的数据
+     * @param $video
+     * @return mixed
+     */
+    public static function tidyVideo($video)
+    {
+        $res = array(
+            'rep_id' => '3',
+            'MsgId' => $video['MsgId'],
+            'MediaId' => $video['MediaId'],
+            'msg' => '媒体ID:' . $video['MediaId'],
+        );
+        return $res;
+    }
+
+    /**
+     * 整理声音显示的数据
+     * @param $voice
+     * @return mixed
+     */
+    public static function tidyVoice($voice)
+    {
+        $res = array(
+            'rep_id' => '4',
+            'MsgId' => $voice['MsgId'],
+            'MediaId' => $voice['MediaId'],
+            'msg' => '媒体ID:' . $voice['MediaId'],
+        );
+        return $res;
+    }
+
+    /**
+     * 地理位置
+     * @param $location
+     * @return array
+     */
+    public static function tidyLocation($location)
+    {
+        $res = array(
+            'rep_id' => '5',
+            'MsgId' => $location['MsgId'],
+            'Label' => $location['Label'],
+            'msg' => $location['Label'],
+        );
+        return $res;
+    }
+
+    /**
+     * 获取用户扫码点击事件
+     * @param array $where
+     * @return array
+     */
+    public static function systemPage($where = array())
+    {
+        $model = new self;
+        $model = $model->alias('m');
+        if ($where['nickname'] !== '') {
+            $user = UserModel::where('nickname', 'LIKE', "%$where[nickname]%")->field('openid')->select();
+            if (empty($user->toArray())) $model = $model->where('m.id', 0);
+            foreach ($user as $v) {
+                $model = $model->where('m.openid', $v['openid']);
+            }
+        }
+        if ($where['type'] !== '') $model = $model->where('m.type', $where['type']);
+        if ($where['data'] !== '') {
+            list($startTime, $endTime) = explode(' - ', $where['data']);
+            $model = $model->where('m.add_time', '>', strtotime($startTime));
+            $model = $model->where('m.add_time', '<', strtotime($endTime));
+        }
+        $model = $model->field('u.nickname,m.*')->join('WechatUser u', 'u.openid=m.openid')->order('m.id desc');
+        return self::page($model, function ($item) {
+            switch ($item['type']) {
+                case 'text':
+                    $item['result_arr'] = self::tidyText(json_decode($item['result'], true));
+                    break;
+                case 'image':
+                    $item['result_arr'] = self::tidyImage(json_decode($item['result'], true));
+                    break;
+                case 'video':
+                    $item['result_arr'] = self::tidyVideo(json_decode($item['result'], true));
+                    break;
+                case 'voice':
+                    $item['result_arr'] = self::tidyVoice(json_decode($item['result'], true));
+                    break;
+                case 'location':
+                    $item['result_arr'] = self::tidyLocation(json_decode($item['result'], true));
+                    break;
+                case 'event_click':
+                    $item['result_arr'] = self::tidyEvent(json_decode($item['result'], true));
+                    break;
+                case 'event_view':
+                    $item['result_arr'] = self::tidyEvent(json_decode($item['result'], true));
+                    break;
+                case 'event_subscribe':
+                    $item['result_arr'] = self::tidyNull();
+                    break;
+                case 'event_unsubscribe':
+                    $item['result_arr'] = self::tidyNull();
+                    break;
+                case 'event_scan':
+                    $item['result_arr'] = self::tidyNull();
+                    break;
+                default :
+                    $item['result_arr'] = ['msg' => $item['type']];
+                    break;
+            }
+            $item['type_name'] = isset(self::$mold[$item['type']]) ? self::$mold[$item['type']] : '未知';
+        }, $where);
+    }
+
+    /*
+    * 获取应为记录数据
+     *
+     */
+    public static function getViweList($date, $class = [])
+    {
+        $model = new self();
+        switch ($date) {
+            case null:
+            case 'today':
+            case 'week':
+            case 'year':
+                if ($date == null) $date = 'month';
+                $model = $model->whereTime('add_time', $date);
+                break;
+            case 'quarter':
+                $time = User::getMonth('n');
+                $model = $model->where('add_time', 'between', $time);
+                break;
+            default:
+                list($startTime, $endTime) = explode('-', $date);
+                $model = $model->where('add_time', '>', strtotime($startTime));
+                $model = $model->where('add_time', '<', strtotime($endTime));
+                break;
+        }
+        $list = $model->field(['type', 'count(*) as num', 'result'])->group('type')->limit(0, 20)->select()->toArray();
+        $viwe = [];
+        foreach ($list as $key => $item) {
+            $now_list['name'] = isset(self::$mold[$item['type']]) ? self::$mold[$item['type']] : '未知';
+            $now_list['value'] = $item['num'];
+            $now_list['class'] = isset($class[$key]) ? $class[$key] : '';
+            $viwe[] = $now_list;
+        }
+        return $viwe;
+    }
+}

+ 138 - 0
app/admin/model/wechat/WechatNews.php

@@ -0,0 +1,138 @@
+<?php
+/**
+ * @author: xaboy<365615158@qq.com>
+ * @day: 2017/11/02
+ */
+namespace app\admin\model\wechat;
+
+use app\admin\model\system\SystemAdmin;
+use crmeb\traits\ModelTrait;
+use crmeb\basic\BaseModel;
+use think\facade\Db;
+
+/**
+ * TODO 图文管理 Model
+ * Class WechatNews
+ * @package app\admin\model\wechat
+ */
+class WechatNews extends BaseModel
+{
+
+    /**
+     * 数据表主键
+     * @var string
+     */
+    protected $pk = 'id';
+
+    /**
+     * 模型名称
+     * @var string
+     */
+    protected $name = 'wechat_news';
+
+    use ModelTrait;
+
+    /**
+     * 获取配置分类
+     * @param array $where
+     * @return array
+     */
+    public static function getAll($where = array()){
+        $model = new self;
+        if($where['title'] !== '') $model = $model->where('title','LIKE',"%$where[title]%");
+        if($where['cid'] !== '') $model = $model->where("CONCAT(',',cid,',')  LIKE '%,$where[cid],%'");
+        if($where['cid'] == ''){
+            if(!$where['merchant']) $model = $model->where('mer_id',0);
+            if($where['merchant']) $model = $model->where('mer_id','>',0);
+        }
+        $model = $model->where('status',1)->where('hide',0);
+        return self::page($model,function($item){
+            $item['admin_name'] = '总后台管理员---》'.SystemAdmin::where('id',$item['admin_id'])->value('real_name');
+            $item['content'] = Db::name('wechatNewsContent')->where('nid',$item['id'])->value('content');
+        },$where);
+    }
+
+    /**
+     * 删除图文
+     * @param $id
+     * @return bool
+     */
+    public static function del($id){
+        return self::edit(['status'=>0],$id,'id');
+    }
+
+    /**
+     * 获取指定字段的值
+     * @return array
+     */
+    public static function getNews()
+    {
+        return self::where('status',1)->where('hide',0)->order('id desc')->column('id,title');
+    }
+
+    /**
+     * 给表中的字符串类型追加值
+     * 删除所有有当前分类的id之后重新添加
+     * @param $cid
+     * @param $id
+     * @return bool
+     */
+    public static function saveBatchCid($cid,$id){
+        $res_all = self::where('cid','LIKE',"%$cid%")->select();//获取所有有当前分类的图文
+        foreach ($res_all as $k=>$v){
+            $cid_arr = explode(',',$v['cid']);
+            if(in_array($cid,$cid_arr)){
+                $key = array_search($cid, $cid_arr);
+                array_splice($cid_arr, $key, 1);
+            }
+            if(empty($cid_arr)) {
+                $data['cid'] = 0;
+                self::edit($data,$v['id']);
+            }else{
+                $data['cid'] = implode(',',$cid_arr);
+                self::edit($data,$v['id']);
+            }
+        }
+        $res = self::where('id','IN',$id)->select();
+        foreach ($res as $k=>$v){
+            if(!in_array($cid,explode(',',$v['cid']))){
+                if(!$v['cid']){
+                    $data['cid'] = $cid;
+                }else{
+                    $data['cid'] = $v['cid'].','.$cid;
+                }
+                self::edit($data,$v['id']);
+            }
+        }
+       return true;
+    }
+
+    public static function setContent($id,$content){
+        $count = Db::name('wechatNewsContent')->where('nid',$id)->count();
+        $data['nid'] = $id;
+        $data['content'] = $content;
+        if($count){
+            $contentSql = Db::name('wechatNewsContent')->where('nid',$id)->value('content');
+            if($contentSql == $content) $res = true;
+            else $res = Db::name('wechatNewsContent')->where('nid',$id)->update(['content'=>$content]);
+            if($res !== false) $res = true;
+        }
+        else
+            $res = Db::name('wechatNewsContent')->insert($data);
+        return $res;
+    }
+
+    public static function merchantPage($where = array()){
+        $model = new self;
+        if($where['title'] !== '') $model = $model->where('title','LIKE',"%$where[title]%");
+        if($where['cid'] !== '') $model = $model->where('cid','LIKE',"%$where[cid]%");
+        $model = $model
+            ->where('status',1)
+            ->where('hide',0)
+            ->where('admin_id',$where['admin_id'])
+            ->where('mer_id',$where['mer_id']);
+        return self::page($model,function($item){
+            $item['content'] = Db::name('wechatNewsContent')->where('nid',$item['id'])->value('content');
+        },$where);
+    }
+}

+ 105 - 0
app/admin/model/wechat/WechatNewsCategory.php

@@ -0,0 +1,105 @@
+<?php
+/**
+ * @author: xaboy<365615158@qq.com>
+ * @day: 2017/11/02
+ */
+
+namespace app\admin\model\wechat;
+
+use crmeb\traits\ModelTrait;
+use crmeb\basic\BaseModel;
+use app\admin\model\article\Article as ArticleModel;
+
+/**
+ * 图文消息 model
+ * Class WechatNewsCategory
+ * @package app\admin\model\wechat
+ */
+class WechatNewsCategory extends BaseModel
+{
+    /**
+     * 数据表主键
+     * @var string
+     */
+    protected $pk = 'id';
+
+    /**
+     * 模型名称
+     * @var string
+     */
+    protected $name = 'wechat_news_category';
+
+    use ModelTrait;
+
+    /**
+     * 获取配置分类
+     * @param array $where
+     * @return array
+     */
+    public static function getAll($where = array())
+    {
+        $model = new self;
+//        if($where['status'] !== '') $model = $model->where('status',$where['status']);
+//        if($where['access'] !== '') $model = $model->where('access',$where['access']);
+        if ($where['cate_name'] !== '') $model = $model->where('cate_name', 'LIKE', "%$where[cate_name]%");
+        $model = $model->where('status', 1);
+        return self::page($model, function ($item) use ($where) {
+            $new = ArticleModel::where('id', 'in', $item['new_id'])->where('status', 1)->where('hide', 0)->select();
+            if ($new) $new = $new->toArray();
+            $item['new'] = $new;
+        });
+    }
+
+    /**
+     * 获取一条图文
+     * @param int $id
+     * @return array|false|\PDOStatement|string|\think\Model
+     */
+    public static function getWechatNewsItem($id = 0, $new_id = 0)
+    {
+        if (!$id) return [];
+        $list = self::where('id', $id)->where('status', 1)->field('cate_name as title,new_id')->find();
+        if ($list) {
+            $list = $list->toArray();
+            $new = ArticleModel::where('id', $new_id)->where('status', 1)->where('hide', 0)->select();
+            $new = $new->toArray();
+            if ($new) {
+                $temp = [];
+                $temp[] = $new[0];
+                $list['new'] = $temp;
+            } else {
+                $list['new'] = $new;
+            }
+
+        }
+        return $list;
+    }
+
+    /**
+     * 获取发送图文
+     * @param array $where
+     * @return array
+     */
+    public static function getSendAll($where = array())
+    {
+        $model = new self();
+        if ($where['cate_name'] !== '') $model = $model->where('cate_name', 'LIKE', "%$where[cate_name]%");
+        $new_ids = $model->where('status', 1)->column('new_id');
+        $new_ids = array_values($new_ids);
+        $new_ids = implode(',', $new_ids);
+
+        $model = ArticleModel::where('status', 1)->where('hide', 0)->where('id', 'in', $new_ids)->field('id,title,image_input,add_time');
+        return ArticleModel::page($model, function ($item) use ($where) {
+            $new = self::where('status', 1)->whereFindInSet('new_id', $item['id'])->find();
+            $item['cate_name'] = $new['cate_name'];
+            $temp[0]['title'] = $item['title'];
+            $temp[0]['image_input'] = $item['image_input'];
+            $temp[0]['id'] = $item['id'];
+            $temp[0]['add_time'] = $item['add_time'];
+            $item['id'] = $new['id'];
+            $item['new'] = $temp;
+        });
+    }
+
+
+}

+ 122 - 0
app/admin/model/wechat/WechatQrcode.php

@@ -0,0 +1,122 @@
+<?php
+/**
+ * @author: xaboy<365615158@qq.com>
+ * @day: 2017/11/22
+ */
+
+namespace app\admin\model\wechat;
+
+use crmeb\traits\ModelTrait;
+use crmeb\basic\BaseModel;
+use crmeb\services\WechatService;
+
+/**
+ * 获取二维码
+ * Class WechatQrcode
+ * @package app\admin\model\wechat
+ */
+class WechatQrcode extends BaseModel
+{
+    /**
+     * 数据表主键
+     * @var string
+     */
+    protected $pk = 'id';
+
+    /**
+     * 模型名称
+     * @var string
+     */
+    protected $name = 'wechat_qrcode';
+
+    use ModelTrait;
+
+    /**
+     * 创建临时二维码    有效期 30天
+     *
+     * 修改时    要使用的主键id $qtcode_id
+     * @param $id
+     * @param $type
+     * @param string $qtcode_id
+     */
+    public static function createTemporaryQrcode($id,$type,$qtcode_id=''){
+        $qrcode = WechatService::qrcodeService();
+        $data  = $qrcode->temporary($id,30*24*3600)->toArray();
+        $data['qrcode_url'] = $data['url'];
+        $data['expire_seconds'] = $data['expire_seconds']+time();
+        $data['url'] = $qrcode->url($data['ticket']);
+        $data['status'] = 1;
+        $data['third_id'] = $id;
+        $data['third_type'] = $type;
+        if($qtcode_id){
+            self::edit($data,$qtcode_id);
+        }else{
+            $data['add_time'] = time();
+            self::create($data);
+        }
+    }
+
+    /**
+     * 创建永久二维码
+     * @param $id
+     * @param $type
+     */
+    public static function createForeverQrcode($id,$type){
+        $qrcode = WechatService::qrcodeService();
+        $data  = $qrcode->forever($id)->toArray();
+        $data['qrcode_url'] = $data['url'];
+        $data['url'] = $qrcode->url($data['ticket']);
+        $data['expire_seconds'] = 0;
+        $data['status'] = 1;
+        $data['third_id'] = $id;
+        $data['third_type'] = $type;
+        $data['add_time'] = time();
+        self::create($data);
+    }
+
+    /**
+     * 获取临时二维码
+     * @param $type
+     * @param $id
+     * @return array|false|\PDOStatement|string|\think\Model
+     */
+    public static function getTemporaryQrcode($type,$id){
+          $res = self::where('third_id',$id)->where('third_type',$type)->find();
+          if(empty($res)){
+              self::createTemporaryQrcode($id,$type);
+              $res = self::getTemporaryQrcode($type,$id);
+          }else if(empty($res['expire_seconds']) || $res['expire_seconds'] < time()){
+              self::createTemporaryQrcode($id,$type,$res['id']);
+              $res = self::getTemporaryQrcode($type,$id);
+          }
+          if(!$res['ticket']) exception('临时二维码获取错误');
+          return $res;
+    }
+
+    /**
+     * 获取永久二维码
+     * @param $type
+     * @param $id
+     * @return array|false|\PDOStatement|string|\think\Model
+     */
+    public static function getForeverQrcode($type,$id){
+        $res = self::where('third_id',$id)->where('third_type',$type)->find();
+        if(empty($res)) {
+            self::createForeverQrcode($id, $type);
+            $res = self::getForeverQrcode($type, $id);
+        }
+        if(!$res['ticket']) exception('永久二维码获取错误');
+        return $res;
+    }
+
+    public static function getQrcode($id,$type = 'id')
+    {
+        return self::where($type,$id)->find();
+    }
+
+    public static function scanQrcode($id,$type = 'id')
+    {
+        return self::where($type,$id)->inc('scan')->update();
+    }
+
+}

+ 225 - 0
app/admin/model/wechat/WechatReply.php

@@ -0,0 +1,225 @@
+<?php
+/**
+ * @author: xaboy<365615158@qq.com>
+ * @day: 2017/11/22
+ */
+
+namespace app\admin\model\wechat;
+
+use crmeb\basic\BaseModel;
+use crmeb\traits\ModelTrait;
+use crmeb\services\WechatService;
+use think\facade\Route as Url;
+
+/**
+ * 关键字 model
+ * Class WechatReply
+ * @package app\admin\model\wechat
+ */
+class WechatReply extends BaseModel
+{
+    /**
+     * 数据表主键
+     * @var string
+     */
+    protected $pk = 'id';
+
+    /**
+     * 模型名称
+     * @var string
+     */
+    protected $name = 'wechat_reply';
+
+    use ModelTrait;
+
+    public static $reply_type = ['text', 'image', 'news', 'voice'];
+
+    /**
+     * 根据关键字查询一条
+     *
+     * @param $key
+     * @return array|null|\think\Model
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public static function getDataByKey($key)
+    {
+        $resdata = ['data' => ''];
+        $resdata = self::where('key', $key)->find();
+        $resdata['data'] = json_decode($resdata['data'], true);
+        return $resdata;
+    }
+
+    public function getUrlAttr($value, $data)
+    {
+        return $value == '' ? Url::buildUrl('index/index/news', ['id' => $data['id']]) : $value;
+    }
+
+    /**
+     * @param $data
+     * @param $key
+     * @param $type
+     * @param int $status
+     * @return bool
+     */
+    public static function redact($data, $key, $type, $status = 1)
+    {
+        $method = 'tidy' . ucfirst($type);
+        $res = self::$method($data, $key);
+        if (!$res) return false;
+        $count = self::where('key', $key)->count();
+        if ($count) {
+            $res = self::edit(['type' => $type, 'data' => json_encode($res), 'status' => $status], $key, 'key');
+            if (!$res) return self::setErrorInfo('保存失败!');
+        } else {
+            $res = self::create([
+                'key' => $key,
+                'type' => $type,
+                'data' => json_encode($res),
+                'status' => $status,
+            ]);
+            if (!$res) return self::setErrorInfo('保存失败!');
+        }
+        return true;
+    }
+
+    /**
+     * @param $key
+     * @param string $field
+     * @param int $hide
+     * @return bool
+     */
+    public static function changeHide($key, $field = 'id', $hide = 0)
+    {
+        return self::edit(compact('hide'), $key, $field);
+    }
+
+
+    /**
+     * 整理文本输入的消息
+     * @param $data
+     * @param $key
+     * @return array|bool
+     */
+    public static function tidyText($data, $key)
+    {
+        $res = [];
+        if (!isset($data['content']) || $data['content'] == '')
+            return self::setErrorInfo('请输入回复信息内容');
+        $res['content'] = $data['content'];
+        return $res;
+    }
+
+    /**
+     * 整理图片资源
+     * @param $data
+     * @param $key
+     * @return array|bool|mixed
+     */
+    public static function tidyImage($data, $key)
+    {
+        if (!isset($data['src']) || $data['src'] == '')
+            return self::setErrorInfo('请上传回复的图片');
+        $reply = self::get(['key' => $key]);
+        if ($reply) $reply['data'] = json_decode($reply['data'], true);
+        if ($reply && isset($reply['data']['src']) && $reply['data']['src'] == $data['src']) {
+            $res = $reply['data'];
+        } else {
+            $res = [];
+            //TODO 图片转media
+            $res['src'] = $data['src'];
+            $material = (WechatService::materialService()->uploadImage(url_to_path($data['src'])));
+            $res['media_id'] = $material->media_id;
+            $dataEvent = ['media_id' => $material->media_id, 'path' => $res['src'], 'url' => $material->url];
+            $type = 'image';
+            event('WechatMaterialAfter', [$dataEvent, $type]);
+        }
+        return $res;
+    }
+
+    /**
+     * 整理声音资源
+     * @param $data
+     * @param $key
+     * @return array|bool|mixed
+     */
+    public static function tidyVoice($data, $key)
+    {
+        if (!isset($data['src']) || $data['src'] == '')
+            return self::setErrorInfo('请上传回复的声音');
+        $reply = self::get(['key' => $key]);
+        if ($reply) $reply['data'] = json_decode($reply['data'], true);
+        if ($reply && isset($reply['data']['src']) && $reply['data']['src'] == $data['src']) {
+            $res = $reply['data'];
+        } else {
+            $res = [];
+            //TODO 声音转media
+            $res['src'] = $data['src'];
+            $material = (WechatService::materialService()->uploadVoice(url_to_path($data['src'])));
+            $res['media_id'] = $material->media_id;
+            $dataEvent = ['media_id' => $material->media_id, 'path' => $res['src']];
+            $type = 'voice';
+            event('WechatMaterialAfter', [$dataEvent, $type]);
+        }
+        return $res;
+    }
+
+    /**
+     * 整理图文资源
+     * @param $data
+     * @param $key
+     * @return bool
+     */
+    public static function tidyNews($data, $key = '')
+    {
+        if (!count($data))
+            return self::setErrorInfo('请选择图文消息');
+        $siteUrl = sys_config('site_url');
+        foreach ($data as $k => $v) {
+            if (empty($v['url'])) $data[$k]['url'] = $siteUrl . '/news_detail/' . $v['id'];
+            if ($v['image']) $data[$k]['image'] = $v['image'];
+        }
+        return $data;
+    }
+
+    /**
+     * 获取所有关键字
+     * @param array $where
+     * @return array
+     */
+    public static function getKeyAll($where = array())
+    {
+        $model = new self;
+        if ($where['key'] !== '') $model = $model->where('key', 'LIKE', "%$where[key]%");
+        if ($where['type'] !== '') $model = $model->where('type', $where['type']);
+        $model = $model->where('key', '<>', 'subscribe');
+        $model = $model->where('key', '<>', 'default');
+        return self::page($model);
+    }
+
+    /**
+     * 获取关键字
+     * @param $key
+     * @param string $default
+     * @return array|\EasyWeChat\Message\Image|\EasyWeChat\Message\News|\EasyWeChat\Message\Text|\EasyWeChat\Message\Voice
+     */
+    public static function reply($key, $default = '')
+    {
+        $res = self::where('key', $key)->where('status', '1')->find();
+        if (empty($res)) $res = self::where('key', 'default')->where('status', '1')->find();
+        if (empty($res)) return WechatService::transfer();
+        $res['data'] = json_decode($res['data'], true);
+        if ($res['type'] == 'text') {
+            return WechatService::textMessage($res['data']['content']);
+        } else if ($res['type'] == 'image') {
+            return WechatService::imageMessage($res['data']['media_id']);
+        } else if ($res['type'] == 'news') {
+            return WechatService::newsMessage($res['data']);
+        } else if ($res['type'] == 'voice') {
+            return WechatService::voiceMessage($res['data']['media_id']);
+        }
+    }
+
+
+}

+ 53 - 0
app/admin/model/wechat/WechatTemplate.php

@@ -0,0 +1,53 @@
+<?php
+/**
+ * @author: xaboy<365615158@qq.com>
+ * @day: 2017/11/02
+ */
+
+namespace app\admin\model\wechat;
+
+use crmeb\traits\ModelTrait;
+use crmeb\basic\BaseModel;
+
+/**
+ * 微信模板消息model
+ * Class WechatTemplate
+ * @package app\admin\model\wechat
+ */
+class WechatTemplate extends BaseModel
+{
+    /**
+     * 数据表主键
+     * @var string
+     */
+    protected $pk = 'id';
+
+    /**
+     * 模型名称
+     * @var string
+     */
+    protected $name = 'template_message';
+
+    use ModelTrait;
+
+    public static function vialdWhere(string $alias = '', int $type = 1)
+    {
+        if ($alias) {
+            $alias .= '.';
+        }
+        return self::where($alias . 'type', $type);
+    }
+
+    /**
+     * 获取系统分页数据   分类
+     * @param array $where
+     * @return array
+     */
+    public static function systemPage($where = array())
+    {
+        $model = self::vialdWhere();
+        if ($where['name'] !== '') $model = $model->where('name', 'LIKE', "%$where[name]%");
+        if ($where['status'] !== '') $model = $model->where('status', $where['status']);
+        return self::page($model);
+    }
+}

+ 736 - 0
app/admin/model/wechat/WechatUser.php

@@ -0,0 +1,736 @@
+<?php
+/**
+ * @author: xaboy<365615158@qq.com>
+ * @day: 2017/11/28
+ */
+
+namespace app\admin\model\wechat;
+
+use crmeb\basic\BaseModel;
+use crmeb\traits\ModelTrait;
+use think\facade\{Cache, Config};
+use crmeb\services\{WechatService, PHPExcelService};
+use app\admin\model\user\{User, UserBill, UserExtract};
+use app\admin\model\order\{StoreOrder, StoreOrderStatus};
+
+/**
+ * 微信用户 model
+ * Class WechatUser
+ * @package app\admin\model\wechat
+ */
+class WechatUser extends BaseModel
+{
+
+    /**
+     * 数据表主键
+     * @var string
+     */
+    protected $pk = 'uid';
+
+    /**
+     * 模型名称
+     * @var string
+     */
+    protected $name = 'wechat_user';
+
+    use ModelTrait;
+
+    protected $insert = ['add_time'];
+
+    /**
+     * 用uid获得 微信openid
+     * @param $uid
+     * @return mixed
+     * @throws \Exception
+     */
+    public static function uidToOpenid($uid)
+    {
+        $openid = self::where('uid', $uid)->value('openid');
+        if (!$openid) exception('对应的openid不存在!');
+        return $openid;
+    }
+
+    /**
+     * 用uid获得 小程序 openid
+     * @param $uid
+     * @return mixed
+     * @throws \Exception
+     */
+    public static function uidToRoutineOpenid($uid)
+    {
+        $openid = self::where('uid', $uid)->value('routine_openid');
+        if (!$openid) exception('对应的routine_openid不存在!');
+        return $openid;
+    }
+
+    public static function setAddTimeAttr($value)
+    {
+        return time();
+    }
+
+    /**
+     * .添加新用户
+     * @param $openid
+     * @return object
+     */
+    public static function setNewUser($openid)
+    {
+        $userInfo = WechatService::getUserInfo($openid);
+        $userInfo['tagid_list'] = implode(',', $userInfo['tagid_list']);
+        return self::create($userInfo);
+    }
+
+    /**
+     * 更新用户信息
+     * @param $openid
+     * @return bool
+     */
+    public static function updateUser($openid)
+    {
+        $userInfo = WechatService::getUserInfo($openid);
+        $userInfo['tagid_list'] = implode(',', $userInfo['tagid_list']);
+        return self::edit($userInfo, $openid, 'openid');
+    }
+
+    /**
+     * 用户存在就更新 不存在就添加
+     * @param $openid
+     */
+    public static function saveUser($openid)
+    {
+        self::be($openid, 'openid') == true ? self::updateUser($openid) : self::setNewUser($openid);
+    }
+
+    /**
+     * 用户取消关注
+     * @param $openid
+     * @return bool
+     */
+    public static function unSubscribe($openid)
+    {
+        return self::edit(['subscribe' => 0], $openid, 'openid');
+    }
+
+    /**
+     * 获取微信用户
+     * @param array $where
+     * @return array
+     */
+    public static function systemPage($where = [], $isall = false)
+    {
+        $model = new self;
+        $model = $model->where('openid|routine_openid', 'NOT NULL');
+        if ($where['nickname'] !== '') $model = $model->where('nickname', 'LIKE', "%$where[nickname]%");
+        if (isset($where['data']) && $where['data'] !== '') $model = self::getModelTime($where, $model, 'add_time');
+        if (isset($where['tagid_list']) && $where['tagid_list'] !== '') {
+            $tagid_list = explode(',', $where['tagid_list']);
+            foreach ($tagid_list as $v) {
+                $model = $model->where('tagid_list', 'LIKE', "%$v%");
+            }
+        }
+        if (isset($where['groupid']) && $where['groupid'] !== '-1') $model = $model->where('groupid', "$where[groupid]");
+        if (isset($where['sex']) && $where['sex'] !== '') $model = $model->where('sex', "$where[sex]");
+        if (isset($where['subscribe']) && $where['subscribe'] !== '') $model = $model->where('subscribe', "$where[subscribe]");
+        $model = $model->order('uid desc');
+        if (isset($where['export']) && $where['export'] == 1) {
+            $list = $model->select()->toArray();
+            $export = [];
+            foreach ($list as $index => $item) {
+                $export[] = [
+                    $item['nickname'],
+                    $item['sex'],
+                    $item['country'] . $item['province'] . $item['city'],
+                    $item['subscribe'] == 1 ? '关注' : '未关注',
+                ];
+                $list[$index] = $item;
+            }
+            PHPExcelService::setExcelHeader(['名称', '性别', '地区', '是否关注公众号'])
+                ->setExcelTile('微信用户导出', '微信用户导出' . time(), ' 生成时间:' . date('Y-m-d H:i:s', time()))
+                ->setExcelContent($export)
+                ->ExcelSave();
+        }
+        return self::page($model, function ($item) {
+            $item['time'] = $item['add_time'] ? date('Y-m-d H:i', $item['add_time']) : '暂无';
+        }, $where);
+    }
+
+    public static function setSpreadWhere($where = [], $alias = 'a', $model = null)
+    {
+        $model = is_null($model) ? new  self() : $model;
+        if ($alias) {
+            $model = $model->alias($alias)->join('user u', 'a.uid=u.uid')->order('u.uid desc');
+            $alias .= '.';
+        }
+        $status = (int)sys_config('store_brokerage_statu');
+        if ($status == 1) {
+            if ($Listuids = User::where(['is_promoter' => 1])->field('uid')->select()) {
+                $newUids = [];
+                foreach ($Listuids as $item) {
+                    $newUids[] = $item['uid'];
+                }
+                $uids = $newUids;
+                unset($uid, $newUids);
+                $model = $model->where($alias . 'uid', 'in', implode(',', $uids));
+            } else
+                $model = $model->where($alias . 'uid', -1);
+        }
+        if ($where['nickname'] !== '') $model = $model->where("{$alias}nickname|{$alias}uid|u.phone", 'LIKE', "%$where[nickname]%");
+        if ((isset($where['start_time']) && isset($where['end_time'])) && $where['start_time'] !== '' && $where['end_time'] !== '') {
+            $model = $model->where("{$alias}add_time", 'between', [strtotime($where['start_time']), strtotime($where['end_time'])]);
+        }
+        if (isset($where['sex']) && $where['sex'] !== '') $model = $model->where($alias . 'sex', $where['sex']);
+        if (isset($where['subscribe']) && $where['subscribe'] !== '') $model = $model->where($alias . 'subscribe', $where['subscribe']);
+        if (isset($where['order']) && $where['order'] != '') $model = $model->order($where['order']);
+        if (isset($where['user_type']) && $where['user_type'] != '') {
+            if ($where['user_type'] == 1) {
+                $model = $model->where($alias . 'unionid', 'neq', 'NULL');
+            } else if ($where['user_type'] == 2)
+                $model = $model->where($alias . 'openid', 'neq', 'NULL')->where($alias . 'unionid', 'NULL');
+            else if ($where['user_type'] == 3)
+                $model = $model->where($alias . 'routine_openid', 'neq', 'NULL')->where($alias . 'unionid', 'NULL');
+        }
+        if (isset($where['is_time']) && isset($where['data']) && $where['data']) $model = self::getModelTime($where, $model, $alias . 'add_time');
+        return $model;
+    }
+
+    /**
+     * 获取分销用户
+     * @param array $where
+     * @return array
+     */
+    public static function agentSystemPage($where = [])
+    {
+        $exteactSql = UserExtract::where(['status' => 1])
+            ->group('uid')
+            ->field(['sum(extract_price) as extract_count_price', 'count(id) as extract_count_num', 'uid as euid'])
+            ->fetchSql(true)
+            ->select();
+        $orderSql = StoreOrder::alias('o')
+            ->where(['o.paid' => 1, 'o.refund_status' => 0])
+            ->field(['sum(o.pay_price) as order_price', 'count(o.id) as order_count', 'o.uid as ouid'])
+            ->group('o.uid')
+            ->fetchSql(true)
+            ->select();
+        $billSql = UserBill::where(['status' => 1])
+            ->where('type','brokerage')
+            ->group('uid')
+            ->field(['sum(number) as brokerage_money', 'uid as buid'])
+            ->fetchSql(true)
+            ->select();
+        $model = User::where(['status' => 1]);
+        $model = $model->alias('u')
+            ->join('(' . $orderSql . ') o', 'o.ouid = u.uid', 'left')
+            ->join('(' . $billSql . ') b', 'b.buid = u.uid', 'left')
+            ->join('(' . $exteactSql . ') e', 'e.euid = u.uid', 'left');
+        if ($where['nickname'] !== '') {
+            $model = $model->where("u.nickname|u.uid|u.phone", 'LIKE', "%$where[nickname]%");
+        }
+        if ($where['data']) $model = self::getModelTime($where, $model, 'u.add_time');
+        $count = $model->count();
+        $data = $model->field(['avatar as headimgurl', 'brokerage_price as new_money', 'u.*', 'o.*', 'e.*', 'b.*'])
+            ->page((int)$where['page'], (int)$where['limit'])
+            ->order('u.uid desc')
+            ->select();
+        $data = count($data) ? $data->toArray() : [];
+        $export = [];
+        $broken_time = intval(sys_config('extract_time'));
+        $search_time = time() - 86400 * $broken_time;
+        foreach ($data as &$item) {
+            if ($spread_uid = User::where('uid', $item['uid'])->value('spread_uid')) {
+                if ($user = User::where('uid', $spread_uid)->field(['uid', 'nickname'])->find()) {
+                    $item['spread_name'] = $user['nickname'] . '/' . $user['uid'];
+                }
+            }
+            $item['spread_count'] = User::where('spread_uid',$item['uid'])->count();
+            //返佣 +
+            $brokerage_commission = UserBill::where(['uid' => $item['uid'], 'category' => 'now_money', 'type' => 'brokerage'])
+                ->where('add_time', '>', $search_time)
+                ->where('pm', 1)
+                ->sum('number');
+            //退款退的佣金 -
+            $refund_commission = UserBill::where(['uid' => $item['uid'], 'category' => 'now_money', 'type' => 'brokerage'])
+                ->where('add_time', '>', $search_time)
+                ->where('pm', 0)
+                ->sum('number');
+            $item['broken_commission'] = bcsub($brokerage_commission, $refund_commission, 2);
+            if ($item['broken_commission'] < 0)
+                $item['broken_commission'] = 0;
+            //导出数据
+            $export[] = [
+                $item['uid'],
+                $item['nickname'],
+                $item['phone'],
+                $item['spread_count'],
+                $item['order_count'],
+                $item['order_price'],
+                $item['brokerage_money'],
+                $item['extract_count_price'],
+                $item['extract_count_num'],
+                $item['new_money'],
+                $item['spread_name'] ?? '',
+            ];
+        }
+        if (isset($where['excel']) && $where['excel'] == 1) {
+            PHPExcelService::setExcelHeader(['用户编号', '昵称', '电话号码', '推广用户数量', '订单数量', '推广订单金额', '佣金金额', '已提现金额', '提现次数', '未提现金额', '上级推广人'])
+                ->setExcelTile('推广用户', '推广用户导出' . time(), ' 生成时间:' . date('Y-m-d H:i:s', time()))
+                ->setExcelContent($export)
+                ->ExcelSave();
+        }
+
+        return compact('data', 'count');
+    }
+
+    public static function setSairOrderWhere($where, $model = null, $alias = '')
+    {
+        $model = $model === null ? new self() : $model;
+        if (!isset($where['uid'])) return $model;
+        if ($alias) {
+            $model = $model->alias($alias);
+            $alias .= '.';
+        }
+        if (isset($where['type'])) {
+            switch ((int)$where['type']) {
+                case 1:
+                    $uids = User::where('spread_uid', $where['uid'])->column('uid');
+                    if (count($uids))
+                        $model = $model->where("{$alias}uid", 'in', $uids);
+                    else
+                        $model = $model->where("{$alias}uid", 0);
+                    break;
+                case 2:
+                    $uids = User::where('spread_uid', $where['uid'])->column('uid');
+                    if (count($uids))
+                        $spread_uid_two = User::where('spread_uid', 'in', $uids)->column('uid');
+                    else
+                        $spread_uid_two = [0];
+                    if (count($spread_uid_two))
+                        $model = $model->where("{$alias}uid", 'in', $spread_uid_two);
+                    else
+                        $model = $model->where("{$alias}uid", 0);
+                    break;
+                default:
+                    $uids = User::where('spread_uid', $where['uid'])->column('uid');
+                    if (count($uids)) {
+                        if ($spread_uid_two = User::where('spread_uid', 'in', $uids)->column('uid')) {
+                            $uids = array_merge($uids, $spread_uid_two);
+                            $uids = array_unique($uids);
+                            $uids = array_merge($uids);
+                        }
+                        $model = $model->where("{$alias}uid", 'in', $uids);
+                    } else
+                        $model = $model->where("{$alias}uid", 0);
+                    break;
+            }
+        }
+        if (isset($where['data']) && $where['data']) $model = self::getModelTime($where, $model, "{$alias}add_time");
+        return $model->where("{$alias}is_del", 0)->where("{$alias}is_system_del", 0)->where($alias . 'paid', 1);
+    }
+
+    /*
+    *  推广订单统计
+    * @param array $where
+    * @return array
+    * */
+    public static function getStairOrderBadge($where)
+    {
+        if (!isset($where['uid'])) return [];
+        $data['order_count'] = self::setSairOrderWhere($where, new StoreOrder())->count();
+        $data['order_price'] = self::setSairOrderWhere($where, new StoreOrder())->sum('pay_price');
+        $ids = self::setSairOrderWhere($where, new StoreOrder())
+            ->where(['paid' => 1, 'is_del' => 0, 'refund_status' => 0])
+            ->where('status', '>', 1)
+            ->column('id');
+        $data['number_price'] = 0;
+        if (count($ids)) $data['number_price'] = UserBill::where(['category' => 'now_money', 'type' => 'brokerage', 'uid' => $where['uid']])->where('link_id', 'in', $ids)->sum('number');
+        $where['type'] = 1;
+        $data['one_price'] = self::setSairOrderWhere($where, new StoreOrder())->sum('pay_price');
+        $data['one_count'] = self::setSairOrderWhere($where, new StoreOrder())->count();
+        $where['type'] = 2;
+        $data['two_price'] = self::setSairOrderWhere($where, new StoreOrder())->sum('pay_price');
+        $data['two_count'] = self::setSairOrderWhere($where, new StoreOrder())->count();
+        return [
+            [
+                'name' => '总金额',
+                'field' => '元',
+                'count' => $data['order_price'],
+                'background_color' => 'layui-bg-cyan',
+                'col' => 3,
+            ],
+            [
+                'name' => '订单总数',
+                'field' => '单',
+                'count' => $data['order_count'],
+                'background_color' => 'layui-bg-cyan',
+                'col' => 3,
+            ],
+            [
+                'name' => '返佣总金额',
+                'field' => '元',
+                'count' => $data['number_price'],
+                'background_color' => 'layui-bg-cyan',
+                'col' => 3,
+            ],
+            [
+                'name' => '一级总金额',
+                'field' => '元',
+                'count' => $data['one_price'],
+                'background_color' => 'layui-bg-cyan',
+                'col' => 3,
+            ],
+            [
+                'name' => '一级订单数',
+                'field' => '单',
+                'count' => $data['one_count'],
+                'background_color' => 'layui-bg-cyan',
+                'col' => 3,
+            ],
+            [
+                'name' => '二级总金额',
+                'field' => '元',
+                'count' => $data['two_price'],
+                'background_color' => 'layui-bg-cyan',
+                'col' => 3,
+            ],
+            [
+                'name' => '二级订单数',
+                'field' => '单',
+                'count' => $data['two_count'],
+                'background_color' => 'layui-bg-cyan',
+                'col' => 3,
+            ],
+        ];
+    }
+
+    /*
+     * 设置查询条件
+     * @param array $where
+     * @param object $model
+     * @param string $alias
+     * */
+    public static function setSairWhere($where, $model = null, $alias = '')
+    {
+        $model = $model === null ? new self() : $model;
+        if (!isset($where['uid'])) return $model;
+        if ($alias) {
+            $model = $model->alias($alias);
+            $alias .= '.';
+        }
+        if (isset($where['type'])) {
+            switch ((int)$where['type']) {
+                case 1:
+                    $uids = User::where('spread_uid', $where['uid'])->column('uid');
+                    if (count($uids))
+                        $model = $model->where("{$alias}uid", 'in', $uids);
+                    else
+                        $model = $model->where("{$alias}uid", 0);
+                    break;
+                case 2:
+                    $uids = User::where('spread_uid', $where['uid'])->column('uid');
+                    if (count($uids))
+                        $spread_uid_two = User::where('spread_uid', 'in', $uids)->column('uid');
+                    else
+                        $spread_uid_two = [0];
+                    if (count($spread_uid_two))
+                        $model = $model->where("{$alias}uid", 'in', $spread_uid_two);
+                    else
+                        $model = $model->where("{$alias}uid", 0);
+                    break;
+                default:
+                    $uids = User::where('spread_uid', $where['uid'])->column('uid');
+                    if (count($uids)) {
+                        if ($spread_uid_two = User::where('spread_uid', 'in', $uids)->column('uid')) {
+                            $uids = array_merge($uids, $spread_uid_two);
+                            $uids = array_unique($uids);
+                            $uids = array_merge($uids);
+                        }
+                        $model = $model->where("{$alias}uid", 'in', $uids);
+                    } else
+                        $model = $model->where("{$alias}uid", 0);
+                    break;
+            }
+        }
+        if (isset($where['data']) && $where['data']) $model = self::getModelTime($where, $model, "{$alias}add_time");
+        if (isset($where['nickname']) && $where['nickname']) $model = $model->where("{$alias}phone|{$alias}nickname|{$alias}real_name|{$alias}uid", 'LIKE', "%$where[nickname]%");
+        return $model->where($alias . 'status', 1);
+    }
+
+    public static function getSairBadge($where)
+    {
+        $data['number'] = self::setSairWhere($where, new User())->count();
+        $where['type'] = 1;
+        $data['one_number'] = self::setSairWhere($where, new User())->count();
+        $where['type'] = 2;
+        $data['two_number'] = self::setSairWhere($where, new User())->count();
+        $col = $data['two_number'] > 0 ? 4 : 6;
+        return [
+            [
+                'name' => '总人数',
+                'field' => '人',
+                'count' => $data['number'],
+                'background_color' => 'layui-bg-cyan',
+                'col' => $col,
+            ],
+            [
+                'name' => '一级人数',
+                'field' => '人',
+                'count' => $data['one_number'],
+                'background_color' => 'layui-bg-cyan',
+                'col' => $col,
+            ],
+            [
+                'name' => '二级人数',
+                'field' => '人',
+                'count' => $data['two_number'],
+                'background_color' => 'layui-bg-cyan',
+                'col' => $col,
+            ],
+        ];
+    }
+
+    public static function getStairList($where)
+    {
+        if (!isset($where['uid'])) return [];
+        $data = self::setSairWhere($where, new User())->order('add_time desc')->page((int)$where['page'], (int)$where['limit'])->select();
+        $data = count($data) ? $data->toArray() : [];
+        foreach ($data as &$item) {
+            $item['spread_count'] = User::where('spread_uid', $item['uid'])->count();
+            $item['order_count'] = StoreOrder::where('uid', $item['uid'])->where(['paid' => 1, 'is_del' => 0])->count();
+            $item['promoter_name'] = $item['is_promoter'] ? '是' : '否';
+            $item['add_time'] = $item['add_time'] ? date("Y-m-d H:i:s", $item['add_time']) : '';
+        }
+        $count = self::setSairWhere($where, new User())->count();
+        return compact('data', 'count');
+    }
+
+    /*
+    * 推广订单
+    * @param array $where
+    * @return array
+    * */
+    public static function getStairOrderList($where)
+    {
+        if (!isset($where['uid'])) return [];
+        $data = self::setSairOrderWhere($where, new StoreOrder())
+            ->page((int)$where['page'], (int)$where['limit'])
+            ->order('add_time desc')
+            ->select();
+        $data = count($data) ? $data->toArray() : [];
+        $Info = User::where('uid', $where['uid'])->find();
+        foreach ($data as &$item) {
+            $userInfo = User::where('uid', $item['uid'])->find();
+            $item['user_info'] = '';
+            $item['avatar'] = '';
+            if ($userInfo) {
+                $item['user_info'] = $userInfo->nickname . '|' . ($userInfo->phone ? $userInfo->phone . '|' : '') . $userInfo->real_name;
+                $item['avatar'] = $userInfo->avatar;
+            }
+            $item['spread_info'] = $Info->nickname . "|" . ($Info->phone ? $Info->phone . "|" : '') . $Info->uid;
+            $item['number_price'] = UserBill::where(['category' => 'now_money', 'type' => 'brokerage', 'link_id' => $item['id']])->value('number');
+            $item['_pay_time'] = date('Y-m-d H:i:s', $item['pay_time']);
+            $item['_add_time'] = date('Y-m-d H:i:s', $item['add_time']);
+            $item['take_time'] = ($change_time = StoreOrderStatus::where(['change_type' => 'user_take_delivery', 'oid' => $item['id']])->value('change_time')) ?
+                date('Y-m-d H:i:s', $change_time) : '暂无';
+        }
+        $count = self::setSairOrderWhere($where, new StoreOrder())->count();
+        return compact('data', 'count');
+    }
+
+    /*
+    * 获取分销员列表头部统计
+    * */
+    public static function getSpreadBadge($where)
+    {
+        $where['is_time'] = 1;
+        $listuids = self::setSpreadWhere($where)->field('u.uid')->select();
+        $newUids = [];
+        foreach ($listuids as $item) {
+            $newUids[] = $item['uid'];
+        }
+        $uids = $newUids;
+        unset($uid, $newUids);
+        //分销员人数
+        $data['sum_count'] = count($uids);
+        $data['spread_sum'] = 0;
+        $data['order_count'] = 0;
+        $data['pay_price'] = 0;
+        $data['number'] = 0;
+        $data['extract_count'] = 0;
+        $data['extract_price'] = 0;
+        if ($data['sum_count']) {
+            //发展会员人数
+            $data['spread_sum'] = User::where('spread_uid', 'in', $uids)->count();
+            //订单总数
+            $data['order_count'] = StoreOrder::where('uid', 'in', $uids)->where(['paid' => 1, 'refund_status' => 0])->count();
+            //订单金额
+            $data['pay_price'] = StoreOrder::where('uid', 'in', $uids)->where(['paid' => 1, 'refund_status' => 0])->sum('pay_price');
+            //可提现金额
+            $data['number'] = User::where('uid', 'in', $uids)->sum('brokerage_price');
+            //提现次数
+            $data['extract_count'] = UserExtract::where('uid', 'in', $uids)->count();
+            //获取某个用户可提现金额
+            $data['extract_price'] = User::getextractPrice($uids, $where);
+        }
+
+        return [
+            [
+                'name' => '分销员人数',
+                'field' => '人',
+                'count' => $data['sum_count'],
+                'background_color' => 'layui-bg-cyan',
+                'col' => 2,
+            ],
+            [
+                'name' => '发展会员人数',
+                'field' => '人',
+                'count' => $data['spread_sum'],
+                'background_color' => 'layui-bg-cyan',
+                'col' => 2,
+            ],
+            [
+                'name' => '分销订单数',
+                'field' => '单',
+                'count' => $data['order_count'],
+                'background_color' => 'layui-bg-cyan',
+                'col' => 2,
+            ],
+            [
+                'name' => '订单金额',
+                'field' => '元',
+                'count' => $data['pay_price'],
+                'background_color' => 'layui-bg-cyan',
+                'col' => 2,
+            ],
+            [
+                'name' => '提现金额',
+                'field' => '元',
+                'count' => $data['number'],
+                'background_color' => 'layui-bg-cyan',
+                'col' => 2,
+            ],
+            [
+                'name' => '提现次数',
+                'field' => '次',
+                'count' => $data['extract_count'],
+                'background_color' => 'layui-bg-cyan',
+                'col' => 2,
+            ],
+            [
+                'name' => '未提现金额',
+                'field' => '元',
+                'count' => $data['extract_price'],
+                'background_color' => 'layui-bg-cyan',
+                'col' => 2,
+            ],
+        ];
+    }
+
+    /**
+     * 获取筛选后的所有用户uid
+     * @param array $where
+     * @return array
+     */
+    public static function getAll($where = [])
+    {
+        $model = new self;
+        if ($where['nickname'] !== '') $model = $model->where('nickname', 'LIKE', "%$where[nickname]%");
+        if ($where['data'] !== '') $model = self::getModelTime($where, $model, 'add_time');
+        if ($where['tagid_list'] !== '') {
+            $model = $model->where('tagid_list', 'LIKE', "%$where[tagid_list]%");
+        }
+        if ($where['groupid'] !== '-1') $model = $model->where('groupid', "$where[groupid]");
+        if ($where['sex'] !== '') $model = $model->where('sex', "$where[sex]");
+        return $model->column('uid', 'uid');
+    }
+
+    /**
+     * 获取已关注的用户
+     * @param $field
+     */
+    public static function getSubscribe($field)
+    {
+        return self::where('subscribe', 1)->column($field);
+    }
+
+    public static function getUserAll($field)
+    {
+        return self::column($field);
+    }
+
+    public static function getUserTag()
+    {
+        $tagName = Config::get('system_wechat_tag');
+        return Cache::tag($tagName)->remember('_wechat_tag', function () use ($tagName) {
+            Cache::tag($tagName, ['_wechat_tag']);
+            $tag = WechatService::userTagService()->lists()->toArray()['tags'] ?: [];
+            $list = [];
+            foreach ($tag as $g) {
+                $list[$g['id']] = $g;
+            }
+            return $list;
+        });
+    }
+
+    public static function clearUserTag()
+    {
+        Cache::delete('_wechat_tag');
+    }
+
+    public static function getUserGroup()
+    {
+        $tagName = Config::get('system_wechat_tag');
+        return Cache::tag($tagName)->remember('_wechat_group', function () use ($tagName) {
+            Cache::tag($tagName, ['_wechat_group']);
+            $tag = WechatService::userGroupService()->lists()->toArray()['groups'] ?: [];
+            $list = [];
+            foreach ($tag as $g) {
+                $list[$g['id']] = $g;
+            }
+            return $list;
+        });
+    }
+
+    public static function clearUserGroup()
+    {
+
+        Cache::delete('_wechat_group');
+    }
+
+    /**
+     * 获取推广人数
+     * @param $uid //用户的uid
+     * @param int $spread
+     * $spread 0 一级推广人数  1 二级推广人数
+     * @return int|string
+     */
+    public static function getUserSpreadUidCount($uid, $spread = 1)
+    {
+        $userStair = User::where('spread_uid', $uid)->column('uid', 'uid');//获取一级推家人
+        if ($userStair) {
+            if (!$spread) return count($userStair);//返回一级推人人数
+            else return User::where('spread_uid', 'IN', implode(',', $userStair))->count();//二级推荐人数
+        } else return 0;
+    }
+
+    /**
+     * 获取推广人的订单
+     * @param $uid
+     * @param int $spread
+     * $spread 0 一级推广总订单  1 所有推广总订单
+     * @return int|string
+     */
+    public static function getUserSpreadOrderCount($uid, $spread = 1)
+    {
+        $userStair = User::where('spread_uid', $uid)->column('uid', 'uid');//获取一级推家人uid
+        if ($userStair) {
+            if (!$spread) {
+                return StoreOrder::where('uid', 'IN', implode(',', $userStair))->where('paid', 1)->where('refund_status', 0)->where('status', 2)->count();//获取一级推广人订单数
+            } else {
+                $userSecond = User::where('spread_uid', 'IN', implode(',', $userStair))->column('uid', 'uid');//二级推广人的uid
+                if ($userSecond) {
+                    return StoreOrder::where('uid', 'IN', implode(',', $userSecond))->where('paid', 1)->where('refund_status', 0)->where('status', 2)->count();//获取二级推广人订单数
+                } else return 0;
+            }
+        } else return 0;
+    }
+
+}

+ 19 - 0
app/admin/provider.php

@@ -0,0 +1,19 @@
+<?php
+// +----------------------------------------------------------------------
+// | ThinkPHP [ WE CAN DO IT JUST THINK ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
+// +----------------------------------------------------------------------
+// | Author: liu21st <liu21st@gmail.com>
+// +----------------------------------------------------------------------
+
+use app\Request;
+
+// 容器Provider定义文件
+return [
+    'think\exception\Handle' => \app\admin\controller\AdminException::class,
+    'JobLogic' => \app\admin\logic\enterprise\JobLogic::class,
+    'ApplyLogic' => \app\admin\logic\enterprise\ApplyLogic::class
+];

+ 11 - 0
app/admin/readme.txt

@@ -0,0 +1,11 @@
+
+store 产品
+order 订单
+user 会员
+wechat 微信用户
+record 数据
+finance 财务
+ump 营销
+system 设置
+article 内容
+server 升级服务器版

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików