Browse Source

2021-3-25

Gogs 4 years ago
commit
9ffe612f8d
100 changed files with 18983 additions and 0 deletions
  1. BIN
      .DS_Store
  2. 15 0
      .gitignore
  3. 2 0
      .version
  4. 44 0
      README.md
  5. BIN
      application/.DS_Store
  6. 196 0
      application/admin/common.php
  7. 36 0
      application/admin/config.php
  8. 99 0
      application/admin/controller/AuthController.php
  9. 33 0
      application/admin/controller/Common.php
  10. 584 0
      application/admin/controller/Index.php
  11. 83 0
      application/admin/controller/Login.php
  12. 205 0
      application/admin/controller/article/Article.php
  13. 147 0
      application/admin/controller/article/ArticleCategory.php
  14. 217 0
      application/admin/controller/article/ArticleV1.php
  15. 151 0
      application/admin/controller/article/Consult.php
  16. 48 0
      application/admin/controller/article/Search.php
  17. 198 0
      application/admin/controller/article/WechatNews.php
  18. 140 0
      application/admin/controller/finance/Finance.php
  19. 130 0
      application/admin/controller/finance/UserExtract.php
  20. 105 0
      application/admin/controller/finance/UserRecharge.php
  21. 1180 0
      application/admin/controller/live/AliyunLive.php
  22. 0 0
      application/admin/controller/order/StoreOrder.php
  23. 241 0
      application/admin/controller/setting/SystemAdmin.php
  24. 334 0
      application/admin/controller/setting/SystemBroadcast.php
  25. 166 0
      application/admin/controller/setting/SystemBucket.php
  26. 468 0
      application/admin/controller/setting/SystemConfig.php
  27. 68 0
      application/admin/controller/setting/SystemConfigContent.php
  28. 150 0
      application/admin/controller/setting/SystemConfigTab.php
  29. 154 0
      application/admin/controller/setting/SystemGroup.php
  30. 774 0
      application/admin/controller/setting/SystemGroupData.php
  31. 184 0
      application/admin/controller/setting/SystemMenus.php
  32. 146 0
      application/admin/controller/setting/SystemNotice.php
  33. 685 0
      application/admin/controller/setting/SystemPlat.php
  34. 152 0
      application/admin/controller/setting/SystemRole.php
  35. 149 0
      application/admin/controller/special/Course.php
  36. 176 0
      application/admin/controller/special/Grade.php
  37. 194 0
      application/admin/controller/special/Lecturer.php
  38. 141 0
      application/admin/controller/special/SpecialTaskCategory.php
  39. 1172 0
      application/admin/controller/special/SpecialType.php
  40. 147 0
      application/admin/controller/special/Subject.php
  41. 193 0
      application/admin/controller/special/Task.php
  42. 179 0
      application/admin/controller/store/StoreCategory.php
  43. 479 0
      application/admin/controller/store/StoreProduct.php
  44. 103 0
      application/admin/controller/store/StoreProductReply.php
  45. 82 0
      application/admin/controller/system/Clear.php
  46. 139 0
      application/admin/controller/system/Express.php
  47. 84 0
      application/admin/controller/system/SystemAttachment.php
  48. 139 0
      application/admin/controller/system/SystemClear.php
  49. 187 0
      application/admin/controller/system/SystemCleardata.php
  50. 230 0
      application/admin/controller/system/SystemDatabackup.php
  51. 248 0
      application/admin/controller/system/SystemFile.php
  52. 44 0
      application/admin/controller/system/SystemLog.php
  53. 29 0
      application/admin/controller/system/SystemUpgradeclient.php
  54. 220 0
      application/admin/controller/ump/EventRegistration.php
  55. 154 0
      application/admin/controller/ump/StoreCombination.php
  56. 152 0
      application/admin/controller/user/MemberCard.php
  57. 39 0
      application/admin/controller/user/MemberRecord.php
  58. 117 0
      application/admin/controller/user/MemberShip.php
  59. 127 0
      application/admin/controller/user/SignPoster.php
  60. 812 0
      application/admin/controller/user/User.php
  61. 320 0
      application/admin/controller/user/UserNotice.php
  62. 37 0
      application/admin/controller/user/UserSign.php
  63. 261 0
      application/admin/controller/user/UserSpread.php
  64. 48 0
      application/admin/controller/wechat/Menus.php
  65. 200 0
      application/admin/controller/wechat/Reply.php
  66. 186 0
      application/admin/controller/wechat/StoreService.php
  67. 43 0
      application/admin/controller/wechat/WechatMessage.php
  68. 291 0
      application/admin/controller/wechat/WechatNewsCategory.php
  69. 143 0
      application/admin/controller/wechat/WechatTemplate.php
  70. 394 0
      application/admin/controller/wechat/WechatUser.php
  71. 299 0
      application/admin/controller/widget/Images.php
  72. 62 0
      application/admin/controller/widget/Widgets.php
  73. 198 0
      application/admin/model/article/Article.php
  74. 90 0
      application/admin/model/article/ArticleCategory.php
  75. 25 0
      application/admin/model/article/ArticleContent.php
  76. 38 0
      application/admin/model/article/Search.php
  77. 289 0
      application/admin/model/finance/FinanceModel.php
  78. 69 0
      application/admin/model/live/LiveBarrage.php
  79. 53 0
      application/admin/model/live/LiveGift.php
  80. 203 0
      application/admin/model/live/LiveGoods.php
  81. 56 0
      application/admin/model/live/LiveHonouredGuest.php
  82. 75 0
      application/admin/model/live/LivePlayback.php
  83. 95 0
      application/admin/model/live/LiveReward.php
  84. 190 0
      application/admin/model/live/LiveStudio.php
  85. 58 0
      application/admin/model/live/LiveUser.php
  86. 1042 0
      application/admin/model/order/StoreOrder.php
  87. 60 0
      application/admin/model/order/StoreOrderStatus.php
  88. 213 0
      application/admin/model/record/StoreStatistics.php
  89. 56 0
      application/admin/model/record/StoreVisit.php
  90. 48 0
      application/admin/model/special/Grade.php
  91. 215 0
      application/admin/model/special/Lecturer.php
  92. 41 0
      application/admin/model/special/RecommendBanner.php
  93. 227 0
      application/admin/model/special/Special.php
  94. 27 0
      application/admin/model/special/SpecialBarrage.php
  95. 26 0
      application/admin/model/special/SpecialContent.php
  96. 60 0
      application/admin/model/special/SpecialCourse.php
  97. 99 0
      application/admin/model/special/SpecialSource.php
  98. 47 0
      application/admin/model/special/SpecialSubject.php
  99. 160 0
      application/admin/model/special/SpecialTask.php
  100. 68 0
      application/admin/model/special/SpecialTaskCategory.php

BIN
.DS_Store


+ 15 - 0
.gitignore

@@ -0,0 +1,15 @@
+# Windows thumbnail cache files
+/.idea
+/runtime
+/public/uploads
+/public/nginx.htaccess
+*.txt
+think
+.htaccess
+*.log:
+/application/database.php
+/vendor/workerman/workerman.log
+/application/wap/controller/Login.php
+/application/wap/model/user/WechatUser.php
+/public/aa.mp4
+/public/audio.mp3

+ 2 - 0
.version

@@ -0,0 +1,2 @@
+version=CRMEB-ZSFF-BUSINESSv1.4.3
+version_code=4

+ 44 - 0
README.md

@@ -0,0 +1,44 @@
+# 知识付费
+
+#### 介绍
+知识付费系统
+
+
+#### 安装教程
+
+1. 上传代码到服务器进行解压
+2. 配置运行目录到public下
+3. 配置站点伪静态
+4. 检查php版本 7.1 版本
+5. 修改runtime和public/uploads文件夹权限为777和用户组,没有创建
+6. 配置好站点访问 http://域名 进行安装
+7. 进入安装界面进行一键安装
+
+## 使用说明
+
+### 图片 文件 视频上传说明
+
+本系统使用阿里云oss进行视频和图片上传,个别特殊文件需要上传至本地
+
+#### 配置
+
+1. 登陆阿里云后台,进入[对象存储OSS]
+2. 点击[Bucket 列表] 进行创建 Bucket,设置读取权限为[公共读],其他可自行设置
+3. 登陆知识付费系统后台,配置阿里云 OSS 上传
+
+### 短信
+
+本系统使用阿里云短信,其他短信驱动暂不支持
+
+#### 配置
+
+1. 登陆阿里云控制台后台,进入[短信服务]
+2. 点击左侧[国内消息],进行申请短信签名,短信模板
+3. 等待审核通过后,进入知识付付费系统后台,配置阿里云短信服务
+
+
+
+
+
+
+

BIN
application/.DS_Store


+ 196 - 0
application/admin/common.php

@@ -0,0 +1,196 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+
+// 应用公共文件
+
+/**
+ * 获取用户名称
+ * @param $uid
+ * @return mixed
+ */
+function getUserNickname($uid){
+    return \app\admin\model\user\User::where('uid',$uid)->value('nickname');
+}
+
+/**删除缓存hash数据
+ * @param $name
+ * @param $key
+ * @return bool
+ */
+function del_redis_hash($name, $key)
+{
+    if (!$name || !$key) return false;
+    $redisModel = new \think\cache\driver\Redis();
+    $site_url = \service\SystemConfigService::get('site_url');
+    $subjectUrl=GetUrlToDomain($site_url);
+    $name=$subjectUrl.$subjectUrl;
+    $exists_recommend_redis = $redisModel->HEXISTS($name,$key);
+    if ($exists_recommend_redis)  $redisModel->hdel($name,$key);
+    return true;
+}
+/**
+ * 获取产品名称
+ * @param $id
+ * @return mixed
+ */
+function getProductName($id){
+    return \app\admin\model\store\StoreProduct::where('id',$id)->value('store_name');
+}
+
+
+/**
+ * 获取订单编号
+ * @param $id
+ */
+function getOrderId($id){
+    return \app\admin\model\order\StoreOrder::where('id',$id)->value('order_id');
+}
+
+
+/**
+ * 根据用户uid获取订单数
+ * @param $uid
+ * @return int|string
+ */
+function getOrderCount($uid){
+    return \app\admin\model\order\StoreOrder::where('uid',$uid)->where('paid',1)->where('refund_status',0)->where('status',2)->count();
+}
+
+/**
+ * 格式化属性
+ * @param $arr
+ * @return array
+ */
+function attrFormat($arr){
+    $data = [];
+    $res = [];
+    if(count($arr) > 1){
+        for ($i=0; $i < count($arr)-1; $i++) {
+            if($i == 0) $data = $arr[$i]['detail'];
+            //替代变量1
+            $rep1 = [];
+            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($arr)-2){
+                        foreach (explode('-', $rep2) as $k => $h) {
+                            //替代变量3
+                            $rep3 = explode('_', $h);
+                            //替代变量4
+                            $rep4['detail'][$rep3[0]] = $rep3[1];
+                        }
+                        $res[] = $rep4;
+                    }
+                }
+            }
+            $data = $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];
+}
+
+/**
+ * 格式化月份
+ * @param string $time
+ * @param int $ceil
+ * @return array
+ */
+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);
+}
+/**删除目录下所有文件
+ * @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;
+}
+function get_server_ip(){
+    if(isset($_SERVER)){
+        if(array_key_exists("SERVER_ADDR",$_SERVER)){
+            $server_ip=$_SERVER['SERVER_ADDR'];
+        }else{
+            $server_ip=$_SERVER['LOCAL_ADDR'];
+        }
+    }else{
+        $server_ip = getenv('SERVER_ADDR');
+    }
+    return $server_ip;
+}
+
+/**
+ * 获取CRMEB系统版本号
+ * @param string $default
+ * @return string
+ */
+function get_crmeb_version($default = 'v1.0.0')
+{
+    try {
+        $version = parse_ini_file(app()->getRootPath() . '.version');
+        return $version['version'] ?? $default;
+    } catch (\Throwable $e) {
+        return $default;
+    }
+}
+if (!function_exists('check_phone')) {
+    /**
+     * 手机号验证
+     * @param $phone
+     * @return false|int
+     */
+    function check_phone($phone)
+    {
+        return preg_match( "/^1[3456789]\d{9}$/", $phone);
+    }
+}

+ 36 - 0
application/admin/config.php

@@ -0,0 +1,36 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+
+
+return [
+    'session'                => [
+        // SESSION 前缀
+        'prefix'         => 'admin',
+        // 驱动方式 支持redis memcache memcached
+        'type'           => '',
+        // 是否自动开启 SESSION
+        'auto_start'     => true,
+    ],
+    'app_debug'              => true,
+    // 应用Trace
+    'app_trace'              => false,
+    // 视图输出字符串内容替换
+    'view_replace_str'       => [
+        '{__ADMIN_PATH}'=>PUBILC_PATH.'system/',//后台
+        '{__FRAME_PATH}'=>PUBILC_PATH.'system/frame/',//H+框架
+        '{__PLUG_PATH}'=>PUBILC_PATH.'static/plug/',//前后台通用
+        '{__MODULE_PATH}'=>PUBILC_PATH.'system/module/',//后台功能模块
+        '{__STATIC_PATH}'=>PUBILC_PATH.'static/',//全站通用
+        '{__PUBLIC_PATH}'=>PUBILC_PATH,//静态资源路径
+        '{__PC_KS3}'=>PUBILC_PATH.'pc/ks3-js-sdk/'
+    ],
+];

+ 99 - 0
application/admin/controller/AuthController.php

@@ -0,0 +1,99 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller;
+
+use app\admin\model\system\SystemAdmin;
+use app\admin\model\system\SystemMenus;
+use app\admin\model\system\SystemRole;
+use basic\AuthBasic;
+use basic\SystemBasic;
+use behavior\system\SystemBehavior;
+use service\HookService;
+use think\Session;
+use think\Url;
+/**
+ * 基类 所有控制器继承的类
+ * Class AuthController
+ * @package app\admin\controller
+ */
+class AuthController extends AuthBasic
+{
+    /**
+     * 当前登陆管理员信息
+     * @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('Login/index');
+        try {
+            $adminInfo = SystemAdmin::activeAdminInfoOrFail();
+        } catch (\Exception $e) {
+            return $this->failed(SystemAdmin::getErrorInfo($e->getMessage()), Url::build('Login/index'));
+        }
+        $this->adminInfo = $adminInfo;
+        $this->adminId = $adminInfo['id'];
+        $this->getActiveAdminInfo();
+        $this->auth = SystemAdmin::activeAdminAuthOrFail();
+        $this->adminInfo->level === 0 || $this->checkAuth();
+        $this->assign('_admin', $this->adminInfo);
+        HookService::listen('admin_visit', $this->adminInfo, 'system', false, SystemBehavior::class);
+    }
+
+
+    protected function checkAuth($action = null, $controller = null, $module = null, array $route = [])
+    {
+        static $allAuth = null;
+        if ($allAuth === null) $allAuth = SystemRole::getAllAuth();
+        if ($module === null) $module = $this->request->module();
+        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;
+    }
+}

+ 33 - 0
application/admin/controller/Common.php

@@ -0,0 +1,33 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller;
+
+
+use service\UtilService;
+
+class Common extends AuthController
+{
+    /**
+     * 删除原来图片
+     * @param $url
+     */
+    public function rmPublicResource($url)
+    {
+        $res = UtilService::rmPublicResource($url);
+        if ($res->status)
+            return $this->successful('删除成功!');
+        else
+            return $this->failed($res->msg);
+    }
+
+
+}

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

@@ -0,0 +1,584 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller;
+
+use app\admin\model\store\StoreProduct;
+use app\admin\model\system\SystemConfig;
+use app\admin\model\system\SystemMenus;
+use app\admin\model\system\SystemRole;
+use app\admin\model\order\StoreOrder as StoreOrderModel;//订单
+use app\admin\model\user\UserExtract as UserExtractModel;//分销
+use app\admin\model\user\MemberRecord as MemberRecordModel;//会员购买记录
+use app\admin\model\user\User as UserModel;//用户
+use FormBuilder\Json;
+use service\JsonService;
+use think\Cache;
+use think\DB;
+
+/**
+ * 首页控制器
+ * 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),
+            'role_name' => SystemRole::where('id', $roles[0])->field('role_name')->find()
+        ]);
+        return $this->fetch();
+    }
+
+    //后台首页内容
+    public function main()
+    {
+        /*首页第一行统计*/
+        $now_day = strtotime(date('Y-m-d'));//今日
+        $pre_day = strtotime(date('Y-m-d', strtotime('-1 day')));//昨天时间戳
+
+        //新增学员->日
+        $now_day_user = DB::name('User')->where('add_time', 'gt', $now_day)->count();
+        $pre_day_user = DB::name('User')->where('add_time', 'gt', $pre_day)->where('add_time', 'lt', $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_day_user = DB::name('learning_records')->where('add_time', 'gt', $now_day)->count();
+        $pre_day_user = DB::name('learning_records')->where('add_time', 'gt', $pre_day)->where('add_time', 'lt', $now_day)->count();
+        $pre_day_user = $pre_day_user ? $pre_day_user : 0;
+        $first_line['records'] = [
+            '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_day_order_p = StoreOrderModel::where('paid', 1)->where(['is_del'=>0,'type'=>0])->where('pay_time', 'gt', $now_day)->count();
+        $pre_day_order_p = StoreOrderModel::where('paid', 1)->where(['is_del'=>0,'type'=>0])->where('pay_time', 'gt', $pre_day)->where('pay_time', 'lt', $now_day)->count();
+        $first_line['d_num'] = [
+            'data' => $now_day_order_p ? $now_day_order_p : 0,
+            'percent' => abs($now_day_order_p - $pre_day_order_p),
+            'is_plus' => $now_day_order_p - $pre_day_order_p > 0 ? 1 : ($now_day_order_p - $pre_day_order_p == 0 ? -1 : 0)
+        ];
+
+        //课程交易额->今天
+        $now_month_order_p = StoreOrderModel::where('paid', 1)->where(['is_del'=>0,'type'=>0])->where('pay_time', 'gt', $now_day)->value('sum(pay_price)');
+        $pre_month_order_p = StoreOrderModel::where('paid', 1)->where(['is_del'=>0,'type'=>0])->where('pay_time', 'gt', $pre_day)->where('pay_time', 'lt', $now_day)->value('sum(pay_price)');
+        $first_line['d_price'] = [
+            'data' => $now_month_order_p > 0 ? $now_month_order_p : 0,
+            'percent' => abs($now_month_order_p - $pre_month_order_p),
+            'is_plus' => $now_month_order_p - $pre_month_order_p > 0 ? 1 : ($now_month_order_p - $pre_month_order_p == 0 ? -1 : 0)
+        ];
+
+        //商品订单数->今日
+        $now_day_order_p = StoreOrderModel::where('paid', 1)->where(['is_del'=>0,'type'=>2])->where('pay_time', 'gt', $now_day)->count();
+        $pre_day_order_p = StoreOrderModel::where('paid', 1)->where(['is_del'=>0,'type'=>2])->where('pay_time', 'gt', $pre_day)->where('pay_time', 'lt', $now_day)->count();
+        $first_line['d_store_num'] = [
+            'data' => $now_day_order_p ? $now_day_order_p : 0,
+            'percent' => abs($now_day_order_p - $pre_day_order_p),
+            'is_plus' => $now_day_order_p - $pre_day_order_p > 0 ? 1 : ($now_day_order_p - $pre_day_order_p == 0 ? -1 : 0)
+        ];
+
+        //商品交易额->今天
+        $now_month_order_p = StoreOrderModel::where('paid', 1)->where(['is_del'=>0,'type'=>2])->where('pay_time', 'gt', $now_day)->value('sum(pay_price)');
+        $pre_month_order_p = StoreOrderModel::where('paid', 1)->where(['is_del'=>0,'type'=>2])->where('pay_time', 'gt', $pre_day)->where('pay_time', 'lt', $now_day)->value('sum(pay_price)');
+        $first_line['d_store_price'] = [
+            'data' => $now_month_order_p > 0 ? $now_month_order_p : 0,
+            'percent' => abs($now_month_order_p - $pre_month_order_p),
+            'is_plus' => $now_month_order_p - $pre_month_order_p > 0 ? 1 : ($now_month_order_p - $pre_month_order_p == 0 ? -1 : 0)
+        ];
+
+        //新增会员->今日
+        $now_day_order_p = DB::name('User')->where('level',1)->where('member_time', 'gt', $now_day)->count();
+        $pre_day_order_p = DB::name('User')->where('level',1)->where('member_time', 'gt', $pre_day)->where('member_time', 'lt', $now_day)->count();
+        $first_line['d_vip_num'] = [
+            'data' => $now_day_order_p ? $now_day_order_p : 0,
+            'percent' => abs($now_day_order_p - $pre_day_order_p),
+            'is_plus' => $now_day_order_p - $pre_day_order_p > 0 ? 1 : ($now_day_order_p - $pre_day_order_p == 0 ? -1 : 0)
+        ];
+
+        //会员充值->今天
+        $now_month_order_p = StoreOrderModel::where('paid', 1)->where(['is_del'=>0,'type'=>1])->where('pay_time', 'gt', $now_day)->value('sum(pay_price)');
+        $pre_month_order_p = StoreOrderModel::where('paid', 1)->where(['is_del'=>0,'type'=>1])->where('pay_time', 'gt', $pre_day)->where('pay_time', 'lt', $now_day)->value('sum(pay_price)');
+        $first_line['d_vip_price'] = [
+            'data' => $now_month_order_p > 0 ? $now_month_order_p : 0,
+            'percent' => abs($now_month_order_p - $pre_month_order_p),
+            'is_plus' => $now_month_order_p - $pre_month_order_p > 0 ? 1 : ($now_month_order_p - $pre_month_order_p == 0 ? -1 : 0)
+        ];
+        $this->assign([
+            'ip'=>get_server_ip(),
+            'first_line' => $first_line,
+        ]);
+        return $this->fetch();
+    }
+
+    /**
+     * 订单图表
+     */
+    public function orderchart()
+    {
+        $cycle = $this->request->get('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 = StoreOrderModel::where('add_time', 'between time', [$datebefor, $dateafter])
+                    ->where('is_del',0)->where('paid',1)->field("FROM_UNIXTIME(add_time,'%m-%d') as day,count(*) as count,sum(pay_price) as price")
+                    ->group("FROM_UNIXTIME(add_time, '%Y%m%e')")->order('add_time asc')->select()->toArray();
+                if (empty($order_list)) {
+                    return JsonService::successful([]);
+                }
+                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轴值
+                $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 = StoreOrderModel::where('add_time', 'between time', [$pre_datebefor, $pre_dateafter])
+                    ->field("count(*) as count,sum(pay_price) as price")->where('is_del',0)->where('paid',1)
+                    ->find();
+                if ($pre_total) {
+                    $chartdata['pre_cycle']['count'] = [
+                        'data' => $pre_total['count'] ?: 0
+                    ];
+                    $chartdata['pre_cycle']['price'] = [
+                        'data' => $pre_total['price'] ?: 0
+                    ];
+                }
+                //统计总数
+                $total = StoreOrderModel::where('add_time', 'between time', [$datebefor, $dateafter])
+                    ->field("count(*) as count,sum(pay_price) as price")->where('is_del',0)->where('paid',1)
+                    ->find();
+                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' => 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' => round(abs($cha_price) / $pre_total['price'] * 100, 2),
+                        'is_plus' => $cha_price > 0 ? -1 : ($cha_price == 0 ? 0 : 1)
+                    ];
+                }
+                return JsonService::successful('ok', $chartdata);
+                break;
+            case 'week':
+                $weekarray = array(['周日'], ['周一'], ['周二'], ['周三'], ['周四'], ['周五'], ['周六']);
+                $datebefor = date('Y-m-d', strtotime('-2 monday', time()));
+                $dateafter = date('Y-m-d', strtotime('-1 sunday', time()));
+                $order_list = StoreOrderModel::where('add_time', 'between time', [$datebefor, $dateafter])
+                    ->where('is_del',0)->where('paid',1)->field("FROM_UNIXTIME(add_time,'%w') as day,count(*) as count,sum(pay_price) as price")
+                    ->group("FROM_UNIXTIME(add_time, '%Y%m%e')")
+                    ->order('add_time asc')
+                    ->select()->toArray();
+                //数据查询重新处理
+                $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 = StoreOrderModel::where('add_time', 'between time', [$now_datebefor, $now_dateafter])
+                    ->where('is_del',0)->where('paid',1)->field("FROM_UNIXTIME(add_time,'%w') as day,count(*) as count,sum(pay_price) as price")
+                    ->group("FROM_UNIXTIME(add_time, '%Y%m%e')")
+                    ->order('add_time asc')
+                    ->select()->toArray();
+                //数据查询重新处理 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轴值
+                $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 = StoreOrderModel::where('add_time', 'between time', [$datebefor, $dateafter])
+                    ->where('is_del',0)->where('paid',1)->field("count(*) as count,sum(pay_price) as price")
+                    ->find();
+                if ($pre_total) {
+                    $chartdata['pre_cycle']['count'] = [
+                        'data' => $pre_total['count'] ?: 0
+                    ];
+                    $chartdata['pre_cycle']['price'] = [
+                        'data' => $pre_total['price'] ?: 0
+                    ];
+                }
+                //统计总数
+                $total = StoreOrderModel::where('add_time', 'between time', [$now_datebefor, $now_dateafter])
+                    ->where('is_del',0)->where('paid',1)->field("count(*) as count,sum(pay_price) as price")
+                    ->find();
+                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' => 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' => round(abs($cha_price) / $pre_total['price'] * 100, 2),
+                        'is_plus' => $cha_price > 0 ? -1 : ($cha_price == 0 ? 0 : 1)
+                    ];
+                }
+                return JsonService::successful('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 = StoreOrderModel::where('add_time', 'between time', [$datebefor, $dateafter])
+                    ->where('is_del',0)->where('paid',1)->field("FROM_UNIXTIME(add_time,'%d') as day,count(*) as count,sum(pay_price) as price")
+                    ->group("FROM_UNIXTIME(add_time, '%Y%m%e')")
+                    ->order('add_time asc')
+                    ->select()->toArray();
+                //数据查询重新处理
+                $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 = StoreOrderModel::where('add_time', 'between time', [$now_datebefor, $now_dateafter])
+                    ->where('is_del',0)->where('paid',1)->field("FROM_UNIXTIME(add_time,'%d') as day,count(*) as count,sum(pay_price) as price")
+                    ->group("FROM_UNIXTIME(add_time, '%Y%m%e')")
+                    ->order('add_time asc')
+                    ->select()->toArray();
+                //数据查询重新处理 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 = StoreOrderModel::where('add_time', 'between time', [$datebefor, $dateafter])
+                    ->where('is_del',0)->where('paid',1)->field("count(*) as count,sum(pay_price) as price")
+                    ->find();
+                if ($pre_total) {
+                    $chartdata['pre_cycle']['count'] = [
+                        'data' => $pre_total['count'] ?: 0
+                    ];
+                    $chartdata['pre_cycle']['price'] = [
+                        'data' => $pre_total['price'] ?: 0
+                    ];
+                }
+                //统计总数
+                $total = StoreOrderModel::where('add_time', 'between time', [$now_datebefor, $now_dateafter])
+                    ->where('is_del',0)->where('paid',1)->field("count(*) as count,sum(pay_price) as price")
+                    ->find();
+                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' => 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' => round(abs($cha_price) / $pre_total['price'] * 100, 2),
+                        'is_plus' => $cha_price > 0 ? -1 : ($cha_price == 0 ? 0 : 1)
+                    ];
+                }
+                return JsonService::successful('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 = StoreOrderModel::where('add_time', 'between time', [$datebefor, $dateafter])
+                    ->where('is_del',0)->where('paid',1)->field("FROM_UNIXTIME(add_time,'%m') as day,count(*) as count,sum(pay_price) as price")
+                    ->group("FROM_UNIXTIME(add_time, '%Y%m')")
+                    ->order('add_time asc')
+                    ->select()->toArray();
+                //数据查询重新处理
+                $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 = StoreOrderModel::where('add_time', 'between time', [$now_datebefor, $now_dateafter])
+                    ->where('is_del',0)->where('paid',1)->field("FROM_UNIXTIME(add_time,'%m') as day,count(*) as count,sum(pay_price) as price")
+                    ->group("FROM_UNIXTIME(add_time, '%Y%m')")
+                    ->order('add_time asc')
+                    ->select()->toArray();
+                //数据查询重新处理 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轴值
+                $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 = StoreOrderModel::where('add_time', 'between time', [$datebefor, $dateafter])
+                    ->where('is_del',0)->where('paid',1)->field("count(*) as count,sum(pay_price) as price")
+                    ->find();
+                if ($pre_total) {
+                    $chartdata['pre_cycle']['count'] = [
+                        'data' => $pre_total['count'] ?: 0
+                    ];
+                    $chartdata['pre_cycle']['price'] = [
+                        'data' => $pre_total['price'] ?: 0
+                    ];
+                }
+                //统计总数
+                $total = StoreOrderModel::where('add_time', 'between time', [$now_datebefor, $now_dateafter])
+                    ->where('is_del',0)->where('paid',1)->field("count(*) as count,sum(pay_price) as price")
+                    ->find();
+                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' => 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' => round(abs($cha_price) / $pre_total['price'] * 100, 2),
+                        'is_plus' => $cha_price > 0 ? -1 : ($cha_price == 0 ? 0 : 1)
+                    ];
+                }
+                return JsonService::successful($chartdata);
+                break;
+            default:
+                return JsonService::successful([]);
+                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;//最大值数量
+        if (empty($user_list)) return Json::fail('无数据');
+        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 Json::succ('ok', $chartdata);
+    }
+
+    /**待办事统计
+     * @param Request|null $request
+     */
+    public function Jnotice()
+    {
+        header('Content-type:text/json');
+        $data = [];
+        $data['reflectnum'] = UserExtractModel::where('status', 0)->count();;//提现
+        $data['msgcount'] = intval(intval($data['reflectnum']));
+        return Json::succ('ok', $data);
+    }
+
+    public function check_auth(){
+        return Json::succ('ok', $this->checkAuthDecrypt());
+    }
+    /**
+     * @return mixed
+     */
+   public function auth()
+    {
+        return $this->fetch();
+    }
+    public function auth_data()
+    {
+        return Json::succ('ok', $this->getAuth());
+    }
+}
+
+

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

@@ -0,0 +1,83 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller;
+
+
+use app\admin\model\system\SystemAdmin;
+use basic\SystemBasic;
+use service\CacheService;
+use service\UtilService;
+use think\Request;
+use think\Response;
+use think\Session;
+use think\Url;
+
+/**
+ * 登录验证控制器
+ * Class Login
+ * @package app\admin\controller
+ */
+class Login extends SystemBasic
+{
+    public function index()
+    {
+        return $this->fetch();
+    }
+
+    /**
+     * 登录验证 + 验证码验证
+     */
+    public function verify(Request $request)
+    {
+        if (!$request->isPost()) return ['code'=>4];
+        list($account, $pwd, $verify) = UtilService::postMore([
+            'account', 'pwd', 'verify'
+        ], $request, true);
+        //检验验证码
+        if (!captcha_check($verify)) return ['code'=>2];
+        $error = Session::get('login_error') ?: ['num' => 0, 'time' => time()];
+        if ($error['num'] >= 5 && $error['time'] < strtotime('+ 5 minutes')){
+            return ['code'=>3];
+        }
+        //检验帐号密码
+        $res = SystemAdmin::login($account, $pwd);
+        if ($res) {
+            Session::set('login_error', null);
+            return ['code'=>1];
+        } else {
+            $error['num'] += 1;
+            $error['time'] = time();
+            Session::set('login_error', $error);
+            return ['code'=>0];
+        }
+    }
+
+    public function captcha()
+    {
+        ob_clean();
+        $captcha = new \think\captcha\Captcha([
+            'codeSet' => '0123456789',
+            'length' => 4,
+            'fontSize' => 30
+        ]);
+        return $captcha->entry();
+    }
+
+    /**
+     * 退出登陆
+     */
+    public function logout()
+    {
+        SystemAdmin::clearLoginInfo();
+        $this->redirect('Login/index');
+    }
+}

+ 205 - 0
application/admin/controller/article/Article.php

@@ -0,0 +1,205 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\article;
+
+use app\admin\controller\AuthController;
+use service\JsonService as Json;
+use service\UploadService as Upload;
+use think\Request;
+use app\admin\model\article\ArticleCategory as ArticleCategoryModel;
+use app\admin\model\article\Article as ArticleModel;
+use app\admin\model\system\SystemAttachment;
+
+/**
+ * 图文管理
+ * Class WechatNews
+ * @package app\admin\controller\wechat
+ */
+class Article extends AuthController
+{
+    /**
+     * 显示后台管理员添加的图文
+     * @return mixed
+     */
+    public function index($cid = 0)
+    {
+        $where = parent::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('cate',ArticleCategoryModel::getTierList());
+        $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['is_banner'] = '';
+        $news['is_hot'] = '';
+        $news['content'] = '';
+        $news['synopsis'] = '';
+        $news['url'] = '';
+        $news['cid'] = array();
+        if($id){
+            $news = ArticleModel::where('n.id',$id)->alias('n')->field('n.*,c.content')->join('ArticleContent 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','neq',0)->column('id,title');
+                $select = 1;
+            }else{
+                $all = ArticleCategoryModel::where('id',$cid)->column('id,title');
+                $select = 1;
+            }
+
+        }
+        if(empty($all)){
+            $select =  0;
+            $list = ArticleCategoryModel::getTierList();
+            $all = [];
+            foreach ($list as $menu){
+                $all[$menu['id']] = $menu['html'].$menu['title'];
+            }
+        }
+        $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(){
+        $res = Upload::Image($_POST['file'],'wechat/image/'.date('Ymd'));
+        //产品图片上传记录
+        $fileInfo = $res->fileInfo->getinfo();
+        SystemAttachment::attachmentAdd($res->fileInfo->getSaveName(),$fileInfo['size'],$fileInfo['type'],$res->dir,'',5);
+        if(!$res->status) return Json::fail($res->error);
+        return Json::successful('上传成功!',['url'=>$res->filePath]);
+    }
+
+    /**
+     * 添加和修改图文
+     * @param Request $request
+     * @return \think\response\Json
+     */
+    public function add_new(Request $request){
+        $post  = $request->post();
+        $data = parent::postMore([
+            ['id',0],
+            ['cid',[]],
+            'title',
+            'author',
+            'image_input',
+            'content',
+            'synopsis',
+            'share_title',
+            'share_synopsis',
+            ['visit',0],
+            ['sort',0],
+            'url',
+            ['status',1],],$request);
+        $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::set($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 = parent::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();
+    }
+}

+ 147 - 0
application/admin/controller/article/ArticleCategory.php

@@ -0,0 +1,147 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\article;
+
+use app\admin\controller\AuthController;
+use service\FormBuilder as Form;
+use service\JsonService as Json;
+use service\UploadService as Upload;
+use think\Request;
+use think\Url;
+use app\admin\model\article\ArticleCategory as ArticleCategoryModel;
+use app\admin\model\article\Article as ArticleModel;
+
+/**
+ * 文章分类管理  控制器
+ * */
+class ArticleCategory extends AuthController
+{
+    /**
+     * 分类管理
+     **/
+     public function index(){
+         $where = parent::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(){
+            $menus[] = ['value'=>0,'label'=>'顶级分类'];
+            return $menus;
+        })->filterable(1);
+        $f[] = Form::input('title','分类名称');
+        $f[] = Form::input('intr','分类简介')->type('textarea');
+        $f[] = Form::number('sort','排序',0);
+        $f[] = Form::radio('status','状态',1)->options([['value'=>1,'label'=>'显示'],['value'=>0,'label'=>'隐藏']]);
+        $form = Form::make_post_form('添加分类',$f,Url::build('save'),2);
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * s上传图片
+     * */
+    public function upload(){
+        $res = Upload::image('file','article');
+        $thumbPath = Upload::thumb($res->dir);
+        if($res->status == 200)
+            return Json::successful('图片上传成功!',['name'=>$res->fileInfo->getSaveName(),'url'=>Upload::pathToUrl($thumbPath)]);
+        else
+            return Json::fail($res->error);
+    }
+
+    /**
+     * 保存分类管理
+     * */
+    public function save(Request $request){
+        $data = parent::postMore([
+            'title',
+            'pid',
+            'intr',
+            ['sort',0],
+            'status',],$request);
+        if(!$data['title']) return Json::fail('请输入分类名称');
+        if($data['sort'] < 0) return Json::fail('排序不能是负数');
+        $data['add_time'] = time();
+        if(ArticleCategoryModel::be(['title'=>$data['title'],'is_del'=>0])){
+            return Json::fail('分类名称已存在!');
+        }
+        ArticleCategoryModel::set($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(){
+            $menus[] = ['value'=>0,'label'=>'顶级分类'];
+            return $menus;
+        })->filterable(1);
+        $f[] = Form::input('title','分类名称',$article['title']);
+        $f[] = Form::input('intr','分类简介',$article['intr'])->type('textarea');
+        $f[] = Form::number('sort','排序',$article['sort']);
+        $f[] = Form::radio('status','状态',$article['status'])->options([['value'=>1,'label'=>'显示'],['value'=>0,'label'=>'隐藏']]);
+        $form = Form::make_post_form('编辑分类',$f,Url::build('update',array('id'=>$id)),2);
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**保存修改
+     * @param Request $request
+     * @param $id
+     * @throws \think\exception\DbException
+     */
+    public function update(Request $request, $id)
+    {
+        $data = parent::postMore([
+            'pid',
+            'title',
+            'intr',
+            ['image',[]],
+            ['sort',0],
+            'status',],$request);
+        if(!$data['title']) return Json::fail('请输入分类名称');
+        if($data['sort'] < 0) return Json::fail('排序不能是负数');
+        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('删除成功!');
+    }
+
+
+}
+

+ 217 - 0
application/admin/controller/article/ArticleV1.php

@@ -0,0 +1,217 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\article;
+
+use app\admin\controller\AuthController;
+use app\admin\model\article\ArticleCategory as ArticleCategoryModel;
+use app\admin\model\article\ArticleContent;
+use service\JsonService as Json;
+use service\UploadService as Upload;
+use think\Request;
+use app\admin\model\article\Article;
+use app\admin\model\system\Recommend;
+use app\admin\model\system\RecommendRelation;
+use think\Url;
+use service\FormBuilder as Form;
+use app\admin\model\wechat\WechatNewsCategory as WechatNewsCategoryModel;
+
+/**
+ * 图文管理
+ * Class WechatNews
+ * @package app\admin\controller\wechat
+ */
+class ArticleV1 extends AuthController
+{
+    public function index($cid = 0)
+    {
+        $this->assign('cid',$cid);
+        $this->assign('cate',ArticleCategoryModel::getTierList());
+        $this->assign('type', $this->request->param('type', 1));
+        return $this->fetch();
+    }
+
+
+    public function article_list()
+    {
+        $where = parent::getMore([
+            ['limit', 20],
+            ['page', 1],
+            ['cid', $this->request->param('cid')],
+            ['store_name', ''],
+            ['order', ''],
+            ['is_show', ''],
+        ]);
+        return Json::successlayui(Article::getArticleLayList($where));
+    }
+
+    /**
+     * 设置单个产品上架|下架
+     *
+     * @return json
+     */
+    public function set_show($is_show = '', $id = '')
+    {
+        ($is_show == '' || $id == '') && Json::fail('缺少参数');
+        $res = Article::where(['id' => $id])->update(['is_show' => (int)$is_show]);
+        if ($res) {
+            return Json::successful($is_show == 1 ? '显示成功' : '隐藏成功');
+        } else {
+            return Json::fail($is_show == 1 ? '显示失败' : '隐藏失败');
+        }
+    }
+
+    /**
+     * 快速编辑
+     *
+     * @return json
+     */
+    public function set_value($field = '', $id = '', $value = '')
+    {
+        $field == '' || $id == '' || $value == '' && Json::fail('缺少参数');
+        if (Article::where(['id' => $id])->update([$field => $value]))
+            return Json::successful('保存成功');
+        else
+            return Json::fail('保存失败');
+    }
+
+    public function add_article($id=0)
+    {
+        $this->assign('id', $id);
+        if ($id) {
+            $article = Article::get($id);
+            $article->profile->content = htmlspecialchars_decode($article->profile->content);
+            $this->assign('article', $article->toJson());
+        }
+        if(empty($all)){
+            $list = ArticleCategoryModel::getTierList();
+            $all = [];
+            foreach ($list as $menu){
+                $all[$menu['id']] = $menu['html'].$menu['title'];
+            }
+        }
+        $this->assign('all', json_encode($all));
+        $this->assign('type', $this->request->param('type', 2));
+        return $this->fetch();
+    }
+
+    public function save_article($id = 0)
+    {
+        $data = parent::postMore([
+            ['title', ''],
+            ['synopsis', ''],
+            ['sort', 0],
+            ['cid', 0],
+            ['content', ''],
+            ['image_input', ''],
+            ['label', []],
+        ]);
+        if (!$data['title']) return Json::fail('请输入图文标题');
+        if (!$data['synopsis']) return Json::fail('请输入图文简介');
+        if (!$data['content']) return Json::fail('请输入图文内容');
+        $data['label'] = json_encode($data['label']);
+        $content = htmlspecialchars($data['content']);
+        Article::beginTrans();
+        try {
+            if ($id) {
+                Article::update($data, ['id' => $id]);
+                ArticleContent::update(['content' => $content], ['nid' => $id]);
+                Article::commitTrans();
+                return Json::successful('修改成功');
+            } else {
+                $data['add_time'] = time();
+                $data['is_show'] = 1;
+                $res1 = Article::set($data);
+                $res2 = ArticleContent::set(['nid' => Article::getLastInsID(), 'content' => $content]);
+                if ($res1 && $res2) {
+                    Article::commitTrans();
+                    return Json::successful('添加成功');
+                } else {
+                    Article::rollbackTrans();
+                    return Json::fail('添加失败');
+                }
+            }
+        } catch (\Exception $e) {
+            Article::rollbackTrans();
+            return Json::fail($e->getMessage());
+        }
+    }
+
+    public function delete($id = 0)
+    {
+        if (!$id) return Json::fail('缺少参数');
+        $article = Article::get($id);
+        if (!$article) return Json::fail('没有查找到图文');
+        Article::beginTrans();
+        try {
+            $res = $article->delete();
+            $res1 = ArticleContent::where('nid', $id)->delete();
+            if ($res1 && $res) {
+                if($article['hide']==1){
+                    WechatNewsCategoryModel::where('new_id',$id)->delete();
+                }
+                Article::commitTrans();
+                return Json::successful('删除成功');
+            } else {
+                Article::rollbackTrans();
+                return Json::fail('删除失败');
+            }
+        } catch (\Exception $e) {
+            Article::rollbackTrans();
+            return Json::fail($e->getMessage());
+        }
+    }
+
+    /*
+    * 添加推荐
+    * */
+    public function recommend($article_id = 0)
+    {
+        if (!$article_id) $this->failed('缺少参数');
+        $article = Article::get($article_id);
+        if (!$article) $this->failed('没有查到此专题');
+        $form = Form::create(Url::build('save_recommend', ['article_id' => $article_id]), [
+            Form::select('recommend_id', '推荐')->setOptions(function () {
+                $list = Recommend::where(['is_show' => 1, 'type' => 1])->field('title,id')->order('sort desc,add_time desc')->select();
+                $menus = [['value' => 0, 'label' => '顶级菜单']];
+                foreach ($list as $menu) {
+                    $menus[] = ['value' => $menu['id'], 'label' => $menu['title']];
+                }
+                return $menus;
+            })->filterable(1),
+            Form::number('sort', '排序'),
+        ]);
+        $form->setMethod('post')->setTitle('推荐设置')->setSuccessScript('parent.$(".J_iframe:visible")[0].contentWindow.location.reload(); setTimeout(function(){parent.layer.close(parent.layer.getFrameIndex(window.name));},800);');
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /*
+     * 保存推荐
+     * */
+    public function save_recommend($article_id = 0)
+    {
+        if (!$article_id) $this->failed('缺少参数');
+        $data = parent::postMore([
+            ['recommend_id', 0],
+            ['sort', 0],
+        ]);
+        if (!$data['recommend_id']) return Json::fail('请选择推荐');
+        $data['add_time'] = time();
+        $data['type'] = 1;
+        $data['link_id'] = $article_id;
+        if (RecommendRelation::be(['type' => 1, 'link_id' => $article_id, 'recommend_id' => $data['recommend_id']])) return Json::fail('已推荐,请勿重复推荐');
+        if (RecommendRelation::set($data))
+            return Json::successful('推荐成功');
+        else
+            return Json::fail('推荐失败');
+    }
+}

+ 151 - 0
application/admin/controller/article/Consult.php

@@ -0,0 +1,151 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\article;
+
+use app\admin\controller\AuthController;
+use service\FormBuilder as Form;
+use service\JsonService as Json;
+use service\UploadService as Upload;
+use think\Request;
+use think\Url;
+use app\admin\model\article\ArticleContent as ArticleContentContentModel;
+use app\admin\model\article\Article as WechatNewsModel;
+use traits\CurdControllerTrait;
+/**
+ * 活动咨询控制器
+ * Class Consult
+ * @package app\admin\controller\wechat
+ */
+class Consult extends AuthController
+{
+
+    use CurdControllerTrait;
+
+    protected $bindModel = ArticleContentContentModel::class;
+
+    public function edit_content($id,$type='content'){
+        if(!$id) return $this->failed('数据不存在');
+        $news = WechatNewsModel::get($id);
+        if(!$news) return Json::fail('数据不存在!');
+        $this->assign([
+            'content'=>ArticleContentContentModel::where('nid',$id)->value($type),
+            'field'=>$type,
+            'action'=>Url::build('consult_field',['id'=>$id,'field'=>$type])
+        ]);
+        return $this->fetch('public/edit_content');
+    }
+
+     public function index(){
+         $where = parent::getMore([
+             ['consult_type',0],
+             ['title',''],
+         ],$this->request);
+         $this->assign('where',$where);
+         $this->assign(WechatNewsModel::getConsultList($where));
+         return $this->fetch();
+     }
+
+    public function create(){
+
+
+        $field = [
+            Form::text('title','文章标题'),
+            Form::frameImages('consult_image','产品轮播图(640*640px)',Url::build('admin/widget.images/index',array('fodder'=>'consult_image')))->maxLength(5)->icon('images')->width('100%')->height('550px')->spin(0),
+            Form::number('visit','浏览量',0),
+            Form::number('sort','排序',0),
+            Form::radio('status','状态',0)->options([['label'=>'显示','value'=>1],['label'=>'隐藏','value'=>0]])->col(8)
+        ];
+        $form = Form::create(Url::build('save'));
+        $form->setMethod('post')->setTitle('编辑文章')->components($field)->setSuccessScript('parent.$(".J_iframe:visible")[0].contentWindow.location.reload();');
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * s上传图片
+     * */
+    public function upload(){
+        $res = Upload::image('file','article');
+        $thumbPath = Upload::thumb($res->dir);
+        if($res->status == 200)
+            return Json::successful('图片上传成功!',['name'=>$res->fileInfo->getSaveName(),'url'=>Upload::pathToUrl($thumbPath)]);
+        else
+            return Json::fail($res->error);
+    }
+
+    public function save(Request $request){
+        $data = parent::postMore([
+            ['title',''],
+            ['consult_image',[]],
+            ['visit',0],
+            ['sort',0],
+            ['consult_type',1],
+            ['status',0],
+        ],$request);
+        if(!strlen(trim($data['title']))) return Json::fail('请输入文章名称');
+        if(!count($data['consult_image'])) return Json::fail('请上传图片');
+        if($data['sort'] < 0) return Json::fail('排序不能是负数');
+        $data['add_time'] = time();
+        $data['is_consult'] = 1;
+        $data['hide'] = 0;
+        $data['is_hot'] = 1;
+        $data['status'] = (int)$data['status'];
+        $data['consult_image'] = implode(',',$data['consult_image']);
+        $res = WechatNewsModel::set($data);
+        if(!$res) return Json::fail('文章添加失败');
+        return Json::successful('添加文章成功!');
+    }
+
+    public function edit($id){
+        $article = WechatNewsModel::get($id);
+        if(!$article) return Json::fail('数据不存在!');
+        $form = Form::create(Url::build('update',array('id'=>$id)),[
+            Form::text('title','文章标题',$article->getData('title')),
+            Form::frameImages('consult_image','产品轮播图(640*640px)',Url::build('admin/widget.images/index',array('fodder'=>'consult_image')),explode(',',$article->getData('consult_image')))->maxLength(5)->icon('images')->width('100%')->height('550px')->spin(0),
+            Form::number('visit','浏览量',$article->getData('visit')),
+            Form::number('sort','排序',$article->getData('sort')),
+            Form::radio('status','状态',$article->getData('status'))->options([['label'=>'显示','value'=>1],['label'=>'隐藏','value'=>0]])->col(8)
+        ]);
+        $form->setMethod('post')->setTitle('编辑文章')->setSuccessScript('parent.$(".J_iframe:visible")[0].contentWindow.location.reload();');
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    public function update(Request $request, $id)
+    {
+        $data = parent::postMore([
+            ['title',''],
+            ['consult_image',[]],
+            ['visit',0],
+            ['sort',0],
+            ['consult_type',1],
+            ['status',0],
+        ],$request);
+        if(!strlen(trim($data['title']))) return Json::fail('请输入文章名称');
+        if(!count($data['consult_image'])) return Json::fail('请上传图片');
+        if($data['sort'] < 0) return Json::fail('排序不能是负数');
+        $data['consult_image'] = implode(',',$data['consult_image']);
+        $data['status'] = (int)$data['status'];
+        if(!WechatNewsModel::get($id)) return Json::fail('编辑的记录不存在!');
+        $res = WechatNewsModel::edit($data,$id);
+        if(!$res) return Json::fail('修改失败');
+        return Json::successful('修改成功!');
+    }
+
+    public function delete($id)
+    {
+        $res = WechatNewsModel::edit(['hide'=>1],$id);
+        if(!$res) return Json::fail('删除失败,请稍候再试!');
+        else return Json::successful('删除成功!');
+    }
+}
+

+ 48 - 0
application/admin/controller/article/Search.php

@@ -0,0 +1,48 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\article;
+
+use app\admin\controller\AuthController;
+use service\JsonService as Json;
+use service\UploadService as Upload;
+use think\Request;
+use think\Url;
+use service\FormBuilder as Form;
+use app\admin\model\article\Search as SearchModel;
+/**
+ * 搜索
+ * Class Search
+ * @package app\admin\controller\article
+ */
+class Search extends AuthController
+{
+    public function index(){
+        $this->assign('list',SearchModel::getAll());
+        return $this->fetch();
+    }
+
+    public function save($name=''){
+        if(!$name) return Json::fail('请输入热词名称');
+        if($res=SearchModel::saveSearch($name))
+            return Json::successful('添加成功',$res);
+        else
+            return Json::fail(SearchModel::getErrorInfo('添加失败'));
+    }
+
+    public function del_search($id=0){
+        if(!$id) return Json::fail('缺少参数');
+        if(SearchModel::del($id))
+            return Json::successful('删除成功');
+        else
+            return Json::fail('删除失败');
+    }
+}

+ 198 - 0
application/admin/controller/article/WechatNews.php

@@ -0,0 +1,198 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\article;
+
+use app\admin\controller\AuthController;
+use service\JsonService as Json;
+use service\UploadService as Upload;
+use think\Request;
+use app\admin\model\article\ArticleCategory as ArticleCategoryModel;
+use app\admin\model\article\Article as ArticleModel;
+use app\admin\model\system\SystemAttachment;
+
+/**
+ * 图文管理
+ * Class WechatNews
+ * @package app\admin\controller\wechat
+ */
+class WechatNews extends AuthController
+{
+    /**
+     * 显示后台管理员添加的图文
+     * @return mixed
+     */
+    public function index($cid = 0)
+    {
+        $where = parent::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 = \app\admin\model\wechat\WechatNews::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','neq',0)->column('id,title');
+                $select = 1;
+            }else{
+                $all = ArticleCategoryModel::where('id',$cid)->column('id,title');
+                $select = 1;
+            }
+
+        }
+        if(empty($all)){
+            $all = ArticleCategoryModel::getField('id,title');//新闻分类
+            $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(){
+        $res = Upload::Image($_POST['file'],'wechat/image/'.date('Ymd'));
+        //产品图片上传记录
+        $fileInfo = $res->fileInfo->getinfo();
+        SystemAttachment::attachmentAdd($res->fileInfo->getSaveName(),$fileInfo['size'],$fileInfo['type'],$res->dir,'',5);
+        if(!$res->status) return Json::fail($res->error);
+        return Json::successful('上传成功!',['url'=>$res->filePath]);
+    }
+
+    /**
+     * 添加和修改图文
+     * @param Request $request
+     * @return \think\response\Json
+     */
+    public function add_new(Request $request){
+        $post  = $request->post();
+        $data = parent::postMore([
+            ['id',0],
+            ['cid',[]],
+            'title',
+            'author',
+            'image_input',
+            'content',
+            'synopsis',
+            'share_title',
+            'share_synopsis',
+            ['visit',0],
+            ['sort',0],
+            'url',
+            ['status',1],],$request);
+        $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::set($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 = parent::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();
+    }
+}

+ 140 - 0
application/admin/controller/finance/Finance.php

@@ -0,0 +1,140 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+
+namespace app\admin\controller\finance;
+
+use app\admin\controller\AuthController;
+use app\admin\model\user\UserBill;
+use service\JsonService as Json;
+use app\admin\model\finance\FinanceModel;
+use service\SystemConfigService;
+use service\FormBuilder as Form;
+use service\HookService;
+use think\Url;
+use app\admin\model\user\User;
+use app\admin\model\user\UserExtract;
+
+/**
+ * 微信充值记录
+ * Class UserRecharge
+ * @package app\admin\controller\user
+ */
+class Finance extends AuthController
+{
+
+    /**
+     * 显示资金记录
+     */
+    public function bill()
+    {
+        $category = $this->request->param('category','now_money');
+        $bill_where_op = FinanceModel::bill_where_op($category);
+        $list = UserBill::where('type', $bill_where_op['type']['op'], $bill_where_op['type']['condition'])
+            ->where('category', $bill_where_op['category']['op'], $bill_where_op['category']['condition'])
+            ->field(['title', 'type'])
+            ->group('type')
+            ->distinct(true)
+            ->select()
+            ->toArray();
+        $this->assign('selectList', $list);
+        $this->assign('category', $category);
+        $this->assign('gold_name', $category == "now_money" ? "金额" : SystemConfigService::get("gold_name"));
+        return $this->fetch();
+    }
+
+    /**
+     * 显示资金记录ajax列表
+     */
+    public function billlist()
+    {
+        $where = parent::getMore([
+            ['start_time', ''],
+            ['end_time', ''],
+            ['nickname', ''],
+            ['limit', 20],
+            ['page', 1],
+            ['type', ''],
+            ['category', 'now_money'],
+        ]);
+        return Json::successlayui(FinanceModel::getBillList($where));
+    }
+
+    /**
+     *保存资金监控的excel表格
+     */
+    public function save_bell_export()
+    {
+        $where = parent::getMore([
+            ['start_time', ''],
+            ['end_time', ''],
+            ['nickname', ''],
+            ['type', ''],
+            ['category', 'now_money'],
+        ]);
+        FinanceModel::SaveExport($where);
+    }
+
+    /**
+     * 显示佣金记录
+     */
+    public function commission_list()
+    {
+        $this->assign('is_layui', true);
+        return $this->fetch();
+    }
+
+    /**
+     * 佣金记录异步获取
+     */
+    public function get_commission_list()
+    {
+        $get = parent::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['nickname', ''],
+            ['price_max', ''],
+            ['price_min', ''],
+            ['order', '']
+        ]);
+        return Json::successlayui(User::getCommissionList($get));
+    }
+
+
+    /**
+     * 佣金详情
+     */
+    public function content_info($uid = '')
+    {
+        if ($uid == '') return $this->failed('缺少参数');
+        $this->assign('userinfo', User::getUserinfo($uid));
+        $this->assign('uid', $uid);
+        return $this->fetch();
+    }
+
+    /**
+     * 佣金提现记录个人列表
+     */
+    public function get_extract_list($uid = '')
+    {
+        if ($uid == '') return Json::fail('缺少参数');
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['start_time', ''],
+            ['end_time', ''],
+            ['nickname', '']
+        ]);
+        return Json::successlayui(UserBill::getExtrctOneList($where, $uid));
+    }
+
+}
+

+ 130 - 0
application/admin/controller/finance/UserExtract.php

@@ -0,0 +1,130 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+
+namespace app\admin\controller\finance;
+
+use app\admin\controller\AuthController;
+use service\FormBuilder as Form;
+use app\admin\model\user\UserExtract as UserExtractModel;
+use service\JsonService;
+use think\Request;
+use think\Url;
+
+/**
+ * 用户提现管理
+ * Class UserExtract
+ * @package app\admin\controller\finance
+ */
+class UserExtract extends AuthController
+{
+    public function index()
+    {
+        $where = parent::getMore([
+            ['status', ''],
+            ['nickname', ''],
+            ['extract_type', ''],
+            ['nireid', ''],
+        ], $this->request);
+        $this->assign('where', $where);
+        $this->assign(UserExtractModel::systemPage($where));
+        return $this->fetch();
+    }
+
+    public function edit($id)
+    {
+        if (!$id) return $this->failed('数据不存在');
+        $UserExtract = UserExtractModel::get($id);
+        if (!$UserExtract) return JsonService::fail('数据不存在!');
+        $f = array();
+        $f[] = Form::input('real_name', '姓名', $UserExtract['real_name']);
+        $f[] = Form::number('extract_price', '提现金额', $UserExtract['extract_price'])->precision(2);
+        if ($UserExtract['extract_type'] == 'alipay') {
+            $f[] = Form::input('alipay_code', '支付宝账号', $UserExtract['alipay_code']);
+        } else {
+            $f[] = Form::input('bank_code', '银行卡号', $UserExtract['bank_code']);
+            $f[] = Form::input('bank_address', '开户行', $UserExtract['bank_address']);
+        }
+        $f[] = Form::input('mark', '备注', $UserExtract['mark'])->type('textarea');
+        $form = Form::make_post_form('编辑', $f, Url::build('update', array('id' => $id)));
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+
+    }
+
+    public function update(Request $request, $id)
+    {
+        $UserExtract = UserExtractModel::get($id);
+        if (!$UserExtract) return JsonService::fail('数据不存在!');
+        if ($UserExtract['extract_type'] == 'alipay') {
+            $data = parent::postMore([
+                'real_name',
+                'mark',
+                'extract_price',
+                'alipay_code',
+            ], $request);
+            if (!$data['real_name']) return JsonService::fail('请输入姓名');
+            if ($data['extract_price'] <= -1) return JsonService::fail('请输入提现金额');
+            if (!$data['alipay_code']) return JsonService::fail('请输入支付宝账号');
+        } else {
+            $data = parent::postMore([
+                'real_name',
+                'extract_price',
+                'mark',
+                'bank_code',
+                'bank_address',
+            ], $request);
+            if (!$data['real_name']) return JsonService::fail('请输入姓名');
+            if ($data['extract_price'] <= -1) return JsonService::fail('请输入提现金额');
+            if (!$data['bank_code']) return JsonService::fail('请输入银行卡号');
+            if (!$data['bank_address']) return JsonService::fail('请输入开户行');
+        }
+        if (!UserExtractModel::edit($data, $id))
+            return JsonService::fail(UserExtractModel::getErrorInfo('修改失败'));
+        else
+            return JsonService::successful('修改成功!');
+    }
+
+    public function fail(Request $request, $id)
+    {
+        if (!UserExtractModel::be(['id' => $id, 'status' => 0])) return JsonService::fail('操作记录不存在或状态错误!');
+        $fail_msg = $request->post();
+        $extract = UserExtractModel::get($id);
+        if (!$extract) return JsonService::fail('操作记录不存!');
+        if ($extract->status == 1) return JsonService::fail('已经提现,错误操作');
+        if ($extract->status == -1) return JsonService::fail('您的提现申请已被拒绝,请勿重复操作!');
+        $res = UserExtractModel::changeFail($id, $fail_msg['message']);
+        if ($res) {
+            return JsonService::successful('操作成功!');
+        } else {
+            return JsonService::fail('操作失败!');
+        }
+    }
+
+    public function succ($id)
+    {
+        if (!UserExtractModel::be(['id' => $id, 'status' => 0]))
+            return JsonService::fail('操作记录不存在或状态错误!');
+        UserExtractModel::beginTrans();
+        $extract = UserExtractModel::get($id);
+        if (!$extract) return JsonService::fail('操作记录不存!');
+        if ($extract->status == 1) return JsonService::fail('您已提现,请勿重复提现!');
+        if ($extract->status == -1) return JsonService::fail('您的提现申请已被拒绝!');
+        $res = UserExtractModel::changeSuccess($id);
+        if ($res) {
+            UserExtractModel::commitTrans();
+            return JsonService::successful('操作成功!');
+        } else {
+            UserExtractModel::rollbackTrans();
+            return JsonService::fail('操作失败!');
+        }
+    }
+}

+ 105 - 0
application/admin/controller/finance/UserRecharge.php

@@ -0,0 +1,105 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\finance;
+
+use app\admin\controller\AuthController;
+use app\admin\model\user\UserRecharge as UserRechargeModel;
+use app\wap\model\user\UserBill;
+use service\JsonService as Json;
+use think\Url;
+use service\FormBuilder as Form;
+use think\Request;
+use service\HookService;
+use behavior\wechat\PaymentBehavior;
+use service\WechatTemplateService;
+use app\wap\model\user\WechatUser as WechatUserWap;
+
+/**
+ * 微信充值记录
+ * Class UserRecharge
+ * @package app\admin\controller\user
+ */
+class UserRecharge extends AuthController
+{
+    /**
+     * 显示操作记录
+     */
+    public function index()
+    {
+        $where = parent::getMore([
+            ['order_id', ''],
+        ], $this->request);
+        $list = UserRechargeModel::systemPage($where);
+        $recharge_type_cn = ['yue' => "余额", 'weixin' => "微信", 'zhifubao' => "支付宝"];
+        $this->assign('recharge_type_cn', $recharge_type_cn);
+        $this->assign('where', $where);
+        $this->assign($list);
+        return $this->fetch();
+    }
+
+    /**退款
+     * @param $id
+     * @return mixed|void
+     */
+    public function edit($id)
+    {
+        if (!$id) return $this->failed('数据不存在');
+        $UserRecharge = UserRechargeModel::get($id);
+        if (!$UserRecharge) return Json::fail('数据不存在!');
+        if ($UserRecharge['paid'] == 1) {
+            $f = array();
+            $f[] = Form::input('order_id', '退款单号', $UserRecharge->getData('order_id'))->disabled(1);
+            $f[] = Form::number('refund_price', '退款金额', $UserRecharge->getData('price'))->precision(2)->min(0)->max($UserRecharge->getData('price'));
+            $form = Form::make_post_form('编辑', $f, Url::build('updateRefundY', array('id' => $id)));
+            $this->assign(compact('form'));
+            return $this->fetch('public/form-builder');
+        } else return Json::fail('数据不存在!');
+    }
+
+    /**退款更新
+     * @param Request $request
+     * @param $id
+     */
+    public function updateRefundY(Request $request, $id)
+    {
+        $data = parent::postMore([
+            'refund_price',
+        ], $request);
+        if (!$id) return $this->failed('数据不存在');
+        $UserRecharge = UserRechargeModel::get($id);
+        if (!$UserRecharge) return Json::fail('数据不存在!');
+        if ($UserRecharge['price'] == $UserRecharge['refund_price']) return Json::fail('已退完支付金额!不能再退款了');
+        if (!$data['refund_price']) return Json::fail('请输入退款金额');
+        $refund_price = $data['refund_price'];
+        $data['refund_price'] = bcadd($data['refund_price'], $UserRecharge['refund_price'], 2);
+        $bj = bccomp((float)$UserRecharge['price'], (float)$data['refund_price'], 2);
+        if ($bj < 0) return Json::fail('退款金额大于支付金额,请修改退款金额');
+        $refund_data['pay_price'] = $UserRecharge['price'];
+        $refund_data['refund_price'] = $refund_price;
+        try {
+            HookService::listen('user_recharge_refund', $UserRecharge['order_id'], $refund_data, true, PaymentBehavior::class);
+        } catch (\Exception $e) {
+            return Json::fail($e->getMessage());
+        }
+        UserRechargeModel::edit($data, $id);
+        WechatTemplateService::sendTemplate(WechatUserWap::uidToOpenid($UserRecharge['uid']), WechatTemplateService::ORDER_REFUND_STATUS, [
+            'first' => '亲,您充值的金额已退款,本次退款' .
+                $data['refund_price'] . '金额',
+            'keyword1' => $UserRecharge['order_id'],
+            'keyword2' => $UserRecharge['price'],
+            'keyword3' => date('Y-m-d H:i:s', $UserRecharge['add_time']),
+            'remark' => '请查看账单'
+        ], '');
+        UserBill::expend('系统退款', $UserRecharge['uid'], 'now_money', 'user_recharge_refund', $refund_price, $id, $UserRecharge['price'], '退款给用户' . $refund_price . '元');
+        return Json::successful('退款成功!');
+    }
+}

+ 1180 - 0
application/admin/controller/live/AliyunLive.php

@@ -0,0 +1,1180 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\live;
+
+use app\admin\controller\AuthController;
+use app\admin\model\live\LiveGoods;
+use app\admin\model\live\LiveGift;
+use app\admin\model\live\LiveReward;
+use app\admin\model\order\StoreOrder as StoreOrderModel;
+use app\admin\model\live\LiveBarrage;
+use app\admin\model\live\LiveHonouredGuest;
+use app\admin\model\live\LiveStudio;
+use app\admin\model\live\LiveUser;
+use app\admin\model\live\LivePlayback;
+use app\admin\model\special\Grade;
+use app\admin\model\special\Special as SpecialModel;
+use app\admin\model\special\Special;
+use app\admin\model\special\SpecialCourse;
+use app\admin\model\special\SpecialSubject;
+use app\admin\model\special\SpecialTask;
+use app\admin\model\system\SystemAdmin;
+use app\admin\model\user\User;
+use app\wap\model\user\WechatUser;
+use service\JsonService as Json;
+use service\SystemConfigService;
+use service\WechatTemplateService;
+use think\Exception;
+use service\FormBuilder as Form;
+use Api\AliyunLive as ApiAliyunLive;
+use think\Session;
+use think\Url;
+use \GatewayWorker\Lib\Gateway;
+use app\admin\model\system\SystemRole as RoleModel;
+
+class AliyunLive extends AuthController
+{
+    /**
+     * 阿里云直播句柄
+     * @var \Api\AliyunLive
+     */
+    protected $aliyunLive;
+
+    protected function _initialize()
+    {
+        parent::_initialize();
+        $this->aliyunLive = \Api\AliyunLive::instance([
+            'AccessKey' => SystemConfigService::get('accessKeyId'),
+            'AccessKeySecret' => SystemConfigService::get('accessKeySecret'),
+            'OssEndpoint' => SystemConfigService::get('aliyun_live_end_point'),
+            'OssBucket' => SystemConfigService::get('aliyun_live_oss_bucket'),
+            'appName' => SystemConfigService::get('aliyun_live_appName'),
+            'payKey' => SystemConfigService::get('aliyun_live_play_key'),
+            'key' => SystemConfigService::get('aliyun_live_push_key'),
+            'playLike' => SystemConfigService::get('aliyun_live_playLike'),
+            'rtmpLink' => SystemConfigService::get('aliyun_live_rtmpLink'),
+        ]);
+    }
+
+    /**
+     * 直播间管理
+     * */
+    public function index()
+    {
+        $this->assign([
+            'special_list' => SpecialModel::where('type', SPECIAL_LIVE)->where(['is_del'=>0])->field(['id', 'title'])->select()->toArray(),
+            'type' => $this->request->param('type', 1),
+        ]);
+        return $this->fetch();
+    }
+
+    /**
+     * 快速设置直播的某个字段的值
+     * @param string $field 键值
+     * @param string $value 值
+     * @param int $id 直播id
+     * @return json
+     * */
+    public function set_live_value($field = '', $value = '', $id = 0)
+    {
+        if (!$field || !$id) return Json::fail('缺少参数');
+        $value = str_replace('免密', '', $value);
+        if (LiveStudio::where('id', $id)->update([$field => $value]))
+            return Json::successful('修改成功');
+        else
+            return Json::fail('修改失败');
+    }
+
+    /**
+     * 编辑直播间
+     * */
+    public function update_live($id = 0)
+    {
+        if (!$id) return $this->failed('缺少参数');
+        $liveInfo = LiveStudio::get($id);
+        if (!$liveInfo) return $this->failed('未查到直播间信息');
+        $f[] = Form::input('stream_name', '直播间号:', $liveInfo->getData('stream_name'))->disabled(true);
+        $f[] = Form::input('live_title', '直播间标题:', $liveInfo->getData('live_title'));
+        $f[] = Form::frameImageOne('live_image', '直播封面:', Url::build('admin/widget.images/index', array('fodder' => 'live_image')), $liveInfo->getData('live_image'))->icon('image')->width('100%')->height('500px');
+        $f[] = Form::input('studio_pwd', '直播间密码:', $liveInfo->getData('studio_pwd'));
+        $f[] = Form::textarea('live_introduction', '直播间简介:', $liveInfo->getData('live_introduction'));
+        $f[] = Form::number('online_num', '虚拟在线人数:', $liveInfo->getData('online_num'));
+        $f[] = Form::number('sort', '排序', $liveInfo->getData('sort'));
+        $f[] = Form::radio('is_remind', '开播提醒:', $liveInfo->getData('is_remind'))->options([
+            ['value' => 1, 'label' => '是'],
+            ['value' => 0, 'label' => '否'],
+        ]);
+        $f[] = Form::number('remind_time', '开播前提醒时间(分):', $liveInfo->getData('remind_time'));
+        $f[] = Form::radio('is_recording', '自动录制:', $liveInfo->getData('is_recording'))->options([
+            ['value' => 1, 'label' => '是'],
+            ['value' => 0, 'label' => '否'],
+        ]);
+        $f[] = Form::radio('is_playback', '回放:', $liveInfo->getData('is_playback'))->options([
+            ['value' => 1, 'label' => '是'],
+            ['value' => 0, 'label' => '否'],
+        ]);
+        $form = Form::make_post_form('修改直播间', $f, Url::build('save_live', array('id' => $id)), 3);
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 修改直播间
+     * @param int $id
+     * @return json
+     * */
+    public function save_live($id = 0)
+    {
+        if (!$id) return Json::fail('缺少参数');
+        $data = parent::postMore([
+            ['live_title', ''],
+            ['live_image', ''],
+            ['studio_pwd', ''],
+            ['live_introduction', ''],
+            ['online_num', 0],
+            ['sort', 0],
+            ['is_remind', 0],
+            ['remind_time', 0],
+            ['is_recording', 0],
+            ['is_playback', 0],
+        ]);
+        if (!$data['live_title']) return Json::fail('直播间标题不能为空');
+        if (!$data['live_introduction']) return Json::fail('直播间简介不能为空');
+        if ($data['is_remind'] && !$data['remind_time']) return Json::fail('请输入直播前提醒时间!');
+        if (LiveStudio::edit($data, $id))
+            return Json::successful('修改成功');
+        else
+            return Json::fail('修改失败或者您没有修改内容');
+    }
+
+    /**
+     * 直播间用户管理
+     * @param int $id
+     * */
+    public function live_user($id = 0)
+    {
+        if (!$id) return $this->failed('缺少参数');
+        $liveInfo = LiveStudio::get($id);
+        if (!$liveInfo) return $this->failed('未查到直播间');
+        $this->assign([
+            'stream_name' => $liveInfo->stream_name,
+            'live_id' => $id
+        ]);
+        return $this->fetch();
+    }
+
+    /**
+     * 获取直播间用户列表
+     * */
+    public function get_live_user_list()
+    {
+        $where = parent::getMore([
+            ['live_id', 0],
+            ['page', 0],
+            ['limit', 20],
+            ['nickname', ''],
+            ['start_time', ''],
+            ['end_time', ''],
+        ]);
+        if (!$where['live_id']) return Json::fail('缺少参数');
+        return Json::successlayui(LiveUser::getLiveUserList($where));
+    }
+
+    /**
+     * 设置直播用户
+     * @param string $field
+     * @param string $id
+     * @param string $value
+     */
+    public function set_live_user_value($field = '', $id = '', $value = '')
+    {
+        if (!$field || !$id) return Json::fail('缺少参数');
+        if (LiveUser::where('id', $id)->update([$field => $value]))
+            return Json::successful('修改成功');
+        else
+            return Json::fail('修改失败');
+    }
+
+    /**
+     * 禁止发言
+     */
+    public function live_no_speaking($id)
+    {
+        if (!$id) return $this->failed('缺少参数');
+        $liveInfo = LiveUser::get($id);
+        if (!$liveInfo) return $this->failed('未查到直播间信息');
+        $f[] = Form::radio('is_ban', '是否禁言', $liveInfo->getData('is_ban'))->options([
+            ['value' => 1, 'label' => '是'],
+            ['value' => 0, 'label' => '否'],
+        ]);
+        $f[] = Form::number('ban_time', '禁言时间:分');
+        $form = Form::make_post_form('禁止发言', $f, Url::build('save_no_speaking', array('id' => $id)), 2);
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+    public function save_no_speaking($id = 0)
+    {
+        if (!$id) return Json::fail('缺少参数');
+        $data = parent::postMore([
+            ['is_ban', 0],
+            ['ban_time', 0]
+        ]);
+        if ($data['is_ban']) {
+            $workerman = \think\Config::get('workerman.channel', []);
+            Gateway::$registerAddress = $workerman['ip'] . ':' . $workerman['port'];
+            $uid = LiveUser::where('id', $id)->value('uid');
+            if (Gateway::isUidOnline($uid)) {
+                Gateway::sendToUid($uid, json_encode([
+                    'type' => 'ban',
+                    'value' => 1
+                ]));
+            }
+        }
+        if ($data['is_ban'] && $data['ban_time']<=0) return Json::fail('请输入禁言时间');
+        $data['ban_time']=bcadd(time(),bcmul($data['ban_time'],60,0),0);
+        if (LiveUser::edit($data, $id)){
+            return Json::successful('修改成功');
+        }else{
+            return Json::fail('修改失败');
+        }
+    }
+
+    /**
+     * 禁止进入
+     */
+    public function live_no_entry($id)
+    {
+        if (!$id) return $this->failed('缺少参数');
+        $liveInfo = LiveUser::get($id);
+        if (!$liveInfo) return $this->failed('未查到直播间信息');
+        $f[] = Form::radio('is_open_ben', '是否禁止进入直播间', $liveInfo->getData('is_open_ben'))->options([
+            ['value' => 1, 'label' => '是'],
+            ['value' => 0, 'label' => '否'],
+        ]);
+        $f[] = Form::number('open_ben_time', '禁止时间:分');
+        $form = Form::make_post_form('禁止进入', $f, Url::build('save_no_entry', array('id' => $id)), 2);
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+    public function save_no_entry($id = 0)
+    {
+        if (!$id) return Json::fail('缺少参数');
+        $data = parent::postMore([
+            ['is_open_ben', 0],
+            ['open_ben_time', 0]
+        ]);
+        if ($data['is_open_ben'] && $data['open_ben_time']<=0) return Json::fail('请输入禁止时间');
+        $data['open_ben_time']=bcadd(time(),bcmul($data['open_ben_time'],60,0),0);
+        if (LiveUser::edit($data, $id)){
+            return Json::successful('修改成功');
+        }else{
+            return Json::fail('修改失败');
+        }
+    }
+    /**
+     * 直播间管理
+     */
+    public function get_live_list()
+    {
+        $where = parent::getMore([
+            ['stream_name', ''],
+            ['start_time', ''],
+            ['end_time', ''],
+            ['page', 1],
+            ['limit', 20],
+            ['special_id', 0],
+        ]);
+        //根据账号身份获取各自的列表数据
+        $role_sign = get_login_role();
+        if (isset($role_sign['role_sign']) && $role_sign['role_sign'] == "anchor") {
+            $where['admin_id'] = get_login_id()['admin_id'];
+        }
+        return Json::successlayui(LiveStudio::getLiveList($where));
+    }
+
+
+    /**
+     * 直播专题列表
+     * @param int $subject_id
+     * @return mixed
+     */
+    public function special_live($subject_id = 0)
+    {
+        $special_type = $this->request->param("special_type");
+        $role_session = Session::get("adminInfo") ? Session::get("adminInfo")->toArray() : [];
+        if ($role_session) {
+            $login_role = RoleModel::where(['id' => $role_session['roles']])->field('role_name, id, sign, status')->find()->toArray();
+        }
+        if (!$special_type || !is_numeric($special_type)) return $this->failed('专题类型参数缺失');
+        $admin_list = SystemAdmin::getRoleAdmin(['anchor', 'admin']);
+        $subjectlist = Grade::with(['SpecialSubject'=>function($query){
+            $query->where(['is_show'=>1,'is_del'=>0]);
+        }])->where(['is_del'=>0,'is_show'=>1])->order('sort desc')->select();
+        $this->assign([
+            'type' => $this->request->param('type', 1),
+            'special_type' => $special_type,
+            'special_title' => SPECIAL_TYPE[$special_type],
+            'subject_id' => $subject_id,
+            'subject_list' => $subjectlist,
+            'is_live' => 1,
+            'login_role' => $login_role,
+            'admin_list' => $admin_list
+        ]);
+        return $this->fetch();
+    }
+
+    /**
+     * 获取直播推流地址
+     * @param int $id
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function go_live($id = 0)
+    {
+        if (!$id) return Json::fail('缺少参数');
+        $specialInfo = SpecialModel::get($id);
+        if (!$specialInfo) return Json::fail('直播专题暂未查到');
+        if ($specialInfo->type!=SPECIAL_LIVE) return Json::fail('此专题不授予直播专题,无法获取推流地址!');
+        $liveInfo = LiveStudio::where('special_id', $specialInfo->id)->find();
+        if (!$liveInfo) return Json::fail('没有查到此直播间');
+        if ($liveInfo->is_del) return Json::fail('直播间已删除无法推流');
+        $url = $this->aliyunLive->getPushSteam($liveInfo->stream_name);
+        return Json::successful($url);
+    }
+    /**
+     * 直播消息提醒
+     * @param int $id
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function send_remind($id = 0)
+    {
+        if (!$id) return Json::fail('缺少参数');
+        $specialInfo = SpecialModel::get($id);
+        if (!$specialInfo) return Json::fail('直播专题暂未查到,无法进行提醒');
+        $liveInfo = LiveStudio::where('special_id', $specialInfo->id)->find();
+        if (!$liveInfo) return Json::fail('没有查到此直播间,无法提醒');
+        if ($liveInfo->is_del) return Json::fail('直播间已删除无法提醒');
+        try {
+            if($specialInfo['pay_type']==1 && $specialInfo['member_pay_type']==1){
+                $orderList = StoreOrderModel::where(['cart_id' => $id])->column("uid");
+            }elseif ($specialInfo['pay_type']==1 && $specialInfo['member_pay_type']==0){
+                $order = StoreOrderModel::where(['cart_id' => $id])->column("uid");
+                $user =User::where('is_h5user',0)->where('level',1)->column("uid");
+                $orderList=array_merge($order,$user);
+            }else{
+                $orderList =User::where('is_h5user',0)->column("uid");
+            }
+            if (!$orderList) {
+                return Json::fail('暂无合适用户,无需提醒');
+            }
+            $sendUid = array();
+            $site_url = SystemConfigService::get('site_url');
+           foreach (array_unique($orderList) as $k => $v) {
+               if ($openId = WechatUser::where('uid',$v)->value('openid')) {
+                   WechatTemplateService::sendTemplate($openId,WechatTemplateService::LIVE_START_NOTICE, [
+                       'first' => '叮!直播马上开始啦,精彩不容错过!',
+                       'keyword1' => $specialInfo->title,
+                       'keyword2' => $liveInfo->start_play_time,
+                       'remark' => '直播间通道'
+                   ], $site_url . Url::build('wap/special/details',['id' => $id]));
+                   $sendUid[] = $v;
+               }
+
+           }
+            return Json::successful("发送成功",$sendUid);
+        } catch (\Exception $e) {
+            return Json::fail($e->getMessage());
+        }
+    }
+
+
+    /**
+     * 获取专题直播列表
+     */
+    public function special_list()
+    {
+        $where = parent::getMore([
+            ['subject_id', 0],
+            ['page', 1],
+            ['limit', 20],
+            ['store_name', ''],
+            ['title', ''],
+            ['start_time', ''],
+            ['end_time', ''],
+            ['order', ''],
+            ['is_show', ''],
+            ['special_type', 4],
+        ]);
+        if (isset($where['special_type'])) {
+            $where['type'] = $where['special_type'];
+        }
+        //根据账号身份获取各自的列表数据
+        $role_sign = get_login_role();
+        if (isset($role_sign['role_sign']) && $role_sign['role_sign'] == "anchor") {
+            $where['admin_id'] = get_login_id()['admin_id'];
+        }
+        $special_list = SpecialModel::getSpecialList($where);
+        if ($special_list && isset($special_list['data'])) {
+            foreach ($special_list['data'] as $k => $v) {
+                $sys_admin = SystemAdmin::where(['id' => $v['admin_id']])->field('real_name, account')->find();
+                $special_list['data'][$k]['admin_name'] = $sys_admin ? ($sys_admin['real_name'] ? $sys_admin['real_name'] : $sys_admin['account']) : "超级管理员";
+            }
+        }
+        return Json::successlayui($special_list);
+    }
+
+    /**
+     * 删除专题和直播间
+     * @param int $id
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function delete($id = 0)
+    {
+        if (!$id) return Json::fail('缺少参数');
+        $specialInfo = SpecialModel::get($id);
+        if (!$specialInfo) return Json::fail('查找的专题不存在');
+        if ($specialInfo->is_del) return Json::fail('专题已经删除');
+        $liveInfo = LiveStudio::where(['special_id' => $id])->find();
+        if (!$liveInfo) return Json::fail('删除的专题直播不存在');
+        if ($liveInfo->is_del) return Json::fail('直播间已删除');
+        $specialInfo->is_del = 1;
+        $liveInfo->is_del = 1;
+        if ($specialInfo->save() && $liveInfo->save()) {
+            LiveStudio::where(['special_id' => $id])->update(['is_del' => 1]);
+            return Json::successful('删除成功');
+        }else{
+            return Json::fail('删除失败');
+        }
+
+    }
+
+    public function recommend($id = 0){
+        if (!$id) return Json::fail('缺少参数');
+        $specialInfo = SpecialModel::get($id);
+        if (!$specialInfo) return Json::fail('专题不存在');
+        Session::set('live_one_id',$id,'wap');
+        return Json::successful('推荐成功');
+    }
+    /**
+     * 嘉宾列表
+     * @param $live_id
+     * @return mixed
+     */
+    public function guest_list($live_id = 0)
+    {
+        $this->assign('live_id', $live_id);
+        return $this->fetch();
+    }
+
+    /**
+     * 添加嘉宾
+     * @param int $live_id
+     * @return mixed|void
+     * @throws \FormBuilder\exception\FormBuilderException
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function add_course($live_id = 0){
+        $where = parent::getMore([
+            ['nickname', ''],
+            ['status', ''],
+            ['is_promoter', ''],
+        ], $this->request);
+        $this->assign('where', $where);
+        $this->assign(User::systemPage($where));
+        $this->assign('live_id', $live_id);
+        return $this->fetch();
+    }
+    /**
+     * 添加嘉宾
+     * @param int $live_id
+     */
+    public function save_guest($uid=0,$live_id = 0,$type=0)
+    {
+        if (!$live_id) return Json::fail('缺少直播间id');
+        if (!$uid) return Json::fail('请选择用户');
+        if ($type === '') return Json::fail('请选择类型');
+        if ($type && LiveHonouredGuest::be(['live_id' => $live_id, 'type' => 1])) return Json::fail('讲师只能添加一个');
+        $data['uid'] = $uid;
+        $data['type'] = $type;
+        $data['live_id'] = $live_id;
+        $data['nickname'] = User::where('uid', $uid)->value('nickname');
+        $data['add_time'] = time();
+        if (LiveHonouredGuest::set($data))
+            return Json::successful('添加成功');
+        else
+            return Json::fail('添加失败');
+    }
+
+    /**
+     * 获取嘉宾列表
+     */
+    public function get_guest_list()
+    {
+        $where = parent::getMore([
+            ['live_id', 0],
+            ['nickname', ''],
+            ['page', 1],
+            ['limit', 20],
+        ]);
+        return Json::successlayui(LiveHonouredGuest::getGuestList($where));
+    }
+
+    /**
+     * 删除嘉宾
+     * @param int $id
+     */
+    public function del_guest($id = 0)
+    {
+        if (!$id) return Json::fail('缺少参数');
+        if (LiveHonouredGuest::del($id))
+            return Json::successful('删除成功');
+        else
+            return Json::fail('删除失败');
+    }
+
+
+    /**
+     * 回放设置和下载列表
+     * @param int $special_id
+     * @return mixed|void
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function download_list($special_id = 0)
+    {
+        if (!$special_id) return $this->failed('缺少参数');
+        $specialInfo = SpecialModel::get($special_id);
+        if (!$specialInfo) return $this->failed('查找的专题不存在');
+        if ($specialInfo->is_del) return $this->failed('专题已经删除');
+        $liveInfo = LiveStudio::where(['special_id' => $special_id])->find();
+        if (!$liveInfo) return $this->failed('直播不存在!');
+        $livePlayBack = LivePlayback::where(['stream_name' => $liveInfo->stream_name, 'is_record' => 1])->find();
+        $this->assign([
+            'stream_name' => $liveInfo->stream_name,
+            'record_id' => $livePlayBack ? $livePlayBack->RecordId : 0,
+            'is_playback' => 1
+        ]);
+        return $this->fetch();
+    }
+
+    /**
+     * 获取直播间下的录制内容
+     * @param string $record_id
+     * @param string $stream_name
+     * @param string $start_time
+     * @param string $end_time
+     * @param int $page
+     * @param int $limit
+     */
+    public function get_live_record()
+    {
+        $start_time = $this->request->param('syn_start_time');
+        $end_time = $this->request->param('syn_end_time');
+        $stream_name = $this->request->param('stream_name');
+        $record_id = $this->request->param('record_id');
+        if (!$stream_name) return Json::fail('缺少直播间id');
+        $aliyunLive = $this->aliyunLive;
+        $beginToday = mktime(0, 0, 0, date('m'), date('d') - 3, date('Y'));
+        if ($start_time && $end_time) {
+            $start_time = strtotime($start_time);
+            $end_time = strtotime($end_time);
+            if ($start_time > $end_time) return Json::fail('开始时间不能大于结束时间');
+            $time = bcsub($end_time, $start_time, 0) / 86400;
+            if ($time > 4) return Json::fail('开始和结束的时间不能间隔4天');
+        }
+        try{
+            $res = $aliyunLive->queryLiveRecordFiles(
+                $stream_name,
+                $start_time ? ApiAliyunLive::setTimeFormat($start_time) : ApiAliyunLive::setTimeFormat($beginToday),
+                $end_time ? ApiAliyunLive::setTimeFormat($end_time) : ApiAliyunLive::setTimeFormat(time()),
+                 1,
+                 10
+            );
+            $data = [];
+            $count = 0;
+            if ($res) {
+                if (isset($res['RecordIndexInfoList']['RecordIndexInfo'])) {
+                    foreach ($res['RecordIndexInfoList']['RecordIndexInfo'] as $item) {
+                        LivePlayback::livePlaybackAdd($item);
+                        $data [] = [
+                            'StreamName' => $item['StreamName'],
+                            'RecordId' => $item['RecordId'],
+                            'playback_record_id' => $record_id,
+                            'RecordUrl' => $item['RecordUrl'],
+                            'StartTime' => $item['StartTime'],
+                            'EndTime' => $item['EndTime'],
+                        ];
+                    }
+                }
+                if (isset($res['TotalNum'])) $count = $res['TotalNum'];
+                return Json::successlayui($count, $data);
+            } else {
+                return Json::fail('未拉取到直播回放');
+            }
+        }catch (Exception $exception){
+            return Json::fail($exception->getMessage());
+        }
+
+    }
+
+    /**回放列表
+     * @param string $stream_name
+     * @param string $start_time
+     * @param string $end_time
+     * @param int $page
+     * @param int $limit
+     */
+    public function get_live_record_list()
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['stream_name', ''],
+            ['start_time', ''],
+            ['end_time', ''],
+        ]);
+        $data=LivePlayback::getLivePlaybackList($where);
+        return Json::successlayui($data);
+    }
+
+    /**
+     * 删除直播回放
+     */
+    public function delete_live_playback($id=0)
+    {
+        $res=LivePlayback::where('id',$id)->update(['is_del'=>1]);
+        if($res){
+            return Json::successful('删除成功');
+        }else{
+            return Json::fail('删除失败');
+        }
+    }
+    /**设置显示
+     * @param string $is_show
+     * @param string $id
+     */
+    public function set_show($is_show = '', $id = '')
+    {
+        ($is_show == '' || $id == '') && Json::fail('缺少参数');
+        $res = LivePlayback::where(['id' => $id])->update(['is_show' => (int)$is_show]);
+        if ($res) {
+            return Json::successful($is_show == 1 ? '显示成功' : '隐藏成功');
+        } else {
+            return Json::fail($is_show == 1 ? '显示失败' : '隐藏失败');
+        }
+    }
+    /**
+     * 设置某个字段
+     * @param int $stream_name
+     * @param string $field
+     * @param string $value
+     */
+    public function set_playback_value($field = '',$id=0, $value = '')
+    {
+        if (!$id || !$field) return Json::fail('缺少参数');
+        $res = LivePlayback::where(['id' => $id])->update([$field => $value]);
+        if ($res)
+            return Json::successful('编辑成功');
+        else
+            return Json::fail('编辑失败');
+    }
+    /**
+     * 设置某个字段
+     * @param int $stream_name
+     * @param string $field
+     * @param string $value
+     */
+    public function set_value($stream_name = 0, $field = '', $value = '')
+    {
+        if (!$stream_name || !$field) return Json::fail('缺少参数');
+        $res = LiveStudio::where('stream_name', $stream_name)->update([$field => $value]);
+        if ($res)
+            return Json::successful('设置成功');
+        else
+            return Json::fail('设置失败');
+    }
+    public function set_record($stream_name = 0, $record_id = 0, $field = '', $value = '')
+    {
+        if (!$stream_name || !$record_id || !$field) return Json::fail('缺少参数');
+        $res = LivePlayback::where(['stream_name' => $stream_name, 'RecordId' => $record_id])->update([$field => $value]);
+        if ($value == 1) {
+            LiveStudio::where(['stream_name' => $stream_name])->update(['playback_record_id' => $record_id, 'is_playback' => 1]);
+            LivePlayback::where(['stream_name' => $stream_name])->where( 'RecordId',"neq",$record_id)->update([$field => 0]);
+        }else{
+            LiveStudio::where(['stream_name' => $stream_name])->update(['playback_record_id' => "", 'is_playback' => 0]);
+        }
+        if ($res)
+            return Json::successful('设置成功');
+        else
+            return Json::fail('设置失败');
+    }
+
+    /**
+     * 直播回放
+     * @param string $record_url
+     * @return mixed|void
+     */
+    public function live_record_look($record_url = '')
+    {
+        if (!$record_url) return $this->failed('缺少回放地址');
+        $this->assign('record_url', $record_url);
+        return $this->fetch();
+    }
+
+    /**
+     * 下载引导页面
+     * @param string $record_url
+     * @return mixed|void
+     */
+    public function download($record_url = '')
+    {
+        if (!$record_url) return $this->failed('缺少回放地址');
+        $this->assign('record_url', $record_url);
+        return $this->fetch();
+    }
+
+    /**
+     * 评论页面
+     * @param int $special_id
+     * @return mixed|void
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function comment_list($special_id = 0)
+    {
+        if (!$special_id) return $this->failed('缺少参数');
+        $specialInfo = SpecialModel::get($special_id);
+        if (!$specialInfo) return $this->failed('查找的专题不存在');
+        if ($specialInfo->is_del) return $this->failed('专题已经删除');
+        $liveInfo = LiveStudio::where(['special_id' => $special_id])->find();
+        if (!$liveInfo) return $this->failed('直播不存在!');
+        if ($liveInfo->is_del) return $this->failed('直播间已删除!');
+        $this->assign('live_id', $liveInfo->id);
+        return $this->fetch();
+    }
+
+    /**
+     * 获取直播评论列表
+     */
+    public function get_live_comment_list()
+    {
+        $where = parent::getMore([
+            ['live_id', 0],
+            ['page', 1],
+            ['limit', 20],
+            ['nickname', ''],
+            ['start_time', ''],
+            ['end_time', ''],
+        ]);
+        if (!$where['live_id']) return Json::fail('缺少直播间id');
+        return Json::successlayui(LiveBarrage::getLiveCommentList($where));
+    }
+
+    /**
+     * 设置评论隐藏显示
+     *
+     * @return json
+     */
+    public function set_show_comment($is_show = '', $id = '')
+    {
+        ($is_show == '' || $id == '') && Json::fail('缺少参数');
+        $res = LiveBarrage::where(['id' => $id])->update(['is_show' => (int)$is_show]);
+        if ($res) {
+            return Json::successful('设置成功');
+        } else {
+            return Json::fail('设置失败');
+        }
+    }
+
+    /**
+     * 任务关联列表
+     * @param int $special_id
+     * @return mixed|void
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function relation_task($special_id = 0)
+    {
+        $specialInfo = SpecialModel::get($special_id);
+        if (!$specialInfo) return $this->failed('专题不存在');
+        $liveInfo = LiveStudio::where('special_id', $special_id)->find();
+        if (!$liveInfo) return $this->failed('直播间不存在');
+        if ($liveInfo->is_del) return $this->failed('直播间已删除!');
+        $this->assign('live_id', $liveInfo->id);
+        return $this->fetch();
+    }
+
+    /**
+     * 任务关联列表展示
+     * @throws Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function get_relation_task()
+    {
+        $where = parent::getMore([
+            ['live_id', 0],
+            ['title', ''],
+            ['start_time', ''],
+            ['end_time', ''],
+            ['page', 1],
+            ['limit', 20],
+        ]);
+        if (!$where['live_id']) return Json::fail('缺少参数');
+        return Json::successlayui(SpecialTask::getRelationTask($where));
+    }
+
+    /**
+     * 保存直播任务关联
+     * @param int $live_id
+     * @param int $special_id
+     * @return mixed|void
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function save_task($live_id = 0, $special_id = 0)
+    {
+        if (!$live_id) return $this->failed('缺少参数');
+        $liveInfo = LiveStudio::get($live_id);
+        if (!$liveInfo) return $this->failed('直播间不存在');
+        if ($special_id) {
+            $list = SpecialCourse::where('is_show', 1)->where('special_id', $special_id)->field(['id', 'course_name'])->select();
+            $opens = [];
+            foreach ($list as $item) {
+                $opens [] = ['value' => $item['id'], 'label' => $item['course_name']];
+            }
+            $f[] = Form::input('special_id', '专题id', $special_id)->disabled(true);
+            $f[] = Form::input('title', '任务标题', $liveInfo->getData('live_title'));
+            $f[] = Form::frameImageOne('image', '任务封面图', Url::build('admin/widget.images/index', array('fodder' => 'image')), $liveInfo->getData('live_image'))->icon('image')->width('100%')->height('550px');
+            $f[] = Form::number('sort', '排序', 0);
+            $form = Form::make_post_form('关联任务', $f, Url::build('set_task', array('live_id' => $live_id)), 3);
+            $this->assign(compact('form'));
+            return $this->fetch('public/form-builder');
+        } else {
+            $this->assign('grade_list', Grade::where(['is_del'=>0,'is_show'=>1])->order('sort desc')->field(['id', 'name'])->select()->toArray());
+            $this->assign('live_id', $live_id);
+            return $this->fetch();
+        }
+    }
+
+    /**
+     * @param int $grade_id
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function get_subject_list($grade_id = 0)
+    {
+        if (!$grade_id) return Json::fail('缺少参数');
+        $subjectlist = SpecialSubject::where(['grade_id' => $grade_id, 'is_show' => 1, 'is_del' => 0])->order('sort desc')->select();
+        return Json::successful($subjectlist);
+    }
+
+    /**
+     * @param int $subject_id
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function get_special_list($subject_id = false, $live_goods_list = false)
+    {
+        $where['is_show'] = 1;
+        $where['is_del'] = 0;
+        if ($subject_id) $where['subject_id'] = $subject_id;
+        if (!$live_goods_list) {
+            $dataList = $specialList = Special::where($where)->order('sort desc')->select();
+        }else{
+            $dataList = array();
+            $specialList = Special::where($where)->whereIn('type',[1,2,3,5])->order('type desc')->select();
+            foreach($specialList as $k => $v) {
+                $dataList[$k]['value'] = $v['id'];
+                $dataList[$k]['title'] = SPECIAL_TYPE[$v['type']]."--".$v['title'];
+            }
+        }
+        return Json::successful($dataList);
+    }
+
+    public function move_live_admin() {
+        $parm = parent::getMore([
+            'special_id',
+            'admin_id'
+        ]);
+        if (!$parm['special_id'] || !$parm['admin_id']) {
+            Json::fail('缺少参数');
+        }
+        $special_info = Special::get(['id' => $parm['special_id']]);
+        if (!$special_info) Json::fail('直播间不存在');
+        if ($special_info['admin_id'] == $parm['admin_id']) return Json::successful('转移成功');
+        $special_info->save(['admin_id' => $parm['admin_id']]);
+        return Json::successful('转移成功');
+    }
+
+    /**
+     * 新增直播任务
+     * @param int $live_id
+     */
+    public function set_task($live_id = 0)
+    {
+        if (!$live_id) return Json::fail('缺少直播id');
+        $data = parent::postMore([
+            ['coures_id', ''],
+            ['title', ''],
+            ['image', ''],
+            ['sort', 0],
+            ['is_show', 1],
+            ['special_id',0]
+        ]);
+        if (!$data['special_id']) return Json::fail('关联专题Id缺失');
+        if (!$data['title']) return Json::fail('请输入任务标题!');
+        if (!$data['image']) return Json::fail('请上传图片');
+        $data['add_time'] = time();
+        $data['live_id'] = $live_id;
+        $special_id = LiveStudio::where('id', $live_id)->value('special_id');
+        $data['is_pay'] = SpecialModel::where(['type' => SPECIAL_LIVE, 'id' => $special_id])->value('pay_type');
+        if (SpecialTask::set($data))
+            return Json::successful('保存成功');
+        else
+            return Json::fail('保存失败');
+    }
+
+    /**直播推荐(课程)
+     * @return mixed
+     */
+    public function live_goods()
+    {
+        $live_id = $this->request->get('live_id',0);
+        $this->assign('live_id', $live_id);
+        return $this->fetch();
+    }
+    /**直播推荐列表数据
+     * @return mixed
+     */
+    public function live_goods_list($live_id = false)
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['live_id', 0],
+            ['store_name', ""],
+            ['limit', 20],
+            ['order', ''],
+            ['is_show', ''],
+        ]);
+        if ($live_id) $where['live_id'] = $live_id;
+        return Json::successlayui(LiveGoods::getLiveGoodsList($where));
+    }
+    /**直播推荐(商品)
+     * @return mixed
+     */
+    public function live_store()
+    {
+        $live_id = $this->request->get('live_id',0);
+        $this->assign('live_id', $live_id);
+        return $this->fetch();
+    }
+    /**直播推荐列表数据
+     * @return mixed
+     */
+    public function live_store_list($live_id = false)
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['live_id', 0],
+            ['store_name', ""],
+            ['limit', 20],
+            ['order', ''],
+            ['is_show', ''],
+        ]);
+        if ($live_id) $where['live_id'] = $live_id;
+        return Json::successlayui(LiveGoods::getLiveStoreProductList($where));
+    }
+    /**直播打赏
+     * @return mixed
+     */
+    public function live_reward()
+    {
+        $gold_info = SystemConfigService::more(['gold_name','gold_image']);
+        $role_sign = get_login_role();
+        $where['l.is_del'] = 0;
+        if (isset($role_sign['role_sign']) && $role_sign['role_sign'] == "anchor") {
+            $admin_id = get_login_id()['admin_id'];
+            $where['s.admin_id'] = $admin_id;
+        }
+        $live_studio = LiveStudio::alias('l')->where($where)->join('__SPECIAL__ s','l.special_id = s.id')->field('l.id,l.live_title')->select();
+        $live_studio = $live_studio ? $live_studio->toArray() : [];
+        $this->assign("year",getMonth('y'));
+        $this->assign("live_studio",json_encode($live_studio));
+        $this->assign("gold_info",$gold_info);
+        return $this->fetch();
+    }
+
+    /**礼物管理
+     * @return mixed
+     */
+    public function live_gift()
+    {
+        $list=LiveGift::liveGiftList();
+        $this->assign("list",$list);
+        return $this->fetch();
+    }
+
+    /**添加礼物
+     * @return mixed
+     * @throws \FormBuilder\exception\FormBuilderException
+     * @throws \think\exception\DbException
+     */
+    public function create($id=0)
+    {
+        if ($id) $gift = LiveGift::get($id);
+        $form = Form::create(Url::build('save',['id'=>$id]), [
+            Form::input('live_gift_name', '礼物名称', isset($gift) ? $gift->live_gift_name : ''),
+            Form::number('live_gift_price', '礼物价格(虚拟货币)', isset($gift) ? $gift->live_gift_price : ''),
+            Form::checkbox('live_gift_num', '赠送数量列表', isset($gift) ? json_decode($gift->live_gift_num) : [])->options([
+                ['label' => '1', 'value' => 1],
+                ['label' => '5', 'value' => 5],
+                ['label' => '10', 'value' => 10],
+                ['label' => '20', 'value' => 20],
+                ['label' => '66', 'value' => 66],
+                ['label' => '99', 'value' => 99],
+                ['label' => '520', 'value' => 520],
+                ['label' => '999', 'value' => 999],
+                ['label' => '1314', 'value' => 1314]
+            ]),
+            Form::frameImageOne('live_gift_show_img', '图标(100*100px)', Url::build('admin/widget.images/index', array('fodder' => 'live_gift_show_img')), isset($gift) ? $gift->live_gift_show_img : '')->icon('image')->width('70%')->height('500px'),
+            Form::number('sort', '排序', isset($gift) ? $gift->sort : 0),
+            Form::radio('is_show', '状态',isset($gift) ? $gift->is_show : 1)->options([['label' => '显示', 'value' => 1], ['label' => '隐藏', 'value' => 0]])
+        ]);
+        $form->setMethod('post')->setTitle($id ? '修改礼物':'添加礼物')->setSuccessScript('parent.layer.close(parent.layer.getFrameIndex(window.name));parent.$(".J_iframe:visible")[0].contentWindow.location.reload()');
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 保存数据
+     */
+    public function save($id)
+    {
+        $post = parent::postMore([
+            ['live_gift_name', ''],
+            ['live_gift_price', 0],
+            ['live_gift_num', []],
+            ['live_gift_show_img', ''],
+            ['is_show', 1],
+            ['sort', 0],
+        ]);
+        if (!$post['live_gift_name']) return Json::fail('请输入礼物名称');
+        if (bcsub($post['live_gift_price'],0,0)<=0) return Json::fail('请输入礼物价格');
+        if (count($post['live_gift_num'])<1) return Json::fail('请选择赠送数量列表');
+        if (!$post['live_gift_show_img']) return Json::fail('请选择礼物图标');
+        $post['live_gift_num']=json_encode($post['live_gift_num']);
+        $post['add_time']=time();
+        if(!$id){
+            $res=LiveGift::set($post);
+            if ($res) {
+                return Json::successful('添加成功');
+            }else {
+                return Json::fail('添加失败');
+            }
+        }else{
+            $res=LiveGift::edit($post,$id);
+            if ($res) {
+                return Json::successful('修改成功');
+            }else {
+                return Json::fail('修改失败');
+            }
+        }
+    }
+    /**礼物是否显示快捷操作
+     * @param string $is_show
+     * @param string $id
+     * @return mixed
+     */
+    public function set_gift_show($is_show = '', $id = '')
+    {
+        ($is_show == '' || $id == '') && Json::fail('缺少参数');
+        $res = LiveGift::where(['id' => $id])->update(['is_show' => (int)$is_show]);
+        if ($res) {
+            return Json::successful($is_show == 1 ? '显示成功' : '隐藏成功');
+        } else {
+            return Json::fail($is_show == 1 ? '显示失败' : '隐藏失败');
+        }
+    }
+    /**
+     * 直播礼物列表
+     */
+    public function live_gift_list()
+    {
+        return Json::successlayui(LiveGift::liveGiftList());
+    }
+
+    /**直播礼物
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function liveGiftList()
+    {
+        $data=LiveGift::order('sort ASC')->select();
+        return Json::successful($data);
+    }
+    /**直播推荐列表数据
+     * @return mixed
+     */
+    public function live_reward_list()
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['user_info', ""],
+            ['limit', 20],
+            ['order', ''],
+            ['live_id', 0],
+            ['gift_id', 0],
+            ['date', 0],
+        ]);
+        //根据账号身份获取各自的列表数据
+        $role_sign = get_login_role();
+        if (isset($role_sign['role_sign']) && $role_sign['role_sign'] == "anchor") {
+            $where['admin_id'] = get_login_id()['admin_id'];
+        }
+        return Json::successlayui(LiveReward::getLiveRewardList($where));
+    }
+    /**
+     * 获取头部订单金额等信息
+     * return json
+     *
+     */
+    public function getBadge()
+    {
+        $where = parent::postMore([
+            ['page', 1],
+            ['user_info', ""],
+            ['limit', 20],
+            ['order', ''],
+            ['live_id', 0],
+            ['gift_id', 0],
+            ['date', 0],
+        ]);
+        return Json::successful(LiveReward::getBadge($where));
+    }
+
+}

File diff suppressed because it is too large
+ 0 - 0
application/admin/controller/order/StoreOrder.php


+ 241 - 0
application/admin/controller/setting/SystemAdmin.php

@@ -0,0 +1,241 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\setting;
+
+use app\admin\controller\AuthController;
+use app\wap\model\user\User;
+use service\FormBuilder as Form;
+use service\JsonService as Json;
+use think\Request;
+use app\admin\model\system\SystemRole;
+use think\Url;
+use app\admin\model\system\SystemAdmin as AdminModel;
+
+/**
+ * 管理员列表控制器
+ * Class SystemAdmin
+ * @package app\admin\controller\system
+ */
+class SystemAdmin extends AuthController
+{
+
+    /**
+     * 显示资源列表
+     *
+     * @return \think\Response
+     */
+    public function index()
+    {
+        $admin = $this->adminInfo;
+        $where = parent::getMore([
+            ['name', ''],
+            ['roles', ''],
+            ['level', bcadd($admin->level, 1, 0)]
+        ], $this->request);
+        $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::input('phone', '前端登录手机号')->type('phone');
+        $f[] = Form::radio('status', '状态', 1)->options([['label' => '开启', 'value' => 1], ['label' => '关闭', 'value' => 0]]);
+        $form = Form::make_post_form('添加管理员', $f, Url::build('save'));
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 保存新建的资源
+     *
+     * @param  \think\Request $request
+     * @return \think\Response
+     */
+    public function save(Request $request)
+    {
+        $data = parent::postMore([
+            'account',
+            'conf_pwd',
+            'pwd',
+            'real_name',
+            'phone',
+            ['roles', []],
+            ['status', 0]
+        ], $request);
+        if (!$data['account']) return Json::fail('请输入管理员账号');
+        if (!$data['roles']) return Json::fail('请选择至少一个管理员身份');
+        foreach ($data['roles'] as $v) {
+            $role = SystemRole::where('id',$v)->find();
+            if ($role && $role['sign'] == 'verification') {
+                if (!$data['phone']) return Json::fail('请填写前端登录电话');
+                $user = User::where('phone',$data['phone'])->find();
+                if (!$user) 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('管理员账号已存在');
+        $data['pwd'] = md5($data['pwd']);
+        unset($data['conf_pwd']);
+        $data['level'] = $this->adminInfo['level'] + 1;
+        AdminModel::set($data);
+        return Json::successful('添加管理员成功!');
+    }
+
+    /**
+     * 显示编辑资源表单页.
+     *
+     * @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::input('phone', '前端登录手机号', $admin->phone)->type('phone');
+        $f[] = Form::radio('status', '状态', 1)->options([['label' => '开启', 'value' => 1], ['label' => '关闭', 'value' => 0]]);
+        $form = Form::make_post_form('编辑管理员', $f, Url::build('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(Request $request, $id)
+    {
+        $data = parent::postMore([
+            'account',
+            'conf_pwd',
+            'pwd',
+            'real_name',
+            'phone',
+            ['roles', []],
+            ['status', 0]
+        ], $request);
+        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('两次输入密码不想同');
+            $data['pwd'] = md5($data['pwd']);
+        }
+        foreach ($data['roles'] as $v) {
+            $role = SystemRole::where('id',$v)->find();
+            if ($role && $role['sign'] == 'verification') {
+                if (!$data['phone']) return Json::fail('请填写前端登录电话');
+                $user = User::where('phone',$data['phone'])->find();
+                if (!$user) return Json::fail('请至前端-个人中心-点击头像补充个人资料');
+            }
+        }
+        if (AdminModel::where('account', $data['account'])->where('id', '<>', $id)->count()) return Json::fail('管理员账号已存在');
+        unset($data['conf_pwd']);
+        AdminModel::edit($data, $id);
+        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('删除失败!');
+    }
+
+    /**
+     * 个人资料 展示
+     * */
+    public function adminInfo()
+    {
+        $adminInfo = $this->adminInfo;//获取当前登录的管理员
+        $this->assign('adminInfo', $adminInfo);
+        return $this->fetch('admininfo');
+    }
+
+    public function setAdminInfo(Request $request)
+    {
+        $adminInfo = $this->adminInfo;//获取当前登录的管理员
+        if ($request->isPost()) {
+            $data = parent::postMore([
+                ['new_pwd', ''],
+                ['new_pwd_ok', ''],
+                ['pwd', ''],
+                'real_name',
+            ], $request);
+            if ($data['pwd'] != '') {
+                $pwd = md5($data['pwd']);
+                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'] != '') {
+                $data['pwd'] = md5($data['new_pwd']);
+            } else {
+                unset($data['pwd']);
+            }
+            unset($data['new_pwd']);
+            unset($data['new_pwd_ok']);
+            AdminModel::edit($data, $adminInfo['id']);
+            return Json::successful('修改成功!,请重新登录');
+        }
+    }
+}

+ 334 - 0
application/admin/controller/setting/SystemBroadcast.php

@@ -0,0 +1,334 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+
+namespace app\admin\controller\setting;
+
+use service\JsonService as Json;
+use service\FormBuilder as Form;
+use think\Request;
+use think\Url;
+use app\admin\controller\AuthController;
+use service\AlipayDisposeService;
+use app\admin\model\system\SystemBucket as SystemBucketModel;
+use app\admin\model\system\SystemBroadcast as SystemBroadcastModel;
+use service\SystemConfigService;
+/**
+ * Class SystemBroadcast
+ * @package app\admin\controller\setting
+ */
+class SystemBroadcast extends AuthController
+{
+
+    protected static $endpoint =[
+        '华北2(北京)'=>'cn-beijing',
+        '华东2(上海)'=>'cn-shanghai',
+        '华南1(深圳)'=>'cn-shenzhen',
+        '华北1(青岛)'=>'cn-qingdao',
+        '亚太东南1(新加坡)'=>'ap-southeast-1',
+        '德国'=>'eu-central-1',
+        '亚太东北1(东京)'=>'ap-northeast-1',
+        '印度(孟买)'=>'ap-south-1',
+        '印度尼西亚(雅加达)'=>'ap-southeast-5',
+    ];
+    /**
+     * 视频直播配置页面
+     * @return \think\Response
+     */
+    public function index()
+    {
+        $this->assign(['list'=>SystemBroadcastModel::broadcastList()]);
+        return $this->fetch();
+    }
+
+
+    /**
+     * 添加视频直播域名
+     */
+    public function create()
+    {
+        $endpoint=self::$endpoint;
+        $this->assign(['endpoint'=>json_encode($endpoint)]);
+        return $this->fetch();
+    }
+
+    /**
+     *播流域名添加推流域名
+     */
+    public function addStreaming($id=0)
+    {
+        if(!$id) return $this->failed('参数有误');
+        $domain=SystemBroadcastModel::where('is_del',0)->where('live_domain_type','liveVideo')->where('id',$id)->find();
+        if(!$domain) return $this->failed('域名不存在或不是播流域名');
+        $region=$domain['region'];
+        $list = SystemBroadcastModel::where('is_del',0)->where('region',$region)->where('live_domain_type','liveEdge')->select();
+        if(count($list)<1) return $this->failed('请先添加推流域名');
+        $form = Form::create(Url::build('streamingSave',['id'=>$id]), [
+            Form::select('push_flow', '添加推流域名')->setOptions(function () use($list) {
+                $menus=[];
+                foreach ($list as $menu) {
+                    $menus[] = ['value' => $menu['domain_name'], 'label' => $menu['domain_name']];
+                }
+                return $menus;
+            })->filterable(1),
+        ]);
+        $form->setMethod('post')->setTitle('播流域名配置')->setSuccessScript('parent.layer.close(parent.layer.getFrameIndex(window.name));parent.$(".J_iframe:visible")[0].contentWindow.location.reload();');
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 保存数据
+     */
+    public function streamingSave($id=0)
+    {
+        $data = parent::postMore([
+            ['push_flow', ''],
+        ]);
+        if (!$data['push_flow']) return Json::fail('请选择推流域名');
+        if(!$id) return Json::fail('参数有误');
+        $pushFlow=SystemBroadcastModel::where('is_del',0)->where('live_domain_type','liveEdge')->where('domain_name',$data['push_flow'])->find();
+        if(!$pushFlow) return Json::fail('推流域名不存在或不是推流域名');
+        $domain=SystemBroadcastModel::where('is_del',0)->where('live_domain_type','liveVideo')->where('id',$id)->find();
+        if(!$domain) return Json::fail('域名不存在或不是播流域名');
+        $describe=AlipayDisposeService::describeLiveStreamsNotifyUrlConfig($pushFlow['domain_name'],$pushFlow['region']);
+        if(!$describe['LiveStreamsNotifyConfig']['NotifyUrl']){
+            $res2=AlipayDisposeService::setLiveStreamsNotifyUrlConfigs($pushFlow['domain_name'],$pushFlow['region']);
+            if(!$res2) return Json::fail('请设置推流域名回调地址!');
+        }
+        if(SystemBroadcastModel::be(['is_del'=>0,'live_domain_type'=>'liveVideo','push_domain'=>$data['push_flow']])) return Json::fail('该推流域名已绑定!');
+        $res=AlipayDisposeService::addLiveDomainMappings($domain['domain_name'],$data['push_flow'],$domain['region']);
+        if($res){
+            SystemBroadcastModel::where('is_del',0)->where('live_domain_type','liveVideo')->where('id',$id)->update(['push_domain'=>$data['push_flow']]);
+            return Json::successful('添加成功!');
+        }else{
+            return Json::fail('添加失败!');
+        }
+    }
+
+    /**
+     * 删除推流域名
+     */
+    public function delStreaming($id=0)
+    {
+        if(!$id) return Json::fail('参数有误');
+        $domain=SystemBroadcastModel::where('is_del',0)->where('live_domain_type','liveVideo')->where('id',$id)->find();
+        if(!$domain) return Json::fail('域名不存在或不是播流域名');
+        $res=AlipayDisposeService::deleteLiveDomainMappings($domain['domain_name'],$domain['push_domain'],$domain['region']);
+        if($res){
+            SystemBroadcastModel::where('is_del',0)->where('live_domain_type','liveVideo')->where('id',$id)->update(['push_domain'=>'']);
+            return Json::successful('删除成功!');
+        }else{
+            return Json::fail('删除失败!');
+        }
+    }
+    /**
+     *播流域名的录制配置
+     */
+    public function toConfigure($id=0)
+    {
+        if(!$id) return $this->failed('参数有误');
+        $domain=SystemBroadcastModel::where('is_del',0)->where('live_domain_type','liveVideo')->where('id',$id)->find();
+        $region='oss-'.$domain['region'].'.aliyuncs.com';
+        $list = SystemBucketModel::where(['is_del'=>0,'is_use'=>0])->where('endpoint',$region)->select();
+        if(count($list)<1) return $this->failed('请先添加对象存储oss');
+        $form = Form::create(Url::build('toConfigureSave',['id'=>$id]), [
+            Form::radio('format', '存储格式','m3u8')->options([['label' => 'm3u8', 'value' => 'm3u8'], ['label' => 'flv', 'value' => 'flv'], ['label' => 'mp4', 'value' => 'mp4']]),
+            Form::number('duration', '录制周期(分)',30),
+            Form::select('OssBucketId', 'OssBucket名称')->setOptions(function () use($list) {
+                $menus=[];
+                foreach ($list as $menu) {
+                    $menus[] = ['value' => $menu['id'], 'label' => $menu['bucket_name']];
+                }
+                return $menus;
+            })->filterable(1),
+        ]);
+        $form->setMethod('post')->setTitle('录制配置')->setSuccessScript('parent.layer.close(parent.layer.getFrameIndex(window.name));parent.$(".J_iframe:visible")[0].contentWindow.location.reload();');
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 保存
+     */
+    public function toConfigureSave($id=0)
+    {
+        $data = parent::postMore([
+            ['format', 'm3u8'],
+            ['duration', 30],
+            ['OssBucketId', 0],
+        ]);
+        if (!$data['OssBucketId']) return Json::fail('请选择oss桶');
+        if (!$data['duration']) return Json::fail('请输入录制周期(分)');
+        if(!$id) return Json::fail('参数有误');
+        $domain=SystemBroadcastModel::where('is_del',0)->where('live_domain_type','liveVideo')->where('id',$id)->find();
+        if(!$domain)return Json::fail('播流域名不存在');
+        $bucket=SystemBucketModel::where('is_del',0)->where('id',$data['OssBucketId'])->find();
+        if(!$bucket)return Json::fail('储存空间不存在');
+        $res=AlipayDisposeService::addLiveAppRecordConfigs($domain['domain_name'],$domain['region'],'*','*',$bucket['bucket_name'],$bucket['endpoint'],$data['format'],$data['duration']);
+        if($res){
+            SystemBucketModel::where('is_del',0)->where('id',$data['OssBucketId'])->update(['is_use'=>2]);
+            SystemBroadcastModel::where('is_del',0)->where('live_domain_type','liveVideo')->where('id',$id)->update(['bucket_name'=>$bucket['bucket_name']]);
+            return Json::successful('录制配置设置成功!');
+        }else{
+            return Json::fail('录制配置设置失败!');
+        }
+    }
+
+    /**
+     * 删除录制配置
+     */
+    public function delLiveAppRecordConfig($id=0)
+    {
+        if(!$id) return Json::fail('参数有误!');
+        $domain=SystemBroadcastModel::where('is_del',0)->where('live_domain_type','liveVideo')->where('id',$id)->find();
+        if(!$domain) return Json::fail('域名不存在!');
+        $res=AlipayDisposeService::deleteLiveAppRecordConfigs($domain['domain_name'],$domain['region'],'*','*');
+        if($res){
+            SystemBucketModel::where('is_del',0)->where('bucket_name',$domain['bucket_name'])->update(['is_use'=>0]);
+            SystemBroadcastModel::where('is_del',0)->where('live_domain_type','liveVideo')->where('id',$id)->update(['bucket_name'=>'']);
+            return Json::successful('录制配置设置成功!');
+        }else{
+            return Json::fail('录制配置设置失败!');
+        }
+    }
+    /**
+     * 保存视频直播域名
+     */
+    public function save()
+    {
+        $data = parent::postMore([
+            ['domain_name', ''],
+            ['region', ''],
+            ['live_domain_type', 'liveVideo'],
+            ['scope', 'domestic'],
+        ]);
+        if (!$data['domain_name']) return Json::fail('请输入直播域名');
+        if(mb_substr($data['domain_name'],0,1,'utf-8')=='*') return Json::fail('暂不支持添加泛域名');
+        if(SystemBroadcastModel::be(['domain_name'=>$data['domain_name'],'is_del'=>0])) return Json::fail('域名已存在!');
+        $res=AlipayDisposeService::addLiveDomain($data);
+        if($res){
+            $res1=AlipayDisposeService::describeLiveDomainDetails($data['domain_name'],$data['region']);
+            $res2=true;
+            if($data['live_domain_type']=='liveEdge'){
+                $res2=AlipayDisposeService::setLiveStreamsNotifyUrlConfigs($data['domain_name'],$data['region']);
+            }
+            $auth_key=SystemBroadcastModel::auth_key($data['domain_name'],$data['region']);
+            $res3=true;
+            if($data['live_domain_type']=='liveVideo'){
+                $res3=AlipayDisposeService::batchSetLiveDomainConfigs($data['domain_name'],$data['region']);
+            }
+            if($res1 && $res2 && $res3 && $auth_key && SystemBroadcastModel::addBroadcast($data,$res1,$auth_key)){
+                return Json::successful('添加直播域名成功!');
+            }else{
+                return Json::fail('添加到数据库失败或添加直播域名失败!');
+            }
+        }else{
+            return Json::fail('添加直播域名失败!');
+        }
+    }
+    /**
+     * 删除推流回调地址
+     */
+    public function delNotifUrl($id=0)
+    {
+        if(!$id) return Json::fail('参数有误!');
+        $broadcast=SystemBroadcastModel::where('id',$id)->where('is_del',0)->find();
+        if (!$broadcast) return Json::fail('直播域名不存在!');
+        $res=AlipayDisposeService::deleteLiveStreamsNotifyUrlConfigs($broadcast['domain_name'],$broadcast['region']);
+        if($res){
+            return Json::successful('删除推流回调地址成功!');
+        }else{
+            return Json::fail('删除推流回调地址失败!');
+        }
+    }
+    /**
+     * 删除视频直播域名
+     */
+    public function delete($id=0)
+    {
+        if (!$id) return Json::fail('参数错误');
+        $broadcast=SystemBroadcastModel::where('id',$id)->where('is_del',0)->find();
+        if(!$broadcast) return Json::fail('删除直播域名不存在');
+        $res=AlipayDisposeService::deleteLiveDomains($broadcast['domain_name'],$broadcast['region']);
+        if($res){
+            SystemBroadcastModel::where('id',$id)->update(['is_del'=>1]);
+            return Json::successful('删除视频直播域名成功');
+        }else{
+            return Json::fail('删除视频直播域名失败');
+        }
+    }
+
+    /**停用域名
+     * @param int $id
+     */
+    public function offlines($id=0)
+    {
+        if (!$id) return Json::fail('参数错误');
+        $broadcast=SystemBroadcastModel::where('id',$id)->where('is_del',0)->find();
+        if(!$broadcast) return Json::fail('停用域名不存在');
+        $res=AlipayDisposeService::stopLiveDomains($broadcast['domain_name'],$broadcast['region']);
+        if($res){
+            SystemBroadcastModel::where('id',$id)->update(['domain_status'=>'offline']);
+            return Json::successful('停用域名成功');
+        }else{
+            return Json::fail('停用域名失败');
+        }
+    }
+
+    /**启用域名
+     * @param int $id
+     */
+    public function onlines($id=0)
+    {
+        if (!$id) return Json::fail('参数错误');
+        $broadcast=SystemBroadcastModel::where('id',$id)->where('is_del',0)->find();
+        if(!$broadcast) return Json::fail('启用不存在');
+        $res=AlipayDisposeService::startLiveDomains($broadcast['domain_name'],$broadcast['region']);
+        if($res){
+            SystemBroadcastModel::where('id',$id)->update(['domain_status'=>'online']);
+            return Json::successful('启用域名成功');
+        }else{
+            return Json::fail('启用域名失败');
+        }
+    }
+
+    /**使用直播域名
+     * @param int $id
+     */
+    public function userLiveUse($id=0)
+    {
+        if (!$id) return Json::fail('参数错误');
+        $broadcast=SystemBroadcastModel::where('id',$id)->where('live_domain_type','liveVideo')->where('domain_status','online')->where('is_del',0)->find();
+        if(!$broadcast) return Json::fail('域名不存在或不是播流域名');
+        if(!$broadcast['push_domain']) return Json::fail('请绑定推流域名');
+        $push_domain=SystemBroadcastModel::where('domain_name',$broadcast['push_domain'])->where('live_domain_type','liveEdge')->where('domain_status','online')->where('is_del',0)->find();
+        if(!$push_domain) return Json::fail('绑定的推流域名不存在');
+        $bucket=SystemBucketModel::where('is_del',0)->where('bucket_name',$broadcast['bucket_name'])->find();
+        if(!$bucket) return Json::fail('储存oss桶不存在');
+        $res=SystemConfigService::setOneValue('aliyun_live_rtmpLink',$broadcast['push_domain']);
+        $res1=SystemConfigService::setOneValue('aliyun_live_playLike',$broadcast['domain_name']);
+        $res2=SystemConfigService::setOneValue('aliyun_live_push_key',$push_domain['auth_key1']);
+        $res3=SystemConfigService::setOneValue('aliyun_live_play_key',$broadcast['auth_key1']);
+        $res4=SystemConfigService::setOneValue('aliyun_live_appName','zsffLive');
+        $res5=SystemConfigService::setOneValue('aliyun_live_oss_bucket',$broadcast['bucket_name']);
+        $res6=SystemConfigService::setOneValue('aliyun_live_end_point',$bucket['endpoint']);
+        if($res && $res1 && $res2 && $res3 && $res4 && $res5 && $res6){
+            SystemBucketModel::where('is_use',2)->where('is_del',0)->update(['is_use'=>0]);
+            SystemBucketModel::where('id',$id)->where('is_del',0)->update(['is_use'=>2]);
+            SystemBroadcastModel::where('id',$id)->where('live_domain_type','liveVideo')->where('domain_status','online')->where('is_del',0)->update(['is_use'=>1]);
+            SystemBroadcastModel::where('domain_name',$broadcast['push_domain'])->where('live_domain_type','liveEdge')->where('domain_status','online')->where('is_del',0)->update(['is_use'=>1]);
+            return Json::successful('设置直播域名成功');
+        }else{
+            return Json::fail('设置直播域名失败');
+        }
+    }
+}

+ 166 - 0
application/admin/controller/setting/SystemBucket.php

@@ -0,0 +1,166 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+
+namespace app\admin\controller\setting;
+
+use service\JsonService as Json;
+use think\Request;
+use think\Url;
+use app\admin\controller\AuthController;
+use service\AlipayDisposeService;
+use app\admin\model\system\SystemBucket as SystemBucketModel;
+use service\SystemConfigService;
+/**
+ * Class SystemBucket
+ * @package app\admin\controller\setting
+ */
+class SystemBucket extends AuthController
+{
+
+    protected static $endpoint =[
+        '华东1(杭州)'=>'oss-cn-hangzhou.aliyuncs.com',
+        '华东2(上海)'=>'oss-cn-shanghai.aliyuncs.com',
+        '华北1(青岛)'=>'oss-cn-qingdao.aliyuncs.com',
+        '华北2(北京)'=>'oss-cn-beijing.aliyuncs.com',
+        '华北3(张家口)'=>'oss-cn-zhangjiakou.aliyuncs.com',
+        '华北5(呼和浩特)'=>'oss-cn-huhehaote.aliyuncs.com',
+        '华北6(乌兰察布)'=>'oss-cn-wulanchabu.aliyuncs.com',
+        '华南1(深圳)'=>'oss-cn-shenzhen.aliyuncs.com',
+        '华南2(河源)'=>'oss-cn-heyuan.aliyuncs.com',
+        '华南3(广州)'=>'oss-cn-guangzhou.aliyuncs.com',
+        '西南1(成都)'=>'oss-cn-chengdu.aliyuncs.com',
+        '中国(香港)'=>'oss-cn-hongkong.aliyuncs.com',
+        '新加坡'=>'oss-ap-southeast-1.aliyuncs.com',
+        '澳大利亚(悉尼)'=>'oss-ap-southeast-2.aliyuncs.com',
+        '马来西亚(吉隆坡)'=>'oss-ap-southeast-3.aliyuncs.com',
+        '印度尼西亚(雅加达)'=>'oss-ap-southeast-5.aliyuncs.com',
+        '日本(东京)'=>'oss-ap-northeast-1.aliyuncs.com',
+        '印度(孟买)'=>'oss-ap-south-1.aliyuncs.com',
+        '德国(法兰克福)'=>'oss-eu-central-1.aliyuncs.com',
+        '英国(伦敦)'=>'oss-eu-west-1.aliyuncs.com',
+        '美国(硅谷)'=>'oss-us-west-1.aliyuncs.com',
+        '美国(佛吉尼亚)'=>'oss-us-east-1.aliyuncs.com',
+        '阿联酋(迪拜)'=>'oss-me-east-1.aliyuncs.com',
+    ];
+    /**
+     * 对象存储OSS配置页面
+     * @return \think\Response
+     */
+    public function index()
+    {
+        $endpoint=self::$endpoint;
+        $where = parent::getMore([
+            ['endpoint', ''],
+            ['types', 1],
+        ], $this->request);
+        $this->assign(['list'=>SystemBucketModel::bucKetList($where),'endpoint'=>$endpoint,'where'=>$where]);
+        return $this->fetch();
+    }
+
+    /**
+     * 拉取储存空间
+     */
+    public function pullBucket()
+    {
+        $endpoint=self::$endpoint;
+        foreach ($endpoint as $key=>$value){
+            $list=AlipayDisposeService::ossBucketList($value);
+            if(count($list)>0){
+                SystemBucketModel::addListBucket($list);
+            }
+        }
+        return Json::successful('ok');
+    }
+
+    /**
+     * 添加存储空间
+     */
+    public function create()
+    {
+        $endpoint=self::$endpoint;
+        $this->assign(['endpoint'=>json_encode($endpoint)]);
+        return $this->fetch();
+    }
+
+    /**
+     * 添加存储空间
+     */
+    public function save()
+    {
+        $data = parent::postMore([
+            ['bucket_name', ''],
+            ['endpoint', ''],
+            ['type', 1],
+            ['jurisdiction', 1],
+        ]);
+        if (!$data['bucket_name']) return Json::fail('请输入存储空间名称');
+        if(AlipayDisposeService::doesBucketExist($data['endpoint'],$data['bucket_name'])){
+            return Json::fail('存储空间已存在');
+        }
+        $res=AlipayDisposeService::ossDispose($data['endpoint'],$data['bucket_name'],$data['jurisdiction'],$data['type']);
+        if($res){
+            $res1=AlipayDisposeService::putBucketCors($data['endpoint'],$data['bucket_name']);
+            if($res1 && SystemBucketModel::addBucket($data)){
+                return Json::successful('添加存储空间成功!');
+            }else{
+                return Json::fail('添加到数据库失败或设置跨域规则失败!');
+            }
+        }else{
+            return Json::fail('添加存储空间失败!');
+        }
+    }
+
+    /**
+     * 删除存储空间
+     */
+    public function delete($id=0)
+    {
+        if (!$id) return Json::fail('参数错误');
+        $bucket=SystemBucketModel::where('id',$id)->where('is_del',0)->find();
+        if(!$bucket) return Json::fail('删除存储空间不存在');
+        $res=AlipayDisposeService::deleteBucket($bucket['endpoint'],$bucket['bucket_name']);
+        if($res){
+            SystemBucketModel::where('id',$id)->update(['is_del'=>1]);
+            return Json::successful('删除存储空间成功');
+        }else{
+            return Json::fail('删除存储空间失败');
+        }
+    }
+
+    /**使用储存空间
+     * @param int $id
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function userUse($id=0)
+    {
+        if (!$id) return Json::fail('参数错误');
+        $bucket=SystemBucketModel::where('id',$id)->where('is_del',0)->find();
+        if(!$bucket) return Json::fail('存储空间不存在');
+        $res=SystemConfigService::setOneValue('uploadUrl',$bucket['domain_name']);
+        $res1=SystemConfigService::setOneValue('OssBucket',$bucket['bucket_name']);
+        $res2=SystemConfigService::setOneValue('end_point',$bucket['endpoint']);
+        if($res && $res1 && $res2){
+            SystemBucketModel::where('is_use',1)->where('is_del',0)->update(['is_use'=>0]);
+            SystemBucketModel::where('id',$id)->where('is_del',0)->update(['is_use'=>1]);
+            return Json::successful('设置存储空间成功');
+        }else{
+            return Json::fail('设置存储空间失败');
+        }
+    }
+    public function crossDomainRules()
+    {
+        $res=AlipayDisposeService::addLiveDomain('oss-cn-shanghai.aliyuncs.com','123456789ldw');
+    }
+
+}

+ 468 - 0
application/admin/controller/setting/SystemConfig.php

@@ -0,0 +1,468 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\setting;
+
+use think\Url;
+use service\FormBuilder as Form;
+use think\Request;
+use service\JsonService as Json;
+use service\UploadService as Upload;
+use app\admin\controller\AuthController;
+use app\admin\model\system\SystemConfig as ConfigModel;
+
+/**
+ *  配置列表控制器
+ * Class SystemConfig
+ * @package app\admin\controller\system
+ */
+class SystemConfig extends AuthController
+{
+    /**
+     * 基础配置
+     * */
+    public function index()
+    {
+        list($type, $pid, $tab_id, $children_tab_id) = parent::getMore([
+            ['type', $this->request->param('type',0)],//配置类型
+            ['paid', 0],//父级分类ID
+            ['tab_id', $this->request->param('tab_id',0)],//当前分类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);
+        }
+        if ($pid) {
+            $children_config_tab = ConfigModel::getConfigChildrenTabAll($pid);
+            foreach ($children_config_tab as $kk => $vv) {
+                $arr = ConfigModel::getAll($vv['id'])->toArray();
+                if (empty($arr)) {
+                    unset($children_config_tab[$kk]);
+                }
+            }
+            $tab_id = $pid;
+            //表单字段
+            $list = ConfigModel::getAll($children_tab_id);
+        } else {
+            $children_config_tab = ConfigModel::getConfigChildrenTabAll($tab_id);
+            foreach ($children_config_tab as $kk => $vv) {
+                $arr = ConfigModel::getAll($vv['id'])->toArray();
+                if (empty($arr)) {
+                    unset($children_config_tab[$kk]);
+                }
+            }
+            if (!$children_tab_id && $children_config_tab) $children_tab_id = $children_config_tab[0]['id'];
+            //表单字段
+            $list = ConfigModel::getAll($tab_id);
+        }
+        $this->assign('pid', $pid);
+        $this->assign('children_tab_id', $children_tab_id);
+        $this->assign('tab_id', $tab_id);
+        $this->assign('config_tab', $config_tab);
+        $this->assign('children_config_tab', $children_config_tab);
+        $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) {
+                            if(strstr($v,'=>') !== false){
+                                $pdata = explode("=>", $v);
+                            }else if(strstr($v,'=') !== false){
+                                $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::build('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::build('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::build('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) {
+                            if(strstr($v,'=>') !== false){
+                                $pdata = explode("=>", $v);
+                            }else if(strstr($v,'=') !== false){
+                                $pdata = explode("=", $v);
+                            }
+                            $options[] = ['label' => $pdata[1], 'value' => $pdata[0]];
+                        }
+                        if (!is_array($data['value'])) {
+                            $value = [$data['value']];
+                        }else{
+                            $value = $data['value'];
+                        }
+                        $formbuider[] = Form::checkbox($data['menu_name'], $data['info'], $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) {
+                            if(strstr($v,'=>') !== false){
+                                $pdata = explode("=>", $v);
+                            }else if(strstr($v,'=') !== false){
+                                $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;
+            }
+        }
+        $form = Form::make_post_form('编辑配置', $formbuider, Url::build('save_basics'));
+        $this->assign(compact('form'));
+        $this->assign('list', $list);
+        return $this->fetch();
+    }
+
+    /**
+     * 添加字段
+     * */
+    public function create(Request $request)
+    {
+        $data = parent::getMore(['type'], $request);//接收参数
+        $tab_id = $request->param('tab_id', 1);
+        $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;
+        }
+        $form = Form::make_post_form('添加字段', $formbuider, Url::build('save'));
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 保存字段
+     * */
+    public function save(Request $request)
+    {
+        $data = parent::postMore([
+            'menu_name',
+            'type',
+            'config_tab_id',
+            'parameter',
+            'upload_type',
+            'required',
+            'width',
+            'high',
+            'value',
+            'info',
+            'desc',
+            'sort',
+            'status',], $request);
+        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());
+        }
+        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::set($data);
+        return Json::successful('添加菜单成功!');
+    }
+
+    /**
+     * @param Request $request
+     * @param $id
+     * @return \think\response\Json
+     */
+    public function update_config(Request $request, $id)
+    {
+        $data = parent::postMore(['status', 'info', 'desc', 'sort', 'config_tab_id', 'required', 'parameter', 'value', 'upload_type'], $request);
+        if (!ConfigModel::get($id)) return Json::fail('编辑的记录不存在!');
+        $data['value'] = rtrim($data['value'], '"');
+        $data['value'] = ltrim($data['value'], '"');
+        ConfigModel::edit($data, $id);
+        return Json::successful('修改成功!');
+    }
+
+    /**
+     * 修改是否显示子子段
+     * @param $id
+     * @return mixed
+     */
+    public function edit_cinfig($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::select('config_tab_id', '分类', (string)$menu['config_tab_id'])->setOptions(ConfigModel::getConfigTabAll(-1));
+        $formbuider[] = Form::input('info', '配置名称', $menu['info'])->autofocus(1);
+        $formbuider[] = Form::input('desc', '配置简介', $menu['desc']);
+        //输入框验证规则
+        if (!empty($menu['required'])) {
+            $formbuider[] = Form::input('value', '默认值', $menu['value']);
+            $formbuider[] = Form::number('width', '文本框宽(%)', $menu['width']);
+            $formbuider[] = Form::input('required', '验证规则', $menu['required'])->placeholder('多个请用,隔开例如:required:true,url: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']);
+        }
+        //单选和多选参数配置
+        if (!empty($menu['parameter'])) {
+            $formbuider[] = Form::textarea('parameter', '配置参数', $menu['parameter'])->placeholder("参数方式例如:\n1=白色\n2=红色\n3=黑色");
+        }
+        //上传类型选择
+        if (!empty($menu['upload_type'])) {
+            $formbuider[] = Form::radio('upload_type', '上传类型', $menu['upload_type'])->options([['value' => 1, 'label' => '单图'], ['value' => 2, 'label' => '多图'], ['value' => 3, 'label' => '文件']]);
+        }
+        $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::build('update_config', array('id' => $id)));
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 删除子字段
+     * @return \think\response\Json
+     */
+    public function delete_cinfig()
+    {
+        $id = input('id');
+        if (!ConfigModel::del($id))
+            return Json::fail(ConfigModel::getErrorInfo('删除失败,请稍候再试!'));
+        else
+            return Json::successful('删除成功!');
+    }
+
+    /**
+     * 保存数据    true
+     * */
+    public function save_basics()
+    {
+        $request = Request::instance();
+        if ($request->isPost()) {
+            $post = $request->post();
+            if(isset($post['tab_id'])) unset($post['tab_id']);
+            foreach ($post as $k => $v) {
+                if (is_array($v)) {
+                    $res = ConfigModel::where('menu_name', $k)->column('type,upload_type');
+                    foreach ($res as $kk => $vv) {
+                        if ($kk == 'upload') {
+                            if ($vv == 1 || $vv == 3) {
+                                $post[$k] = $v[0];
+                            }
+                        }
+                    }
+                }
+            }
+            foreach ($post as $k => $v) {
+                if($k=='site_url'){
+                    $http = "/^(http(s)?:\/\/)([0-9a-z-]{1,}.)?[0-9a-z-]{2,}.([0-9a-z-]{2,}.)?[a-z]{2,}$/i";
+                    if(!preg_match($http,$v) || substr_count($v,'/')>2){
+                        return Json::fail('域名有误!应如:http://crmeb.net');
+                    }
+                }
+                if($k=='gold_rate' || $k=='single_gold_coin'|| $k=='extract_min_money'|| $k=='store_brokerage_ratio'|| $k=='store_brokerage_two'|| $k=='barrage_show_time'|| $k=='store_stock'){
+                     if(bcsub($v,0,0)<=0){
+                        switch ($k){
+                            case 'gold_rate':
+                                return Json::fail('人民币与金币换算率不能小于等于0');
+                            break;
+                            case 'single_gold_coin':
+                                return Json::fail('单次签到虚拟币数不能小于等于0');
+                            break;
+                            case 'extract_min_money':
+                                return Json::fail('提现最低金额不能小于等于0');
+                            break;
+                            case 'store_brokerage_ratio':
+                                return Json::fail('一级推广人返佣比例不能小于等于0');
+                            break;
+                            case 'store_brokerage_two':
+                                return Json::fail('二级推广人返佣比例不能小于等于0');
+                            break;
+                            case 'barrage_show_time':
+                                return Json::fail('专题弹幕停留时间不能小于等于0');
+                            break;
+                            case 'store_stock':
+                                return Json::fail('警戒库存不能小于等于0');
+                            break;
+                        }
+                     }
+                }
+                ConfigModel::edit(['value' => json_encode($v)], $k, 'menu_name');
+            }
+            return Json::successful('修改成功');
+        }
+    }
+
+    /**
+     * 模板表单提交
+     * */
+    public function view_upload()
+    {
+        if ($_POST['type'] == 3) {
+            $res = Upload::file($_POST['file'], 'config/file');
+        } else {
+            $res = Upload::Image($_POST['file'], 'config/image');
+        }
+        if (!$res->status) return Json::fail($res->error);
+        return Json::successful('上传成功!', ['url' => $res->filePath]);
+    }
+
+    /**
+     * 基础配置  单个
+     * @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);
+        $config_tab = ConfigModel::getConfigTabAll();
+        foreach ($config_tab as $kk => $vv) {
+            $arr = ConfigModel::getAll($vv['value'])->toArray();
+            if (empty($arr)) {
+                unset($config_tab[$kk]);
+            }
+        }
+        $this->assign('config_tab', $config_tab);
+        $this->assign('list', $list);
+        return $this->fetch();
+    }
+
+    /**
+     * 保存数据  单个
+     * @return mixed
+     */
+    public function save_basics_alone()
+    {
+        $request = Request::instance();
+        if ($request->isPost()) {
+            $post = $request->post();
+            $tab_id = $post['tab_id'];
+            unset($post['tab_id']);
+            foreach ($post as $k => $v) {
+                ConfigModel::edit(['value' => json_encode($v)], $k, 'menu_name');
+            }
+            return $this->successfulNotice('修改成功');
+        }
+    }
+
+    /**
+     * 获取文件名
+     * */
+    public function getImageName()
+    {
+        $request = Request::instance();
+        $post = $request->post();
+        $src = $post['src'];
+        $data['name'] = basename($src);
+        exit(json_encode($data));
+    }
+
+    /**
+     * 上传文件
+     * @return string
+     */
+    public function file_upload()
+    {
+        $res = Upload::file('file', 'config/file');
+        if(!$res->status) return Json::fail($res->error);
+        return Json::successful('上传成功!',['filePath'=>$res->filePath]);
+    }
+}

+ 68 - 0
application/admin/controller/setting/SystemConfigContent.php

@@ -0,0 +1,68 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\setting;
+
+use app\admin\controller\AuthController;
+use app\admin\model\system\SystemConfigContent as SystemConfigContentModel;
+use service\JsonService;
+
+/**
+ * 配置文章
+ * Class SystemConfigContent
+ * @package app\admin\controller\setting
+ */
+class SystemConfigContent extends AuthController
+{
+    /**
+     * 展示数据
+     * @param int $id
+     * @return mixed|void
+     */
+    public function index($id = 0)
+    {
+        if (!$id) {
+            return $this->failed('缺少参数');
+        }
+        $this->assign([
+            'id' => $id,
+            'content' => SystemConfigContentModel::getValue($id, 'id'),
+            'title' => SystemConfigContentModel::getValue($id, 'id', 'title'),
+        ]);
+        return $this->fetch();
+    }
+
+    /**
+     * 保存数据
+     * @param int $id
+     * @throws \think\exception\DbException
+     */
+    public function save($id = 0)
+    {
+        if (!$id) {
+            return $this->failed('缺少参数');
+        }
+        $content = $this->request->post('content', '');
+        $info = SystemConfigContentModel::get($id);
+        if (!$info) {
+            return JsonService::fail('您保存的配置不存在');
+        }
+        if (!$content) {
+            return JsonService::fail('内容不能为空');
+        }
+        $info->content = htmlspecialchars($content);
+        if ($info->save()) {
+            return JsonService::successful('保存成功');
+        } else {
+            return JsonService::fail('保存失败');
+        }
+    }
+}

+ 150 - 0
application/admin/controller/setting/SystemConfigTab.php

@@ -0,0 +1,150 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\setting;
+
+use think\Url;
+use service\FormBuilder as Form;
+use think\Request;
+use service\JsonService as Json;
+use app\admin\controller\AuthController;
+use app\admin\model\system\SystemConfigTab as ConfigTabModel;
+use app\admin\model\system\SystemConfig as ConfigModel;
+
+/**
+ * 配置分类控制器
+ * Class SystemConfigTab
+ * @package app\admin\controller\system
+ */
+class SystemConfigTab extends AuthController
+{
+
+    /**
+     * 子子段
+     * @return mixed|\think\response\Json
+     */
+    public function sonconfigtab($tab_id = '')
+    {
+        if (!$tab_id) return Json::fail('参数错误');
+        $this->assign('tab_id', $tab_id);
+        $list = ConfigModel::getAll($tab_id);
+        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'] = is_array($v['value']) ? explode(',', $v['value'][0]) : explode(',', $v['value']);
+            }
+        }
+        $this->assign('list', $list);
+        return $this->fetch();
+    }
+
+    /**
+     * 基础配置
+     * @return mixed
+     */
+    public function index()
+    {
+        $where = parent::getMore([
+            ['status', ''],
+            ['title', ''],
+        ], $this->request);
+        $this->assign('where', $where);
+        $this->assign(ConfigTabModel::getSystemConfigTabPage($where));
+        return $this->fetch();
+    }
+
+    /**
+     * 添加配置分类
+     * @return mixed
+     */
+    public function create()
+    {
+        $form = Form::create(Url::build('save'), [
+            Form::input('title', '分类昵称'),
+            Form::input('eng_title', '分类字段'),
+            Form::frameInputOne('icon', '图标', Url::build('admin/widget.widgets/icon', array('fodder' => 'icon')))->icon('ionic'),
+            Form::radio('type', '类型', 0)->options([['value' => 0, 'label' => '系统'], ['value' => 1, 'label' => '公众号'],['value' => 4, 'label' => '支付'],['value' => 5, 'label' => '阿里云'],['value' => 3, 'label' => '其它'],['value' => 7, 'label' => '虚拟币']]),
+            Form::radio('status', '状态', 1)->options([['value' => 1, 'label' => '显示'], ['value' => 2, 'label' => '隐藏']])
+        ]);
+        $form->setMethod('post')->setTitle('添加分类配置');
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 保存分类名称
+     * @param Request $request
+     * @return \think\response\Json
+     */
+    public function save(Request $request)
+    {
+        $data = parent::postMore([
+            'eng_title',
+            'status',
+            'title',
+            'icon',
+            'type'], $request);
+        if (!$data['title']) return Json::fail('请输入按钮名称');
+        ConfigTabModel::set($data);
+        return Json::successful('添加菜单成功!');
+    }
+
+    /**
+     * 修改分类
+     * @param $id
+     * @return mixed
+     */
+    public function edit($id)
+    {
+        $menu = ConfigTabModel::get($id)->getData();
+        if (!$menu) return Json::fail('数据不存在!');
+        $form = Form::create(Url::build('update', array('id' => $id)), [
+            Form::input('title', '分类昵称', $menu['title']),
+            Form::input('eng_title', '分类字段', $menu['eng_title']),
+            Form::frameInputOne('icon', '图标', Url::build('admin/widget.widgets/icon', array('fodder' => 'icon')), $menu['icon'])->icon('ionic'),
+            Form::radio('type', '类型', $menu['type'])->options([['value' => 0, 'label' => '系统'], ['value' => 1, 'label' => '公众号'], ['value' => 4, 'label' => '支付'] ,['value' => 5, 'label' => '阿里云'],['value' => 3, 'label' => '其它'],['value' => 6, 'label' => '虚拟币']]),
+            Form::radio('status', '状态', $menu['status'])->options([['value' => 1, 'label' => '显示'], ['value' => 2, 'label' => '隐藏']])
+        ]);
+        $form->setMethod('post')->setTitle('添加分类配置');
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * @param Request $request
+     * @param $id
+     * @return \think\response\Json
+     */
+    public function update(Request $request, $id)
+    {
+        $data = parent::postMore(['title', 'status', 'eng_title', 'icon', 'type'], $request);
+        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
+     * @return \think\response\Json
+     */
+    public function delete($id)
+    {
+        if (!ConfigTabModel::del($id))
+            return Json::fail(ConfigTabModel::getErrorInfo('删除失败,请稍候再试!'));
+        else
+            return Json::successful('删除成功!');
+    }
+}

+ 154 - 0
application/admin/controller/setting/SystemGroup.php

@@ -0,0 +1,154 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\setting;
+
+use EasyWeChat\ShakeAround\Group;
+
+use service\JsonService as Json;
+
+use think\Request;
+
+use think\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()
+    {
+        $type = $this->request->param('type', "");
+        $where_type = [];
+        if (isset($type) && $type) {
+            switch ($type) {
+                case "bank":
+                    $where_type['config_name'] = ['extract_bank', 'extract_rule'];
+                    break;
+            }
+        }
+        $list = GroupModel::getGroupDataByType($where_type);
+        $this->assign($list);
+        return $this->fetch();
+    }
+
+    /**
+     * 显示创建资源表单页.
+     *
+     * @return \think\Response
+     */
+    public function create()
+    {
+        $this->assign(['title' => '添加数据组', 'save' => Url::build('save')]);
+        return $this->fetch();
+    }
+
+    /**
+     * 保存新建的资源
+     *
+     * @param  \think\Request $request
+     * @return \think\Response
+     */
+    public function save(Request $request)
+    {
+        $params = parent::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"] = json_encode($data["fields"]);
+        //判断ID是否存在,存在就是编辑,不存在就是添加
+        if (!$params['id']) {
+            GroupModel::set($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::build('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('删除成功!');
+        }
+    }
+}

+ 774 - 0
application/admin/controller/setting/SystemGroupData.php

@@ -0,0 +1,774 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\setting;
+
+use app\admin\model\special\Grade;
+use app\admin\model\special\RecommendBanner;
+use app\admin\model\special\Special;
+use app\admin\model\system\Recommend;
+use app\admin\model\system\RecommendRelation;
+use app\admin\model\user\Group;
+use service\FormBuilder as Form;
+use service\JsonService as Json;
+use service\UploadService as Upload;
+use think\Request;
+use think\Url;
+use app\admin\model\system\SystemGroup as GroupModel;
+use app\admin\model\system\SystemGroupData as GroupDataModel;
+use app\admin\controller\AuthController;
+use app\admin\model\system\SystemAttachment;
+
+/**
+ * 数据列表控制器  在组合数据中
+ * Class SystemGroupData
+ * @package app\admin\controller\system
+ */
+class SystemGroupData extends AuthController
+{
+
+    /**
+     * 显示资源列表
+     * @return \think\Response
+     */
+    public function index($gid)
+    {
+        $where = parent::getMore([
+            ['status', '']
+        ], $this->request);
+        $this->assign('where', $where);
+        $this->assign(compact("gid"));
+        $this->assign(GroupModel::getField($gid));
+        $where['gid'] = $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 (!empty($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) {
+                        if (strstr($v, '=>') !== false) {
+                            list($left, $right) = explode('=>', $v);
+                        } else if (strstr($v, '=') !== false) {
+                            list($left, $right) = explode('=', $v);
+                        }
+                        $val["value"] = $left;
+                        $val["label"] = $right;
+                        $info[] = $val;
+                    }
+                }
+            }
+
+            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"], isset($info[0]["value"]) ? $info[0]["value"] : '')->options($info);
+                    break;
+                case 'checkbox':
+                    $f[] = Form::checkbox($value["title"], $value["name"], isset($info[0]) ? $info[0] : '')->options($info);
+                    break;
+                case 'select':
+                    $f[] = Form::select($value["title"], $value["name"], isset($info[0]) ? $info[0] : '')->options($info)->multiple(false);
+                    break;
+                case 'upload':
+                    $f[] = Form::frameImageOne($value["title"], $value["name"], Url::build('admin/widget.images/index', array('fodder' => $value["title"])))->icon('image')->width('100%')->height('500px');
+                    break;
+                case 'uploads':
+                    $f[] = Form::frameImages($value["title"], $value["name"], Url::build('admin/widget.images/index', array('fodder' => $value["title"])))->maxLength(5)->icon('images')->width('100%')->height('500px')->spin(0);
+                    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::build('save', compact('gid')), 2);
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 保存新建的资源
+     *
+     * @param  \think\Request $request
+     * @return \think\Response
+     */
+    public function save(Request $request, $gid)
+    {
+        $Fields = GroupModel::getField($gid);
+        $params = $request->post();
+        $value = array();
+        foreach ($params as $key => $param) {
+            foreach ($Fields['fields'] as $index => $field) {
+                if ($key == $field["title"]) {
+                    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" => json_encode($value), "sort" => $params["sort"], "status" => $params["status"]);
+        GroupDataModel::set($data);
+        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();
+        foreach ($Fields['fields'] as $key => $value) {
+            $info = [];
+            if (!empty($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) {
+                        if (strstr($v, '=>') !== false) {
+                            list($left, $right) = explode('=>', $v);
+                        } else if (strstr($v, '=') !== false) {
+                            list($left, $right) = explode('=', $v);
+                        }
+                        $val["value"] = $left;
+                        $val["label"] = $right;
+                        $info[] = $val;
+                    }
+                }
+            }
+            switch ($value['type']) {
+                case 'input':
+                    $f[] = Form::input($value['title'], $value['name'], $GroupDataValue[$value['title']]['value']);
+                    break;
+                case 'textarea':
+                    $f[] = Form::input($value['title'], $value['name'], $GroupDataValue[$value['title']]['value'])->type('textarea');
+                    break;
+                case 'radio':
+                    $f[] = Form::radio($value['title'], $value['name'], $GroupDataValue[$value['title']]['value'])->options($info);
+                    break;
+                case 'checkbox':
+                    if(array_key_exists($value['title'],$GroupDataValue)){
+                        $f[] = Form::checkbox($value['title'], $value['name'], $GroupDataValue[$value['title']]['value'])->options($info);
+                    }else{
+                        $f[] = Form::checkbox($value["title"], $value["name"], isset($info[0]) ? $info[0] : '')->options($info);
+                    }
+                    break;
+                case 'upload':
+                    if (!empty($GroupDataValue[$value['title']]['value'])) {
+                        $image = is_string($GroupDataValue[$value['title']]['value']) ? $GroupDataValue[$value['title']]['value'] : $GroupDataValue[$value['title']]['value'][0];
+                    } else {
+                        $image = '';
+                    }
+                    $f[] = Form::frameImageOne($value['title'], $value['name'], Url::build('admin/widget.images/index', array('fodder' => $value['title'])), $image)->icon('image')->width('100%')->height('500px');
+                    break;
+                case 'uploads':
+                    $images = !empty($GroupDataValue[$value['title']]['value']) ? $GroupDataValue[$value['title']]['value'] : [];
+                    $f[] = Form::frameImages($value['title'], $value['name'], Url::build('admin/widget.images/index', array('fodder' => $value['title'])), $images)->maxLength(5)->icon('images')->width('100%')->height('550px')->spin(0);
+                    break;
+                case 'select':
+                    $f[] = Form::select($value['title'], $value['name'], $GroupDataValue[$value['title']]['value'])->setOptions($info);
+                    break;
+                default:
+                    $f[] = Form::input($value['title'], $value['name'], $GroupDataValue[$value['title']]['value']);
+                    break;
+
+            }
+        }
+        $f[] = Form::input('sort', '排序', $GroupData["sort"]);
+        $f[] = Form::radio('status', '状态', $GroupData["status"])->options([['value' => 1, 'label' => '显示'], ['value' => 2, 'label' => '隐藏']]);
+        $form = Form::make_post_form('编辑', $f, Url::build('update', compact('id')), 2);
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 保存更新的资源
+     *
+     * @param  \think\Request $request
+     * @param  int $id
+     * @return \think\Response
+     */
+    public function update(Request $request, $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 ($param == "" || !$param || empty($param))
+                        return Json::fail($field["name"] . "不能为空!");
+                    else {
+                        $value[$key]["type"] = $field["type"];
+                        $value[$key]["value"] = $param;
+                    }
+                }
+            }
+        }
+        $data = array("value" => json_encode($value), "sort" => $params["sort"], "status" => $params["status"]);
+        GroupDataModel::edit($data, $id);
+        return Json::successful('修改成功!');
+    }
+
+    /**
+     * 删除指定资源
+     *
+     * @param  int $id
+     * @return \think\Response
+     */
+    public function delete($id)
+    {
+        if (!GroupDataModel::del($id))
+            return Json::fail(GroupDataModel::getErrorInfo('删除失败,请稍候再试!'));
+        else
+            return Json::successful('删除成功!');
+    }
+
+    public function upload()
+    {
+        $res = Upload::image('file', 'common');
+        $thumbPath = Upload::thumb($res->dir);
+        //产品图片上传记录
+        $fileInfo = $res->fileInfo->getinfo();
+        SystemAttachment::attachmentAdd($res->fileInfo->getSaveName(), $fileInfo['size'], $fileInfo['type'], $res->dir, $thumbPath, 6);
+
+        if ($res->status == 200)
+            return Json::successful('图片上传成功!', ['name' => $res->fileInfo->getSaveName(), 'url' => Upload::pathToUrl($thumbPath)]);
+        else
+            return Json::fail($res->error);
+    }
+
+    public function recommend()
+    {
+        $this->assign('fixedList', Recommend::fixedList());
+        return $this->fetch();
+    }
+
+    public function recommend_list()
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['order', ''],
+            ['is_fixed', $this->request->param('is_fixed', 0)]
+        ]);
+        return Json::successlayui(Recommend::getRecommendList($where));
+    }
+
+    public function create_recemmend($id = 0)
+    {
+        if ($id) $this->assign('recemmend', Recommend::get($id));
+        $this->assign('is_fixed', 1);
+        $this->assign('grade_list', Grade::getAll());
+        $this->assign('id', $id);
+        return $this->fetch();
+    }
+
+    public function create_recemmend_v1($id = 0)
+    {
+        if ($id) $this->assign('recemmend', Recommend::get($id));
+        $this->assign('is_fixed', 0);
+        $this->assign('grade_list', Grade::getAll());
+        $this->assign('is_fixed', 0);
+        $this->assign('id', $id);
+        return $this->fetch();
+    }
+
+    public function save_recemmend($id = 0)
+    {
+        $post = parent::postMore([
+            ['icon', ''],
+            ['image', ''],
+            ['title', ''],
+            ['type', ''],
+            ['sort', 0],
+            ['is_fixed', 0],
+            ['is_show', 0],
+            ['grade_id', 0],
+            ['show_count', 0],
+            ['typesetting', ''],
+        ]);
+        if ($id) {
+            $post['is_show'] = $post['is_fixed'] ? 1 : $post['is_show'];
+            $rescomm = Recommend::get($id);
+            if (!$rescomm) return Json::fail('修改的信息不存在');
+            if($post['typesetting']==5){
+                unset($post['type'],$post['icon'],$post['image'],$post['is_fixed'],$post['is_show'],$post['grade_id'],$post['show_count']);
+            }
+            Recommend::update($post, ['id' => $id]);
+            return Json::successful('修改成功');
+        } else {
+            $post['add_time'] = time();
+            if (Recommend::set($post))
+                return Json::successful('保存成功');
+            else
+                return Json::fail('保存失败');
+        }
+    }
+
+    public function recemmend_content($id = 0)
+    {
+        if (!$id) return Json::fail('缺少参数');
+        if ($this->request->isAjax()) {
+            $where = parent::getMore([
+                ['page', 1],
+                ['limit', 20],
+            ]);
+            return Json::successlayui(RecommendRelation::getAll($where, $id));
+        } else {
+            $this->assign('id', $id);
+            return $this->fetch();
+        }
+    }
+
+    public function recemmed_delete($id = 0)
+    {
+        if (!$id) return Json::fail('缺少参数');
+        if (RecommendRelation::del($id))
+            return Json::successful('删除成功');
+        else
+            return Json::fail('删除失败');
+    }
+
+    /**
+     * 设置单个产品上架|下架
+     *
+     * @return json
+     */
+    public function set_show($is_show = '', $id = '')
+    {
+        ($is_show == '' || $id == '') && Json::fail('缺少参数');
+        $res = Recommend::where(['id' => $id])->update(['is_show' => (int)$is_show]);
+        if ($res) {
+            return Json::successful($is_show == 1 ? '显示成功' : '隐藏成功');
+        } else {
+            return Json::fail($is_show == 1 ? '显示失败' : '隐藏失败');
+        }
+    }
+
+    public function set_show_banner($is_show = '', $id = '')
+    {
+        ($is_show == '' || $id == '') && Json::fail('缺少参数');
+        $res = RecommendBanner::where(['id' => $id])->update(['is_show' => (int)$is_show]);
+        if ($res) {
+            return Json::successful($is_show == 1 ? '显示成功' : '隐藏成功');
+        } else {
+            return Json::fail($is_show == 1 ? '显示失败' : '隐藏失败');
+        }
+    }
+
+    /**
+     * 快速编辑
+     *
+     * @return json
+     */
+    public function set_value($field = '', $id = '', $value = '')
+    {
+        $field == '' || $id == '' || $value == '' && Json::fail('缺少参数');
+        if (Recommend::where(['id' => $id])->update([$field => $value]))
+            return Json::successful('保存成功');
+        else
+            return Json::fail('保存失败');
+    }
+
+    /**
+     * 快速编辑
+     *
+     * @return json
+     */
+    public function set_recemmend_value($field = '', $id = '', $value = '')
+    {
+        $field == '' || $id == '' || $value == '' && Json::fail('缺少参数');
+        if(bcsub($value,0,0)<0) Json::fail('不能为负数');
+        if (RecommendRelation::where(['id' => $id])->update([$field => $value]))
+            return Json::successful('保存成功');
+        else
+            return Json::fail('保存失败');
+    }
+
+    public function set_value_banner($field = '', $id = '', $value = '')
+    {
+        $field == '' || $id == '' || $value == '' && Json::fail('缺少参数');
+        if (RecommendBanner::where(['id' => $id])->update([$field => $value]))
+            return Json::successful('保存成功');
+        else
+            return Json::fail('保存失败');
+    }
+
+    /**
+     * 删除指定资源
+     *
+     * @param  int $id
+     * @return \think\Response
+     */
+    public function delete_recomm($id)
+    {
+        if (RecommendBanner::be(['recommend_id' => $id])) return Json::fail('删除失败,请先删除Banner图');
+        if (RecommendRelation::be(['recommend_id' => $id])) return Json::fail('删除失败,请先删除内容管理里面的列表');
+        if (!Recommend::del($id))
+            return Json::fail('删除失败');
+        else
+            return Json::successful('删除成功!');
+    }
+
+    /**
+     * 删除导航推荐
+     * @param string $id
+     */
+    public function delete_banner($id = '')
+    {
+        if (!RecommendBanner::del($id))
+            return Json::fail('删除失败');
+        else
+            return Json::successful('删除成功!');
+    }
+
+    public function recemmend_banner($id = '')
+    {
+        if ($id == '') return $this->failed('缺少参数');
+        $this->assign('id', $id);
+        $this->assign('type', 1);
+        return $this->fetch();
+    }
+
+    public function recemmend_banner_list()
+    {
+        $where = parent::getMore([
+            ['id', ''],
+            ['page', ''],
+            ['limit', ''],
+        ]);
+        if ($where['id'] == '') return Json::fail('缺少参数');
+        return Json::successlayui(RecommendBanner::getRecemmodBannerList($where));
+    }
+
+    /*
+     * 创建banner图
+     * */
+    public function create_recemmend_banner($id = '', $banner_id = 0)
+    {
+        $this->assign('id', $id);
+        if ($banner_id) {
+            $banner = RecommendBanner::get($banner_id);
+            if (!$banner) return $this->failed('缺少修改的banner');
+            $banner['pic_key'] = get_key_attr($banner['pic'], false);
+            $this->assign('banner', $banner);
+        }
+        $this->assign('banner_id', (int)$banner_id);
+        $this->assign('type', 2);
+        return $this->fetch();
+    }
+
+    public function save_recemmend_banner($id = '', $banner_id = '')
+    {
+        $post = parent::postMore([
+            ['url', ''],
+            ['sort', ''],
+            ['is_show', 0],
+            ['pic', ''],
+        ]);
+        if ($id == '') return Json::fail('缺少参数');
+        if ($post['pic'] == '') return Json::fail('请上传封面图!');
+        if ($post['is_show'] == 'on') $post['is_show'] = 1;
+        else $post['is_show'] = 0;
+        $post['recommend_id'] = $id;
+        if ($banner_id) {
+            RecommendBanner::edit($post, $banner_id);
+            return Json::successful('修改成功');
+        } else {
+            $post['add_time'] = time();
+            RecommendBanner::set($post);
+            return Json::successful('保存成功');
+        }
+    }
+
+    /**
+     * 首页导航固定跳转添加
+     * @return mixed
+     */
+    public function navigation()
+    {
+        return $this->fetch();
+    }
+
+    /**
+     * 自定义跳转导航添加和修改页面
+     * @param int $id
+     * @return mixed|void
+     * @throws \FormBuilder\exception\FormBuilderException
+     * @throws \think\exception\DbException
+     */
+    public function create_recemmend_custom($id = 0)
+    {
+        if ($id) {
+            $recommend = Recommend::get($id);
+            if (!$recommend) {
+                return $this->failed('您修改的导航不存在');
+            }
+        }
+        $f[] = Form::input('title', '导航名称', isset($recommend) ? $recommend->title : '');
+        $f[] = Form::frameImageOne('icon', '图标(100*100px)', get_image_Url('icon'), isset($recommend) ? $recommend->icon : '')->icon('image')->width('100%')->height('500px');
+        $f[] = Form::input('link', '跳转路径', isset($recommend) ? $recommend->link : '');
+        $f[] = Form::input('sort', '排序', isset($recommend) ? $recommend->sort : 0);
+        $f[] = Form::radio('is_show', '状态', isset($recommend) ? $recommend->is_show : 0)->options([['value' => 1, 'label' => '显示'], ['value' => 0, 'label' => '隐藏']]);
+        $form = Form::make_post_form('编辑', $f, Url::build('save_recemmend_custom', compact('id')), 2);
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 保存自定义导航链接
+     * @param int $id
+     */
+    public function save_recemmend_custom($id = 0)
+    {
+        $data = parent::postMore([
+            ['title', ''],
+            ['icon', ''],
+            ['link', ''],
+            ['sort', 0],
+            ['is_show', 0],
+            ['type', 3],
+            ['is_fixed', 1],
+        ]);
+
+        if (!$data['title']) {
+            return Json::fail('请填写导航名称');
+        }
+        if (!$data['icon']) {
+            return Json::fail('请选择导航图标');
+        }
+        if (!$data['link']) {
+            return Json::fail('请填写导航跳转地址');
+        }
+
+        if ($id) {
+            Recommend::where('id', $id)->update($data);
+            return Json::successful('修改成功');
+        } else {
+            $data['add_time'] = time();
+            $res = Recommend::set($data);
+            if ($res) {
+                return Json::successful('添加成功');
+            } else {
+                return Json::fail('修改失败');
+            }
+        }
+    }
+
+
+    /**
+     * 显示资源列表
+     * @return \think\Response
+     */
+    public function index_v1($gid)
+    {
+        $this->assign(compact("gid"));
+        return $this->fetch();
+    }
+
+    /**
+     * 获取某个组合数据列表
+     * @param int $gid
+     * @param int $page
+     * @param int $limit
+     * @throws \think\Exception
+     */
+    public function get_group_data_list($gid = 0, $status = '', $page = 1, $limit = 10)
+    {
+        $model = GroupDataModel::where(function ($query) use ($gid, $status) {
+            $query->where('gid', $gid);
+            if ($status != '') {
+                $query->where('status', $status);
+            }
+        });
+        $data = $model->order('sort desc,id desc')->page($page, $limit)->select();
+        $data = count($data) ? $data->toArray() : [];
+        foreach ($data as &$item) {
+            $value = json_decode($item['value'], true);
+            foreach ($value as $key => $val) {
+                $item[$key] = $value[$key]['value'];
+            }
+        }
+        $count = $model->count();
+        return Json::successlayui(compact('data', 'count'));
+    }
+
+    /**
+     * 修改某个字段
+     * @param string $field
+     * @param int $id
+     * @param string $value
+     */
+    public function set_group_data($field = '', $id = 0, $value = '')
+    {
+        if ('id' == $field) {
+            return Json::fail('修改失败,主键不允许修改');
+        }
+        if (!$field && !$value) {
+            return Json::fail('缺少修改参数');
+        }
+        $info = GroupDataModel::where('id', $id)->find();
+        if (!$info) {
+            return Json::fail('修改的信息不存在');
+        }
+        if (in_array($field, ['sort', 'status'])) {
+            $info->{$field} = $value;
+            $res = $info->save();
+        } else {
+            $infoVale = json_decode($info->value, true);
+            $infoVale[$field]['value'] = $value;
+            $info->value = json_encode($infoVale);
+            $res = $info->save();
+        }
+        if ($res) {
+            return Json::successful('修改成功');
+        } else {
+            return Json::fail('修改失败');
+        }
+    }
+
+    /**
+     * 添加组合数据页面
+     * @return mixed
+     */
+    public function create_v1($id = 0)
+    {
+        $this->assign([
+            'specialList' => json_encode(Special::PreWhere()->field(['id', 'title'])->order('sort desc,id desc')->select()),
+            'cateList' => json_encode(Grade::where(['is_del' => 0,'is_show'=>1])->field(['id', 'name as title'])->order('sort desc,id desc')->select()),
+        ]);
+        if ($id) {
+            $info = GroupDataModel::get($id);
+            if ($info) {
+                $infoValue = json_decode($info->value, true);
+                $this->assign('data', [
+                    'title' => isset($infoValue['title']['value']) ? $infoValue['title']['value'] : "",
+                    'pic' => isset($infoValue['pic']['value']) ? $infoValue['pic']['value'] : "",
+                    'info' => isset($infoValue['info']['value']) ? $infoValue['info']['value'] : '',
+                    'sort' => $info->sort,
+                    'status' => $info->status,
+                    'type' => isset($infoValue['type']['value']) ? $infoValue['type']['value'] : "''",
+                    'select_id' => isset($infoValue['select_id']['value']) ? $infoValue['select_id']['value'] : "''",
+                    'id' => $id
+                ]);
+            }
+        }
+        return $this->fetch();
+    }
+
+    public function save_group_data($name = '')
+    {
+        $data = parent::postMore([
+            ['title', ''],
+            ['id', ''],
+            ['image', ''],
+            ['info', ''],
+            ['type', 0],
+            ['select_id', 0],
+            ['sort', 0],
+            ['status', 0],
+        ]);
+        $gid = GroupModel::where(['config_name' => $name])->value('id');
+        if (!isset($data['id']) || !$data['id']) {
+            if (GroupDataModel::where('gid', $gid)->count() >= 3) {
+                return Json::fail('最多能添加3条信息');
+            }
+        }
+        if (!$data['title']) {
+            return Json::fail('请输入标题');
+        }
+        if (!$data['image']) {
+            return Json::fail('请选择图片');
+        }
+        if (!$data['info']) {
+            return Json::fail('请输入简介');
+        }
+        if (!$data['select_id']) {
+            return Json::fail('请选择' . ($data['type'] ? '分类' : "专题"));
+        }
+        $info = '{"pic":{"type":"upload","value":""},"title":{"type":"input","value":""},"info":{"type":"input","value":""},"wap_link":{"type":"select","value":""}}';
+        $info = json_decode($info, true);
+        $info['pic']['value'] = $data['image'];
+        $info['title']['value'] = $data['title'];
+        $info['info']['value'] = $data['info'];
+        $info['select_id']['value'] = $data['select_id'];
+        $info['select_id']['type'] = 'select';
+        $info['type']['type'] = 'radio';
+        $info['type']['value'] = $data['type'];
+        if ($data['type']) {
+            $info['wap_link']['value'] = '/wap/special/special_cate?cate_id=' . $data['select_id'];
+        } else {
+            $info['wap_link']['value'] = '/wap/special/details?id=' . $data['select_id'];
+        }
+        if (isset($data['id']) && $data['id']) {
+            $res = GroupDataModel::update([
+                'gid' => $gid,
+                'value' => json_encode($info),
+                'sort' => $data['sort'],
+                'status' => $data['status'],
+            ],['id' => $data['id']]);
+        }else{
+            $res = GroupDataModel::set([
+                'gid' => $gid,
+                'value' => json_encode($info),
+                'add_time' => time(),
+                'sort' => $data['sort'],
+                'status' => $data['status'],
+            ]);
+        }
+
+        if ($res) {
+            return Json::successful('编辑成功');
+        } else {
+            return Json::fail('编辑失败');
+        }
+    }
+}

+ 184 - 0
application/admin/controller/setting/SystemMenus.php

@@ -0,0 +1,184 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\setting;
+
+use service\FormBuilder as Form;
+use traits\CurdControllerTrait;
+use service\UtilService as Util;
+use service\JsonService as Json;
+use service\UploadService as Upload;
+use think\Request;
+use think\Url;
+use app\admin\model\system\SystemMenus as MenusModel;
+use app\admin\controller\AuthController;
+
+/**
+ * 菜单管理控制器
+ * 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 = parent::getMore([
+            ['is_show', ''],
+//            ['access',''],
+            ['keyword', ''],
+            ['pid', $pid]
+        ], $this->request);
+        $this->assign(MenusModel::getAdminPage($params));
+        $this->assign(compact('params'));
+        return $this->fetch();
+    }
+
+
+    /**
+     * 显示创建资源表单页.
+     *
+     * @return \think\Response
+     */
+    public function create($cid = 0)
+    {
+        $form = Form::create(Url::build('save'), [
+            Form::input('menu_name', '按钮名称')->required('按钮名称必填'),
+            Form::select('pid', '父级id', $cid)->setOptions(function () {
+                $list = (Util::sortListTier(MenusModel::all()->toArray(), '顶级', '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),
+            Form::select('module', '模块名')->options([['label' => '总后台', 'value' => 'admin']]),
+            Form::input('controller', '控制器名'),
+            Form::input('action', '方法名'),
+            Form::input('params', '参数')->placeholder('举例:a/123/b/234'),
+            Form::frameInputOne('icon', '图标', Url::build('admin/widget.widgets/icon', array('fodder' => 'icon')))->icon('ionic'),
+            Form::number('sort', '排序', 0),
+            Form::radio('is_show', '是否菜单', 1)->options([['value' => 0, 'label' => '隐藏'], ['value' => 1, 'label' => '显示(菜单只显示三级)']]),
+        ]);
+        $form->setMethod('post')->setTitle('添加权限');
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 保存新建的资源
+     *
+     * @param  \think\Request $request
+     * @return \think\Response
+     */
+    public function save(Request $request)
+    {
+        $data = parent::postMore([
+            'menu_name',
+            'controller',
+            ['module', 'admin'],
+            'action',
+            'icon',
+            'params',
+            ['pid', 0],
+            ['sort', 0],
+            ['is_show', 0],
+            ['access', 1]], $request);
+        if (!$data['menu_name']) return Json::fail('请输入按钮名称');
+        MenusModel::set($data);
+        return Json::successful('添加菜单成功!');
+    }
+
+    /**
+     * 显示编辑资源表单页.
+     *
+     * @param  int $id
+     * @return \think\Response
+     */
+    public function edit($id)
+    {
+        $menu = MenusModel::get($id);
+        if (!$menu) return Json::fail('数据不存在!');
+        $form = Form::create(Url::build('update', array('id' => $id)), [
+            Form::input('menu_name', '按钮名称', $menu['menu_name']),
+            Form::select('pid', '父级id', (string)$menu->getData('pid'))->setOptions(function () use ($id) {
+                $list = (Util::sortListTier(MenusModel::where('id', '<>', $id)->select()->toArray(), '顶级', '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),
+            Form::select('module', '模块名', $menu['module'])->options([['label' => '总后台', 'value' => 'admin']]),
+            Form::input('controller', '控制器名', $menu['controller']),
+            Form::input('action', '方法名', $menu['action']),
+            Form::input('params', '参数', MenusModel::paramStr($menu['params']))->placeholder('举例:a/123/b/234'),
+            Form::frameInputOne('icon', '图标', Url::build('admin/widget.widgets/icon', array('fodder' => 'icon')), $menu['icon'])->icon('ionic'),
+            Form::number('sort', '排序', $menu['sort']),
+            Form::radio('is_show', '是否菜单', $menu['is_show'])->options([['value' => 0, 'label' => '隐藏'], ['value' => 1, 'label' => '显示(菜单只显示三级)']])
+        ]);
+        $form->setMethod('post')->setTitle('编辑权限');
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 保存更新的资源
+     *
+     * @param  \think\Request $request
+     * @param  int $id
+     * @return \think\Response
+     */
+    public function update(Request $request, $id)
+    {
+        $data = parent::postMore([
+            'menu_name',
+            'controller',
+            ['module', 'admin'],
+            'action',
+            'params',
+            'icon',
+            ['sort', 0],
+            ['pid', 0],
+            ['is_show', 0],
+            ['access', 1]], $request);
+        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('删除成功!');
+    }
+
+}

+ 146 - 0
application/admin/controller/setting/SystemNotice.php

@@ -0,0 +1,146 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\setting;
+
+use app\admin\controller\AuthController;
+use service\FormBuilder as Form;
+use app\admin\model\system\SystemAdmin;
+use app\admin\model\system\SystemNotice as NoticeModel;
+use service\JsonService;
+use think\Request;
+use think\Url;
+
+/**
+ * 管理员消息通知 控制器
+ * Class SystemNotice
+ * @package app\admin\controller\system
+ */
+class SystemNotice extends AuthController
+{
+    /**
+     * 展示管理员列表
+     * @return mixed
+     */
+    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')) : '';
+        }));
+        return $this->fetch();
+    }
+
+    public function create()
+    {
+        $f = array();
+        $f[] = Form::input('title', '通知标题');
+        $f[] = Form::input('type', '通知类型');
+        $f[] = Form::frameInputOne('icon', '图标', Url::build('admin/widget.widgets/icon', array('fodder' => 'icon')))->icon('ionic');
+        $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::build('save'));
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    public function save(Request $request)
+    {
+        $data = parent::postMore([
+            'title', 'type', 'icon', 'template', 'table_title',
+            ['push_admin', []], ['status', 0]
+        ], $request);
+        $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::set($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::build('admin/widget.widgets/icon', array('fodder' => 'icon')), $data->icon)->icon('ionic');
+        $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::build('update', array('id' => $id)));
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    public function update(Request $request, $id)
+    {
+        $data = parent::postMore([
+            'title', 'type', 'icon', 'template', 'table_title',
+            ['push_admin', []], ['status', 0]
+        ], $request);
+        $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();
+    }
+}

+ 685 - 0
application/admin/controller/setting/SystemPlat.php

@@ -0,0 +1,685 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\setting;
+
+use app\admin\controller\AuthController;
+use app\admin\model\system\SystemConfig as ConfigModel;
+use service\JsonService as Json;
+use service\FormBuilder as Form;
+use service\CacheService;
+use think\Url;
+use service\CrmebPlatService;
+use service\sms\storage\Sms;
+use service\SystemConfigService;
+use app\admin\model\system\SmsAccessToken;
+
+/**
+ * crmeb 平台
+ * Class SystemPlat
+ * @package app\admin\controller\setting
+ */
+class SystemPlat extends AuthController
+{
+    protected $account = NULL;
+
+    protected $secret = NULL;
+    /**
+     * @var $crmebPlatHandle
+     */
+    protected $crmebPlatHandle;
+    /**
+     * @var $smsHandle
+     */
+    protected $smsHandle;
+    /**
+     * @var $expressHandle
+     */
+    protected $expressHandle;
+    /**
+     * @var $productHandle
+     */
+    protected $productHandle;
+
+    protected $allowAction = ['index', 'verify', 'login', 'go_login', 'register', 'go_register', 'modify', 'go_modify', 'forget', 'go_forget', 'loginOut', 'meal', 'sms_temp'];
+
+    /**
+     * @var string
+     */
+    protected $cacheTokenPrefix = "_crmeb_plat";
+
+    protected $cacheKey;
+
+    protected function _initialize()
+    {
+        parent::_initialize();
+        $this->account = SystemConfigService::get('sms_account');
+        $this->secret = SystemConfigService::get('sms_token');
+        $this->crmebPlatHandle = new CrmebPlatService();
+        $this->smsHandle = new Sms();
+        $this->cacheKey = md5($this->account . '_' . $this->secret . $this->cacheTokenPrefix);
+    }
+
+    /**
+     * 显示资源列表
+     *
+     * @return \think\Response
+     */
+    public function index()
+    {
+        if (!CacheService::get($this->cacheKey, '')) {
+            return $this->redirect(Url::build('login').'?url=index');
+        }
+        list($out, $type) = parent::postMore([
+            ['out', 0],
+            ['type', 'sms']
+        ], null, true);
+        try {
+            $info = $this->crmebPlatHandle->info();
+            if (!isset($info['status']) || $info['status'] != 200) {
+                $info = [];
+            }else{
+                $info =$info['data'];
+            }
+        } catch (\Throwable $e) {
+            $info = [];
+        }
+        $this->assign('info', $info);
+        $this->assign('type', $type);
+        if ($out == 0 && $info) {
+            return $this->fetch();
+        } else {
+            $this->assign('account', $this->account);
+            $this->assign('password', $this->secret);
+            return $this->fetch('login');
+        }
+
+    }
+
+    /**
+     * 获取短信验证码
+     */
+    public function verify()
+    {
+        list($phone) = parent::postMore([
+            ['phone', '']
+        ], null, true);
+        if (!$phone) {
+            return Json::fail('请输入手机号');
+        }
+        if (!check_phone($phone)) {
+            return Json::fail('请输入正确的手机号');
+        }
+        $data=$this->crmebPlatHandle->code($phone);
+        if (!isset($data['status']) || $data['status'] != 200) {
+            return Json::fail($data['msg']);
+        }else{
+            return Json::successful('获取成功');
+        }
+    }
+
+    /**
+     * 登录页面
+     * @return string
+     * @throws \Exception
+     */
+    public function login($url='')
+    {
+        $this->assign('str', $url);
+        $this->assign('account', $this->account);
+        $this->assign('password', $this->secret);
+        return $this->fetch();
+    }
+
+    /**
+     * 退出登录
+     * @return string
+     * @throws \Exception
+     */
+    public function loginOut()
+    {
+        CacheService::rm($this->cacheKey);
+        return Json::successful('退出成功', $this->crmebPlatHandle->loginOut());
+    }
+
+
+    /**
+     * 登录逻辑
+     */
+    public function go_login()
+    {
+        $data = parent::postMore([
+            ['account', ''],
+            ['password', '']
+        ]);
+        if (!$data['account']) {
+            return Json::fail('请输入账号');
+        }
+        if (!$data['password']) {
+            return Json::fail('请输入秘钥');
+        }
+        $this->save_basics(['sms_account' => $data['account'], 'sms_token' => $data['password']]);
+        $token = $this->crmebPlatHandle->login($data['account'], $data['password']);
+        if($token){
+            return Json::successful('登录成功', $token);
+        }else{
+            return Json::fail('登录失败,账号或密码有误!');
+        }
+
+    }
+
+    /**
+     * 注册页面
+     * @return string
+     * @throws \Exception
+     */
+    public function register()
+    {
+        return $this->fetch();
+    }
+
+    /**
+     * 注册逻辑
+     */
+    public function go_register()
+    {
+        $data = parent::postMore([
+            ['account', ''],
+            ['phone', ''],
+            ['password', ''],
+            ['verify_code', ''],
+        ]);
+        if (!$data['account']) {
+            return Json::fail('请输入账号');
+        }
+        if (!$data['phone']) {
+            return Json::fail('请输入手机号');
+        }
+        if (!check_phone($data['phone'])) {
+            return Json::fail('请输入正确的手机号');
+        }
+        if (!$data['password']) {
+            return Json::fail('请设置秘钥');
+        }
+        if (strlen($data['password']) < 6 || strlen($data['password']) > 32) {
+            return Json::fail('密码长度6~32位');
+        }
+        if (!$data['verify_code']) {
+            return Json::fail('请先获取短信验证码');
+        }
+        $result =$this->crmebPlatHandle->register($data['account'], $data['phone'], $data['password'], $data['verify_code']);
+        if (!isset($result['status']) || $result['status'] != 200) {
+            return Json::fail($result['msg']);
+        }else{
+            $result =$result['data'];
+        }
+        $this->save_basics(['sms_account' => $data['account'], 'sms_token' => $data['password']]);
+        return Json::successful('注册成功', $result);
+    }
+
+    /**
+     * 修改秘钥页面
+     * @return string
+     * @throws \Exception
+     */
+    public function modify()
+    {
+        $this->assign('account', $this->account);
+        return $this->fetch();
+    }
+
+    /**
+     * 修改秘钥逻辑
+     */
+    public function go_modify()
+    {
+        $data = parent::postMore([
+            ['account', ''],
+            ['phone', ''],
+            ['password', ''],
+            ['verify_code', ''],
+        ]);
+        if (!$data['account']) {
+            return Json::fail('请输入账号');
+        }
+        if (!$data['phone']) {
+            return Json::fail('请输入手机号');
+        }
+        if (!check_phone($data['phone'])) {
+            return Json::fail('请输入正确的手机号');
+        }
+        if (!$data['password']) {
+            return Json::fail('请设置秘钥');
+        }
+        if (strlen($data['password']) < 6 || strlen($data['password']) > 32) {
+            return Json::fail('密码长度6~32位');
+        }
+        if (!$data['verify_code']) {
+            return Json::fail('请先获取短信验证码');
+        }
+        $result = $this->crmebPlatHandle->modify($data['account'], $data['phone'], $data['password'], $data['verify_code']);
+        if (!isset($result['status']) || $result['status'] != 200) {
+            return Json::fail($result['msg']);
+        }else{
+            $result =$result['data'];
+        }
+        $this->save_basics(['sms_account' => $data['account'], 'sms_token' => $data['password']]);
+        return Json::successful('修改成功', $result);
+    }
+
+    /**
+     * 找回账号
+     * @return string
+     * @throws \Exception
+     */
+    public function forget()
+    {
+        return $this->fetch();
+    }
+
+    /**
+     * 找回账号逻辑
+     */
+    public function go_fotget()
+    {
+        $data = $where = parent::postMore([
+            ['phone', ''],
+            ['verify_code', ''],
+        ]);
+        if (!isset($data['phone']) || $data['phone']) {
+            return Json::fail('请输入手机号');
+        }
+        if (!check_phone($data['phone'])) {
+            return Json::fail('请输入正确的手机号');
+        }
+        if (!isset($data['verify_code']) || $data['verify_code']) {
+            return Json::fail('请先获取短信验证码');
+        }
+        $result = $this->crmebPlatHandle->forget($data['phone'], $data['verify_code']);
+        if (!isset($result['status']) || $result['status'] != 200) {
+            return Json::fail($result['msg']);
+        }else{
+            $result =$result['data'];
+        }
+        return Json::successful('修改成功', $result);
+    }
+
+    /**
+     * 获取消费记录
+     */
+    public function record()
+    {
+        list($type, $page, $limit) = parent::getMore([
+            ['type', 'sms'],
+            ['page', 1],
+            ['limit', 20]
+        ], null, true);
+        $result = $this->crmebPlatHandle->record($type, $page, $limit);
+        if (!isset($result['status']) || $result['status'] != 200) {
+            return Json::fail($result['msg']);
+        }else{
+            $result =$result['data'];
+        }
+        return Json::successlayui($result['count'],$result['data']);
+    }
+
+    /**
+     * @return string
+     * @throws \Exception
+     */
+    public function meal()
+    {
+        if (!CacheService::get($this->cacheKey, '')) {
+            return $this->redirect(Url::build('login').'?url=meal');
+        }
+        try {
+            $info = $this->crmebPlatHandle->info();
+            if (!isset($info['status']) || $info['status'] != 200) {
+                $info = [];
+            }else{
+                $info =$info['data'];
+            }
+        } catch (\Throwable $e) {
+            $info = [];
+        }
+        $this->assign('info', $info);
+        return $this->fetch();
+    }
+
+    /**
+     * 获取套餐列表
+     */
+    public function get_meal()
+    {
+        list($type) = parent::getMore([
+            ['type', 'sms']
+        ], null, true);
+        $result=$this->crmebPlatHandle->meal($type);
+        if (!isset($result['status']) || $result['status'] != 200) {
+            return Json::fail($result['msg']);
+        }else{
+            $result =$result['data'];
+        }
+        return Json::successful($result);
+    }
+
+    /**
+     * 获取支付二维码
+     * @return string
+     * @throws \Exception
+     */
+    public function pay()
+    {
+        list($meal_id, $price, $num, $type, $pay_type) = parent::postMore([
+            ['meal_id', 0],
+            ['price', ''],
+            ['num', 0],
+            ['type', ''],
+            ['pay_type', 'weixin']
+        ], null, true);
+        if (!$meal_id) {
+            return Json::fail('请选择套餐');
+        }
+        try {
+            $info = $this->crmebPlatHandle->info();
+            if (!isset($info['status']) || $info['status'] != 200) {
+                $info = [];
+            }else{
+                $info =$info['data'];
+            }
+        } catch (\Throwable $e) {
+            $info = [];
+        }
+        if(!$info) {
+            return Json::fail('用户信息不存在!');
+        }
+        $payContent=$this->crmebPlatHandle->pay($type, $meal_id, $price, $num, $pay_type);
+        if (!isset($payContent['status']) || $payContent['status'] != 200) {
+            $payContent = [];
+        }else{
+            $payContent =$payContent['data'];
+        }
+        if (isset($info['sms']['open']) && $info['sms']['open'] == 1){
+            $payContent['code_show']=true;
+        }else{
+            $payContent['code_show']=false;
+        }
+        return Json::successful($payContent);
+    }
+
+
+    /**
+     * 保存一号通配置
+     */
+    public function save_basics($data)
+    {
+        if ($data) {
+            CacheService::clear();
+            foreach ($data as $k => $v) {
+                ConfigModel::edit(['value' => json_encode($v)], $k, 'menu_name');
+            }
+        }
+        return true;
+    }
+
+    /**
+     * 开通短信服务页面
+     * @return string
+     * @throws \Exception
+     */
+    public function sms_open()
+    {
+        try {
+            $info = $this->crmebPlatHandle->info();
+            if (!isset($info['status']) || $info['status'] != 200) {
+                $info = [];
+            }else{
+                $info =$info['data'];
+            }
+        } catch (\Throwable $e) {
+            $info = [];
+        }
+        $this->assign('info', $info);
+        return $this->fetch();
+    }
+
+    /**
+     * 处理开通短信服务
+     */
+    public function go_sms_open()
+    {
+        list($sign) = parent::postMore([
+            ['sign', '']
+        ], null, true);
+        if (!$sign) {
+            return Json::fail('请输入短信签名');
+        }
+        try{
+           $sign= $this->smsHandle->setSign($sign)->open();
+            if (!isset($sign['status']) || $sign['status'] != 200) {
+                return Json::fail($sign['msg']);
+            }else{
+                return Json::successful('开通成功,可以在短信账户中查看');
+            }
+        }catch (\Throwable $e){
+            return Json::fail('开通失败或服务已开通');
+        }
+    }
+
+    /**
+     * 短信账户信息
+     */
+    public function sms_info()
+    {
+        return Json::successful($this->smsHandle->info());
+    }
+
+    /**
+     * 修改签名页面
+     * @return string
+     * @throws \Exception
+     */
+    public function sms_modify()
+    {
+        $this->assign('account', $this->account);
+        return $this->fetch();
+    }
+
+    /**
+     * 处理修改签名
+     */
+    public function go_sms_modify()
+    {
+        list($sign,$phone,$verify_code) = parent::postMore([
+            ['sign', ''],
+            ['phone', ''],
+            ['verify_code', ''],
+        ], null, true);
+        if (!$sign) {
+            return Json::fail('请输入短信签名');
+        }
+        if (!isset($phone) || !$phone) {
+            return Json::fail('请输入手机号');
+        }
+        if (!check_phone($phone)) {
+            return Json::fail('请输入正确的手机号');
+        }
+        if (!isset($verify_code) || !$verify_code) {
+            return Json::fail('请先获取短信验证码');
+        }
+        try{
+           $result= $this->smsHandle->modify($sign,$phone,$verify_code);
+           if (!isset($result['status']) || $result['status'] != 200) {
+                return Json::fail($result['msg'] ? $result['msg'] : '发生异常,请稍后重试');
+            }else{
+               return Json::successful($result['msg']);
+           }
+        }catch (\Throwable $e){
+            return Json::fail($e->getMessage());
+        }
+    }
+
+    /**
+     * 短信模版页面
+     */
+    public function sms_temp()
+    {
+        if (!CacheService::get($this->cacheKey, '')) {
+            return $this->redirect(Url::build('login').'?url=sms_temp');
+        }
+        list($type) = parent::getMore([
+            ['type', 'temps'],
+        ], null, true);
+        $this->assign('type', $type);
+        return $this->fetch();
+    }
+
+    /**
+     * 显示创建资源表单页.
+     *
+     * @return string
+     * @throws \FormBuilder\exception\FormBuilderException
+     */
+    public function create()
+    {
+        $field = [
+            Form::input('title', '模板名称'),
+            Form::textarea('text', '模板内容示例', '您的验证码是:{$code},有效期为{$time}分钟。如非本人操作,可不用理会。(模板中的{$code}和{$time}需要替换成对应的变量,请开发者知晓。修改此项无效!)')->readonly(true),
+            Form::input('content', '模板内容')->type('textarea'),
+            Form::radio('type', '模板类型', 1)->options([['label' => '验证码', 'value' => 1], ['label' => '通知', 'value' => 2], ['label' => '推广', 'value' => 3]])
+        ];
+        $form = Form::make_post_form('申请短信模板', $field, Url::build('go_sms_temps_apply'), 2);
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 短信模版
+     */
+    public function get_sms_temps()
+    {
+        list($page, $limit, $temp_type) = parent::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['temp_type', ''],
+        ], null, true);
+        $data=$this->smsHandle->temps($page, $limit, $temp_type);
+        if (!isset($data['status']) || $data['status'] != 200) {
+            return Json::fail($data['msg']);
+        }else{
+            $sms_platform_selection=SystemConfigService::get('sms_platform_selection');
+            $smsTemplateCode=SystemConfigService::get('smsTemplateCode');
+            if($sms_platform_selection==2){
+                foreach ($data['data']['data'] as &$value){
+                    if($value['temp_id']==$smsTemplateCode){
+                        $value['is_use']=1;
+                    }else{
+                        $value['is_use']=0;
+                    }
+                }
+            }
+            return Json::successlayui($data['data']);
+        }
+    }
+
+    /**
+     * 使用短信模板
+     */
+    public function sms_temp_use()
+    {
+        list($temp_id) = parent::getMore([
+            ['temp_id', 0],
+        ], null, true);
+        if($sms_platform_selection=SystemConfigService::get('sms_platform_selection')!=1){
+            $info = $this->crmebPlatHandle->info();
+            if (!isset($info['status']) || $info['status'] != 200) {
+                $info = [];
+            }else{
+                $info =$info['data'];
+            }
+            $res1=SystemConfigService::setOneValue('smsTemplateCode',$temp_id);
+            $res2=SystemConfigService::setOneValue('smsSignName',$info['sms']['sign']);
+            $res= $res1 && $res2;
+            if($res){
+                return Json::successful('设置成功');
+            }else{
+                return Json::fail('设置失败');
+            }
+        }else{
+            return Json::fail('请选择把短信平台切换成crmeb短信平台');
+        }
+    }
+    /**
+     * 短信模版申请记录
+     */
+    public function get_sms_appls()
+    {
+        list($temp_type, $page, $limit) = parent::getMore([
+            ['temp_type', ''],
+            ['page', 1],
+            ['limit', 20]
+        ], null, true);
+        $data=$this->smsHandle->applys($temp_type, $page, $limit);
+        if (!isset($data['status']) || $data['status'] != 200) {
+            return Json::fail($data['msg']);
+        }else{
+            return Json::successlayui($data['data']);
+        }
+    }
+
+    /**
+     * 短信发送记录
+     */
+    public function sms_record()
+    {
+        list($record_id) = parent::getMore([
+            ['record_id', 0],
+        ], null, true);
+        return Json::successful($this->smsHandle->record($record_id));
+    }
+
+    /**
+     * 模版申请页面
+     * @return string
+     * @throws \Exception
+     */
+    public function sms_temps_apply()
+    {
+        return $this->fetch();
+    }
+
+    /**
+     * 处理申请模版
+     */
+    public function go_sms_temps_apply()
+    {
+        list($type, $title, $content) = parent::postMore([
+            ['type', 1],
+            ['title', ''],
+            ['content', '']
+        ], null, true);
+        if (!$type) {
+            return Json::fail('请选择模版类型');
+        }
+        if (!$title) {
+            return Json::fail('请输入模板名称');
+        }
+        if (!$content) {
+            return Json::fail('请输入模版内容');
+        }
+        $data=$this->smsHandle->apply($title, $content, $type);
+        if (!isset($data['status']) || $data['status'] != 200) {
+            return Json::fail($data['msg']);
+        }else{
+            return Json::successful('申请成功');
+        }
+    }
+}

+ 152 - 0
application/admin/controller/setting/SystemRole.php

@@ -0,0 +1,152 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\setting;
+
+use app\admin\model\system\SystemMenus;
+use service\JsonService as Json;
+use think\Request;
+use think\Url;
+use app\admin\model\system\SystemRole as RoleModel;
+use app\admin\controller\AuthController;
+
+/**
+ * 身份管理  控制器
+ * Class SystemRole
+ * @package app\admin\controller\setting
+ */
+class SystemRole extends AuthController
+{
+
+    /**
+     * 显示资源列表
+     *
+     * @return \think\Response
+     */
+    public function index()
+    {
+        $where = parent::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()
+    {
+        $menus = $this->adminInfo['level'] == 0 ? SystemMenus::ruleList() : SystemMenus::rolesByRuleList($this->adminInfo['roles']);
+        $this->assign(['menus' => json($menus)->getContent(), 'saveUrl' => Url::build('save')]);
+        return $this->fetch();
+    }
+
+    /**
+     * 保存新建的资源
+     *
+     * @param  \think\Request $request
+     * @return \think\Response
+     */
+    public function save(Request $request)
+    {
+        $data = parent::postMore([
+            'role_name',
+            'sign',
+            ['status', 0],
+            ['checked_menus', [], '', 'rules']
+        ], $request);
+        if (!$data['role_name']) return Json::fail('请输入身份名称');
+        if (!$data['sign']) return Json::fail('请输入身份标识');
+        $sign_info = RoleModel::get(['sign' => $data['sign']]);
+        if ($sign_info) {
+            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;
+        RoleModel::set($data);
+        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::build('update', array('id' => $id))]);
+        return $this->fetch();
+    }
+
+    /**
+     * 保存更新的资源
+     *
+     * @param  \think\Request $request
+     * @param  int $id
+     * @return \think\Response
+     */
+    public function update(Request $request, $id)
+    {
+        $data = parent::postMore([
+            'role_name',
+            ['status', 0],
+            ['checked_menus', [], '', 'rules']
+        ], $request);
+        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']);
+        RoleModel::edit($data, $id);
+        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('删除成功!');
+    }
+}

+ 149 - 0
application/admin/controller/special/Course.php

@@ -0,0 +1,149 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\special;
+
+use app\admin\controller\AuthController;
+use app\admin\model\special\SpecialCourse;
+use service\JsonService;
+use service\FormBuilder as Form;
+use app\admin\model\special\Special;
+use think\response\Json;
+use think\Url;
+
+/**
+ * 课程控制器
+ * Class Grade
+ * @package app\admin\controller\special
+ */
+class Course extends AuthController
+{
+    /**
+     * 课程列表
+     * @param int $special_id
+     * @return mixed
+     */
+    public function index($special_id = 0)
+    {
+        $this->assign('special_id', $special_id);
+        return $this->fetch();
+    }
+
+    /**
+     * 添加课程
+     * @param int $special_id
+     * @param int $id
+     * @return mixed|void
+     * @throws \think\exception\DbException
+     */
+    public function add_course($special_id = 0, $id = 0)
+    {
+        if (!$special_id) return $this->failed('缺少参数');
+        $special = Special::get($special_id);
+        if (!$special) return $this->failed('并没有查到相关专题');
+        if ($special->is_del) return $this->failed('此专题已被删除');
+        if ($id) $course = SpecialCourse::get($id);
+        $form = [
+            Form::input('title', '专题名称', $special->title)->disabled(true),
+            Form::input('course_name', '课程名称', isset($course) ? $course->course_name : ''),
+            Form::number('sort', '排序', isset($course) ? $course->sort : ''),
+            Form::radio('is_show', '状态', isset($course) ? $course->is_show : 1)->options([['label' => '显示', 'value' => 1], ['label' => '隐藏', 'value' => 0]])
+        ];
+        $form = Form::make_post_form('添加课程', $form, Url::build('save_course', ['special_id' => $special_id, 'id' => $id]), 3);
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 保存课程
+     * @param int $special_id
+     * @param int $id
+     */
+    public function save_course($special_id = 0, $id = 0)
+    {
+        if (!$special_id) return JsonService::fail('缺少参数');
+        $post = parent::postMore([
+            ['course_name', ''],
+            ['sort', 0],
+            ['is_show', 1],
+        ]);
+        if (!$post['course_name']) return JsonService::fail('请输入课程名称');
+        $post['special_id'] = $special_id;
+        if ($id) {
+            SpecialCourse::update($post, ['id' => $id]);
+            return JsonService::successful('修改成功');
+        } else {
+            $post['add_time'] = time();
+            if (SpecialCourse::set($post))
+                return JsonService::successful('添加成功');
+            else
+                return JsonService::fail('添加失败');
+        }
+    }
+
+    /**
+     * 专题列表
+     */
+    public function course_list()
+    {
+        $where = parent::getMore([
+            ['special_id', 0],
+            ['is_show', ''],
+            ['course_name', ''],
+            ['page', 1],
+            ['limit', 20],
+        ]);
+        return JsonService::successlayui(SpecialCourse::getCourseList($where));
+    }
+
+    /**
+     * 删除课程
+     * @param int $id
+     */
+    public function delete($id = 0)
+    {
+        if (!$id) return JsonService::fail('缺少参数');
+        if (SpecialCourse::DelCourse($id))
+            return JsonService::successful('删除成功');
+        else
+            return JsonService::fail(SpecialCourse::getErrorInfo('删除失败'));
+    }
+
+    /**
+     * 设置单个产品上架|下架
+     *
+     * @return json
+     */
+    public function set_show($is_show = '', $id = '')
+    {
+        ($is_show == '' || $id == '') && JsonService::fail('缺少参数');
+        $res = SpecialCourse::where(['id' => $id])->update(['is_show' => (int)$is_show]);
+        if ($res) {
+            return JsonService::successful($is_show == 1 ? '显示成功' : '隐藏成功');
+        } else {
+            return JsonService::fail($is_show == 1 ? '显示失败' : '隐藏失败');
+        }
+    }
+
+    /**
+     * 快速编辑
+     *
+     * @return json
+     */
+    public function set_value($field = '', $id = '', $value = '')
+    {
+        $field == '' || $id == '' || $value == '' && JsonService::fail('缺少参数');
+        if (SpecialCourse::where(['id' => $id])->update([$field => $value]))
+            return JsonService::successful('保存成功');
+        else
+            return JsonService::fail('保存失败');
+    }
+}

+ 176 - 0
application/admin/controller/special/Grade.php

@@ -0,0 +1,176 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\special;
+
+use app\admin\model\special\SpecialSubject;
+use think\Url;
+use service\FormBuilder as Form;
+use service\JsonService as Json;
+use app\admin\controller\AuthController;
+use app\admin\model\special\Grade as GradeModel;
+
+/**
+ * 年级控制器
+ * Class Grade
+ * @package app\admin\controller\special
+ */
+class Grade extends AuthController
+{
+    public function index()
+    {
+        $this->assign('grade', GradeModel::getAll());
+        return $this->fetch();
+    }
+
+    public function get_grade_list()
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['cate_name', ''],
+        ]);
+        return Json::successlayui(GradeModel::getAllList($where));
+    }
+
+    /**
+     * 创建分类
+     * @param int $id
+     * @return mixed
+     * @throws \think\exception\DbException
+     */
+    public function create($id = 0,$sid=0,$level=1,$pid=0)
+    {
+        $cate=[];
+        if ($id && $sid==0){
+            $cate = GradeModel::get($id);
+        }else if($id==0 && $sid){
+            $cate = SpecialSubject::get($sid);
+        }
+        $this->assign(['cate'=>json_encode($cate),'id'=>$id,'sid'=>$sid,'level'=>$level,'pid'=>$pid]);
+        return $this->fetch();
+    }
+    /**获取一级分类
+     * @param int $sid
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function get_cate_list($level = 0)
+    {
+        $cate= GradeModel::where('is_del',0)->where('is_show',1)->field('id,name')->order('sort desc')->select();
+        $cate=count($cate) >0 ? $cate->toArray() : [];
+        $array=[];
+        $oneCate['id']=0;
+        $oneCate['name']='顶级分类';
+        array_push($array,$oneCate);
+        foreach ($cate as $key=>$value){
+            array_push($array,$value);
+        }
+        return Json::successful($array);
+    }
+
+    /**
+     * 快速编辑
+     *
+     * @return json
+     */
+    public function set_value($field = '', $id = '', $value = '')
+    {
+        $field == '' || $id == '' || $value == '' && Json::fail('缺少参数');
+        if (GradeModel::where(['id' => $id])->update([$field => $value]))
+            return Json::successful('保存成功');
+        else
+            return Json::fail('保存失败');
+    }
+
+    /**是否显示快捷操作
+     * @param string $is_show
+     * @param string $id
+     * @return mixed
+     */
+    public function set_show($is_show = '', $id = '')
+    {
+        ($is_show == '' || $id == '') && Json::fail('缺少参数');
+        $res = GradeModel::where(['id' => $id])->update(['is_show' => (int)$is_show]);
+        if ($res) {
+            return Json::successful($is_show == 1 ? '显示成功' : '隐藏成功');
+        } else {
+            return Json::fail($is_show == 1 ? '显示失败' : '隐藏失败');
+        }
+    }
+    /**
+     * 新增或者修改
+     *
+     * @return json
+     */
+    public function save($id = 0,$sid=0)
+    {
+        $post = parent::postMore([
+            ['name', ''],
+            ['pic', ''],
+            ['grade_id', 0],
+            ['sort', 0],
+            ['is_show', 0],
+        ]);
+        if (!$post['name']) return Json::fail('请输入分类名称');
+        if($post['grade_id']){
+            if (!$post['pic']) return Json::fail('请选择分类图标');
+        }
+        if ($id || $sid>0) {
+            if($id && $sid==0){
+                unset($post['pic'],$post['grade_id']);
+                $res=GradeModel::edit($post,$id);
+            }else if($sid && $id==0){
+                $res=SpecialSubject::edit($post,$sid);
+            }
+            if ($res)
+                return Json::successful('修改成功');
+            else
+                return Json::fail('修改失败');
+        } else {
+            $post['add_time'] = time();
+            if($post['grade_id']){
+                if(SpecialSubject::be(['name'=>$post['name'],'is_del'=>0])){
+                    return Json::fail('分类名称已存在!');
+                }
+                $res=SpecialSubject::set($post);
+            }else{
+                unset($post['pic'],$post['grade_id']);
+                if(GradeModel::be(['name'=>$post['name'],'is_del'=>0])){
+                    return Json::fail('分类名称已存在!');
+                }
+                $res=GradeModel::set($post);
+            }
+            if ($res)
+                return Json::successful('添加成功');
+            else
+                return Json::fail('添加失败');
+        }
+    }
+
+    /**
+     * 删除
+     *
+     * @return json
+     */
+    public function delete($id = 0)
+    {
+        if (!$id) return Json::fail('缺少参数');
+        $count=SpecialSubject::where('grade_id',$id)->where('is_del',0)->count();
+        if ($count) return Json::fail('请先删除下级分类');
+        $data['is_del']=1;
+        if (GradeModel::update($data,['id'=>$id]))
+            return Json::successful('删除成功');
+        else
+            return Json::fail('删除失败');
+    }
+}

+ 194 - 0
application/admin/controller/special/Lecturer.php

@@ -0,0 +1,194 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\special;
+
+use app\admin\controller\AuthController;
+use app\admin\model\special\Special;
+use app\admin\model\special\Lecturer as LecturerModel;
+use service\JsonService;
+use think\Url;
+
+/**
+ * 讲师控制器
+ */
+class Lecturer extends AuthController
+{
+    /**
+     * 讲师列表展示
+     * @return
+     * */
+    public function index()
+    {
+        return $this->fetch();
+    }
+    /**
+     * 讲师列表获取
+     * @return
+     * */
+    public function lecturer_list()
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['is_show', ''],
+            ['limit', 20],
+            ['title', ''],
+        ]);
+        return JsonService::successlayui(LecturerModel::getLecturerList($where));
+    }
+
+    /**添加/编辑
+     * @param int $id
+     * @return mixed|void
+     * @throws \think\exception\DbException
+     */
+    public function create($id = 0)
+    {
+        if ($id) {
+            $lecturer= LecturerModel::get($id);
+            $lecturer['label'] =json_decode($lecturer['label']);
+            $lecturer['introduction'] = htmlspecialchars_decode($lecturer['introduction']);
+            if(!$lecturer) return JsonService::fail('讲师信息不存在!');
+        }else{
+            $lecturer=[];
+        }
+        $this->assign(['lecturer'=>json_encode($lecturer),'id'=>$id]);
+        return $this->fetch();
+    }
+
+    /**
+     * 添加和修改讲师
+     * @param int $id 修改
+     * @return JsonService
+     * */
+    public function save_lecturer($id = 0)
+    {
+        $data = parent::postMore([
+            ['lecturer_name', ''],
+            ['lecturer_head', ''],
+            ['label', []],
+            ['explain', ''],
+            ['introduction', ''],
+            ['sort', 0],
+            ['is_show', 1],
+        ]);
+        if (!$data['lecturer_name']) return JsonService::fail('请输入讲师名称');
+        if (!$data['lecturer_head']) return JsonService::fail('请输入讲师头像');
+        if (!count($data['label'])) return JsonService::fail('请输入标签');
+        if (!$data['explain']) return JsonService::fail('请编辑讲师说明');
+        if (!$data['introduction']) return JsonService::fail('请编辑讲师介绍');
+        $data['label']=json_encode($data['label']);
+        $data['introduction']=htmlspecialchars($data['introduction']);
+        if ($id) {
+            LecturerModel::edit($data,$id);
+            return JsonService::successful('修改成功');
+        } else {
+            $data['add_time'] = time();
+            if (LecturerModel::set($data))
+                return JsonService::successful('添加成功');
+            else
+                return JsonService::fail('添加失败');
+        }
+    }
+
+    /**
+     * 设置单个产品上架|下架
+     * @param int $is_show 是否显示
+     * @param int $id 修改的主键
+     * @return JsonService
+     */
+    public function set_show($is_show = '', $id = '')
+    {
+        ($is_show == '' || $id == '') && JsonService::fail('缺少参数');
+        $res = LecturerModel::where(['id' => $id])->update(['is_show' => (int)$is_show]);
+        if ($res) {
+            return JsonService::successful($is_show == 1 ? '显示成功' : '隐藏成功');
+        } else {
+            return JsonService::fail($is_show == 1 ? '显示失败' : '隐藏失败');
+        }
+    }
+
+    /**
+     * 快速编辑
+     * @param string $field 字段名
+     * @param int $id 修改的主键
+     * @param string value 修改后的值
+     * @return JsonService
+     */
+    public function set_value($field = '', $id = '', $value = '')
+    {
+        $field == '' || $id == '' || $value == '' && JsonService::fail('缺少参数');
+        if (LecturerModel::where(['id' => $id])->update([$field => $value]))
+            return JsonService::successful('保存成功');
+        else
+            return JsonService::fail('保存失败');
+    }
+
+    /**
+     * 删除讲师
+     * @param int $id 修改的主键
+     * @return json
+     * */
+    public function delete($id = 0)
+    {
+        if (!$id) return JsonService::fail('缺少参数');
+        if (LecturerModel::delLecturer($id))
+            return JsonService::successful('删除成功');
+        else
+            return JsonService::fail(LecturerModel::getErrorInfo('删除失败'));
+    }
+
+    /**
+     * 讲师课程订单
+     */
+    public function lecturer_order($id=0)
+    {
+        $this->assign([
+            'year' => getMonth('h'),
+            'lecturer_id' => $id,
+        ]);
+        return $this->fetch();
+    }
+
+    /**讲师课程购买记录
+     * @throws \think\exception\DbException
+     */
+    public function lecturer_order_list()
+    {
+        $where = parent::getMore([
+            ['lecturer_id', 0],
+            ['page', 1],
+            ['limit', 10],
+            ['data', ''],
+        ]);
+        if (!$where['lecturer_id']) return JsonService::fail('缺少参数!');
+        $lecturer= LecturerModel::get($where['lecturer_id']);
+        if (!$lecturer) return JsonService::fail('讲师不存在!');
+        $list=LecturerModel::lecturerOrderList($where);
+        return JsonService::successlayui($list);
+    }
+
+    /**
+     * 讲师盈利
+     */
+    public function getBadge()
+    {
+        $where = parent::postMore([
+            ['lecturer_id', 0],
+            ['data', ''],
+        ]);
+        if (!$where['lecturer_id']) return JsonService::fail('缺少参数!');
+        $lecturer= LecturerModel::get($where['lecturer_id']);
+        if (!$lecturer) return JsonService::fail('讲师不存在!');
+        $list=LecturerModel::getBadge($where);
+        return JsonService::successful($list);
+    }
+}

+ 141 - 0
application/admin/controller/special/SpecialTaskCategory.php

@@ -0,0 +1,141 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\special;
+
+use think\Url;
+use service\FormBuilder as Form;
+use service\JsonService as Json;
+use app\admin\controller\AuthController;
+use app\admin\model\special\SpecialTaskCategory as SpecialTaskCategoryModel;
+
+/**
+ * 素材分类控制器
+ * Class Grade
+ * @package app\admin\controller\special
+ */
+class SpecialTaskCategory extends AuthController
+{
+    public function index($pid=0)
+    {
+        $this->assign(['category'=>SpecialTaskCategoryModel::taskCategoryAll(1),'pid'=>$pid]);
+        return $this->fetch();
+    }
+
+    public function get_category_list()
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['pid', 0],
+            ['cate_name', ''],
+        ]);
+        return Json::successlayui(SpecialTaskCategoryModel::getAllList($where));
+    }
+
+    /**
+     * 创建分类
+     * @param int $id
+     * @return mixed
+     * @throws \think\exception\DbException
+     */
+    public function create($id = 0,$pid=0)
+    {
+        $cate=[];
+        if($id){
+            $cate = SpecialTaskCategoryModel::get($id);
+        }
+        $this->assign(['cate'=>json_encode($cate),'id'=>$id,'pid'=>$pid]);
+        return $this->fetch();
+    }
+
+    public function get_cate_list()
+    {
+        $category=SpecialTaskCategoryModel::taskCategoryAll(2);
+        return Json::successful($category);
+    }
+
+    public function add_cate_list()
+    {
+        $category=SpecialTaskCategoryModel::where(['pid'=>0,'is_del'=>0])->select();
+        $category=count($category) >0 ? $category->toArray() : [];
+        $array=[];
+        $oneCate['id']=0;
+        $oneCate['title']='顶级分类';
+        array_push($array,$oneCate);
+        foreach ($category as $key=>$value){
+            array_push($array,$value);
+        }
+        return Json::successful($array);
+    }
+    /**
+     * 快速编辑
+     *
+     * @return json
+     */
+    public function set_value($field = '', $id = '', $value = '')
+    {
+        $field == '' || $id == '' || $value == '' && Json::fail('缺少参数');
+        if (SpecialTaskCategoryModel::where(['id' => $id])->update([$field => $value]))
+            return Json::successful('保存成功');
+        else
+            return Json::fail('保存失败');
+    }
+
+    /**
+     * 新增或者修改
+     *
+     * @return json
+     */
+    public function save($id = 0)
+    {
+        $post = parent::postMore([
+            ['title', ''],
+            ['pid', ''],
+            ['sort', 0],
+        ]);
+        if (!$post['title']) return Json::fail('请输入分类名称');
+        if ($id) {
+            $res=SpecialTaskCategoryModel::edit($post,$id);
+            if ($res)
+                return Json::successful('修改成功');
+            else
+                return Json::fail('修改失败');
+        } else {
+            $post['add_time'] = time();
+            if(SpecialTaskCategoryModel::be(['title'=>$post['title'],'is_del'=>0])){
+                return Json::fail('分类名称已存在!');
+            }
+            $res=SpecialTaskCategoryModel::set($post);
+            if ($res)
+                return Json::successful('添加成功');
+            else
+                return Json::fail('添加失败');
+        }
+    }
+
+    /**
+     * 删除
+     *
+     * @return json
+     */
+    public function delete($id = 0)
+    {
+        if (!$id) return Json::fail('缺少参数');
+        $count=SpecialTaskCategoryModel::where('pid',$id)->where('is_del',0)->count();
+        if ($count) return Json::fail('请先删除下级分类');
+        $data['is_del']=1;
+        if (SpecialTaskCategoryModel::update($data,['id'=>$id]))
+            return Json::successful('删除成功');
+        else
+            return Json::fail('删除失败');
+    }
+}

+ 1172 - 0
application/admin/controller/special/SpecialType.php

@@ -0,0 +1,1172 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\special;
+
+use app\admin\controller\AuthController;
+use app\admin\model\live\LiveGoods;
+use app\admin\model\special\SpecialBarrage;
+use app\admin\model\system\SystemConfig;
+use app\admin\model\live\LiveStudio;
+use app\admin\model\store\StoreProduct;
+use app\admin\model\store\StoreCategory;
+use app\admin\model\special\Grade;
+use app\admin\model\special\Special as SpecialModel;
+use app\admin\model\special\Special;
+use app\wap\model\special\SpecialBuy;
+use app\admin\model\special\Lecturer as LecturerModel;
+use app\admin\model\special\SpecialContent;
+use app\admin\model\special\SpecialCourse;
+use app\admin\model\special\SpecialSource;
+use app\admin\model\special\SpecialSubject;
+use app\admin\model\special\SpecialTask;
+use app\admin\model\system\Recommend;
+use app\admin\model\system\RecommendRelation;
+use service\JsonService as Json;
+use service\SystemConfigService;
+use service\VodService;
+use think\Db;
+use think\Exception;
+use service\FormBuilder as Form;
+use Api\AliyunLive as ApiAliyunLive;
+use think\Url;
+use app\admin\model\special\SpecialTaskCategory as SpecialTaskCategoryModel;
+
+/**课程管理-图文专题控制器
+ * Class Special
+ * @package app\admin\controller\special
+ */
+class SpecialType extends AuthController
+{
+
+    /** 图文专题列表模板渲染
+     * @return mixed
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function index($subject_id = 0)
+    {
+        $special_type = $this->request->param('special_type');
+        $subjectlist = Grade::with(['SpecialSubject'=>function($query){
+            $query->where(['is_show'=>1,'is_del'=>0]);
+        }])->where(['is_del'=>0,'is_show'=>1])->order('sort desc')->select();
+        $this->assign([
+            'activity_type' => $this->request->param('activity_type', 1),
+            'subject_id' => $subject_id,
+            'special_title' => SPECIAL_TYPE[$special_type],
+            'special_type' => $special_type,
+            'subject_list' => $subjectlist
+        ]);
+        $template = $this->switch_template($special_type, request()->action());
+        if (!$template) $template = "";
+        return $this->fetch($template);
+    }
+
+    public function groupList(){
+        $subjectlist = Grade::with(['SpecialSubject'=>function($query){
+            $query->where(['is_show'=>1,'is_del'=>0]);
+        }])->where(['is_del'=>0,'is_show'=>1])->order('sort desc')->select();
+        $this->assign([
+            'subject_list' => $subjectlist
+        ]);
+        return $this->fetch('special/group_list/index');
+    }
+
+    /**
+     * 专题拼团列表
+     */
+    public function pink_list(){
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['store_name', ''],
+            ['start_time', ''],
+            ['end_time', ''],
+            ['order', ''],
+            ['is_show', ''],
+        ]);
+        return Json::successlayui(SpecialModel::getPinkList($where));
+    }
+    /**
+     * 获取图文专题列表数据
+     */
+    public function list($special_type = 6)
+    {
+        $where = parent::getMore([
+            ['subject_id', 0],
+            ['page', 1],
+            ['limit', 20],
+            ['store_name', ''],
+            ['start_time', ''],
+            ['end_time', ''],
+            ['order', ''],
+            ['is_show', ''],
+        ]);
+        $where['type'] = $special_type;
+        return Json::successlayui(SpecialModel::getSpecialList($where));
+    }
+    /**
+     * 添加页面
+     * @param int $id
+     * @param int $is_live
+     * @return mixed|void
+     */
+    public function add($id = 0)
+    {
+        $special_type = $this->request->param('special_type');
+        if ($id) {
+            $special = SpecialModel::getOne($id, $special_type == SPECIAL_LIVE ? $special_type : 0);
+            if ($special === false) {
+                return $this->failed(SpecialModel::getErrorInfo('您修改的专题不存在'));
+            }
+            if($special_type!=SPECIAL_LIVE){
+                $specialSourceId = SpecialSource::getSpecialSource($id)->toArray();
+                $sourceCheckList = array();
+                if ($specialSourceId) {
+                    foreach ($specialSourceId as $k => $v) {
+                        if ($special_type == SPECIAL_COLUMN) {
+                            $task_list = SpecialModel::where(['id' => $v['source_id'],'is_del'=>0,'is_show'=>1])->find();
+                        }else{
+                            $task_list = SpecialTask::where(['id' => $v['source_id'],'is_del'=>0,'is_show'=>1])->find();
+                        }
+                        if($task_list){
+                            $task_list['is_check'] = 1;
+                            $task_list['sort'] = $v['sort'];
+                            $task_list['pay_status'] = $v['pay_status'];
+                            array_push($sourceCheckList,$task_list);
+                        }else{
+                            array_splice($specialSourceId,$k,1);
+                            continue;
+                        }
+                    }
+                }
+                $storeCheckList=[];
+            }else{
+                $live_id=LiveStudio::where('special_id',$id)->value('id');
+                $sourceCheckList=LiveGoods::getLiveGoodsLists($live_id,0);
+                $storeCheckList=LiveGoods::getLiveProductLists($live_id,1);
+            }
+            list($specialInfo, $liveInfo) = $special;
+            $this->assign('liveInfo', json_encode($liveInfo));
+            $this->assign('special', json_encode($specialInfo));
+            $this->assign('sourceCheckList', json_encode($sourceCheckList));
+            $this->assign('storeCheckList', json_encode($storeCheckList));
+        }
+        $this->assign('special_type', $special_type);
+        $this->assign('id', $id);
+        $template = $this->switch_template($special_type, request()->action());
+        if (!$template) $template = "";
+        return $this->fetch($template);
+    }
+
+    /**
+     * 素材页面渲染
+     * @return
+     * */
+    public function source_index($coures_id = 0)
+    {
+        $special_type = $this->request->param('special_type');
+        $this->assign('coures_id', $coures_id);
+        $this->assign('special_title', SPECIAL_TYPE[$special_type]);
+        $this->assign('special_type', $special_type);//图文专题
+        $this->assign('activity_type', $this->request->param('activity_type', 1));
+        $this->assign('special_id', SpecialCourse::where('id', $coures_id)->value('special_id'));
+        $this->assign('specialList', SpecialModel::PreWhere()->field(['id', 'title'])->select());
+        $template = $this->switch_template($special_type, request()->action());
+        if (!$template) $template = "";
+        return $this->fetch($template);
+    }
+
+    /**
+     * 素材管理
+     */
+    public function sources_index(){
+        $this->assign(['category'=>SpecialTaskCategoryModel::taskCategoryAll()]);
+        return $this->fetch('special/task/source_index');
+    }
+    /**
+     * 图文专题素材列表获取
+     * @return json
+     * */
+    public function source_list()
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['is_show', 1],
+            ['limit', 20],
+            ['title', ''],
+            ['pid', ''],
+            ['type', ''],
+            ['order', ''],
+            ['special_id', 0],
+            ['special_type', 0],
+            ['check_source_sure', '']
+        ]);
+        $special_source = array();
+        if (isset($where['special_id']) && $where['special_id'] && $where['special_type']!=SPECIAL_LIVE) {
+            $special_source = SpecialSource::where(['special_id' => $where['special_id']])->select()->toArray();
+            $special_source = array_column($special_source, 'pay_status', 'source_id');
+        }else if(isset($where['special_id']) && $where['special_id'] && $where['special_type']==SPECIAL_LIVE){
+            $live_id=LiveStudio::where('special_id',$where['special_id'])->value('id');
+            $special_source = LiveGoods::where(['live_id' => $live_id,'is_delete'=>0,'type'=>0])->select()->toArray();
+            $special_source = array_column($special_source, 'id', 'special_id');
+        }
+
+        $special_task = SpecialTask::getTaskList2($where);
+        if (isset($special_task['data']) && $special_task['data']) {
+            foreach ($special_task['data'] as $k => $v) {
+                if (array_key_exists($v['id'], $special_source)) {
+                    $special_task['data'][$k]['is_check'] = 1;
+                    $special_task['data'][$k]['LAY_CHECKED'] = true;
+                    if ($special_source[$v['id']] && $special_source[$v['id']] == PAY_MONEY) {
+                        $special_task['data'][$k]['pay_status'] = PAY_MONEY;
+                    } else {
+                        $special_task['data'][$k]['pay_status'] = PAY_NO_MONEY;
+                    }
+                } else {
+                    $special_task['data'][$k]['is_check'] = 0;
+                    $special_task['data'][$k]['pay_status'] = PAY_MONEY;
+                }
+                switch ($v['type']){
+                        case 1:
+                            $special_task['data'][$k]['types'] = '图文';
+                        break;
+                        case 2:
+                            $special_task['data'][$k]['types'] = '音频';
+                        break;
+                        case 3:
+                            $special_task['data'][$k]['types'] = '视频';
+                        break;
+                        case 4:
+                            $special_task['data'][$k]['types'] = '直播';
+                        break;
+                        case 5:
+                            $special_task['data'][$k]['types'] = '专栏';
+                        break;
+                        case 6:
+                            $special_task['data'][$k]['types'] = '其他';
+                        break;
+                }
+            }
+        }
+        $special_task['source'] = $special_source;
+        return Json::successlayui($special_task);
+    }
+    /**
+     * 商品列表获取
+     * @return json
+     * */
+    public function store_list()
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['is_show', ''],
+            ['limit', 20],
+            ['title', ''],
+            ['order', ''],
+            ['special_id', 0],
+            ['cate_id', '']
+        ]);
+        $special_source = array();
+        if(isset($where['special_id']) && $where['special_id']){
+            $live_id=LiveStudio::where('special_id',$where['special_id'])->value('id');
+            $special_source = LiveGoods::where(['live_id' => $live_id,'is_delete'=>0,'type'=>1])->select()->toArray();
+            $special_source = array_column($special_source, 'id', 'special_id');
+        }
+        $special_task = StoreProduct::storeProductList($where);
+        if (isset($special_task['data']) && $special_task['data']) {
+            foreach ($special_task['data'] as $k => $v) {
+                if (array_key_exists($v['id'], $special_source)) {
+                    $special_task['data'][$k]['is_check'] = 1;
+                    $special_task['data'][$k]['LAY_CHECKED'] = true;
+                } else {
+                    $special_task['data'][$k]['is_check'] = 0;
+                    $special_task['data'][$k]['LAY_CHECKED'] = false;
+                }
+            }
+        }
+        $special_task['source'] = $special_source;
+        return Json::successlayui($special_task);
+    }
+
+    /**
+     * 添加和修改素材
+     * @param int $id 修改
+     * @return
+     * */
+    public function add_source($id = 0)
+    {
+        $special_type = $this->request->param("special_type");
+        $this->assign('id', $id);
+        if ($id) {
+            $task = SpecialTask::get($id);
+            $task->detail = htmlspecialchars_decode($task->detail);
+            $task->content = htmlspecialchars_decode($task->content);
+            $task->image = get_key_attr($task->image);
+            $this->assign('special', $task);
+        }
+        $alicloud_account_id=SystemConfigService::get('alicloud_account_id');//阿里云账号ID
+        $configuration_item_region=SystemConfigService::get('configuration_item_region');//配置项region
+        $demand_switch=SystemConfigService::get('demand_switch');//视频点播开关
+        $this->assign('alicloud_account_id', $alicloud_account_id);
+        $this->assign('configuration_item_region', $configuration_item_region);
+        $this->assign('demand_switch', $demand_switch);
+        $this->assign('special_type', $special_type);
+        $template = $this->switch_template($special_type, request()->action());
+        if (!$template) $template = "";
+        return $this->fetch($template);
+    }
+
+    /**
+     * 添加和修改素材
+     * @param int $id 修改
+     * @return json
+     * */
+    public function save_source($id = 0)
+    {
+        $special_type = $this->request->param('special_type');
+        if (!$special_type) return Json::fail('专题类型参数缺失');
+        $data = parent::postMore([
+            ['title', ''],
+            ['image', ''],
+            ['content', ''],
+            ['detail', ''],
+            ['image', ''],
+            ['link', ''],
+            ['videoId', ''],
+            ['file_type', ''],
+            ['file_name', ''],
+            ['sort', 0],
+            ['pid', 0],
+            ['is_show', 1],
+        ]);
+        $data['type'] = $special_type;
+        if (!$data['title']) return Json::fail('请输入课程标题');
+        if (!$data['image']) return Json::fail('请上传封面图');
+        if ($id) {
+            unset($data['is_show']);
+            SpecialTask::update($data, ['id' => $id]);
+            return Json::successful('修改成功');
+        } else {
+            $data['add_time'] = time();
+            if (SpecialTask::set($data))
+                return Json::successful('添加成功');
+            else
+                return Json::fail('添加失败');
+        }
+    }
+
+    /**
+     * 统一添加素材
+     */
+    public function addSources($id=0)
+    {
+        if ($id) {
+            $task = SpecialTask::get($id);
+            $task->detail = htmlspecialchars_decode($task->detail);
+            if($task['type']!=1){
+                $task->content =$task->link ? ($task->content ? htmlspecialchars_decode($task->content) : '') : '';
+            }else{
+                $task->content = htmlspecialchars_decode($task->content);
+            }
+            $task->image = get_key_attr($task->image);
+            $this->assign('special', $task);
+        }
+        $alicloud_account_id=SystemConfigService::get('alicloud_account_id');//阿里云账号ID
+        $configuration_item_region=SystemConfigService::get('configuration_item_region');//配置项region
+        $demand_switch=SystemConfigService::get('demand_switch');//视频点播开关
+        $this->assign('alicloud_account_id', $alicloud_account_id);
+        $this->assign('configuration_item_region', $configuration_item_region);
+        $this->assign('demand_switch', $demand_switch);
+        $this->assign('id', $id);
+        return $this->fetch('special/task/add_source');
+    }
+    /**
+     * 快速编辑
+     * @param string $field 字段名
+     * @param int $id 修改的主键
+     * @param string value 修改后的值
+     * @return json
+     */
+    public function set_value($field = '', $id = '', $value = '', $model_type)
+    {
+        if(!$field || !$id || $value == '' || !$model_type) Json::fail('缺少参数3');
+
+        if (!$model_type) Json::fail('缺少参数2');
+        if ($model_type == "special") {//需要执行事件触发器,db写法无法触发。
+            if($field=='sort' && bcsub($value,0,0)<0)return Json::fail('排序不能为负数');
+            $res =  SpecialModel::update([$field => $value], ['id' => $id]);
+        }else{
+            $model_type = $this->switch_model($model_type);
+            $res = $model_type::saveFieldByWhere(['id' => $id],[$field => $value]);
+        }
+        if ($res)
+            return Json::successful('保存成功');
+        else
+            return Json::fail('保存失败');
+    }
+
+    /**根据标识选着模型对象
+     * @param $model_type 表名
+     * @return Special|SpecialTask|bool
+     */
+    protected function switch_model($model_type)
+    {
+        if (!$model_type) {
+            return false;
+        }
+        switch ($model_type) {
+            case 'task':
+                return new SpecialTask();
+                break;
+            case 'special':
+                return new Special();
+                break;
+            case 'source':
+                return new SpecialSource();
+                break;
+            case 'live_goods':
+                return new LiveGoods();
+                break;
+            default:
+                return false;
+        }
+    }
+
+    /**
+     * 编辑详情
+     * @return mixed
+     */
+    public function update_content($id = 0)
+    {
+        $field = $this->request->param('field');
+        $special_type = $this->request->param('special_type');
+        if (!$special_type) {
+            return $this->failed('专题类型丢失 ');
+        }
+        if (!$id) {
+            return $this->failed('缺少id ');
+        }
+        if (!$field) {
+            return $this->failed('缺少要修改的字段参数 ');
+        }
+        try {
+            $this->assign([
+                'action' => Url::build('save_content', ['id' => $id, 'field' => $field]),
+                'field' => $field,
+                'contentOrDetail' => htmlspecialchars_decode(SpecialTask::where('id', $id)->value($field))
+            ]);
+            $template = $this->switch_template($special_type, request()->action());
+            if (!$template) $this->failed('模板查询异常 ');
+            return $this->fetch($template);
+        } catch (\Exception $e) {
+            return $this->failed('异常错误 ');
+        }
+    }
+
+    /**
+     * @param $id
+     * @throws \think\exception\DbException
+     */
+    public function save_content($id, $field)
+    {
+        $content = $this->request->post($field, '');
+        $task = SpecialTask::get($id);
+        if (!$field) return Json::fail('修改项缺失');
+        if (!$task) {
+            return Json::fail('修改得素材不存在');
+        }
+        $task->$field = htmlspecialchars($content);
+        if ($task->save()) {
+            return Json::successful('保存成功');
+        } else {
+            return Json::fail('保存失败或者您没有修改什么');
+        }
+    }
+
+
+    /**获取分类
+     * @param int $grade_id
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function get_subject_list($grade_id = 0)
+    {
+        $subjectlist = Grade::with(['SpecialSubject'=>function($query){
+            $query->where(['is_show'=>1,'is_del'=>0]);
+        }])->where(['is_del'=>0,'is_show'=>1])->order('sort desc')->select();
+        return Json::successful($subjectlist);
+    }
+
+    /**
+     * 获取讲师
+     */
+    public function get_lecturer_list()
+    {
+        $list=LecturerModel::where(['is_del'=>0,'is_show'=>1])->order('sort desc')->select();
+        return Json::successful($list);
+    }
+    /**获取素材列表
+     * @param bool $type
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function get_special_source_list()
+    {
+        $special_type = $this->request->param('special_type');
+        $where['is_show'] = 1;
+        if ($special_type && is_numeric($special_type) && $special_type != SPECIAL_COLUMN) {
+            $where['type'] = $special_type;
+        }
+
+        if ($special_type == SPECIAL_COLUMN) {//专栏
+            $sourceList = SpecialModel::where($where)->whereIn('type', [SPECIAL_IMAGE_TEXT, SPECIAL_AUDIO, SPECIAL_VIDEO])->field('id, title, type')->order('type desc, sort desc')->select();
+            if ($sourceList) {
+                foreach ($sourceList as $k => $v) {
+                    $sourceList[$k]['title'] = SPECIAL_TYPE[$v['type']] . "--" . $v['title'];
+                }
+            }
+        } else {
+            $sourceList = SpecialTask::where($where)->field('id, title')->order('sort desc')->select();
+        }
+        return Json::successful($sourceList->toArray());
+    }
+
+    /**获取视频上传地址和凭证
+     * @param string $videoId
+     * @param string $FileName
+     * @param int $type
+     */
+    public function video_upload_address_voucher()
+    {
+        $data = parent::postMore([
+            ['FileName',''],
+            ['type',1],
+            ['image',''],
+            ['videoId',''],
+        ]);
+        $url=VodService::videoUploadAddressVoucher($data['FileName'],$data['type'],$data['videoId'],$data['image']);
+        return Json::successful($url);
+    }
+    /**
+     * 编辑和新增
+     *
+     * @return json
+     */
+    public function save_special($id = 0)
+    {
+        $special_type = $this->request->param('special_type');
+        if (!$special_type || !is_numeric($special_type)) return Json::fail('专题类型参数缺失');
+        $data = parent::postMore([
+            ['title', ''],
+            ['abstract', ''],
+            ['subject_id', 0],
+            ['lecturer_id', 0],
+            ['fake_sales', 0],
+            ['browse_count', 0],
+            ['label', []],
+            ['image', ''],
+            ['banner', []],
+            ['poster_image', ''],
+            ['service_code', ''],
+            ['money', 0],
+            ['content', ''],
+            ['is_pink', 0],
+            ['pink_money', 0],
+            ['pink_number', 0],
+            ['pink_time', 0],
+            ['pink_strar_time', ''],
+            ['pink_end_time', ''],
+            ['subjectIds',''],
+            ['storeIds',''],
+            ['phrase', ''],
+            ['is_fake_pink', 0],
+            ['sort', 0],
+            ['fake_pink_number', 0],
+            ['member_money', 0],
+            ['member_pay_type', 0],
+            ['pay_type', 0],//支付方式:免费、付费、密码
+        ]);
+        $lecturer_id=$data['lecturer_id'];
+        $data['check_source_sure']=json_decode($data['subjectIds']);
+        $data['check_store_sure']=json_decode($data['storeIds']);
+        $data['type'] = $special_type;
+        if ($special_type == SPECIAL_LIVE) {
+            $liveInfo = parent::postMore([
+                ['is_remind', 1],//开播提醒
+                ['remind_time', 0],//开播提醒时间
+                ['live_time', ''],//直播开始时间
+                ['live_duration', 0],//直播时长 单位:分钟
+                ['auto_phrase', ''],//首次进入直播间欢迎词
+                ['password', ''],//密码(密码访问模式)
+                ['is_recording', ''],//是否录制视频
+            ]);
+        }
+        if (!$data['subject_id']) return Json::fail('请选择分类');
+        if ($special_type != SPECIAL_LIVE) {
+            if (!$data['check_source_sure']) return Json::fail('请选择素材');
+        }
+        if (!$data['title']) return Json::fail('请输入专题标题');
+        if (!$data['abstract']) return Json::fail('请输入专题简介');
+        if (!count($data['label'])) return Json::fail('请输填写标签');
+        if (!count($data['banner'])) return Json::fail('请上传banner图');
+        if (!$data['image']) return Json::fail('请上传专题封面图');
+        if (!$data['poster_image']) return Json::fail('请上传推广海报');
+        if (!$data['service_code']) return Json::fail('请上传客服二维码');
+        if (!$data['phrase']) return Json::fail('请填写短语!');
+        if ($data['pay_type'] == PAY_MONEY && ($data['money'] == '' || $data['money'] == 0.00 || $data['money'] < 0)) return Json::fail('购买金额未填写或者金额非法');
+        if ($data['member_pay_type'] == MEMBER_PAY_MONEY && ($data['member_money'] == '' || $data['member_money'] == 0.00 || $data['member_money'] < 0)) return Json::fail('会员购买金额未填写或金额非法');
+        if ($data['pay_type'] != PAY_MONEY) {
+            $data['money'] = 0;
+        }
+        if ($data['member_pay_type'] != MEMBER_PAY_MONEY) {
+            $data['member_money'] = 0;
+        }
+        if ($data['is_pink']) {
+            if (!$data['pink_money'] || $data['pink_money'] == 0.00 || $data['pink_money'] < 0) return Json::fail('拼团金额未填写或者金额非法');
+            if (!$data['pink_number'] || $data['pink_number'] <= 0) return Json::fail('拼团人数未填写或拼团人数非法');
+            if (!$data['pink_strar_time']) return Json::fail('请填选择拼团开始时间');
+            if (!$data['pink_end_time']) return Json::fail('请填选择拼团结束时间');
+            if ($data['pink_end_time'] < $data['pink_strar_time']) return Json::fail('拼团时间范围非法');
+            if (!$data['pink_time'] || $data['pink_time'] < 0) return Json::fail('拼团时间未填写或时间非法');
+            if (($data['is_fake_pink'] && !$data['fake_pink_number']) || ($data['is_fake_pink'] && $data['fake_pink_number'] < 0)) return Json::fail('虚拟拼团比例未填写或者比例非法');
+        }
+        $content = htmlspecialchars($data['content']);
+        $data['label'] = json_encode($data['label']);
+        $data['pink_strar_time'] = strtotime($data['pink_strar_time']);
+        $data['pink_end_time'] = strtotime($data['pink_end_time']);
+        if ($special_type == SPECIAL_LIVE) {
+            $liveInfo['live_title'] = $data['title'];
+            $liveInfo['studio_pwd'] = $liveInfo['password'];
+            if (strlen($liveInfo['studio_pwd']) > 32) return Json::fail('密码长度不能超过32位');
+            $liveInfo['start_play_time'] = $liveInfo['live_time'];
+            $liveInfo['stop_play_time'] = date('Y-m-d H:i:s', bcadd(strtotime($liveInfo['live_time']), bcmul($liveInfo['live_duration'], 60)));
+            $liveInfo['live_introduction'] = $data['abstract'];
+            unset($liveInfo['live_time'], $liveInfo['password']);
+            $cacheModel = Db::name('cache');
+            $aliyunLive = ApiAliyunLive::instance([
+                'AccessKey' => SystemConfigService::get('accessKeyId'),
+                'AccessKeySecret' => SystemConfigService::get('accessKeySecret'),
+                'OssEndpoint' => SystemConfigService::get('aliyun_live_end_point'),
+                'OssBucket' => SystemConfigService::get('aliyun_live_oss_bucket'),
+                'appName' => SystemConfigService::get('aliyun_live_appName'),
+                'payKey' => SystemConfigService::get('aliyun_live_play_key'),
+                'key' => SystemConfigService::get('aliyun_live_push_key'),
+                'playLike' => SystemConfigService::get('aliyun_live_playLike'),
+                'rtmpLink' => SystemConfigService::get('aliyun_live_rtmpLink'),
+            ]);
+            if (!$cacheModel->where('key', 'LiveNotifyUrl')->count()) {
+                try {
+                    $res = $aliyunLive->setLiveNotifyUrl(SystemConfigService::get('site_url') . Url::build('live/index/serve'))->executeResponse();
+                    if ($res) {
+                        $cacheModel->insert(['key' => 'LiveNotifyUrl', 'add_time' => time()]);
+                    }
+                } catch (\Throwable $e) {
+                    echo $e->getMessage();
+                }
+            }
+            if (!$cacheModel->where('key', 'liveRecordConfig')->count()) {
+                try {
+                    $res = $aliyunLive->liveRecordConfig()->executeResponse();
+                    if ($res) {
+                        $cacheModel->insert(['key' => 'liveRecordConfig', 'add_time' => time()]);
+                    }
+                } catch (\Throwable $e) {
+                    echo $e->getMessage();
+                }
+            }
+        }
+        $banner = [];
+        SpecialModel::beginTrans();
+        try {
+            foreach ($data['banner'] as $item) {
+                $banner[] = $item['pic'];
+            }
+            $sourceCheckList = $data['check_source_sure'];
+            $storeCheckList = $data['check_store_sure'];
+            unset($data['check_source_sure']);
+            $data['banner'] = json_encode($banner);
+            unset($data['content']);
+            if ($id) {
+                $original = SpecialModel::where('id',$id)->field('lecturer_id,browse_count')->find();
+                SpecialModel::update($data, ['id' => $id]);
+                SpecialContent::update(['content' => $content], ['special_id' => $id]);
+                if ($special_type == SPECIAL_LIVE) {
+                    LiveStudio::update($liveInfo, ['special_id' => $id]);
+                }
+                if ($special_type == SPECIAL_LIVE) {
+                    $save_source = LiveGoods::saveLiveGoods($sourceCheckList, $id,0);
+                    $save_store = LiveGoods::saveLiveGoods($storeCheckList, $id,1);
+                }else{
+                    $save_source = SpecialSource::saveSpecialSource($sourceCheckList,$id,$special_type,$data);
+                    $save_store=true;
+                }
+                if (!$save_source || !$save_store) return Json::fail('添加失败');
+                if($original['lecturer_id']!=$lecturer_id){
+                    $count=Db::name('learning_records')->where('special_id',$id)->count();
+                    $this->lecturerCurriculum($lecturer_id,1,$count);
+                    $this->lecturerCurriculum($original['lecturer_id'],-1,$count);
+                }
+                if ($special_type == SPECIAL_COLUMN) {
+                    SpecialBuy::columnUpdate($id);
+                }
+                SpecialModel::commitTrans();
+                return Json::successful('修改成功');
+            } else {
+                $data['add_time'] = time();
+                $data['is_show'] = 1;
+                $data['is_fake_pink'] = $data['is_pink'] ? $data['is_fake_pink'] : 0;
+                $res1 = SpecialModel::insertGetId($data);
+                $res2 = SpecialContent::set(['special_id' => $res1, 'content' => $content, 'add_time' => time()]);
+                $res5=true;
+                if ($special_type == SPECIAL_LIVE) {
+                    $liveInfo['special_id'] = $res1;
+                    $liveInfo['stream_name'] = LiveStudio::getliveStreamName();
+                    $liveInfo['live_image'] = $data['image'];
+                    $res5 = LiveStudio::set($liveInfo);
+                }
+                if ($special_type == SPECIAL_LIVE) {
+                    $res3 = LiveGoods::saveLiveGoods($sourceCheckList, $res1,0);
+                    $res4 = LiveGoods::saveLiveGoods($storeCheckList, $res1,1);
+                }else{
+                    $res3 = SpecialSource::saveSpecialSource($sourceCheckList,$res1,$special_type,$data);
+                    $res4 = true;
+                }
+                if ($res1 && $res2 && $res3 && $res4 && $res5) {
+                    $this->lecturerCurriculum($lecturer_id,1,0);
+                    SpecialModel::commitTrans();
+                    return Json::successful('添加成功');
+                } else {
+                    SpecialModel::rollbackTrans();
+                    return Json::fail('添加失败');
+                }
+            }
+        } catch (\Exception $e) {
+            SpecialModel::rollbackTrans();
+            return Json::fail($e->getMessage());
+        }
+    }
+
+    /**
+     * 讲师课程数量更新
+     */
+    public function lecturerCurriculum($lecturer_id=0,$pm=1,$study=0)
+    {
+        if(!$lecturer_id) return true;
+        $lecturer=LecturerModel::where('id',$lecturer_id)->find();
+        if(!$lecturer) return false;
+        if($pm==1){
+            $res=LecturerModel::where('id',$lecturer_id)->update(['curriculum'=>bcadd($lecturer['curriculum'],1,0), 'study'=>bcadd($lecturer['study'],$study,0)]);
+        }else{
+            $res=LecturerModel::where('id',$lecturer_id)->update(['curriculum'=>bcsub($lecturer['curriculum'],1,0), 'study'=>bcsub($lecturer['study'],$study,0)]);
+        }
+        return $res;
+    }
+    /**
+     * 拼团设置
+     * @param int $special_id
+     * @return mixed
+     * @throws \FormBuilder\exception\FormBuilderException
+     * @throws \think\exception\DbException
+     */
+    public function pink($special_id = 0)
+    {
+        if (!$special_id) $this->failed('缺少参数');
+        $special = SpecialModel::get($special_id);
+        if (!$special) $this->failed('没有查到此专题');
+        if ($special->is_del) $this->failed('此专题已删除');
+        $form = [
+            Form::input('title', '专题标题', $special->title)->disabled(true),
+            Form::number('pink_money', '拼团金额', $special->pink_money),
+            Form::number('pink_number', '拼团人数', $special->pink_number),
+            Form::number('pink_time', '拼团时效(h)', $special->pink_time ? $special->pink_time : 24),
+            Form::dateTimeRange('pink_time_new', '拼团时间', $special->pink_strar_time, $special->pink_end_time),
+            Form::radio('is_fake_pink', '开启虚拟拼团', $special->is_fake_pink)->options([['label' => '开启', 'value' => 1], ['label' => '关闭', 'value' => 0]]),
+            Form::number('fake_pink_number', '补齐比例', $special->fake_pink_number),
+        ];
+        $form = Form::make_post_form('开启拼团设置', $form, Url::build('save_pink', ['special_id' => $special_id]), 2);
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**保存拼团
+     * @param $special_id
+     */
+    public function save_pink($special_id)
+    {
+        if (!$special_id) $this->failed('缺少参数');
+        $data = parent::postMore([
+            ['pink_money', 0],
+            ['pink_number', 0],
+            ['pink_time', 0],
+            ['pink_time_new', []],
+            ['is_fake_pink', 0],
+            ['fake_pink_number', 0],
+        ]);
+        if (!$data['pink_number']) return Json::fail('拼团人数不能为0');
+        if (!$data['pink_time']) return Json::fail('拼团时效不能为0');
+        if ($data['pink_time_new'][0]=='' || $data['pink_time_new'][1]=='') return Json::fail('请设置拼团时间');
+        if ($data['is_fake_pink'] && !$data['fake_pink_number']) return Json::fail('请设置虚拟拼团比例');
+        if ($data['is_fake_pink'] != 1) {
+            $data['fake_pink_number'] = 0;
+        }
+        $data['is_pink'] = 1;
+        if (is_array($data['pink_time_new']) && isset($data['pink_time_new'][0]) && $data['pink_time_new'][1]) {
+            $data['pink_strar_time'] = strtotime($data['pink_time_new'][0]);
+            $data['pink_end_time'] = strtotime($data['pink_time_new'][1]);
+        }
+        unset($data['pink_time_new']);
+        SpecialModel::update($data, ['id' => $special_id]);
+        return Json::successful('保存成功');
+    }
+
+    /**删除指定专题和素材
+     * @param int $id修改的主键
+     * @param $model_type要修改的表
+     * @throws \think\exception\DbException
+     */
+
+    public function delete($id = 0, $model_type = false)
+    {
+        if (!$id || !isset($model_type) || !$model_type) return Json::fail('缺少参数');
+        $model_table = $this->switch_model($model_type);
+        if (!$model_table) return Json::fail('缺少参数');
+        try {
+            $res_get = $model_table::get($id);
+            $model_table::startTrans();
+            if (!$res_get) return Json::fail('删除的数据不存在');
+            $res_del = $res_get->where('id',$id)->update(['is_del'=>1]);
+            if ($model_type == 'special' && $res_del) {
+                $model_source = $this->switch_model('source');
+                $get_source = $model_source::where('special_id', $id)->value('id');
+                if ($get_source) {
+                    $del_source = $model_source::where('special_id', $id)->delete();
+                }
+                if($res_get['lecturer_id']){
+                    $count=Db::name('learning_records')->where('special_id',$id)->count();
+                    $this->lecturerCurriculum($res_get['lecturer_id'],-1,$count);
+                }
+            }
+            $model_table::commit();
+            return Json::successful('删除成功');
+        } catch (\Exception $e) {
+            $model_table::rollback();
+            return Json::fail(SpecialTask::getErrorInfo('删除失败' . $e->getMessage()));
+        }
+    }
+
+    /**转换专题
+     * @param int $id修改的主键
+     * @param $model_type要修改的表
+     * @throws \think\exception\DbException
+     */
+
+    public function turnTo($id = 0, $model_type = false,$type=1)
+    {
+        if (!$id || !isset($model_type) || !$model_type) return Json::fail('缺少参数');
+        $model_table = $this->switch_model($model_type);
+        if (!$model_table) return Json::fail('缺少参数');
+        try {
+            $res_get = $model_table::get($id);
+            $model_table::startTrans();
+            if (!$res_get) return Json::fail('转换的数据不存在');
+            $res= $model_table::where('id',$id)->update(['type'=>$type]);
+            $model_table::commit();
+            return Json::successful('转换成功');
+        } catch (\Exception $e) {
+            $model_table::rollback();
+            return Json::fail(SpecialTask::getErrorInfo('转换失败' . $e->getMessage()));
+        }
+    }
+
+    /**
+     * 添加推荐
+     * @param int $special_id
+     * @return mixed
+     * @throws \think\exception\DbException
+     */
+    public function recommend($special_id = 0)
+    {
+        if (!$special_id) $this->failed('缺少参数');
+        $special = SpecialModel::get($special_id);
+        if (!$special) $this->failed('没有查到此专题');
+        if ($special->is_del) $this->failed('此专题已删除');
+        $form = Form::create(Url::build('save_recommend', ['special_id' => $special_id]), [
+            Form::select('recommend_id', '推荐')->setOptions(function () use ($special_id) {
+                $list = Recommend::where(['is_show' => 1,'type'=>0])->where('is_fixed', 0)->field('title,id')->order('sort desc,add_time desc')->select();
+                $menus = [];
+                foreach ($list as $menu) {
+                    $menus[] = ['value' => $menu['id'], 'label' => $menu['title']];
+                }
+                return $menus;
+            })->filterable(1),
+            Form::number('sort', '排序'),
+        ]);
+        $form->setMethod('post')->setTitle('推荐设置')->setSuccessScript('parent.$(".J_iframe:visible")[0].contentWindow.location.reload(); setTimeout(function(){parent.layer.close(parent.layer.getFrameIndex(window.name));},800);');
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 保存推荐
+     * @param int $special_id
+     * @throws \think\exception\DbException
+     */
+    public function save_recommend($special_id = 0)
+    {
+        if (!$special_id) $this->failed('缺少参数');
+        $data = parent::postMore([
+            ['recommend_id', 0],
+            ['sort', 0],
+        ]);
+        if (!$data['recommend_id']) return Json::fail('请选择推荐');
+        $recommend = Recommend::get($data['recommend_id']);
+        if (!$recommend) return Json::fail('导航菜单不存在');
+        $data['add_time'] = time();
+        $data['type'] = $recommend->type;
+        $data['link_id'] = $special_id;
+        if (RecommendRelation::be(['type' => $recommend->type, 'link_id' => $special_id, 'recommend_id' => $data['recommend_id']])) return Json::fail('已推荐,请勿重复推荐');
+        if (RecommendRelation::set($data))
+            return Json::successful('推荐成功');
+        else
+            return Json::fail('推荐失败');
+    }
+
+    /**取消推荐
+     * @param int $id
+     */
+    public function cancel_recommendation($id=0,$special_id=0)
+    {
+        if (!$id || !$special_id) $this->failed('缺少参数');
+        if (RecommendRelation::be(['id' => $id, 'link_id' => $special_id])){
+            $res=RecommendRelation::where(['id'=>$id,'link_id'=>$special_id])->delete();
+            if ($res)
+                return Json::successful('取消推荐成功');
+            else
+                return Json::fail('取消推荐失败');
+        }else{
+            return Json::fail('推荐不存在');
+        }
+    }
+    /**专题编辑内素材列表
+     * @param int $coures_id
+     * @return mixed
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function search_task($coures_id = 0)
+    {
+        $special_type = $this->request->param('special_type');
+        $special_id = $this->request->param('special_id');
+        $this->assign('coures_id', $coures_id);
+        $this->assign('special_title', SPECIAL_TYPE[$special_type]);
+        $this->assign('special_type', $special_type);//图文专题
+        $this->assign('activity_type', $this->request->param('activity_type', 1));
+        $this->assign('special_id', $special_id);
+        $this->assign('specialList', SpecialModel::PreWhere()->field(['id', 'title'])->select());
+        return $this->fetch('special/task/search_task');
+    }
+
+    public function searchs_task($coures_id=0)
+    {
+        $special_type = $this->request->param('special_type');
+        $special_id = $this->request->param('special_id');
+        $this->assign('coures_id', $coures_id);
+        $this->assign('special_title', SPECIAL_TYPE[$special_type]);
+        $this->assign('special_type', $special_type);//图文专题
+        $this->assign('special_id', $special_id);
+        $this->assign('cateList', SpecialTaskCategoryModel::taskCategoryAll());
+        return $this->fetch('special/task/searchs_task');
+    }
+
+    /**专题编辑内素材列表
+     * @param int $coures_id
+     * @return mixed
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function special_task($coures_id = 0)
+    {
+        $special_type = $this->request->param('special_type');
+        $special_id = $this->request->param('special_id');
+        $this->assign('coures_id', $coures_id);
+        $this->assign('special_title', SPECIAL_TYPE[$special_type]);
+        $this->assign('special_type', $special_type);//图文专题
+        $this->assign('activity_type', $this->request->param('activity_type', 1));
+        $this->assign('special_id', $special_id);
+        $this->assign('specialList', SpecialModel::PreWhere()->field(['id', 'title'])->select());
+        return $this->fetch('special/task/special_task');
+    }
+
+    /**直播专题编辑内商品列表
+     * @param int $coures_id
+     * @return mixed
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function store_task($coures_id = 0)
+    {
+        $special_id = $this->request->param('special_id');
+        $this->assign('special_id', $special_id);
+        $this->assign('cateList',StoreCategory::getTierList());
+        return $this->fetch('special/task/store_task');
+    }
+
+    /**
+     * @param int $coures_id
+     * @return mixed
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function create($coures_id = 0){
+        $special_type = $this->request->param('special_type');
+        $special_id = $this->request->param('special_id');
+        $this->assign('coures_id', $coures_id);
+        $this->assign('special_title', SPECIAL_TYPE[$special_type]);
+        $this->assign('special_type', $special_type);//图文专题
+        $this->assign('activity_type', $this->request->param('activity_type', 1));
+        $this->assign('special_id', $special_id);
+        $this->assign('specialList', SpecialModel::PreWhere()->field(['id', 'title'])->select());
+        return $this->fetch('special/task/create');
+    }
+
+    /**
+     * 专题弹幕列表和添加
+     * */
+    public function special_barrage()
+    {
+        $this->assign([
+            'type' => $this->request->param('type', 1),
+            'is_layui' => true,
+            'open_barrage' => SystemConfig::getValue('open_barrage'),
+        ]);
+        return $this->fetch('special/barrage/special_barrage');
+    }
+
+    /**
+     * 获取专题弹幕列表
+     * */
+    public function get_barrage_list($page = 1, $limit = 22)
+    {
+        $list = SpecialBarrage::where('is_show', 1)->order('sort desc,id desc')->page((int)$page, (int)$limit)->select();
+        $list = count($list) ? $list->toArray() : [];
+        $count = SpecialBarrage::where('is_show', 1)->count();
+        return Json::successful(compact('list', 'count'));
+    }
+
+    /**
+     * 删除某个弹幕
+     * @param int $id 弹幕id
+     * */
+    public function del_barrage($id = 0)
+    {
+        if (SpecialBarrage::del($id))
+            return Json::successful('删除成功');
+        else
+            return Json::fail('删除失败');
+    }
+
+    /**
+     * 保存专题弹幕
+     * */
+    public function save_barrage($id = 0)
+    {
+        $data = parent::postMore([
+            ['nickname', ''],
+            ['avatar', ''],
+            ['action', 0],
+            ['sort', 0],
+        ]);
+        if (!$data['nickname']) return Json::fail('请填写用户昵称');
+        if (!$data['avatar']) return Json::fail('请上传用户图像');
+        if (!$data['action']) return Json::fail('请勾选动作类型');
+        if ($id) {
+            SpecialBarrage::edit($data, $id);
+            return Json::successful('修改成功');
+        } else {
+            $data['add_time'] = time();
+            if (SpecialBarrage::set($data))
+                return Json::successful('添加成功');
+            else
+                return Json::fail('添加失败');
+        }
+    }
+
+    /**
+     * 设置虚拟用户弹幕是否开启
+     * */
+    public function set_barrage_show($value = 0, $key_nime = '')
+    {
+        if (!$key_nime) return Json::fail('缺少参数');
+        $confing = SystemConfig::where(['menu_name' => $key_nime])->find();
+        if ($confing) {
+            SystemConfig::edit(['value' => json_encode($value)], $confing->id);
+            return Json::successful('操作成功');
+        } else {
+            $res = SystemConfig::set([
+                'menu_name' => $key_nime,
+                'type' => 'radio',
+                'parameter' => "1=开启\n0=关闭",
+                'value' => '1',
+                'config_tab_id' => 1,
+                'upload_type' => 0,
+                'width' => '100%',
+                'info' => '虚拟用户专题弹幕开关',
+                'desc' => '虚拟用户专题弹幕开关',
+                'sort' => 0,
+                'status' => 1
+            ]);
+            if ($res)
+                return Json::successful('操作成功');
+            else
+                return Json::fail('操作失败');
+        }
+    }
+
+    /**渲染模板
+     * @param $special_type
+     * @param $template_type
+     * @return bool|string|void
+     */
+    protected function switch_template($special_type, $template_type)
+    {
+        if (!$special_type || !$template_type) {
+            return false;
+        }
+        switch ($special_type) {
+            case 1:
+                return 'special/image_text/' . $template_type;
+                break;
+            case 2:
+                return 'special/audio_video/' . $template_type;
+                break;
+            case 3:
+                return 'special/audio_video/' . $template_type;
+                break;
+            case 4:
+                return 'special/live/' . $template_type;
+                break;
+            case 5:
+                return 'special/column/' . $template_type;
+                break;
+            default:
+                return $this->failed('没有对应模板 ');
+        }
+    }
+
+}

+ 147 - 0
application/admin/controller/special/Subject.php

@@ -0,0 +1,147 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\special;
+
+use app\admin\model\special\SpecialSubject;
+use app\admin\model\special\Grade;
+use app\admin\model\special\Special;
+use think\Url;
+use service\FormBuilder as Form;
+use service\JsonService as Json;
+use app\admin\controller\AuthController;
+
+/**
+ * 科目控制器
+ * Class Grade
+ * @package app\admin\controller\special
+ */
+class Subject extends AuthController
+{
+    public function index($pid=0)
+    {
+        $this->assign('grade', Grade::getAll());
+        $this->assign('pid',$pid);
+        return $this->fetch();
+    }
+
+    public function get_subject_list()
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['pid',$this->request->param('pid','')],
+            ['name', ''],
+        ]);
+        return Json::successlayui(SpecialSubject::get_subject_list($where));
+    }
+
+    /**
+     * 显示创建资源表单页.
+     *
+     * @return \think\Response
+     */
+    public function create($id = 0)
+    {
+        if ($id) $subject = SpecialSubject::get($id);
+        $form = Form::create(Url::build('save', ['id' => $id]), [
+            Form::select('grade_id', '一级分类', isset($subject) ? (string)$subject->grade_id : 0)->setOptions(function () {
+                $list = Grade::getAll();
+                $menus = [['value' => 0, 'label' => '顶级菜单']];
+                foreach ($list as $menu) {
+                    $menus[] = ['value' => $menu['id'], 'label' => $menu['name']];
+                }
+                return $menus;
+            })->filterable(1),
+            Form::input('name', '分类名称', isset($subject) ? $subject->name : ''),
+            Form::frameImageOne('pic', '图标', Url::build('admin/widget.images/index', array('fodder' => 'pic')), isset($subject) ? $subject->pic : '')->icon('image')->width('70%')->height('500px'),
+            Form::number('sort', '排序', isset($subject) ? $subject->sort : 0),
+            Form::radio('is_show', '状态', isset($subject) ? $subject->is_show : 1)->options([['label' => '显示', 'value' => 1], ['label' => '隐藏', 'value' => 0]])
+        ]);
+        $form->setMethod('post')->setTitle($id ? '修改二级分类':'添加二级分类')->setSuccessScript('parent.$(".J_iframe:visible")[0].contentWindow.location.reload();');
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 新增或者修改
+     *
+     * @return json
+     */
+    public function save($id = 0)
+    {
+        $post = parent::postMore([
+            ['name', ''],
+            ['pic', ''],
+            ['is_show', 1],
+            ['grade_id', 0],
+            ['sort', 0],
+        ]);
+        if (!$post['name']) return Json::fail('请输入分类名称');
+        if (!$post['pic']) return Json::fail('请选择分类图标');
+        if (!$post['grade_id']) return Json::fail('请选择一级分类');
+        if ($id) {
+            SpecialSubject::update($post, ['id' => $id]);
+            return Json::successful('修改成功');
+        } else {
+            $post['add_time'] = time();
+            if (SpecialSubject::set($post))
+                return Json::successful('添加成功');
+            else
+                return Json::fail('添加失败');
+        }
+    }
+
+    /**
+     * 快速编辑
+     *
+     * @return json
+     */
+    public function set_value($field = '', $id = '', $value = '')
+    {
+        $field == '' || $id == '' || $value == '' && Json::fail('缺少参数');
+        if (SpecialSubject::where(['id' => $id])->update([$field => $value]))
+            return Json::successful('保存成功');
+        else
+            return Json::fail('保存失败');
+    }
+
+    /**二级分是否显示快捷操作
+     * @param string $is_show
+     * @param string $id
+     * @return mixed
+     */
+    public function set_show($is_show = '', $id = '')
+    {
+        ($is_show == '' || $id == '') && Json::fail('缺少参数');
+        $res = SpecialSubject::where(['id' => $id])->update(['is_show' => (int)$is_show]);
+        if ($res) {
+            return Json::successful($is_show == 1 ? '显示成功' : '隐藏成功');
+        } else {
+            return Json::fail($is_show == 1 ? '显示失败' : '隐藏失败');
+        }
+    }
+    /**
+     * 删除
+     *
+     * @return json
+     */
+    public function delete($id = 0)
+    {
+        if (!$id) return Json::fail('缺少参数');
+        if (Special::where('subject_id', $id)->where('is_del', 0)->count()) return Json::fail('暂无法删除,请先去除专题关联');
+        $data['is_del']=1;
+        if (SpecialSubject::update($data,['id'=>$id]))
+            return Json::successful('删除成功');
+        else
+            return Json::fail('删除成功');
+    }
+}

+ 193 - 0
application/admin/controller/special/Task.php

@@ -0,0 +1,193 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\special;
+
+use app\admin\controller\AuthController;
+use app\admin\model\special\SpecialCourse;
+use app\admin\model\special\SpecialTask;
+use service\JsonService;
+use think\Url;
+
+/**
+ * 任务控制器
+ * Class Grade
+ * @package app\admin\controller\special
+ */
+class Task extends AuthController
+{
+    /**
+     * 任务列表展示
+     * @return
+     * */
+    public function index($coures_id = 0)
+    {
+        $this->assign('coures_id', $coures_id);
+        $this->assign('special_id', SpecialCourse::where('id', $coures_id)->value('special_id'));
+        $this->assign('specialList', \app\admin\model\special\Special::PreWhere()->field(['id', 'title'])->select());
+        return $this->fetch();
+    }
+
+    /**
+     * 任务列表获取
+     * @return json
+     * */
+    public function task_list()
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['is_show', ''],
+            ['limit', 20],
+            ['title', ''],
+            ['order', ''],
+            ['special_id', 0],
+        ]);
+        return JsonService::successlayui(SpecialTask::getTaskList($where));
+
+    }
+
+    /**
+     * 添加和修改任务
+     * @param int $id 修改
+     * @return
+     * */
+    public function add_task($id = 0)
+    {
+        $this->assign('id', $id);
+        if ($id) {
+            $task = SpecialTask::get($id);
+            $task->image = get_key_attr($task->image);
+            $task->link = get_key_attr($task->link);
+            $this->assign('special_id', $task->special_id);
+            $this->assign('task', $task->toArray());
+        }
+        $specialList = \app\admin\model\special\Special::PreWhere()->field(['id', 'title', 'is_live'])->select();
+        $this->assign('specialList', $specialList);
+        return $this->fetch();
+    }
+
+    /**
+     * 添加和修改任务
+     * @param int $id 修改
+     * @return json
+     * */
+    public function save_task($id = 0)
+    {
+        $data = parent::postMore([
+            ['title', ''],
+            ['image', ''],
+            ['link', ''],
+            ['play_count', 0],
+            ['special_id', 0],
+            ['sort', 0],
+            ['is_pay', 0],
+            ['is_show', 1],
+        ]);
+        if ($data['special_id'] === 0) return JsonService::fail('请选择课程再尝试添加');
+        if (!$data['title']) return JsonService::fail('请输入课程标题');
+        if (!$data['image']) return JsonService::fail('请上传封面图');
+        if (!$data['link']) return JsonService::fail('请上传或者添加视频');
+        if ($id) {
+            unset($data['is_show']);
+            SpecialTask::update($data, ['id' => $id]);
+            return JsonService::successful('修改成功');
+        } else {
+            $data['add_time'] = time();
+            if (SpecialTask::set($data))
+                return JsonService::successful('添加成功');
+            else
+                return JsonService::fail('添加失败');
+        }
+    }
+
+    /**
+     * 设置单个产品上架|下架
+     * @param int $is_show 是否显示
+     * @param int $id 修改的主键
+     * @return json
+     */
+    public function set_show($is_show = '', $id = '')
+    {
+        ($is_show == '' || $id == '') && JsonService::fail('缺少参数');
+        $res = SpecialTask::where(['id' => $id])->update(['is_show' => (int)$is_show]);
+        if ($res) {
+            return JsonService::successful($is_show == 1 ? '显示成功' : '隐藏成功');
+        } else {
+            return JsonService::fail($is_show == 1 ? '显示失败' : '隐藏失败');
+        }
+    }
+
+    /**
+     * 快速编辑
+     * @param string $field 字段名
+     * @param int $id 修改的主键
+     * @param string value 修改后的值
+     * @return json
+     */
+    public function set_value($field = '', $id = '', $value = '')
+    {
+        $field == '' || $id == '' || $value == '' && JsonService::fail('缺少参数');
+        if (SpecialTask::where(['id' => $id])->update([$field => $value]))
+            return JsonService::successful('保存成功');
+        else
+            return JsonService::fail('保存失败');
+    }
+
+    /**
+     * 删除指定任务并删除指定资源
+     * @param int $id 修改的主键
+     * @return json
+     * */
+    public function delete($id = 0)
+    {
+        if (!$id) return JsonService::fail('缺少参数');
+        if (SpecialTask::delTask($id))
+            return JsonService::successful('删除成功');
+        else
+            return JsonService::fail(SpecialTask::getErrorInfo('删除失败'));
+    }
+
+    /**
+     * 编辑详情
+     * @return mixed
+     */
+    public function update_content($id = 0)
+    {
+        if (!$id) {
+            return $this->failed('缺少id ');
+        }
+        $this->assign([
+            'action' => Url::build('save_content', ['id' => $id]),
+            'field' => 'content',
+            'content' => htmlspecialchars_decode(SpecialTask::where('id', $id)->value('content'))
+        ]);
+        return $this->fetch();
+    }
+
+    /**
+     * @param $id
+     * @throws \think\exception\DbException
+     */
+    public function save_content($id)
+    {
+        $content = $this->request->post('content', '');
+        $task = SpecialTask::get($id);
+        if (!$task) {
+            return JsonService::fail('修改得课程不存在');
+        }
+        $task->content = htmlspecialchars($content);
+        if ($task->save()) {
+            return JsonService::successful('保存成功');
+        } else {
+            return JsonService::fail('保存失败或者您没有修改什么');
+        }
+    }
+}

+ 179 - 0
application/admin/controller/store/StoreCategory.php

@@ -0,0 +1,179 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\store;
+
+use app\admin\controller\AuthController;
+use service\FormBuilder as Form;
+use service\JsonService as Json;
+use service\UploadService as Upload;
+use think\Request;
+use app\admin\model\store\StoreCategory as CategoryModel;
+use think\Url;
+use app\admin\model\system\SystemAttachment;
+
+/**
+ * 产品分类控制器
+ * Class StoreCategory
+ * @package app\admin\controller\system
+ */
+class StoreCategory extends AuthController
+{
+
+    /**
+     * 显示资源列表
+     *
+     * @return \think\Response
+     */
+    public function index()
+    {
+        $this->assign('pid', $this->request->get('pid', 0));
+        $this->assign('cate', CategoryModel::getTierList());
+        return $this->fetch();
+    }
+
+    /**
+     *  异步获取分类列表
+     * @return json
+     */
+    public function category_list()
+    {
+        $where = parent::getMore([
+            ['is_show', ''],
+            ['pid', $this->request->param('pid', '')],
+            ['cate_name', ''],
+            ['page', 1],
+            ['limit', 20],
+            ['order', '']
+        ]);
+        return Json::successlayui(CategoryModel::CategoryList($where));
+    }
+
+    /**
+     * 设置单个产品上架|下架
+     *
+     * @return json
+     */
+    public function set_show($is_show = '', $id = '')
+    {
+        ($is_show == '' || $id == '') && Json::fail('缺少参数');
+        $res = CategoryModel::where(['id' => $id])->update(['is_show' => (int)$is_show]);
+        if ($res) {
+            return Json::successful($is_show == 1 ? '显示成功' : '隐藏成功');
+        } else {
+            return Json::fail($is_show == 1 ? '显示失败' : '隐藏失败');
+        }
+    }
+
+    /**
+     * 快速编辑
+     *
+     * @return json
+     */
+    public function set_category($field = '', $id = '', $value = '')
+    {
+        $field == '' || $id == '' || $value == '' && Json::fail('缺少参数');
+        if (CategoryModel::where(['id' => $id])->update([$field => $value]))
+            return Json::successful('保存成功');
+        else
+            return Json::fail('保存失败');
+    }
+
+    /**
+     * 显示创建资源表单页.
+     *
+     * @return \think\Response
+     */
+    public function create($id = 0)
+    {
+        $cate=[];
+        if ($id){
+            $cate = CategoryModel::get($id);
+        }
+        $this->assign(['cate'=>json_encode($cate),'id'=>$id]);
+        return $this->fetch();
+    }
+
+    /**
+     * 一级分类
+     */
+    public function get_cate_list()
+    {
+        $list=CategoryModel::where('pid',0)->where('is_show',1)->select();
+        return Json::successful($list);
+    }
+
+    /**
+     * 上传图片
+     * @return \think\response\Json
+     */
+    public function upload()
+    {
+        $res = Upload::image('file', 'store/category' . date('Ymd'));
+        $thumbPath = Upload::thumb($res->dir);
+        //产品图片上传记录
+        $fileInfo = $res->fileInfo->getinfo();
+        SystemAttachment::attachmentAdd($res->fileInfo->getSaveName(), $fileInfo['size'], $fileInfo['type'], $res->dir, $thumbPath, 1);
+
+        if ($res->status == 200)
+            return Json::successful('图片上传成功!', ['name' => $res->fileInfo->getSaveName(), 'url' => Upload::pathToUrl($thumbPath)]);
+        else
+            return Json::fail($res->error);
+    }
+
+    /**
+     * 保存新建的资源
+     *
+     * @param  \think\Request $request
+     * @return \think\Response
+     */
+    public function save(Request $request,$id=0)
+    {
+        $data = parent::postMore([
+            'pid',
+            'cate_name',
+            ['pic', []],
+            'sort',
+            ['is_show', 0]
+        ], $request);
+        if ($data['pid'] == '') return Json::fail('请选择父类');
+        if (!$data['cate_name']) return Json::fail('请输入分类名称');
+        if($data['pid'] >0){
+            if (count($data['pic']) < 1) return Json::fail('请上传分类图标');
+        }
+        if ($data['sort'] < 0) $data['sort'] = 0;
+        $data['pic'] = $data['pic'][0];
+        if($id){
+            CategoryModel::edit($data, $id);
+            return Json::successful('修改成功!');
+        }else{
+            $data['add_time'] = time();
+            if(CategoryModel::be(['cate_name'=>$data['cate_name']])){
+                return Json::fail('分类名称已存在!');
+            }
+            CategoryModel::set($data);
+            return Json::successful('添加分类成功!');
+        }
+    }
+    /**
+     * 删除指定资源
+     *
+     * @param  int $id
+     * @return \think\Response
+     */
+    public function delete($id)
+    {
+        if (!CategoryModel::delCategory($id))
+            return Json::fail(CategoryModel::getErrorInfo('删除失败,请删除字分类后再试!'));
+        else
+            return Json::successful('删除成功!');
+    }
+}

+ 479 - 0
application/admin/controller/store/StoreProduct.php

@@ -0,0 +1,479 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\store;
+
+use app\admin\controller\AuthController;
+use app\admin\model\system\Recommend;
+use app\admin\model\system\RecommendRelation;
+use service\FormBuilder as Form;
+use app\admin\model\store\StoreProductAttr;
+use app\admin\model\store\StoreProductAttrResult;
+use app\admin\model\store\StoreProductRelation;
+use app\admin\model\system\SystemConfig;
+use service\JsonService as Json;
+use service\SystemConfigService;
+use traits\CurdControllerTrait;
+use service\UploadService as Upload;
+use think\Request;
+use app\admin\model\store\StoreCategory as CategoryModel;
+use app\admin\model\store\StoreProduct as ProductModel;
+use think\Url;
+use app\admin\model\system\SystemAttachment;
+
+
+/**
+ * 产品管理
+ * Class StoreProduct
+ * @package app\admin\controller\store
+ */
+class StoreProduct extends AuthController
+{
+
+    use CurdControllerTrait;
+
+    protected $bindModel = ProductModel::class;
+
+    /**
+     * 显示资源列表
+     *
+     * @return \think\Response
+     */
+    public function index()
+    {
+
+        $type = $this->request->param('type');
+        //获取分类
+        $this->assign('cate', CategoryModel::getTierList());
+        //出售中产品
+        $onsale = ProductModel::where(['is_show' => 1, 'is_del' => 0])->count();
+        //待上架产品
+        $forsale = ProductModel::where(['is_show' => 0, 'is_del' => 0])->count();
+        //仓库中产品
+        $warehouse = ProductModel::where(['is_del' => 0])->count();
+        //已经售馨产品
+        $outofstock = ProductModel::getModelObject()->where(ProductModel::setData(4))->count();
+        //警戒库存
+        $policeforce = ProductModel::getModelObject()->where(ProductModel::setData(5))->count();
+        //回收站
+        $recycle = ProductModel::where(['is_del' => 1])->count();
+
+        $this->assign(compact('type', 'onsale', 'forsale', 'warehouse', 'outofstock', 'policeforce', 'recycle'));
+        return $this->fetch();
+    }
+
+    /**
+     * 异步查找产品
+     *
+     * @return json
+     */
+    public function product_ist()
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['store_name', ''],
+            ['cate_id', ''],
+            ['excel', 0],
+            ['type', $this->request->param('type')]
+        ]);
+        return Json::successlayui(ProductModel::ProductList($where));
+    }
+
+    /**
+     * 设置单个产品上架|下架
+     *
+     * @return json
+     */
+    public function set_show($is_show = '', $id = '')
+    {
+        ($is_show == '' || $id == '') && Json::fail('缺少参数');
+        $res = ProductModel::where(['id' => $id])->update(['is_show' => (int)$is_show]);
+        if ($res) {
+            return Json::successful($is_show == 1 ? '上架成功' : '下架成功');
+        } else {
+            return Json::fail($is_show == 1 ? '上架失败' : '下架失败');
+        }
+    }
+
+    /**
+     * 快速编辑
+     *
+     * @return json
+     */
+    public function set_product($field = '', $id = '', $value = '')
+    {
+        $field == '' || $id == '' || $value == '' && Json::fail('缺少参数');
+        if (ProductModel::where(['id' => $id])->update([$field => $value]))
+            return Json::successful('保存成功');
+        else
+            return Json::fail('保存失败');
+    }
+
+    /**
+     * 设置批量产品上架
+     *
+     * @return json
+     */
+    public function product_show()
+    {
+        $post = parent::postMore([
+            ['ids', []]
+        ]);
+        if (empty($post['ids'])) {
+            return Json::fail('请选择需要上架的产品');
+        } else {
+            $res = ProductModel::where('id', 'in', $post['ids'])->update(['is_show' => 1]);
+            if ($res)
+                return Json::successful('上架成功');
+            else
+                return Json::fail('上架失败');
+        }
+    }
+
+    public function create($id=0)
+    {
+        $gold_name=SystemConfigService::get('gold_name');//虚拟币名称
+        if($id){
+            $product = ProductModel::get($id);
+            if (!$product) return Json::fail('数据不存在!');
+            $slider_image=[];
+            if($product['slider_image']){
+                foreach (json_decode($product['slider_image']) as $key=>$value){
+                    $image['pic']=$value;
+                    $image['is_show']=false;
+                    array_push($slider_image,$image);
+                }
+
+            }
+            $product['slider_image']=$slider_image;
+        }else{
+            $product=[];
+        }
+        $this->assign(['id'=> $id,'product'=>json_encode($product),'gold_name'=>$gold_name]);
+        return $this->fetch();
+    }
+    public function getCateList()
+    {
+        $list=CategoryModel::where('is_show',1)->where('pid',0)->select();
+        $list=count($list) >0 ? $list->toArray() : [];
+        return Json::successful($list);
+    }
+    /**
+     * 上传图片
+     * @return \think\response\Json
+     */
+    public function upload()
+    {
+        $res = Upload::image('file', 'store/product/' . date('Ymd'));
+        $thumbPath = Upload::thumb($res->dir);
+        //产品图片上传记录
+        $fileInfo = $res->fileInfo->getinfo();
+        SystemAttachment::attachmentAdd($res->fileInfo->getSaveName(), $fileInfo['size'], $fileInfo['type'], $res->dir, $thumbPath, 1);
+        if ($res->status == 200)
+            return Json::successful('图片上传成功!', ['name' => $res->fileInfo->getSaveName(), 'url' => Upload::pathToUrl($thumbPath)]);
+        else
+            return Json::fail($res->error);
+    }
+
+    /**
+     * 保存新建的资源
+     *
+     * @param  \think\Request $request
+     * @return \think\Response
+     */
+    public function save(Request $request,$id=0)
+    {
+        $data = parent::postMore([
+            ['cate_id', ""],
+            'store_name',
+            'store_info',
+            'keyword',
+            ['unit_name', '件'],
+            ['image', []],
+            ['slider_image', []],
+            'postage',
+            'price',
+            'vip_price',
+            'ot_price',
+            'free_shipping',
+            'sort',
+            'stock',
+            'give_gold_num',
+            'ficti',
+            'description',
+            ['is_show', 0],
+            ['cost', 0],
+            ['is_postage', 0],
+            ['member_pay_type', 0],
+        ], $request);
+        if ($data['cate_id'] == "") return Json::fail('请选择商品分类');
+        if (!$data['store_name']) return Json::fail('请输入商品名称');
+        if (!$data['description']) return Json::fail('请输入商品详情');
+        if (count($data['image']) < 1) return Json::fail('请上传商品图片');
+        if (count($data['slider_image']) < 1) return Json::fail('请上传商品轮播图');
+        if ($data['price'] == '' || $data['price'] < 0) return Json::fail('请输入商品售价');
+        if ($data['ot_price'] == '' || $data['ot_price'] < 0) return Json::fail('请输入商品原价');
+        if ($data['vip_price'] == '' || $data['vip_price'] < 0) return Json::fail('请输入商品会员价');
+        if ($data['postage'] == '' || $data['postage'] < 0) return Json::fail('请输入邮费');
+        if ($data['stock'] == '' || $data['stock'] < 0) return Json::fail('请输入商品库存');
+        if ($data['cost'] == '' || $data['ot_price'] < 0) return Json::fail('请输入商品成本价');
+        $data['image'] = $data['image'][0];
+        $slider_image=[];
+        foreach ($data['slider_image'] as $item) {
+            $slider_image[] = $item['pic'];
+        }
+        $data['slider_image'] = json_encode($slider_image);
+        if($id){
+            ProductModel::edit($data,$id);
+            return Json::successful('修改产品成功!');
+        }else{
+            $data['add_time'] = time();
+            ProductModel::set($data);
+            return Json::successful('添加产品成功!');
+        }
+    }
+    /**
+     * 添加推荐
+     * @param int $product_id
+     * @return mixed
+     * @throws \think\exception\DbException
+     */
+    public function recommend($product_id = 0)
+    {
+        if (!$product_id) $this->failed('缺少参数');
+        $special = ProductModel::get($product_id);
+        if (!$special) $this->failed('没有查到此专题');
+        if ($special->is_del) $this->failed('此专题已删除');
+        $form = Form::create(Url::build('save_recommend', ['product_id' => $product_id]), [
+            Form::select('recommend_id', '推荐')->setOptions(function () use ($product_id) {
+                $list = Recommend::where(['is_show' => 1,'type'=>4])->where('is_fixed', 0)->field('title,id')->order('sort desc,add_time desc')->select();
+                $menus = [];
+                foreach ($list as $menu) {
+                    $menus[] = ['value' => $menu['id'], 'label' => $menu['title']];
+                }
+                return $menus;
+            })->filterable(1),
+            Form::number('sort', '排序'),
+        ]);
+        $form->setMethod('post')->setTitle('推荐设置')->setSuccessScript('parent.$(".J_iframe:visible")[0].contentWindow.location.reload(); setTimeout(function(){parent.layer.close(parent.layer.getFrameIndex(window.name));},800);');
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 保存推荐
+     * @param int $special_id
+     * @throws \think\exception\DbException
+     */
+    public function save_recommend($product_id = 0)
+    {
+        if (!$product_id) $this->failed('缺少参数');
+        $data = parent::postMore([
+            ['recommend_id', 0],
+            ['sort', 0],
+        ]);
+        if (!$data['recommend_id']) return Json::fail('请选择推荐');
+        $recommend = Recommend::get($data['recommend_id']);
+        if (!$recommend) return Json::fail('导航菜单不存在');
+        $data['add_time'] = time();
+        $data['type'] = $recommend->type;
+        $data['link_id'] = $product_id;
+        if (RecommendRelation::be(['type' => $recommend->type, 'link_id' => $product_id, 'recommend_id' => $data['recommend_id']])) return Json::fail('已推荐,请勿重复推荐');
+        if (RecommendRelation::set($data))
+            return Json::successful('推荐成功');
+        else
+            return Json::fail('推荐失败');
+    }
+    /**取消推荐
+     * @param int $id
+     */
+    public function cancel_recommendation($id=0,$product_id=0)
+    {
+        if (!$id || !$product_id) $this->failed('缺少参数');
+        if (RecommendRelation::be(['id' => $id, 'link_id' => $product_id])){
+            $res=RecommendRelation::where(['id'=>$id,'link_id'=>$product_id])->delete();
+            if ($res)
+                return Json::successful('取消推荐成功');
+            else
+                return Json::fail('取消推荐失败');
+        }else{
+            return Json::fail('推荐不存在');
+        }
+    }
+    public function attr($id)
+    {
+        if (!$id) return $this->failed('数据不存在!');
+        $result = StoreProductAttrResult::getResult($id);
+        $image = ProductModel::where('id', $id)->value('image');
+        $this->assign(compact('id', 'result', 'product', 'image'));
+        return $this->fetch();
+    }
+
+    /**
+     * 生成属性
+     * @param int $id
+     */
+    public function is_format_attr($id = 0)
+    {
+        if (!$id) return Json::fail('产品不存在');
+        list($attr, $detail) = parent::postMore([
+            ['items', []],
+            ['attrs', []]
+        ], $this->request, true);
+        $product = ProductModel::get($id);
+        if (!$product) return Json::fail('产品不存在');
+        $attrFormat = attrFormat($attr)[1];
+        if (count($detail)) {
+            foreach ($attrFormat as $k => $v) {
+                foreach ($detail as $kk => $vv) {
+                    if ($v['detail'] == $vv['detail']) {
+                        $attrFormat[$k]['price'] = $vv['price'];
+                        $attrFormat[$k]['vip_price'] = $vv['vip_price'];
+                        $attrFormat[$k]['cost'] = isset($vv['cost']) ? $vv['cost'] : $product['cost'];
+                        $attrFormat[$k]['sales'] = $vv['sales'];
+                        $attrFormat[$k]['pic'] = $vv['pic'];
+                        $attrFormat[$k]['check'] = false;
+                        break;
+                    } else {
+                        $attrFormat[$k]['cost'] = $product['cost'];
+                        $attrFormat[$k]['price'] = '';
+                        $attrFormat[$k]['vip_price'] = '';
+                        $attrFormat[$k]['sales'] = '';
+                        $attrFormat[$k]['pic'] = $product['image'];
+                        $attrFormat[$k]['check'] = true;
+                    }
+                }
+            }
+        } else {
+            foreach ($attrFormat as $k => $v) {
+                $attrFormat[$k]['cost'] = $product['cost'];
+                $attrFormat[$k]['price'] = $product['price'];
+                $attrFormat[$k]['vip_price'] = $product['vip_price'];
+                $attrFormat[$k]['sales'] = $product['stock'];
+                $attrFormat[$k]['pic'] = $product['image'];
+                $attrFormat[$k]['check'] = false;
+            }
+        }
+        return Json::successful($attrFormat);
+    }
+
+    public function set_attr($id)
+    {
+        if (!$id) return $this->failed('产品不存在!');
+        list($attr, $detail) = parent::postMore([
+            ['items', []],
+            ['attrs', []]
+        ], $this->request, true);
+        $res = StoreProductAttr::createProductAttr($attr, $detail, $id);
+        if ($res)
+            return $this->successful('编辑属性成功!');
+        else
+            return $this->failed(StoreProductAttr::getErrorInfo());
+    }
+
+    public function clear_attr($id)
+    {
+        if (!$id) return $this->failed('产品不存在!');
+        if (false !== StoreProductAttr::clearProductAttr($id) && false !== StoreProductAttrResult::clearResult($id))
+            return $this->successful('清空产品属性成功!');
+        else
+            return $this->failed(StoreProductAttr::getErrorInfo('清空产品属性失败!'));
+    }
+
+    /**
+     * 删除指定资源
+     *
+     * @param  int $id
+     * @return \think\Response
+     */
+    public function delete($id)
+    {
+        if(!$id) return $this->failed('数据不存在');
+        if(!ProductModel::be(['id'=>$id])) return $this->failed('产品数据不存在');
+        if(ProductModel::be(['id'=>$id,'is_del'=>1])){
+            $data['is_del'] = 0;
+            if(!ProductModel::edit($data,$id))
+                return Json::fail(ProductModel::getErrorInfo('恢复失败,请稍候再试!'));
+            else
+                return Json::successful('成功恢复产品!');
+        }else{
+            $data['is_del'] = 1;
+            if (!ProductModel::edit($data, $id))
+                return Json::fail(ProductModel::getErrorInfo('删除失败,请稍候再试!'));
+            else
+                return Json::successful('删除成功!');
+        }
+    }
+
+
+    /**
+     * 点赞
+     * @param $id
+     * @return mixed|\think\response\Json|void
+     */
+    public function collect($id)
+    {
+        if (!$id) return $this->failed('数据不存在');
+        $product = ProductModel::get($id);
+        if (!$product) return Json::fail('数据不存在!');
+        $this->assign(StoreProductRelation::getCollect($id));
+        return $this->fetch();
+    }
+
+    /**
+     * 收藏
+     * @param $id
+     * @return mixed|\think\response\Json|void
+     */
+    public function like($id)
+    {
+        if (!$id) return $this->failed('数据不存在');
+        $product = ProductModel::get($id);
+        if (!$product) return Json::fail('数据不存在!');
+        $this->assign(StoreProductRelation::getLike($id));
+        return $this->fetch();
+    }
+
+    /**
+     * 修改产品价格
+     * @param Request $request
+     */
+    public function edit_product_price(Request $request)
+    {
+        $data = parent::postMore([
+            ['id', 0],
+            ['price', 0],
+        ], $request);
+        if (!$data['id']) return Json::fail('参数错误');
+        $res = ProductModel::edit(['price' => $data['price']], $data['id']);
+        if ($res) return Json::successful('修改成功');
+        else return Json::fail('修改失败');
+    }
+
+    /**
+     * 修改产品库存
+     * @param Request $request
+     */
+    public function edit_product_stock(Request $request)
+    {
+        $data = parent::postMore([
+            ['id', 0],
+            ['stock', 0],
+        ], $request);
+        if (!$data['id']) return Json::fail('参数错误');
+        $res = ProductModel::edit(['stock' => $data['stock']], $data['id']);
+        if ($res) return Json::successful('修改成功');
+        else return Json::fail('修改失败');
+    }
+
+
+}

+ 103 - 0
application/admin/controller/store/StoreProductReply.php

@@ -0,0 +1,103 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\store;
+
+use app\admin\controller\AuthController;
+use traits\CurdControllerTrait;
+use service\JsonService as Json;
+use service\UploadService as Upload;
+use think\Request;
+use app\admin\model\store\StoreProductReply as ProductReplyModel;
+use think\Url;
+
+/**
+ * 评论管理 控制器
+ * Class StoreProductReply
+ * @package app\admin\controller\store
+ */
+class StoreProductReply extends AuthController
+{
+
+    use CurdControllerTrait;
+
+    /**
+     * 显示资源列表
+     *
+     * @return \think\Response
+     */
+    public function index()
+    {
+        $where = parent::getMore([
+            ['is_reply', ''],
+            ['comment', ''],
+        ], $this->request);
+        $product_id = input('product_id', 0);
+        if ($product_id)
+            $where['product_id'] = $product_id;
+        else
+            $where['product_id'] = 0;
+        $this->assign('where', $where);
+        $this->assign(ProductReplyModel::systemPage($where));
+        return $this->fetch();
+    }
+
+    /**
+     * @param $id
+     * @return \think\response\Json|void
+     */
+    public function delete($id)
+    {
+        if (!$id) return $this->failed('数据不存在');
+        $data['is_del'] = 1;
+        if (!ProductReplyModel::edit($data, $id))
+            return Json::fail(ProductReplyModel::getErrorInfo('删除失败,请稍候再试!'));
+        else
+            return Json::successful('删除成功!');
+    }
+
+    public function set_reply(Request $request)
+    {
+        $data = parent::postMore([
+            'id',
+            'content',
+        ], $request);
+        if (!$data['id']) return Json::fail('参数错误');
+        if ($data['content'] == '') return Json::fail('请输入回复内容');
+        $save['merchant_reply_content'] = $data['content'];
+        $save['merchant_reply_time'] = time();
+        $save['is_reply'] = 2;
+        $res = ProductReplyModel::edit($save, $data['id']);
+        if (!$res)
+            return Json::fail(ProductReplyModel::getErrorInfo('回复失败,请稍候再试!'));
+        else
+            return Json::successful('回复成功!');
+    }
+
+    public function edit_reply(Request $request)
+    {
+        $data = parent::postMore([
+            'id',
+            'content',
+        ], $request);
+        if (!$data['id']) return Json::fail('参数错误');
+        if ($data['content'] == '') return Json::fail('请输入回复内容');
+        $save['merchant_reply_content'] = $data['content'];
+        $save['merchant_reply_time'] = time();
+        $save['is_reply'] = 2;
+        $res = ProductReplyModel::edit($save, $data['id']);
+        if (!$res)
+            return Json::fail(ProductReplyModel::getErrorInfo('回复失败,请稍候再试!'));
+        else
+            return Json::successful('回复成功!');
+    }
+
+}

+ 82 - 0
application/admin/controller/system/Clear.php

@@ -0,0 +1,82 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\system;
+
+use app\admin\controller\AuthController;
+use service\CacheService;
+use service\JsonService as Json;
+use think\Log;
+use think\Cache;
+
+/**
+ * 首页控制器
+ * Class Clear
+ * @package app\admin\controller
+ *
+ */
+class Clear extends AuthController
+{
+    public function index()
+    {
+        return $this->fetch();
+    }
+
+    /**
+     * 刷新数据缓存
+     */
+    public function refresh_cache()
+    {
+        `php think optimize:schema`;
+        `php think optimize:autoload`;
+        `php think optimize:route`;
+        `php think optimize:config`;
+        return Json::successful('数据缓存刷新成功!');
+    }
+
+    /**
+     * 删除缓存
+     */
+    public function delete_cache()
+    {
+        Cache::clear();
+        array_map('unlink', glob(TEMP_PATH . '/*.php'));
+        return Json::successful('清除缓存成功!');
+    }
+
+    /**
+     * 删除日志
+     */
+    public function delete_log()
+    {
+        array_map('unlink', glob(LOG_PATH . '/*.log'));
+        $this->delDirAndFile(LOG_PATH);
+        return Json::successful('清除日志成功!');
+    }
+
+    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);
+        }
+    }
+}
+
+

+ 139 - 0
application/admin/controller/system/Express.php

@@ -0,0 +1,139 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\system;
+
+use service\FormBuilder as Form;
+use service\JsonService as Json;
+use think\Request;
+use think\Url;
+use app\admin\model\system\Express as ExpressModel;
+use app\admin\controller\AuthController;
+
+/**
+ * 物流公司管理控制器
+ * Class SystemMenus
+ * @package app\admin\controller\system
+ */
+class Express extends AuthController
+{
+
+
+    /**
+     * 显示资源列表
+     *
+     * @return \think\Response
+     */
+    public function index()
+    {
+        $params = parent::getMore([
+            ['keyword', '']
+        ], $this->request);
+        $this->assign(ExpressModel::systemPage($params));
+        $this->assign(compact('params'));
+        return $this->fetch();
+    }
+
+
+    /**
+     * 显示创建资源表单页.
+     *
+     * @return \think\Response
+     */
+    public function create($cid = 0)
+    {
+        $formbuider = [
+            Form::input('name', '公司名称')->required('公司名称名称必填'),
+            Form::input('code', '编码'),
+            Form::number('sort', '排序', 0),
+            Form::radio('is_show', '是否启用', 1)->options([['value' => 0, 'label' => '隐藏'], ['value' => 1, 'label' => '启用']]),
+        ];
+        $form = Form::make_post_form('添加物流公司', $formbuider, Url::build('save'), 2);
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 保存新建的资源
+     *
+     * @param  \think\Request $request
+     * @return \think\Response
+     */
+    public function save(Request $request)
+    {
+        $data = parent::postMore([
+            'name',
+            'code',
+            ['sort', 0],
+            ['is_show', 0]], $request);
+        if (!$data['name']) return Json::fail('请输入公司名称');
+        ExpressModel::set($data);
+        return Json::successful('添加公司成功!');
+    }
+
+    /**
+     * 显示编辑资源表单页.
+     *
+     * @param  int $id
+     * @return \think\Response
+     */
+    public function edit($id)
+    {
+        $menu = ExpressModel::get($id);
+        if (!$menu) return Json::fail('数据不存在!');
+        $formbuider = [
+            Form::input('name', '公司名称', $menu['name']),
+            Form::input('code', '编码', $menu['code']),
+            Form::number('sort', '排序', $menu['sort']),
+            Form::radio('is_show', '是否启用', $menu['is_show'])->options([['value' => 0, 'label' => '隐藏'], ['value' => 1, 'label' => '启用']])
+        ];
+        $form = Form::make_post_form('添加物流公司', $formbuider, Url::build('update', array('id' => $id)), 2);
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 保存更新的资源
+     *
+     * @param  \think\Request $request
+     * @param  int $id
+     * @return \think\Response
+     */
+    public function update(Request $request, $id)
+    {
+        $data = parent::postMore([
+            'name',
+            'code',
+            ['sort', 0],
+            ['is_show', 0]], $request);
+        if (!$data['name']) return Json::fail('请输入公司名称');
+        if (!ExpressModel::get($id)) return Json::fail('编辑的记录不存在!');
+        ExpressModel::edit($data, $id);
+        return Json::successful('修改成功!');
+    }
+
+    /**
+     * 删除指定资源
+     *
+     * @param  int $id
+     * @return \think\Response
+     */
+    public function delete($id)
+    {
+        if (!$id) return $this->failed('参数错误,请重新打开');
+        $res = ExpressModel::destroy($id);
+        if (!$res)
+            return Json::fail(ExpressModel::getErrorInfo('删除失败,请稍候再试!'));
+        else
+            return Json::successful('删除成功!');
+    }
+
+}

+ 84 - 0
application/admin/controller/system/SystemAttachment.php

@@ -0,0 +1,84 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\system;
+
+use app\admin\model\system\SystemAttachment as SystemAttachmentModel;
+use app\admin\controller\AuthController;
+use service\SystemConfigService;
+use service\UploadService as Upload;
+
+/**
+ * 附件管理控制器
+ * Class SystemAttachment
+ * @package app\admin\controller\system
+ *
+ */
+class SystemAttachment extends AuthController
+{
+
+    /**
+     * 编辑器上传图片
+     * @return \think\response\Json
+     */
+    public function upload()
+    {
+        $res = Upload::image('upfile', 'editor/' . date('Ymd'));
+        //产品图片上传记录
+        $fileInfo = $res->fileInfo->getinfo();
+        $thumbPath = Upload::thumb($res->dir);
+        SystemAttachmentModel::attachmentAdd($res->fileInfo->getSaveName(), $fileInfo['size'], $fileInfo['type'], $res->dir, $thumbPath, 0);
+        $info = array(
+            "originalName" => $fileInfo['name'],
+            "name" => $res->fileInfo->getSaveName(),
+            "url" => '.' . $res->dir,
+            "size" => $fileInfo['size'],
+            "type" => $fileInfo['type'],
+            "state" => "SUCCESS"
+        );
+        echo json_encode($info);
+    }
+
+    public function index($action)
+    {
+        $CONFIG = json_decode(preg_replace("/\/\*[\s\S]+?\*\//", "", file_get_contents("system/plug/ueditor/php/config.json")), true);
+        $CONFIG['imageUrlPrefix'] = SystemConfigService::get('uploadUrl');
+        switch ($action) {
+            case 'config':
+                $result = json_encode($CONFIG);
+                break;
+
+            /* 上传图片 */
+            case 'uploadimage':
+                /* 上传涂鸦 */
+            case 'uploadscrawl':
+                /* 上传视频 */
+            case 'uploadvideo':
+                /* 上传文件 */
+            case 'uploadfile':
+                $result = json_encode([]);
+                break;
+
+            /* 列出图片 */
+            case 'listimage':
+                $result = json_encode([]);
+                break;
+
+            default:
+                $result = json_encode(array(
+                    'state' => '请求地址出错'
+                ));
+                break;
+        }
+
+        return $result;
+    }
+}

+ 139 - 0
application/admin/controller/system/SystemClear.php

@@ -0,0 +1,139 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\system;
+
+use app\admin\controller\AuthController;
+use app\admin\model\special\Special;
+use app\admin\model\special\SpecialSource;
+use app\admin\model\special\SpecialTask;
+use service\CacheService;
+use service\JsonService as Json;
+
+/**
+ * 清除缓存
+ * Class Clear
+ * @package app\admin\controller
+ *
+ */
+class systemClear extends AuthController
+{
+    public function index()
+    {
+        return $this->fetch();
+    }
+
+    public function refresh_cache()
+    {
+        `php think optimize:schema`;
+        `php think optimize:autoload`;
+        `php think optimize:route`;
+        `php think optimize:config`;
+        return Json::successful('数据缓存刷新成功!');
+    }
+
+    public function delete_cache()
+    {
+        $this->delDirAndFile("./runtime/temp");
+        $this->delDirAndFile("./runtime/cache");
+        return Json::successful('清除缓存成功!');
+    }
+
+    public function delete_log()
+    {
+        $this->delDirAndFile("./runtime/log");
+        return Json::successful('清除日志成功!');
+    }
+
+    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);
+        }
+    }
+
+    public function data_compatible_back()
+    {
+        $specialList = Special::select();
+        if (!$specialList) {
+            return Json::successful('无需兼容!');
+        }
+        $isTask = SpecialSource::find();
+        if ($isTask) {
+            return Json::successful('无需兼容!');
+        }
+
+        try{
+            foreach ($specialList as $k => $v) {
+                SpecialTask::beginTrans();
+                $specialTaskList = SpecialTask::where('special_id', $v['id'])->select();
+                if (count($specialTaskList)) {
+                    foreach ($specialTaskList as $tk => $tv) {
+                        $source_inster['special_id'] = $tv['special_id'];
+                        $source_inster['source_id'] = $tv['id'];
+                        $source_inster['pay_status'] = PAY_MONEY;
+                        $source_inster['add_time'] = time();
+                        SpecialSource::set($source_inster);
+                        if ($tv['live_id'] == 0){
+                            $task_update['type'] = 1;
+                        }else{
+                            $task_update['type'] = 4;
+                        }
+                        SpecialTask::where(['id'=>$tv['id']])->update($task_update);
+                    }
+                    Special::where(['id'=>$v['id']])->update(['type' => 1]);
+                }else{
+                    Special::where(['id'=>$v['id']])->update(['type' => 4]);
+                }
+
+                SpecialTask::commitTrans();
+            }
+            return Json::successful('兼容成功!');
+        }catch (\Exception $e){
+            SpecialTask::rollbackTrans();
+            echo $e->getMessage();die;
+            return Json::fail('兼容失败!');
+        }
+
+    }
+    public function data_compatible()
+    {
+        $specialList = Special::select();
+        if (!$specialList) {
+            return Json::successful('无需兼容!');
+        }
+
+        try{
+            foreach ($specialList as $k => $v) {
+                Special::where(['id'=>$v['id']])->update(['type' => 1]);
+            }
+            $specialTaskList = SpecialTask::select();
+                foreach ($specialTaskList as $tk => $tv) {
+                    SpecialTask::where(['id'=>$tv['id']])->update(['type' => 1]);
+                }
+            return Json::successful('兼容成功!');
+        }catch (\Exception $e){
+            return Json::fail('兼容失败!');
+        }
+
+    }
+}
+
+

+ 187 - 0
application/admin/controller/system/SystemCleardata.php

@@ -0,0 +1,187 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+
+namespace app\admin\controller\system;
+
+
+use app\admin\controller\AuthController;
+use app\admin\model\user\User;
+use app\admin\model\wechat\WechatUser;
+use service\JsonService as Json;
+use think\db;
+use think\Config;
+
+/**
+ * 清除默认数据理控制器
+ * Class SystemCleardata
+ * @package app\admin\controller\system
+ *
+ */
+class SystemCleardata extends AuthController
+{
+    public function index()
+    {
+
+        return $this->fetch();
+    }
+
+    //清除用户数据
+    public function UserRelevant()
+    {
+        SystemCleardata::ClearData('user_recharge', 1);
+        SystemCleardata::ClearData('user_address', 1);
+        SystemCleardata::ClearData('user_bill', 1);
+        SystemCleardata::ClearData('user_enter', 1);
+        SystemCleardata::ClearData('user_extract', 1);
+        SystemCleardata::ClearData('user_notice', 1);
+        SystemCleardata::ClearData('user_notice_see', 1);
+        SystemCleardata::ClearData('wechat_qrcode', 1);
+        SystemCleardata::ClearData('wechat_message', 1);
+        SystemCleardata::ClearData('store_coupon_user', 1);
+        SystemCleardata::ClearData('store_coupon_issue_user', 1);
+        SystemCleardata::ClearData('store_bargain_user', 1);
+        SystemCleardata::ClearData('store_bargain_user_help', 1);
+        SystemCleardata::ClearData('store_product_reply', 1);
+        $this->delDirAndFile('./public/uploads/store/comment');
+        SystemCleardata::ClearData('store_product_relation', 1);
+        return Json::successful('清除数据成功!');
+    }
+
+    //清除商城数据
+    public function storedata()
+    {
+        SystemCleardata::ClearData('store_coupon', 1);
+        SystemCleardata::ClearData('store_coupon_issue', 1);
+        SystemCleardata::ClearData('store_bargain', 1);
+        SystemCleardata::ClearData('store_combination', 1);
+        SystemCleardata::ClearData('store_product_attr', 1);
+        SystemCleardata::ClearData('store_product_attr_result', 1);
+        SystemCleardata::ClearData('store_product_attr_value', 1);
+        SystemCleardata::ClearData('store_seckill', 1);
+        SystemCleardata::ClearData('store_product', 1);
+        $this->delDirAndFile('./public/uploads/store/product');
+
+        return Json::successful('清除数据成功!');
+    }
+
+    //清除产品分类
+    public function categorydata()
+    {
+        SystemCleardata::ClearData('store_category', 1);
+        $this->delDirAndFile('./public/uploads/store/product');
+        return Json::successful('清除数据成功!');
+    }
+
+    //清除订单数据
+    public function orderdata()
+    {
+        SystemCleardata::ClearData('store_order', 1);
+        SystemCleardata::ClearData('store_order_cart_info', 1);
+        SystemCleardata::ClearData('store_order_copy', 1);
+        SystemCleardata::ClearData('store_order_status', 1);
+        SystemCleardata::ClearData('store_pink', 1);
+        SystemCleardata::ClearData('store_cart', 1);
+        return Json::successful('清除数据成功!');
+    }
+
+    //清除客服数据
+    public function kefudata()
+    {
+        SystemCleardata::ClearData('store_service', 1);
+        $this->delDirAndFile('./public/uploads/store/service');
+        SystemCleardata::ClearData('store_service_log', 1);
+        return Json::successful('清除数据成功!');
+    }
+
+    //修改用户默认密码
+    public function userdate()
+    {
+//       SystemCleardata::ClearData('user',1);
+        $headimgurl = WechatUser::Where('uid', 1)->value('headimgurl');
+        $data['account'] = 'crmeb';
+        $data['pwd'] = md5(123456);
+        $data['avatar'] = $headimgurl;
+        $data['add_time'] = time();
+        $data['status'] = 1;
+        $data['level'] = 0;
+        $data['user_type'] = "wechat";
+        $data['is_promoter'] = 1;
+        User::create($data);
+        return Json::successful('清除数据成功!');
+    }
+
+    //清除微信管理数据
+    public function wechatdata()
+    {
+        SystemCleardata::ClearData('wechat_media', 1);
+        SystemCleardata::ClearData('wechat_reply', 1);
+        SystemCleardata::ClearData('wechat_news_content', 1);
+        SystemCleardata::ClearData('wechat_news', 1);
+        SystemCleardata::ClearData('wechat_news_category', 1);
+        $this->delDirAndFile('./public/uploads/wechat');
+        return Json::successful('清除数据成功!');
+    }
+
+    //清除所有附件
+    public function uploaddata()
+    {
+        $this->delDirAndFile('./public/uploads');
+        return Json::successful('清除上传文件成功!');
+    }
+
+    //清除微信用户
+    public function wechatuserdata()
+    {
+        $data = WechatUser::get(1)->toArray();
+        SystemCleardata::ClearData('wechat_user', 1);
+        unset($data['uid']);
+        WechatUser::set($data);
+        return Json::successful('清除数据成功!');
+    }
+
+    //清除内容分类
+    public function articledata()
+    {
+        SystemCleardata::ClearData('article_category', 1);
+        $this->delDirAndFile('./public/uploads/article/');
+        return Json::successful('清除数据成功!');
+    }
+
+    //清除制定表数据
+    public function ClearData($table_name, $status)
+    {
+        $table_name = Config::get('database')['prefix'] . $table_name;
+        if ($status) {
+            db::query('TRUNCATE TABLE ' . $table_name);
+        } else {
+            db::query('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);
+        }
+    }
+}

+ 230 - 0
application/admin/controller/system/SystemDatabackup.php

@@ -0,0 +1,230 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\system;
+
+use app\admin\controller\AuthController;
+use service\FormBuilder as Form;
+use think\Request;
+use service\JsonService as Json;
+use \tp5er\Backup;
+use think\Session;
+use think\Db;
+
+/**
+ * 文件校验控制器
+ * Class SystemDatabackup
+ * @package app\admin\controller\system
+ *
+ */
+class SystemDatabackup extends AuthController
+{
+    protected $DB;
+
+    public function _initialize()
+    {
+        $config = array(
+            'path' => '.' . PUBILC_PATH . 'backup/data/',
+            //数据库备份路径
+            'part' => 20971520,
+            //数据库备份卷大小
+            'compress' => 1,
+            //数据库备份文件是否启用压缩 0不压缩 1 压缩
+            'level' => 5,
+        );
+        $this->DB = new Backup($config);
+    }
+
+    /**
+     * 数据类表列表
+     */
+    public function index()
+    {
+        return $this->fetch();
+    }
+
+    /**
+     * 获取数据库表
+     * @param Request|null $request
+     */
+    public function tablelist(Request $request = null)
+    {
+        $db = $this->DB;
+        return Json::result(0, 'sucess', $db->dataList(), count($db->dataList()));
+    }
+
+    /**
+     * 查看表结构
+     * @param Request|null $request
+     */
+    public function seetable(Request $request = null)
+    {
+        $database = config("database.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;
+    }
+
+    /**
+     * 优化表
+     * @param Request|null $request
+     */
+    public function optimize(Request $request = null)
+    {
+        $tables = $request->post('tables/a');
+        $db = $this->DB;
+        $res = $db->optimize($tables);
+        return Json::successful($res ? '优化成功' : '优化失败');
+    }
+
+    /**修复表
+     * @param Request|null $request
+     */
+    public function repair(Request $request = null)
+    {
+        $tables = $request->post('tables/a');
+        $db = $this->DB;
+        $res = $db->repair($tables);
+        return Json::successful($res ? '修复成功' : '修复失败');
+    }
+
+    /**备份表
+     * @param Request|null $request
+     */
+    public function backup(Request $request = null)
+    {
+        $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 Request|null $request
+     */
+    public function delFile(Request $request = null)
+    {
+        $feilname = intval($request->post('feilname'));
+        $files = $this->DB->delFile($feilname);
+        return Json::result(0, 'sucess');
+    }
+
+    /**倒入备份记录表
+     * @param Request|null $request
+     */
+    public function import(Request $request = null)
+    {
+        $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('参数错误!');
+        }
+        // return Json::result(0,'sucess',$data,count($data));
+    }
+
+    /**下载备份记录表
+     * @param Request|null $request
+     */
+    public function downloadFile(Request $request = null)
+    {
+        $time = intval($request->param('feilname'));
+        $this->DB->downloadFile($time);
+    }
+}

+ 248 - 0
application/admin/controller/system/SystemFile.php

@@ -0,0 +1,248 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\system;
+
+use app\admin\model\system\SystemFile as SystemFileModel;
+use app\admin\controller\AuthController;
+use service\FormBuilder as Form;
+
+/**
+ * 文件校验控制器
+ * Class SystemFile
+ * @package app\admin\controller\system
+ *
+ */
+class SystemFile extends AuthController
+{
+    public function index()
+    {
+        $app = $this->getDir('./application');
+        $extend = $this->getDir('./extend');
+        $public = $this->getDir('./public');
+        $arr = array();
+        $arr = array_merge($app, $extend);
+        $arr = array_merge($arr, $public);
+        $fileAll = array();//本地文件
+        $cha = array();//不同的文件
+        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'] = $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 = array();//不同的文件
+            } else {
+                $cha = $fileAll;
+            }
+        } else {
+            $cha = array();//差异文件
+            foreach ($file as $k => $v) {
+                foreach ($fileAll as $ko => $vo) {
+                    if ($v['filename'] == $vo['filename']) {
+                        if ($v['cthash'] != $vo['cthash']) {
+                            $cha[$k]['filename'] = $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'] = $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'] = $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'] = '新增的';
+            }
+
+        }
+        $this->assign('cha', $cha);
+        return $this->fetch();
+    }
+
+    public function filelist()
+    {
+        $app = $this->getDir('./application');
+        print_r($app);
+        $extend = $this->getDir('./extend');
+        $public = $this->getDir('./public');
+        $arr = array();
+        $arr = array_merge($app, $extend);
+        $arr = array_merge($arr, $public);
+        $fileAll = array();//本地文件
+        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'] = $v;
+            $fileAll[$k]['atime'] = $update_time['atime'];
+            $fileAll[$k]['mtime'] = $update_time['mtime'];
+            $fileAll[$k]['ctime'] = $update_time['ctime'];
+        }
+        dump($fileAll);
+    }
+
+    /**
+     * 获取文件夹中的文件 不包括子文件
+     * @param $dir
+     * @return array
+     */
+    public function getNextDir()
+    {
+        $dir = './';
+        $list = scandir($dir);
+        $dirlist = array();
+        $filelist = array();
+        foreach ($list as $key => $v) {
+            if ($v != '.' && $v != '..') {
+                if (is_dir($dir . '/' . $v)) {
+                    $dirlist[$key]['name'] = $v;
+                    $dirlist[$key]['type'] = 'dir';
+                }
+                if (is_file($dir . '/' . $v)) {
+                    $filelist[$key]['name'] = $v;
+                    $filelist[$key]['type'] = 'file';
+                }
+            }
+        }
+        $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 = array();
+        $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;
+    }
+}

+ 44 - 0
application/admin/controller/system/SystemLog.php

@@ -0,0 +1,44 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\system;
+
+use app\admin\controller\AuthController;
+use app\admin\model\system\SystemAdmin;
+use app\admin\model\system\SystemLog as LogModel;
+
+/**
+ * 管理员操作记录表控制器
+ * Class SystemLog
+ * @package app\admin\controller\system
+ */
+class SystemLog extends AuthController
+{
+    /**
+     * 显示操作记录
+     */
+    public function index()
+    {
+        LogModel::deleteLog();
+        $where = parent::getMore([
+            ['pages', ''],
+            ['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();
+    }
+
+}
+

+ 29 - 0
application/admin/controller/system/SystemUpgradeclient.php

@@ -0,0 +1,29 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\system;
+
+use app\admin\controller\AuthController;
+use service\JsonService as Json;
+use service\UpgradeService as uService;
+use think\Db;
+use app\admin\model\system\SystemConfig;
+
+/**
+ * 在线升级控制器
+ * Class SystemUpgradeclient
+ * @package app\admin\controller\system
+ *
+ */
+class SystemUpgradeclient extends AuthController
+{
+
+}

+ 220 - 0
application/admin/controller/ump/EventRegistration.php

@@ -0,0 +1,220 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\ump;
+
+use app\admin\controller\AuthController;
+use service\JsonService as Json;
+use service\UploadService as Upload;
+use think\Request;
+use app\admin\model\ump\EventRegistration as EventRegistrationModel;
+use app\admin\model\ump\EventSignUp as EventSignUpModel;
+
+class EventRegistration extends AuthController
+{
+     public function index(){
+
+         return $this->fetch();
+     }
+    /**
+     * 活动列表
+     */
+     public function event_registration_list(){
+         $where = parent::getMore([
+             ['title',''],
+             ['page',1],
+             ['limit',20],
+         ],$this->request);
+         return Json::successlayui(EventRegistrationModel::systemPage($where));
+     }
+    public function set_show($is_show = '', $id = '')
+    {
+        if ($is_show == '' || $id == '') return Json::fail('缺少参数');
+        if (EventRegistrationModel::update(['is_show' => $is_show], ['id' => $id]))
+            return Json::successful($is_show == 1 ? '显示成功' : '隐藏成功');
+        else
+            return Json::fail($is_show == 1 ? '显示失败' : '隐藏失败');
+    }
+     public function create(){
+         $id = $this->request->param('id');
+         $news = [];
+         $news['image'] = '';
+         $news['qrcode_img'] = '';
+         $news['title'] = '';
+         $news['start_time'] = '';
+         $news['end_time'] = '';
+         $news['signup_start_time'] = '';
+         $news['signup_end_time'] = '';
+         $news['province'] = '';
+         $news['city'] = '';
+         $news['district'] = '';
+         $news['detail'] = '';
+         $news['number'] = 0;
+         $news['activity_rules'] = '';
+         $news['content'] = '';
+         $news['sort'] = 0;
+         $news['restrictions'] = 0;
+         $news['is_fill'] = 1;
+         $news['is_show'] = 0;
+         $news['pay_type'] = 0;
+         $news['price'] = 0;
+         $news['member_pay_type'] = 0;
+         $news['member_price'] = 0;
+         if($id){
+             $news = EventRegistrationModel::where('id',$id)->find();
+             $news['signup_start_time'] =date('Y-m-d H:i:s',$news['signup_start_time']);
+             $news['signup_end_time'] =date('Y-m-d H:i:s',$news['signup_end_time']);
+             $news['start_time'] =date('Y-m-d H:i:s',$news['start_time']);
+             $news['end_time'] =date('Y-m-d H:i:s',$news['end_time']);
+             $news['activity_rules'] = htmlspecialchars_decode($news['activity_rules']);
+             $news['content'] = htmlspecialchars_decode($news['content']);
+             if(!$news) return $this->failed('数据不存在!');
+         }else{
+             $id=0;
+         }
+         $this->assign('news',json_encode($news));
+         $this->assign('id',$id);
+         return $this->fetch();
+         return $this->fetch();
+     }
+    /**
+     * 删除活动
+     * */
+    public function delete($id)
+    {
+        $res = EventRegistrationModel::delArticleCategory($id);
+        if(!$res)
+            return Json::fail(EventRegistrationModel::getErrorInfo('删除失败,请稍候再试!'));
+        else
+            return Json::successful('删除成功!');
+    }
+    /**
+     * 添加和修改活动
+     */
+    public function add_new(){
+        $data = parent::postMore([
+            ['id',0],
+            'title',
+            'image',
+            'qrcode_img',
+            'activity_rules',
+            'content',
+            'number',
+            'province',
+            'city',
+            'district',
+            'detail',
+            'signup_start_time',
+            'signup_end_time',
+            'start_time',
+            'end_time',
+            ['sort',0],
+            ['restrictions',0],
+            ['pay_type',0],
+            'price',
+            ['member_pay_type',0],
+            'member_price',
+            ['is_fill',1],
+            ['is_show',0],
+            ]);
+        $data['signup_start_time']=strtotime($data['signup_start_time']);
+        $data['signup_end_time']=strtotime($data['signup_end_time']);
+        $data['start_time']=strtotime($data['start_time']);
+        $data['end_time']=strtotime($data['end_time']);
+        if(bcsub($data['signup_end_time'],$data['signup_start_time'],0)<=0 || bcsub($data['start_time'],$data['signup_end_time'],0)<=0 || bcsub($data['end_time'],$data['start_time'],0)<=0) return Json::fail('活动时间有误');
+        if(!$data['pay_type']){
+            $data['price']=0;
+            $data['member_pay_type']=0;
+            $data['member_price']=0;
+        }
+        $data['content']=htmlspecialchars($data['content']);
+        $data['activity_rules']=htmlspecialchars($data['activity_rules']);
+        if(!$data['member_pay_type']) $data['member_price']=0;
+        if($data['id']){
+            $id = $data['id'];
+            unset($data['id']);
+            EventRegistrationModel::beginTrans();
+            $res1 = EventRegistrationModel::edit($data,$id,'id');
+            EventRegistrationModel::checkTrans($res1);
+            if($res1){
+                return Json::successful('修改活动成功!',$id);
+            }else
+                return Json::fail('修改活动失败,您并没有修改什么!',$id);
+        }else{
+            $data['add_time'] = time();
+            EventRegistrationModel::beginTrans();
+            $res2 = EventRegistrationModel::set($data);
+            EventRegistrationModel::checkTrans($res2);
+            if($res2)
+                return Json::successful('添加活动成功!',$res2->id);
+            else
+                return Json::successful('添加活动失败!',$res2->id);
+        }
+    }
+    /**
+     * 查看报名人员
+     */
+    public function viewStaff($id){
+        $activity = EventRegistrationModel::where('id',$id)->find();
+        if(!$activity) return Json::fail('活动不存在!');
+        $this->assign('aid',$id);
+        return $this->fetch('view_staff');
+    }
+
+    /**
+     * 查看活动报名订单列表
+     */
+    public function get_sign_up_list(){
+        $id = $this->request->param('id');
+        $where=parent::getMore([
+            ['id',$id],
+            ['page',1],
+            ['limit',20],
+            ['status',''],
+            ['real_name',''],
+            ['excel',0],
+        ]);
+        return Json::successlayui(EventSignUpModel::getUserSignUpAll($where));
+    }
+
+    /**
+     * 统计
+     */
+    public function getBadge()
+    {
+        $id = $this->request->param('id');
+        $where=parent::getMore([
+            ['id',$id],
+            ['status',''],
+            ['real_name',''],
+            ['excel',0],
+        ]);
+        return Json::successful(EventSignUpModel::getBadge($where));
+    }
+    /**用户活动核销
+     * @param string $order_id
+     * @param int $aid
+     * @param string $code
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function scanCodeSignIn($id){
+        if (!$id) $this->failed('参数有误!');
+        $order=EventSignUpModel::where('id',$id)->find();
+        if(!$order) $this->failed('订单不存在!');
+        if($order['status']) $this->failed('订单已核销!');
+        $res=EventSignUpModel::where('id',$id)->where('paid',1)->update(['status'=>1]);
+        if($res) return Json::successful('ok');
+        else return Json::fail('核销失败');
+    }
+}
+

+ 154 - 0
application/admin/controller/ump/StoreCombination.php

@@ -0,0 +1,154 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\ump;
+
+use app\admin\controller\AuthController;
+use app\admin\model\special\Special;
+use app\admin\model\ump\StorePinkFalse;
+use traits\CurdControllerTrait;
+use service\JsonService as Json;
+use think\Request;
+use think\Url;
+use app\wap\model\store\StorePink;
+
+/**
+ * 拼团管理
+ * Class StoreCombination
+ * @package app\admin\controller\store
+ */
+class StoreCombination extends AuthController
+{
+
+    use CurdControllerTrait;
+
+    /**拼团列表
+     * @return mixed
+     */
+    public function combina_list($cid = 0)
+    {
+        $special_type = $this->request->param('special_type');
+        $this->assign('special_type', $special_type);
+        $this->assign('cid', $cid);
+        return $this->fetch();
+    }
+
+    /*
+     * 获取拼团列表
+     * @param array $where
+     * @return json
+     * */
+    public function get_pink_list()
+    {
+        $where = parent::getMore([
+            ['status', ''],
+            ['data', ''],
+            ['nickname', ''],
+            ['page', 1],
+            ['cid', 0],
+            ['limit', 10],
+        ], $this->request);
+        return Json::successlayui(StorePink::getPinkList($where));
+    }
+
+
+    /*
+     * 删除虚拟拼团
+     * @param int $id 拼团id
+     * @return json
+     * */
+    public function delete_pink($id = 0)
+    {
+        if (!$id) return Json::fail('缺少参数');
+        if (StorePink::be(['is_false' => 0, 'id' => $id])) return Json::fail('不是虚拟拼团无法删除');
+        if (StorePink::where('id', $id)->delete())
+            return Json::successful('删除成功');
+        else
+            return Json::fail('删除失败');
+    }
+
+    /*
+     * 下架拼团
+     * @param int $id 拼团id
+     * @return json
+     * */
+    public function down_pink($id = 0)
+    {
+        if (!$id) return Json::fail('缺少参数');
+        $res = StorePink::downPink($id);
+        if ($res === false)
+            return Json::fail(StorePink::getErrorInfo());
+        else
+            return Json::successful('下架成功');
+    }
+
+    /*
+     * 助力拼团
+     * */
+    public function helpe_pink($id = 0)
+    {
+        $this->assign('id', $id);
+        return $this->fetch();
+    }
+
+    public function save_helpe_pink()
+    {
+        list($pink_id, $nickname, $avatar) = parent::postMore([
+            ['pink_id', 0],
+            ['nickname', ''],
+            ['avatar', ''],
+        ], $this->request, true);
+        if (!$pink_id) return Json::fail('缺少助力团ID');
+        if (!$nickname) return Json::fail('请输入助力用户用户名');
+        if (!$avatar) return Json::fail('请上传助力用户头像');
+        $res = StorePink::helpePink($pink_id, $nickname, $avatar);
+        if ($res === false)
+            return Json::fail(StorePink::getErrorInfo());
+        else
+            return Json::successful('助力成功');
+    }
+
+    /**拼团人列表
+     * @return mixed
+     */
+    public function order_pink($id)
+    {
+        if (!$id) return $this->failed('数据不存在');
+        $StorePink = StorePink::getPinkUserOne($id);
+        if (!$StorePink) return $this->failed('数据不存在!');
+        $list = StorePink::getPinkMember($id);
+        $list[] = $StorePink;
+        if ($id = StorePink::where(['k_id' => $id, 'is_false' => 1])->column('id')) {
+            $falsePink = count($id) ? StorePinkFalse::where('pink_id', 'in', $id)->select()->toArray() : [];
+            foreach ($falsePink as $item) {
+                $item['uid'] = 0;
+                $item['is_refund'] = 0;
+                $item['is_false'] = 1;
+                $item['total_price'] = $StorePink['total_price'];
+                array_push($list, $item);
+            }
+        }
+        $this->assign('list', $list);
+        return $this->fetch();
+    }
+
+
+    /*
+     * 创建虚拟拼团
+     *
+     * */
+    public function create_pink_false()
+    {
+        $this->assign('list', Special::PreWhere()->field('id,title')->select());
+        return $this->fetch();
+    }
+
+}

+ 152 - 0
application/admin/controller/user/MemberCard.php

@@ -0,0 +1,152 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\user;
+
+use app\admin\model\user\MemberCardBatch;
+use app\admin\model\user\MemberCard as MemberCardModel;
+use app\admin\controller\AuthController;
+use service\JsonService as Json;
+use service\FormBuilder as Form;
+use think\Db;
+use think\Url;
+
+/**
+ * 会员卡管理控制器
+ * Class User
+ * @package app\admin\controller\user
+ */
+class MemberCard extends AuthController
+{
+    public function batch_index()
+    {
+        $this->assign([
+            'activity_type' => 1,
+        ]);
+        return $this->fetch();
+    }
+
+    public function batch_list()
+    {
+        $where = parent::getMore([
+            ['title', ""],
+            ['page', 1],
+            ['limit', 20],
+        ]);
+        $batch_list = MemberCardBatch::getBatchList($where);
+        return Json::successlayui($batch_list);
+    }
+
+    public function add_batch()
+    {
+        $id = $this->request->param('id',0);
+        if ($id){
+            $batch_data = MemberCardBatch::getBatchOne($id);
+            $this->assign('batch', json_encode($batch_data));
+        }
+        $this->assign([
+            'id' => $id,
+        ]);
+        return $this->fetch();
+    }
+
+    public function save_batch()
+    {
+        $id = $this->request->param('id',0);
+        $data = parent::postMore([
+            ['title', ''],
+            ['use_day', 1],
+            ['total_num', 1],
+            ['status', 0],
+        ]);
+        if (!isset($data['use_day']) || $data['use_day'] <= 0 || !is_numeric( $data['use_day'])) return Json::fail('体验时间未填写或不合法');
+        if (!isset($data['total_num']) || $data['total_num'] <= 0 || !is_numeric( $data['total_num'])) return Json::fail('制卡未填写或不合法');
+        if ($data['total_num'] > 6000) return Json::fail('单次制卡数量最高不得超过6000张');
+
+        try{
+            MemberCardBatch::beginTrans();
+            if ($id) {
+                $data['update_time'] = time();
+            }else{
+                $data['create_time'] = time();
+                $batch_id = MemberCardBatch::addBatch($data);
+                $batch_card = MemberCardModel::addCard($batch_id, $data['total_num']);
+                if($batch_id && $batch_card){
+                    $qrcodeUrl=MemberCardBatch::qrcodes_url($batch_id,5);
+                    MemberCardBatch::where('id',$batch_id)->update(['qrcode'=>$qrcodeUrl]);
+                }
+            }
+            MemberCardBatch::commitTrans();
+            return Json::successful('添加成功');
+        }catch (\Exception $e) {
+            MemberCardBatch::rollbackTrans();
+            return Json::fail('添加失败');
+        }
+    }
+
+    /**
+     * 快速编辑
+     * @param string $field 字段名
+     * @param int $id 修改的主键
+     * @param string value 修改后的值
+     * @return json
+     */
+    public function set_value($field = '', $id, $value = '', $model_type)
+    {
+        if ($field == "use_day" && $id) {
+            if (!$value || !is_numeric($value) || $value <= 0) return Json::fail('非法数值');
+            $get_one = MemberCardModel::getCardOne(['card_batch_id' => $id, 'use_uid' => ['>',0]]);
+            if ($get_one){
+                return Json::fail('此批次卡片已经在使用当中,无法进行此非法操作');
+            }
+        }
+        $use=MemberCardModel::where('card_batch_id',$id)->where('use_uid','>',0)->count();
+        if($use) return Json::fail('此批次卡片已经在使用当中,无法进行此非法操作');
+        if($model_type=='member_card' && $id){
+            $card = MemberCardModel::where(['id' => $id, 'use_uid' => ['>',0]])->find();
+            if($card) return Json::fail('此卡片已经在使用当中,无法进行此非法操作');
+        }
+        return  set_field_value([$field => $value], ['id' => $id], $value, $model_type);
+    }
+
+    public function card_index()
+    {
+        $data = parent::getMore([
+            ['activity_type', 2],
+            ['card_batch_id', 0],
+
+        ]);
+        $batch_list = MemberCardBatch::getBatchAll([]);
+        $this->assign([
+            'activity_type' => $data['activity_type'],
+            'card_batch_id' => $data['card_batch_id'],
+            'batch_list' => $batch_list ? $batch_list->toArray() : [],
+        ]);
+        return $this->fetch();
+    }
+    public function card_list()
+    {
+        $card_batch_id = $this->request->param('card_batch_id',0);
+        $excel = $this->request->param('excel',0);
+        $where = parent::getMore([
+            ['card_number', ""],
+            ['phone', ""],
+            ['card_batch_id', $card_batch_id],
+            ['is_use',""],
+            ['is_status',""],
+            ['page', 1],
+            ['limit', 20],
+            ['excel', $excel],
+        ]);
+        $card_list = MemberCardModel::getCardList($where);
+        return Json::successlayui($card_list);
+    }
+}

+ 39 - 0
application/admin/controller/user/MemberRecord.php

@@ -0,0 +1,39 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\user;
+
+use app\admin\controller\AuthController;
+use service\JsonService as Json;
+use service\FormBuilder as Form;
+use think\Url;
+use app\admin\model\user\MemberRecord as MemberRecordModel;
+
+
+class MemberRecord extends AuthController
+{
+    public function index()
+    {
+        return $this->fetch();
+    }
+
+    public function member_record_list()
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['title', ''],
+            ['type', ''],
+        ]);
+        return Json::successlayui(MemberRecordModel::getPurchaseRecordList($where));
+    }
+
+}

+ 117 - 0
application/admin/controller/user/MemberShip.php

@@ -0,0 +1,117 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\user;
+
+use app\admin\controller\AuthController;
+use service\JsonService as Json;
+use service\FormBuilder as Form;
+use think\Url;
+use app\admin\model\user\MemberShip as MembershipModel;
+
+/**
+ * 会员设置控制器
+ * Class User
+ * @package app\admin\controller\user
+ */
+class MemberShip extends AuthController
+{
+    public function index()
+    {
+        return $this->fetch();
+    }
+
+    public function membership_vip_list()
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['is_publish', ''],
+            ['title', ''],
+        ]);
+        return Json::successlayui(MembershipModel::getSytemVipList($where));
+    }
+
+    public function add_vip($id = 0)
+    {
+        $membership =[];
+        if ($id) {
+            $membership = MembershipModel::get($id);
+            if ($membership) $membership['sorts'] = $membership['sort'];
+            if ($membership['is_free']) $membership['free_day'] = $membership['vip_day'];
+        }
+        $this->assign('id',$id);
+        $this->assign('membership',json_encode($membership));
+        return $this->fetch();
+    }
+
+    public function save_sytem_vip($id = 0)
+    {
+        $post = parent::postMore([
+            ['title', ''],
+            ['vip_day', 0],
+            ['free_day', 0],
+            ['original_price', 0],
+            ['price', 0],
+            ['sort', 0],
+            ['is_permanent', 0],
+            ['is_publish', 0],
+            ['is_free', 0],
+            ['add_time', time()],
+        ]);
+        if ($post['title'] == '') $this->failed('请输入会员标题');
+        if ($post['is_permanent'] == 0 && $post['vip_day'] <= 0 && $post['is_free'] ==0) $this->failed('会员有有效期时,请设置会员有效期');
+        if ($post['is_free'] == 1 && $post['free_day'] <= 0) $this->failed('免费会员有有效期时,请设置会员有效期');
+        if (bcsub($post['original_price'],0,0) < 0) $this->failed('请输入会员原价');
+        if (bcsub($post['price'],0,0) < 0) $this->failed('请输入会员原价');
+        if($post['is_free'] == 1){
+            $post['vip_day']=$post['free_day'];
+            unset($post['free_day']);
+        }
+        MembershipModel::beginTrans();
+        try {
+            if ($id) {
+                $vipinfo = MembershipModel::get($id);
+                unset($post['add_time']);
+                MembershipModel::update($post, ['id' => $id]);
+                MembershipModel::commitTrans();
+                return Json::successful('修改成功');
+            } else {
+                MembershipModel::set($post);
+                MembershipModel::commitTrans();
+                return Json::successful('添加成功');
+            }
+        } catch (\Exception $e) {
+            MembershipModel::rollbackTrans();
+            return Json::fail($e->getMessage());
+        }
+    }
+
+    public function set_publish($is_publish = '', $id = '')
+    {
+        if ($is_publish == '' || $id == '') return Json::fail('缺少参数');
+        if (MembershipModel::update(['is_publish' => $is_publish], ['id' => $id]))
+            return Json::successful($is_publish == 1 ? '发布成功' : '隐藏成功');
+        else
+            return Json::fail($is_publish == 1 ? '发布失败' : '隐藏失败');
+    }
+
+    public function delete($id = '')
+    {
+        if ($id == '') return Json::fail('缺少参数');
+        if (MembershipModel::update(['is_del' => 1], ['id' => $id]))
+            return Json::successful('删除成功');
+        else
+            return Json::fail('删除失败');
+    }
+
+
+}

+ 127 - 0
application/admin/controller/user/SignPoster.php

@@ -0,0 +1,127 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\user;
+
+use app\admin\model\user\SignPoster as SignPosterModel;
+use app\admin\controller\AuthController;
+use service\JsonService as Json;
+use service\FormBuilder as Form;
+use think\Url;
+use think\Request;
+use service\UploadService as Upload;
+/**
+ * 会员管理控制器
+ * Class User
+ * @package app\admin\controller\user
+ */
+class SignPoster extends AuthController
+{
+    public function index()
+    {
+        return $this->fetch();
+    }
+
+    public function getSignPosterList()
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20],
+        ]);
+        return Json::successlayui(SignPosterModel::getSignPosterList($where));
+    }
+    /**
+     * 添加签到海报
+     * @param $id
+     * @return mixed|\think\response\Json|void
+     */
+    public function create()
+    {
+        $f = array();
+        $f[] = Form::dateTime('sign_time', '签到时间');
+        $f[] =Form::frameImageOne('poster', '签到海报(690*590px)', Url::build('admin/widget.images/index', array('fodder' => 'poster')))->icon('image')->width('100%')->height('500px');
+        $f[] =Form::input('sign_talk', '签到语录');
+        $f[] = Form::number('sort', '排序')->col(12);
+        $form = Form::make_post_form('新增海报', $f, Url::build('save'),2);
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    public function save(Request $request)
+    {
+        $data = parent::postMore([
+            ['sign_time', ''],
+            ['poster', []],
+            ['sign_talk', ''],
+            ['sort', 0],
+        ], $request);
+       if(!$data['sign_time']) return Json::fail('请选择时间');
+       if(count($data['poster'])<1) return Json::fail('请上传海报');
+        $data['add_time'] = time();
+        $data['poster']=$data['poster'][0];
+        $data['sign_time']=strtotime($data['sign_time']);
+        $res=SignPosterModel::set($data);
+        if ($res)
+            return Json::successful('添加成功');
+        else
+            return Json::fail('添加失败');
+    }
+    /**
+     * 编辑签到海报
+     * @param $id
+     * @return mixed|\think\response\Json|void
+     */
+    public function edit($id)
+    {
+        if (!$id) return $this->failed('数据不存在');
+        $poster = SignPosterModel::get($id);
+        if (!$poster) return Json::fail('数据不存在!');
+        $f = array();
+        $f[] = Form::dateTime('sign_time', '签到时间',date('Y-m-d H:i:s',$poster->getData('sign_time')));
+        $f[] =Form::frameImageOne('poster', '签到海报(690*590px)', Url::build('admin/widget.images/index', array('fodder' => 'poster')),$poster->getData('poster'))->icon('image')->width('100%')->height('500px');
+        $f[] =Form::input('sign_talk', '签到语录', $poster->getData('sign_talk'));
+        $f[] = Form::number('sort', '排序',$poster->getData('sort'))->col(12);
+        $form = Form::make_post_form('修改海报', $f, Url::build('update',compact('id')),2);
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    public function update(Request $request,$id)
+    {
+        $data = parent::postMore([
+            ['sign_time', ''],
+            ['poster', []],
+            ['sign_talk', ''],
+            ['sort', 0],
+        ], $request);
+       if(!$data['sign_time']) return Json::fail('请选择时间');
+       if(count($data['poster'])<1) return Json::fail('请上传海报');
+        $data['poster']=$data['poster'][0];
+        $data['sign_time']=strtotime($data['sign_time']);
+        $res=SignPosterModel::edit($data,$id);
+        if ($res)
+            return Json::successful('修改成功');
+        else
+            return Json::fail('修改失败');
+    }
+
+    public function delete($id = '')
+    {
+        if ($id == '') return Json::fail('缺少参数');
+        $poster = SignPosterModel::get($id);
+        if (!$poster) return Json::fail('数据不存在');
+        if (SignPosterModel::del($id))
+            return Json::successful('删除成功');
+        else
+            return Json::fail('删除失败');
+    }
+
+}

+ 812 - 0
application/admin/controller/user/User.php

@@ -0,0 +1,812 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\user;
+
+use app\admin\controller\AuthController;
+use app\admin\model\special\Grade;
+use app\admin\model\special\Special;
+use app\admin\model\special\SpecialSubject;
+use app\admin\model\special\SpecialSource;
+use app\wap\model\special\SpecialBuy;
+use service\FormBuilder as Form;
+use think\Db;
+use traits\CurdControllerTrait;
+use service\JsonService as Json;
+use think\Request;
+use think\Url;
+use app\admin\model\user\User as UserModel;
+use app\wap\model\user\UserBill;
+use app\admin\model\user\UserBill AS UserBillAdmin;
+use basic\ModelBasic;
+use service\HookService;
+use behavior\wap\UserBehavior;
+use app\admin\model\store\StoreVisit;
+use app\admin\model\wechat\WechatMessage;
+use app\admin\model\order\StoreOrder;
+use app\wap\model\store\StoreOrder as StoreOrderModel;
+use service\SystemConfigService;
+use app\admin\model\user\MemberRecord as MemberRecordModel;
+use app\wap\model\user\MemberShip;
+
+/**
+ * 用户管理控制器
+ * Class User
+ * @package app\admin\controller\user
+ */
+class User extends AuthController
+{
+    use CurdControllerTrait;
+
+    /**
+     * 显示资源列表
+     *
+     * @return \think\Response
+     */
+    public function index()
+    {
+        $this->assign(['count_user'=>UserModel::count(),'count_vip'=>UserModel::where('level',1)->count()]);
+        $this->assign('gold_name', SystemConfigService::get("gold_name"));
+        return $this->fetch();
+    }
+
+    /**
+     * 修改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 = parent::postMore([
+                ['uids', []]
+            ]);
+            UserModel::destrSyatus($uids['uids'], $status);
+        }
+        return Json::successful($status == 0 ? '禁用成功' : '解禁成功');
+    }
+
+    /**
+     * 赠送会员
+     */
+    public function members($uid = 0)
+    {
+        if(!$uid)return Json::fail('参数错误');
+        $user=UserModel::where(['uid' => $uid])->find();
+        if(!$user) return Json::fail('用户不存在!');
+        $form = Form::create(Url::build('gift_members', ['uid' => $uid]), [
+            Form::select('member', '会员等级')->setOptions(function () {
+                $list = MemberShip::where(['is_publish' => 1,'is_del'=>0])->field('title,id')->order('sort desc,add_time desc')->select();
+                $list=count($list)>0 ? $list->toArray() : [];
+                $menus = [];
+                foreach ($list as $menu) {
+                    $menus[] = ['value' => $menu['id'], 'label' => $menu['title']];
+                }
+                return $menus;
+            })->filterable(1),
+        ]);
+        $form->setMethod('post')->setTitle('赠送会员')->setSuccessScript('parent.$(".J_iframe:visible")[0].contentWindow.location.reload(); setTimeout(function(){parent.layer.close(parent.layer.getFrameIndex(window.name));},800);');
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**赠送会员
+     * @param int $uid
+     */
+    public function gift_members($uid = 0)
+    {
+        if(!$uid)return Json::fail('参数错误');
+        $data = parent::postMore([
+            ['member',0],
+        ]);
+        if (!$data['member']) return Json::fail('会员等级');
+        $userInfo = UserModel::where('uid',$uid)->find();
+        if (!$userInfo) return UserModel::setErrorInfo('用户不存在!');
+        if($userInfo['level'] && $userInfo['is_permanent']) return UserModel::setErrorInfo('该用户是永久会员,无需续费!');
+        $member=MemberShip::where('id',$data['member'])->where('is_publish',1)->where('is_del',0)->where('type',1)->find();
+        $orderInfo = [
+            'uid' => $uid,
+            'order_id' => StoreOrderModel::getNewOrderId(),
+            'type'=>1,
+            'member_id' => $data['member'],
+            'total_num' => 1,
+            'total_price' => $member['original_price'],
+            'pay_price' => 0,
+            'pay_type' => 'yue',
+            'combination_id' => 0,
+            'is_gift' => 0,
+            'pink_time' => 0,
+            'paid' => 0,
+            'pink_id' => 0,
+            'unique' => md5(time() . '' . $uid . $data['member']),
+            'cost' => $member['original_price'],
+            'link_pay_uid' => 0,
+            'spread_uid' => $userInfo['spread_uid'] ? $userInfo['spread_uid'] : 0,
+            'is_del' => 0,
+        ];
+        $order = StoreOrderModel::set($orderInfo);
+        if($order){
+            $res1 = UserBill::expend('赠送会员', $uid, 'now_money', 'give_vip', $order['pay_price'], $order['id'], 0, '会员价值' . floatval($order['pay_price']) . '元');
+            $res2 = StoreOrderModel::payMeSuccess($order['order_id']);
+            if($res1 && $res2){
+                return Json::successful('赠送成功');
+            }else{
+                return Json::fail('赠送失败');
+            }
+        }else{
+            return Json::fail('赠送失败');
+        }
+    }
+
+    /**
+     * 清除会员等级
+     */
+    public function del_vip($uid = 0){
+        if(!$uid) return Json::fail('参数错误!');
+        $user=UserModel::where('uid',$uid)->where('level',1)->find();
+        if(!$user) return Json::fail('用户不存在或不是会员!');
+        $res=UserModel::edit(['level'=>0,'is_permanent'=>0,'overdue_time'=>0,'member_time'=>0],$uid,'uid');
+        if($res){
+            return Json::successful('清除会员成功');
+        }else{
+            return Json::fail('清除会员失败');
+        }
+    }
+
+    public function user_data($uid = 0)
+    {
+        $spread = UserModel::where(['spread_uid' => $uid])->column('uid');
+
+        $count['pay_count'] = Db::name('special_buy')->where('uid', $uid)->count();
+        $count['bill_count'] = UserBill::where(['category' => 'now_money'])->where('uid', $uid)
+            ->where('type', 'in', ['rake_back', 'rake_back_one', 'rake_back_two', 'extract'])
+            ->count();
+        $count['order_count'] = UserBill::where('u.uid', $uid)->alias('u')->join('__STORE_ORDER__ a', 'a.id=u.link_id')
+            ->where('u.category', 'now_money')->where('u.type', 'in', ['rake_back', 'rake_back_one'])
+            ->where(['a.paid' => 1, 'a.is_gift' => 0, 'a.is_receive_gift' => 0])->count();
+        $count['spread_count'] = UserModel::where('uid', 'in', $spread)->count();
+        $this->assign('gradeList', json_encode(Grade::getAll()));
+        $this->assign('uid', $uid);
+        $this->assign('count', json_encode($count));
+        return $this->fetch();
+    }
+
+    public function member_record($uid = 0){
+        if (!$uid) return Json::fail('缺少参数');
+        $this->assign(MemberRecordModel::userOneRecord($uid));
+        return $this->fetch();
+    }
+    public function get_subjec_list($grade_id = 0)
+    {
+        return Json::successful(SpecialSubject::where(['grade_id' => $grade_id, 'is_show' => 1,'is_del' => 0])->order('sort desc,add_time desc')->field('id,name')->select());
+    }
+
+    public function get_special_list($subjec_id = 0)
+    {
+        return Json::successful(Special::PreWhere()->where('subject_id', $subjec_id)->order('sort desc,add_time desc')->field('id,title')->select());
+    }
+
+    public function save_give()
+    {
+        $post = parent::postMore([
+            ['uid', 0],
+            ['special_id', 0],
+        ]);
+        if (!$post['uid'] || !$post['special_id']) return Json::fail('缺少参数无法赠送');
+        $special = Special::get($post['special_id']);
+        if (SpecialBuy::be(['uid' => $post['uid'], 'special_id' => $post['special_id'], 'is_del' => 0])) return Json::fail('此用户已经拥有此专题无需赠送');
+        if ($special['type'] == SPECIAL_COLUMN) {
+            $special_source = SpecialSource::getSpecialSource($special['id']);
+            if ($special_source){
+                foreach($special_source as $k => $v) {
+                    $task_special = Special::get($v['source_id']);
+                    if ($task_special['is_show'] == 1){
+                        SpecialBuy::setBuySpecial('', $post['uid'], $v['source_id'], 3,$post['special_id']);
+                    }
+                }
+            }
+            $res=SpecialBuy::setBuySpecial('', $post['uid'], $post['special_id'], 3);
+        }else{
+            $res=SpecialBuy::setBuySpecial('', $post['uid'], $post['special_id'], 3);
+        }
+        if ($res)
+            return Json::successful('赠送成功');
+        else
+            return Json::fail('赠送失败');
+    }
+
+    public function get_user_info($uid = 0)
+    {
+        if (!$uid) return Json::fail('缺少用户参数');
+        return Json::successful(UserModel::getUserinfoV1($uid));
+    }
+
+    public function get_pay_list()
+    {
+        $where = parent::getMore([
+            ['uid', 0],
+            ['limit', 10],
+            ['page', 1],
+        ]);
+        return Json::successful(SpecialBuy::getPayList($where));
+    }
+
+    public function get_spread_list()
+    {
+        $where = parent::getMore([
+            ['uid', 0],
+            ['limit', 10],
+            ['page', 1],
+        ]);
+        return Json::successful(UserModel::getSpreadListV1($where));
+    }
+
+    public function get_order_list()
+    {
+        $where = parent::getMore([
+            ['uid', 0],
+            ['limit', 10],
+            ['page', 1],
+            ['excel', 0],
+            ['start_date', ''],
+            ['end_date', ''],
+        ]);
+        return Json::successful(StoreOrder::getOrderList($where));
+    }
+
+    public function get_bill_list()
+    {
+        $where = parent::getMore([
+            ['limit', 10],
+            ['page', 1],
+            ['uid', 0],
+            ['excel', 0],
+            ['start_date', ''],
+            ['end_date', ''],
+        ]);
+        return Json::successful(UserBillAdmin::getBillList($where, $where['uid']));
+    }
+
+    public function update_user_spread($uid = 0, $type = 0)
+    {
+        if (!$uid || !$type) return Json::fail('缺少参数');
+        $user = UserModel::get($uid);
+        switch ($type) {
+            case '1':
+            case "2":
+            case "3":
+            case '4':
+                $user->is_promoter = (int)$type;
+                break;
+            case "5":
+                $user->is_promoter = 1;
+                $user->spread_uid = 0;
+                break;
+        }
+        if ($user->save())
+            return Json::successful('修改成功');
+        else
+            return Json::fail('修改失败');
+    }
+
+    /**
+     * 获取user表
+     *
+     * @return json
+     */
+    public function get_user_list()
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['nickname', ''],
+            ['status', ''],
+            ['pay_count', ''],
+            ['is_promoter', ''],
+            ['order', ''],
+            ['data', ''],
+            ['country', ''],
+            ['province', ''],
+            ['city', ''],
+            ['user_time_type', ''],
+            ['user_time', ''],
+            ['sex', ''],
+        ]);
+        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('nickname', '用户姓名', $user->getData('nickname'));
+        $f[] = Form::radio('money_status', '修改余额', 1)->options([['value' => 1, 'label' => '增加'], ['value' => 2, 'label' => '减少']]);
+        $f[] = Form::number('money', '余额')->min(0);
+        $f[] = Form::radio('status', '状态', $user->getData('status'))->options([['value' => 1, 'label' => '开启'], ['value' => 0, 'label' => '锁定']]);
+        $f[] = Form::radio('is_promoter', '推广员', $user->getData('is_promoter'))->options([
+            ['value' => 0, 'label' => '关闭'],
+            ['value' => 1, 'label' => '推广员'],
+        ]);
+        $form = Form::make_post_form('添加用户通知', $f, Url::build('update', array('id' => $uid)));
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    public function update(Request $request, $uid)
+    {
+        $data = parent::postMore([
+            ['money_status', 0],
+            ['is_promoter', 1],
+            ['is_senior', 0],
+            ['money', 0],
+            ['nickname', ''],
+            ['integration_status', 0],
+            ['integration', 0],
+            ['status', 0],
+        ], $request);
+        if (!$uid) return $this->failed('数据不存在');
+        $user = UserModel::get($uid);
+        if (!$user) return Json::fail('数据不存在!');
+        ModelBasic::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 = UserBill::income('系统增加余额', $user['uid'], 'now_money', 'system_add', $data['money'], $this->adminId, $user['now_money'], '系统增加了' . floatval($data['money']) . '余额');
+                try {
+                    HookService::listen('admin_add_money', $user, $data['money'], false, UserBehavior::class);
+                } catch (\Exception $e) {
+                    ModelBasic::rollbackTrans();
+                    return Json::fail($e->getMessage());
+                }
+            } else if ($data['money_status'] == 2) {//减少
+                $edit['now_money'] = bcsub($user['now_money'], $data['money'], 2);
+                $res1 = UserBill::expend('系统减少余额', $user['uid'], 'now_money', 'system_sub', $data['money'], $this->adminId, $user['now_money'], '系统扣除了' . floatval($data['money']) . '余额');
+                try {
+                    HookService::listen('admin_sub_money', $user, $data['money'], false, UserBehavior::class);
+                } catch (\Exception $e) {
+                    ModelBasic::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 = UserBill::income('系统增加积分', $user['uid'], 'integral', 'system_add', $data['integration'], $this->adminId, $user['integral'], '系统增加了' . floatval($data['integration']) . '积分');
+                try {
+                    HookService::listen('admin_add_integral', $user, $data['integration'], false, UserBehavior::class);
+                } catch (\Exception $e) {
+                    ModelBasic::rollbackTrans();
+                    return Json::fail($e->getMessage());
+                }
+            } else if ($data['integration_status'] == 2) {//减少
+                $edit['integral'] = bcsub($user['integral'], $data['integration'], 2);
+                $res2 = UserBill::expend('系统减少积分', $user['uid'], 'integral', 'system_sub', $data['integration'], $this->adminId, $user['integral'], '系统扣除了' . floatval($data['integration']) . '积分');
+                try {
+                    HookService::listen('admin_sub_integral', $user, $data['integration'], false, UserBehavior::class);
+                } catch (\Exception $e) {
+                    ModelBasic::rollbackTrans();
+                    return Json::fail($e->getMessage());
+                }
+            }
+        } else {
+            $res2 = true;
+        }
+        $edit['status'] = $data['status'];
+        $edit['nickname'] = $data['nickname'];
+        $edit['is_promoter'] = $data['is_promoter'];
+        $edit['is_senior'] = $data['is_senior'];
+        if ($edit) $res3 = UserModel::edit($edit, $uid);
+        else $res3 = true;
+        if ($res1 && $res2 && $res3) $res = true;
+        else $res = false;
+        ModelBasic::checkTrans($res);
+        if ($res) return Json::successful('修改成功!');
+        else return Json::fail('修改失败');
+    }
+
+    /**
+     * 用户图表
+     * @return mixed
+     */
+    public function user_analysis()
+    {
+        $where = parent::getMore([
+            ['nickname', ''],
+            ['status', ''],
+            ['is_promoter', ''],
+            ['date', ''],
+            ['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'][] = UserBill::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();
+    }
+
+    /**
+     * 会员详情
+     */
+    public function see($uid = '')
+    {
+        $this->assign([
+            'uid' => $uid,
+            'userinfo' => UserModel::getUserDetailed($uid),
+            'is_layui' => true,
+            'headerList' => UserModel::getHeaderList($uid),
+            'count' => UserModel::getCountInfo($uid),
+            'gold_name'=>SystemConfigService::get("gold_name")
+        ]);
+        return $this->fetch();
+    }
+
+    public function getBuySpecilList($uid, $page = 1, $limit = 20)
+    {
+        $list = SpecialBuy::where(['a.uid' => $uid, 'a.is_del' => 0])
+            ->join('__STORE_ORDER__ o', 'a.order_id=o.order_id', 'left')
+            ->join("__SPECIAL__ s", 's.id=a.special_id')
+            ->alias('a')->field(['a.*', 'o.total_num', 'o.pay_price', 's.title'])->page((int)$page, (int)$limit)->select();
+        $list=count($list) ? $list->toArray() : [];
+        foreach ($list as &$value){
+            if($value['type']=='赠送获得') {
+                $value['order_id']='赠送获得';
+                $value['total_num']='1';
+                $value['pay_price']='0';
+            }
+        }
+        return Json::successful($list);
+    }
+
+    public function del_special_buy($id = 0)
+    {
+        if ($id == 0) return Json::fail('缺少参数');
+        if (SpecialBuy::where('id', $id)->update(['is_del' => 1]))
+            return Json::successful('删除成功');
+        else
+            return Json::fail('删除失败');
+    }
+
+    /*
+     * 获取某个用户的推广下线
+     * */
+    public function getSpreadList($uid, $page = 1, $limit = 20)
+    {
+        return Json::successful(UserModel::getSpreadList($uid, (int)$page, (int)$limit));
+    }
+
+    /**
+     * 获取某用户的订单列表
+     */
+    public function getOneorderList($uid, $page = 1, $limit = 20)
+    {
+        return Json::successful(StoreOrder::getOneorderList(compact('uid', 'page', 'limit')));
+    }
+    /**
+     * 获取某用户的签到列表
+     */
+    public function getOneSignList($uid, $page = 1, $limit = 20)
+    {
+        return Json::successful(UserBillAdmin::getOneSignList(compact('uid', 'page', 'limit')));
+    }
+
+    /**
+     * 获取某用户的余额变动记录
+     */
+    public function getOneBalanceChangList($uid, $page = 1, $limit = 20)
+    {
+        return Json::successful(UserBillAdmin::getOneBalanceChangList(compact('uid', 'page', 'limit')));
+    }
+}

+ 320 - 0
application/admin/controller/user/UserNotice.php

@@ -0,0 +1,320 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\user;
+
+use app\admin\controller\AuthController;
+use service\FormBuilder as Form;
+use service\JsonService as Json;
+use think\Request;
+use think\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 = parent::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::build('save'));
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 保存新建的资源
+     *
+     * @param  \think\Request $request
+     * @return \think\Response
+     */
+    public function save(Request $request)
+    {
+        $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");
+            $params["uid"] = count($uids) > 0 ? "," . implode(",", $uids) . "," : "";
+        }
+        $params["add_time"] = time();
+        UserNoticeModel::set($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::build('update', ["id" => $id]), 2);
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 保存新建的资源
+     *
+     * @param  \think\Request $request
+     * @return \think\Response
+     */
+    public function update(Request $request, $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('__USER_NOTICE_SEE__ 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  \think\Request $request
+     * @return \think\Response
+     */
+    public function user_create($id)
+    {
+        $where = parent::getMore([
+            ['nickname', ''],
+            ['data', ''],
+        ], $this->request);
+        $this->assign('where', $where);
+        $this->assign(UserModel::systemPage($where));
+        $this->assign(['title' => '添加发送用户', 'save' => Url::build('user_save', array('id' => $id))]);
+        return $this->fetch();
+    }
+
+    /**
+     * 保存新建的资源
+     *
+     * @param  \think\Request $request
+     * @return \think\Response
+     */
+    public function user_save(Request $request, $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");
+        } 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");
+        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  \think\Request $request
+     * @return \think\Response
+     */
+    public function user_select_delete(Request $request, $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 = parent::getMore([
+            ['title', ''],
+        ], $this->request);
+        $nickname = UserModel::where('uid', 'IN', $id)->column('uid,nickname');
+        $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('参数错误');
+        $uid = "," . $uid . ",";
+        UserNoticeModel::edit(array("is_send" => 1, "send_time" => time(), 'uid' => $uid), $id);
+        return Json::successful('发送成功!');
+    }
+}

+ 37 - 0
application/admin/controller/user/UserSign.php

@@ -0,0 +1,37 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\user;
+
+use app\admin\model\user\UserSign as UserSignModel;
+use app\admin\controller\AuthController;
+use service\JsonService as Json;
+use think\Url;
+use think\Request;
+
+class UserSign extends AuthController
+{
+    public function index()
+    {
+        return $this->fetch();
+    }
+
+    public function getUserSignList()
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['title', ''],
+        ]);
+        return Json::successlayui(UserSignModel::getUserSignList($where));
+    }
+
+}

+ 261 - 0
application/admin/controller/user/UserSpread.php

@@ -0,0 +1,261 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\user;
+
+use app\admin\controller\AuthController;
+use service\JsonService;
+use service\QrcodeService;
+use traits\CurdControllerTrait;
+use app\admin\model\user\User;
+use app\admin\model\user\UserBill;
+use app\admin\model\wechat\WechatUser as UserModel;
+use app\admin\model\order\StoreOrder;
+
+/**
+ * 用户推广员管理
+ * Class UserSpread
+ * @package app\admin\controller\user
+ */
+class UserSpread extends AuthController
+{
+    use CurdControllerTrait;
+
+    public function index()
+    {
+        $this->assign( 'year',getMonth());
+        return $this->fetch();
+    }
+
+    public function spread_list()
+    {
+        $where=parent::getMore([
+            ['nickname',''],
+            ['start_time',''],
+            ['end_time',''],
+            ['sex',''],
+            ['excel',''],
+            ['data',''],
+            ['subscribe',''],
+            ['order',''],
+            ['page',1],
+            ['limit',20],
+            ['user_type',''],
+        ]);
+        return JsonService::successlayui(UserModel::agentSystemPage($where));
+    }
+
+    public function get_badge_list()
+    {
+        $where = parent::postMore([
+            ['data',''],
+            ['nickname',''],
+            ['excel',''],
+        ]);
+        return JsonService::successful(UserModel::getSpreadBadge($where));
+    }
+    /**
+     * 一级推荐人页面
+     * @return mixed
+     */
+    public function stair($uid = ''){
+        if($uid == '') return $this->failed('参数错误');
+        $this->assign('uid',$uid ? : 0);
+        $this->assign( 'year',getMonth());
+        return $this->fetch();
+    }
+    /*
+    *  统计推广订单
+    * @param int $uid
+    * */
+    public function stair_order($uid = 0)
+    {
+        if($uid == '') return $this->failed('参数错误');
+        $this->assign('uid',$uid ? : 0);
+        $this->assign( 'year',getMonth());
+        return $this->fetch();
+    }
+
+    public function get_stair_order_list(){
+        $where = parent::getMore([
+            ['uid',$this->request->param('uid',0)],
+            ['data',''],
+            ['order_id',''],
+            ['type',''],
+            ['page',1],
+            ['limit',20],
+        ]);
+        return JsonService::successlayui(UserModel::getStairOrderList($where));
+    }
+
+    public function get_stair_order_badge()
+    {
+        $where = parent::getMore([
+            ['uid',''],
+            ['data',''],
+            ['order_id',''],
+            ['type',''],
+        ]);
+        return JsonService::successful(UserModel::getStairOrderBadge($where));
+    }
+
+    public function get_stair_list()
+    {
+        $where = parent::getMore([
+            ['uid',$this->request->param('uid',0)],
+            ['data',''],
+            ['nickname',''],
+            ['type',''],
+            ['page',1],
+            ['limit',20],
+        ]);
+        return JsonService::successlayui(UserModel::getStairList($where));
+    }
+
+    public function get_stair_badge()
+    {
+        $where = parent::getMore([
+            ['uid',''],
+            ['data',''],
+            ['nickname',''],
+            ['type',''],
+        ]);
+        return JsonService::successful(UserModel::getSairBadge($where));
+    }
+
+    /**
+     * 二级推荐人页面
+     * @return mixed
+     */
+    public function stair_two($uid = '')
+    {
+        if($uid == '') return $this->failed('参数错误');
+        $spread_uid=User::where('spread_uid',$uid)->column('uid','uid');
+        if(count($spread_uid))
+            $spread_uid_two=User::where('spread_uid','in',$spread_uid)->column('uid','uid');
+        else
+            $spread_uid_two=[0];
+        $list = User::alias('u')
+            ->where('u.uid','in',$spread_uid_two)
+            ->field('u.avatar,u.nickname,u.now_money,u.spread_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'])?:0;
+        $this->assign('list',$list);
+        return $this->fetch('stair');
+    }
+
+    /*
+     * 批量清除推广权限
+     * */
+    public function delete_promoter()
+    {
+        list($uids)=parent::postMore([
+            ['uids',[]]
+        ],$this->request,true);
+        if(!count($uids)) return JsonService::fail('请选择需要解除推广权限的用户!');
+        User::beginTrans();
+        try{
+            if(User::where('uid','in',$uids)->update(['is_promoter'=>0])){
+                User::commitTrans();
+                return JsonService::successful('解除成功');
+            }else{
+                User::rollbackTrans();
+                return JsonService::fail('解除失败');
+            }
+        }catch (\PDOException $e){
+            User::rollbackTrans();
+            return JsonService::fail('数据库操作错误',['line'=>$e->getLine(),'message'=>$e->getMessage()]);
+        }catch (\Exception $e){
+            User::rollbackTrans();
+            return JsonService::fail('系统错误',['line'=>$e->getLine(),'message'=>$e->getMessage()]);
+        }
+
+    }
+
+    /*
+     * 查看公众号推广二维码
+     * @param int $uid
+     * @return json
+     * */
+    public function look_code($uid='',$action='')
+    {
+        if(!$uid || !$action) return JsonService::fail('缺少参数');
+        try{
+            if(method_exists($this,$action)){
+                $res = $this->$action($uid);
+                if($res)
+                    return JsonService::successful($res);
+                else
+                    return JsonService::fail(isset($res['msg']) ? $res['msg'] : '获取失败,请稍后再试!' );
+            }else
+                return JsonService::fail('暂无此方法');
+        }catch (\Exception $e){
+            return JsonService::fail('获取推广二维码失败,请检查您的微信配置',['line'=>$e->getLine(),'messag'=>$e->getMessage()]);
+        }
+    }
+
+
+    /*
+     * 获取公众号二维码
+     * */
+    public function wechant_code($uid)
+    {
+        $qr_code = QrcodeService::getForeverQrcode('spread',$uid);
+        if(isset($qr_code['url']))
+            return ['code_src'=>$qr_code['url']];
+        else
+            throw new \think\Exception('获取失败,请稍后再试!');
+    }
+
+    /*
+     * 解除单个用户的推广权限
+     * @param int $uid
+     * */
+    public function delete_spread($uid=0)
+    {
+        if(!$uid) return JsonService::fail('缺少参数');
+        if(User::where('uid',$uid)->update(['is_promoter'=>0]))
+            return JsonService::successful('解除成功');
+        else
+            return JsonService::fail('解除失败');
+    }
+
+    /*
+     * 清除推广人
+     * */
+    public function empty_spread($uid=0)
+    {
+        if(!$uid) return JsonService::fail('缺少参数');
+        $res =  User::where('uid',$uid)->update(['spread_uid'=>0]);
+        if($res)
+            return JsonService::successful('清除成功');
+        else
+            return JsonService::fail('清除失败');
+    }
+    /**
+     * 个人资金详情页面
+     * @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();
+    }
+}

+ 48 - 0
application/admin/controller/wechat/Menus.php

@@ -0,0 +1,48 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\wechat;
+
+use app\admin\controller\AuthController;
+use service\WechatService;
+use think\Cache;
+use think\Db;
+use think\Request;
+
+/**
+ * 微信菜单  控制器
+ * Class Menus
+ * @package app\admin\controller\wechat
+ */
+class Menus extends AuthController
+{
+
+    public function index()
+    {
+        $menus = Db::name('cache')->where('key', 'wechat_menus')->value('result');
+        $menus = $menus ?: '[]';
+        $this->assign('menus', $menus);
+        return $this->fetch();
+    }
+
+    public function save(Request $request)
+    {
+        $buttons = $request->post('button/a', []);
+        if (!count($buttons)) return $this->failed('请添加至少一个按钮');
+        try {
+            WechatService::menuService()->add($buttons);
+            Db::name('cache')->insert(['key' => 'wechat_menus', 'result' => json_encode($buttons), 'add_time' => time()], true);
+            return $this->successful('修改成功!');
+        } catch (\Exception $e) {
+            return $this->failed($e->getMessage());
+        }
+    }
+}

+ 200 - 0
application/admin/controller/wechat/Reply.php

@@ -0,0 +1,200 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\wechat;
+
+use app\admin\controller\AuthController;
+use app\admin\model\wechat\WechatReply;
+use service\JsonService as Json;
+use service\UploadService as Upload;
+use think\Request;
+
+/**
+ * 关键字管理  控制器
+ * Class Reply
+ * @package app\admin\controller\wechat
+ */
+class Reply extends AuthController
+{
+    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 = '编辑关注回复';
+                break;
+            case 'default':
+                $title = '编辑关键字默认回复';
+                break;
+            default:
+                $title = '编辑关键字回复';
+                break;
+        }
+
+        $replay = WechatReply::where('key', input('key'))->find();
+        $replay_arr = $replay ? $replay : [];
+        if (isset($replay_arr['data'])) $replay_arr['data'] = json_decode($replay_arr['data'], true);
+        $this->assign('replay_arr', json_encode($replay_arr));
+        $this->assign('key',$key);
+        $this->assign('title', $title);
+        return $this->fetch();
+    }
+
+    public function one_reply()
+    {
+        $where = parent::postMore([
+            ['key'],
+            ['add', 0],
+        ], $this->request);
+        if (!empty($where['key'])) $replay = WechatReply::where('key', $where['key'])->find();
+        $replay_arr = $replay->toArray();
+        $replay_arr['code'] = 200;
+        $replay_arr['data'] = json_decode($replay_arr['data'], true);
+        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(Request $request)
+    {
+        $data = parent::postMore([
+            'type',
+            'key',
+            ['status', 0],
+            ['data', []],
+        ], $request);
+        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(Request $request)
+    {
+        $name = $request->post('file');
+        if (!$name) return Json::fail('请上传图片');
+        $res = Upload::image($name, 'wechat/image');
+        return $res->status === true ? Json::successful('上传成功', $res->filePath) : Json::fail($res->error);
+    }
+
+    public function upload_file(Request $request)
+    {
+        $name = $request->post('file');
+        if (!$name) return Json::fail('请上传声音');
+        $autoValidate['size'] = 2097152;
+        $res = Upload::file($name, 'wechat/voice', true, $autoValidate);
+        return $res->status === true ? Json::successful('上传成功', $res->filePath) : Json::fail($res->error);
+    }
+
+    /**
+     * 关键字回复
+     * */
+    public function keyword()
+    {
+        $where = parent::getMore([
+            ['key', ''],
+            ['type', ''],
+        ], $this->request);
+        $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', json_encode(array()));
+        return $this->fetch();
+    }
+
+    /**
+     * 修改关键字
+     * */
+    public function info_keyword()
+    {
+        $key = input('key');
+        if (empty($key)) return $this->failed('参数错误,请重新修改');
+        $replay = WechatReply::where('key', $key)->find();
+       if($replay){
+           $replay_arr = $replay->toArray();
+           $replay_arr['data'] = json_decode($replay_arr['data'], true);
+       }else{
+           $replay_arr=[];
+       }
+        $this->assign('replay_arr', json_encode($replay_arr));
+        $this->assign('key', $key);
+        $this->assign('dis', 2);
+        return $this->fetch('add_keyword');
+    }
+
+    /**
+     * 保存关键字
+     * */
+    public function save_keyword(Request $request)
+    {
+        $data = parent::postMore([
+            'key',
+            'type',
+            ['status', 0],
+            ['data', []],
+        ], $request);
+        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('删除成功!');
+    }
+
+
+}

+ 186 - 0
application/admin/controller/wechat/StoreService.php

@@ -0,0 +1,186 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\wechat;
+
+use app\admin\controller\AuthController;
+use service\FormBuilder as Form;
+use service\JsonService as Json;
+use service\UploadService as Upload;
+use think\Request;
+use think\Url;
+use app\admin\model\wechat\StoreService as ServiceModel;
+use app\admin\model\wechat\StoreServiceLog as StoreServiceLog;
+use app\admin\model\wechat\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 = parent::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::build('save')]);
+        return $this->fetch();
+    }
+
+    /**
+     * 保存新建的资源
+     *
+     * @param  \think\Request $request
+     * @return \think\Response
+     */
+    public function save(Request $request)
+    {
+        $params = $request->post();
+        if (count($params["checked_menus"]) <= 0) return Json::fail('请选择要添加的用户!');
+        if (ServiceModel::where('mer_id', 0)->where(array("uid" => array("in", $params["checked_menus"])))->count()) return Json::fail('添加用户中存在已有的客服!');
+        foreach ($params["checked_menus"] as $key => $value) {
+            $now_user = UserModel::where('uid', $value)->find();
+            $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::build('admin/widget.images/index', array('fodder' => 'avatar')), $service['avatar'])->icon('image');
+        $f[] = Form::input('nickname', '客服名称', $service["nickname"]);
+//        $f[] = Form::switches('notify', '订单通知', 1)->trueValue(1)->falseValue(0)->openStr('开启')->closeStr('关闭');
+        $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::build('update', compact('id')));
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 保存新建的资源
+     *
+     * @param  \think\Request $request
+     * @return \think\Response
+     */
+    public function update(Request $request, $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']
+        );
+        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\Json
+     */
+    public function upload()
+    {
+        $res = Upload::image('file', 'store/service');
+        $thumbPath = Upload::thumb($res->dir);
+        if ($res->status == 200)
+            return Json::successful('图片上传成功!', ['name' => $res->fileInfo->getSaveName(), 'url' => Upload::pathToUrl($thumbPath)]);
+        else
+            return Json::fail($res->error);
+    }
+
+    /**
+     * 显示资源列表
+     *
+     * @return \think\Response
+     */
+    public function chat_user($id)
+    {
+        $now_service = ServiceModel::get($id);
+        if (!$now_service) return Json::fail('数据不存在!');
+        $list = ServiceModel::getChatUser($now_service, 0);
+        $this->assign(compact('list', 'now_service'));
+        return $this->fetch();
+    }
+
+    /**
+     * 显示资源列表
+     *
+     * @return \think\Response
+     */
+    public function chat_list($uid, $to_uid)
+    {
+        $this->assign(StoreServiceLog::getChatList($uid, $to_uid, 0));
+        $this->assign('to_uid', $to_uid);
+        return $this->fetch();
+    }
+}

+ 43 - 0
application/admin/controller/wechat/WechatMessage.php

@@ -0,0 +1,43 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\wechat;
+
+use app\admin\controller\AuthController;
+use app\admin\model\wechat\WechatMessage as MessageModel;
+
+/**
+ * 用户扫码点击事件
+ * Class SystemMessage
+ * @package app\admin\controller\system
+ */
+class WechatMessage extends AuthController
+{
+
+    /**
+     * 显示操作记录
+     */
+    public function index()
+    {
+        $where = parent::getMore([
+            ['nickname', ''],
+            ['type', ''],
+            ['data', ''],
+        ], $this->request);
+        $this->assign('where', $where);
+        $this->assign('mold', MessageModel::$mold);
+        $this->assign(MessageModel::systemPage($where));
+        return $this->fetch();
+    }
+
+
+}
+

+ 291 - 0
application/admin/controller/wechat/WechatNewsCategory.php

@@ -0,0 +1,291 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\wechat;
+
+use app\admin\controller\AuthController;
+use app\admin\model\article\Article;
+use service\FormBuilder as Form;
+use service\JsonService as Json;
+use app\admin\model\wechat\WechatReply;
+use app\admin\model\wechat\WechatUser;
+use think\Db;
+use think\Request;
+use think\Url;
+use service\WechatService;
+use app\admin\model\wechat\WechatNewsCategory as WechatNewsCategoryModel;
+use app\admin\model\article\Article as ArticleModel;
+
+/**
+ * 图文信息
+ * Class WechatNewsCategory
+ * @package app\admin\controller\wechat
+ *
+ */
+class WechatNewsCategory extends AuthController
+{
+    public function select($callback = '_selectNews$eb')
+    {
+        $where = parent::getMore([
+            ['cate_name', '']
+        ], $this->request);
+        $this->assign('where', $where);
+        $this->assign('callback', $callback);
+        $this->assign(WechatNewsCategoryModel::getAll($where));
+        return $this->fetch();
+    }
+
+    public function index()
+    {
+        $where = parent::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::build('save'));
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    public function save(Request $request)
+    {
+        $data = parent::postMore([
+            'cate_name',
+            ['new_id', []],
+            ['sort', 0],
+            ['add_time', time()],
+            ['status', 1],], $request);
+        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::set($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::build('update', compact('id')));
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    public function update(Request $request, $id)
+    {
+        $data = parent::postMore([
+            'cate_name',
+            ['new_id', []],
+            ['sort', 0],
+            ['status', 1],], $request);
+        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)
+    {
+        $cate=WechatNewsCategoryModel::get($id);
+        if (!$cate){
+            return Json::fail(WechatNewsCategoryModel::getErrorInfo('删除失败,请稍候再试!'));
+        }else{
+            $res=WechatNewsCategoryModel::del($id);
+            $res1=Article::where('id',$cate['new_id'])->delete();
+            if($res && $res1){
+                return Json::successful('删除成功!');
+            }else{
+                return Json::fail(WechatNewsCategoryModel::getErrorInfo('删除失败,请稍候再试!'));
+            }
+        }
+    }
+
+
+    /**
+     * 发送消息
+     * @param int $id
+     * @param string $wechat
+     * $wechat  不为空  发消息  /  空 群发消息
+     */
+    public function push($id = 0, $wechat = '')
+    {
+        if (!$id) return Json::fail('参数错误');
+        $list = WechatNewsCategoryModel::getWechatNewsItem($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) . ',剩余的发送成功');
+        } else {//群发消息
+        }
+    }
+
+    public function send_news($id = '')
+    {
+        if ($id == '') return $this->failed('参数错误');
+        $where = parent::getMore([
+            ['cate_name', '']
+        ], $this->request);
+        $this->assign('where', $where);
+        $this->assign('wechat', $id);
+        $this->assign(WechatNewsCategoryModel::getAll($where));
+        return $this->fetch();
+    }
+
+    public function append()
+    {
+        $this->assign('list', [
+            [
+                'id' => 0,
+                'title' => '',
+                'author' => $this->adminInfo->real_name,
+                'content' => '',
+                'image_input' => '/public/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(Request $request)
+    {
+        $data = parent::postMore([
+            ['list', []],
+            ['id', 0]
+        ], $request);
+        $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['hide'] = 1;
+            $v['add_time'] = time();
+            if ($v['id']) {
+                $idC = $v['id'];
+                unset($v['id']);
+                Article::edit($v, $idC);
+                Db::name('ArticleContent')->where('nid', $idC)->update(['content' => $v['content']]);
+                $data['list'][$k]['id'] = $idC;
+                $id[] = $idC;
+            } else {
+                unset($v['id']);
+                $v['is_show']=1;
+                $res = Article::set($v)->toArray();
+                $id[] = $res['id'];
+                $data['list'][$k]['id'] = $res['id'];
+                Db::name('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::set($newsCategory);
+                return Json::successful('添加成功');
+            }
+        }
+    }
+
+    public function modify($id)
+    {
+        $menu = WechatNewsCategoryModel::get($id);
+        $list = Article::getArticleList($menu['new_id']);
+        $this->assign('list', $list);
+        $this->assign('id', $id);
+        $this->assign('author', $this->adminInfo->real_name);
+        return $this->fetch('append');
+    }
+
+}

+ 143 - 0
application/admin/controller/wechat/WechatTemplate.php

@@ -0,0 +1,143 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\wechat;
+
+use app\admin\controller\AuthController;
+use service\FormBuilder as Form;
+use service\JsonService as Json;
+use service\WechatTemplateService;
+use think\Cache;
+use think\Request;
+use think\Url;
+use app\admin\model\wechat\WechatTemplate as WechatTemplateModel;
+use app\admin\model\system\SystemConfig;
+
+/**
+ * 微信模板消息控制器
+ * Class WechatTemplate
+ * @package app\admin\controller\wechat
+ */
+class WechatTemplate extends AuthController
+{
+
+    protected $cacheTag = '_system_wechat';
+
+    public function index()
+    {
+        $where = parent::getMore([
+            ['name', ''],
+            ['status', '']
+        ], $this->request);
+        $this->assign('where', $where);
+        $this->assign(WechatTemplateModel::SystemPage($where));
+        try {
+            $industry = Cache::tag($this->cacheTag)->remember('_wechat_industry', function () {
+                $cache = WechatTemplateService::getIndustry();
+                if (!$cache) return [];
+                Cache::tag($this->cacheTag, ['_wechat_industry']);
+                return $cache->toArray();
+            }, 0) ?: [];
+        } catch (\Exception $e) {
+            $industry = [];
+        }
+        !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::build('save'));
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    public function save(Request $request)
+    {
+        $data = parent::postMore([
+            'tempkey',
+            'tempid',
+            'name',
+            'content',
+            ['status', 0]
+        ], $request);
+        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();
+        WechatTemplateModel::set($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::build('update', compact('id')));
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    public function update(Request $request, $id)
+    {
+        $data = parent::postMore([
+            'tempid',
+            ['status', 0]
+        ], $request);
+        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('删除成功!');
+    }
+
+
+}

+ 394 - 0
application/admin/controller/wechat/WechatUser.php

@@ -0,0 +1,394 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\wechat;
+
+use app\admin\controller\AuthController;
+use service\FormBuilder as Form;
+use app\admin\model\user\User;
+use app\admin\model\wechat\WechatUser as UserModel;
+use app\wap\model\user\UserBill;
+use service\JsonService;
+use service\WechatService;
+use think\Collection;
+use think\Request;
+use think\Url;
+
+/**
+ * 管理员操作记录表控制器
+ * Class WechatUser
+ * @package app\admin\controller\wechat
+ */
+class WechatUser extends AuthController
+{
+    /**
+     * 显示操作记录
+     */
+    public function index()
+    {
+        $where = parent::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);
+        $this->assign([
+            'where' => $where,
+            'groupList' => UserModel::getUserGroup(),
+            'tagList' => UserModel::getUserTag()
+        ]);
+        $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::build('update_user_tag', compact('openid')));
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    public function update_user_tag(Request $request, $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::beginTrans();
+        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('tag_id', '用户标签', (string)$groupId)->setOptions($list->toArray())];
+        $form = Form::make_post_form('标签名称', $f, Url::build('update_user_group', compact('openid')));
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    public function update_user_group(Request $request, $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)
+    {
+        if ($refresh == 1) {
+            UserModel::clearUserTag();
+            $this->redirect(Url::build('tag'));
+        }
+        $list = UserModel::getUserTag();
+        $this->assign(compact('list'));
+        return $this->fetch();
+    }
+
+    /**
+     * 添加标签
+     * @return mixed
+     */
+    public function create_tag()
+    {
+        $f = [Form::input('name', '标签名称')];
+        $form = Form::make_post_form('标签名称', $f, Url::build('save_tag'));
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 添加
+     * @param Request $request
+     * @return \think\response\Json
+     */
+    public function save_tag(Request $request)
+    {
+        $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::build('update_tag', ['id' => $id]));
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 修改标签
+     * @param Request $request
+     * @param $id
+     * @return \think\response\Json
+     */
+    public function update_tag(Request $request, $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)
+    {
+        if ($refresh == 1) {
+            UserModel::clearUserGroup();
+            $this->redirect(Url::build('group'));
+        }
+        $list = UserModel::getUserGroup();
+        $this->assign(compact('list'));
+        return $this->fetch();
+    }
+
+    /**
+     * 添加分组
+     * @return mixed
+     */
+    public function create_group()
+    {
+        $f = [Form::input('name', '分组名称')];
+        $form = Form::make_post_form('标签名称', $f, Url::build('save_group'));
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 添加
+     * @param Request $request
+     * @return \think\response\Json
+     */
+    public function save_group(Request $request)
+    {
+        $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::build('update_group', compact('id')));
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 修改分组
+     * @param Request $request
+     * @param $id
+     * @return \think\response\Json
+     */
+    public function update_group(Request $request, $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();
+        $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();
+    }
+
+}
+

+ 299 - 0
application/admin/controller/widget/Images.php

@@ -0,0 +1,299 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\widget;
+
+use Api\AliyunOss;
+use app\admin\model\system\SystemAttachment as SystemAttachmentModel;
+use app\admin\model\system\SystemAttachmentCategory as Category;
+use app\admin\controller\AuthController;
+use service\SystemConfigService;
+use service\JsonService as Json;
+use service\FormBuilder as Form;
+use think\Url;
+
+/**
+ * TODO 附件控制器
+ * Class Images
+ * @package app\admin\controller\widget
+ */
+class Images extends AuthController
+{
+
+    /**
+     * 初始化
+     */
+    protected function init()
+    {
+        return AliyunOss::instance([
+            'AccessKey' => SystemConfigService::get('accessKeyId'),
+            'AccessKeySecret' => SystemConfigService::get('accessKeySecret'),
+            'OssEndpoint' => SystemConfigService::get('end_point'),
+            'OssBucket' => SystemConfigService::get('OssBucket'),
+            'uploadUrl' => SystemConfigService::get('uploadUrl'),
+        ]);
+    }
+
+    /**
+     * 附件列表
+     * @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);
+        $this->assign('maxLength', $this->request->get('max_count', 0));
+        $this->assign('fodder', $this->request->param('fodder', $this->request->get('fodder','')));
+        return $this->fetch('widget/images');
+    }
+
+    /**获取图片列表
+     *
+     */
+    public function get_image_list()
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 18],
+            ['pid', 0]
+        ]);
+        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 = input('pid') != NULL ? input('pid') : session('pid');
+        try {
+            $aliyunOss = $this->init();
+            $res = $aliyunOss->upload('file');
+            if ($res) {
+                SystemAttachmentModel::attachmentAdd($res['key'], 0, 'image/jpg', $res['url'], $res['url'], $pid, 1, time());
+                return Json::successful(['url' => $res]);
+            } else {
+                return Json::fail($aliyunOss->getErrorInfo()['msg']);
+            }
+        } catch (\Exception $e) {
+            return Json::fail('上传失败:' . $e->getMessage());
+        }
+    }
+
+    /**
+     * ajax 提交删除
+     */
+    public function delete()
+    {
+        $post = $this->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 {
+                $this->init()->delOssFile($attinfo->name);
+            } catch (\Throwable $e) {
+            }
+            $attinfo->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::build('moveImgCecate'));
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 移动图片分类操作
+     */
+    public function moveImgCecate()
+    {
+        $data = parent::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::build('saveCate'), $jsContent);
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 添加分类
+     */
+    public function saveCate()
+    {
+        $post = $this->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::build('updateCate'), $jsContent);
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 更新分类
+     * @param $id
+     */
+    public function updateCate($id)
+    {
+        $data = parent::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)) {
+            SystemAttachmentModel::where(['pid' => $id])->update(['pid' => 0]);
+            return Json::successful('删除成功!');
+        } else
+            return Json::fail('删除失败');
+    }
+
+    /**
+     * 获取签名
+     */
+    public function get_signature()
+    {
+        return Json::successful($this->init()->getSignature());
+    }
+
+    /**
+     * 删除阿里云oss
+     * @param $key
+     */
+    public function del_oss_key($key = '', $url = '')
+    {
+        if (!$key && !$url) {
+            return Json::fail('删除失败');
+        }
+        if ($url) {
+            $key = SystemAttachmentModel::where(['att_dir' => $url])->value('name');
+        }
+        $res = $this->init()->delOssFile($key);
+        if ($res) {
+            return Json::successful('删除成功');
+        } else {
+            return Json::fail('删除失败');
+        }
+    }
+}

+ 62 - 0
application/admin/controller/widget/Widgets.php

@@ -0,0 +1,62 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+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');
+    }
+
+
+}

+ 198 - 0
application/admin/model/article/Article.php

@@ -0,0 +1,198 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+
+namespace app\admin\model\article;
+
+use app\admin\model\system\RecommendRelation;
+use app\admin\model\system\SystemAdmin;
+use traits\ModelTrait;
+use basic\ModelBasic;
+use think\Db;
+
+/**
+ * 图文管理 Model
+ * Class WechatNews
+ * @package app\admin\model\wechat
+ */
+class Article extends ModelBasic {
+
+    use ModelTrait;
+
+    public function profile()
+    {
+        return $this->hasOne('ArticleContent','nid','id')->field('content');
+    }
+    public static function getAddTimeAttr($value){
+        return $value ? date('Y-m-d H:i:s',$value) : '';
+    }
+    public static function getLabelAttr($value){
+        return is_string($value) ? json_decode($value,true) : $value;
+    }
+    public static function PreWhere($alias=''){
+        $alias=$alias ? $alias.'.' : '';
+        return self::where(["{$alias}is_show"=>1]);
+    }
+    public static function setWhere($where,$alias='',$model=null){
+        if($model===null) $model=new self();
+        if($alias){
+            $model->alias($alias);
+            $alias.='.';
+        }
+        if($where['store_name']) $model->where("{$alias}title",'LIKE',"%$where[store_name]%");
+        if($where['cid']) $model->where("{$alias}cid",$where['cid']);
+        if($where['order'])
+            $model->order($alias.self::setOrder($where['order']));
+        else
+            $model->order($alias.'sort desc');
+        if($where['is_show']!=='') $model->where("{$alias}is_show",$where['is_show']);
+        $model->where("{$alias}hide",0);
+        return $model;
+    }
+    public static function getArticleLayList($where){
+        $data=self::setWhere($where,'A')->join('__ARTICLE_CONTENT__ B','A.id=B.nid')->field('A.*,B.content')->page((int)$where['page'],(int)$where['limit'])->select();
+        foreach ($data as &$item){
+           $item['cate_name']=ArticleCategory::where('id',$item['cid'])->where('is_del',0)->value('title');
+        }
+        $count=self::setWhere($where)->count();
+        return compact('data','count');
+    }
+    /**
+     * 获取配置分类
+     * @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','GT',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('ArticleContent')->where('nid',$item['id'])->value('content');
+            $item['catename'] = Db::name('ArticleCategory')->where('id',$item['cid'])->value('title');
+        },$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('ArticleContent')->where('nid',$id)->count();
+        $data['nid'] = $id;
+        $data['content'] = $content;
+        if($count){
+            $res = Db::name('ArticleContent')->where('nid',$id)->setField('content',$content);
+            if($res !== false) $res = true;
+        }
+        else
+            $res = Db::name('ArticleContent')->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']);
+        return self::page($model,function($item){
+            $item['content'] = Db::name('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'] = Db::name('ArticleContent')->where('nid',$v['id'])->value('content');
+         }
+         return $list;
+    }
+
+
+    /**
+     * 获取活动咨询列表
+     * @param array $where
+     * @return array
+     */
+    public static function getConsultList($where = array()){
+        $model = new self;
+        if(isset($where['title']) && $where['title'] !== '') $model = $model->where('title','LIKE',"%$where[title]%");
+        if(isset($where['consult_type']) && $where['consult_type']) $model = $model->where('consult_type',$where['consult_type']);
+        $model = $model->where('is_consult',1)->where('hide',0);
+        return self::page($model,$where);
+    }
+
+}

+ 90 - 0
application/admin/model/article/ArticleCategory.php

@@ -0,0 +1,90 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\model\article;
+
+use traits\ModelTrait;
+use app\admin\model\article\Article as ArticleModel;
+use basic\ModelBasic;
+use service\UtilService as Util;
+
+/**
+ * 文章分类model
+ * Class ArticleCategory
+ * @package app\admin\model\wechat
+ */
+class ArticleCategory extends ModelBasic
+{
+    use ModelTrait;
+
+    /**
+     * 获取系统分页数据   分类
+     * @param array $where
+     * @return array
+     */
+    public static function systemPage($where = array()){
+        $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     field
+     * @param $field
+     * @return array
+     */
+    public  static function getField($field){
+          return self::where('is_del','eq',0)->where('status','eq',1)->where('hidden','eq',0)->column($field);
+    }
+    /**
+     * 分级排序列表
+     * @param null $model
+     * @return array
+     */
+    public static function getTierList($model = null)
+    {
+        if($model === null) $model = new self();
+        return Util::sortListTier($model->where('is_del',0)->select()->toArray());
+    }
+
+    /**
+     * 获取分类底下的文章
+     * id  分类表中的分类id
+     * return array
+     * */
+    public static function getArticle($id,$field){
+        $res = ArticleModel::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;
+    }
+
+}

+ 25 - 0
application/admin/model/article/ArticleContent.php

@@ -0,0 +1,25 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\model\article;
+
+use traits\ModelTrait;
+use basic\ModelBasic;
+
+/**
+ * Class ArticleContent
+ * @package app\admin\model\wechat
+ */
+class ArticleContent extends ModelBasic {
+
+    use ModelTrait;
+
+}

+ 38 - 0
application/admin/model/article/Search.php

@@ -0,0 +1,38 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\model\article;
+
+use traits\ModelTrait;
+use basic\ModelBasic;
+
+/**
+ * 关键词 Model
+ * Class WechatNews
+ * @package app\admin\model\article
+ */
+class Search extends ModelBasic
+{
+    use ModelTrait;
+
+    public static function saveSearch($name){
+        if(!self::be(['name'=>$name])){
+            if($res=self::set(['name'=>$name,'add_time'=>time()]))
+                return $res;
+            else
+                return self::setErrorInfo('添加失败');
+        }else
+            return self::setErrorInfo('请勿重复添加');
+    }
+    public static function getAll(){
+        return self::order('add_time desc')->select()->toArray();
+    }
+}

+ 289 - 0
application/admin/model/finance/FinanceModel.php

@@ -0,0 +1,289 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+
+namespace app\admin\model\finance;
+
+use traits\ModelTrait;
+use basic\ModelBasic;
+use service\ExportService;
+use app\wap\model\user\UserBill;
+use app\admin\model\user\User;
+use service\PHPExcelService;
+
+/**数据统计处理
+ * Class FinanceModel
+ * @package app\admin\model\finance
+ */
+class FinanceModel extends ModelBasic
+{
+    protected $name = 'user_bill';
+    use ModelTrait;
+
+    /**
+     * 处理金额
+     * @param $where
+     * @return array
+     */
+    public static function systemPage($where)
+    {
+        $model = new self;
+        //翻页
+        $limit = $where['limit'];
+        $offset= $where['offset'];
+        $limit = $offset.','.$limit;
+        //排序
+        $order = '';
+        if(!empty($where['sort'])&&!empty($where['sortOrder'])){
+            $order = $where['sort'].' '.$where['sortOrder'];
+        }
+        unset($where['limit']);unset($where['offset']);
+        unset($where['sort']);unset($where['sortOrder']);
+        if(!empty($where['add_time'])){
+            list($startTime,$endTime) = explode(' - ',$where['add_time']);
+            $where['add_time'] = array('between',[strtotime($startTime),strtotime($endTime)]);
+        }else{
+            $where['add_time'] = array('between',[strtotime(date('Y/m').'/01'),strtotime(date('Y/m').'/'.date('t'))]);
+        }
+        if(empty($where['title'])){
+            unset($where['title']);
+        }
+
+        $total = $model->where($where)->count();
+        $rows = $model->where($where)->order($order)->limit($limit)->select()->each(function($e){
+            return $e['add_time'] = date('Y-m-d H:i:s',$e['add_time']);
+        })->toArray();
+        return compact('total','rows');
+    }
+    public static function getBillList($where){
+        $data=($data=self::setWhereList($where)->page((int)$where['page'],(int)$where['limit'])->select()) && count($data) ? $data->toArray():[];
+        if ($data) {
+            foreach ($data as &$v) {
+                if ($where['category'] != "now_money") {
+                    $v['number'] = floor($v['number']);
+                }
+            }
+        }
+        $count=self::setWhereList($where)->count();
+        return compact('data','count');
+    }
+    public static function SaveExport($where){
+        $data=($data=self::setWhereList($where)->select()) && count($data) ? $data->toArray():[];
+        $export = [];
+        foreach ($data as $value){
+            $export[]=[
+                $value['uid'],
+                $value['nickname'],
+                $value['pm']==0 ? '-'.$value['number']:$value['number'],
+                $value['title'],
+                $value['mark'],
+                $value['add_time'],
+            ];
+        }
+        if($where['category']=='now_money'){
+            $type='余额';
+        }else{
+            $type='金币';
+        }
+        PHPExcelService::setExcelHeader(['会员ID','昵称',$type,'类型','备注','创建时间'])
+            ->setExcelTile('资金监控', '资金监控',date('Y-m-d H:i:s',time()))
+            ->setExcelContent($export)
+            ->ExcelSave();
+    }
+    public static function setWhereList($where){
+        $time['data']='';
+        if($where['start_time']!='' && $where['end_time']!=''){
+            $time['data']=$where['start_time'].' - '.$where['end_time'];
+        }
+        $bill_where_op = self::bill_where_op($where['category']);
+        if (!$bill_where_op) return false;
+        $model=self::getModelTime($time,self::alias('A')
+            ->join('user B','B.uid=A.uid')
+            ->where('A.category', $bill_where_op['category']['op'],$bill_where_op['category']['condition'])
+            ->order('A.add_time desc'),'A.add_time');
+        if(trim($where['type'])!=''){
+            $model=$model->where('A.type',$where['type']);
+        }else{
+            $model=$model->where('A.type', $bill_where_op['type']['op'],$bill_where_op['type']['condition']);
+        }
+        if($where['nickname']!=''){
+            $model=$model->where('B.nickname|B.uid','like',"%$where[nickname]%");
+        }
+        return $model->field(['A.*','FROM_UNIXTIME(A.add_time,"%Y-%m-%d %H:%i:%s") as add_time','B.uid','B.nickname','B.name']);
+    }
+
+    /**
+     * @param $category
+     * @return array|bool
+     */
+    public static function bill_where_op($category){
+        if (!$category || !in_array($category,['now_money','gold_num'])) {
+            return false;
+        }
+        switch($category){
+            case "now_money" :
+                $bill_where_op['category']['op'] = 'not in';
+                $bill_where_op['category']['condition'] = 'integral,gold_num';
+                $bill_where_op['type']['op'] = 'not in';
+                $bill_where_op['type']['condition'] = 'gain,deduction,sign,recharge,pay_vip,extract_success';
+                break;
+            case "gold_num" :
+                $bill_where_op['category']['op'] = 'in';
+                $bill_where_op['category']['condition'] = 'gold_num';
+                $bill_where_op['type']['op'] = 'in';
+                $bill_where_op['type']['condition'] = 'sign,recharge,live_reward,gain,return';
+                break;
+        }
+        return $bill_where_op;
+    }
+    /**
+     * 获取营业数据
+     */
+    public static function getOrderInfo($where)
+    {
+        $orderinfo = self::getTimeWhere($where)
+            ->field('sum(total_price) total_price,sum(cost) cost,sum(pay_postage) pay_postage,sum(pay_price) pay_price,sum(coupon_price) coupon_price,sum(deduction_price) deduction_price,from_unixtime(pay_time,\'%Y-%m-%d\') pay_time')->order('pay_time')->group('from_unixtime(pay_time,\'%Y-%m-%d\')')->select()->toArray();
+        $price = 0;
+        $postage = 0;
+        $deduction = 0;
+        $coupon = 0;
+        $cost = 0;
+        foreach ($orderinfo as $info) {
+            $price = bcadd($price, $info['total_price'], 2);//应支付
+            $postage = bcadd($postage, $info['pay_postage'], 2);//邮费
+            $deduction = bcadd($deduction, $info['deduction_price'], 2);//抵扣
+            $coupon = bcadd($coupon, $info['coupon_price'], 2);//优惠券
+            $cost = bcadd($cost, $info['cost'], 2);//成本
+        }
+        return compact('orderinfo', 'price', 'postage', 'deduction', 'coupon', 'cost');
+    }
+
+    /**
+     * 处理where条件
+     */
+    public static function statusByWhere($status, $model = null)
+    {
+        if ($model == null) $model = new self;
+        if ('' === $status)
+            return $model;
+        else if ($status == 'weixin')//微信支付
+            return $model->where('pay_type', 'weixin');
+        else if ($status == 'yue')//余额支付
+            return $model->where('pay_type', 'yue');
+        else if ($status == 'offline')//线下支付
+            return $model->where('pay_type', 'offline');
+        else
+            return $model;
+    }
+
+    public static function getTimeWhere($where, $model = null)
+    {
+        return self::getTime($where)->where('paid', 1)->where('refund_status', 0);
+    }
+    /**
+     * 获取时间区间
+     */
+    public static function getTime($where,$model=null,$prefix='add_time'){
+        if ($model == null) $model = new self;
+        if ($where['data'] == '') {
+            switch ($where['date']){
+                case 'today':case 'week':case 'month':case 'year':
+                    $model=$model->whereTime($prefix,$where['date']);
+                    break;
+                case 'quarter':
+                    list($startTime,$endTime)=User::getMonth('n');
+                    $model = $model->where($prefix, '>', strtotime($startTime));
+                    $model = $model->where($prefix, '<', strtotime($endTime));
+                    break;
+            }
+        }else{
+            list($startTime, $endTime) = explode(' - ', $where['data']);
+            $model = $model->where($prefix, '>', strtotime($startTime));
+            $model = $model->where($prefix, '<', strtotime($endTime));
+        }
+        return $model;
+    }
+    /**
+     * 获取新增消费
+     */
+    public static function getConsumption($where)
+    {
+        $consumption=self::getTime($where,new UserBill,'b.add_time')->alias('a')->join('user b','a.uid = b.uid')
+            ->field('sum(a.number) number')
+        ->where('a.type','pay_product')->find()->toArray();
+        return $consumption;
+    }
+    /**
+     * 获取普通商品数
+     */
+    public static function getOrdinary($where)
+    {
+        $ordinary = self::getTimeWhere($where)->where('pink_id', 'eq', 0)->where('seckill_id','eq','0')->sum('pay_price');
+        return $ordinary;
+    }
+
+    /**
+     * 获取用户充值
+     */
+    public static function getRecharge($where)
+    {
+        $Recharge = self::getTime($where,new UserBill)->where('type', 'system_add')->where('category','now_money')->sum('number');
+        return $Recharge;
+    }
+    /**
+     * 获取推广金
+     */
+    public static function getExtension($where)
+    {
+        $brokerage = self::getTime($where,new UserBill)->where('type', 'brokerage')->where('category','now_money')->sum('number');
+        $brokerage_return= self::getTime($where,new UserBill)->where('type', 'brokerage_return')->where('category','now_money')->sum('number');
+        $extension=bcsub($brokerage,$brokerage_return,2);
+        return $extension;
+    }
+
+    /**
+     * 最近交易
+     */
+    public static function trans()
+    {
+        $trans = self::alias('a')
+            ->join('user b', 'a.uid=b.uid')
+            ->join('store_order_cart_info c', 'a.id=c.oid')
+            ->join('store_product d', 'c.product_id=d.id')
+            ->field('b.nickname,a.pay_price,d.store_name')
+            ->order('a.add_time DESC')
+            ->limit('6')
+            ->select()->toArray();
+        return $trans;
+    }
+
+    /**
+     * 导出表格
+     */
+    public static function systemTable($where){
+        $orderinfos=self::getOrderInfo($where);
+        if($where['export'] == 1){
+            $export = [];
+            $orderinfo=$orderinfos['orderinfo'];
+            foreach($orderinfo as $info){
+                $time=$info['pay_time'];
+                $price = $info['total_price']+$info['pay_postage'];
+                $zhichu = $info['coupon_price']+$info['deduction_price']+$info['cost'];
+                $profit = ($info['total_price']+$info['pay_postage'])-($info['coupon_price']+$info['deduction_price']+$info['cost']);
+                $deduction=$info['deduction_price'];//积分抵扣
+                $coupon=$info['coupon_price'];//优惠
+                $cost=$info['cost'];//成本
+                $export[] = [$time,$price,$zhichu,$cost,$coupon,$deduction,$profit];
+            }
+            PHPExcelService::setExcelHeader(['时间','营业额(元)','支出(元)','成本','优惠','积分抵扣','盈利(元)'])->setExcelTile('财务统计', '财务统计',date('Y-m-d H:i:s',time()))->setExcelContent($export)->ExcelSave();
+        }
+    }
+}

+ 69 - 0
application/admin/model/live/LiveBarrage.php

@@ -0,0 +1,69 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\model\live;
+
+/**
+ * 直播间评论表
+ */
+use basic\ModelBasic;
+use traits\ModelTrait;
+
+class LiveBarrage extends ModelBasic
+{
+
+    use ModelTrait;
+
+    /*
+     * 设置where条件
+     * @param array $where 查询条件
+     * @param object $model 模型实例化对象
+     * @param string $alias 表别名
+     * @param string $jsonField json 模糊查询字段
+     * @return object
+     * */
+    public static function setWhere($where,$model =null ,$alias ='',$jsonField='')
+    {
+        $model = is_null($model) ? new self() : $model;
+        if($alias){
+            $model = $model->alias($alias);
+            $alias.='.';
+        }
+        if($where['nickname']) $model = $model->where("{$alias}barrage".($jsonField ? '|'.$jsonField : ""),'like',"%$where[nickname]%");
+        if($where['live_id']) $model = $model->where("{$alias}live_id",$where['live_id']);
+        if($where['start_time'] && $where['end_time']) $model = $model->where("{$alias}add_time",'between',[strtotime($where['start_time']),strtotime($where['end_time'])]);
+        return $model;
+    }
+    /*
+     * 查询评论列表
+     * @param array $where 查询条件
+     * @return array
+     * */
+    public static function getLiveCommentList($where)
+    {
+        $data = self::setWhere($where,null,'a','u.nickname')->join('user u','u.uid=a.uid')->field(['a.*','u.avatar','u.nickname'])
+            ->page((int)$where['page'],(int)$where['limit'])->order('id','desc')->select();
+        $data = count($data) ? $data->toArray() : [];
+        foreach ($data as &$item){
+            $type = LiveHonouredGuest::where(['uid'=>$item['uid'],'live_id'=>$where['live_id']])->value('type');
+            if($type === null)
+                $item['type_name'] = '听众';
+            else if($type === 1)
+                $item['type_name'] = '讲师';
+            else if($type === 0)
+                $item['type_name'] = '助教';
+            $item['add_time'] = date('Y-m-d H:i:s',$item['add_time']);
+        }
+        $count = self::setWhere($where,null,'a','u.nickname')->join('user u','u.uid=a.uid')->count();
+        return compact('data','count');
+    }
+
+}

+ 53 - 0
application/admin/model/live/LiveGift.php

@@ -0,0 +1,53 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\model\live;
+
+/**
+ * 直播间礼物
+ */
+use basic\ModelBasic;
+use traits\ModelTrait;
+use app\admin\model\system\SystemGroupData;
+
+class LiveGift extends ModelBasic
+{
+    use ModelTrait;
+
+    /**礼物列表
+     * @return array
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public static function liveGiftList()
+    {
+        $data=self::order('sort ASC')->select();
+        $data = count($data) ? $data->toArray() : [];
+        foreach ($data as &$item) {
+            $item['add_time'] = date('Y-m-d H:i:s',$item['add_time']);
+            $item['live_gift_num'] = implode(',',json_decode($item['live_gift_num']));
+        }
+        $count = self::count();
+        return compact('data','count');
+    }
+
+    /**
+     * 单个礼物信息
+     */
+    public static function liveGiftOne($id)
+    {
+        $gift=self::where('id',$id)->find();
+        if($gift) return $gift;
+        else return [];
+    }
+}

+ 203 - 0
application/admin/model/live/LiveGoods.php

@@ -0,0 +1,203 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\model\live;
+
+/**
+ * 直播带货商品
+ */
+use app\admin\model\order\StoreOrder;
+use app\admin\model\store\StoreProduct;
+use basic\ModelBasic;
+use traits\ModelTrait;
+
+class LiveGoods extends ModelBasic
+{
+    use ModelTrait;
+
+
+    /*
+     * 查询直播间用户列表
+     * @param array $where
+     * */
+    public static function getLiveGoodsList($where)
+    {
+        $data = self::alias('g');
+        $data = $data->where('g.is_delete',0)->where('g.type',0);
+        if ($where['store_name'] && isset($where['store_name'])){
+            $data = $data->whereLike('g.special_name',"%".$where['store_name']."%");
+        }
+        if ($where['is_show'] != "" && isset($where['is_show'])){
+            $data = $data->where('g.is_show',$where['is_show']);
+        }
+        if ($where['live_id'] != 0 && isset($where['live_id'])){
+            $data = $data->where('g.live_id',$where['live_id']);
+        }
+        $data = $data->join('special s','g.special_id=s.id')->join('__SPECIAL_SUBJECT__ J', 'J.id=s.subject_id')->field('g.id as live_goods_id, g.sort as gsort, g.fake_sales as gfake_sales, g.is_show as gis_show, g.sales as gsales, s.*, J.name as subject_name');
+        $data = $data->page((int)$where['page'],(int)$where['limit'])->select();
+        $data = count($data) ? $data->toArray() : [];
+        foreach ($data as &$item){
+            $item['_add_time']  = date('Y-m-d H:i:s',$item['add_time']);
+            $item['pink_end_time'] = $item['pink_end_time'] ? strtotime($item['pink_end_time']) : 0;
+            $item['sales'] = StoreOrder::where(['paid' => 1,'type'=>0, 'cart_id' => $item['id'], 'refund_status' => 0])->count();
+            //查看拼团状态,如果已结束关闭拼团
+            if ($item['is_pink'] && $item['pink_end_time'] < time()) {
+                self::update(['is_pink' => 0], ['id' => $item['id']]);
+                $item['is_pink'] = 0;
+            }
+        }
+        $count = self::alias('g')->join('special s','g.special_id=s.id')->count();
+        return compact('data','count');
+    }
+    public static function getLiveStoreProductList($where)
+    {
+        $data = self::alias('g');
+        $data = $data->where('g.is_delete',0)->where('g.type',1);
+        if ($where['store_name'] && isset($where['store_name'])){
+            $data = $data->whereLike('g.special_name',"%".$where['store_name']."%");
+        }
+        if ($where['is_show'] != "" && isset($where['is_show'])){
+            $data = $data->where('g.is_show',$where['is_show']);
+        }
+        if ($where['live_id'] != 0 && isset($where['live_id'])){
+            $data = $data->where('g.live_id',$where['live_id']);
+        }
+        $data = $data->join('StoreProduct s','g.special_id=s.id')->where(['s.is_del'=>0,'s.is_show'=>1])->join('StoreCategory c', 'c.id=s.cate_id')->field('g.live_id as live_id, g.id as live_goods_id, g.sort as gsort, g.fake_sales as gfake_sales, g.is_show as gis_show, g.sales as gsales, s.*,c.cate_name');
+        $data = $data->page((int)$where['page'],(int)$where['limit'])->select();
+        $data = count($data) ? $data->toArray() : [];
+        foreach ($data as &$item){
+            $item['_add_time']  = date('Y-m-d H:i:s',$item['add_time']);
+        }
+        $count = self::alias('g')->join('StoreProduct s','g.special_id=s.id')->where(['s.is_del'=>0,'s.is_show'=>1])->count();
+        return compact('data','count');
+    }
+
+    /**直播带课
+     * @param $live_id
+     * @param int $type
+     * @return LiveGoods|array|false|\PDOStatement|string|\think\Collection
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public static function getLiveGoodsLists($live_id,$type=0)
+    {
+        $data = self::alias('g');
+        $data = $data->where('g.is_delete',0);
+        $data = $data->where('g.live_id',$live_id);
+        $data = $data->where('g.type',$type);
+        $data = $data->join('special s','g.special_id=s.id')->where(['s.is_del'=>0,'s.is_show'=>1])->join('__SPECIAL_SUBJECT__ J', 'J.id=s.subject_id')->field('g.live_id as live_id, g.id as live_goods_id, g.sort, g.fake_sales as gfake_sales, g.is_show as gis_show, g.sales as gsales,
+         s.id,s.title,s.image,s.add_time,s.pink_end_time,s.is_pink,J.name as subject_name');
+        $data = $data->order('g.sort DESC')->select();
+        $data = count($data) ? $data->toArray() : [];
+        foreach ($data as &$item){
+            $item['_add_time']  = date('Y-m-d H:i:s',$item['add_time']);
+            $item['pink_end_time'] = $item['pink_end_time'] ? strtotime($item['pink_end_time']) : 0;
+            $item['sales'] = StoreOrder::where(['paid' => 1, 'cart_id' => $item['id'], 'refund_status' => 0])->count();
+            //查看拼团状态,如果已结束关闭拼团
+            if ($item['is_pink'] && $item['pink_end_time'] < time()) {
+                self::update(['is_pink' => 0], ['id' => $item['id']]);
+                $item['is_pink'] = 0;
+            }
+        }
+        return $data;
+    }
+
+    /**直播带货
+     * @param $live_id
+     * @param int $type
+     * @return LiveGoods|array|false|\PDOStatement|string|\think\Collection
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public static function getLiveProductLists($live_id,$type=0)
+    {
+        $data = self::alias('g');
+        $data = $data->where('g.is_delete',0);
+        $data = $data->where('g.live_id',$live_id);
+        $data = $data->where('g.type',$type);
+        $data = $data->join('StoreProduct s','g.special_id=s.id')->where(['s.is_del'=>0,'s.is_show'=>1])->field('g.live_id as live_id, g.id as live_goods_id, g.sort, g.fake_sales as gfake_sales, g.is_show as gis_show, g.sales as gsales,
+         s.id,s.store_name,s.image,s.price,s.sales,s.add_time');
+        $data = $data->order('g.sort DESC')->select();
+        $data = count($data) ? $data->toArray() : [];
+        foreach ($data as &$item){
+            $item['_add_time']  = date('Y-m-d H:i:s',$item['add_time']);
+        }
+        return $data;
+    }
+
+    /**插入带货商品
+     * @param array $data
+     * @return bool|int|string
+     */
+    public static function insterLiveGoods(array $data)
+    {
+        if (!$data) return false;
+        return self::insertGetId($data);
+    }
+
+    /**获取单个
+     * @param array $where
+     * @return array|bool|false|\PDOStatement|string|\think\Model
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public static function getOne(array $where)
+    {
+        if (!$where) return false;
+        return self::where($where)->find();
+    }
+    /**添加带货专题
+     * @param $source_list_ids  一维数组,素材id
+     * @param int $special_id 专题id
+     * @return bool
+     */
+    public static function saveLiveGoods($source_list_ids, int $special_id,$type=0)
+    {
+        if (!$special_id || !is_numeric($special_id)) {
+            return false;
+        }
+        $live_id = LiveStudio::where('special_id', $special_id)->field('id')->find();
+        if (!$live_id) return false;
+        if (!$source_list_ids) {
+            self::where(['live_id' => $live_id->id,'type'=>$type])->delete();
+            return true;
+        }
+        try {
+            $where['live_id'] = $live_id->id;
+            $liveGoodsAll = self::getOne($where);
+            if ($liveGoodsAll) {
+                self::where(['live_id' => $live_id->id,'type'=>$type])->delete();
+            }
+            $inster['live_id'] = $live_id->id;
+            foreach ($source_list_ids as $sk => $sv) {
+                $inster['special_id'] = $sv->id;
+                $inster['type'] = $type;
+                if($type==1){
+                    $inster['special_name'] = $sv->store_name;
+                }else{
+                    $inster['special_name'] = $sv->title;
+                }
+                $inster['sort'] = $sv->sort;
+                $inster['add_time'] = time();
+                self::set($inster);
+            }
+            return true;
+
+        } catch (\Exception $e) {
+            return false;
+        }
+    }
+
+}

+ 56 - 0
application/admin/model/live/LiveHonouredGuest.php

@@ -0,0 +1,56 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\model\live;
+
+/**
+ * 直播嘉宾
+ */
+use basic\ModelBasic;
+use traits\ModelTrait;
+
+class LiveHonouredGuest extends ModelBasic
+{
+    use ModelTrait;
+
+    /*
+     * 设置where条件
+     * @param array $where 条件
+     * */
+    public static function setWhere($where,$model = null,$alial='',$join='')
+    {
+        $model = $model === null ? new static() : $model;
+        if($alial){
+            $model = $model->alias($alial);
+            $alial.='.';
+        }
+        if($where['nickname'] != '') $model = $model->where("{$alial}nickname".($join ? '|'.$join : ''),'LIKE',"$where[nickname]");
+        return $model->where("{$alial}live_id",$where['live_id']);
+    }
+
+    /*
+     * 获取嘉宾列表
+     * @param array $where 查询条件
+     * @return array
+     * */
+    public static function getGuestList($where)
+    {
+        $data = self::setWhere($where,null,'a','u.nickname')->order('a.sort desc,a.add_time')->join('user u','a.uid=u.uid')->field(['a.*','u.avatar','u.nickname as u_nickname'])
+            ->page((int)$where['page'],(int)$where['limit'])->select();
+        $count = self::setWhere($where,null,'a','u.nickname')->join('user u','a.uid=u.uid')->count();
+        $data = count($data) ? $data->toArray() : [];
+        foreach ($data as &$item){
+            $item['nickname'] = $item['nickname'] ? : $item['u_nickname'];
+            $item['_type_name'] = $item['type'] ? '讲师': '助教';
+        }
+        return compact('data','count');
+    }
+}

+ 75 - 0
application/admin/model/live/LivePlayback.php

@@ -0,0 +1,75 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\model\live;
+
+/**
+ * 直播间用户表
+ */
+use basic\ModelBasic;
+use traits\ModelTrait;
+
+class LivePlayback extends ModelBasic
+{
+    use ModelTrait;
+
+    /**储存直播回放
+     * @param $item
+     * @param $record_id
+     */
+    public static function livePlaybackAdd($item){
+        if(!self::be(['RecordId'=>$item['RecordId'],'stream_name'=>$item['StreamName']])){
+            $data=[
+                'stream_name'=>$item['StreamName'],
+                'playback_url'=>$item['RecordUrl'],
+                'start_time'=>strtotime($item['StartTime']),
+                'end_time'=>strtotime($item['EndTime']),
+                'RecordId'=>$item['RecordId'],
+                'add_time'=>time(),
+            ];
+            return self::set($data);
+        }else{
+            return true;
+        }
+    }
+    /**
+     *  设置查询条件
+     */
+    public static function setUserWhere($where,$model = null,$alias='a',$jsonField='u.nickname')
+    {
+        $model = is_null($model) ? new self() : $model ;
+        if($alias){
+            $model = $model->alias($alias);
+            $alias.='.';
+        }
+        if($where['start_time'] && $where['end_time']) $model = $model->where("{$alias}add_time",'between',[strtotime($where['start_time']),strtotime($where['end_time'])]);
+        return $model->order("{$alias}sort desc,{$alias}add_time desc")->where("{$alias}stream_name",$where['stream_name'])->where("{$alias}is_del",0);
+    }
+
+    /**
+     * 查询直播间用户列表
+     * @param array $where
+     */
+    public static function getLivePlaybackList($where)
+    {
+        $data = self::setUserWhere($where)
+            ->page((int)$where['page'],(int)$where['limit'])->select();
+        $data = count($data) ? $data->toArray() : [];
+        foreach ($data as &$item){
+            $item['_add_time']  = date('Y-m-d H:i:s',$item['add_time']);
+            $item['StartTime']  = date('Y-m-d H:i:s',$item['start_time']);
+            $item['EndTime']  = date('Y-m-d H:i:s',$item['end_time']);
+        }
+        $count = self::setUserWhere($where)->count();
+        return compact('data','count');
+    }
+
+}

+ 95 - 0
application/admin/model/live/LiveReward.php

@@ -0,0 +1,95 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\model\live;
+
+/**
+ * 直播间礼物
+ */
+use basic\ModelBasic;
+use service\SystemConfigService;
+use traits\ModelTrait;
+use app\wap\model\user\User;
+use app\admin\model\live\LiveGift;
+
+class LiveReward extends ModelBasic
+{
+
+    use ModelTrait;
+
+    public static function getLiveRewardList($where)
+    {
+        $data = self::setWhere($where,'g')->field('g.total_price,g.uid,g.gift_id,g.id,g.live_id,from_unixtime(g.add_time) as add_time,g.gift_price,g.gift_num,u.avatar,u.nickname,l.live_title')->order('add_time desc')
+                  ->page((int)$where['page'],(int)$where['limit'])->select();
+        $data = count($data) ? $data->toArray() : [];
+        foreach ($data as &$item) {
+            $live_gift = LiveGift::liveGiftOne($item['gift_id']);
+            $item['gift_name'] = $live_gift ? $live_gift['live_gift_name'] : "";
+            $item['gift_image'] = $live_gift ? $live_gift['live_gift_show_img'] : "";
+        }
+        $count = self::setWhere($where,'g')->count();
+        return compact('data','count');
+    }
+
+    //设置条件
+    public static function setWhere($where, $alert = '', $model = null)
+    {
+        $model = $model === null ? new self() : $model;
+        if ($alert) $model = $model->alias($alert);
+        $alert = $alert ? $alert . '.' : '';
+        $model->whereIn($alert.'is_show',[0,1]);
+        $model->join('__LIVE_STUDIO__ l',$alert.'live_id = l.id');
+        $model->join('__USER__ u',$alert.'uid = u.uid');
+        $model->join('__SPECIAL__ s','s.id = l.special_id');
+        if (isset($where['admin_id']) && $where['admin_id']) {
+            $model->where('s.admin_id',$where['admin_id']);
+        }
+        if (isset($where['live_id']) && $where['live_id']) {
+            $model->where($alert.'live_id',$where['live_id']);
+        }
+        if (isset($where['gift_id']) && $where['gift_id']) {
+            $model->where($alert.'gift_id',$where['gift_id']);
+        }
+        if (isset($where['user_info']) && $where['user_info']) {
+            $userinfo = User::whereLike('nickname' ,"%".$where['user_info']."%")->whereOr('phone',$where['user_info'])->field('uid')->find();
+            $model->where($alert.'uid',$userinfo ? $userinfo['uid'] : 0);
+        }
+        if (isset($where['date']) && ($where['date'] != '' || $where['date'] != 0)) {
+            $where['data'] = $where['date'];
+            $model = self::getModelTime($where, $model, $alert . 'add_time');
+        }
+        return $model;
+    }
+
+    public static function getBadge($where)
+    {
+        $data = self::setWhere($where,'g')->field(['sum(g.total_price) as total_price','sum(g.gift_num) as gift_num'])->find();
+        $data = $data ? $data->toArray() : [];
+        return [
+            [
+                'name' => '虚拟币总额',
+                'field' => '个',
+                'count' => $data['total_price'],
+                'background_color' => 'layui-bg-blue',
+                'col' => 3
+            ],
+            [
+                'name' => '礼物数量',
+                'field' => '件',
+                'count' => $data['gift_num'],
+                'background_color' => 'layui-bg-blue',
+                'col' => 3
+            ]
+        ];
+    }
+
+
+}

+ 190 - 0
application/admin/model/live/LiveStudio.php

@@ -0,0 +1,190 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\model\live;
+
+/**
+ * 直播信息表
+ */
+use app\admin\model\order\StoreOrder;
+use app\admin\model\user\User;
+use basic\ModelBasic;
+use traits\ModelTrait;
+use \GatewayWorker\Lib\Gateway;
+use service\SystemConfigService;
+
+class LiveStudio extends ModelBasic
+{
+
+    use ModelTrait;
+
+    protected $insert = ['add_time'];
+
+    //直播间号码不能连续存在的数字
+    protected static $taboo = ['4', '38', '13', '14', '7', '7086', '5454', '3838', '36', '69', '47', '18'];
+
+    protected function setAddTimeAttr()
+    {
+        return time();
+    }
+
+    /**
+     * 生成并检查直播间号码
+     * @param string $StreamName 直播间号码
+     * @return string
+     * */
+    public static function getliveStreamName($StreamName = '')
+    {
+        if ($StreamName) {
+            if (preg_match('/[\x7f-\xff]/', $StreamName)) return self::setErrorInfo('直播间号码不能为中文');
+            if (strlen($StreamName) < 6) return self::setErrorInfo('直播间号码不能少于6位');
+            if (self::be(['stream_name' => $StreamName])) return self::setErrorInfo('直播间号码已存在');
+            return $StreamName;
+        } else {
+            $num = mt_rand(10, 99999999);//生成随机数
+            //开头不允许为0
+            if (strpos((string)$num, chr(0)) === 0) return self::getliveStreamName();
+            //不允许连续出现预设的数字
+            foreach (self::$taboo as $val) {
+                if (strstr((string)$num, $val)) return self::getliveStreamName();
+            }
+            if (strlen($num) > 6)
+                $num = str_pad((string)$num, 8, 0, STR_PAD_RIGHT);//大于6位的填充到8位
+            else
+                $num = str_pad((string)$num, 6, 0, STR_PAD_RIGHT);//小于6位的填充到6位
+            if (self::be(['stream_name' => $num])) return self::getliveStreamName();
+            return $num;
+        }
+    }
+
+    /**
+     * 设置直播间直播状态
+     * @param $StreamName
+     * @return bool|false|int
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public static function setLivePalyStatus($StreamName, $is_play, $action)
+    {
+        $liveInfo = self::where('stream_name', $StreamName)->find();
+        if (!$liveInfo) return self::setErrorInfo('暂未查到直播间');
+        live_log('log', ['title'=>'开始','liveInfo'=>$liveInfo->toArray(),'streamName'=>$StreamName,'is_play'=>$is_play]);
+        if ($liveInfo->is_play == 1 && $action == 'publish') {
+            return true;
+        } else if ($liveInfo->is_play == 0 && $action == 'publish_done') {
+            return true;
+        }
+        $liveInfo->is_play = $is_play;
+        try {
+            $aliyunLive = \Api\AliyunLive::instance([
+                'AccessKey' => SystemConfigService::get('accessKeyId'),
+                'AccessKeySecret' => SystemConfigService::get('accessKeySecret'),
+                'OssEndpoint' => SystemConfigService::get('aliyun_live_end_point'),
+                'OssBucket' => SystemConfigService::get('aliyun_live_oss_bucket'),
+                'appName' => SystemConfigService::get('aliyun_live_appName'),
+                'payKey' => SystemConfigService::get('aliyun_live_play_key'),
+                'key' => SystemConfigService::get('aliyun_live_push_key'),
+                'playLike' => SystemConfigService::get('aliyun_live_playLike'),
+                'rtmpLink' => SystemConfigService::get('aliyun_live_rtmpLink'),
+            ]);
+            if ($liveInfo->is_play) {
+                //开启自动录制,进行手开启动录制直播间
+                if ($liveInfo->is_recording) {
+                    $res = $aliyunLive->liveRecording($liveInfo->stream_name)->executeResponse();
+                    live_log('log', ['title'=>'直播录制开启','res'=>$res,'error'=>$aliyunLive->getErrorInfo()]);
+                    if ($res) $liveInfo->recording = 1;
+                }
+                //向所有在线用户广播直播地址
+                $workerman = \think\Config::get('workerman.channel', []);
+                Gateway::$registerAddress = $workerman['ip'] . ':' . $workerman['port'];
+                if (Gateway::getClientIdCountByGroup($liveInfo->id)) {
+                    Gateway::sendToGroup($liveInfo->id, json_encode([
+                        'type' => 'live_ing',
+                        'pull_url' => $aliyunLive->getPullSteam($liveInfo->stream_name),
+                    ]));
+                }
+            } else {
+                //开启自动录制,进行手动停止录制直播间
+                if ($liveInfo->recording) {
+                    $res = $aliyunLive->liveRecording($liveInfo->stream_name, false)->executeResponse();
+                    live_log('log', ['title'=>'直播录制关闭','res'=>$res,'error'=>$aliyunLive->getErrorInfo()]);
+                    $liveInfo->recording = 0;
+                }
+                //向所有在线用户广播直播地址
+                $workerman = \think\Config::get('workerman.channel', []);
+                Gateway::$registerAddress = $workerman['ip'] . ':' . $workerman['port'];
+                if (Gateway::getClientIdCountByGroup($liveInfo->id)) {
+                    Gateway::sendToGroup($liveInfo->id, json_encode([
+                        'type' => 'live_end',
+                        'pull_url' => false,
+                    ]));
+                }
+            }
+        } catch (\Exception $e) {
+            live_log('error', ['code' => $e->getCode(), 'line' => $e->getLine(), 'msg' => $e->getMessage()]);
+            if ($liveInfo->recording) $liveInfo->recording = 0;
+            self::setErrorInfo($e->getMessage());
+        }
+        return $liveInfo->save();
+    }
+
+    /**
+     * 设置直播查询条件
+     * @param $where
+     * @param null $model
+     * @param string $alias
+     * @return $this
+     */
+    public static function setLiveWhere($where, $model = null, $alias = '')
+    {
+        $model = is_null($model) ? new self() : $model;
+        if ($alias) {
+            $model = $model->alias($alias);
+            $alias .= '.';
+        }
+        if ($where['special_id']) $model = $model->where("{$alias}special_id", $where['special_id']);
+        if (isset($where['admin_id']) && $where['admin_id']) $model = $model->where("S.admin_id", $where['admin_id']);
+        if ($where['stream_name']) $model = $model->where("{$alias}stream_name", $where['stream_name']);
+        if ($where['start_time'] && $where['end_time']) $model = $model->where("{$alias}add_time", 'between', [strtotime($where['start_time']), strtotime($where['end_time'])]);
+        return $model->where("{$alias}is_del", 0);
+    }
+
+    /**
+     * 查询直播间列表
+     * @param $where
+     * @return array
+     * @throws \think\Exception
+     */
+    public static function getLiveList($where)
+    {
+        $data = self::setLiveWhere($where,null,'L')
+            ->field('L.*, S.admin_id as admin_id,S.pay_type,S.member_pay_type')->join('__SPECIAL__ S', 'L.special_id=S.id', 'LEFT')->order('L.sort desc,L.add_time desc')->page((int)$where['page'], (int)$where['limit'])->select();
+        $data = count($data) ? $data->toArray() : [];
+        foreach ($data as &$item) {
+            $item['add_time'] = date('Y-m-d H:i:s', $item['add_time']);
+            $item['studio_pwd'] = $item['studio_pwd'] ?: '';
+            $buy_user_num=StoreOrder::where(['paid' => 1, 'cart_id' => $item['special_id']])->count('id');
+            if($item['pay_type']==1 && $item['member_pay_type']==1){
+                $item['buy_user_num'] = $buy_user_num;
+            }elseif($item['pay_type']==1 && $item['member_pay_type']==0){
+                $userCount =User::where('is_h5user',0)->where('level',1)->count("uid");
+                $item['buy_user_num'] =bcadd($buy_user_num,$userCount,0);
+            }else{
+                $item['buy_user_num'] =User::where('is_h5user',0)->count("uid");
+            }
+            $item['online_user_num'] =LiveUser::where(['is_online'=>1,'live_id'=>$item['id']])->count();
+        }
+        $count = self::setLiveWhere($where, null, 'L')->join('__SPECIAL__ S', 'L.special_id=S.id', 'LEFT')->count();
+        return compact('data', 'count');
+    }
+
+}

+ 58 - 0
application/admin/model/live/LiveUser.php

@@ -0,0 +1,58 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\model\live;
+
+/**
+ * 直播间用户表
+ */
+use basic\ModelBasic;
+use traits\ModelTrait;
+
+class LiveUser extends ModelBasic
+{
+    use ModelTrait;
+
+    /*
+     *  设置查询条件
+     * */
+    public static function setUserWhere($where,$model = null,$alias='a',$jsonField='u.nickname')
+    {
+        $model = is_null($model) ? new self() : $model ;
+        if($alias){
+            $model = $model->alias($alias);
+            $alias.='.';
+        }
+        if($where['nickname']) $model = $model->where("{$alias}uid".($jsonField ? '|'.$jsonField : ''),'LIKE',"$where[nickname]");
+        if($where['start_time'] && $where['end_time']) $model = $model->where("{$alias}add_time",'between',[strtotime($where['start_time']),strtotime($where['end_time'])]);
+        return $model->order("{$alias}add_time desc")->where("{$alias}live_id",$where['live_id']);
+    }
+
+    /*
+     * 查询直播间用户列表
+     * @param array $where
+     * */
+    public static function getLiveUserList($where)
+    {
+        $data = self::setUserWhere($where)->join('user u','a.uid=u.uid')->field(['a.*','u.nickname','u.avatar'])
+            ->page((int)$where['page'],(int)$where['limit'])->select();
+        $data = count($data) ? $data->toArray() : [];
+        foreach ($data as &$item){
+            $item['_add_time']  = date('Y-m-d H:i:s',$item['add_time']);
+            $item['_last_time'] = $item['last_time'] ? date('Y-m-d H:i:s',$item['last_time']) : '暂无';
+            $item['ban_time']=$item['ban_time'] ? date('Y-m-d H:i:s',$item['ban_time']) : '0';
+            $item['open_ben_time']=$item['open_ben_time'] ? date('Y-m-d H:i:s',$item['open_ben_time']) : '0';
+        }
+        $count = self::setUserWhere($where)->join('user u','a.uid=u.uid')->count();
+        return compact('data','count');
+    }
+
+}

+ 1042 - 0
application/admin/model/order/StoreOrder.php

@@ -0,0 +1,1042 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\model\order;
+
+use app\admin\model\user\User;
+use app\admin\model\user\UserBill;
+use app\admin\model\wechat\WechatUser;
+use app\admin\model\ump\StorePink;
+use app\admin\model\store\StoreProduct;
+use service\PHPExcelService;
+use traits\ModelTrait;
+use basic\ModelBasic;
+use service\WechatTemplateService;
+use think\Url;
+use think\Db;
+use service\SystemConfigService;
+
+/**
+ * 订单管理Model
+ * Class StoreOrder
+ * @package app\admin\model\store
+ */
+class StoreOrder extends ModelBasic
+{
+    use ModelTrait;
+
+
+    public static function getOrderList($where)
+    {
+        $model = UserBill::where('u.uid', $where['uid'])->alias('u')->join('__STORE_ORDER__ a', 'a.id=u.link_id')
+            ->where('u.category', 'now_money')->where('u.type', 'in', ['rake_back', 'rake_back_one'])
+            ->where(['a.paid' => 1, 'a.is_gift' => 0, 'a.is_receive_gift' => 0])->order('a.add_time desc')->field('a.*');
+        if ($where['start_date'] && $where['end_date']) $model = $model->where('a.add_time', 'between', [strtotime($where['start_date']), strtotime($where['end_date'])]);
+        if ($where['excel']) {
+            $list = $model->select();
+            $excel = [];
+            foreach ($list as $item) {
+                $item['title'] = self::getDb('special')->where('id', $item['cart_id'])->value('title');
+                $item['add_time'] = date('Y-m-d H:i:s', $item['add_time']);
+                $item['nickname'] = self::getDb('user')->where('uid', $item['uid'])->value('nickname');
+                $excel[] = [$item['add_time'], $item['order_id'], $item['nickname'], $item['title'], $item['pay_price'],];
+            }
+            PHPExcelService::setExcelHeader(['时间', '订单号', '用户名', '商品名', '订单金额'])
+                ->setExcelTile('直推订单导出', '直推订单信息' . time(), ' 生成时间:' . date('Y-m-d H:i:s', time()))
+                ->setExcelContent($excel)->ExcelSave();
+        } else
+            $list = $model->page((int)$where['page'], (int)$where['limit'])->select();
+        $list = count($list)>0 ? $list->toArray() : [];
+        foreach ($list as &$item) {
+            $item['title'] = self::getDb('special')->where('id', $item['cart_id'])->value('title');
+            $item['add_time'] = date('Y-m-d H:i:s', $item['add_time']);
+            $item['nickname'] = self::getDb('user')->where('uid', $item['uid'])->value('nickname');
+        }
+        return $list;
+    }
+
+    public static function orderCount($type=0)
+    {
+            $data['wz'] = self::statusByWhere(0, new self(),'',$type)->count();
+            $data['wf'] = self::statusByWhere(1, new self(),'',$type)->count();
+            $data['sh'] = self::statusByWhere(2, new self(),'',$type)->count();
+            $data['wc'] = self::statusByWhere(3, new self(),'',$type)->count();
+            $data['pt'] = self::statusByWhere(5, new self(),'',$type)->count();
+            $data['pu'] = self::statusByWhere(6, new self(),'',$type)->count();
+            $data['lw'] = self::statusByWhere(7, new self(),'',$type)->count();
+            $data['sp'] = self::statusByWhere(8, new self(),'',$type)->count();
+            $data['vip'] = self::statusByWhere(9, new self(),'',$type)->count();
+            $data['tk'] = self::statusByWhere(-1, new self(),'',$type)->count();
+            $data['yt'] = self::statusByWhere(-2, new self(),'',$type)->count();
+            return $data;
+    }
+
+    public static function OrderList($where)
+    {
+        $model = self::getOrderWhere($where, self::alias('a')->join('user r', 'r.uid=a.uid', 'LEFT'), 'a.', 'r')->field('a.*,r.nickname,r.phone');
+        if ($where['order'] != '') {
+            $model = $model->order(self::setOrder($where['order']));
+        } else {
+            $model = $model->order('a.id desc');
+        }
+        if (isset($where['mer_id']) && $where['mer_id']) $model->where('mer_id', $where['mer_id']);
+        if (isset($where['excel']) && $where['excel'] == 1) {
+            $data = ($data = $model->select()) && count($data) ? $data->toArray() : [];
+        } else {
+            $data = ($data = $model->page((int)$where['page'], (int)$where['limit'])->select()) && count($data) ? $data->toArray() : [];
+        }
+        foreach ($data as &$item) {
+            switch ($item['type']){
+                case 0:
+                    $item['_info'] = db('special')->where('id', $item['cart_id'])->find();
+                    if ($item['pink_id']) {
+                        $item['pink_name'] = '[拼团订单]';
+                        $item['color'] = '#895612';
+                    } else if ($item['is_gift'] && !$item['pink_id']) {
+                        $item['pink_name'] = '[送礼物订单]';
+                        $item['color'] = '#895612';
+                    } else if (!$item['is_gift'] && !$item['pink_id'] && $item['gift_order_id']) {
+                        $item['pink_name'] = '[领礼物订单]';
+                        $item['color'] = '#895612';
+                    } else {
+                        $item['pink_name'] = '[普通订单]';
+                        $item['color'] = '#895612';
+                    }
+                    if (!$item['_info']){
+                        $item['_info']['title'] = '专题被删除';
+                    }else{
+                        $len=strlen($item['_info']['title']);
+                        $item['_info']['title'] =$len > 16 ? mb_substr($item['_info']['title'],0,16).'...' : $item['_info']['title'];
+                    }
+                    break;
+                case 1:
+                    $item['_info'] = db('member_ship')->where('id', $item['member_id'])->find();
+                    $item['pink_name'] = '[会员订单]';
+                    $item['color'] = '#895612';
+                    if (!$item['_info']) $item['_info']['title'] = '会员被删除';
+                    break;
+                case 2:
+                    $_info = Db::name('store_order_cart_info')->where('oid', $item['id'])->field('cart_info')->select();
+                    foreach ($_info as $k => $v) {
+                        $cart_info = json_decode($v['cart_info'], true);
+                        if (!isset($cart_info['productInfo'])) $cart_info['productInfo'] = [];
+                        $len=strlen($cart_info['productInfo']['store_name']);
+                        $cart_info['productInfo']['store_name']=$len > 30 ? mb_substr($cart_info['productInfo']['store_name'],0,30).'...' : $cart_info['productInfo']['store_name'];
+                        $_info[$k]['cart_info'] = $cart_info;
+                        unset($cart_info);
+                    }
+                    $item['_info'] = $_info;
+                    $item['pink_name'] = '[商品订单]';
+                    $item['color'] = '#895612';
+                    break;
+            }
+            if ($item['paid'] == 1) {
+                switch ($item['pay_type']) {
+                    case 'weixin':
+                        $item['pay_type_name'] = '微信支付';
+                        break;
+                    case 'yue':
+                        $item['pay_type_name'] = '余额支付';
+                        break;
+                    case 'offline':
+                        $item['pay_type_name'] = '线下支付';
+                        break;
+                    case 'zhifubao':
+                        $item['pay_type_name'] = '支付宝支付';
+                        break;
+                    default:
+                        $item['pay_type_name'] = '其他支付';
+                        break;
+                }
+            } else {
+                switch ($item['pay_type']) {
+                    case 'offline':
+                        $item['pay_type_name'] = '线下支付';
+                        $item['pay_type_info'] = 1;
+                        break;
+                    default:
+                        $item['pay_type_name'] = '未支付';
+                        break;
+                }
+            }
+            if ($item['paid'] == 0 && $item['status'] == 0) {
+                $item['status_name'] = '未支付';
+            } else if ($item['paid'] == 1 && $item['status'] == 0 && $item['refund_status'] == 0 && $item['type'] != 2) {
+                $item['status_name'] = '已支付';
+            } else if ($item['paid'] == 1 && $item['status'] == 0 && $item['refund_status'] == 0 && $item['type'] == 2) {
+                $item['status_name'] = '待发货';
+            } else if ($item['paid'] == 1 && $item['status'] == 1 && $item['refund_status'] == 0 && $item['type'] == 2) {
+                $item['status_name'] = '待收货';
+            } else if ($item['paid'] == 1 && $item['status'] == 2 && $item['refund_status'] == 0 && $item['type'] == 2) {
+                $item['status_name'] = '已完成';
+            } else if ($item['paid'] == 1 && $item['refund_status'] == 1) {
+                $item['status_name'] = <<<HTML
+<b style="color:#f124c7">申请退款</b><br/>
+HTML;
+            } else if ($item['paid'] == 1 && $item['refund_status'] == 2) {
+                $item['status_name'] = '已退款';
+            }
+            if ($item['paid'] == 0 && $item['status'] == 0 && $item['refund_status'] == 0) {
+                $item['_status'] = 1;
+            } else if ($item['paid'] == 1 && $item['status'] == 0 && $item['refund_status'] == 0) {
+                $item['_status'] = 2;
+            } else if ($item['paid'] == 1 && $item['refund_status'] == 1) {
+                $item['_status'] = 3;
+            } else if ($item['paid'] == 1 && $item['status'] == 1 && $item['refund_status'] == 0) {
+                $item['_status'] = 4;
+            } else if ($item['paid'] == 1 && $item['status'] == 2 && $item['refund_status'] == 0) {
+                $item['_status'] = 5;
+            } else if ($item['paid'] == 1 && $item['status'] == 3 && $item['refund_status'] == 0) {
+                $item['_status'] = 6;
+            } else if ($item['paid'] == 1 && $item['refund_status'] == 2) {
+                $item['_status'] = 7;
+            }
+            $item['spread_name'] = '';
+            $item['spread_name_two'] = '';
+            if ($item['type'] == 0) {
+                if ($item['link_pay_uid']) {
+                    $spread_name = User::where('uid', $item['link_pay_uid'])->value('nickname');
+                    $item['spread_name'] = $spread_name ? $spread_name.'/'.$item['link_pay_uid'] : '无';
+                    $spread_uid_two = User::where('uid', $item['link_pay_uid'])->value('spread_uid');
+                    if ($spread_uid_two) {
+                        $spread_name_two = User::where('uid', $spread_uid_two)->value('nickname');
+                        $item['spread_name_two'] = $spread_name_two ? $spread_name_two.'/'.$spread_uid_two : '无';
+                    } else {
+                        $item['spread_name_two'] = '无';
+                    }
+                } else if ($item['spread_uid']) {
+                    $spread_name = User::where('uid', $item['spread_uid'])->value('nickname');
+                    $item['spread_name'] = $spread_name ? $spread_name.'/'.$item['spread_uid'] : '无';
+                    $spread_uid_two = User::where('uid', $item['spread_uid'])->value('spread_uid');
+                    if ($spread_uid_two) {
+                        $spread_name_two = User::where('uid', $spread_uid_two)->value('nickname');
+                        $item['spread_name_two'] = $spread_name_two ? $spread_name_two.'/'.$spread_uid_two : '无';
+                    } else {
+                        $item['spread_name_two'] = '无';
+                    }
+                } else {
+                    $item['spread_name'] = '无';
+                    $item['spread_name_two'] = '无';
+                }
+            }else{
+                $item['spread_name'] = '不参与分销';
+                $item['spread_name_two'] = '不参与分销';
+            }
+        }
+        if (isset($where['excel']) && $where['excel'] == 1) {
+            self::SaveExcel($data);
+        }
+        $count = self::getOrderWhere($where, self::alias('a')->join('user r', 'r.uid=a.uid', 'LEFT'), 'a.', 'r')->count();
+        return compact('count', 'data');
+    }
+
+    /*
+     * 保存并下载excel
+     * $list array
+     * return
+     */
+    public static function SaveExcel($list)
+    {
+        $export = [];
+        foreach ($list as $index => $item) {
+            $goodsName = '';
+            if($item['type']==0){
+                $special = self::getDb('special')->where('id', $item['cart_id'])->field('title,money')->find();
+                if ($special){
+                    $goodsName = $special['title'] . '| ' . $special['money'];
+                }else{
+                    $goodsName ='专题被删除';
+                }
+                $total='专题总数';
+                $totalPrice ='专题总价';
+                $information ='专题信息';
+            }else if($item['type']==2){
+                $_info = Db::name('store_order_cart_info')->where('oid', $item['id'])->column('cart_info');
+                $goodsName = [];
+                foreach ($_info as $k => $v) {
+                    $v = json_decode($v, true);
+                    $goodsName[] = implode(
+                        [$v['productInfo']['store_name'],
+                            isset($v['productInfo']['attrInfo']) ? '(' . $v['productInfo']['attrInfo']['suk'] . ')' : '',
+                            "[{$v['cart_num']} * {$v['truePrice']}]"
+                        ], ' ');
+                }
+                $item['cartInfo'] = $_info;
+                $total='商品总数';
+                $totalPrice ='商品总价';
+                $information ='商品信息';
+            }else if($item['type']==1){
+                $_info=db('member_ship')->where('id', $item['member_id'])->find();
+                if ($_info){
+                    $goodsName = $_info['title'] . '会员| ' . $_info['price'];
+                }else{
+                    $goodsName ='会员信息被删除';
+                }
+                $total='会员总数';
+                $totalPrice ='会员总价';
+                $information ='会员信息';
+            }
+            if ($item['paid'] == 0 && $item['status'] == 0) {
+                $item['status_name'] = '未支付';
+            } else if ($item['paid'] == 1 && $item['status'] == 0 && $item['refund_status'] == 0 && $item['type'] != 2) {
+                $item['status_name'] = '已支付';
+            }else if ($item['paid'] == 1 && $item['status'] == 0 && $item['refund_status'] == 0 && $item['type'] == 2) {
+                $item['status_name'] = '待发货';
+            }else if ($item['paid'] == 1 && $item['status'] == 1 && $item['refund_status'] == 0 && $item['type'] == 2) {
+                $item['status_name'] = '待收货';
+            }else if ($item['paid'] == 1 && $item['status'] == 2 && $item['refund_status'] == 0 && $item['type'] == 2) {
+                $item['status_name'] = '已完成';
+            } else if ($item['paid'] == 1 && $item['refund_status'] == 1) {
+                $item['status_name'] = '退款中';
+            } else if ($item['paid'] == 1 && $item['refund_status'] == 2) {
+                $item['status_name'] = '已退款';
+            }
+            $export[] = [
+                $item['order_id'], $item['pay_type_name'],
+                $item['total_num'], $item['total_price'], $item['total_postage'], $item['pay_price'], $item['refund_price'],
+                $goodsName,
+                $item['spread_name'],
+                $item['spread_name_two'],
+                [$item['paid'] == 1 ? '已支付' : '未支付', '支付时间: ' . ($item['pay_time'] > 0 ? date('Y/m/d H:i', $item['pay_time']) : '暂无')],
+                $item['status_name'],
+                $item['nickname'],
+                $item['phone']
+            ];
+        }
+        PHPExcelService::setExcelHeader(['订单号', '支付方式', $total, $totalPrice, '邮费', '支付金额', '退款金额', $information, '推广人', '推广人上级', '支付状态','订单状态', '微信昵称', '手机号'])
+            ->setExcelTile('订单导出', '订单信息' . time(), ' 生成时间:' . date('Y-m-d H:i:s', time()))
+            ->setExcelContent($export)
+            ->ExcelSave();
+    }
+
+    public static function statusByWhere($status, $model = null, $alert = '',$type=0)
+    {
+        if ($model == null) $model = new self;
+        switch ($type){
+            case 0:
+                $model=$model->where($alert . 'type', 0);
+            break;
+            case 1:
+                $model=$model->where($alert . 'type', 1);
+            break;
+            case 2:
+                $model=$model->where($alert . 'type', 2);
+            break;
+        }
+        if ('' === $status)
+            return $model;
+        else if ($status == 0)//未支付
+            return $model->where($alert . 'paid', 0)->where($alert . 'is_del', 0)->where($alert . 'status', 0)->where($alert . 'refund_status', 0);
+        else if ($status == 1)//已支付 未发货
+            return $model->where($alert . 'paid', 1)->where($alert . 'is_del', 0)->where($alert . 'status', 0)->where($alert . 'refund_status', 0);
+        else if ($status == 2)//已支付 已发货
+            return $model->where($alert . 'paid', 1)->where($alert . 'is_del', 0)->where($alert . 'status', 1)->where($alert . 'refund_status', 0);
+        else if ($status == 3)//已支付 已完成
+            return $model->where($alert . 'paid', 1)->where($alert . 'is_del', 0)->where($alert . 'status', 2)->where($alert . 'refund_status', 0);
+        else if ($status == 5)//课程订单
+            return $model->where($alert . 'combination_id', 0)->where($alert . 'is_del', 0)->where($alert . 'is_gift', 0);
+        else if ($status == 6)// 拼团订单
+            return $model->where($alert . 'combination_id','>', 0)->where($alert . 'is_del', 0)->where($alert . 'is_gift', 0);
+        else if ($status == 7)// 礼物订单
+            return $model->where($alert . 'combination_id', 0)->where($alert . 'is_del', 0)->where($alert . 'is_gift','>', 0);
+        else if ($status == 8)//商品订单
+            return $model->where($alert . 'combination_id', 0)->where($alert . 'is_del', 0)->where($alert . 'is_gift', 0);
+        else if ($status == 9)//会员订单
+            return $model->where($alert . 'combination_id', 0)->where($alert . 'is_del', 0)->where($alert . 'is_gift', 0);
+        else if ($status == -1)//退款中
+            return $model->where($alert . 'paid', 1)->where($alert . 'is_del', 0)->where($alert . 'refund_status', 1);
+        else if ($status == -2)//已退款
+            return $model->where($alert . 'paid', 1)->where($alert . 'is_del', 0)->where($alert . 'refund_status', 2);
+        else
+            return $model;
+    }
+
+    /**退金币
+     * @param $data
+     * @param $oid
+     */
+    public static function returnGoldCoin($oid)
+    {
+        $gold_name=SystemConfigService::get('gold_name');//虚拟币名称
+        $order=self::where('id',$oid)->field('id,order_id,gain_gold_num,uid,type')->find();
+        if($order['type']!=2) return true;
+        if($order['gain_gold_num']>0){
+            $uill=UserBill::where(['link_id'=>$order['id'],'pm'=>1,'category'=>'gold_num','type'=>'gain'])->find();
+            if($uill){
+                $userInfo = User::where('uid',$order['uid'])->find();
+                if(bcsub($userInfo['gold_num'], $order['gain_gold_num'], 2)>0){
+                    $gold_num=bcsub($userInfo['gold_num'], $order['gain_gold_num'], 2);
+                }else{
+                    $gold_num=0;
+                }
+                $res1=User::where('uid', $order['uid'])->update(['gold_num' =>$gold_num]);
+                $res2=UserBill::expend($gold_name.'返还', $order['uid'], 'gold_num', 'return', $order['gain_gold_num'], $order['id'], $gold_num, '用户退款返还' . floatval($order['gain_gold_num']) . $gold_name);
+                $res=$res1 && $res2;
+                return $res;
+            }else{
+                return true;
+            }
+        }else{
+            return true;
+        }
+    }
+    /**退佣金 一级
+     * @param $data
+     * @param $oid
+     */
+    public static function returnCommissionOne($oid)
+    {
+            $order=self::where('id',$oid)->find();
+            if($order['type']!=0) return true;
+            $userInfo = User::where('uid',$order['uid'])->find();
+            if (!$userInfo || !$userInfo['spread_uid']) return true;
+            $storeBrokerageStatu = SystemConfigService::get('store_brokerage_statu') ?: 1;//获取后台分销类型
+            if ($storeBrokerageStatu == 1) {
+                if (!User::be(['uid' => $userInfo['spread_uid'], 'is_promoter' => 1])) return true;
+            }
+            $userInfoOne = User::where('uid',$userInfo['spread_uid'])->find();
+            $uill=UserBill::where(['link_id'=>$order['id'],'pm'=>1,'uid'=>$userInfoOne['uid'],'category'=>'now_money','type'=>'brokerage'])->find();
+            if($uill){
+                if(bcsub($userInfoOne['brokerage_price'], $uill['number'], 2)>0){
+                    $brokerage_price=bcsub($userInfoOne['brokerage_price'], $uill['number'], 2);
+                }else{
+                    $brokerage_price=0;
+                }
+                $res1=User::where('uid', $userInfoOne['uid'])->update(['brokerage_price' =>$brokerage_price]);
+                $res2=UserBill::expend('佣金返还', $userInfoOne['uid'], 'now_money', 'brokerage_return', $uill['number'], $order['id'], $brokerage_price, '用户退款返还佣金' . floatval($uill['number']) .'元');
+                $res=$res1 && $res2;
+                if($res){
+                  return  self::returnCommissionTwo($userInfoOne,$order);
+                }
+            }else{
+                return true;
+            }
+    }
+    /**退佣金 二级
+     * @param $data
+     * @param $oid
+     */
+    public static function returnCommissionTwo($userInfoOne,$order)
+    {
+        if (!$userInfoOne || !$userInfoOne['spread_uid']) return true;
+        $storeBrokerageStatu = SystemConfigService::get('store_brokerage_statu') ?: 1;//获取后台分销类型
+        if ($storeBrokerageStatu == 1) {
+            if (!User::be(['uid' => $userInfoOne['spread_uid'], 'is_promoter' => 1])) return true;
+        }
+        $userInfoTwo = User::where('uid',$userInfoOne['spread_uid'])->find();
+        $uill=UserBill::where(['link_id'=>$order['id'],'pm'=>1,'uid'=>$userInfoTwo['uid'],'category'=>'now_money','type'=>'brokerage'])->find();
+        if($uill){
+            if(bcsub($userInfoTwo['brokerage_price'], $uill['number'], 2)>0){
+                $brokerage_price=bcsub($userInfoTwo['brokerage_price'], $uill['number'], 2);
+            }else{
+                $brokerage_price=0;
+            }
+            $res1=User::where('uid', $userInfoTwo['uid'])->update(['brokerage_price' =>$brokerage_price]);
+            $res2=UserBill::expend('佣金返还', $userInfoTwo['uid'], 'now_money', 'brokerage_return', $uill['number'], $order['id'], $brokerage_price, '用户退款返还佣金' . floatval($uill['number']) .'元');
+            $res=$res1 && $res2;
+            return $res;
+        }else{
+            return true;
+        }
+    }
+    public static function timeQuantumWhere($startTime = null, $endTime = null, $model = null)
+    {
+        if ($model === null) $model = new self;
+        if ($startTime != null && $endTime != null)
+            $model = $model->where('add_time', '>', strtotime($startTime))->where('add_time', '<', strtotime($endTime));
+        return $model;
+    }
+
+    public static function changeOrderId($orderId)
+    {
+        $ymd = substr($orderId, 2, 8);
+        $key = substr($orderId, 16);
+        return 'wx' . $ymd . date('His') . $key;
+    }
+
+    /**
+     * 线下付款
+     * @param $id
+     * @return $this
+     */
+    public static function updateOffline($id)
+    {
+        $orderId = self::where('id', $id)->value('order_id');
+        $res = self::where('order_id', $orderId)->update(['paid' => 1, 'pay_time' => time()]);
+        return $res;
+    }
+
+    /**
+     * 退款发送模板消息
+     * @param $oid
+     * $oid 订单id  key
+     */
+    public static function refundTemplate($data, $oid)
+    {
+        $order = self::where('id', $oid)->find();
+        WechatTemplateService::sendTemplate(WechatUser::uidToOpenid($order['uid']), WechatTemplateService::ORDER_REFUND_STATUS, [
+            'first' => '亲,您购买的专题已退款,本次退款' . $data['refund_price'] . '金额',
+            'keyword1' => $order['order_id'],
+            'keyword2' => $order['pay_price'],
+            'keyword3' => date('Y-m-d H:i:s', $order['add_time']),
+            'remark' => '请查看账单'
+        ], '');
+    }
+
+    /**
+     * 处理where条件
+     * @param $where
+     * @param $model
+     * @return mixed
+     */
+    public static function getOrderWhere($where, $model, $aler = '', $join = '')
+    {
+        if ($where['status'] != '') $model = self::statusByWhere($where['status'], $model, $aler,$where['types']);
+        $model = $model->where($aler . 'is_del', $where['is_del']);
+        if ($where['real_name'] != '') {
+            $model = $model->where($aler . 'order_id|' . $aler . 'real_name|' . $aler . 'user_phone' . ($join ? '|' . $join . '.nickname|' . $join . '.uid|' . $join . '.phone' : ''), 'LIKE', "%$where[real_name]%");
+        }
+        $model = $model->where($aler . 'type', $where['types']);
+        if($where['type'] != ''){
+            switch ($where['type']){
+                case 5:
+                    $model = $model->where($aler . 'combination_id', 0)->where($aler . 'is_gift', 0);
+                    break;
+                case 6:
+                    $model = $model->where($aler . 'combination_id','>', 0)->where($aler . 'is_gift', 0);
+                    break;
+                case 7:
+                    $model = $model->where($aler . 'combination_id', 0)->where($aler .'is_gift','>',0);
+                    break;
+                case 8:
+                    $model = $model->where($aler . 'combination_id', 0)->where($aler .'is_gift',0);
+                    break;
+                case 9:
+                    $model = $model->where($aler . 'combination_id', 0)->where($aler .'is_gift',0);
+                    break;
+            }
+        }
+        if ($where['data'] !== '') {
+            $model = self::getModelTime($where, $model, $aler . 'add_time');
+        }
+        return $model;
+    }
+
+    public static function getBadge($where)
+    {
+        $price = self::getOrderPrice($where);
+        switch ($where['types']){
+            case 0:
+                $name='售出专题';
+                break;
+            case 1:
+                $name='售出会员';
+                break;
+            case 2:
+                $name='售出商品';
+                break;
+        }
+        return [
+            [
+                'name' => '订单数量',
+                'field' => '件',
+                'count' => $price['order_sum'],
+                'background_color' => 'layui-bg-blue',
+                'col' => 3
+            ],
+            [
+                'name' => $name,
+                'field' => '件',
+                'count' => $price['total_num'],
+                'background_color' => 'layui-bg-blue',
+                'col' => 3
+            ],
+            [
+                'name' => '订单金额',
+                'field' => '元',
+                'count' => $price['pay_price'],
+                'background_color' => 'layui-bg-blue',
+                'col' => 3
+            ],
+            [
+                'name' => '退款金额',
+                'field' => '元',
+                'count' => $price['refund_price'],
+                'background_color' => 'layui-bg-blue',
+                'col' => 3
+            ],
+            [
+                'name' => '微信支付金额',
+                'field' => '元',
+                'count' => $price['pay_price_wx'],
+                'background_color' => 'layui-bg-blue',
+                'col' => 3
+            ],
+            [
+                'name' => '余额支付金额',
+                'field' => '元',
+                'count' => $price['pay_price_yue'],
+                'background_color' => 'layui-bg-blue',
+                'col' => 3
+            ],
+            [
+                'name' => '支付宝支付金额',
+                'field' => '元',
+                'count' => $price['pay_price_zhifubao'],
+                'background_color' => 'layui-bg-blue',
+                'col' => 3
+            ]
+        ];
+    }
+
+    /**
+     * 处理订单金额
+     * @param $where
+     * @return array
+     */
+    public static function getOrderPrice($where)
+    {
+        $model = new self;
+        $price = array();
+        $price['pay_price'] = 0;//支付金额
+        $price['refund_price'] = 0;//退款金额
+        $price['pay_price_wx'] = 0;//微信支付金额
+        $price['pay_price_yue'] = 0;//余额支付金额
+        $price['pay_price_offline'] = 0;//线下支付金额
+        $price['pay_price_zhifubao'] = 0;//支付宝支付金额
+        $price['pay_price_other'] = 0;//其他支付金额
+
+        $list = self::getOrderWhere($where, $model)->field([
+            'sum(total_num) as total_num',
+            'sum(pay_price) as pay_price',
+            'sum(refund_price) as refund_price'])->find()->toArray();
+        $price['total_num'] = $list['total_num'];//商品总数
+        $price['pay_price'] = $list['pay_price'];//支付金额
+        $price['refund_price'] = $list['refund_price'];//退款金额
+        $list = self::getOrderWhere($where, $model)->field('sum(pay_price) as pay_price,pay_type')->group('pay_type')->select()->toArray();
+        foreach ($list as $v) {
+            if ($v['pay_type'] == 'weixin') {
+                $price['pay_price_wx'] = $v['pay_price'];
+            } elseif ($v['pay_type'] == 'yue') {
+                $price['pay_price_yue'] = $v['pay_price'];
+            } elseif ($v['pay_type'] == 'offline') {
+                $price['pay_price_offline'] = $v['pay_price'];
+            } elseif ($v['pay_type'] == 'zhifubao') {
+                $price['pay_price_zhifubao'] = $v['pay_price'];
+            } else {
+                $price['pay_price_other'] = $v['pay_price'];
+            }
+        }
+        $price['order_sum'] =self::getOrderWhere($where, $model)->count();
+        return $price;
+    }
+
+    public static function systemPagePink($where)
+    {
+        $model = new self;
+        $model = self::getOrderWherePink($where, $model);
+        $model = $model->order('id desc');
+
+        if ($where['export'] == 1) {
+            $list = $model->select()->toArray();
+            $export = [];
+            foreach ($list as $index => $item) {
+
+                if ($item['pay_type'] == 'weixin') {
+                    $payType = '微信支付';
+                } elseif ($item['pay_type'] == 'yue') {
+                    $payType = '余额支付';
+                } elseif ($item['pay_type'] == 'offline') {
+                    $payType = '线下支付';
+                } else {
+                    $payType = '其他支付';
+                }
+
+                $_info = db('store_order_cart_info')->where('oid', $item['id'])->column('cart_info');
+                $goodsName = [];
+                foreach ($_info as $k => $v) {
+                    $v = json_decode($v, true);
+                    $goodsName[] = implode(
+                        [$v['productInfo']['store_name'],
+                            isset($v['productInfo']['attrInfo']) ? '(' . $v['productInfo']['attrInfo']['suk'] . ')' : '',
+                            "[{$v['cart_num']} * {$v['truePrice']}]"
+                        ], ' ');
+                }
+                $item['cartInfo'] = $_info;
+                $export[] = [
+                    $item['order_id'], $payType,
+                    $item['total_num'], $item['total_price'], $item['total_postage'], $item['pay_price'], $item['refund_price'],
+                    $item['mark'], $item['remark'],
+                    [$item['real_name'], $item['user_phone'], $item['user_address']],
+                    $goodsName,
+                    [$item['paid'] == 1 ? '已支付' : '未支付', '支付时间: ' . ($item['pay_time'] > 0 ? date('Y/md H:i', $item['pay_time']) : '暂无')]
+
+                ];
+                $list[$index] = $item;
+            }
+            PHPExcelService::setExcelHeader(['订单号', '支付方式', '商品总数', '商品总价', '邮费', '支付金额', '退款金额', '用户备注', '管理员备注', '收货人信息', '商品信息', '支付状态'])
+                ->setExcelTile('订单导出', '订单导出' . time())
+                ->setExcelContent($export)
+                ->ExcelSave();
+        }
+
+        return self::page($model, function ($item) {
+            $item['nickname'] = WechatUser::where('uid', $item['uid'])->value('nickname');
+            $_info = db('store_order_cart_info')->where('oid', $item['id'])->field('cart_info')->select();
+            foreach ($_info as $k => $v) {
+                $_info[$k]['cart_info'] = json_decode($v['cart_info'], true);
+            }
+            $item['_info'] = $_info;
+        }, $where);
+    }
+
+    /**
+     * 处理where条件
+     * @param $where
+     * @param $model
+     * @return mixed
+     */
+    public static function getOrderWherePink($where, $model)
+    {
+        if ($where['status'] != '') $model = self::statusByWhere($where['status']);
+        $model = $model->where('combination_id', 'GT', 0);
+        if ($where['real_name'] != '') {
+            $model = $model->where('order_id|real_name|user_phone', 'LIKE', "%$where[real_name]%");
+        }
+        if ($where['data'] !== '') {
+            list($startTime, $endTime) = explode(' - ', $where['data']);
+            $model = $model->where('add_time', '>', strtotime($startTime));
+            $model = $model->where('add_time', '<', strtotime($endTime));
+        }
+        return $model;
+    }
+
+    /**
+     * 处理订单金额
+     * @param $where
+     * @return array
+     */
+    public static function getOrderPricePink($where)
+    {
+        $model = new self;
+        $price = array();
+        $price['pay_price'] = 0;//支付金额
+        $price['refund_price'] = 0;//退款金额
+        $price['pay_price_wx'] = 0;//微信支付金额
+        $price['pay_price_yue'] = 0;//余额支付金额
+        $price['pay_price_offline'] = 0;//线下支付金额
+        $price['pay_price_other'] = 0;//其他支付金额
+        $price['use_integral'] = 0;//用户使用积分
+        $price['back_integral'] = 0;//退积分总数
+        $price['deduction_price'] = 0;//抵扣金额
+        $price['total_num'] = 0; //商品总数
+        $model = self::getOrderWherePink($where, $model);
+        $list = $model->select()->toArray();
+        foreach ($list as $v) {
+            $price['total_num'] = bcadd($price['total_num'], $v['total_num'], 0);
+            $price['pay_price'] = bcadd($price['pay_price'], $v['pay_price'], 2);
+            $price['refund_price'] = bcadd($price['refund_price'], $v['refund_price'], 2);
+            $price['use_integral'] = bcadd($price['use_integral'], $v['use_integral'], 2);
+            $price['back_integral'] = bcadd($price['back_integral'], $v['back_integral'], 2);
+            $price['deduction_price'] = bcadd($price['deduction_price'], $v['deduction_price'], 2);
+            if ($v['pay_type'] == 'weixin') {
+                $price['pay_price_wx'] = bcadd($price['pay_price_wx'], $v['pay_price'], 2);
+            } elseif ($v['pay_type'] == 'yue') {
+                $price['pay_price_yue'] = bcadd($price['pay_price_yue'], $v['pay_price'], 2);
+            } elseif ($v['pay_type'] == 'offline') {
+                $price['pay_price_offline'] = bcadd($price['pay_price_offline'], $v['pay_price'], 2);
+            } else {
+                $price['pay_price_other'] = bcadd($price['pay_price_other'], $v['pay_price'], 2);
+            }
+        }
+        return $price;
+    }
+
+    /**
+     * 获取昨天的订单   首页在使用
+     * @param int $preDay
+     * @param int $day
+     * @return $this|StoreOrder
+     */
+    public static function isMainYesterdayCount($preDay = 0, $day = 0)
+    {
+        $model = new self();
+        $model = $model->where('add_time', 'gt', $preDay);
+        $model = $model->where('add_time', 'lt', $day);
+        return $model;
+    }
+
+    /**
+     * 获取用户购买次数
+     * @param int $uid
+     * @return int|string
+     */
+    public static function getUserCountPay($uid = 0)
+    {
+        if (!$uid) return 0;
+        return self::where('uid', $uid)->where('paid', 1)->count();
+    }
+
+    /**
+     * 获取单个用户购买列表
+     * @param array $where
+     * @return array
+     */
+    public static function getOneorderList($where)
+    {
+        return self::where(['uid' => $where['uid'], 'paid' => 1])
+            ->order('add_time desc')
+            ->page((int)$where['page'], (int)$where['limit'])
+            ->field(['order_id', 'total_num', 'total_price', 'pay_price',
+                'FROM_UNIXTIME(pay_time,"%Y-%m-%d") as pay_time', 'paid', 'pay_type',
+                'pink_id'
+            ])->select()
+            ->toArray();
+    }
+
+    /*
+     * 设置订单统计图搜索
+     * $where array 条件
+     * return object
+     */
+    public static function setEchatWhere($where, $status = null, $time = null)
+    {
+        $model = self::statusByWhere($where['status']);
+        if ($status !== null) $where['type'] = $status;
+        if ($time === true) $where['data'] = '';
+        switch ($where['type']) {
+            case 1:
+                //普通商品
+                $model = $model->where('combination_id', 0)->where('seckill_id', 0);
+                break;
+            case 2:
+                //拼团商品
+                $model = $model->where('combination_id', ">", 0)->where('pink_id', ">", 0);
+                break;
+            case 3:
+                //秒杀商品
+                $model = $model->where('seckill_id', ">", 0);
+                break;
+            case 4:
+                //砍价商品
+                $model = $model->where('bargain_id', '>', 0);
+                break;
+        }
+        return self::getModelTime($where, $model);
+    }
+
+    /*
+     * 获取订单数据统计图
+     * $where array
+     * $limit int
+     * return array
+     */
+    public static function getEchartsOrder($where, $limit = 20)
+    {
+        $orderlist = self::setEchatWhere($where)->field([
+            'FROM_UNIXTIME(add_time,"%Y-%m-%d") as _add_time',
+            'sum(total_num) total_num',
+            'count(*) count',
+            'sum(total_price) total_price',
+            'sum(refund_price) refund_price',
+            'group_concat(cart_id SEPARATOR "|") cart_ids'
+        ])->group('_add_time')->order('_add_time asc')->select();
+        count($orderlist) && $orderlist = $orderlist->toArray();
+        $legend = ['商品数量', '订单数量', '订单金额', '退款金额'];
+        $seriesdata = [
+            [
+                'name' => $legend[0],
+                'type' => 'line',
+                'data' => [],
+            ],
+            [
+                'name' => $legend[1],
+                'type' => 'line',
+                'data' => []
+            ],
+            [
+                'name' => $legend[2],
+                'type' => 'line',
+                'data' => []
+            ],
+            [
+                'name' => $legend[3],
+                'type' => 'line',
+                'data' => []
+            ]
+        ];
+        $xdata = [];
+        $zoom = '';
+        foreach ($orderlist as $item) {
+            $xdata[] = $item['_add_time'];
+            $seriesdata[0]['data'][] = $item['total_num'];
+            $seriesdata[1]['data'][] = $item['count'];
+            $seriesdata[2]['data'][] = $item['total_price'];
+            $seriesdata[3]['data'][] = $item['refund_price'];
+        }
+        count($xdata) > $limit && $zoom = $xdata[$limit - 5];
+        $badge = self::getOrderBadge($where);
+        $bingpaytype = self::setEchatWhere($where)->group('pay_type')->field(['count(*) as count', 'pay_type'])->select();
+        count($bingpaytype) && $bingpaytype = $bingpaytype->toArray();
+        $bing_xdata = ['微信支付', '余额支付', '其他支付'];
+        $color = ['#ffcccc', '#99cc00', '#fd99cc', '#669966'];
+        $bing_data = [];
+        foreach ($bingpaytype as $key => $item) {
+            if ($item['pay_type'] == 'weixin') {
+                $value['name'] = $bing_xdata[0];
+            } else if ($item['pay_type'] == 'yue') {
+                $value['name'] = $bing_xdata[1];
+            } else {
+                $value['name'] = $bing_xdata[2];
+            }
+            $value['value'] = $item['count'];
+            $value['itemStyle']['color'] = isset($color[$key]) ? $color[$key] : $color[0];
+            $bing_data[] = $value;
+        }
+        return compact('zoom', 'xdata', 'seriesdata', 'badge', 'legend', 'bing_data', 'bing_xdata');
+    }
+
+    public static function getOrderBadge($where)
+    {
+        return [
+            [
+                'name' => '拼团订单数量',
+                'field' => '个',
+                'count' => self::setEchatWhere($where, 2)->count(),
+                'content' => '拼团总订单数量',
+                'background_color' => 'layui-bg-cyan',
+                'sum' => self::setEchatWhere($where, 2, true)->count(),
+                'class' => 'fa fa-line-chart',
+                'col' => 2
+            ],
+            [
+                'name' => '砍价订单数量',
+                'field' => '个',
+                'count' => self::setEchatWhere($where, 4)->count(),
+                'content' => '砍价总订单数量',
+                'background_color' => 'layui-bg-cyan',
+                'sum' => self::setEchatWhere($where, 4, true)->count(),
+                'class' => 'fa fa-line-chart',
+                'col' => 2
+            ],
+            [
+                'name' => '秒杀订单数量',
+                'field' => '个',
+                'count' => self::setEchatWhere($where, 3)->count(),
+                'content' => '秒杀总订单数量',
+                'background_color' => 'layui-bg-cyan',
+                'sum' => self::setEchatWhere($where, 3, true)->count(),
+                'class' => 'fa fa-line-chart',
+                'col' => 2
+            ],
+            [
+                'name' => '普通订单数量',
+                'field' => '个',
+                'count' => self::setEchatWhere($where, 1)->count(),
+                'content' => '普通总订单数量',
+                'background_color' => 'layui-bg-cyan',
+                'sum' => self::setEchatWhere($where, 1, true)->count(),
+                'class' => 'fa fa-line-chart',
+                'col' => 2,
+            ],
+            [
+                'name' => '使用优惠卷金额',
+                'field' => '元',
+                'count' => self::setEchatWhere($where)->sum('coupon_price'),
+                'content' => '普通总订单数量',
+                'background_color' => 'layui-bg-cyan',
+                'sum' => self::setEchatWhere($where, null, true)->sum('coupon_price'),
+                'class' => 'fa fa-line-chart',
+                'col' => 2
+            ],
+            [
+                'name' => '积分消耗数',
+                'field' => '个',
+                'count' => self::setEchatWhere($where)->sum('use_integral'),
+                'content' => '积分消耗总数',
+                'background_color' => 'layui-bg-cyan',
+                'sum' => self::setEchatWhere($where, null, true)->sum('use_integral'),
+                'class' => 'fa fa-line-chart',
+                'col' => 2
+            ],
+            [
+                'name' => '积分抵扣金额',
+                'field' => '个',
+                'count' => self::setEchatWhere($where)->sum('deduction_price'),
+                'content' => '积分抵扣总金额',
+                'background_color' => 'layui-bg-cyan',
+                'sum' => self::setEchatWhere($where, null, true)->sum('deduction_price'),
+                'class' => 'fa fa-money',
+                'col' => 2
+            ],
+            [
+                'name' => '在线支付金额',
+                'field' => '元',
+                'count' => self::setEchatWhere($where)->where('pay_type', 'weixin')->sum('pay_price'),
+                'content' => '在线支付总金额',
+                'background_color' => 'layui-bg-cyan',
+                'sum' => self::setEchatWhere($where, null, true)->where('pay_type', 'weixin')->sum('pay_price'),
+                'class' => 'fa fa-weixin',
+                'col' => 2
+            ],
+            [
+                'name' => '余额支付金额',
+                'field' => '元',
+                'count' => self::setEchatWhere($where)->where('pay_type', 'yue')->sum('pay_price'),
+                'content' => '余额支付总金额',
+                'background_color' => 'layui-bg-cyan',
+                'sum' => self::setEchatWhere($where, null, true)->where('pay_type', 'yue')->sum('pay_price'),
+                'class' => 'fa  fa-balance-scale',
+                'col' => 2
+            ],
+            [
+                'name' => '赚取积分',
+                'field' => '分',
+                'count' => self::setEchatWhere($where)->sum('gain_integral'),
+                'content' => '赚取总积分',
+                'background_color' => 'layui-bg-cyan',
+                'sum' => self::setEchatWhere($where, null, true)->sum('gain_integral'),
+                'class' => 'fa fa-gg-circle',
+                'col' => 2
+            ],
+            [
+                'name' => '交易额',
+                'field' => '元',
+                'count' => self::setEchatWhere($where)->sum('pay_price'),
+                'content' => '总交易额',
+                'background_color' => 'layui-bg-cyan',
+                'sum' => self::setEchatWhere($where, null, true)->sum('pay_price'),
+                'class' => 'fa fa-jpy',
+                'col' => 2
+            ],
+            [
+                'name' => '订单商品数量',
+                'field' => '元',
+                'count' => self::setEchatWhere($where)->sum('total_num'),
+                'content' => '订单商品总数量',
+                'background_color' => 'layui-bg-cyan',
+                'sum' => self::setEchatWhere($where, null, true)->sum('total_num'),
+                'class' => 'fa fa-cube',
+                'col' => 2
+            ]
+        ];
+    }
+    /**
+     * 获取订单总数
+     * @param int $uid
+     * @return int|string
+     */
+    public static function getOrderCount($uid = 0)
+    {
+        if (!$uid) return 0;
+        return self::where('uid', $uid)->where('paid', 1)->where('refund_status', 0)->where('status', 2)->count();
+    }
+}

+ 60 - 0
application/admin/model/order/StoreOrderStatus.php

@@ -0,0 +1,60 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\model\order;
+
+use traits\ModelTrait;
+use basic\ModelBasic;
+
+/**
+ * 订单操作纪律model
+ * Class StoreOrderStatus
+ * @package app\admin\model\store
+ */
+class StoreOrderStatus extends ModelBasic
+{
+    use ModelTrait;
+
+    /**
+     * @param $oid
+     * @param $type
+     * @param $message
+     */
+   public static function setStatus($oid,$type,$message,$order_type=0){
+       $data['oid'] = (int)$oid;
+       $data['type'] = $order_type;
+       $data['change_type'] = $type;
+       $data['change_message'] = $message;
+       $data['change_time'] = time();
+       self::set($data);
+   }
+
+    /**
+     * @param $where
+     * @return array
+     */
+    public static function systemPage($oid){
+        $model = new self;
+        $model = $model->where('oid',$oid);
+        $model = $model->order('change_time asc');
+        return self::page($model);
+    }
+    /**
+     * @param $where
+     * @return array
+     */
+    public static function systemPageMer($oid){
+        $model = new self;
+        $model = $model->where('oid',$oid);
+        $model = $model->order('change_time asc');
+        return self::page($model);
+    }
+}

+ 213 - 0
application/admin/model/record/StoreStatistics.php

@@ -0,0 +1,213 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\model\record;
+
+use traits\ModelTrait;
+use basic\ModelBasic;
+use service\ExportService;
+use app\wap\model\user\UserBill;
+use app\admin\model\user\User;
+use service\PHPExcelService;
+
+class StoreStatistics extends ModelBasic
+{
+    protected $name = 'store_order';
+    use ModelTrait;
+
+    /**
+     * 处理金额
+     * @param $where
+     * @return array
+     */
+    public static function getOrderPrice($where)
+    {
+        $model = new self;
+        $price = array();
+        $price['pay_price_wx'] = 0;//微信支付金额
+        $price['pay_price_yue'] = 0;//余额支付金额
+        $price['pay_price_offline'] = 0;//线下支付金额
+        $list = self::getTimeWhere($where, $model)->field('pay_price,total_price,deduction_price,coupon_price,total_postage,pay_type,pay_time')->select()->toArray();
+        if (empty($list)) {
+            $price['pay_price_wx'] = 0;
+            $price['pay_price_yue'] = 0;
+            $price['pay_price_offline'] = 0;
+        }
+        foreach ($list as $v) {
+            if ($v['pay_type'] == 'weixin') {
+                $price['pay_price_wx'] = bcadd($price['pay_price_wx'], $v['pay_price'], 2);
+            } elseif ($v['pay_type'] == 'yue') {
+                $price['pay_price_yue'] = bcadd($price['pay_price_yue'], $v['pay_price'], 2);
+            } elseif ($v['pay_type'] == 'offline') {
+                $price['pay_price_offline'] = bcadd($price['pay_price_offline'], $v['pay_price'], 2);
+            }
+        }
+        return $price;
+    }
+
+    /**
+     * 获取营业数据
+     */
+    public static function getOrderInfo($where)
+    {
+        $orderinfo = self::getTimeWhere($where)
+            ->field('sum(total_price) total_price,sum(cost) cost,sum(pay_postage) pay_postage,sum(pay_price) pay_price,sum(coupon_price) coupon_price,sum(deduction_price) deduction_price,from_unixtime(pay_time,\'%Y-%m-%d\') pay_time')->order('pay_time')->group('from_unixtime(pay_time,\'%Y-%m-%d\')')->select()->toArray();
+        $price = 0;
+        $postage = 0;
+        $deduction = 0;
+        $coupon = 0;
+        $cost = 0;
+        foreach ($orderinfo as $info) {
+            $price = bcadd($price, $info['total_price'], 2);//应支付
+            $postage = bcadd($postage, $info['pay_postage'], 2);//邮费
+            $deduction = bcadd($deduction, $info['deduction_price'], 2);//抵扣
+            $coupon = bcadd($coupon, $info['coupon_price'], 2);//优惠券
+            $cost = bcadd($cost, $info['cost'], 2);//成本
+        }
+        return compact('orderinfo', 'price', 'postage', 'deduction', 'coupon', 'cost');
+    }
+
+    /**
+     * 处理where条件
+     */
+    public static function statusByWhere($status, $model = null)
+    {
+        if ($model == null) $model = new self;
+        if ('' === $status)
+            return $model;
+        else if ($status == 'weixin')//微信支付
+            return $model->where('pay_type', 'weixin');
+        else if ($status == 'yue')//余额支付
+            return $model->where('pay_type', 'yue');
+        else if ($status == 'offline')//线下支付
+            return $model->where('pay_type', 'offline');
+        else
+            return $model;
+    }
+
+    public static function getTimeWhere($where, $model = null)
+    {
+        return self::getTime($where)->where('paid', 1)->where('refund_status', 0);
+    }
+    /**
+     * 获取时间区间
+     */
+    public static function getTime($where,$model=null,$prefix='add_time'){
+        if ($model == null) $model = new self;
+        if ($where['data'] == '') {
+            switch ($where['date']){
+                case 'today':case 'week':case 'month':case 'year':
+                    $model=$model->whereTime($prefix,$where['date']);
+                    break;
+                case 'quarter':
+                    list($startTime,$endTime)=User::getMonth('n');
+                    $model = $model->where($prefix, '>', strtotime($startTime));
+                    $model = $model->where($prefix, '<', strtotime($endTime));
+                    break;
+            }
+        }else{
+            list($startTime, $endTime) = explode(' - ', $where['data']);
+            $model = $model->where($prefix, '>', strtotime($startTime));
+            $model = $model->where($prefix, '<', strtotime($endTime));
+        }
+        return $model;
+    }
+    /**
+     * 获取新增消费
+     */
+    public static function getConsumption($where)
+    {
+        $consumption=self::getTime($where,new UserBill,'b.add_time')->alias('a')->join('user b','a.uid = b.uid')
+            ->field('sum(a.number) number')
+        ->where('a.type','pay_product')->find()->toArray();
+        return $consumption;
+    }
+    /**
+     * 获取拼团商品
+     */
+    public static function getPink($where)
+    {
+        $pink = self::getTimeWhere($where)->where('pink_id', 'neq', 0)->sum('pay_price');
+        return $pink;
+    }
+    /**
+     * 获取秒杀商品
+     */
+    public static function getSeckill($where){
+        $seckill=self::getTimeWhere($where)->where('seckill_id', 'neq', 0)->sum('pay_price');
+        return $seckill;
+    }
+    /**
+     * 获取普通商品数
+     */
+    public static function getOrdinary($where)
+    {
+        $ordinary = self::getTimeWhere($where)->where('pink_id', 'eq', 0)->where('seckill_id','eq','0')->sum('pay_price');
+        return $ordinary;
+    }
+
+    /**
+     * 获取用户充值
+     */
+    public static function getRecharge($where)
+    {
+            $Recharge = self::getTime($where,new UserBill)->where('type', 'system_add')->where('category','now_money')->sum('number');
+            return $Recharge;
+    }
+    /**
+     * 获取推广金
+     */
+    public static function getExtension($where)
+    {
+        $rake_back = self::getTime($where,new UserBill)->where('type', 'brokerage')->where('category','now_money')->sum('number');
+        $return = self::getTime($where,new UserBill)->where('type', 'brokerage_return')->where('category','now_money')->sum('number');
+        $extension=bcsub($rake_back,$return,2);
+        return $extension;
+    }
+
+    /**
+     * 最近交易
+     */
+    public static function trans()
+    {
+        $trans = self::alias('a')
+            ->join('user b', 'a.uid=b.uid')
+            ->join('store_order_cart_info c', 'a.id=c.oid')
+            ->join('store_product d', 'c.product_id=d.id')
+            ->field('b.nickname,a.pay_price,d.store_name')
+            ->order('a.add_time DESC')
+            ->limit('6')
+            ->select()->toArray();
+        return $trans;
+    }
+
+    /**
+     * 导出表格
+     */
+    public static function systemTable($where){
+        $orderinfos=self::getOrderInfo($where);
+        if($where['export'] == 1){
+            $export = [];
+            $orderinfo=$orderinfos['orderinfo'];
+            foreach($orderinfo as $info){
+                $time=$info['pay_time'];
+                $price = $info['total_price']+$info['pay_postage'];
+                $zhichu = $info['coupon_price']+$info['deduction_price']+$info['cost'];
+                $profit = ($info['total_price']+$info['pay_postage'])-($info['coupon_price']+$info['deduction_price']+$info['cost']);
+                $deduction=$info['deduction_price'];//积分抵扣
+                $coupon=$info['coupon_price'];//优惠
+                $cost=$info['cost'];//成本
+                $export[] = [$time,$price,$zhichu,$cost,$coupon,$deduction,$profit];
+            }
+            PHPExcelService::setExcelHeader(['时间','营业额(元)','支出(元)','成本','优惠','积分抵扣','盈利(元)'])->setExcelTile('财务统计', '财务统计',date('Y-m-d H:i:s',time()))->setExcelContent($export)->ExcelSave();
+        }
+    }
+}

+ 56 - 0
application/admin/model/record/StoreVisit.php

@@ -0,0 +1,56 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\model\store;
+
+use traits\ModelTrait;
+use basic\ModelBasic;
+use app\admin\model\user\User;
+
+class StoreVisit extends ModelBasic
+{
+    use ModelTrait;
+    /**
+     * @param $where
+     * @return array
+     */
+    public static function getVisit($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':
+                list($startTime,$endTime)=User::getMonth('n');
+                $model = $model->where('add_time','>',$startTime);
+                $model = $model->where('add_time','<',$endTime);
+                break;
+            default:
+                list($startTime,$endTime)=explode('-',$date);
+                $model = $model->where('add_time','>',strtotime($startTime));
+                $model = $model->where('add_time','<',strtotime($endTime));
+                break;
+        }
+        $list=$model->group('type')->field('sum(count) as sum,product_id,cate_id,type,content')->order('sum desc')->limit(0,10)->select()->toArray();
+        $view=[];
+        foreach ($list as $key=>$val){
+            $now_list['name']=$val['type']=='viwe'?'浏览量':'搜索';
+            $now_list['value']=$val['sum'];
+            $now_list['class']=isset($class[$key])?$class[$key]:'';
+            $view[]=$now_list;
+        }
+        if(empty($list)){
+            $view=[['name'=>'暂无数据', 'value'=>100, 'class'=>'']];
+        }
+        return $view;
+    }
+}

+ 48 - 0
application/admin/model/special/Grade.php

@@ -0,0 +1,48 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\model\special;
+
+use traits\ModelTrait;
+use basic\ModelBasic;
+
+/**
+ * Class Grade 一级分类
+ * @package app\admin\model\special
+ */
+class Grade extends ModelBasic
+{
+    use ModelTrait;
+
+    public static function getAll()
+    {
+        return self::where(['is_del' => 0,'is_show'=>1])->order('sort desc,add_time desc')->field(['name', 'id'])->select();
+    }
+
+    public static function getAllList($where)
+    {
+        $data = self::setWhere($where)->page((int)$where['page'], (int)$where['limit'])->select();
+        $count = self::setWhere($where)->count();
+        return compact('data', 'count');
+    }
+
+    public static function setWhere($where)
+    {
+        $model = self::order('sort desc,add_time desc')->where('is_del', 0);
+        if ($where['cate_name'] != '') $model = $model->where('name', 'like', "%$where[cate_name]%");
+        return $model;
+    }
+
+    public function SpecialSubject()
+    {
+        return $this->hasMany('SpecialSubject','grade_id');
+    }
+}

+ 215 - 0
application/admin/model/special/Lecturer.php

@@ -0,0 +1,215 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\model\special;
+
+use traits\ModelTrait;
+use basic\ModelBasic;
+use app\admin\model\order\StoreOrder as StoreOrderModel;
+use app\admin\model\special\Special;
+
+/**
+ * Class Lecturer 讲师
+ * @package app\admin\model\special
+ */
+class Lecturer extends ModelBasic
+{
+    use ModelTrait;
+
+    //设置where条件
+    public static function setWhere($where, $alirs = '', $model = null)
+    {
+        $model = $model === null ? new self() : $model;
+        $model = $alirs === '' ? $model->alias($alirs) : $model;
+        $alirs = $alirs === '' ? $alirs : $alirs . '.';
+        $model = $model->where("{$alirs}is_del", 0);
+        if ($where['is_show'] !== '') $model = $model->where("{$alirs}is_show", $where['is_show']);
+        if ($where['title']) $model = $model->where("{$alirs}lecturer_name", 'LIKE', "%$where[title]%");
+            $model = $model->order("{$alirs}sort desc");
+        return $model;
+    }
+
+    /**讲师列表
+     * @param $where
+     * @return array
+     * @throws \think\Exception
+     */
+    public static function getLecturerList($where)
+    {
+        $data = self::setWhere($where)->page((int)$where['page'], (int)$where['limit'])->select();
+        $data = count($data) ? $data->toArray() : [];
+        $count = self::setWhere($where)->count();
+        return compact('data', 'count');
+    }
+    /**
+     * 删除讲师
+     * @param $id
+     * @return bool|int
+     * @throws \think\exception\DbException
+     */
+    public static function delLecturer($id)
+    {
+        $lecturer = self::get($id);
+        if (!$lecturer) return self::setErrorInfo('删除的数据不存在');
+        $count=Special::where('is_del',0)->where('lecturer_id',$id)->count();
+        if($count){
+            Special::where('is_del',0)->where('lecturer_id',$id)->update(['lecturer_id'=>0]);
+        }
+        return self::where('id',$id)->update(['is_del'=>1]);
+    }
+
+    /**讲师课程订单
+     * @param $lecturer_id
+     */
+    public static function lecturerOrderList($where)
+    {
+        $model =self::getOrderWhere($where)->field('a.order_id,a.pay_price,a.pay_type,a.paid,a.status,a.total_price,a.refund_status,a.type,s.title,r.nickname,a.uid');
+        $data = ($data = $model->page((int)$where['page'], (int)$where['limit'])->select()) && count($data) ? $data->toArray() : [];
+        foreach ($data as $key=>&$value){
+            if ($value['paid'] == 0 && $value['status'] == 0) {
+                $value['status_name'] = '未支付';
+            } else if ($value['paid'] == 1 && $value['status'] == 0 && $value['refund_status'] == 0 && $value['type'] != 2) {
+                $value['status_name'] = '已支付';
+            }
+            if($value['nickname']){
+                $value['nickname']=$value['nickname'].'/'.$value['uid'];
+            }else{
+                $value['nickname']='用户被删除/'.$value['uid'];
+            }
+            if ($value['paid'] == 1) {
+                switch ($value['pay_type']) {
+                    case 'weixin':
+                        $value['pay_type_name'] = '微信支付';
+                        break;
+                    case 'yue':
+                        $value['pay_type_name'] = '余额支付';
+                        break;
+                    case 'zhifubao':
+                        $value['pay_type_name'] = '支付宝支付';
+                        break;
+                    default:
+                        $value['pay_type_name'] = '其他支付';
+                        break;
+                }
+            } else {
+                switch ($value['pay_type']) {
+                    default:
+                        $value['pay_type_name'] = '未支付';
+                        break;
+                }
+            }
+        }
+        $count = self::getOrderWhere($where)->count();
+        return compact('count', 'data');
+    }
+
+    /**条件处理
+     * @param $where
+     * @return StoreOrderModel
+     */
+    public static function getOrderWhere($where)
+    {
+        $model=StoreOrderModel::alias('a')->join('user r', 'r.uid=a.uid', 'LEFT')
+            ->join('Special s','a.cart_id=s.id')
+            ->where('a.type',0)->where('a.paid',1);
+        if($where['lecturer_id']){
+            $model=$model->where('s.lecturer_id',$where['lecturer_id']);
+        }
+        if ($where['data'] !== '') {
+            $model = self::getModelTime($where, $model, 'a.add_time');
+        }
+        $model = $model->order('a.id desc');
+        return $model;
+    }
+    /**
+     * 处理订单金额
+     * @param $where
+     * @return array
+     */
+    public static function getOrderPrice($where)
+    {
+        $price = array();
+        $price['pay_price'] = 0;//支付金额
+        $price['pay_price_wx'] = 0;//微信支付金额
+        $price['pay_price_yue'] = 0;//余额支付金额
+        $price['pay_price_zhifubao'] = 0;//支付宝支付金额
+
+        $list = self::getOrderWhere($where)->field([
+            'sum(a.total_num) as total_num',
+            'sum(a.pay_price) as pay_price',
+        ])->find()->toArray();
+        $price['total_num'] = $list['total_num'];//商品总数
+        $price['pay_price'] = $list['pay_price'];//支付金额
+        $list = self::getOrderWhere($where)->field('sum(a.pay_price) as pay_price,a.pay_type')->group('a.pay_type')->select()->toArray();
+        foreach ($list as $v) {
+            if ($v['pay_type'] == 'weixin') {
+                $price['pay_price_wx'] = $v['pay_price'];
+            } elseif ($v['pay_type'] == 'yue') {
+                $price['pay_price_yue'] = $v['pay_price'];
+            } elseif ($v['pay_type'] == 'zhifubao') {
+                $price['pay_price_zhifubao'] = $v['pay_price'];
+            } else {
+                $price['pay_price_other'] = $v['pay_price'];
+            }
+        }
+        $price['order_sum'] =self::getOrderWhere($where)->count();
+        return $price;
+    }
+
+    public static function getBadge($where)
+    {
+        $price = self::getOrderPrice($where);
+        return [
+            [
+                'name' => '订单数量',
+                'field' => '件',
+                'count' => $price['order_sum'],
+                'background_color' => 'layui-bg-blue',
+                'col' => 4
+            ],
+            [
+                'name' => '售出课程',
+                'field' => '件',
+                'count' => $price['total_num'],
+                'background_color' => 'layui-bg-blue',
+                'col' => 4
+            ],
+            [
+                'name' => '订单金额',
+                'field' => '元',
+                'count' => $price['pay_price'],
+                'background_color' => 'layui-bg-blue',
+                'col' => 4
+            ],
+            [
+                'name' => '微信支付金额',
+                'field' => '元',
+                'count' => $price['pay_price_wx'],
+                'background_color' => 'layui-bg-blue',
+                'col' => 4
+            ],
+            [
+                'name' => '余额支付金额',
+                'field' => '元',
+                'count' => $price['pay_price_yue'],
+                'background_color' => 'layui-bg-blue',
+                'col' => 4
+            ],
+            [
+                'name' => '支付宝支付金额',
+                'field' => '元',
+                'count' => $price['pay_price_zhifubao'],
+                'background_color' => 'layui-bg-blue',
+                'col' => 4
+            ]
+        ];
+    }
+}

+ 41 - 0
application/admin/model/special/RecommendBanner.php

@@ -0,0 +1,41 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\model\special;
+
+use traits\ModelTrait;
+use basic\ModelBasic;
+
+class RecommendBanner extends ModelBasic
+{
+    use ModelTrait;
+
+    public static function valiWhere($alias = '', $model = null)
+    {
+        if (is_null($model)) $model = new self();
+        if ($alias) {
+            $model = $model->alias($alias);
+            $alias .= '.';
+        }
+        return $model->where("{$alias}is_show", 1);
+    }
+
+    public static function getRecemmodBannerList($where)
+    {
+        $data = self::valiWhere()->order('sort DESC')->where('recommend_id', $where['id'])->page((int)$where['page'], (int)$where['limit'])->select();
+        $data = count($data) ? $data->toArray() : [];
+        foreach ($data as &$item) {
+            $item['add_time'] = date('Y-m-d H:i:s', $item['add_time']);
+        }
+        $count = self::valiWhere()->order('sort DESC')->where('recommend_id', $where['id'])->count();
+        return compact('data', 'count');
+    }
+}

+ 227 - 0
application/admin/model/special/Special.php

@@ -0,0 +1,227 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\model\special;
+
+use app\admin\model\live\LiveGoods;
+use app\admin\model\live\LiveStudio;
+use app\admin\model\order\StoreOrder;
+use app\admin\model\system\RecommendRelation;
+use think\cache\driver\Redis;
+use traits\ModelTrait;
+use basic\ModelBasic;
+
+/**
+ * Class Special 专题
+ * @package app\admin\model\special
+ */
+class Special extends ModelBasic
+{
+    use ModelTrait;
+
+    protected static function init()
+    {
+        self::afterUpdate(function () {
+            del_redis_hash("wap_index_has","recommend_list");
+        });
+    }
+    public function profile()
+    {
+        return $this->hasOne('SpecialContent', 'special_id', 'id')->field('content');
+    }
+
+    public static function PreWhere($alert = '')
+    {
+        $alert = $alert ? $alert . '.' : '';
+        return self::where([$alert . 'is_show' => 1, $alert . 'is_del' => 0]);
+    }
+
+    //动态赋值
+    public static function getPinkStrarTimeAttr($value)
+    {
+        return $value ? date('Y-m-d H:i:s', $value) : '';
+    }
+
+    public static function getPinkEndTimeAttr($value)
+    {
+        return $value ? date('Y-m-d H:i:s', $value) : '';
+    }
+
+    public static function getAddTimeAttr($value)
+    {
+        return date('Y-m-d H:i:s', $value);
+    }
+
+    public static function getBannerAttr($value)
+    {
+        return is_string($value) ? json_decode($value, true) : $value;
+    }
+
+    public static function getLabelAttr($value)
+    {
+        return is_string($value) ? json_decode($value, true) : $value;
+    }
+    //end
+    //设置
+    public static function getBannerKeyAttr($banner)
+    {
+        if (is_string($banner)) $banner = json_decode($banner, true);
+        if ($banner === false) return [];
+        $value = [];
+        foreach ($banner as $item) {
+            $value[] = [
+                'is_show' => false,
+                'pic' => $item
+            ];
+        }
+        return $value;
+    }
+
+    public static function saveFieldByWhere(array $where, array $data)
+    {
+        if (!$where || !$data) return false;
+        return parent::saveFieldByWhere($where, $data);
+    }
+
+    //获取单个专题
+    public static function getOne($id, $is_live = false)
+    {
+        $special = self::get($id);
+        if (!$special) return false;
+        if ($special->is_del) return false;
+        $special->banner = self::getBannerKeyAttr($special->banner);
+        $special->profile->content = htmlspecialchars_decode($special->profile->content);
+        if ($is_live) {
+            $liveInfo = LiveStudio::where('special_id', $special->id)->find();
+            if (!$liveInfo) return self::setErrorInfo('暂未查到直播间');
+            if ($liveInfo->is_del) return self::setErrorInfo('直播间已删除无法编辑');
+            $liveInfo->live_duration = (strtotime($liveInfo->stop_play_time) - strtotime($liveInfo->start_play_time)) / 60;
+            $liveInfo = $liveInfo->toArray();
+        } else
+            $liveInfo = [];
+        return [$special->toArray(), $liveInfo];
+    }
+
+    //设置条件
+    public static function setWhere($where, $alert = '', $model = null)
+    {
+        $model = $model === null ? new self() : $model;
+        if ($alert) $model = $model->alias($alert);
+        $alert = $alert ? $alert . '.' : '';
+        if ($where['order'])
+            $model = $model->order($alert . self::setOrder($where['order']));
+        else
+            $model = $model->order($alert.'sort desc,'.$alert.'id desc');
+        if (isset($where['subject_id']) && $where['subject_id']) $model = $model->where($alert . 'subject_id', $where['subject_id']);
+        if (isset($where['store_name']) && $where['store_name']!='') $model = $model->where($alert . 'title|' . $alert . 'abstract|' . $alert . 'phrase|'. $alert . 'id', "LIKE", "%$where[store_name]%");
+        if ($where['is_show'] !== '') $model = $model->where($alert . 'is_show', $where['is_show']);
+        if (isset($where['type']) && $where['type']) $model = $model->where($alert . 'type', $where['type']);
+        if (isset($where['special_type']) && $where['special_type'] !== '') {
+            $model = $model->where($alert . 'type', $where['special_type']);
+        }
+        if (isset($where['admin_id']) && $where['admin_id']) $model = $model->where($alert . 'admin_id', $where['admin_id']);
+        if (isset($where['start_time']) && $where['start_time'] && isset($where['end_time']) && $where['end_time']) $model = $model->whereTime($alert . 'add_time', 'between', [strtotime($where['start_time']), strtotime($where['end_time'])]);
+        return $model->where($alert .'is_del', 0);
+    }
+
+    /**
+     * @param $where
+     */
+    public static function getPinkList($where)
+    {
+        $data = self::setWhere($where, 'A')->field('A.*,T.content,S.name as subject_name')
+            ->join('__SPECIAL_CONTENT__ T', 'T.special_id=A.id','LEFT')->join('__SPECIAL_SUBJECT__ S', 'S.id=A.subject_id','LEFT')
+            ->page((int)$where['page'], (int)$where['limit'])->where('A.is_pink',1)->select();
+        $data = count($data) ? $data->toArray() : [];
+        foreach ($data as &$item) {
+            $item['recommend'] = RecommendRelation::where('a.link_id', $item['id'])->where('a.type', 'in', [0, 2])->alias('a')
+                ->join('__RECOMMEND__ r', 'a.recommend_id=r.id')->column('a.id,r.title');
+            $item['pink_end_time'] = $item['pink_end_time'] ? strtotime($item['pink_end_time']) : 0;
+            $item['sales'] = StoreOrder::where(['paid' => 1, 'cart_id' => $item['id'], 'refund_status' => 0])->count();
+            $liveGoods = LiveGoods::getOne(['special_id' => $item['id'], 'is_delete' => 0]);
+            $item['is_live_goods'] = 0;
+            $item['live_goods_id'] = 0;
+            if ($liveGoods) {
+                $item['live_goods_id'] = $liveGoods->id;
+                if ($liveGoods->is_show == 1) {
+                    $item['is_live_goods'] = 1;
+                }
+            }
+            //查看拼团状态,如果已结束关闭拼团
+            if ($item['is_pink'] && $item['pink_end_time'] < time()) {
+                self::update(['is_pink' => 0], ['id' => $item['id']]);
+                $item['is_pink'] = 0;
+            }
+            if(!$item['is_pink']){
+                $item['pink_money'] = 0;
+            }
+            $item['stream_name'] = LiveStudio::where('special_id', $item['id'])->value('stream_name');
+            $oldTaskCount = SpecialTask::where('special_id', $item['id'])->where('is_show', 1)->count();
+            $newTaskCount = SpecialSource::where('special_id', $item['id'])->count();
+            $item['task_count'] = $newTaskCount + $oldTaskCount;
+            $item['live_id'] = LiveStudio::where('special_id', $item['id'])->value('id');
+            $item['is_play'] =0;
+            if ($item['live_id']) {
+                $item['online_num'] = LiveStudio::where('id', $item['live_id'])->value('online_num');
+                $item['is_play'] = LiveStudio::where('id', $item['live_id'])->value('is_play') ? 1 : 0;
+            }
+            $item['buy_user_num'] = StoreOrder::where(['paid' => 1, 'cart_id' => $item['id']])->count('id');
+            $item['start_play_time'] = LiveStudio::where('special_id', $item['id'])->value('start_play_time');
+        }
+        $count = self::setWhere($where)->count();
+        return compact('data', 'count');
+    }
+    //查找专题列表
+    public static function getSpecialList($where)
+    {
+        $data = self::setWhere($where, 'A')->field('A.*,T.content,S.name as subject_name')
+            ->join('__SPECIAL_CONTENT__ T', 'T.special_id=A.id','LEFT')->join('__SPECIAL_SUBJECT__ S', 'S.id=A.subject_id','LEFT')
+            ->page((int)$where['page'], (int)$where['limit'])->select();
+        $data = count($data) ? $data->toArray() : [];
+        foreach ($data as &$item) {
+            $item['recommend'] = RecommendRelation::where('a.link_id', $item['id'])->where('a.type', 'in', [0, 2])->alias('a')
+                ->join('__RECOMMEND__ r', 'a.recommend_id=r.id')->column('a.id,r.title');
+            $item['pink_end_time'] = $item['pink_end_time'] ? strtotime($item['pink_end_time']) : 0;
+            $item['sales'] = StoreOrder::where(['paid' => 1, 'cart_id' => $item['id'], 'refund_status' => 0])->count();
+            $liveGoods = LiveGoods::getOne(['special_id' => $item['id'], 'is_delete' => 0]);
+            $item['is_live_goods'] = 0;
+            $item['live_goods_id'] = 0;
+            if ($liveGoods) {
+                $item['live_goods_id'] = $liveGoods->id;
+                if ($liveGoods->is_show == 1) {
+                    $item['is_live_goods'] = 1;
+                }
+            }
+            //查看拼团状态,如果已结束关闭拼团
+            if ($item['is_pink'] && $item['pink_end_time'] < time()) {
+                self::update(['is_pink' => 0], ['id' => $item['id']]);
+                $item['is_pink'] = 0;
+            }
+            if(!$item['is_pink']){
+                $item['pink_money'] = 0;
+            }
+            if ($where['type'] == 4) $item['stream_name'] = LiveStudio::where('special_id', $item['id'])->value('stream_name');
+            $oldTaskCount = SpecialTask::where('special_id', $item['id'])->where('is_show', 1)->count();
+            $newTaskCount = SpecialSource::where('special_id', $item['id'])->count();
+            $item['task_count'] = $newTaskCount + $oldTaskCount;
+            $item['live_id'] = LiveStudio::where('special_id', $item['id'])->value('id');
+            $item['is_play'] =0;
+            if ($item['live_id']) {
+                $item['online_num'] = LiveStudio::where('id', $item['live_id'])->value('online_num');
+                $item['is_play'] = LiveStudio::where('id', $item['live_id'])->value('is_play') ? 1 : 0;
+            }
+            $item['buy_user_num'] = StoreOrder::where(['paid' => 1, 'cart_id' => $item['id']])->count('id');
+            $item['start_play_time'] = LiveStudio::where('special_id', $item['id'])->value('start_play_time');
+        }
+        $count = self::setWhere($where)->count();
+        return compact('data', 'count');
+    }
+}

+ 27 - 0
application/admin/model/special/SpecialBarrage.php

@@ -0,0 +1,27 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\model\special;
+
+use app\admin\model\order\StoreOrder;
+use app\admin\model\system\RecommendRelation;
+use traits\ModelTrait;
+use basic\ModelBasic;
+
+/**
+ * Class Special 专题弹幕
+ * @package app\admin\model\special
+ */
+class SpecialBarrage extends ModelBasic
+{
+    use ModelTrait;
+
+}

+ 26 - 0
application/admin/model/special/SpecialContent.php

@@ -0,0 +1,26 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\model\special;
+
+use traits\ModelTrait;
+use basic\ModelBasic;
+
+/**
+ * Class SpecialContent 专题详情
+ * @package app\admin\model\special
+ */
+class SpecialContent extends ModelBasic
+{
+    use ModelTrait;
+
+
+}

+ 60 - 0
application/admin/model/special/SpecialCourse.php

@@ -0,0 +1,60 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\model\special;
+
+use traits\ModelTrait;
+use basic\ModelBasic;
+
+/**
+ * Class SpecialCourse 专题课程
+ * @package app\admin\model\special
+ */
+class SpecialCourse extends ModelBasic
+{
+    use ModelTrait;
+
+    public static function getAddTimeAttr($value)
+    {
+        return $value ? date('Y-m-d H:i:s', $value) : '';
+    }
+
+    public static function setWhere($where, $alias = '', $model = null)
+    {
+        if ($model === null) $model = new  self();
+        if ($alias) $model = $model->alias($alias);
+        $alias = $alias ? $alias . '.' : '';
+        if ($where['is_show'] !== '') $model = $model->where("{$alias}is_show", $where['is_show']);
+        if ($where['special_id']) $model = $model->where("{$alias}special_id", $where['special_id']);
+        if ($where['course_name']) $model = $model->where("{$alias}course_name", 'LIKE', "%$where[course_name]%");
+        return $model;
+    }
+
+    public static function getCourseList($where)
+    {
+        $data = self::setWhere($where)->page((int)$where['page'], (int)$where['limit'])->select();
+        foreach ($data as &$item) {
+            $item['special_name'] = Special::where('id', $item['special_id'])->value('title');
+            $item['number'] = SpecialTask::where(['coures_id' => $item['id'], 'is_show' => 1])->count();
+        }
+        $count = self::setWhere($where)->count();
+        return compact('data', 'count');
+    }
+
+    public static function DelCourse($id)
+    {
+        $coures = self::get($id);
+        if (!$coures) return false;
+        if (SpecialTask::where('coures_id', $id)->count()) return self::setErrorInfo('请先删除此课程下的任务再尝试删除');
+        return $coures->delete();
+    }
+
+}

+ 99 - 0
application/admin/model/special/SpecialSource.php

@@ -0,0 +1,99 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\model\special;
+
+use app\admin\model\special\Special as SpecialModel;
+use traits\ModelTrait;
+use basic\ModelBasic;
+
+/**
+ * Class Special 专题素材关联表
+ * @package app\admin\model\special
+ */
+class SpecialSource extends ModelBasic
+{
+    use ModelTrait;
+
+    /**获取专题素材
+     * @param bool $special_id
+     * @return false|\PDOStatement|string|\think\Collection
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public static function getSpecialSource($special_id = false, $source_id = false)
+    {
+        $where = array();
+        $data = self::where($where);
+        if ($special_id && is_numeric($special_id)) {
+            $where['special_id'] = $special_id;
+            $data->where($where);
+        }
+        if ($source_id) {
+            if (!is_array($source_id)) {
+                $where['source_id'] = $source_id;
+                $data->where($where);
+            } else {
+                $data->whereIn('source_id', $source_id);
+            }
+        }
+        return $data->order('sort desc')->select();
+    }
+
+    /**更新及添加专题素材
+     * @param $source_list_ids  一维数组,素材id
+     * @param int $special_id 专题id
+     * @return bool
+     */
+    public static function saveSpecialSource($source_list_ids,$special_id=0,$special_type=1,$data=[])
+    {
+        if (!$special_id || !is_numeric($special_id)) {
+            return false;
+        }
+        if (!$source_list_ids || !is_array($source_list_ids)) {
+            return false;
+        }
+        try {
+            $specialSourceAll = self::getSpecialSource($special_id)->toArray();
+            if ($specialSourceAll) {
+                self::where(['special_id' => $special_id])->delete();
+            }
+            $inster['special_id'] = $special_id;
+            foreach ($source_list_ids as $sk => $sv) {
+                if($special_type==SPECIAL_COLUMN){
+                    $special=SpecialModel::where('id',$sv->id)->field('pay_type,member_pay_type')->find();
+                    if($data['pay_type']==1 && $data['member_pay_type']==0){
+                        if($special['pay_type']==1 && $special['member_pay_type']==1){
+                            SpecialModel::where('id',$sv->id)->update(['member_pay_type'=>0,'member_money'=>0]);
+                        }
+                        $inster['pay_status'] = 1;
+                    }else if($data['pay_type']==0){
+                        if($special['pay_type']==1){
+                            SpecialModel::where('id',$sv->id)->update(['member_pay_type'=>0,'member_money'=>0,'pay_type'=>0,'money'=>0]);
+                        }
+                        $inster['pay_status'] = 0;
+                    }
+                }else{
+                    $inster['pay_status'] = $sv->pay_status;
+                }
+                $inster['source_id'] = $sv->id;
+                $inster['sort'] = $sv->sort;
+                $inster['add_time'] = time();
+                self::set($inster);
+            }
+                return true;
+        } catch (\Exception $e) {
+            return false;
+        }
+    }
+
+}

+ 47 - 0
application/admin/model/special/SpecialSubject.php

@@ -0,0 +1,47 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+
+namespace app\admin\model\special;
+
+use traits\ModelTrait;
+use basic\ModelBasic;
+
+/**
+ * Class SpecialSubject 二级分类
+ * @package app\admin\model\special
+ */
+class SpecialSubject extends ModelBasic
+{
+    use ModelTrait;
+
+    public static function get_subject_list($where){
+        $data=self::setWhere($where)->page((int)$where['page'],(int)$where['limit'])->select();
+        foreach ($data as &$item){
+            $item['grade_name']=Grade::where('id',$item['grade_id'])->where('is_del',0)->value('name');
+            $item['add_time']=date('Y-m-d H:i:s',$item['add_time']);
+            $item['special_count']=Special::PreWhere()->where('subject_id',$item['id'])->count();
+        }
+        $count=self::setWhere($where)->count();
+        return compact('data','count');
+    }
+
+    public static function setWhere($where){
+        $model=self::order('sort desc,add_time desc')->where('is_del',0);
+        if($where['name']) $model=$model->where('name','like',"%$where[name]%");
+        if($where['pid']) $model=$model->where('grade_id',$where['pid']);
+        return $model;
+    }
+
+    public static function getSubjectAll(){
+        return self::order('sort desc,add_time desc')->where(['is_show'=>1,'is_del'=>0])->field('name,id')->select();
+    }
+}

+ 160 - 0
application/admin/model/special/SpecialTask.php

@@ -0,0 +1,160 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\model\special;
+
+use traits\ModelTrait;
+use basic\ModelBasic;
+/**
+ * Class SpecialTask 专题任务
+ * @package app\admin\model\special
+ */
+class SpecialTask extends ModelBasic
+{
+    use ModelTrait;
+
+    public static function getAddTimeAttr($value)
+    {
+        return $value ? date("Y-m-d H:i:s", $value) : '';
+    }
+
+    public static function getCouresNameAttr($value, $data)
+    {
+        return SpecialCourse::where('id', $data['coures_id'])->value('course_name');
+    }
+
+    //设置where条件
+    public static function setWhere($where, $alirs = '', $model = null)
+    {
+        $model = $model === null ? new self() : $model;
+        $model = $alirs === '' ? $model->alias($alirs) : $model;
+        $alirs = $alirs === '' ? $alirs : $alirs . '.';
+        if ($where['is_show'] !== '') $model = $model->where("{$alirs}is_show", $where['is_show']);
+        if ($where['pid']>0) {
+            $pids=SpecialTaskCategory::categoryId($where['pid']);
+            array_push($pids,$where['pid']);
+           if(count($pids)>0){
+               $model = $model->where("{$alirs}pid",'in', $pids);
+           }else{
+               $model = $model->where("{$alirs}pid", $where['pid']);
+           }
+        }
+        if ($where['title']) $model = $model->where("{$alirs}title", 'LIKE', "%$where[title]%");
+        if (isset($where['special_type']) && $where['special_type']) $model = $model->where("{$alirs}type", $where['special_type']);
+        $model = $model->where("{$alirs}is_del", 0);
+        if ($where['order'])
+            $model = $model->order($alirs . self::setOrder($where['order']));
+        else
+            $model = $model->order("{$alirs}sort desc,{$alirs}id desc");
+        return $model;
+    }
+
+    public static function getTaskCount($special_id)
+    {
+        $ids = self::getDb('special_course')->where('special_id', $special_id)->where('is_show', 1)->column('id');
+        return self::where('is_show', 1)->where('is_del',0)->where('coures_id', 'in', $ids)->count();
+    }
+
+    //查找任务列表-对getTaskList2
+    public static function getTaskList($where)
+    {
+        $data = self::setWhere($where)->page((int)$where['page'], (int)$where['limit'])->select();
+        $data = count($data) ? $data->toArray() : [];
+        foreach ($data as &$item) {
+            $item['course_name'] = Special::where('id', $item['special_id'])->value('title');
+        }
+        $count = self::setWhere($where)->count();
+        return compact('data', 'count');
+    }
+    public static function getTaskList2($where)
+    {
+        if (isset($where['special_type']) && $where['special_type'] == SPECIAL_COLUMN){
+            unset($where['special_type']);
+            $where['store_name']=$where['title'];
+            if($where['type']==''){
+                $data = Special::setWhere($where)->whereIn('type',[SPECIAL_IMAGE_TEXT, SPECIAL_AUDIO, SPECIAL_VIDEO])->page((int)$where['page'], (int)$where['limit'])->select();
+                $data = count($data) ? $data->toArray() : [];
+                $count = Special::setWhere($where)->whereIn('type',[SPECIAL_IMAGE_TEXT, SPECIAL_AUDIO, SPECIAL_VIDEO])->count();
+            }else{
+                $data = Special::setWhere($where)->page((int)$where['page'], (int)$where['limit'])->select();
+                $data = count($data) ? $data->toArray() : [];
+                $count = Special::setWhere($where)->count();
+            }
+        }elseif (isset($where['special_type']) && $where['special_type'] == SPECIAL_LIVE){
+            unset($where['special_type']);
+            $where['store_name']=$where['title'];
+            if($where['type']==''){
+                $data = Special::setWhere($where)->whereIn('type',[SPECIAL_IMAGE_TEXT, SPECIAL_AUDIO, SPECIAL_VIDEO])->page((int)$where['page'], (int)$where['limit'])->select();
+                $data = count($data) ? $data->toArray() : [];
+                $count = Special::setWhere($where)->whereIn('type',[SPECIAL_IMAGE_TEXT, SPECIAL_AUDIO, SPECIAL_VIDEO])->count();
+            }else{
+                $data = Special::setWhere($where)->page((int)$where['page'], (int)$where['limit'])->select();
+                $data = count($data) ? $data->toArray() : [];
+                $count = Special::setWhere($where)->count();
+            }
+        }else{
+            if($where['pid']>0){$where['special_type']=0;}
+            $data = self::setWhere($where)->page((int)$where['page'], (int)$where['limit'])->select();
+            $data = count($data) ? $data->toArray() : [];
+            $count = self::setWhere($where)->count();
+        }
+        return compact('data', 'count');
+    }
+    /**
+     * 删除任务
+     * @param $id
+     * @return bool|int
+     * @throws \think\exception\DbException
+     */
+    public static function delTask($id)
+    {
+        $task = self::get($id);
+        if (!$task) return self::setErrorInfo('删除的数据不存在');
+        return $task->delete();
+    }
+
+    /**
+     * 设置直播关联查询条件
+     * @param $where
+     * @return $this
+     */
+    public static function setLiveWhereTask($where)
+    {
+        $model = self::where('live_id', $where['live_id']);
+        if ($where['title']) $model = $model->where('title', 'like', "%$where[title]%");
+        if ($where['start_time'] && $where['end_time']) $model = $model->where('add_time', 'between', [strtotime($where['start_time']), strtotime($where['end_time'])]);
+        return $model;
+    }
+
+    /**
+     * 获取直播关联的任务
+     * @param $where
+     * @return array
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public static function getRelationTask($where)
+    {
+        $data = self::setLiveWhereTask($where)->page((int)$where['page'], (int)$where['limit'])->order('sort desc')->select();
+        $data = count($data) ? $data->toArray() : [];
+        foreach ($data as &$item) {
+            $special = SpecialCourse::where('a.id', $item['coures_id'])->alias('a')->join('special s', 's.id=a.special_id')->field('s.id,s.title')->find();
+            if ($special)
+                $item['special_title'] = $special['title'] . '&nbsp/&nbsp' . $special['id'];
+            else
+                $item['special_title'] = '';
+        }
+        $count = self::setLiveWhereTask($where)->count();
+        return compact('data', 'count');
+    }
+}

+ 68 - 0
application/admin/model/special/SpecialTaskCategory.php

@@ -0,0 +1,68 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\model\special;
+
+use traits\ModelTrait;
+use basic\ModelBasic;
+use service\UtilService as Util;
+use app\admin\model\special\SpecialTask;
+
+class SpecialTaskCategory extends ModelBasic
+{
+    use ModelTrait;
+
+    /**
+     * 全部素材分类
+     */
+    public static function taskCategoryAll($type=0){
+        $model=self::where('is_del',0);
+        if($type==1){
+            $model=$model->where('pid',0);
+        }
+        $list=$model->select();
+        $list=count($list) > 0 ? $list->toArray() : [];
+        $list=Util::sortListTier($list);
+        return $list;
+    }
+    /**
+     * 素材分类列表
+     */
+    public static function getAllList($where){
+        $data = self::setWhere($where)->page((int)$where['page'], (int)$where['limit'])->select();
+        $data=count($data) > 0 ? $data->toArray() : [];
+        foreach ($data as &$item){
+            $pids=self::categoryId($item['id']);
+            if(count($pids)>0){
+                $item['sum']=SpecialTask::where("pid",'in', $pids)->count();
+            }else{
+                $item['sum']=SpecialTask::where("pid", $item['id'])->count();
+            }
+        }
+        $count = self::setWhere($where)->count();
+        return compact('data', 'count');
+    }
+
+    public static function setWhere($where)
+    {
+        $model = self::order('sort desc,add_time desc')->where('is_del', 0)->where('pid',$where['pid']);
+        if ($where['cate_name'] != '') $model = $model->where('title', 'like', "%$where[cate_name]%");
+        return $model;
+    }
+
+    /**获取一个分类下的所有分类ID
+     * @param int $pid
+     */
+    public static function categoryId($pid=0){
+        $data=self::where('is_del', 0)->where('pid',$pid)->column('id');
+        return $data;
+    }
+}

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